autopilot-ai 1.24.1 → 1.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -102,8 +102,8 @@ async function flushAndCloseForTesting() {
102
102
  const s = currentStream;
103
103
  currentStream = null;
104
104
  currentDate = null;
105
- await new Promise((resolve19) => {
106
- s.end(() => resolve19());
105
+ await new Promise((resolve20) => {
106
+ s.end(() => resolve20());
107
107
  });
108
108
  }
109
109
  function isLogSinkEnabled() {
@@ -1342,10 +1342,10 @@ async function* readSSE(stream, signal, idleTimeoutMs, postFirstByteIdleTimeoutM
1342
1342
  gotFirstByte = true;
1343
1343
  buffer += decoder.decode(value, { stream: true });
1344
1344
  buffer = buffer.replace(/\r\n/g, "\n");
1345
- let sep7;
1346
- while ((sep7 = buffer.indexOf("\n\n")) !== -1) {
1347
- const event = buffer.slice(0, sep7);
1348
- buffer = buffer.slice(sep7 + 2);
1345
+ let sep8;
1346
+ while ((sep8 = buffer.indexOf("\n\n")) !== -1) {
1347
+ const event = buffer.slice(0, sep8);
1348
+ buffer = buffer.slice(sep8 + 2);
1349
1349
  const data = extractData(event);
1350
1350
  if (data !== null) yield data;
1351
1351
  }
@@ -2782,7 +2782,8 @@ async function* parseStream(body, signal, idleTimeoutMs = DEFAULT_IDLE_TIMEOUT_M
2782
2782
  index: idx,
2783
2783
  id: buf.id,
2784
2784
  name: buf.name,
2785
- arguments: buf.args
2785
+ arguments: buf.args,
2786
+ finishReason
2786
2787
  };
2787
2788
  }
2788
2789
  yield { type: "done", finishReason, usage: lastUsage };
@@ -2850,11 +2851,11 @@ function extractApiError(parsed, rawText) {
2850
2851
  return null;
2851
2852
  }
2852
2853
  function sleep(ms, signal) {
2853
- return new Promise((resolve19, reject) => {
2854
+ return new Promise((resolve20, reject) => {
2854
2855
  if (signal?.aborted) return reject(new DOMException("aborted", "AbortError"));
2855
2856
  const t = setTimeout(() => {
2856
2857
  signal?.removeEventListener("abort", onAbort);
2857
- resolve19();
2858
+ resolve20();
2858
2859
  }, ms);
2859
2860
  const onAbort = () => {
2860
2861
  clearTimeout(t);
@@ -3608,9 +3609,9 @@ var require_node_gyp_build = __commonJS({
3608
3609
  var debug = getFirst(path.join(dir, "build/Debug"), matchBuild);
3609
3610
  if (debug) return debug;
3610
3611
  }
3611
- var prebuild = resolve19(dir);
3612
+ var prebuild = resolve20(dir);
3612
3613
  if (prebuild) return prebuild;
3613
- var nearby = resolve19(path.dirname(process.execPath));
3614
+ var nearby = resolve20(path.dirname(process.execPath));
3614
3615
  if (nearby) return nearby;
3615
3616
  var target = [
3616
3617
  "platform=" + platform8,
@@ -3626,7 +3627,7 @@ var require_node_gyp_build = __commonJS({
3626
3627
  // eslint-disable-line
3627
3628
  ].filter(Boolean).join(" ");
3628
3629
  throw new Error("No native build was found for " + target + "\n loaded from: " + dir + "\n");
3629
- function resolve19(dir2) {
3630
+ function resolve20(dir2) {
3630
3631
  var tuples = readdirSync2(path.join(dir2, "prebuilds")).map(parseTuple);
3631
3632
  var tuple = tuples.filter(matchTuple(platform8, arch)).sort(compareTuples)[0];
3632
3633
  if (!tuple) return;
@@ -4047,7 +4048,7 @@ function truncateForEmbedding(text) {
4047
4048
  return text.slice(0, MAX_EMBED_CHARS);
4048
4049
  }
4049
4050
  async function sleep2(ms) {
4050
- return new Promise((resolve19) => setTimeout(resolve19, ms));
4051
+ return new Promise((resolve20) => setTimeout(resolve20, ms));
4051
4052
  }
4052
4053
  async function fetchWithRetry(url, init, retries = 3) {
4053
4054
  let lastError;
@@ -4699,6 +4700,8 @@ If the user asks what model you are, answer with exactly: \`${opts2.model}\`. Th
4699
4700
  - Today: ${date}`;
4700
4701
  const hasLsp = opts2.tools.some((t) => t.name.startsWith("lsp_"));
4701
4702
  const lspBlock = hasLsp ? "\n\nLSP tools are available for semantic code intelligence. Prefer `lsp_definition` over `grep` when looking for the source of a symbol. Prefer `lsp_references` over `grep` when finding usages. Use `lsp_hover` to confirm types before refactoring." : "";
4703
+ const hasArtifactTool = opts2.tools.some((t) => t.name === "create_artifact");
4704
+ const artifactGuidance = hasArtifactTool ? "\n\n## Choosing when to create an artifact\nUse `create_artifact` when the user would benefit from a visual, interactive, or polished standalone deliverable (for example, a dashboard, chart, diagram, prototype, or long structured report). Prefer a normal terminal response for brief answers, explanations, code snippets, and routine repository changes. For an artifact, first use `write` to save the complete HTML document as a local `.html` file in the workspace; then call `create_artifact` with a concise title and that file's workspace-relative `sourcePath`. Never put the full HTML document in `create_artifact` arguments. After it opens, summarize the result briefly in the terminal." : "";
4702
4705
  const tools = `Tools available:
4703
4706
  ${toolsBlock}`;
4704
4707
  const userShellBlock = userShellCommandsEnabled() ? `
@@ -4740,7 +4743,7 @@ ${opts2.lspContext}` : "";
4740
4743
  The following MCP server information was pre-computed by the coordinator.
4741
4744
 
4742
4745
  ${opts2.mcpContext}` : "";
4743
- return identity + "\n\n" + env2 + "\n\n" + tools + lspBlock + userShellBlock + contextBlock + modeBlock + skillsBlock + memoryBlock + lspContextBlock + mcpContextBlock;
4746
+ return identity + "\n\n" + env2 + "\n\n" + tools + artifactGuidance + lspBlock + userShellBlock + contextBlock + modeBlock + skillsBlock + memoryBlock + lspContextBlock + mcpContextBlock;
4744
4747
  }
4745
4748
  function buildSystemPrompt(opts2) {
4746
4749
  return buildStaticPrefix(opts2) + "\n\n" + buildSessionPrefix(opts2);
@@ -5438,15 +5441,15 @@ async function gitNumstat(cwd, opts2 = {}) {
5438
5441
  if (opts2.includeUntracked) {
5439
5442
  try {
5440
5443
  const { stdout } = await execFileAsync("git", ["ls-files", "--others", "--exclude-standard"], { cwd, timeout: 5e3 });
5441
- const { readFile: readFile36, stat: stat13 } = await import("fs/promises");
5442
- const { join: join57 } = await import("path");
5444
+ const { readFile: readFile37, stat: stat14 } = await import("fs/promises");
5445
+ const { join: join58 } = await import("path");
5443
5446
  for (const file of stdout.split("\n").filter(Boolean)) {
5444
5447
  let lines = 0;
5445
5448
  try {
5446
- const path = join57(cwd, file);
5447
- const size = (await stat13(path)).size;
5449
+ const path = join58(cwd, file);
5450
+ const size = (await stat14(path)).size;
5448
5451
  if (size > 0 && size <= 1024 * 1024) {
5449
- const text = await readFile36(path, "utf8");
5452
+ const text = await readFile37(path, "utf8");
5450
5453
  lines = text.split("\n").length - (text.endsWith("\n") ? 1 : 0);
5451
5454
  }
5452
5455
  } catch {
@@ -6048,11 +6051,11 @@ Not in this API \u2014 call these as separate tools instead: ${directTools.map((
6048
6051
  opts2.callbacks.onToolCallArgs?.(ev.index, ev.argsDelta);
6049
6052
  break;
6050
6053
  case "tool_call_complete": {
6051
- const safeArgs = validateToolArguments(ev.arguments);
6054
+ const callArgs = validateToolArguments(ev.arguments, ev.name, ev.id, ev.finishReason, opts2.sessionId);
6052
6055
  const call = {
6053
6056
  id: ev.id,
6054
6057
  type: "function",
6055
- function: { name: normalizeToolName(ev.name, opts2.tools), arguments: safeArgs }
6058
+ function: { name: normalizeToolName(ev.name, opts2.tools), arguments: callArgs }
6056
6059
  };
6057
6060
  toolCalls.push(call);
6058
6061
  tr.toolsUsed.push(call.function.name);
@@ -6901,14 +6904,29 @@ function replaceMessagesInPlace(target, next) {
6901
6904
  function normalizeToolName(name, tools) {
6902
6905
  return name === "spawn_worker" && tools.some((t) => t.name === "subagent") ? "subagent" : name;
6903
6906
  }
6904
- function validateToolArguments(raw) {
6905
- if (!raw || !raw.trim()) return "{}";
6906
- try {
6907
- JSON.parse(raw);
6908
- return raw;
6909
- } catch {
6910
- return "{}";
6907
+ function validateToolArguments(raw, name, id, finishReason, sessionId) {
6908
+ let issue = null;
6909
+ if (!raw.trim()) {
6910
+ issue = "empty arguments";
6911
+ } else {
6912
+ try {
6913
+ const parsed = JSON.parse(raw);
6914
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) issue = "arguments must be a JSON object";
6915
+ } catch (error) {
6916
+ issue = error instanceof Error ? error.message : "invalid JSON";
6917
+ }
6918
+ }
6919
+ if (issue) {
6920
+ logger.warn("turn:tool_arguments_invalid", {
6921
+ sessionId,
6922
+ tool: name,
6923
+ toolCallId: id,
6924
+ argumentBytes: Buffer.byteLength(raw, "utf8"),
6925
+ finishReason,
6926
+ issue
6927
+ });
6911
6928
  }
6929
+ return raw;
6912
6930
  }
6913
6931
  function llmAuthOf(opts2) {
6914
6932
  return {
@@ -7813,15 +7831,15 @@ function makeErrorOutput(message2) {
7813
7831
  return { content: message2, rawBytes: bytes, reducedBytes: bytes };
7814
7832
  }
7815
7833
  async function execOnce(command, cwd) {
7816
- return new Promise((resolve19) => {
7834
+ return new Promise((resolve20) => {
7817
7835
  const child = spawn("bash", ["-lc", command], { cwd });
7818
7836
  let out = "";
7819
7837
  child.stdout.on("data", (d) => {
7820
7838
  out += d.toString("utf8");
7821
7839
  });
7822
7840
  child.on("close", (code) => {
7823
- if (code !== 0) return resolve19(void 0);
7824
- resolve19(out.trim() || void 0);
7841
+ if (code !== 0) return resolve20(void 0);
7842
+ resolve20(out.trim() || void 0);
7825
7843
  });
7826
7844
  });
7827
7845
  }
@@ -7975,7 +7993,7 @@ async function runBash(args, ctx) {
7975
7993
  if (pushGuard) return pushGuard;
7976
7994
  const { shell, args: shellArgs, isPosix } = getShellCommand(ctx.shell);
7977
7995
  const { command, env: coauthorEnv } = isPosix ? injectCoauthor(args.command, ctx.coauthor) : { command: args.command, env: {} };
7978
- return new Promise((resolve19, reject) => {
7996
+ return new Promise((resolve20, reject) => {
7979
7997
  logger.debug("bash:spawn", { command: args.command.slice(0, 200), cwd: ctx.cwd, shell });
7980
7998
  const child = spawn(shell, [...shellArgs, command], {
7981
7999
  cwd: ctx.cwd,
@@ -8040,7 +8058,7 @@ ${stderr}`
8040
8058
  if (hint) parts.push(hint);
8041
8059
  }
8042
8060
  const raw = parts.join("\n");
8043
- resolve19({
8061
+ resolve20({
8044
8062
  content: raw,
8045
8063
  rawBytes: Buffer.byteLength(raw, "utf8"),
8046
8064
  reducedBytes: Buffer.byteLength(raw, "utf8"),
@@ -9438,7 +9456,7 @@ import { tmpdir as tmpdir2 } from "os";
9438
9456
  import { join as join19, dirname as dirname8 } from "path";
9439
9457
  async function autoScroll(page) {
9440
9458
  await page.evaluate(async () => {
9441
- await new Promise((resolve19) => {
9459
+ await new Promise((resolve20) => {
9442
9460
  let totalHeight = 0;
9443
9461
  const distance = 300;
9444
9462
  const timer3 = setInterval(() => {
@@ -9447,12 +9465,12 @@ async function autoScroll(page) {
9447
9465
  totalHeight += distance;
9448
9466
  if (totalHeight >= scrollHeight) {
9449
9467
  clearInterval(timer3);
9450
- resolve19();
9468
+ resolve20();
9451
9469
  }
9452
9470
  }, 100);
9453
9471
  setTimeout(() => {
9454
9472
  clearInterval(timer3);
9455
- resolve19();
9473
+ resolve20();
9456
9474
  }, 1e4);
9457
9475
  });
9458
9476
  });
@@ -9551,6 +9569,288 @@ var init_browser = __esm({
9551
9569
  }
9552
9570
  });
9553
9571
 
9572
+ // src/util/open-browser.ts
9573
+ import { spawn as spawn2 } from "child_process";
9574
+ import { platform as platform3 } from "os";
9575
+ function openBrowser(url) {
9576
+ if (process.env.KIMIFLARE_NO_BROWSER === "1" || process.env.BROWSER === "none") return false;
9577
+ try {
9578
+ const os2 = platform3();
9579
+ const [cmd, args] = os2 === "darwin" ? ["open", [url]] : os2 === "win32" ? ["cmd", ["/c", "start", "", url]] : ["xdg-open", [url]];
9580
+ const child = spawn2(cmd, args, { detached: true, stdio: "ignore" });
9581
+ child.on("error", () => void 0);
9582
+ child.unref();
9583
+ return true;
9584
+ } catch {
9585
+ return false;
9586
+ }
9587
+ }
9588
+ var init_open_browser = __esm({
9589
+ "src/util/open-browser.ts"() {
9590
+ "use strict";
9591
+ }
9592
+ });
9593
+
9594
+ // src/tools/html-artifact.ts
9595
+ import { chmod as chmod2, lstat as lstat2, mkdir as mkdir9, mkdtemp, readFile as readFile11, readdir as readdir4, realpath as realpath2, rm as rm2, stat as stat5, writeFile as writeFile10 } from "fs/promises";
9596
+ import { execFileSync } from "child_process";
9597
+ import { tmpdir as tmpdir3 } from "os";
9598
+ import { isAbsolute as isAbsolute2, join as join20, relative as relative3, resolve as resolve3, sep as sep2 } from "path";
9599
+ import { pathToFileURL as pathToFileURL2 } from "url";
9600
+ async function createHtmlArtifactFromFile(args, cwd, options = {}) {
9601
+ assertArtifactSourceArgs(args);
9602
+ const workspaceRoot = await getWorkspaceRoot(cwd);
9603
+ const workspaceReal = await realpath2(workspaceRoot);
9604
+ const inputPath = resolvePath(cwd, args.sourcePath);
9605
+ let inputReal;
9606
+ try {
9607
+ inputReal = await realpath2(inputPath);
9608
+ } catch (error) {
9609
+ if (error.code === "ENOENT") {
9610
+ throw new ToolError({
9611
+ code: "not_found",
9612
+ message: `Artifact source file not found: ${args.sourcePath}`,
9613
+ suggestion: "Use the write tool to create the complete HTML file first, then pass its path as sourcePath."
9614
+ });
9615
+ }
9616
+ throw error;
9617
+ }
9618
+ if (!isWithin(workspaceReal, inputReal)) {
9619
+ throw new ToolError({
9620
+ code: "policy_rejection",
9621
+ message: "Artifact sourcePath must resolve to a file inside the current workspace.",
9622
+ suggestion: "Write the HTML file inside the workspace and retry with its workspace-relative path."
9623
+ });
9624
+ }
9625
+ const info = await stat5(inputReal);
9626
+ if (!info.isFile()) {
9627
+ throw new ToolError({ code: "invalid_args", message: "Artifact sourcePath must be a regular HTML file." });
9628
+ }
9629
+ if (info.size > MAX_ARTIFACT_HTML_LENGTH * 4) {
9630
+ throw new ToolError({ code: "invalid_args", message: `Artifact HTML exceeds ${MAX_ARTIFACT_HTML_LENGTH} characters.` });
9631
+ }
9632
+ const html = await readFile11(inputReal, "utf8");
9633
+ return createHtmlArtifact({ title: args.title, html }, cwd, options);
9634
+ }
9635
+ async function createHtmlArtifact(args, cwd, options = {}) {
9636
+ assertArtifactHtmlArgs(args);
9637
+ const rootDir = options.rootDir ?? join20(tmpdir3(), ARTIFACT_ROOT);
9638
+ const workspaceRoot = await getWorkspaceRoot(cwd);
9639
+ const workspaceReal = await realpath2(workspaceRoot);
9640
+ if (isWithin(workspaceReal, resolve3(rootDir))) {
9641
+ throw new Error("Refusing to store an artifact inside the workspace: " + rootDir);
9642
+ }
9643
+ await ensureSecureRoot(rootDir);
9644
+ const rootReal = await realpath2(rootDir);
9645
+ if (isWithin(workspaceReal, rootReal)) {
9646
+ throw new Error("Refusing to store an artifact inside the workspace: " + rootReal);
9647
+ }
9648
+ await cleanupOldArtifacts(rootDir, (options.now ?? Date.now)());
9649
+ const artifactDir = await mkdtemp(join20(rootDir, ARTIFACT_PREFIX));
9650
+ await chmod2(artifactDir, 448);
9651
+ const filePath = join20(artifactDir, "index.html");
9652
+ await writeFile10(filePath, buildArtifactHtml(args.title, args.html), {
9653
+ encoding: "utf8",
9654
+ flag: "wx",
9655
+ mode: 384
9656
+ });
9657
+ const opened = (options.open ?? openBrowser)(pathToFileURL2(filePath).href);
9658
+ const status = opened ? "Opened in your browser." : "Could not open a browser automatically.";
9659
+ return "Artifact: " + args.title + "\n" + status + "\nTemporary file: " + filePath;
9660
+ }
9661
+ async function cleanupOldArtifacts(rootDir, now2 = Date.now()) {
9662
+ let entries;
9663
+ try {
9664
+ entries = await readdir4(rootDir, { withFileTypes: true });
9665
+ } catch {
9666
+ return;
9667
+ }
9668
+ for (const entry of entries) {
9669
+ if (!entry.name.startsWith(ARTIFACT_PREFIX) || !entry.isDirectory() || entry.isSymbolicLink()) continue;
9670
+ const path = join20(rootDir, entry.name);
9671
+ try {
9672
+ const info = await lstat2(path);
9673
+ if (!info.isDirectory() || info.isSymbolicLink() || now2 - info.mtimeMs < ARTIFACT_MAX_AGE_MS) continue;
9674
+ await rm2(path, { recursive: true, force: true });
9675
+ } catch {
9676
+ }
9677
+ }
9678
+ }
9679
+ function buildArtifactHtml(title, html) {
9680
+ assertArtifactHtmlArgs({ title, html });
9681
+ const safeTitle = escapeHtml(title);
9682
+ const safeSrcdoc = escapeAttribute(html);
9683
+ const lines = [
9684
+ "<!doctype html>",
9685
+ '<html lang="en">',
9686
+ "<head>",
9687
+ ' <meta charset="utf-8">',
9688
+ ' <meta name="viewport" content="width=device-width, initial-scale=1">',
9689
+ ' <meta name="theme-color" content="#090909">',
9690
+ " <title>" + safeTitle + " \xB7 Autopilot</title>",
9691
+ " <style>",
9692
+ ' :root { color-scheme: dark; font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; }',
9693
+ " * { box-sizing: border-box; }",
9694
+ " html, body { width: 100%; height: 100%; margin: 0; }",
9695
+ " body { display: grid; grid-template-rows: auto minmax(0, 1fr); overflow: hidden; background: #090909; color: #f4f4f5; }",
9696
+ " .autopilot-bar { position: sticky; top: 0; z-index: 10; display: flex; min-height: 54px; align-items: center; justify-content: space-between; gap: 16px; padding: 0 22px; border-bottom: 1px solid #262626; background: rgba(9, 9, 9, .96); backdrop-filter: blur(12px); }",
9697
+ " .autopilot-brand { display: inline-flex; align-items: center; gap: 9px; color: #f5f5f5; font-size: 14px; font-weight: 650; letter-spacing: -.025em; text-decoration: none; }",
9698
+ " .autopilot-mark { width: 20px; height: 20px; flex: none; }",
9699
+ " .autopilot-actions { display: flex; align-items: center; gap: 16px; }",
9700
+ " .autopilot-actions a { color: #a3a3a3; font-size: 12px; text-decoration: none; transition: color .15s ease; }",
9701
+ " .autopilot-actions a:hover { color: #fff; }",
9702
+ " .autopilot-actions .star { padding: 7px 11px; border: 1px solid #343434; border-radius: 7px; color: #f0f0f0; }",
9703
+ " .autopilot-actions .star:hover { border-color: #ff9933; color: #ffb15c; }",
9704
+ " main { min-width: 0; min-height: 0; }",
9705
+ " iframe { display: block; width: 100%; height: 100%; border: 0; background: #fff; }",
9706
+ " @media (max-width: 520px) { .autopilot-bar { min-height: 48px; padding: 0 14px; } .autopilot-actions { gap: 10px; } .autopilot-actions a { font-size: 11px; } }",
9707
+ " </style>",
9708
+ "</head>",
9709
+ "<body>",
9710
+ ' <header class="autopilot-bar">',
9711
+ ' <a class="autopilot-brand" href="' + AUTOPILOT_URL + '" target="_blank" rel="noopener noreferrer" aria-label="Autopilot on GitHub">',
9712
+ ' <svg class="autopilot-mark" viewBox="0 0 24 24" role="img" aria-label="Autopilot logo" xmlns="http://www.w3.org/2000/svg">',
9713
+ ' <path fill="#ff9933" d="M12 1.8a10.2 10.2 0 1 0 10.2 10.2A10.21 10.21 0 0 0 12 1.8Zm0 2.3a7.9 7.9 0 1 1 0 15.8 7.9 7.9 0 0 1 0-15.8Z"/>',
9714
+ ' <path fill="#ff9933" d="m6.9 16.8 4.3-9.6c.3-.7 1.3-.7 1.6 0l4.3 9.6h-2.5l-2.6-6-2.6 6H6.9Z"/>',
9715
+ " </svg>",
9716
+ " <span>autopilot</span>",
9717
+ " </a>",
9718
+ ' <nav class="autopilot-actions" aria-label="Autopilot links">',
9719
+ ' <a href="' + AUTOPILOT_URL + '" target="_blank" rel="noopener noreferrer">About Autopilot \u2197</a>',
9720
+ ' <a class="star" href="' + AUTOPILOT_URL + '" target="_blank" rel="noopener noreferrer" aria-label="Star Autopilot on GitHub">\u2606 Star on GitHub</a>',
9721
+ " </nav>",
9722
+ " </header>",
9723
+ ' <main><iframe title="' + escapeAttribute(title) + '" sandbox="allow-scripts" srcdoc="' + safeSrcdoc + '"></iframe></main>',
9724
+ "</body>",
9725
+ "</html>"
9726
+ ];
9727
+ return lines.join("\n") + "\n";
9728
+ }
9729
+ function assertArtifactSourceArgs(value) {
9730
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
9731
+ throw new ToolError({
9732
+ code: "invalid_args",
9733
+ recoverable: true,
9734
+ message: "Invalid create_artifact arguments: expected an object with a title and sourcePath.",
9735
+ suggestion: "Use write to save the complete HTML file in the workspace, then pass its path as sourcePath."
9736
+ });
9737
+ }
9738
+ const args = value;
9739
+ const issues = [];
9740
+ if (typeof args.title !== "string" || args.title.trim().length === 0 || args.title.length > MAX_ARTIFACT_TITLE_LENGTH) {
9741
+ issues.push(`title must be a non-empty string of at most ${MAX_ARTIFACT_TITLE_LENGTH} characters`);
9742
+ }
9743
+ if (typeof args.sourcePath !== "string" || args.sourcePath.trim().length === 0) {
9744
+ issues.push("sourcePath must be a non-empty path to an HTML file created with write");
9745
+ }
9746
+ if (issues.length > 0) {
9747
+ throw new ToolError({
9748
+ code: "invalid_args",
9749
+ recoverable: true,
9750
+ message: `Invalid create_artifact arguments: ${issues.join("; ")}.`,
9751
+ suggestion: "Use write to save the complete HTML file in the workspace, then call create_artifact with its title and sourcePath."
9752
+ });
9753
+ }
9754
+ }
9755
+ function assertArtifactHtmlArgs(value) {
9756
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
9757
+ throw new ToolError({
9758
+ code: "invalid_args",
9759
+ recoverable: true,
9760
+ message: "Invalid artifact content: expected an object with a title and HTML document.",
9761
+ suggestion: "Provide a non-empty title and complete HTML content."
9762
+ });
9763
+ }
9764
+ const args = value;
9765
+ const issues = [];
9766
+ if (typeof args.title !== "string" || args.title.trim().length === 0 || args.title.length > MAX_ARTIFACT_TITLE_LENGTH) {
9767
+ issues.push(`title must be a non-empty string of at most ${MAX_ARTIFACT_TITLE_LENGTH} characters`);
9768
+ }
9769
+ if (typeof args.html !== "string" || args.html.trim().length === 0 || args.html.length > MAX_ARTIFACT_HTML_LENGTH) {
9770
+ issues.push(`html must be a non-empty string of at most ${MAX_ARTIFACT_HTML_LENGTH} characters`);
9771
+ }
9772
+ if (issues.length > 0) {
9773
+ throw new ToolError({
9774
+ code: "invalid_args",
9775
+ recoverable: true,
9776
+ message: `Invalid artifact content: ${issues.join("; ")}.`,
9777
+ suggestion: "Supply a non-empty title and complete HTML document."
9778
+ });
9779
+ }
9780
+ }
9781
+ async function ensureSecureRoot(rootDir) {
9782
+ await mkdir9(rootDir, { recursive: true, mode: 448 });
9783
+ const info = await lstat2(rootDir);
9784
+ if (!info.isDirectory() || info.isSymbolicLink()) throw new Error("Artifact storage path is not a real directory: " + rootDir);
9785
+ if (typeof process.getuid === "function" && info.uid !== process.getuid()) {
9786
+ throw new Error("Artifact storage directory is not owned by the current user: " + rootDir);
9787
+ }
9788
+ if ((info.mode & 63) !== 0) await chmod2(rootDir, 448);
9789
+ }
9790
+ async function getWorkspaceRoot(cwd) {
9791
+ try {
9792
+ return execFileSync("git", ["rev-parse", "--show-toplevel"], {
9793
+ cwd,
9794
+ encoding: "utf8",
9795
+ stdio: ["ignore", "pipe", "ignore"]
9796
+ }).trim();
9797
+ } catch {
9798
+ return cwd;
9799
+ }
9800
+ }
9801
+ function isWithin(parent, candidate) {
9802
+ const rel = relative3(parent, candidate);
9803
+ return rel === "" || rel !== ".." && !rel.startsWith(".." + sep2) && !isAbsolute2(rel);
9804
+ }
9805
+ function escapeHtml(value) {
9806
+ return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
9807
+ }
9808
+ function escapeAttribute(value) {
9809
+ return escapeHtml(value).replaceAll('"', "&quot;").replaceAll("'", "&#39;");
9810
+ }
9811
+ var ARTIFACT_ROOT, ARTIFACT_PREFIX, ARTIFACT_MAX_AGE_MS, AUTOPILOT_URL, MAX_ARTIFACT_TITLE_LENGTH, MAX_ARTIFACT_HTML_LENGTH, htmlArtifactTool;
9812
+ var init_html_artifact = __esm({
9813
+ "src/tools/html-artifact.ts"() {
9814
+ "use strict";
9815
+ init_paths2();
9816
+ init_open_browser();
9817
+ init_tool_error();
9818
+ ARTIFACT_ROOT = "autopilot-artifacts";
9819
+ ARTIFACT_PREFIX = "artifact-";
9820
+ ARTIFACT_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1e3;
9821
+ AUTOPILOT_URL = "https://github.com/sinameraji/autopilot";
9822
+ MAX_ARTIFACT_TITLE_LENGTH = 160;
9823
+ MAX_ARTIFACT_HTML_LENGTH = 1e6;
9824
+ htmlArtifactTool = {
9825
+ name: "create_artifact",
9826
+ description: "Open a polished standalone HTML artifact in the user's browser. First use the normal write tool to save the complete HTML document as a local .html file in the workspace. Then call create_artifact with its title and sourcePath; do not pass the full HTML as a tool argument. The source file is kept in the workspace, and a branded, sandboxed browser copy is stored outside the project. Use for visual or interactive deliverables, dashboards, diagrams, prototypes, and substantial structured reports\u2014not short answers, explanations, code snippets, or routine code changes.",
9827
+ parameters: {
9828
+ type: "object",
9829
+ properties: {
9830
+ title: {
9831
+ type: "string",
9832
+ description: "Non-empty, short human-readable artifact title."
9833
+ },
9834
+ sourcePath: {
9835
+ type: "string",
9836
+ description: "Workspace-relative path to the complete HTML file already created with the write tool."
9837
+ }
9838
+ },
9839
+ required: ["title", "sourcePath"],
9840
+ additionalProperties: false
9841
+ },
9842
+ needsPermission: true,
9843
+ render: (args) => ({
9844
+ title: "create artifact: " + String(args.title ?? "Missing title").slice(0, 80),
9845
+ body: `Read ${String(args.sourcePath ?? "Missing sourcePath")} \xB7 opens in your browser`
9846
+ }),
9847
+ async run(args, ctx) {
9848
+ return createHtmlArtifactFromFile(args, ctx.cwd);
9849
+ }
9850
+ };
9851
+ }
9852
+ });
9853
+
9554
9854
  // src/tools/tasks.ts
9555
9855
  var tasksSetTool;
9556
9856
  var init_tasks = __esm({
@@ -9766,9 +10066,9 @@ var init_memory = __esm({
9766
10066
 
9767
10067
  // src/tools/hotcell-snapshot.ts
9768
10068
  import { execFile as execFile4 } from "child_process";
9769
- import { mkdtemp, rm as rm2 } from "fs/promises";
9770
- import { tmpdir as tmpdir3 } from "os";
9771
- import { join as join20 } from "path";
10069
+ import { mkdtemp as mkdtemp2, rm as rm3 } from "fs/promises";
10070
+ import { tmpdir as tmpdir4 } from "os";
10071
+ import { join as join21 } from "path";
9772
10072
  import { promisify as promisify4 } from "util";
9773
10073
  async function git(args, cwd, env2) {
9774
10074
  const { stdout } = await execFileAsync2("git", args, {
@@ -9816,9 +10116,9 @@ async function getRepositorySnapshot(cwd) {
9816
10116
  if (!ref) {
9817
10117
  throw new Error("Could not find an origin branch containing the base commit. Run git fetch, then retry.");
9818
10118
  }
9819
- const scratch = await mkdtemp(join20(tmpdir3(), "autopilot-snapshot-"));
10119
+ const scratch = await mkdtemp2(join21(tmpdir4(), "autopilot-snapshot-"));
9820
10120
  try {
9821
- const env2 = { GIT_INDEX_FILE: join20(scratch, "index") };
10121
+ const env2 = { GIT_INDEX_FILE: join21(scratch, "index") };
9822
10122
  await git(["read-tree", "HEAD"], root, env2);
9823
10123
  await git(["add", "-A", "--", ".", ...SECRET_EXCLUDES], root, env2);
9824
10124
  const tree = (await git(["write-tree"], root, env2)).trim();
@@ -9837,15 +10137,15 @@ async function getRepositorySnapshot(cwd) {
9837
10137
  }
9838
10138
  return { url, ref, commit, patch: patch.toString("base64"), changedFiles: names.length };
9839
10139
  } finally {
9840
- await rm2(scratch, { recursive: true, force: true });
10140
+ await rm3(scratch, { recursive: true, force: true });
9841
10141
  }
9842
10142
  }
9843
10143
  async function getWorkingTreeArchive(cwd, limitBytes = MAX_ARCHIVE_BYTES) {
9844
10144
  const root = (await git(["rev-parse", "--show-toplevel"], cwd).catch(() => "")).trim();
9845
10145
  if (!root) throw new Error("Subagents need to run inside a Git repository.");
9846
- const scratch = await mkdtemp(join20(tmpdir3(), "autopilot-archive-"));
10146
+ const scratch = await mkdtemp2(join21(tmpdir4(), "autopilot-archive-"));
9847
10147
  try {
9848
- const env2 = { GIT_INDEX_FILE: join20(scratch, "index") };
10148
+ const env2 = { GIT_INDEX_FILE: join21(scratch, "index") };
9849
10149
  const hasHead = await git(["rev-parse", "--verify", "-q", "HEAD"], root).then(() => true, () => false);
9850
10150
  await git(hasHead ? ["read-tree", "HEAD"] : ["read-tree", "--empty"], root, env2);
9851
10151
  await git(["add", "-A", "--", ".", ...SECRET_EXCLUDES], root, env2);
@@ -9859,7 +10159,7 @@ async function getWorkingTreeArchive(cwd, limitBytes = MAX_ARCHIVE_BYTES) {
9859
10159
  bytes: tarball.byteLength
9860
10160
  };
9861
10161
  } finally {
9862
- await rm2(scratch, { recursive: true, force: true });
10162
+ await rm3(scratch, { recursive: true, force: true });
9863
10163
  }
9864
10164
  }
9865
10165
  function chunkPayload(base64, chunkSize = PAYLOAD_CHUNK_CHARS) {
@@ -9893,23 +10193,23 @@ var init_hotcell_snapshot = __esm({
9893
10193
  });
9894
10194
 
9895
10195
  // src/tools/hotcell-worker-cache.ts
9896
- import { mkdir as mkdir9, readFile as readFile11, writeFile as writeFile10 } from "fs/promises";
10196
+ import { mkdir as mkdir10, readFile as readFile12, writeFile as writeFile11 } from "fs/promises";
9897
10197
  import { homedir as homedir11 } from "os";
9898
- import { dirname as dirname9, join as join21 } from "path";
10198
+ import { dirname as dirname9, join as join22 } from "path";
9899
10199
  function workerCachePath() {
9900
- const xdg = process.env.XDG_CONFIG_HOME || join21(homedir11(), ".config");
9901
- return join21(xdg, "kimiflare", "hotcell-worker-cache.json");
10200
+ const xdg = process.env.XDG_CONFIG_HOME || join22(homedir11(), ".config");
10201
+ return join22(xdg, "kimiflare", "hotcell-worker-cache.json");
9902
10202
  }
9903
10203
  async function readCache2() {
9904
10204
  try {
9905
- return JSON.parse(await readFile11(workerCachePath(), "utf8"));
10205
+ return JSON.parse(await readFile12(workerCachePath(), "utf8"));
9906
10206
  } catch {
9907
10207
  return {};
9908
10208
  }
9909
10209
  }
9910
10210
  async function writeCache2(cache) {
9911
- await mkdir9(dirname9(workerCachePath()), { recursive: true });
9912
- await writeFile10(workerCachePath(), JSON.stringify(cache, null, 2) + "\n", { mode: 384 });
10211
+ await mkdir10(dirname9(workerCachePath()), { recursive: true });
10212
+ await writeFile11(workerCachePath(), JSON.stringify(cache, null, 2) + "\n", { mode: 384 });
9913
10213
  }
9914
10214
  function ensureWorkerBackup(opts2) {
9915
10215
  const existing = inflight.get(opts2.packageSpec);
@@ -9969,13 +10269,13 @@ var init_hotcell_worker_cache = __esm({
9969
10269
  });
9970
10270
 
9971
10271
  // src/tools/hotcell-worker.ts
9972
- import { spawn as spawn2 } from "child_process";
10272
+ import { spawn as spawn3 } from "child_process";
9973
10273
  import { promisify as promisify5 } from "util";
9974
10274
  import { execFile as execFile5 } from "child_process";
9975
- import { resolve as resolve3 } from "path";
10275
+ import { resolve as resolve4 } from "path";
9976
10276
  async function runHotcellWorker(options) {
9977
10277
  const workerId = `hotcell-${crypto.randomUUID().slice(0, 8)}`;
9978
- const cwd = resolve3(options.cwd ?? process.cwd());
10278
+ const cwd = resolve4(options.cwd ?? process.cwd());
9979
10279
  const model = options.model.trim();
9980
10280
  if (!model) throw new Error("Hotcell workers require the coordinator's explicit model ID.");
9981
10281
  validateModelId(model);
@@ -10283,7 +10583,7 @@ function parsePrintOutput(stdout) {
10283
10583
  async function runProcess(executable, args, options) {
10284
10584
  if (options.signal?.aborted) return { code: 130, stdout: "", stderr: "", aborted: true };
10285
10585
  return await new Promise((resolvePromise, reject) => {
10286
- const child = spawn2(executable, args, { cwd: options.cwd, stdio: ["ignore", "pipe", "pipe"] });
10586
+ const child = spawn3(executable, args, { cwd: options.cwd, stdio: ["ignore", "pipe", "pipe"] });
10287
10587
  const stdout = [];
10288
10588
  const stderr = [];
10289
10589
  let bytes = 0;
@@ -10515,17 +10815,17 @@ var init_worker_registry = __esm({
10515
10815
  });
10516
10816
 
10517
10817
  // src/tools/subagent-stats.ts
10518
- import { appendFile as appendFile2, mkdir as mkdir10, readFile as readFile12 } from "fs/promises";
10818
+ import { appendFile as appendFile2, mkdir as mkdir11, readFile as readFile13 } from "fs/promises";
10519
10819
  import { homedir as homedir12 } from "os";
10520
- import { dirname as dirname10, join as join22 } from "path";
10820
+ import { dirname as dirname10, join as join23 } from "path";
10521
10821
  function subagentStatsPath() {
10522
- const xdg = process.env.XDG_DATA_HOME || join22(homedir12(), ".local", "share");
10523
- return join22(xdg, "kimiflare", "subagents.jsonl");
10822
+ const xdg = process.env.XDG_DATA_HOME || join23(homedir12(), ".local", "share");
10823
+ return join23(xdg, "kimiflare", "subagents.jsonl");
10524
10824
  }
10525
10825
  async function recordSubagentEvent(event) {
10526
10826
  const path = subagentStatsPath();
10527
10827
  try {
10528
- await mkdir10(dirname10(path), { recursive: true });
10828
+ await mkdir11(dirname10(path), { recursive: true });
10529
10829
  await appendFile2(path, JSON.stringify(event) + "\n");
10530
10830
  } catch (error) {
10531
10831
  logger.debug("subagents:stats_write_failed", { error: String(error) });
@@ -10545,7 +10845,7 @@ function failureReason(error) {
10545
10845
  async function readSubagentStats(days = 7, now2 = Date.now()) {
10546
10846
  let raw = "";
10547
10847
  try {
10548
- raw = await readFile12(subagentStatsPath(), "utf8");
10848
+ raw = await readFile13(subagentStatsPath(), "utf8");
10549
10849
  } catch {
10550
10850
  }
10551
10851
  const since = now2 - days * 24 * 60 * 60 * 1e3;
@@ -11439,18 +11739,18 @@ var init_expand_artifact = __esm({
11439
11739
 
11440
11740
  // src/jobs/manager.ts
11441
11741
  import Database from "better-sqlite3";
11442
- import { spawn as spawn3, execFileSync } from "child_process";
11742
+ import { spawn as spawn4, execFileSync as execFileSync2 } from "child_process";
11443
11743
  import { mkdirSync as mkdirSync5, openSync, readFileSync as readFileSync4, readSync, existsSync as existsSync4, statSync as statSync3, closeSync, rmSync } from "fs";
11444
11744
  import { homedir as homedir13 } from "os";
11445
- import { dirname as dirname11, join as join23 } from "path";
11745
+ import { dirname as dirname11, join as join24 } from "path";
11446
11746
  import { randomUUID as randomUUID4 } from "crypto";
11447
11747
  function defaultJobDbPath() {
11448
- const root = process.env.XDG_STATE_HOME || join23(homedir13(), ".local", "state");
11449
- return process.env.AUTOPILOT_JOBS_DB || join23(root, "autopilot", "jobs.db");
11748
+ const root = process.env.XDG_STATE_HOME || join24(homedir13(), ".local", "state");
11749
+ return process.env.AUTOPILOT_JOBS_DB || join24(root, "autopilot", "jobs.db");
11450
11750
  }
11451
11751
  function isProcessGroupAlive(pgid) {
11452
11752
  try {
11453
- const rows = execFileSync("ps", ["-axo", "pgid=,state="], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
11753
+ const rows = execFileSync2("ps", ["-axo", "pgid=,state="], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
11454
11754
  return rows.split("\n").some((line) => {
11455
11755
  const match = line.trim().match(/^(\d+)\s+(\S+)/);
11456
11756
  return match?.[1] === String(pgid) && !match[2].startsWith("Z");
@@ -11476,22 +11776,22 @@ function waitForProcessStartTime(pid, jobId, exitPath) {
11476
11776
  function readProcessStartTime(pid) {
11477
11777
  if (process.platform === "linux") {
11478
11778
  try {
11479
- const stat13 = readFileSync4(`/proc/${pid}/stat`, "utf8");
11480
- const fieldsAfterCommand = stat13.slice(stat13.lastIndexOf(")") + 1).trim().split(/\s+/);
11779
+ const stat14 = readFileSync4(`/proc/${pid}/stat`, "utf8");
11780
+ const fieldsAfterCommand = stat14.slice(stat14.lastIndexOf(")") + 1).trim().split(/\s+/);
11481
11781
  return fieldsAfterCommand[19] ? `linux:${fieldsAfterCommand[19]}` : null;
11482
11782
  } catch {
11483
11783
  return null;
11484
11784
  }
11485
11785
  }
11486
11786
  try {
11487
- return execFileSync("ps", ["-o", "lstart=", "-o", "command=", "-p", String(pid)], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim() || null;
11787
+ return execFileSync2("ps", ["-o", "lstart=", "-o", "command=", "-p", String(pid)], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim() || null;
11488
11788
  } catch {
11489
11789
  return null;
11490
11790
  }
11491
11791
  }
11492
11792
  function isZombie(pid) {
11493
11793
  try {
11494
- const state = execFileSync("ps", ["-o", "state=", "-p", String(pid)], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
11794
+ const state = execFileSync2("ps", ["-o", "state=", "-p", String(pid)], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
11495
11795
  return state.startsWith("Z");
11496
11796
  } catch {
11497
11797
  return true;
@@ -11590,7 +11890,7 @@ child.on('close', (code, signal) => {
11590
11890
  jobsDir;
11591
11891
  constructor(dbPath = defaultJobDbPath()) {
11592
11892
  mkdirSync5(dirname11(dbPath), { recursive: true, mode: 448 });
11593
- this.jobsDir = join23(dirname11(dbPath), "jobs");
11893
+ this.jobsDir = join24(dirname11(dbPath), "jobs");
11594
11894
  mkdirSync5(this.jobsDir, { recursive: true, mode: 448 });
11595
11895
  this.db = new Database(dbPath);
11596
11896
  this.db.pragma("journal_mode = WAL");
@@ -11641,13 +11941,13 @@ child.on('close', (code, signal) => {
11641
11941
  if (existing) return toJobRecord(existing);
11642
11942
  }
11643
11943
  const id = randomUUID4();
11644
- const jobDir = join23(this.jobsDir, id);
11944
+ const jobDir = join24(this.jobsDir, id);
11645
11945
  mkdirSync5(jobDir, { recursive: true, mode: 448 });
11646
11946
  const paths = {
11647
- stdoutPath: join23(jobDir, "stdout.log"),
11648
- stderrPath: join23(jobDir, "stderr.log"),
11649
- exitPath: join23(jobDir, "exit.json"),
11650
- pidPath: join23(jobDir, "pid")
11947
+ stdoutPath: join24(jobDir, "stdout.log"),
11948
+ stderrPath: join24(jobDir, "stderr.log"),
11949
+ exitPath: join24(jobDir, "exit.json"),
11950
+ pidPath: join24(jobDir, "pid")
11651
11951
  };
11652
11952
  const now2 = Date.now();
11653
11953
  try {
@@ -11671,7 +11971,7 @@ child.on('close', (code, signal) => {
11671
11971
  timeoutMs: options.timeoutMs ?? null,
11672
11972
  ...paths
11673
11973
  });
11674
- const child = spawn3(process.execPath, ["--input-type=module", "-e", JOB_WRAPPER, spec], {
11974
+ const child = spawn4(process.execPath, ["--input-type=module", "-e", JOB_WRAPPER, spec], {
11675
11975
  cwd: options.cwd,
11676
11976
  detached: true,
11677
11977
  stdio: "ignore",
@@ -11928,10 +12228,10 @@ import Database2 from "better-sqlite3";
11928
12228
  import { createHash as createHash2, randomUUID as randomUUID5 } from "crypto";
11929
12229
  import { chmodSync, mkdirSync as mkdirSync6 } from "fs";
11930
12230
  import { homedir as homedir14 } from "os";
11931
- import { dirname as dirname12, join as join24 } from "path";
12231
+ import { dirname as dirname12, join as join25 } from "path";
11932
12232
  function defaultRunsDbPath() {
11933
- const root = process.env.XDG_STATE_HOME || join24(homedir14(), ".local", "state");
11934
- return process.env.AUTOPILOT_RUNS_DB || join24(root, "autopilot", "runs.db");
12233
+ const root = process.env.XDG_STATE_HOME || join25(homedir14(), ".local", "state");
12234
+ return process.env.AUTOPILOT_RUNS_DB || join25(root, "autopilot", "runs.db");
11935
12235
  }
11936
12236
  function validateOptionalPositiveInteger(name, value, minimum = 1) {
11937
12237
  if (value !== null && (!Number.isSafeInteger(value) || value < minimum)) {
@@ -12541,8 +12841,8 @@ var init_wait_for = __esm({
12541
12841
  });
12542
12842
 
12543
12843
  // src/tools/executor.ts
12544
- import { realpath as realpath2 } from "fs/promises";
12545
- import { isAbsolute as isAbsolute2, relative as relative3, resolve as resolve4, sep as sep2 } from "path";
12844
+ import { realpath as realpath3 } from "fs/promises";
12845
+ import { isAbsolute as isAbsolute3, relative as relative4, resolve as resolve5, sep as sep3 } from "path";
12546
12846
  function getWorkerTools(profile) {
12547
12847
  return profile === "research" ? ALL_TOOLS.filter((tool) => RESEARCH_WORKER_TOOL_NAMES.has(tool.name) && tool.isReadOnly === true).map(restrictResearchTool) : ALL_TOOLS;
12548
12848
  }
@@ -12563,28 +12863,28 @@ function restrictResearchTool(tool) {
12563
12863
  }
12564
12864
  async function assertResearchPath(pathValue, cwd) {
12565
12865
  if (typeof pathValue !== "string" || !pathValue) throw new Error("Research worker paths must be non-empty strings.");
12566
- const root = await realpath2(cwd);
12567
- const candidate = resolve4(root, pathValue);
12866
+ const root = await realpath3(cwd);
12867
+ const candidate = resolve5(root, pathValue);
12568
12868
  assertInsideResearchRoot(candidate, root);
12569
12869
  assertNoSensitivePath(candidate, root);
12570
- const actual = await realpath2(candidate);
12870
+ const actual = await realpath3(candidate);
12571
12871
  assertInsideResearchRoot(actual, root);
12572
12872
  assertNoSensitivePath(actual, root);
12573
12873
  }
12574
12874
  function assertInsideResearchRoot(path, root) {
12575
- const rel = relative3(root, path);
12576
- if (rel === ".." || rel.startsWith(`..${sep2}`) || isAbsolute2(rel)) {
12875
+ const rel = relative4(root, path);
12876
+ if (rel === ".." || rel.startsWith(`..${sep3}`) || isAbsolute3(rel)) {
12577
12877
  throw new Error("Research workers may only inspect paths inside their cloned repository.");
12578
12878
  }
12579
12879
  }
12580
12880
  function assertNoSensitivePath(path, root) {
12581
- const parts = relative3(root, path).split(sep2).filter(Boolean).map((part) => part.toLowerCase());
12881
+ const parts = relative4(root, path).split(sep3).filter(Boolean).map((part) => part.toLowerCase());
12582
12882
  if (parts.some((part) => part === ".env" || part.startsWith(".env.") || SENSITIVE_RESEARCH_PATHS.has(part))) {
12583
12883
  throw new Error("Research worker access to environment, credential, and VCS metadata paths is blocked.");
12584
12884
  }
12585
12885
  }
12586
12886
  function assertSafePattern(value) {
12587
- if (typeof value !== "string" || !value || isAbsolute2(value)) {
12887
+ if (typeof value !== "string" || !value || isAbsolute3(value)) {
12588
12888
  throw new Error("Research worker glob patterns must be relative to the repository.");
12589
12889
  }
12590
12890
  const parts = value.replaceAll("\\\\", "/").split("/");
@@ -12637,9 +12937,6 @@ function normalizeToolOutput(result2) {
12637
12937
  }
12638
12938
  return result2;
12639
12939
  }
12640
- function truncateForError(s) {
12641
- return s.length <= 200 ? s : `${s.slice(0, 200)}... [${s.length - 200} more chars]`;
12642
- }
12643
12940
  var ALL_TOOLS, RESEARCH_WORKER_TOOL_NAMES, SENSITIVE_RESEARCH_PATHS, HOOK_RESULT_CONTENT_CAP_BYTES, ToolExecutor, TRACE_ARGS_INLINE_MAX, ToolTrace;
12644
12941
  var init_executor = __esm({
12645
12942
  "src/tools/executor.ts"() {
@@ -12658,6 +12955,7 @@ var init_executor = __esm({
12658
12955
  init_github();
12659
12956
  init_changelog_image();
12660
12957
  init_browser();
12958
+ init_html_artifact();
12661
12959
  init_tasks();
12662
12960
  init_memory();
12663
12961
  init_subagent();
@@ -12685,6 +12983,7 @@ var init_executor = __esm({
12685
12983
  githubCreatePrTool,
12686
12984
  { ...changelogImageTool, isReadOnly: true },
12687
12985
  { ...browserFetchTool, isReadOnly: true },
12986
+ htmlArtifactTool,
12688
12987
  tasksSetTool,
12689
12988
  memoryRememberTool,
12690
12989
  { ...memoryRecallTool, isReadOnly: true },
@@ -12783,17 +13082,23 @@ var init_executor = __esm({
12783
13082
  }
12784
13083
  let args;
12785
13084
  try {
12786
- args = call.arguments.trim() ? JSON.parse(call.arguments) : {};
13085
+ if (!call.arguments.trim()) throw new SyntaxError("tool arguments were empty");
13086
+ const parsed = JSON.parse(call.arguments);
13087
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
13088
+ throw new SyntaxError("tool arguments must be a JSON object");
13089
+ }
13090
+ args = parsed;
12787
13091
  } catch (e) {
12788
13092
  tr?.call(null, tool.needsPermission);
13093
+ const artifactSuggestion = call.name === "create_artifact" ? "Use write to save the complete HTML document as a workspace .html file, then call create_artifact with its title and sourcePath." : "Retry with valid JSON object arguments for this tool.";
12789
13094
  return {
12790
13095
  tool_call_id: call.id,
12791
13096
  name: call.name,
12792
- content: `Error: invalid JSON arguments for ${call.name}: ${e.message}. Arguments received: ${truncateForError(call.arguments)}`,
13097
+ content: `Error: invalid JSON arguments for ${call.name}: ${e.message}. No tool action was performed (${Buffer.byteLength(call.arguments, "utf8")} argument bytes).`,
12793
13098
  ok: false,
12794
13099
  errorCode: "invalid_args",
12795
- recoverable: false,
12796
- suggestion: "reformulate the tool call with valid JSON arguments"
13100
+ recoverable: true,
13101
+ suggestion: artifactSuggestion
12797
13102
  };
12798
13103
  }
12799
13104
  tr?.call(args, tool.needsPermission);
@@ -13110,12 +13415,12 @@ __export(sessions_exports, {
13110
13415
  saveSession: () => saveSession,
13111
13416
  sessionsDir: () => sessionsDir
13112
13417
  });
13113
- import { readFile as readFile13, writeFile as writeFile11, mkdir as mkdir11, readdir as readdir4, stat as stat5 } from "fs/promises";
13418
+ import { readFile as readFile14, writeFile as writeFile12, mkdir as mkdir12, readdir as readdir5, stat as stat6 } from "fs/promises";
13114
13419
  import { homedir as homedir15 } from "os";
13115
- import { join as join25 } from "path";
13420
+ import { join as join26 } from "path";
13116
13421
  function sessionsDir() {
13117
- const xdg = process.env.XDG_DATA_HOME || join25(homedir15(), ".local", "share");
13118
- return join25(xdg, "kimiflare", "sessions");
13422
+ const xdg = process.env.XDG_DATA_HOME || join26(homedir15(), ".local", "share");
13423
+ return join26(xdg, "kimiflare", "sessions");
13119
13424
  }
13120
13425
  function sanitize(text) {
13121
13426
  return text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40);
@@ -13134,9 +13439,9 @@ function makeSessionId(firstPrompt) {
13134
13439
  }
13135
13440
  async function saveSession(file) {
13136
13441
  const dir = sessionsDir();
13137
- await mkdir11(dir, { recursive: true });
13138
- const path = join25(dir, `${file.id}.json`);
13139
- await writeFile11(path, JSON.stringify(file, null, 2), "utf8");
13442
+ await mkdir12(dir, { recursive: true });
13443
+ const path = join26(dir, `${file.id}.json`);
13444
+ await writeFile12(path, JSON.stringify(file, null, 2), "utf8");
13140
13445
  return path;
13141
13446
  }
13142
13447
  async function pruneSessions() {
@@ -13148,16 +13453,16 @@ async function listSessions(limit = 30, cwd) {
13148
13453
  const dir = sessionsDir();
13149
13454
  let entries;
13150
13455
  try {
13151
- entries = await readdir4(dir);
13456
+ entries = await readdir5(dir);
13152
13457
  } catch {
13153
13458
  return [];
13154
13459
  }
13155
13460
  const summaries = [];
13156
13461
  for (const name of entries) {
13157
13462
  if (!name.endsWith(".json")) continue;
13158
- const path = join25(dir, name);
13463
+ const path = join26(dir, name);
13159
13464
  try {
13160
- const [s, raw] = await Promise.all([stat5(path), readFile13(path, "utf8")]);
13465
+ const [s, raw] = await Promise.all([stat6(path), readFile14(path, "utf8")]);
13161
13466
  const parsed = JSON.parse(raw);
13162
13467
  if (cwd && parsed.cwd !== cwd) continue;
13163
13468
  const firstUser = parsed.messages.find((m) => m.role === "user");
@@ -13179,7 +13484,7 @@ async function listSessions(limit = 30, cwd) {
13179
13484
  return summaries.slice(0, limit);
13180
13485
  }
13181
13486
  async function loadSession(filePath) {
13182
- const raw = await readFile13(filePath, "utf8");
13487
+ const raw = await readFile14(filePath, "utf8");
13183
13488
  const file = JSON.parse(raw);
13184
13489
  if (Array.isArray(file.messages)) repairDanglingToolCalls(file.messages);
13185
13490
  return file;
@@ -13229,10 +13534,10 @@ var init_sessions = __esm({
13229
13534
  });
13230
13535
 
13231
13536
  // src/util/image.ts
13232
- import { readFile as readFile14 } from "fs/promises";
13537
+ import { readFile as readFile15 } from "fs/promises";
13233
13538
  import { basename as basename2 } from "path";
13234
13539
  async function encodeImageFile(filePath) {
13235
- const buf = await readFile14(filePath);
13540
+ const buf = await readFile15(filePath);
13236
13541
  if (buf.byteLength > MAX_IMAGE_BYTES) {
13237
13542
  throw new Error(
13238
13543
  `image too large (${(buf.byteLength / 1024 / 1024).toFixed(1)} MB); max is ${MAX_IMAGE_BYTES / 1024 / 1024} MB`
@@ -13268,7 +13573,7 @@ var init_image = __esm({
13268
13573
  });
13269
13574
 
13270
13575
  // src/permissions-evaluator.ts
13271
- import { resolve as resolve5, relative as relative4 } from "path";
13576
+ import { resolve as resolve6, relative as relative5 } from "path";
13272
13577
  import { homedir as homedir16 } from "os";
13273
13578
  function evaluatePermissionRules(req, rules) {
13274
13579
  const toolRules = rules[req.tool];
@@ -13285,7 +13590,7 @@ function evaluatePermissionRules(req, rules) {
13285
13590
  }
13286
13591
  function expandHome(path) {
13287
13592
  if (path.startsWith("~/")) {
13288
- return resolve5(homedir16(), path.slice(2));
13593
+ return resolve6(homedir16(), path.slice(2));
13289
13594
  }
13290
13595
  return path;
13291
13596
  }
@@ -13296,7 +13601,7 @@ function extractTarget(tool, args, cwd) {
13296
13601
  case "read":
13297
13602
  case "glob":
13298
13603
  case "grep":
13299
- return typeof args.path === "string" ? resolve5(cwd, expandHome(args.path)) : null;
13604
+ return typeof args.path === "string" ? resolve6(cwd, expandHome(args.path)) : null;
13300
13605
  case "bash":
13301
13606
  return typeof args.command === "string" ? args.command : null;
13302
13607
  case "browser_fetch":
@@ -13305,13 +13610,13 @@ function extractTarget(tool, args, cwd) {
13305
13610
  case "search_web":
13306
13611
  return typeof args.query === "string" ? args.query : null;
13307
13612
  default:
13308
- return (typeof args.path === "string" ? resolve5(cwd, expandHome(args.path)) : null) ?? (typeof args.url === "string" ? args.url : null) ?? (typeof args.command === "string" ? args.command : null);
13613
+ return (typeof args.path === "string" ? resolve6(cwd, expandHome(args.path)) : null) ?? (typeof args.url === "string" ? args.url : null) ?? (typeof args.command === "string" ? args.command : null);
13309
13614
  }
13310
13615
  }
13311
13616
  function matchPattern(target, pattern, cwd) {
13312
13617
  let expandedPattern = pattern;
13313
13618
  if (pattern.startsWith("~/")) {
13314
- expandedPattern = resolve5(homedir16(), pattern.slice(2));
13619
+ expandedPattern = resolve6(homedir16(), pattern.slice(2));
13315
13620
  }
13316
13621
  if (target.startsWith(expandedPattern)) {
13317
13622
  return true;
@@ -13321,7 +13626,7 @@ function matchPattern(target, pattern, cwd) {
13321
13626
  return true;
13322
13627
  }
13323
13628
  try {
13324
- const relTarget = relative4(cwd, target);
13629
+ const relTarget = relative5(cwd, target);
13325
13630
  if (regex.test(relTarget)) {
13326
13631
  return true;
13327
13632
  }
@@ -13394,17 +13699,17 @@ __export(retention_exports, {
13394
13699
  listTraceSessions: () => listTraceSessions,
13395
13700
  pruneTraces: () => pruneTraces
13396
13701
  });
13397
- import { readdir as readdir5, rm as rm3, stat as stat6 } from "fs/promises";
13398
- import { join as join26 } from "path";
13702
+ import { readdir as readdir6, rm as rm4, stat as stat7 } from "fs/promises";
13703
+ import { join as join27 } from "path";
13399
13704
  async function dirSize(path) {
13400
13705
  let total = 0;
13401
- const entries = await readdir5(path, { withFileTypes: true });
13706
+ const entries = await readdir6(path, { withFileTypes: true });
13402
13707
  for (const entry of entries) {
13403
- const p = join26(path, entry.name);
13708
+ const p = join27(path, entry.name);
13404
13709
  if (entry.isDirectory()) total += await dirSize(p);
13405
13710
  else if (entry.isFile()) {
13406
13711
  try {
13407
- total += (await stat6(p)).size;
13712
+ total += (await stat7(p)).size;
13408
13713
  } catch {
13409
13714
  }
13410
13715
  }
@@ -13415,19 +13720,19 @@ async function listTraceSessions(root) {
13415
13720
  const base = traceRoot(root);
13416
13721
  let names;
13417
13722
  try {
13418
- names = await readdir5(base);
13723
+ names = await readdir6(base);
13419
13724
  } catch {
13420
13725
  return [];
13421
13726
  }
13422
13727
  const sessions = [];
13423
13728
  for (const name of names) {
13424
- const path = join26(base, name);
13729
+ const path = join27(base, name);
13425
13730
  try {
13426
- const s = await stat6(path);
13731
+ const s = await stat7(path);
13427
13732
  if (!s.isDirectory()) continue;
13428
13733
  let mtime = s.mtime;
13429
13734
  try {
13430
- mtime = (await stat6(join26(path, TRACE_FILE_NAME))).mtime;
13735
+ mtime = (await stat7(join27(path, TRACE_FILE_NAME))).mtime;
13431
13736
  } catch {
13432
13737
  }
13433
13738
  sessions.push({ sessionId: name, path, mtime, bytes: await dirSize(path) });
@@ -13452,7 +13757,7 @@ async function pruneTraces(opts2 = {}) {
13452
13757
  }
13453
13758
  const remove = async (s) => {
13454
13759
  try {
13455
- await rm3(s.path, { recursive: true, force: true });
13760
+ await rm4(s.path, { recursive: true, force: true });
13456
13761
  removed.push(s.sessionId);
13457
13762
  } catch {
13458
13763
  }
@@ -13481,7 +13786,7 @@ var init_retention = __esm({
13481
13786
  // src/trace/session-start.ts
13482
13787
  import { execFile as execFile6 } from "child_process";
13483
13788
  import { existsSync as existsSync5 } from "fs";
13484
- import { dirname as dirname13, join as join27 } from "path";
13789
+ import { dirname as dirname13, join as join28 } from "path";
13485
13790
  import { fileURLToPath as fileURLToPath4 } from "url";
13486
13791
  import { promisify as promisify6 } from "util";
13487
13792
  async function git2(args, cwd) {
@@ -13495,8 +13800,8 @@ async function git2(args, cwd) {
13495
13800
  }
13496
13801
  function harnessCheckoutDir() {
13497
13802
  const here = dirname13(fileURLToPath4(import.meta.url));
13498
- for (const candidate of [join27(here, "..", ".."), join27(here, "..")]) {
13499
- if (existsSync5(join27(candidate, "package.json")) && existsSync5(join27(candidate, ".git"))) return candidate;
13803
+ for (const candidate of [join28(here, "..", ".."), join28(here, "..")]) {
13804
+ if (existsSync5(join28(candidate, "package.json")) && existsSync5(join28(candidate, ".git"))) return candidate;
13500
13805
  }
13501
13806
  return null;
13502
13807
  }
@@ -13634,14 +13939,14 @@ var init_types2 = __esm({
13634
13939
  // src/hooks/settings.ts
13635
13940
  import { existsSync as existsSync6, readFileSync as readFileSync5, mkdirSync as mkdirSync7, writeFileSync as writeFileSync4 } from "fs";
13636
13941
  import { homedir as homedir17 } from "os";
13637
- import { join as join28, dirname as dirname14 } from "path";
13942
+ import { join as join29, dirname as dirname14 } from "path";
13638
13943
  import { createHash as createHash3 } from "crypto";
13639
13944
  function globalSettingsPath() {
13640
- const xdg = process.env.XDG_CONFIG_HOME || join28(homedir17(), ".config");
13641
- return join28(xdg, "kimiflare", "settings.json");
13945
+ const xdg = process.env.XDG_CONFIG_HOME || join29(homedir17(), ".config");
13946
+ return join29(xdg, "kimiflare", "settings.json");
13642
13947
  }
13643
13948
  function projectSettingsPath(cwd) {
13644
- return join28(cwd, ".kimiflare", "settings.json");
13949
+ return join29(cwd, ".kimiflare", "settings.json");
13645
13950
  }
13646
13951
  function readSettingsFile(path) {
13647
13952
  if (!existsSync6(path)) return null;
@@ -13759,7 +14064,7 @@ var init_settings = __esm({
13759
14064
  });
13760
14065
 
13761
14066
  // src/hooks/runner.ts
13762
- import { spawn as spawn4 } from "child_process";
14067
+ import { spawn as spawn5 } from "child_process";
13763
14068
  function isVetoEvent(event) {
13764
14069
  return event === "PreToolUse" || event === "UserPromptSubmit";
13765
14070
  }
@@ -13876,8 +14181,8 @@ var init_runner = __esm({
13876
14181
  init_logger();
13877
14182
  DEFAULT_TIMEOUT_MS = 3e4;
13878
14183
  STREAM_CAP_BYTES = 4 * 1024;
13879
- defaultSpawn = (command, payloadJson, env2, cwd, timeoutMs, signal) => new Promise((resolve19) => {
13880
- const child = spawn4(command, {
14184
+ defaultSpawn = (command, payloadJson, env2, cwd, timeoutMs, signal) => new Promise((resolve20) => {
14185
+ const child = spawn5(command, {
13881
14186
  shell: true,
13882
14187
  cwd,
13883
14188
  env: env2,
@@ -13891,7 +14196,7 @@ var init_runner = __esm({
13891
14196
  settled = true;
13892
14197
  clearTimeout(timer3);
13893
14198
  signal?.removeEventListener("abort", onAbort);
13894
- resolve19({ exitCode, stdout, stderr, timedOut });
14199
+ resolve20({ exitCode, stdout, stderr, timedOut });
13895
14200
  };
13896
14201
  const onAbort = () => {
13897
14202
  child.kill("SIGTERM");
@@ -13964,11 +14269,11 @@ var init_manager2 = __esm({
13964
14269
  });
13965
14270
 
13966
14271
  // src/eval/config.ts
13967
- import { readFile as readFile16 } from "fs/promises";
13968
- import { basename as basename4, resolve as resolve7 } from "path";
14272
+ import { readFile as readFile17 } from "fs/promises";
14273
+ import { basename as basename4, resolve as resolve8 } from "path";
13969
14274
  async function loadEvalConfig(file) {
13970
- const path = resolve7(file);
13971
- const raw = JSON.parse(await readFile16(path, "utf8"));
14275
+ const path = resolve8(file);
14276
+ const raw = JSON.parse(await readFile17(path, "utf8"));
13972
14277
  if (!raw || typeof raw !== "object") throw new Error(`${file}: config must be a JSON object`);
13973
14278
  const config2 = raw.config ?? {};
13974
14279
  if (typeof config2 !== "object" || Array.isArray(config2)) throw new Error(`${file}: "config" must be an object`);
@@ -13988,8 +14293,8 @@ var init_config2 = __esm({
13988
14293
  });
13989
14294
 
13990
14295
  // src/eval/tasks.ts
13991
- import { readdir as readdir6, readFile as readFile17, stat as stat7 } from "fs/promises";
13992
- import { basename as basename5, join as join29, resolve as resolve8 } from "path";
14296
+ import { readdir as readdir7, readFile as readFile18, stat as stat8 } from "fs/promises";
14297
+ import { basename as basename5, join as join30, resolve as resolve9 } from "path";
13993
14298
  function isNonEmptyString(v) {
13994
14299
  return typeof v === "string" && v.trim().length > 0;
13995
14300
  }
@@ -14017,22 +14322,22 @@ function matchesTaskFilter(id, filter) {
14017
14322
  return filter.split(",").map((g) => g.trim()).filter(Boolean).some((g) => matchGlob(id, g));
14018
14323
  }
14019
14324
  async function loadTasks(dir, filter) {
14020
- const root = resolve8(dir);
14021
- const names = (await readdir6(root)).filter((n) => n.endsWith(".json")).sort();
14325
+ const root = resolve9(dir);
14326
+ const names = (await readdir7(root)).filter((n) => n.endsWith(".json")).sort();
14022
14327
  const tasks = [];
14023
14328
  const seen = /* @__PURE__ */ new Set();
14024
14329
  for (const name of names) {
14025
- const file = join29(root, name);
14026
- const task = validateTask(JSON.parse(await readFile17(file, "utf8")), name);
14330
+ const file = join30(root, name);
14331
+ const task = validateTask(JSON.parse(await readFile18(file, "utf8")), name);
14027
14332
  if (task.id !== basename5(name, ".json")) throw new Error(`${name}: "id" (${task.id}) must match the file name`);
14028
14333
  if (seen.has(task.id)) throw new Error(`duplicate task id ${task.id}`);
14029
14334
  seen.add(task.id);
14030
14335
  if (!matchesTaskFilter(task.id, filter)) continue;
14031
14336
  const resolvedFiles = {};
14032
14337
  for (const [dest, src] of Object.entries(task.files ?? {})) {
14033
- const abs = resolve8(root, src);
14338
+ const abs = resolve9(root, src);
14034
14339
  if (!abs.startsWith(root)) throw new Error(`${name}: files["${dest}"] escapes the task directory`);
14035
- await stat7(abs).catch(() => {
14340
+ await stat8(abs).catch(() => {
14036
14341
  throw new Error(`${name}: files["${dest}"] -> ${src} does not exist`);
14037
14342
  });
14038
14343
  resolvedFiles[dest] = abs;
@@ -14053,15 +14358,15 @@ var init_tasks2 = __esm({
14053
14358
  // src/eval/workspace.ts
14054
14359
  import { execFile as execFile7 } from "child_process";
14055
14360
  import { createHash as createHash4 } from "crypto";
14056
- import { mkdir as mkdir12, rm as rm4, stat as stat8 } from "fs/promises";
14057
- import { isAbsolute as isAbsolute3, join as join30, resolve as resolve9 } from "path";
14361
+ import { mkdir as mkdir13, rm as rm5, stat as stat9 } from "fs/promises";
14362
+ import { isAbsolute as isAbsolute4, join as join31, resolve as resolve10 } from "path";
14058
14363
  import { promisify as promisify7 } from "util";
14059
14364
  async function git3(args, cwd, timeoutMs = 6e5) {
14060
14365
  const { stdout } = await execFileAsync5("git", args, { cwd, timeout: timeoutMs, maxBuffer: 64 * 1024 * 1024 });
14061
14366
  return stdout.trim();
14062
14367
  }
14063
14368
  function isLocalRepo(repo) {
14064
- return isAbsolute3(repo) || repo.startsWith(".") || repo.startsWith("~");
14369
+ return isAbsolute4(repo) || repo.startsWith(".") || repo.startsWith("~");
14065
14370
  }
14066
14371
  function prepareSourceRepo(repo, cacheDir) {
14067
14372
  const key = `${cacheDir}\0${repo}`;
@@ -14074,14 +14379,14 @@ function prepareSourceRepo(repo, cacheDir) {
14074
14379
  }
14075
14380
  async function prepareSourceRepoUncached(repo, cacheDir) {
14076
14381
  if (isLocalRepo(repo)) {
14077
- const path = resolve9(repo.replace(/^~/, process.env.HOME ?? ""));
14382
+ const path = resolve10(repo.replace(/^~/, process.env.HOME ?? ""));
14078
14383
  await git3(["rev-parse", "--git-dir"], path);
14079
14384
  return path;
14080
14385
  }
14081
14386
  const slug = `${repo.replace(/[^A-Za-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(-60)}-${createHash4("sha1").update(repo).digest("hex").slice(0, 8)}`;
14082
- const dir = join30(cacheDir, slug);
14083
- await mkdir12(cacheDir, { recursive: true });
14084
- const exists = await stat8(join30(dir, ".git")).then(() => true).catch(() => false);
14387
+ const dir = join31(cacheDir, slug);
14388
+ await mkdir13(cacheDir, { recursive: true });
14389
+ const exists = await stat9(join31(dir, ".git")).then(() => true).catch(() => false);
14085
14390
  if (!exists) {
14086
14391
  await git3(["clone", "--quiet", "--no-checkout", repo, dir], cacheDir);
14087
14392
  } else {
@@ -14100,13 +14405,13 @@ async function ensureCommit(sourceRepo, commit) {
14100
14405
  async function createWorktree(sourceRepo, commit, path) {
14101
14406
  await ensureCommit(sourceRepo, commit);
14102
14407
  await removeWorktree({ sourceRepo, path }).catch(() => void 0);
14103
- await mkdir12(join30(path, ".."), { recursive: true });
14408
+ await mkdir13(join31(path, ".."), { recursive: true });
14104
14409
  await git3(["worktree", "add", "--quiet", "--detach", path, commit], sourceRepo);
14105
14410
  return { sourceRepo, path };
14106
14411
  }
14107
14412
  async function removeWorktree(wt) {
14108
14413
  await git3(["worktree", "remove", "--force", wt.path], wt.sourceRepo).catch(() => void 0);
14109
- await rm4(wt.path, { recursive: true, force: true });
14414
+ await rm5(wt.path, { recursive: true, force: true });
14110
14415
  await git3(["worktree", "prune"], wt.sourceRepo).catch(() => void 0);
14111
14416
  }
14112
14417
  var execFileAsync5, preparing;
@@ -15201,7 +15506,7 @@ Context: This memory was explicitly provided by the user during a conversation.`
15201
15506
  });
15202
15507
 
15203
15508
  // src/lsp/connection.ts
15204
- import { spawn as spawn5 } from "child_process";
15509
+ import { spawn as spawn6 } from "child_process";
15205
15510
  import { EventEmitter as EventEmitter2 } from "events";
15206
15511
  var LspConnection;
15207
15512
  var init_connection = __esm({
@@ -15223,7 +15528,7 @@ var init_connection = __esm({
15223
15528
  if (this.child) {
15224
15529
  throw new Error("LSP connection already started");
15225
15530
  }
15226
- return new Promise((resolve19, reject) => {
15531
+ return new Promise((resolve20, reject) => {
15227
15532
  const abortController = new AbortController();
15228
15533
  const spawnTimer = setTimeout(() => {
15229
15534
  abortController.abort();
@@ -15231,7 +15536,7 @@ var init_connection = __esm({
15231
15536
  reject(new Error(`LSP server spawn timed out after ${spawnTimeoutMs}ms`));
15232
15537
  }, spawnTimeoutMs);
15233
15538
  try {
15234
- const child = spawn5(command[0], command.slice(1), {
15539
+ const child = spawn6(command[0], command.slice(1), {
15235
15540
  env: { ...process.env, ...env2 },
15236
15541
  stdio: ["pipe", "pipe", "pipe"]
15237
15542
  });
@@ -15262,7 +15567,7 @@ var init_connection = __esm({
15262
15567
  if (child.pid) {
15263
15568
  clearTimeout(spawnTimer);
15264
15569
  this.child = child;
15265
- resolve19();
15570
+ resolve20();
15266
15571
  }
15267
15572
  });
15268
15573
  } catch (err) {
@@ -15277,12 +15582,12 @@ var init_connection = __esm({
15277
15582
  }
15278
15583
  const id = this.nextId++;
15279
15584
  const msg = { jsonrpc: "2.0", id, method, params };
15280
- return new Promise((resolve19, reject) => {
15585
+ return new Promise((resolve20, reject) => {
15281
15586
  const timer3 = setTimeout(() => {
15282
15587
  this.pending.delete(id);
15283
15588
  reject(toolTimeoutError(`LSP request '${method}'`, this.requestTimeoutMs));
15284
15589
  }, this.requestTimeoutMs);
15285
- const pending = { resolve: resolve19, reject, signal, timer: timer3 };
15590
+ const pending = { resolve: resolve20, reject, signal, timer: timer3 };
15286
15591
  this.pending.set(id, pending);
15287
15592
  if (signal) {
15288
15593
  const onAbort = () => {
@@ -15375,9 +15680,9 @@ var init_connection = __esm({
15375
15680
  });
15376
15681
 
15377
15682
  // src/lsp/protocol.ts
15378
- import { pathToFileURL as pathToFileURL2, fileURLToPath as fileURLToPath5 } from "url";
15683
+ import { pathToFileURL as pathToFileURL3, fileURLToPath as fileURLToPath5 } from "url";
15379
15684
  function toUri(path) {
15380
- return pathToFileURL2(path).href;
15685
+ return pathToFileURL3(path).href;
15381
15686
  }
15382
15687
  function fromUri(uri) {
15383
15688
  return fileURLToPath5(uri);
@@ -15846,10 +16151,10 @@ var init_manager4 = __esm({
15846
16151
  });
15847
16152
 
15848
16153
  // src/lsp/adapter.ts
15849
- import { relative as relative5 } from "path";
16154
+ import { relative as relative6 } from "path";
15850
16155
  function formatLocation(loc, cwd) {
15851
16156
  const path = fromUri(loc.uri);
15852
- const rel = relative5(cwd, path) || path;
16157
+ const rel = relative6(cwd, path) || path;
15853
16158
  return `${rel}:${loc.range.start.line + 1}:${loc.range.start.character + 1}`;
15854
16159
  }
15855
16160
  function formatLocations(locs, cwd) {
@@ -15886,7 +16191,7 @@ function formatWorkspaceSymbols(symbols, cwd) {
15886
16191
  if (!symbols || symbols.length === 0) return "No symbols found.";
15887
16192
  return symbols.map((s) => {
15888
16193
  const path = fromUri(s.location.uri);
15889
- const rel = relative5(cwd, path) || path;
16194
+ const rel = relative6(cwd, path) || path;
15890
16195
  const container = s.containerName ? ` in ${s.containerName}` : "";
15891
16196
  return `${s.name} (${symbolKindName(s.kind)})${container} \u2014 ${rel}:${s.location.range.start.line + 1}:${s.location.range.start.character + 1}`;
15892
16197
  }).join("\n");
@@ -15906,7 +16211,7 @@ function formatWorkspaceEdit(edit, cwd) {
15906
16211
  if (edit.changes) {
15907
16212
  for (const [uri, edits] of Object.entries(edit.changes)) {
15908
16213
  const path = fromUri(uri);
15909
- const rel = relative5(cwd, path) || path;
16214
+ const rel = relative6(cwd, path) || path;
15910
16215
  lines.push(`File: ${rel}`);
15911
16216
  for (const e of edits) {
15912
16217
  lines.push(` ${e.range.start.line + 1}:${e.range.start.character + 1}-${e.range.end.line + 1}:${e.range.end.character + 1}: ${e.newText}`);
@@ -15931,7 +16236,7 @@ var init_adapter = __esm({
15931
16236
  });
15932
16237
 
15933
16238
  // src/tools/lsp.ts
15934
- import { relative as relative6 } from "path";
16239
+ import { relative as relative7 } from "path";
15935
16240
  function makeOutput2(content) {
15936
16241
  const bytes = Buffer.byteLength(content, "utf8");
15937
16242
  return { content, rawBytes: bytes, reducedBytes: bytes };
@@ -15939,7 +16244,7 @@ function makeOutput2(content) {
15939
16244
  function resolveLspPath(args, ctx) {
15940
16245
  const raw = typeof args.path === "string" ? args.path : "";
15941
16246
  const resolved = resolvePath(ctx.cwd, raw);
15942
- const rel = relative6(ctx.cwd, resolved);
16247
+ const rel = relative7(ctx.cwd, resolved);
15943
16248
  if (isPathOutside(rel)) {
15944
16249
  throw new Error(`Path outside workspace: ${raw}`);
15945
16250
  }
@@ -16205,12 +16510,12 @@ __export(openrouter_catalog_exports, {
16205
16510
  loadOpenRouterCatalog: () => loadOpenRouterCatalog,
16206
16511
  mapOpenRouterModel: () => mapOpenRouterModel
16207
16512
  });
16208
- import { readFile as readFile18, writeFile as writeFile12, mkdir as mkdir13 } from "fs/promises";
16513
+ import { readFile as readFile19, writeFile as writeFile13, mkdir as mkdir14 } from "fs/promises";
16209
16514
  import { homedir as homedir18 } from "os";
16210
- import { join as join32, dirname as dirname16 } from "path";
16515
+ import { join as join33, dirname as dirname16 } from "path";
16211
16516
  function catalogCachePath() {
16212
- const xdg = process.env.XDG_CONFIG_HOME || join32(homedir18(), ".config");
16213
- return join32(xdg, "kimiflare", "openrouter-models.json");
16517
+ const xdg = process.env.XDG_CONFIG_HOME || join33(homedir18(), ".config");
16518
+ return join33(xdg, "kimiflare", "openrouter-models.json");
16214
16519
  }
16215
16520
  function perMtok(perToken) {
16216
16521
  const n = Number(perToken);
@@ -16261,7 +16566,7 @@ async function fetchOpenRouterCatalog(fetchImpl2 = fetch) {
16261
16566
  }
16262
16567
  async function readCache3() {
16263
16568
  try {
16264
- const raw = await readFile18(catalogCachePath(), "utf8");
16569
+ const raw = await readFile19(catalogCachePath(), "utf8");
16265
16570
  const parsed = JSON.parse(raw);
16266
16571
  return parsed.version === CACHE_VERSION ? parsed : null;
16267
16572
  } catch {
@@ -16271,9 +16576,9 @@ async function readCache3() {
16271
16576
  async function writeCache3(models) {
16272
16577
  const path = catalogCachePath();
16273
16578
  try {
16274
- await mkdir13(dirname16(path), { recursive: true });
16579
+ await mkdir14(dirname16(path), { recursive: true });
16275
16580
  const cache = { version: CACHE_VERSION, fetchedAt: (/* @__PURE__ */ new Date()).toISOString(), models };
16276
- await writeFile12(path, JSON.stringify(cache, null, 2), "utf8");
16581
+ await writeFile13(path, JSON.stringify(cache, null, 2), "utf8");
16277
16582
  } catch {
16278
16583
  }
16279
16584
  }
@@ -16320,12 +16625,12 @@ __export(requesty_catalog_exports, {
16320
16625
  loadRequestyCatalog: () => loadRequestyCatalog,
16321
16626
  mapRequestyModel: () => mapRequestyModel
16322
16627
  });
16323
- import { readFile as readFile19, writeFile as writeFile13, mkdir as mkdir14 } from "fs/promises";
16628
+ import { readFile as readFile20, writeFile as writeFile14, mkdir as mkdir15 } from "fs/promises";
16324
16629
  import { homedir as homedir19 } from "os";
16325
- import { join as join33, dirname as dirname17 } from "path";
16630
+ import { join as join34, dirname as dirname17 } from "path";
16326
16631
  function catalogCachePath2() {
16327
- const xdg = process.env.XDG_CONFIG_HOME || join33(homedir19(), ".config");
16328
- return join33(xdg, "kimiflare", "requesty-models.json");
16632
+ const xdg = process.env.XDG_CONFIG_HOME || join34(homedir19(), ".config");
16633
+ return join34(xdg, "kimiflare", "requesty-models.json");
16329
16634
  }
16330
16635
  function isSafeModelId(id) {
16331
16636
  return typeof id === "string" && id.length > 0 && !CONTROL_CHARS.test(id);
@@ -16381,7 +16686,7 @@ async function fetchRequestyCatalog(fetchImpl2 = fetch) {
16381
16686
  }
16382
16687
  async function readCache4() {
16383
16688
  try {
16384
- const raw = await readFile19(catalogCachePath2(), "utf8");
16689
+ const raw = await readFile20(catalogCachePath2(), "utf8");
16385
16690
  const parsed = JSON.parse(raw);
16386
16691
  if (parsed.version !== CACHE_VERSION2) return null;
16387
16692
  return {
@@ -16396,9 +16701,9 @@ async function readCache4() {
16396
16701
  async function writeCache4(catalog) {
16397
16702
  const path = catalogCachePath2();
16398
16703
  try {
16399
- await mkdir14(dirname17(path), { recursive: true });
16704
+ await mkdir15(dirname17(path), { recursive: true });
16400
16705
  const cache = { version: CACHE_VERSION2, fetchedAt: (/* @__PURE__ */ new Date()).toISOString(), ...catalog };
16401
- await writeFile13(path, JSON.stringify(cache, null, 2), "utf8");
16706
+ await writeFile14(path, JSON.stringify(cache, null, 2), "utf8");
16402
16707
  } catch {
16403
16708
  }
16404
16709
  }
@@ -16491,15 +16796,15 @@ var session_exports = {};
16491
16796
  __export(session_exports, {
16492
16797
  createAgentSession: () => createAgentSession
16493
16798
  });
16494
- import { resolve as resolve10 } from "path";
16799
+ import { resolve as resolve11 } from "path";
16495
16800
  import { homedir as homedir20 } from "os";
16496
- import { join as join34 } from "path";
16801
+ import { join as join35 } from "path";
16497
16802
  import { existsSync as existsSync7 } from "fs";
16498
16803
  async function createAgentSession(opts2) {
16499
16804
  const config2 = await resolveSdkConfig(opts2);
16500
16805
  if (usesRequesty(llmAuthFromConfig(config2))) await ensureRequestyCatalog();
16501
16806
  else if (!resolveCustomEndpoint(config2)) await ensureOpenRouterCatalog();
16502
- const cwd = resolve10(opts2.cwd ?? process.cwd());
16807
+ const cwd = resolve11(opts2.cwd ?? process.cwd());
16503
16808
  const tools = opts2.tools ?? ALL_TOOLS;
16504
16809
  let hooks;
16505
16810
  if (opts2.enableHooks) {
@@ -16510,7 +16815,7 @@ async function createAgentSession(opts2) {
16510
16815
  let memoryManager = null;
16511
16816
  const memoryEnabled = opts2.memoryEnabled ?? config2.memoryEnabled ?? false;
16512
16817
  if (memoryEnabled) {
16513
- const dbPath = config2.memoryDbPath ?? join34(homedir20(), ".local", "share", "kimiflare", "memory.db");
16818
+ const dbPath = config2.memoryDbPath ?? join35(homedir20(), ".local", "share", "kimiflare", "memory.db");
16514
16819
  memoryManager = new MemoryManager({
16515
16820
  dbPath,
16516
16821
  ...llmAuthFromConfig(config2),
@@ -16540,7 +16845,7 @@ async function createAgentSession(opts2) {
16540
16845
  }
16541
16846
  let sessionFile;
16542
16847
  if (opts2.sessionId) {
16543
- const filePath = join34(sessionsDir(), `${opts2.sessionId}.json`);
16848
+ const filePath = join35(sessionsDir(), `${opts2.sessionId}.json`);
16544
16849
  try {
16545
16850
  sessionFile = await loadSession(filePath);
16546
16851
  } catch {
@@ -16739,8 +17044,8 @@ var init_session = __esm({
16739
17044
  const parts = [{ type: "text", text }];
16740
17045
  for (const img of options.images) {
16741
17046
  if ("path" in img) {
16742
- const { readFile: readFile36 } = await import("fs/promises");
16743
- const data = await readFile36(img.path, "base64");
17047
+ const { readFile: readFile37 } = await import("fs/promises");
17048
+ const data = await readFile37(img.path, "base64");
16744
17049
  const mimeType = img.path.endsWith(".png") ? "image/png" : img.path.endsWith(".jpg") || img.path.endsWith(".jpeg") ? "image/jpeg" : "image/webp";
16745
17050
  parts.push({ type: "image_url", image_url: { url: `data:${mimeType};base64,${data}` } });
16746
17051
  } else {
@@ -16999,12 +17304,12 @@ var init_session = __esm({
16999
17304
  toolName: req.tool.name,
17000
17305
  args: req.args
17001
17306
  });
17002
- const decision = await new Promise((resolve19) => {
17003
- this.permissionResolvers.set(requestId, resolve19);
17307
+ const decision = await new Promise((resolve20) => {
17308
+ this.permissionResolvers.set(requestId, resolve20);
17004
17309
  setTimeout(() => {
17005
17310
  if (this.permissionResolvers.has(requestId)) {
17006
17311
  this.permissionResolvers.delete(requestId);
17007
- resolve19("deny");
17312
+ resolve20("deny");
17008
17313
  }
17009
17314
  }, 3e5);
17010
17315
  });
@@ -17063,14 +17368,14 @@ var init_session = __esm({
17063
17368
  this.lspManager?.notifyChange(path, content);
17064
17369
  } else {
17065
17370
  void import("fs/promises").then(
17066
- ({ readFile: readFile36 }) => readFile36(path, "utf8").then((c) => this.lspManager?.notifyChange(path, c)).catch(() => {
17371
+ ({ readFile: readFile37 }) => readFile37(path, "utf8").then((c) => this.lspManager?.notifyChange(path, c)).catch(() => {
17067
17372
  })
17068
17373
  ).catch(() => {
17069
17374
  });
17070
17375
  }
17071
17376
  }
17072
17377
  });
17073
- if (["AGENTS.md", "KIMI.md", "KIMIFLARE.md", "AGENT.md"].some((name) => existsSync7(join34(this.cwd, name)))) {
17378
+ if (["AGENTS.md", "KIMI.md", "KIMIFLARE.md", "AGENT.md"].some((name) => existsSync7(join35(this.cwd, name)))) {
17074
17379
  this.messages[0] = {
17075
17380
  role: "system",
17076
17381
  content: buildSystemPrompt({
@@ -17094,13 +17399,13 @@ __export(run_exports, {
17094
17399
  runShell: () => runShell,
17095
17400
  summarizeTrace: () => summarizeTrace
17096
17401
  });
17097
- import { spawn as spawn6 } from "child_process";
17098
- import { appendFile as appendFile3, copyFile, mkdir as mkdir15, readFile as readFile20, writeFile as writeFile14 } from "fs/promises";
17099
- import { dirname as dirname18, join as join35, resolve as resolve11 } from "path";
17402
+ import { spawn as spawn7 } from "child_process";
17403
+ import { appendFile as appendFile3, copyFile, mkdir as mkdir16, readFile as readFile21, writeFile as writeFile15 } from "fs/promises";
17404
+ import { dirname as dirname18, join as join36, resolve as resolve12 } from "path";
17100
17405
  import { performance as performance2 } from "perf_hooks";
17101
17406
  function runShell(command, cwd, timeoutMs) {
17102
17407
  return new Promise((resolveShell) => {
17103
- const child = spawn6(process.platform === "win32" ? process.env.COMSPEC || "cmd.exe" : "bash", [process.platform === "win32" ? "/c" : "-lc", command], {
17408
+ const child = spawn7(process.platform === "win32" ? process.env.COMSPEC || "cmd.exe" : "bash", [process.platform === "win32" ? "/c" : "-lc", command], {
17104
17409
  cwd,
17105
17410
  env: { ...process.env, CI: "1", GIT_EDITOR: "true" }
17106
17411
  });
@@ -17129,8 +17434,8 @@ ${err.message}`, timedOut });
17129
17434
  }
17130
17435
  async function copyTaskFiles(task, worktree) {
17131
17436
  for (const [dest, src] of Object.entries(task.resolvedFiles)) {
17132
- const target = join35(worktree, dest);
17133
- await mkdir15(dirname18(target), { recursive: true });
17437
+ const target = join36(worktree, dest);
17438
+ await mkdir16(dirname18(target), { recursive: true });
17134
17439
  await copyFile(src, target);
17135
17440
  }
17136
17441
  }
@@ -17138,7 +17443,7 @@ async function summarizeTrace(traceFile) {
17138
17443
  const out = { cost_usd: 0, prompt_tokens: 0, completion_tokens: 0, turns: 0, tool_calls: 0, overflow: false };
17139
17444
  let raw;
17140
17445
  try {
17141
- raw = await readFile20(traceFile, "utf8");
17446
+ raw = await readFile21(traceFile, "utf8");
17142
17447
  } catch {
17143
17448
  return out;
17144
17449
  }
@@ -17170,7 +17475,7 @@ function sessionIdFor(runName, task, sample) {
17170
17475
  async function runOne(task, sample, ctx) {
17171
17476
  const startedAt2 = performance2.now();
17172
17477
  const sessionId = sessionIdFor(ctx.runName, task, sample);
17173
- const traceDir = join35(ctx.tracesRoot, sessionId);
17478
+ const traceDir = join36(ctx.tracesRoot, sessionId);
17174
17479
  const base = {
17175
17480
  task_id: task.id,
17176
17481
  sample,
@@ -17195,15 +17500,15 @@ async function runOne(task, sample, ctx) {
17195
17500
  });
17196
17501
  let worktree = null;
17197
17502
  try {
17198
- const sourceRepo = await prepareSourceRepo(task.repo, join35(ctx.out, "cache"));
17199
- worktree = await createWorktree(sourceRepo, task.base_commit, join35(ctx.out, "work", task.id, String(sample)));
17503
+ const sourceRepo = await prepareSourceRepo(task.repo, join36(ctx.out, "cache"));
17504
+ worktree = await createWorktree(sourceRepo, task.base_commit, join36(ctx.out, "work", task.id, String(sample)));
17200
17505
  await copyTaskFiles(task, worktree.path);
17201
17506
  const timeoutMs = (task.timeout_s ?? DEFAULT_TASK_TIMEOUT_S) * 1e3;
17202
17507
  if (task.setup) {
17203
17508
  ctx.log(`[${task.id}#${sample}] setup`);
17204
17509
  const setup = await runShell(task.setup, worktree.path, timeoutMs);
17205
17510
  if (setup.exitCode !== 0) {
17206
- await writeFile14(join35(worktree.path, ".eval-setup.log"), setup.log, "utf8").catch(() => void 0);
17511
+ await writeFile15(join36(worktree.path, ".eval-setup.log"), setup.log, "utf8").catch(() => void 0);
17207
17512
  return finish({ error: `setup failed (exit ${setup.exitCode}${setup.timedOut ? ", timed out" : ""}): ${setup.log.slice(-500)}` });
17208
17513
  }
17209
17514
  }
@@ -17237,8 +17542,8 @@ async function runOne(task, sample, ctx) {
17237
17542
  const test = await runShell(task.test, worktree.path, timeoutMs);
17238
17543
  const testMs = Math.round(performance2.now() - testStartedAt);
17239
17544
  const passed = test.exitCode === 0 && !test.timedOut;
17240
- await mkdir15(traceDir, { recursive: true }).catch(() => void 0);
17241
- await writeFile14(join35(traceDir, "test.log"), test.log, "utf8").catch(() => void 0);
17545
+ await mkdir16(traceDir, { recursive: true }).catch(() => void 0);
17546
+ await writeFile15(join36(traceDir, "test.log"), test.log, "utf8").catch(() => void 0);
17242
17547
  if (session.trace.enabled) {
17243
17548
  session.trace.emit(
17244
17549
  "outcome",
@@ -17256,7 +17561,7 @@ async function runOne(task, sample, ctx) {
17256
17561
  }
17257
17562
  session.dispose({ traceEndReason: "eval_done" });
17258
17563
  await session.trace.flush();
17259
- const stats = await summarizeTrace(join35(traceDir, "trace.jsonl"));
17564
+ const stats = await summarizeTrace(join36(traceDir, "trace.jsonl"));
17260
17565
  ctx.log(`[${task.id}#${sample}] ${passed ? "PASS" : "FAIL"} in ${agentMs + testMs} ms${agentError ? ` (${agentError.slice(0, 120)})` : ""}`);
17261
17566
  return finish({
17262
17567
  passed,
@@ -17274,7 +17579,7 @@ async function runOne(task, sample, ctx) {
17274
17579
  }
17275
17580
  }
17276
17581
  async function runEval(opts2) {
17277
- const out = resolve11(opts2.out);
17582
+ const out = resolve12(opts2.out);
17278
17583
  const log2 = opts2.log ?? ((line) => process.stderr.write(`${line}
17279
17584
  `));
17280
17585
  const evalConfig = await loadEvalConfig(opts2.configFile);
@@ -17285,12 +17590,12 @@ async function runEval(opts2) {
17285
17590
  const samples = Math.max(1, Math.floor(opts2.samples ?? 1));
17286
17591
  const concurrency = Math.max(1, Math.floor(opts2.concurrency ?? 1));
17287
17592
  const createSession = opts2.createSession ?? (await Promise.resolve().then(() => (init_session(), session_exports))).createAgentSession;
17288
- await mkdir15(out, { recursive: true });
17289
- const tracesRoot = join35(out, "traces");
17593
+ await mkdir16(out, { recursive: true });
17594
+ const tracesRoot = join36(out, "traces");
17290
17595
  const runName = evalConfig.name;
17291
- const resultsFile = join35(out, "results.jsonl");
17292
- await writeFile14(
17293
- join35(out, "config.json"),
17596
+ const resultsFile = join36(out, "results.jsonl");
17597
+ await writeFile15(
17598
+ join36(out, "config.json"),
17294
17599
  JSON.stringify({ name: evalConfig.name, model, temperature: evalConfig.temperature ?? null, config: redactConfig(evalConfig.config), tasks: opts2.tasksDir, samples, started_at: (/* @__PURE__ */ new Date()).toISOString() }, null, 2),
17295
17600
  "utf8"
17296
17601
  );
@@ -17334,9 +17639,9 @@ __export(compare_exports, {
17334
17639
  perTask: () => perTask,
17335
17640
  summarizeArm: () => summarizeArm
17336
17641
  });
17337
- import { readFile as readFile21 } from "fs/promises";
17642
+ import { readFile as readFile22 } from "fs/promises";
17338
17643
  async function loadResults(file) {
17339
- const raw = await readFile21(file, "utf8");
17644
+ const raw = await readFile22(file, "utf8");
17340
17645
  return raw.split("\n").filter((l) => l.trim()).map((l) => JSON.parse(l));
17341
17646
  }
17342
17647
  function median(values) {
@@ -17469,16 +17774,16 @@ __export(cost_verify_exports, {
17469
17774
  verifySession: () => verifySession,
17470
17775
  verifyTurn: () => verifyTurn
17471
17776
  });
17472
- import { readFile as readFile22 } from "fs/promises";
17777
+ import { readFile as readFile23 } from "fs/promises";
17473
17778
  import { homedir as homedir21 } from "os";
17474
- import { join as join36 } from "path";
17779
+ import { join as join37 } from "path";
17475
17780
  function usagePath2() {
17476
- const xdg = process.env.XDG_DATA_HOME || join36(homedir21(), ".local", "share");
17477
- return join36(xdg, "kimiflare", "usage.json");
17781
+ const xdg = process.env.XDG_DATA_HOME || join37(homedir21(), ".local", "share");
17782
+ return join37(xdg, "kimiflare", "usage.json");
17478
17783
  }
17479
17784
  async function loadSessions() {
17480
17785
  try {
17481
- return JSON.parse(await readFile22(usagePath2(), "utf8")).sessions ?? [];
17786
+ return JSON.parse(await readFile23(usagePath2(), "utf8")).sessions ?? [];
17482
17787
  } catch {
17483
17788
  return [];
17484
17789
  }
@@ -18009,12 +18314,12 @@ var init_heuristic = __esm({
18009
18314
  });
18010
18315
 
18011
18316
  // src/cost-attribution/classify-from-session.ts
18012
- import { readFile as readFile23 } from "fs/promises";
18013
- import { join as join37 } from "path";
18317
+ import { readFile as readFile24 } from "fs/promises";
18318
+ import { join as join38 } from "path";
18014
18319
  import { homedir as homedir22 } from "os";
18015
18320
  function sessionsDir2() {
18016
- const xdg = process.env.XDG_DATA_HOME || join37(homedir22(), ".local", "share");
18017
- return join37(xdg, "kimiflare", "sessions");
18321
+ const xdg = process.env.XDG_DATA_HOME || join38(homedir22(), ".local", "share");
18322
+ return join38(xdg, "kimiflare", "sessions");
18018
18323
  }
18019
18324
  function parseToolCalls(calls) {
18020
18325
  return calls.map((c) => {
@@ -18028,7 +18333,7 @@ function parseToolCalls(calls) {
18028
18333
  }
18029
18334
  async function classifyFromSessionFile(sessionId) {
18030
18335
  try {
18031
- const raw = await readFile23(join37(sessionsDir2(), `${sessionId}.json`), "utf8");
18336
+ const raw = await readFile24(join38(sessionsDir2(), `${sessionId}.json`), "utf8");
18032
18337
  const session = JSON.parse(raw);
18033
18338
  const messages = session.messages ?? [];
18034
18339
  const turns = [];
@@ -18061,15 +18366,15 @@ var cli_exports = {};
18061
18366
  __export(cli_exports, {
18062
18367
  runCostCommand: () => runCostCommand
18063
18368
  });
18064
- import { readFile as readFile24 } from "fs/promises";
18065
- import { join as join38 } from "path";
18369
+ import { readFile as readFile25 } from "fs/promises";
18370
+ import { join as join39 } from "path";
18066
18371
  import { homedir as homedir23 } from "os";
18067
18372
  function usageDir2() {
18068
- const xdg = process.env.XDG_DATA_HOME || join38(homedir23(), ".local", "share");
18069
- return join38(xdg, "kimiflare");
18373
+ const xdg = process.env.XDG_DATA_HOME || join39(homedir23(), ".local", "share");
18374
+ return join39(xdg, "kimiflare");
18070
18375
  }
18071
18376
  function usagePath3() {
18072
- return join38(usageDir2(), "usage.json");
18377
+ return join39(usageDir2(), "usage.json");
18073
18378
  }
18074
18379
  function today2() {
18075
18380
  return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
@@ -18081,7 +18386,7 @@ function daysAgo(n) {
18081
18386
  }
18082
18387
  async function loadLog2() {
18083
18388
  try {
18084
- const raw = await readFile24(usagePath3(), "utf8");
18389
+ const raw = await readFile25(usagePath3(), "utf8");
18085
18390
  return JSON.parse(raw);
18086
18391
  } catch {
18087
18392
  return { version: 1, days: [], sessions: [] };
@@ -18171,12 +18476,12 @@ __export(aster_workspaces_exports, {
18171
18476
  findAsterWorkspace: () => findAsterWorkspace,
18172
18477
  loadAsterServerConfig: () => loadAsterServerConfig
18173
18478
  });
18174
- import { readFile as readFile25, realpath as realpath3, stat as stat9 } from "fs/promises";
18175
- import { isAbsolute as isAbsolute4, relative as relative7, sep as sep3 } from "path";
18479
+ import { readFile as readFile26, realpath as realpath4, stat as stat10 } from "fs/promises";
18480
+ import { isAbsolute as isAbsolute5, relative as relative8, sep as sep4 } from "path";
18176
18481
  async function loadAsterServerConfig(configPath3 = process.env.AUTOPILOT_ASTER_CONFIG || "/etc/autopilot/aster.json") {
18177
18482
  let raw;
18178
18483
  try {
18179
- raw = JSON.parse(await readFile25(configPath3, "utf8"));
18484
+ raw = JSON.parse(await readFile26(configPath3, "utf8"));
18180
18485
  } catch {
18181
18486
  throw new AsterConfigError();
18182
18487
  }
@@ -18209,15 +18514,15 @@ async function loadAsterServerConfig(configPath3 = process.env.AUTOPILOT_ASTER_C
18209
18514
  if (typeof workspace.displayName !== "string" || !workspace.displayName.trim() || workspace.displayName.length > 100) {
18210
18515
  throw new AsterConfigError();
18211
18516
  }
18212
- if (typeof workspace.rootPath !== "string" || !isAbsolute4(workspace.rootPath)) throw new AsterConfigError();
18517
+ if (typeof workspace.rootPath !== "string" || !isAbsolute5(workspace.rootPath)) throw new AsterConfigError();
18213
18518
  let rootPath;
18214
18519
  try {
18215
- rootPath = await realpath3(workspace.rootPath);
18216
- if (!(await stat9(rootPath)).isDirectory()) throw new Error("not a directory");
18520
+ rootPath = await realpath4(workspace.rootPath);
18521
+ if (!(await stat10(rootPath)).isDirectory()) throw new Error("not a directory");
18217
18522
  } catch {
18218
18523
  throw new AsterConfigError();
18219
18524
  }
18220
- if (roots.some((root) => isWithin(root, rootPath) || isWithin(rootPath, root))) {
18525
+ if (roots.some((root) => isWithin2(root, rootPath) || isWithin2(rootPath, root))) {
18221
18526
  throw new AsterConfigError();
18222
18527
  }
18223
18528
  ids.add(workspace.id);
@@ -18229,9 +18534,9 @@ async function loadAsterServerConfig(configPath3 = process.env.AUTOPILOT_ASTER_C
18229
18534
  function findAsterWorkspace(config2, workspaceId) {
18230
18535
  return config2.workspaces.find((workspace) => workspace.id === workspaceId);
18231
18536
  }
18232
- function isWithin(parent, candidate) {
18233
- const rel = relative7(parent, candidate);
18234
- return rel === "" || rel !== ".." && !rel.startsWith(`..${sep3}`) && !isAbsolute4(rel);
18537
+ function isWithin2(parent, candidate) {
18538
+ const rel = relative8(parent, candidate);
18539
+ return rel === "" || rel !== ".." && !rel.startsWith(`..${sep4}`) && !isAbsolute5(rel);
18235
18540
  }
18236
18541
  var AsterConfigError;
18237
18542
  var init_aster_workspaces = __esm({
@@ -18255,10 +18560,10 @@ import Database4 from "better-sqlite3";
18255
18560
  import { createHash as createHash5, randomBytes as randomBytes2, randomUUID as randomUUID6 } from "crypto";
18256
18561
  import { chmodSync as chmodSync2, mkdirSync as mkdirSync9 } from "fs";
18257
18562
  import { homedir as homedir24 } from "os";
18258
- import { dirname as dirname19, join as join39 } from "path";
18563
+ import { dirname as dirname19, join as join40 } from "path";
18259
18564
  function defaultAsterDbPath() {
18260
- const root = process.env.XDG_STATE_HOME || join39(homedir24(), ".local", "state");
18261
- return process.env.AUTOPILOT_ASTER_DB || join39(root, "autopilot", "aster.db");
18565
+ const root = process.env.XDG_STATE_HOME || join40(homedir24(), ".local", "state");
18566
+ return process.env.AUTOPILOT_ASTER_DB || join40(root, "autopilot", "aster.db");
18262
18567
  }
18263
18568
  function hashToken(token) {
18264
18569
  return createHash5("sha256").update(token).digest("hex");
@@ -18612,7 +18917,7 @@ __export(tui_auth_exports, {
18612
18917
  authGitHubForTui: () => authGitHubForTui
18613
18918
  });
18614
18919
  function sleep3(ms) {
18615
- return new Promise((resolve19) => setTimeout(resolve19, ms));
18920
+ return new Promise((resolve20) => setTimeout(resolve20, ms));
18616
18921
  }
18617
18922
  async function* authGitHubForTui() {
18618
18923
  yield { message: "Starting GitHub OAuth device flow..." };
@@ -19183,18 +19488,18 @@ var init_openapi = __esm({
19183
19488
 
19184
19489
  // src/runs/worktrees.ts
19185
19490
  import { execFile as execFile8 } from "child_process";
19186
- import { access as access2, chmod as chmod2, mkdir as mkdir16, realpath as realpath4 } from "fs/promises";
19491
+ import { access as access2, chmod as chmod3, mkdir as mkdir17, realpath as realpath5 } from "fs/promises";
19187
19492
  import { homedir as homedir25 } from "os";
19188
- import { isAbsolute as isAbsolute5, join as join40, parse, relative as relative8, resolve as resolve12, sep as sep4 } from "path";
19493
+ import { isAbsolute as isAbsolute6, join as join41, parse, relative as relative9, resolve as resolve13, sep as sep5 } from "path";
19189
19494
  function defaultWorktreesDir() {
19190
- const dataHome = process.env.XDG_DATA_HOME || join40(homedir25(), ".local", "share");
19191
- return join40(dataHome, "autopilot", "worktrees");
19495
+ const dataHome = process.env.XDG_DATA_HOME || join41(homedir25(), ".local", "share");
19496
+ return join41(dataHome, "autopilot", "worktrees");
19192
19497
  }
19193
19498
  function isOutside(path) {
19194
- return path === ".." || path.startsWith(`..${sep4}`) || isAbsolute5(path);
19499
+ return path === ".." || path.startsWith(`..${sep5}`) || isAbsolute6(path);
19195
19500
  }
19196
- function isWithin2(parent, candidate) {
19197
- const path = relative8(parent, candidate);
19501
+ function isWithin3(parent, candidate) {
19502
+ const path = relative9(parent, candidate);
19198
19503
  return path === "" || !isOutside(path);
19199
19504
  }
19200
19505
  function runGit(args, cwd) {
@@ -19222,24 +19527,24 @@ var init_worktrees = __esm({
19222
19527
  if (runId === "." || runId === ".." || !/^[a-zA-Z0-9][a-zA-Z0-9._-]{0,127}$/.test(runId)) {
19223
19528
  throw new Error("runId must contain only letters, numbers, dots, underscores, or hyphens");
19224
19529
  }
19225
- const source = await realpath4(sourceCwd);
19530
+ const source = await realpath5(sourceCwd);
19226
19531
  const repositoryRoot = (await runGit(["rev-parse", "--show-toplevel"], source)).trim();
19227
- const repository = await realpath4(repositoryRoot);
19228
- const sourceRelativePath = relative8(repository, source);
19532
+ const repository = await realpath5(repositoryRoot);
19533
+ const sourceRelativePath = relative9(repository, source);
19229
19534
  if (isOutside(sourceRelativePath)) {
19230
19535
  throw new Error("sourceCwd must be inside the Git repository");
19231
19536
  }
19232
- const configuredRoot = resolve12(this.rootDir);
19233
- if (configuredRoot === parse(configuredRoot).root || isWithin2(repository, configuredRoot)) {
19537
+ const configuredRoot = resolve13(this.rootDir);
19538
+ if (configuredRoot === parse(configuredRoot).root || isWithin3(repository, configuredRoot)) {
19234
19539
  throw new Error("worktree root must be outside the source repository and not the filesystem root");
19235
19540
  }
19236
- await mkdir16(configuredRoot, { recursive: true, mode: 448 });
19237
- const worktreesRoot = await realpath4(configuredRoot);
19238
- if (isWithin2(repository, worktreesRoot)) {
19541
+ await mkdir17(configuredRoot, { recursive: true, mode: 448 });
19542
+ const worktreesRoot = await realpath5(configuredRoot);
19543
+ if (isWithin3(repository, worktreesRoot)) {
19239
19544
  throw new Error("worktree root must be outside the source repository");
19240
19545
  }
19241
- await chmod2(worktreesRoot, 448);
19242
- const worktreePath = join40(worktreesRoot, runId);
19546
+ await chmod3(worktreesRoot, 448);
19547
+ const worktreePath = join41(worktreesRoot, runId);
19243
19548
  try {
19244
19549
  await access2(worktreePath);
19245
19550
  throw new Error(`worktree path already exists for run ${runId}`);
@@ -19253,16 +19558,16 @@ var init_worktrees = __esm({
19253
19558
  repositoryRoot: repository,
19254
19559
  sourceCwd: source,
19255
19560
  worktreePath,
19256
- cwd: resolve12(worktreePath, sourceRelativePath),
19561
+ cwd: resolve13(worktreePath, sourceRelativePath),
19257
19562
  branch
19258
19563
  };
19259
19564
  }
19260
19565
  /** Remove a newly-created, still-clean worktree when run initialization fails. */
19261
19566
  async discard(worktree) {
19262
- const root = await realpath4(this.rootDir);
19263
- const target = await realpath4(worktree.worktreePath);
19264
- const repository = await realpath4(worktree.repositoryRoot);
19265
- if (target === root || !isWithin2(root, target)) {
19567
+ const root = await realpath5(this.rootDir);
19568
+ const target = await realpath5(worktree.worktreePath);
19569
+ const repository = await realpath5(worktree.repositoryRoot);
19570
+ if (target === root || !isWithin3(root, target)) {
19266
19571
  throw new Error("worktree path is outside the configured worktree root");
19267
19572
  }
19268
19573
  if (worktree.branch !== `autopilot/run/${worktree.runId}`) {
@@ -19407,8 +19712,8 @@ var init_wake_scheduler = __esm({
19407
19712
  });
19408
19713
 
19409
19714
  // src/server/aster-tools.ts
19410
- import { realpath as realpath5 } from "fs/promises";
19411
- import { isAbsolute as isAbsolute6, relative as relative9, sep as sep5 } from "path";
19715
+ import { realpath as realpath6 } from "fs/promises";
19716
+ import { isAbsolute as isAbsolute7, relative as relative10, sep as sep6 } from "path";
19412
19717
  function createAsterTools(workspaceRoot) {
19413
19718
  return ASTR_TOOLS.map((tool) => ({
19414
19719
  ...tool,
@@ -19420,25 +19725,25 @@ function createAsterTools(workspaceRoot) {
19420
19725
  }
19421
19726
  async function assertAsterWorkspacePath(workspaceRoot, value, allowMissing = false) {
19422
19727
  if (typeof value !== "string" || !value.trim()) throw new Error("workspace_path_invalid");
19423
- const root = await realpath5(workspaceRoot);
19728
+ const root = await realpath6(workspaceRoot);
19424
19729
  const candidate = resolvePath(root, value);
19425
19730
  assertInside(root, candidate);
19426
19731
  assertNotSensitive(root, candidate);
19427
19732
  let actual;
19428
19733
  try {
19429
- actual = await realpath5(candidate);
19734
+ actual = await realpath6(candidate);
19430
19735
  } catch (error) {
19431
19736
  if (!allowMissing || error.code !== "ENOENT") throw new Error("workspace_path_unavailable");
19432
19737
  let ancestor = candidate;
19433
19738
  while (true) {
19434
19739
  try {
19435
- actual = await realpath5(ancestor);
19740
+ actual = await realpath6(ancestor);
19436
19741
  break;
19437
19742
  } catch (ancestorError) {
19438
19743
  if (ancestorError.code !== "ENOENT") throw new Error("workspace_path_unavailable");
19439
- const parent = relative9(root, ancestor);
19744
+ const parent = relative10(root, ancestor);
19440
19745
  if (!parent || parent === ".") throw new Error("workspace_path_unavailable");
19441
- ancestor = ancestor.slice(0, ancestor.lastIndexOf(sep5));
19746
+ ancestor = ancestor.slice(0, ancestor.lastIndexOf(sep6));
19442
19747
  }
19443
19748
  }
19444
19749
  }
@@ -19460,11 +19765,11 @@ function redactLikelySecrets(value) {
19460
19765
  return value.replace(SK_CANDIDATE_RE, (match) => isLikelySkKey(match) ? "[REDACTED_PROVIDER_SECRET]" : match).replace(/\bgh[pousr]_[A-Za-z0-9]{20,}/g, "[REDACTED_PROVIDER_SECRET]").replace(/\bgithub_pat_[A-Za-z0-9_]{20,}/g, "[REDACTED_PROVIDER_SECRET]");
19461
19766
  }
19462
19767
  function assertInside(root, candidate) {
19463
- const rel = relative9(root, candidate);
19464
- if (rel === ".." || rel.startsWith(`..${sep5}`) || isAbsolute6(rel)) throw new Error("workspace_path_forbidden");
19768
+ const rel = relative10(root, candidate);
19769
+ if (rel === ".." || rel.startsWith(`..${sep6}`) || isAbsolute7(rel)) throw new Error("workspace_path_forbidden");
19465
19770
  }
19466
19771
  function assertNotSensitive(root, candidate) {
19467
- const parts = relative9(root, candidate).split(sep5).filter(Boolean).map((part) => part.toLowerCase());
19772
+ const parts = relative10(root, candidate).split(sep6).filter(Boolean).map((part) => part.toLowerCase());
19468
19773
  if (parts.some((part) => part === ".env" || part.startsWith(".env.") || SENSITIVE_NAMES.has(part))) {
19469
19774
  throw new Error("workspace_sensitive_path_forbidden");
19470
19775
  }
@@ -19499,7 +19804,7 @@ var init_aster_tools = __esm({
19499
19804
  // src/server/aster-api.ts
19500
19805
  import { randomUUID as randomUUID7 } from "crypto";
19501
19806
  import { unlink as unlink2 } from "fs/promises";
19502
- import { resolve as resolve13 } from "path";
19807
+ import { resolve as resolve14 } from "path";
19503
19808
  function parseCursor(header, query) {
19504
19809
  const value = (Array.isArray(header) ? header[0] : header) ?? query ?? "0";
19505
19810
  if (!/^\d{1,16}$/.test(value)) return void 0;
@@ -19812,7 +20117,7 @@ var init_aster_api = __esm({
19812
20117
  store.appendEvent(id, null, "conversation.created", { conversationId: id, workspaceId: workspace.id, model });
19813
20118
  json(res, 201, publicConversation(conversation));
19814
20119
  } catch {
19815
- await unlink2(resolve13(sessionsDir(), `${sessionId}.json`)).catch(() => {
20120
+ await unlink2(resolve14(sessionsDir(), `${sessionId}.json`)).catch(() => {
19816
20121
  });
19817
20122
  await worktreeManager.discard(worktree).catch(() => {
19818
20123
  });
@@ -19837,7 +20142,7 @@ var init_aster_api = __esm({
19837
20142
  sendError(res, 409, "conversation_busy", "A turn is already active for this conversation");
19838
20143
  return;
19839
20144
  }
19840
- const sessionPath = resolve13(sessionsDir(), conversation.sessionId + ".json");
20145
+ const sessionPath = resolve14(sessionsDir(), conversation.sessionId + ".json");
19841
20146
  let sessionFile;
19842
20147
  try {
19843
20148
  sessionFile = await loadSession(sessionPath);
@@ -20155,7 +20460,7 @@ data: ${JSON.stringify(event.data)}
20155
20460
 
20156
20461
  // src/server/aster-cell-runtime.ts
20157
20462
  import { execFile as execFile9 } from "child_process";
20158
- import { readFile as readFile26 } from "fs/promises";
20463
+ import { readFile as readFile27 } from "fs/promises";
20159
20464
  import { promisify as promisify8 } from "util";
20160
20465
  import { randomUUID as randomUUID8 } from "crypto";
20161
20466
  async function writeCellFileChunked(cell, path, content) {
@@ -20185,7 +20490,7 @@ async function writeCellFileChunked(cell, path, content) {
20185
20490
  async function readBundledCellSdkBundle() {
20186
20491
  for (const url of [new URL("./sdk/index.js", import.meta.url), new URL("../sdk/index.js", import.meta.url)]) {
20187
20492
  try {
20188
- return await readFile26(url, "utf8");
20493
+ return await readFile27(url, "utf8");
20189
20494
  } catch {
20190
20495
  }
20191
20496
  }
@@ -20238,7 +20543,7 @@ function boundedToolText(text, limit) {
20238
20543
  ${redacted.slice(-half)}`;
20239
20544
  }
20240
20545
  function sleep4(ms) {
20241
- return new Promise((resolve19) => setTimeout(resolve19, ms));
20546
+ return new Promise((resolve20) => setTimeout(resolve20, ms));
20242
20547
  }
20243
20548
  var execFileAsync6, CELL_WORKSPACE, CELL_STATE_DIR, CHECKPOINT_MESSAGE_FILE, CELL_RUNTIME_DIR, INSTALLED_RUNTIME_PACKAGE, CELL_RUNTIME_SDK_ENTRY, NOTES_FILE, MEMORY_FILE, MEMORY_EXTRACTION_TIMEOUT_MS, LIVENESS_CHECK_MS, ARTIFACTS_DIR, MAX_ARTIFACTS, MAX_ARTIFACT_BYTES, BRANCH_RE, REPOSITORY_RE, GIT, COMMIT_SHA_RE, MAX_TOOL_OUTPUT_CHARS, MAX_TOOL_INPUT_CHARS, MAX_CHECKPOINTS, CELL_CONTROL_DIR, BRIDGE_MARKER, CONTROL_RUNNER, BRIDGE_RUNNER, HEALTH_TIMEOUT_MS, EVENT_POLL_MS, AsterHotcellRuntime, CELL_FILE_WRITE_CHUNK_CHARS, ARTIFACT_MIME_TYPES;
20244
20549
  var init_aster_cell_runtime = __esm({
@@ -20681,9 +20986,9 @@ ${turn.userText}` : turn.userText;
20681
20986
  if (!isSafeArtifactPath(path)) throw new Error("invalid_artifact_path");
20682
20987
  const cell = await this.provider.getCell(cellId);
20683
20988
  const file = shellQuote2(`${ARTIFACTS_DIR}/${path}`);
20684
- const stat13 = await cell.exec(`[ -f ${file} ] && [ ! -L ${file} ] && stat -c %s -- ${file}`);
20685
- if (stat13.exitCode !== 0) throw new Error("artifact_not_found");
20686
- if (Number(stat13.stdout.trim()) > MAX_ARTIFACT_BYTES) throw new Error("artifact_too_large");
20989
+ const stat14 = await cell.exec(`[ -f ${file} ] && [ ! -L ${file} ] && stat -c %s -- ${file}`);
20990
+ if (stat14.exitCode !== 0) throw new Error("artifact_not_found");
20991
+ if (Number(stat14.stdout.trim()) > MAX_ARTIFACT_BYTES) throw new Error("artifact_too_large");
20687
20992
  const encoded = await cell.exec(`base64 -w0 -- ${file}`);
20688
20993
  if (encoded.exitCode !== 0) throw new Error("artifact_not_found");
20689
20994
  return { data: Buffer.from(encoded.stdout.trim(), "base64"), mimeType: artifactMimeType(path), name: path.split("/").pop() ?? path };
@@ -20980,8 +21285,8 @@ var init_hotcell_provider = __esm({
20980
21285
  // src/server/routes.ts
20981
21286
  import { randomUUID as randomUUID9 } from "crypto";
20982
21287
  import { URL as URL2 } from "url";
20983
- import { readFile as readFile27, unlink as unlink3 } from "fs/promises";
20984
- import { resolve as resolve14, basename as basename7 } from "path";
21288
+ import { readFile as readFile28, unlink as unlink3 } from "fs/promises";
21289
+ import { resolve as resolve15, basename as basename7 } from "path";
20985
21290
  function createHotcellAsterRuntime() {
20986
21291
  try {
20987
21292
  const idlePauseMs = Number(process.env.AUTOPILOT_ASTER_IDLE_PAUSE_MS ?? 15 * 60 * 1e3);
@@ -21064,9 +21369,9 @@ async function resolveFiles2(filePatterns, cwd) {
21064
21369
  const resolved = /* @__PURE__ */ new Set();
21065
21370
  for (const pattern of filePatterns) {
21066
21371
  try {
21067
- const stat13 = await import("fs/promises").then((m) => m.stat(resolve14(cwd, pattern)));
21068
- if (stat13.isFile()) {
21069
- resolved.add(resolve14(cwd, pattern));
21372
+ const stat14 = await import("fs/promises").then((m) => m.stat(resolve15(cwd, pattern)));
21373
+ if (stat14.isFile()) {
21374
+ resolved.add(resolve15(cwd, pattern));
21070
21375
  continue;
21071
21376
  }
21072
21377
  } catch {
@@ -21094,7 +21399,7 @@ async function buildUserMessage2(prompt, files, cwd) {
21094
21399
  }
21095
21400
  } else {
21096
21401
  try {
21097
- const content = await readFile27(filePath, "utf8");
21402
+ const content = await readFile28(filePath, "utf8");
21098
21403
  const relPath = filePath.startsWith(cwd) ? filePath.slice(cwd.length + 1) : filePath;
21099
21404
  fileContents.push(`
21100
21405
  --- ${relPath} ---
@@ -21123,7 +21428,7 @@ function setupRoutes(config2, options = {}) {
21123
21428
  if (!run.sessionId) throw new Error("Cannot restore run without a session id: " + run.id);
21124
21429
  const existing = activeRuns.get(run.id) ?? activeSessions.get(run.sessionId);
21125
21430
  if (existing) return existing;
21126
- const sessionFile = await loadSession(resolve14(sessionsDir(), run.sessionId + ".json"));
21431
+ const sessionFile = await loadSession(resolve15(sessionsDir(), run.sessionId + ".json"));
21127
21432
  const allowedTools = new Set(run.allowedTools);
21128
21433
  allowedTools.add("wait_for");
21129
21434
  const tools = ALL_TOOLS.filter((tool) => allowedTools.has(tool.name));
@@ -21258,7 +21563,7 @@ function setupRoutes(config2, options = {}) {
21258
21563
  const task = typeof body.task === "string" ? body.task.trim() : "";
21259
21564
  let cwd;
21260
21565
  try {
21261
- cwd = typeof body.cwd === "string" ? resolve14(body.cwd) : process.cwd();
21566
+ cwd = typeof body.cwd === "string" ? resolve15(body.cwd) : process.cwd();
21262
21567
  } catch {
21263
21568
  badRequest(res, "cwd must be a valid path");
21264
21569
  return;
@@ -21371,7 +21676,7 @@ function setupRoutes(config2, options = {}) {
21371
21676
  store.close();
21372
21677
  }
21373
21678
  } catch (error) {
21374
- await unlink3(resolve14(sessionsDir(), `${sessionId}.json`)).catch(() => {
21679
+ await unlink3(resolve15(sessionsDir(), `${sessionId}.json`)).catch(() => {
21375
21680
  });
21376
21681
  if (worktree) {
21377
21682
  await worktreeManager.discard(worktree).catch((cleanupError) => {
@@ -21506,7 +21811,7 @@ function setupRoutes(config2, options = {}) {
21506
21811
  return;
21507
21812
  }
21508
21813
  try {
21509
- const file = await loadSession(resolve14(sessionsDir(), `${sessionId}.json`));
21814
+ const file = await loadSession(resolve15(sessionsDir(), `${sessionId}.json`));
21510
21815
  json2(res, 200, {
21511
21816
  id: file.id,
21512
21817
  cwd: file.cwd,
@@ -21526,7 +21831,7 @@ function setupRoutes(config2, options = {}) {
21526
21831
  activeSessions.delete(sessionId);
21527
21832
  try {
21528
21833
  const { unlink: unlink6 } = await import("fs/promises");
21529
- await unlink6(resolve14(sessionsDir(), `${sessionId}.json`));
21834
+ await unlink6(resolve15(sessionsDir(), `${sessionId}.json`));
21530
21835
  } catch {
21531
21836
  }
21532
21837
  json2(res, 200, { deleted: sessionId });
@@ -21977,13 +22282,13 @@ async function startServer(opts2) {
21977
22282
  };
21978
22283
  process.on("SIGINT", shutdown);
21979
22284
  process.on("SIGTERM", shutdown);
21980
- return new Promise((resolve19, reject) => {
22285
+ return new Promise((resolve20, reject) => {
21981
22286
  server.listen(opts2.port, opts2.hostname, () => {
21982
22287
  logger.info("server: listening", { hostname: opts2.hostname, port: opts2.port });
21983
22288
  console.log(`kimiflare serve: http://${opts2.hostname}:${opts2.port}`);
21984
22289
  console.log(` API docs: http://${opts2.hostname}:${opts2.port}/doc`);
21985
22290
  console.log(` SSE stream: http://${opts2.hostname}:${opts2.port}/event`);
21986
- resolve19(server);
22291
+ resolve20(server);
21987
22292
  });
21988
22293
  server.on("error", reject);
21989
22294
  });
@@ -22288,8 +22593,8 @@ async function runEmitMode(opts2) {
22288
22593
  async function nextFollowUp() {
22289
22594
  if (followUpQueue.length > 0) return followUpQueue.shift();
22290
22595
  if (stdinClosed) return null;
22291
- return new Promise((resolve19) => {
22292
- followUpResolver = resolve19;
22596
+ return new Promise((resolve20) => {
22597
+ followUpResolver = resolve20;
22293
22598
  });
22294
22599
  }
22295
22600
  const cwd = process.cwd();
@@ -22426,8 +22731,8 @@ async function runEmitMode(opts2) {
22426
22731
  return "allow";
22427
22732
  }
22428
22733
  if (opts2.multiTurn) {
22429
- const choice = await new Promise((resolve19) => {
22430
- pendingPermissions.set(reqId, resolve19);
22734
+ const choice = await new Promise((resolve20) => {
22735
+ pendingPermissions.set(reqId, resolve20);
22431
22736
  });
22432
22737
  if (choice === "allow" || choice === "allow_session") {
22433
22738
  emit("PermissionGranted", { request_id: reqId });
@@ -22562,7 +22867,7 @@ async function runAttachMode(opts2) {
22562
22867
  async function streamSse(url, sessionId, format) {
22563
22868
  const eventSource = new EventSource(`${url}/event`);
22564
22869
  let done = false;
22565
- return new Promise((resolve19, reject) => {
22870
+ return new Promise((resolve20, reject) => {
22566
22871
  eventSource.onmessage = (event) => {
22567
22872
  try {
22568
22873
  const data = JSON.parse(event.data);
@@ -22609,7 +22914,7 @@ async function streamSse(url, sessionId, format) {
22609
22914
  done = true;
22610
22915
  eventSource.close();
22611
22916
  if (format === "text") process.stdout.write("\n");
22612
- resolve19(void 0);
22917
+ resolve20(void 0);
22613
22918
  break;
22614
22919
  case "error":
22615
22920
  done = true;
@@ -22622,7 +22927,7 @@ async function streamSse(url, sessionId, format) {
22622
22927
  process.stdout.write(JSON.stringify({ event: "error", message: data.message }) + "\n");
22623
22928
  }
22624
22929
  process.exitCode = 1;
22625
- resolve19(void 0);
22930
+ resolve20(void 0);
22626
22931
  break;
22627
22932
  }
22628
22933
  } catch {
@@ -22648,7 +22953,7 @@ async function streamSseJson(url, sessionId) {
22648
22953
  const toolResults = [];
22649
22954
  let usage;
22650
22955
  const eventSource = new EventSource(`${url}/event`);
22651
- return new Promise((resolve19, reject) => {
22956
+ return new Promise((resolve20, reject) => {
22652
22957
  eventSource.onmessage = (event) => {
22653
22958
  try {
22654
22959
  const data = JSON.parse(event.data);
@@ -22685,7 +22990,7 @@ async function streamSseJson(url, sessionId) {
22685
22990
  2
22686
22991
  ) + "\n"
22687
22992
  );
22688
- resolve19(void 0);
22993
+ resolve20(void 0);
22689
22994
  break;
22690
22995
  case "error":
22691
22996
  eventSource.close();
@@ -22693,7 +22998,7 @@ async function streamSseJson(url, sessionId) {
22693
22998
  JSON.stringify({ error: data.message, sessionId }, null, 2) + "\n"
22694
22999
  );
22695
23000
  process.exitCode = 1;
22696
- resolve19(void 0);
23001
+ resolve20(void 0);
22697
23002
  break;
22698
23003
  }
22699
23004
  } catch {
@@ -23361,6 +23666,9 @@ var init_help_menu = __esm({
23361
23666
  });
23362
23667
 
23363
23668
  // src/agent/queue-batch.ts
23669
+ function canDrainQueue(state) {
23670
+ return !state.busy && !state.queuePlanOpen && state.supervisorIdle && state.hasPendingWork;
23671
+ }
23364
23672
  function createQueueBatch(items) {
23365
23673
  if (items.length < 2) return null;
23366
23674
  if (items.some((item) => isCommand(item.full))) return null;
@@ -23419,10 +23727,9 @@ __export(app_helpers_exports, {
23419
23727
  replaceUserPromptEvent: () => replaceUserPromptEvent,
23420
23728
  trackRecentFile: () => trackRecentFile
23421
23729
  });
23422
- import { execSync as execSync3, spawn as spawn7 } from "child_process";
23730
+ import { execSync as execSync3 } from "child_process";
23423
23731
  import { existsSync as existsSync8, readFileSync as readFileSync6, statSync as statSync5 } from "fs";
23424
- import { join as join41 } from "path";
23425
- import { platform as platform3 } from "os";
23732
+ import { join as join42 } from "path";
23426
23733
  function replaceQueuedPrompt(queue2, key, full, display) {
23427
23734
  const index = queue2.findIndex((item) => item.key === key);
23428
23735
  if (index >= 0) {
@@ -23529,7 +23836,7 @@ function buildFilePickerIgnoreList(cwd) {
23529
23836
  ];
23530
23837
  const gitignorePatterns = [];
23531
23838
  try {
23532
- const gitignorePath = join41(cwd, ".gitignore");
23839
+ const gitignorePath = join42(cwd, ".gitignore");
23533
23840
  const stats = statSync5(gitignorePath);
23534
23841
  if (stats.size > MAX_GITIGNORE_SIZE) {
23535
23842
  return hardcoded;
@@ -23560,19 +23867,6 @@ function costLookupFromConfig(cfg, meta) {
23560
23867
  if (resolveCustomEndpoint(cfg)) return void 0;
23561
23868
  return { apiKey: cfg.openrouterApiKey, meta };
23562
23869
  }
23563
- function openBrowser(url) {
23564
- if (process.env.KIMIFLARE_NO_BROWSER === "1" || process.env.BROWSER === "none") return false;
23565
- try {
23566
- const os2 = platform3();
23567
- const [cmd, args] = os2 === "darwin" ? ["open", [url]] : os2 === "win32" ? ["cmd", ["/c", "start", "", url]] : ["xdg-open", [url]];
23568
- const child = spawn7(cmd, args, { detached: true, stdio: "ignore" });
23569
- child.on("error", () => void 0);
23570
- child.unref();
23571
- return true;
23572
- } catch {
23573
- return false;
23574
- }
23575
- }
23576
23870
  function detectGitHubRepo(cachedRepo) {
23577
23871
  if (cachedRepo) {
23578
23872
  const parts = cachedRepo.split("/");
@@ -23691,6 +23985,7 @@ var init_app_helpers = __esm({
23691
23985
  init_system_prompt();
23692
23986
  init_image();
23693
23987
  init_queue_batch();
23988
+ init_open_browser();
23694
23989
  MAX_GITIGNORE_SIZE = 1 * 1024 * 1024;
23695
23990
  CONTEXT_LIMIT = 262e3;
23696
23991
  AUTO_COMPACT_THRESHOLD = 0.8;
@@ -23707,9 +24002,9 @@ var init_app_helpers = __esm({
23707
24002
 
23708
24003
  // src/ui/bang-command.ts
23709
24004
  import { spawn as spawn8 } from "child_process";
23710
- import { mkdtemp as mkdtemp2, readFile as readFile28, rm as rm5 } from "fs/promises";
23711
- import { tmpdir as tmpdir4, platform as platform4 } from "os";
23712
- import { join as join42 } from "path";
24005
+ import { mkdtemp as mkdtemp3, readFile as readFile29, rm as rm6 } from "fs/promises";
24006
+ import { tmpdir as tmpdir5, platform as platform4 } from "os";
24007
+ import { join as join43 } from "path";
23713
24008
  function registerInkInstance(instance) {
23714
24009
  inkInstance = instance;
23715
24010
  }
@@ -23717,13 +24012,13 @@ function registerTerminalHandoff(h) {
23717
24012
  terminalHandoff = h;
23718
24013
  }
23719
24014
  function runCaptured(inv, cwd) {
23720
- return new Promise((resolve19) => {
24015
+ return new Promise((resolve20) => {
23721
24016
  const child = spawn8(inv.file, inv.args, { cwd, stdio: ["ignore", "pipe", "pipe"], env: inv.env ?? process.env });
23722
24017
  let output = "";
23723
24018
  child.stdout?.on("data", (c) => output += c.toString("utf8"));
23724
24019
  child.stderr?.on("data", (c) => output += c.toString("utf8"));
23725
- child.once("error", (e) => resolve19({ code: 127, signal: null, output: `failed to start: ${e.message}` }));
23726
- child.once("exit", (code, signal) => resolve19({ code, signal, output }));
24020
+ child.once("error", (e) => resolve20({ code: 127, signal: null, output: `failed to start: ${e.message}` }));
24021
+ child.once("exit", (code, signal) => resolve20({ code, signal, output }));
23727
24022
  });
23728
24023
  }
23729
24024
  function isTerminalHandedOff() {
@@ -23791,10 +24086,10 @@ function swallow() {
23791
24086
  });
23792
24087
  }
23793
24088
  function spawnInherit(inv, cwd) {
23794
- return new Promise((resolve19, reject) => {
24089
+ return new Promise((resolve20, reject) => {
23795
24090
  const child = spawn8(inv.file, inv.args, { cwd, stdio: "inherit", env: inv.env ?? process.env });
23796
24091
  child.once("error", reject);
23797
- child.once("exit", (code, signal) => resolve19({ code, signal }));
24092
+ child.once("exit", (code, signal) => resolve20({ code, signal }));
23798
24093
  });
23799
24094
  }
23800
24095
  async function runBangCommand(command, cwd) {
@@ -23812,8 +24107,8 @@ async function runBangCommand(command, cwd) {
23812
24107
  const origErr = stderr.write;
23813
24108
  const readable = stdin.listeners("readable");
23814
24109
  const wasRaw = stdin.isTTY ? stdin.isRaw : false;
23815
- const logDir2 = isWindows ? null : await mkdtemp2(join42(tmpdir4(), "autopilot-bang-"));
23816
- const logPath = logDir2 ? join42(logDir2, "out.log") : null;
24110
+ const logDir2 = isWindows ? null : await mkdtemp3(join43(tmpdir5(), "autopilot-bang-"));
24111
+ const logPath = logDir2 ? join43(logDir2, "out.log") : null;
23817
24112
  const viaScript = logPath ? scriptInvocation(command, shell, logPath) : null;
23818
24113
  inkInstance?.clear();
23819
24114
  origOut.call(stdout, `
@@ -23855,9 +24150,9 @@ $ ${command}
23855
24150
  }
23856
24151
  let output = spawnError ? `failed to start: ${spawnError}` : null;
23857
24152
  if (captured && logPath) {
23858
- output = cleanTerminalOutput(await readFile28(logPath, "utf8").catch(() => ""));
24153
+ output = cleanTerminalOutput(await readFile29(logPath, "utf8").catch(() => ""));
23859
24154
  }
23860
- if (logDir2) await rm5(logDir2, { recursive: true, force: true }).catch(() => {
24155
+ if (logDir2) await rm6(logDir2, { recursive: true, force: true }).catch(() => {
23861
24156
  });
23862
24157
  return { command, exitCode: result2.code, signal: result2.signal, output };
23863
24158
  }
@@ -26047,10 +26342,10 @@ __export(camouflage_view_exports, {
26047
26342
  toolSummary: () => toolSummary,
26048
26343
  validateCommandName: () => validateCommandName
26049
26344
  });
26050
- import { execFileSync as execFileSync2, spawn as spawn10 } from "child_process";
26051
- import { readdir as readdir7 } from "fs/promises";
26345
+ import { execFileSync as execFileSync3, spawn as spawn10 } from "child_process";
26346
+ import { readdir as readdir8 } from "fs/promises";
26052
26347
  import { homedir as homedir26 } from "os";
26053
- import { join as join43, resolve as resolve15 } from "path";
26348
+ import { join as join44, resolve as resolve16 } from "path";
26054
26349
  async function loadSdk() {
26055
26350
  const sdk = await import("camouflage-tui").catch((err) => {
26056
26351
  throw new CamouflageUnavailable(`camouflage-tui is not installed (${err.message})`);
@@ -26139,14 +26434,14 @@ async function runCamouflageView(opts2) {
26139
26434
  }
26140
26435
  }
26141
26436
  function runShell2(command) {
26142
- return new Promise((resolve19) => {
26437
+ return new Promise((resolve20) => {
26143
26438
  const { shell, args } = getShellCommand();
26144
26439
  const child = spawn10(shell, [...args, command], { env: process.env });
26145
26440
  let out = "";
26146
26441
  child.stdout?.on("data", (c) => out += c.toString("utf8"));
26147
26442
  child.stderr?.on("data", (c) => out += c.toString("utf8"));
26148
- child.on("close", (code) => resolve19({ ok: code === 0, output: out || (code === 0 ? "" : `Exit code: ${code}`) }));
26149
- child.on("error", (err) => resolve19({ ok: false, output: err.message }));
26443
+ child.on("close", (code) => resolve20({ ok: code === 0, output: out || (code === 0 ? "" : `Exit code: ${code}`) }));
26444
+ child.on("error", (err) => resolve20({ ok: false, output: err.message }));
26150
26445
  });
26151
26446
  }
26152
26447
  function syncSlashCommands(custom, lastKey, send) {
@@ -26229,10 +26524,10 @@ function truncateText(s, max) {
26229
26524
  async function listMentionDir(cwd, query) {
26230
26525
  const exact = query === "~" || query === "." || query === ".." || query.endsWith("/..");
26231
26526
  const dir = exact ? `${query}/` : query.slice(0, query.lastIndexOf("/") + 1);
26232
- const expanded = dir.startsWith("~") ? join43(homedir26(), dir.slice(1)) : dir;
26233
- const target = resolve15(cwd, expanded || ".");
26527
+ const expanded = dir.startsWith("~") ? join44(homedir26(), dir.slice(1)) : dir;
26528
+ const target = resolve16(cwd, expanded || ".");
26234
26529
  try {
26235
- const items = await readdir7(target, { withFileTypes: true });
26530
+ const items = await readdir8(target, { withFileTypes: true });
26236
26531
  const entries = items.filter((d) => !d.name.startsWith(".")).map((d) => ({ name: d.name, isDir: d.isDirectory() })).sort((a, b) => a.isDir !== b.isDir ? a.isDir ? -1 : 1 : a.name.localeCompare(b.name)).slice(0, 300).map((d) => `${dir}${d.name}${d.isDir ? "/" : ""}`);
26237
26532
  return { dir, entries };
26238
26533
  } catch {
@@ -26315,14 +26610,14 @@ function shortPath(p) {
26315
26610
  }
26316
26611
  function gitBranch(cwd) {
26317
26612
  try {
26318
- return execFileSync2("git", ["rev-parse", "--abbrev-ref", "HEAD"], { cwd, encoding: "utf8", timeout: 500, stdio: ["ignore", "pipe", "ignore"] }).trim();
26613
+ return execFileSync3("git", ["rev-parse", "--abbrev-ref", "HEAD"], { cwd, encoding: "utf8", timeout: 500, stdio: ["ignore", "pipe", "ignore"] }).trim();
26319
26614
  } catch {
26320
26615
  return "";
26321
26616
  }
26322
26617
  }
26323
26618
  function listFiles(cwd) {
26324
26619
  try {
26325
- const out = execFileSync2("git", ["ls-files", "--cached", "--others", "--exclude-standard"], {
26620
+ const out = execFileSync3("git", ["ls-files", "--cached", "--others", "--exclude-standard"], {
26326
26621
  cwd,
26327
26622
  encoding: "utf8",
26328
26623
  timeout: 2e3,
@@ -29221,19 +29516,19 @@ function usePermissionController(getMode, onPlanModeBlocked) {
29221
29516
  const onPlanModeBlockedRef = useRef3(onPlanModeBlocked);
29222
29517
  onPlanModeBlockedRef.current = onPlanModeBlocked;
29223
29518
  const askPermission = useCallback2(
29224
- (req, askOpts) => new Promise((resolve19) => {
29519
+ (req, askOpts) => new Promise((resolve20) => {
29225
29520
  const outcome = decidePermission(req, getModeRef.current(), askOpts);
29226
29521
  if (outcome.kind === "resolve") {
29227
- resolve19(outcome.decision);
29522
+ resolve20(outcome.decision);
29228
29523
  return;
29229
29524
  }
29230
29525
  if (outcome.kind === "plan_blocked") {
29231
29526
  onPlanModeBlockedRef.current(outcome.toolName);
29232
- resolve19(AUTO_DENY);
29527
+ resolve20(AUTO_DENY);
29233
29528
  return;
29234
29529
  }
29235
- resolveRef.current = resolve19;
29236
- setPending({ tool: req.tool, args: req.args, resolve: resolve19 });
29530
+ resolveRef.current = resolve20;
29531
+ setPending({ tool: req.tool, args: req.args, resolve: resolve20 });
29237
29532
  }),
29238
29533
  []
29239
29534
  );
@@ -29578,9 +29873,9 @@ var init_queue_plan_picker = __esm({
29578
29873
  });
29579
29874
 
29580
29875
  // src/agent/jev-context.ts
29581
- import { execFileSync as execFileSync3 } from "child_process";
29582
- import { readFile as readFile29 } from "fs/promises";
29583
- import { basename as basename8, join as join44, resolve as resolve16 } from "path";
29876
+ import { execFileSync as execFileSync4 } from "child_process";
29877
+ import { readFile as readFile30 } from "fs/promises";
29878
+ import { basename as basename8, join as join45, resolve as resolve17 } from "path";
29584
29879
  function messageText(message2) {
29585
29880
  if (typeof message2.content === "string") return message2.content.trim();
29586
29881
  if (!Array.isArray(message2.content)) return "";
@@ -29591,18 +29886,18 @@ function redactCommonSecrets(text) {
29591
29886
  }
29592
29887
  function projectRoot(cwd) {
29593
29888
  try {
29594
- return execFileSync3("git", ["-C", cwd, "rev-parse", "--show-toplevel"], {
29889
+ return execFileSync4("git", ["-C", cwd, "rev-parse", "--show-toplevel"], {
29595
29890
  encoding: "utf8",
29596
29891
  stdio: ["ignore", "pipe", "ignore"],
29597
29892
  timeout: 1e3
29598
29893
  }).trim();
29599
29894
  } catch {
29600
- return resolve16(cwd);
29895
+ return resolve17(cwd);
29601
29896
  }
29602
29897
  }
29603
29898
  async function readPackageMetadata(root) {
29604
29899
  try {
29605
- const parsed = JSON.parse(await readFile29(join44(root, "package.json"), "utf8"));
29900
+ const parsed = JSON.parse(await readFile30(join45(root, "package.json"), "utf8"));
29606
29901
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return {};
29607
29902
  const pkg = parsed;
29608
29903
  const metadata = {};
@@ -29619,7 +29914,7 @@ async function readPackageMetadata(root) {
29619
29914
  async function readLicenseEvidence(root) {
29620
29915
  for (const name of ["LICENSE", "LICENSE.md", "LICENSE.txt", "LICENCE", "COPYING"]) {
29621
29916
  try {
29622
- const content = (await readFile29(join44(root, name), "utf8")).trim();
29917
+ const content = (await readFile30(join45(root, name), "utf8")).trim();
29623
29918
  if (content) return { source: `project license (${name})`, content: content.slice(0, 700) };
29624
29919
  } catch {
29625
29920
  }
@@ -29652,7 +29947,7 @@ async function buildJevContext(question, messages, cwd = process.cwd()) {
29652
29947
  conversationRemaining -= source.length + content.length + 2;
29653
29948
  }
29654
29949
  }
29655
- const currentDirectory = basename8(resolve16(cwd));
29950
+ const currentDirectory = basename8(resolve17(cwd));
29656
29951
  const escapedDirectory = currentDirectory.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
29657
29952
  const namesCurrentDirectory = currentDirectory.length >= 5 && !/^(?:agent|app|code|lib|project|repo|src|test|tests|workspace)$/i.test(currentDirectory) && new RegExp(`\\b${escapedDirectory}\\b`, "i").test(question);
29658
29953
  if (CURRENT_PROJECT_REFERENCE.test(question) || namesCurrentDirectory) {
@@ -30701,8 +30996,8 @@ var init_frontmatter = __esm({
30701
30996
  });
30702
30997
 
30703
30998
  // src/skills/loader.ts
30704
- import { readFile as readFile30, readdir as readdir8, stat as stat10 } from "fs/promises";
30705
- import { join as join45, extname } from "path";
30999
+ import { readFile as readFile31, readdir as readdir9, stat as stat11 } from "fs/promises";
31000
+ import { join as join46, extname } from "path";
30706
31001
  function normalizeManifest(raw, filePath) {
30707
31002
  const name = typeof raw.name === "string" ? raw.name : "";
30708
31003
  const description = typeof raw.description === "string" ? raw.description : "";
@@ -30716,7 +31011,7 @@ function normalizeManifest(raw, filePath) {
30716
31011
  return { name, description, match, scope, priority, enabled: enabled2 };
30717
31012
  }
30718
31013
  async function loadSkillFile(filePath) {
30719
- const raw = await readFile30(filePath, "utf-8");
31014
+ const raw = await readFile31(filePath, "utf-8");
30720
31015
  const parsed = parseFrontmatter(raw);
30721
31016
  const manifest = normalizeManifest(parsed.data, filePath);
30722
31017
  const body = parsed.content.trim();
@@ -30735,11 +31030,11 @@ async function loadSkillFile(filePath) {
30735
31030
  }
30736
31031
  async function loadSkillsFromDir(dirPath) {
30737
31032
  try {
30738
- const entries = await readdir8(dirPath);
31033
+ const entries = await readdir9(dirPath);
30739
31034
  const files = [];
30740
31035
  for (const entry of entries) {
30741
- const full = join45(dirPath, entry);
30742
- const s = await stat10(full);
31036
+ const full = join46(dirPath, entry);
31037
+ const s = await stat11(full);
30743
31038
  if (s.isFile() && extname(entry) === ".md") {
30744
31039
  files.push(full);
30745
31040
  }
@@ -30766,12 +31061,12 @@ var init_loader = __esm({
30766
31061
  });
30767
31062
 
30768
31063
  // src/skills/manager.ts
30769
- import { mkdir as mkdir17, writeFile as writeFile15, unlink as unlink4, readFile as readFile31 } from "fs/promises";
30770
- import { join as join46 } from "path";
31064
+ import { mkdir as mkdir18, writeFile as writeFile16, unlink as unlink4, readFile as readFile32 } from "fs/promises";
31065
+ import { join as join47 } from "path";
30771
31066
  function getSkillDirs(cwd) {
30772
31067
  return {
30773
- projectDir: join46(cwd, ".kimiflare", "skills"),
30774
- globalDir: join46(process.env.HOME ?? "", ".config", "kimiflare", "skills")
31068
+ projectDir: join47(cwd, ".kimiflare", "skills"),
31069
+ globalDir: join47(process.env.HOME ?? "", ".config", "kimiflare", "skills")
30775
31070
  };
30776
31071
  }
30777
31072
  async function listAllSkills(cwd) {
@@ -30785,7 +31080,7 @@ async function listAllSkills(cwd) {
30785
31080
  async function createSkill(opts2) {
30786
31081
  const dirs = getSkillDirs(opts2.cwd);
30787
31082
  const dir = opts2.scope === "project" ? dirs.projectDir : dirs.globalDir;
30788
- const filepath = join46(dir, `${opts2.name}.md`);
31083
+ const filepath = join47(dir, `${opts2.name}.md`);
30789
31084
  const frontmatter = {
30790
31085
  name: opts2.name,
30791
31086
  enabled: true,
@@ -30806,8 +31101,8 @@ ${yaml}
30806
31101
 
30807
31102
  Add your instructions here.
30808
31103
  `;
30809
- await mkdir17(dir, { recursive: true });
30810
- await writeFile15(filepath, content, "utf8");
31104
+ await mkdir18(dir, { recursive: true });
31105
+ await writeFile16(filepath, content, "utf8");
30811
31106
  return { filepath };
30812
31107
  }
30813
31108
  async function deleteSkill(name, cwd) {
@@ -30821,7 +31116,7 @@ async function setSkillEnabled(name, enabled2, cwd) {
30821
31116
  const all = await listAllSkills(cwd);
30822
31117
  const skill = all.project.find((s) => s.name === name) ?? all.global.find((s) => s.name === name);
30823
31118
  if (!skill) throw new Error(`skill "${name}" not found`);
30824
- const raw = await readFile31(skill.filePath, "utf-8");
31119
+ const raw = await readFile32(skill.filePath, "utf-8");
30825
31120
  const parsed = parseFrontmatter(raw);
30826
31121
  parsed.data.enabled = enabled2;
30827
31122
  const yaml = Object.entries(parsed.data).map(([k, v]) => {
@@ -30833,7 +31128,7 @@ ${v.map((item) => ` - ${item}`).join("\n")}`;
30833
31128
  ${yaml}
30834
31129
  ---
30835
31130
  ${parsed.content}`;
30836
- await writeFile15(skill.filePath, content, "utf8");
31131
+ await writeFile16(skill.filePath, content, "utf8");
30837
31132
  return { filepath: skill.filePath };
30838
31133
  }
30839
31134
  async function findSkillFile(name, cwd) {
@@ -31093,15 +31388,15 @@ var tui_report_exports = {};
31093
31388
  __export(tui_report_exports, {
31094
31389
  getCategoryReportText: () => getCategoryReportText
31095
31390
  });
31096
- import { readFile as readFile32 } from "fs/promises";
31097
- import { join as join47 } from "path";
31391
+ import { readFile as readFile33 } from "fs/promises";
31392
+ import { join as join48 } from "path";
31098
31393
  import { homedir as homedir27 } from "os";
31099
31394
  function usageDir3() {
31100
- const xdg = process.env.XDG_DATA_HOME || join47(homedir27(), ".local", "share");
31101
- return join47(xdg, "kimiflare");
31395
+ const xdg = process.env.XDG_DATA_HOME || join48(homedir27(), ".local", "share");
31396
+ return join48(xdg, "kimiflare");
31102
31397
  }
31103
31398
  function usagePath4() {
31104
- return join47(usageDir3(), "usage.json");
31399
+ return join48(usageDir3(), "usage.json");
31105
31400
  }
31106
31401
  function today3() {
31107
31402
  return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
@@ -31113,7 +31408,7 @@ function daysAgo2(n) {
31113
31408
  }
31114
31409
  async function loadLog3() {
31115
31410
  try {
31116
- const raw = await readFile32(usagePath4(), "utf8");
31411
+ const raw = await readFile33(usagePath4(), "utf8");
31117
31412
  return JSON.parse(raw);
31118
31413
  } catch {
31119
31414
  return { version: 1, days: [], sessions: [] };
@@ -31170,7 +31465,7 @@ var init_tui_report = __esm({
31170
31465
  });
31171
31466
 
31172
31467
  // src/ui/slash-commands.ts
31173
- import { join as join48 } from "path";
31468
+ import { join as join49 } from "path";
31174
31469
  import QRCode from "qrcode";
31175
31470
  function executeFreshStart(ctx, planText, overrideMode, opts2 = {}) {
31176
31471
  const oldSessionId = ctx.sessionIdRef.current;
@@ -31641,7 +31936,7 @@ auto (default) lets the coordinator assess substantial tasks and delegate indepe
31641
31936
  const context = noContext ? [] : await buildJevContext(question.prompt, ctx.messagesRef.current, process.cwd());
31642
31937
  const receipt = formatJevContextReceipt(context, showContext);
31643
31938
  setResult(eventKey, { kind: "info", key: eventKey, text: `Jev is evaluating \xB7 ${receipt}`, pending: true });
31644
- await new Promise((resolve19) => setTimeout(resolve19, 0));
31939
+ await new Promise((resolve20) => setTimeout(resolve20, 0));
31645
31940
  const answer = await askJev(apiKey, question, { context });
31646
31941
  const presentation = presentJevAnswer(question, answer);
31647
31942
  setResult(eventKey, {
@@ -32102,7 +32397,7 @@ ${lines.join("\n")}` }]);
32102
32397
  void (async () => {
32103
32398
  try {
32104
32399
  const { sessionsDir: sessionsDir3 } = await Promise.resolve().then(() => (init_sessions(), sessions_exports));
32105
- const file = await loadSession(join48(sessionsDir3(), `${currentId}.json`));
32400
+ const file = await loadSession(join49(sessionsDir3(), `${currentId}.json`));
32106
32401
  const cps = file.checkpoints ?? [];
32107
32402
  if (cps.length === 0) {
32108
32403
  setEvents((e) => [...e, { kind: "info", key: mkKey2(), text: "no checkpoints in this session" }]);
@@ -32147,7 +32442,7 @@ ${lines.join("\n")}` }]);
32147
32442
  try {
32148
32443
  ctx.ensureSessionId();
32149
32444
  const { sessionsDir: sessionsDir3 } = await Promise.resolve().then(() => (init_sessions(), sessions_exports));
32150
- const filePath = join48(sessionsDir3(), `${ctx.sessionIdRef.current}.json`);
32445
+ const filePath = join49(sessionsDir3(), `${ctx.sessionIdRef.current}.json`);
32151
32446
  await addCheckpoint(filePath, cp);
32152
32447
  setEvents((e) => [...e, { kind: "info", key: mkKey2(), text: `checkpoint saved: "${label}"` }]);
32153
32448
  } catch (e) {
@@ -33203,9 +33498,9 @@ async function startLoopbackListener(opts2 = {}) {
33203
33498
  rejectCode(e);
33204
33499
  finish();
33205
33500
  }
33206
- await new Promise((resolve19, reject) => {
33501
+ await new Promise((resolve20, reject) => {
33207
33502
  server.once("error", reject);
33208
- server.listen(0, "127.0.0.1", () => resolve19());
33503
+ server.listen(0, "127.0.0.1", () => resolve20());
33209
33504
  });
33210
33505
  const address = server.address();
33211
33506
  const port = typeof address === "object" && address ? address.port : 0;
@@ -33631,15 +33926,15 @@ var init_frontmatter2 = __esm({
33631
33926
  });
33632
33927
 
33633
33928
  // src/commands/loader.ts
33634
- import { open, realpath as realpath6 } from "fs/promises";
33929
+ import { open, realpath as realpath7 } from "fs/promises";
33635
33930
  import { homedir as homedir28 } from "os";
33636
- import { join as join49, relative as relative10, sep as sep6 } from "path";
33931
+ import { join as join50, relative as relative11, sep as sep7 } from "path";
33637
33932
  function projectCommandsDir(cwd = process.cwd()) {
33638
- return join49(cwd, ".kimiflare", "commands");
33933
+ return join50(cwd, ".kimiflare", "commands");
33639
33934
  }
33640
33935
  function globalCommandsDir() {
33641
- const xdg = process.env.XDG_CONFIG_HOME || join49(homedir28(), ".config");
33642
- return join49(xdg, "kimiflare", "commands");
33936
+ const xdg = process.env.XDG_CONFIG_HOME || join50(homedir28(), ".config");
33937
+ return join50(xdg, "kimiflare", "commands");
33643
33938
  }
33644
33939
  async function loadCustomCommands(cwd = process.cwd()) {
33645
33940
  const warnings = [];
@@ -33678,7 +33973,7 @@ async function loadCustomCommands(cwd = process.cwd()) {
33678
33973
  async function resolveSafeDir(dir, source, cwd, warnings) {
33679
33974
  let realDir;
33680
33975
  try {
33681
- realDir = await realpath6(dir);
33976
+ realDir = await realpath7(dir);
33682
33977
  } catch (err) {
33683
33978
  const code = err.code;
33684
33979
  if (code !== "ENOENT" && code !== "ENOTDIR") {
@@ -33689,11 +33984,11 @@ async function resolveSafeDir(dir, source, cwd, warnings) {
33689
33984
  if (source === "project") {
33690
33985
  let realCwd;
33691
33986
  try {
33692
- realCwd = await realpath6(cwd);
33987
+ realCwd = await realpath7(cwd);
33693
33988
  } catch {
33694
33989
  return null;
33695
33990
  }
33696
- const rel = relative10(realCwd, realDir);
33991
+ const rel = relative11(realCwd, realDir);
33697
33992
  if (rel !== "" && isPathOutside(rel)) {
33698
33993
  warnings.push(`commands dir ${dir} escapes workspace via symlink \u2014 skipped`);
33699
33994
  return null;
@@ -33768,10 +34063,10 @@ async function loadOne(file, rootDir, source, warnings) {
33768
34063
  return cmd;
33769
34064
  }
33770
34065
  function filenameToCommandName(file, rootDir) {
33771
- const rel = relative10(rootDir, file);
34066
+ const rel = relative11(rootDir, file);
33772
34067
  if (!rel || isPathOutside(rel)) return null;
33773
34068
  const noExt = rel.replace(/\.md$/i, "");
33774
- const parts = noExt.split(sep6).filter((p) => p.length > 0);
34069
+ const parts = noExt.split(sep7).filter((p) => p.length > 0);
33775
34070
  if (parts.length === 0) return null;
33776
34071
  if (parts.some((p) => !/^[\w.-]+$/.test(p))) return null;
33777
34072
  return parts.join("/");
@@ -33791,8 +34086,8 @@ var init_loader2 = __esm({
33791
34086
 
33792
34087
  // src/commands/renderer.ts
33793
34088
  import { exec } from "child_process";
33794
- import { open as open2, realpath as realpath7 } from "fs/promises";
33795
- import { isAbsolute as isAbsolute7, relative as relative11, resolve as resolvePathJoin, basename as pathBasename } from "path";
34089
+ import { open as open2, realpath as realpath8 } from "fs/promises";
34090
+ import { isAbsolute as isAbsolute8, relative as relative12, resolve as resolvePathJoin, basename as pathBasename } from "path";
33796
34091
  import { promisify as promisify9 } from "util";
33797
34092
  function tokenizeArgs(s) {
33798
34093
  return [...s.matchAll(ARG_TOKEN_RE)].map((match) => {
@@ -33883,7 +34178,7 @@ async function replaceFiles(prompt, warnings, cmd, cwd, maxFileBytes) {
33883
34178
  return "" + trailing;
33884
34179
  });
33885
34180
  }
33886
- const realCwd = await realpath7(cwd).catch(() => cwd);
34181
+ const realCwd = await realpath8(cwd).catch(() => cwd);
33887
34182
  const replacements = await Promise.all(
33888
34183
  matches.map(async (match) => {
33889
34184
  const rawPath = match[1] ?? "";
@@ -33892,23 +34187,23 @@ async function replaceFiles(prompt, warnings, cmd, cwd, maxFileBytes) {
33892
34187
  warnings.push(`file inclusion blocked: @${rawPath} \u2014 secret file pattern`);
33893
34188
  return "";
33894
34189
  }
33895
- if (isAbsolute7(rawPath) || rawPath.startsWith("~")) {
34190
+ if (isAbsolute8(rawPath) || rawPath.startsWith("~")) {
33896
34191
  warnings.push(`file inclusion skipped: @${rawPath} \u2014 outside workspace`);
33897
34192
  return "";
33898
34193
  }
33899
34194
  const resolved = resolvePathJoin(cwd, rawPath);
33900
- if (isPathOutside(relative11(cwd, resolved))) {
34195
+ if (isPathOutside(relative12(cwd, resolved))) {
33901
34196
  warnings.push(`file inclusion skipped: @${rawPath} \u2014 outside workspace`);
33902
34197
  return "";
33903
34198
  }
33904
34199
  let real;
33905
34200
  try {
33906
- real = await realpath7(resolved);
34201
+ real = await realpath8(resolved);
33907
34202
  } catch (error) {
33908
34203
  warnings.push(`file inclusion failed: @${rawPath} \u2014 ${message(error)}`);
33909
34204
  return "";
33910
34205
  }
33911
- if (isPathOutside(relative11(realCwd, real))) {
34206
+ if (isPathOutside(relative12(realCwd, real))) {
33912
34207
  warnings.push(`file inclusion skipped: @${rawPath} \u2014 symlink escapes workspace`);
33913
34208
  return "";
33914
34209
  }
@@ -34021,11 +34316,11 @@ var init_wcag = __esm({
34021
34316
  });
34022
34317
 
34023
34318
  // src/ui/theme-loader.ts
34024
- import { readFile as readFile33, readdir as readdir9 } from "fs/promises";
34025
- import { join as join50 } from "path";
34319
+ import { readFile as readFile34, readdir as readdir10 } from "fs/promises";
34320
+ import { join as join51 } from "path";
34026
34321
  import { homedir as homedir29 } from "os";
34027
34322
  function projectThemesDir(cwd = process.cwd()) {
34028
- return join50(cwd, ".kimiflare", "themes");
34323
+ return join51(cwd, ".kimiflare", "themes");
34029
34324
  }
34030
34325
  function isHexColor(c) {
34031
34326
  return /^#[0-9a-fA-F]{6}$/.test(c);
@@ -34109,15 +34404,15 @@ async function loadThemesFromDir(dir, source) {
34109
34404
  const errors = [];
34110
34405
  let files;
34111
34406
  try {
34112
- files = await readdir9(dir);
34407
+ files = await readdir10(dir);
34113
34408
  } catch {
34114
34409
  return { themes, errors };
34115
34410
  }
34116
34411
  for (const file of files.filter((f) => f.endsWith(".json"))) {
34117
- const path = join50(dir, file);
34412
+ const path = join51(dir, file);
34118
34413
  let raw;
34119
34414
  try {
34120
- raw = await readFile33(path, "utf-8");
34415
+ raw = await readFile34(path, "utf-8");
34121
34416
  } catch (e) {
34122
34417
  errors.push(`${path}: ${e instanceof Error ? e.message : String(e)}`);
34123
34418
  continue;
@@ -34263,8 +34558,8 @@ var init_theme_loader = __esm({
34263
34558
  "use strict";
34264
34559
  init_wcag();
34265
34560
  init_theme();
34266
- USER_THEMES_DIR = join50(
34267
- process.env.XDG_CONFIG_HOME || join50(homedir29(), ".config"),
34561
+ USER_THEMES_DIR = join51(
34562
+ process.env.XDG_CONFIG_HOME || join51(homedir29(), ".config"),
34268
34563
  "kimiflare",
34269
34564
  "themes"
34270
34565
  );
@@ -36795,9 +37090,9 @@ var init_resume_progress = __esm({
36795
37090
  });
36796
37091
 
36797
37092
  // src/agent/supervisor.ts
36798
- import { readdir as readdir10, readFile as readFile34, stat as stat11 } from "fs/promises";
37093
+ import { readdir as readdir11, readFile as readFile35, stat as stat12 } from "fs/promises";
36799
37094
  import { createHash as createHash7 } from "crypto";
36800
- import { resolve as resolve17, join as join51 } from "path";
37095
+ import { resolve as resolve18, join as join52 } from "path";
36801
37096
  var TurnSupervisor;
36802
37097
  var init_supervisor = __esm({
36803
37098
  "src/agent/supervisor.ts"() {
@@ -37187,12 +37482,12 @@ var init_input_handlers = __esm({
37187
37482
 
37188
37483
  // src/init/context-generator.ts
37189
37484
  import { existsSync as existsSync9, statSync as statSync6 } from "fs";
37190
- import { join as join52 } from "path";
37485
+ import { join as join53 } from "path";
37191
37486
  function detectFlavor(cwd) {
37192
37487
  for (const [flavor, signatures] of Object.entries(FLAVOR_SIGNATURES)) {
37193
37488
  if (flavor === "generic") continue;
37194
37489
  for (const sig of signatures) {
37195
- const path = join52(cwd, sig);
37490
+ const path = join53(cwd, sig);
37196
37491
  if (sig.includes("*")) {
37197
37492
  try {
37198
37493
  const parts = sig.split("*");
@@ -37213,14 +37508,14 @@ function detectFlavor(cwd) {
37213
37508
  }
37214
37509
  function findFile(cwd, candidates) {
37215
37510
  for (const c of candidates) {
37216
- if (existsSync9(join52(cwd, c))) return c;
37511
+ if (existsSync9(join53(cwd, c))) return c;
37217
37512
  }
37218
37513
  return null;
37219
37514
  }
37220
37515
  function findSourceRoots(cwd) {
37221
37516
  const roots = [];
37222
37517
  for (const r of SOURCE_ROOT_CANDIDATES) {
37223
- const p = join52(cwd, r);
37518
+ const p = join53(cwd, r);
37224
37519
  try {
37225
37520
  const s = statSync6(p);
37226
37521
  if (s.isDirectory()) roots.push(r);
@@ -37231,9 +37526,9 @@ function findSourceRoots(cwd) {
37231
37526
  }
37232
37527
  function findCiConfig(cwd) {
37233
37528
  for (const c of CI_PATHS) {
37234
- if (existsSync9(join52(cwd, c))) {
37529
+ if (existsSync9(join53(cwd, c))) {
37235
37530
  try {
37236
- const s = statSync6(join52(cwd, c));
37531
+ const s = statSync6(join53(cwd, c));
37237
37532
  return s.isDirectory() ? c : c;
37238
37533
  } catch {
37239
37534
  }
@@ -37370,7 +37665,7 @@ function analyzeProject(cwd) {
37370
37665
  ciConfig: findCiConfig(cwd),
37371
37666
  readme: findFile(cwd, ["README.md", "README.rst", "README.txt", "Readme.md"]),
37372
37667
  sourceRoots: findSourceRoots(cwd),
37373
- hasGit: existsSync9(join52(cwd, ".git"))
37668
+ hasGit: existsSync9(join53(cwd, ".git"))
37374
37669
  };
37375
37670
  }
37376
37671
  function bashDiscoveryCommands(profile) {
@@ -37535,7 +37830,7 @@ Aim for 100\u2013200 lines total. Use markdown tables where they save space.
37535
37830
  }
37536
37831
  function buildInitPrompt(cwd) {
37537
37832
  const existingName = ["AGENTS.md", "KIMI.md", "KIMIFLARE.md", "AGENT.md"].find(
37538
- (n) => existsSync9(join52(cwd, n))
37833
+ (n) => existsSync9(join53(cwd, n))
37539
37834
  );
37540
37835
  const isRefresh = existingName !== void 0;
37541
37836
  const targetFilename = existingName ?? "AGENTS.md";
@@ -37619,7 +37914,7 @@ var init_context_generator = __esm({
37619
37914
 
37620
37915
  // src/init/run-init.ts
37621
37916
  import { existsSync as existsSync10 } from "fs";
37622
- import { join as join53 } from "path";
37917
+ import { join as join54 } from "path";
37623
37918
  async function runInit(deps) {
37624
37919
  const {
37625
37920
  cfg,
@@ -37712,7 +38007,7 @@ async function runInit(deps) {
37712
38007
  lspManagerRef.current.notifyChange(path, content);
37713
38008
  } else {
37714
38009
  void import("fs/promises").then(
37715
- ({ readFile: readFile36 }) => readFile36(path, "utf8").then((c) => lspManagerRef.current.notifyChange(path, c)).catch(() => {
38010
+ ({ readFile: readFile37 }) => readFile37(path, "utf8").then((c) => lspManagerRef.current.notifyChange(path, c)).catch(() => {
37716
38011
  })
37717
38012
  );
37718
38013
  }
@@ -37817,7 +38112,7 @@ async function runInit(deps) {
37817
38112
  }
37818
38113
  }
37819
38114
  });
37820
- if (existsSync10(join53(cwd, targetFilename))) {
38115
+ if (existsSync10(join54(cwd, targetFilename))) {
37821
38116
  if (cacheStableRef.current) {
37822
38117
  messagesRef.current[1] = {
37823
38118
  role: "system",
@@ -37909,11 +38204,11 @@ var init_run_init = __esm({
37909
38204
  });
37910
38205
 
37911
38206
  // src/skills/discovery.ts
37912
- import { readdir as readdir11, stat as stat12, readFile as readFile35 } from "fs/promises";
37913
- import { join as join54, extname as extname2 } from "path";
38207
+ import { readdir as readdir12, stat as stat13, readFile as readFile36 } from "fs/promises";
38208
+ import { join as join55, extname as extname2 } from "path";
37914
38209
  async function dirExists(path) {
37915
38210
  try {
37916
- const s = await stat12(path);
38211
+ const s = await stat13(path);
37917
38212
  return s.isDirectory();
37918
38213
  } catch {
37919
38214
  return false;
@@ -37921,7 +38216,7 @@ async function dirExists(path) {
37921
38216
  }
37922
38217
  async function fileExists(path) {
37923
38218
  try {
37924
- const s = await stat12(path);
38219
+ const s = await stat13(path);
37925
38220
  return s.isFile();
37926
38221
  } catch {
37927
38222
  return false;
@@ -37929,25 +38224,25 @@ async function fileExists(path) {
37929
38224
  }
37930
38225
  async function scanSkillDir(dirPath, source) {
37931
38226
  if (!await dirExists(dirPath)) return [];
37932
- const entries = await readdir11(dirPath, { withFileTypes: true });
38227
+ const entries = await readdir12(dirPath, { withFileTypes: true });
37933
38228
  const files = [];
37934
38229
  for (const entry of entries) {
37935
38230
  if (!entry.isFile()) continue;
37936
38231
  if (!SKILL_EXTENSIONS.has(extname2(entry.name))) continue;
37937
- files.push({ filePath: join54(dirPath, entry.name), source });
38232
+ files.push({ filePath: join55(dirPath, entry.name), source });
37938
38233
  }
37939
38234
  return files;
37940
38235
  }
37941
38236
  async function discoverSkills(cwd) {
37942
- const agentsSkills = await scanSkillDir(join54(cwd, ".agents", "skills"), "agents");
37943
- const agentsMd = await fileExists(join54(cwd, "AGENTS.md")) ? [{ filePath: join54(cwd, "AGENTS.md"), source: "agents-md" }] : [];
37944
- const githubSkills = await scanSkillDir(join54(cwd, ".github", "skills"), "github");
37945
- const kimiflareSkills = await scanSkillDir(join54(cwd, ".kimiflare", "skills"), "kimiflare");
38237
+ const agentsSkills = await scanSkillDir(join55(cwd, ".agents", "skills"), "agents");
38238
+ const agentsMd = await fileExists(join55(cwd, "AGENTS.md")) ? [{ filePath: join55(cwd, "AGENTS.md"), source: "agents-md" }] : [];
38239
+ const githubSkills = await scanSkillDir(join55(cwd, ".github", "skills"), "github");
38240
+ const kimiflareSkills = await scanSkillDir(join55(cwd, ".kimiflare", "skills"), "kimiflare");
37946
38241
  const ordered = [...agentsSkills, ...agentsMd, ...githubSkills, ...kimiflareSkills];
37947
38242
  return ordered;
37948
38243
  }
37949
38244
  async function readSkillFile(filePath) {
37950
- const bytes = await readFile35(filePath);
38245
+ const bytes = await readFile36(filePath);
37951
38246
  return { bytes, text: bytes.toString("utf-8") };
37952
38247
  }
37953
38248
  var SKILL_EXTENSIONS;
@@ -38153,7 +38448,7 @@ var init_skills = __esm({
38153
38448
 
38154
38449
  // src/ui/run-startup-tasks.ts
38155
38450
  import { existsSync as existsSync11 } from "fs";
38156
- import { join as join55 } from "path";
38451
+ import { join as join56 } from "path";
38157
38452
  function runStartupTasks(deps) {
38158
38453
  const {
38159
38454
  cfg,
@@ -38176,7 +38471,7 @@ function runStartupTasks(deps) {
38176
38471
  }
38177
38472
  });
38178
38473
  if (cfg.memoryEnabled) {
38179
- const dbPath = cfg.memoryDbPath ?? join55(process.cwd(), ".kimiflare", "memory.db");
38474
+ const dbPath = cfg.memoryDbPath ?? join56(process.cwd(), ".kimiflare", "memory.db");
38180
38475
  const manager = new MemoryManager({
38181
38476
  dbPath,
38182
38477
  ...auth,
@@ -38208,7 +38503,7 @@ function runStartupTasks(deps) {
38208
38503
  });
38209
38504
  const cwd = process.cwd();
38210
38505
  sessionStartRecallRef.current = manager.recall({ text: cwd, repoPath: cwd, limit: 5 });
38211
- if (["AGENTS.md", "KIMI.md", "KIMIFLARE.md", "AGENT.md"].some((name) => existsSync11(join55(cwd, name)))) {
38506
+ if (["AGENTS.md", "KIMI.md", "KIMIFLARE.md", "AGENT.md"].some((name) => existsSync11(join56(cwd, name)))) {
38212
38507
  const lastRefresh = manager.getLastKimiMdRefreshTime(cwd);
38213
38508
  const driftCount = manager.countHighSignalMemoriesSince(cwd, lastRefresh);
38214
38509
  if (driftCount >= 5) {
@@ -38219,7 +38514,7 @@ function runStartupTasks(deps) {
38219
38514
  memoryManagerRef.current?.close();
38220
38515
  memoryManagerRef.current = null;
38221
38516
  }
38222
- const skillDbPath = cfg.memoryDbPath ?? join55(process.cwd(), ".kimiflare", "memory.db");
38517
+ const skillDbPath = cfg.memoryDbPath ?? join56(process.cwd(), ".kimiflare", "memory.db");
38223
38518
  const skillDb = getMemoryDb() ?? openMemoryDb(skillDbPath);
38224
38519
  initSkillsSchema(skillDb);
38225
38520
  void indexSkills({
@@ -38576,7 +38871,7 @@ var init_run_compact = __esm({
38576
38871
  });
38577
38872
 
38578
38873
  // src/commands/save.ts
38579
- import { mkdir as mkdir18, writeFile as writeFile16, unlink as unlink5 } from "fs/promises";
38874
+ import { mkdir as mkdir19, writeFile as writeFile17, unlink as unlink5 } from "fs/promises";
38580
38875
  import { dirname as dirname21 } from "path";
38581
38876
  async function saveCustomCommand(opts2) {
38582
38877
  const dir = opts2.source === "project" ? projectCommandsDir(opts2.cwd) : globalCommandsDir();
@@ -38588,8 +38883,8 @@ async function saveCustomCommand(opts2) {
38588
38883
  if (opts2.effort) data.effort = opts2.effort;
38589
38884
  const frontmatter = serializeFrontmatter(data);
38590
38885
  const content = frontmatter + opts2.template;
38591
- await mkdir18(dirname21(filepath), { recursive: true });
38592
- await writeFile16(filepath, content, "utf8");
38886
+ await mkdir19(dirname21(filepath), { recursive: true });
38887
+ await writeFile17(filepath, content, "utf8");
38593
38888
  return { filepath };
38594
38889
  }
38595
38890
  async function deleteCustomCommand(cmd) {
@@ -38712,7 +39007,7 @@ __export(app_exports, {
38712
39007
  import React25, { useState as useState27, useRef as useRef9, useEffect as useEffect11, useCallback as useCallback8, useMemo as useMemo6 } from "react";
38713
39008
  import { Box as Box40, Text as Text41, useApp, useInput as useInput19, useWindowSize as useWindowSize2, render } from "ink";
38714
39009
  import { existsSync as existsSync12 } from "fs";
38715
- import { join as join56, resolve as resolve18 } from "path";
39010
+ import { join as join57, resolve as resolve19 } from "path";
38716
39011
  import { homedir as homedir30 } from "os";
38717
39012
  import { jsx as jsx42, jsxs as jsxs39 } from "react/jsx-runtime";
38718
39013
  function App({
@@ -38844,6 +39139,7 @@ function App({
38844
39139
  hasAnyModal
38845
39140
  } = modals;
38846
39141
  const [queue2, setQueue] = useState27([]);
39142
+ const [queueDrainRevision, setQueueDrainRevision] = useState27(0);
38847
39143
  const runningSubagents = useSubagentList();
38848
39144
  const announcedSubagentsRef = useRef9(/* @__PURE__ */ new Set());
38849
39145
  const queueRef = useRef9([]);
@@ -39039,8 +39335,8 @@ ${wcagWarnings.join("\n")}` }
39039
39335
  const exactDirectory = query === "~" || query === "." || query === ".." || query.endsWith("/..");
39040
39336
  const prefix = exactDirectory ? `${query.replace(/\/$/, "")}/` : slash >= 0 ? query.slice(0, slash + 1) : "";
39041
39337
  const directory = exactDirectory ? query : slash >= 0 ? query.slice(0, slash + 1) : query;
39042
- const expanded = directory.startsWith("~") ? join56(homedir30(), directory.slice(1)) : directory;
39043
- const target = resolve18(cwd, expanded || ".");
39338
+ const expanded = directory.startsWith("~") ? join57(homedir30(), directory.slice(1)) : directory;
39339
+ const target = resolve19(cwd, expanded || ".");
39044
39340
  const entries2 = await glob("*", {
39045
39341
  cwd: target,
39046
39342
  dot: false,
@@ -40022,7 +40318,7 @@ ${result2.output ?? "(output not captured)"}`,
40022
40318
  }
40023
40319
  }
40024
40320
  turnCounterRef.current += 1;
40025
- if (turnCounterRef.current % 15 === 0 && ["AGENTS.md", "KIMI.md", "KIMIFLARE.md", "AGENT.md"].some((name) => existsSync12(join56(process.cwd(), name))) && !kimiMdStale) {
40321
+ if (turnCounterRef.current % 15 === 0 && ["AGENTS.md", "KIMI.md", "KIMIFLARE.md", "AGENT.md"].some((name) => existsSync12(join57(process.cwd(), name))) && !kimiMdStale) {
40026
40322
  setEvents((e) => [
40027
40323
  ...e,
40028
40324
  { kind: "info", key: mkKey(), text: "Tip: Rerunning /init occasionally helps autopilot (formerly kimiflare) stay accurate as your project evolves." }
@@ -40046,7 +40342,7 @@ ${result2.output ?? "(output not captured)"}`,
40046
40342
  };
40047
40343
  ensureSessionId();
40048
40344
  const { sessionsDir: sessionsDir3 } = await Promise.resolve().then(() => (init_sessions(), sessions_exports));
40049
- const filePath = join56(sessionsDir3(), `${sessionIdRef.current}.json`);
40345
+ const filePath = join57(sessionsDir3(), `${sessionIdRef.current}.json`);
40050
40346
  await addCheckpoint(filePath, cp);
40051
40347
  }
40052
40348
  const summary = await generateContinuationSummary({
@@ -40257,6 +40553,7 @@ ${result2.output ?? "(output not captured)"}`,
40257
40553
  const asstId = activeAsstIdRef.current;
40258
40554
  if (asstId !== null) updateAssistant(asstId, () => ({ streaming: false }));
40259
40555
  endTurn();
40556
+ setQueueDrainRevision((revision) => revision + 1);
40260
40557
  activeAsstIdRef.current = null;
40261
40558
  activeScopeRef.current = null;
40262
40559
  clearPermissionResolveRef();
@@ -40376,7 +40673,7 @@ ${result2.output ?? "(output not captured)"}`,
40376
40673
  lspManagerRef.current.notifyChange(path, content2);
40377
40674
  } else {
40378
40675
  void import("fs/promises").then(
40379
- ({ readFile: readFile36 }) => readFile36(path, "utf8").then((c) => lspManagerRef.current.notifyChange(path, c)).catch(() => {
40676
+ ({ readFile: readFile37 }) => readFile37(path, "utf8").then((c) => lspManagerRef.current.notifyChange(path, c)).catch(() => {
40380
40677
  })
40381
40678
  );
40382
40679
  }
@@ -40569,7 +40866,7 @@ ${result2.output ?? "(output not captured)"}`,
40569
40866
  };
40570
40867
  ensureSessionId();
40571
40868
  const { sessionsDir: sessionsDir3 } = await Promise.resolve().then(() => (init_sessions(), sessions_exports));
40572
- const filePath = join56(sessionsDir3(), `${sessionIdRef.current}.json`);
40869
+ const filePath = join57(sessionsDir3(), `${sessionIdRef.current}.json`);
40573
40870
  await addCheckpoint(filePath, cp);
40574
40871
  }
40575
40872
  const summary = await generateContinuationSummary({
@@ -40648,7 +40945,12 @@ ${result2.output ?? "(output not captured)"}`,
40648
40945
  [cfg, handleSlash, updateAssistant, updateTool, saveSessionSafe, updateResponseMeta, setShowPlanCompletePicker, runUserShellCommand, ensureTraceStarted]
40649
40946
  );
40650
40947
  useEffect11(() => {
40651
- if (!busy && queuePlanDraft === null && supervisorRef.current.phase === "idle") {
40948
+ if (canDrainQueue({
40949
+ busy,
40950
+ queuePlanOpen: queuePlanDraft !== null,
40951
+ supervisorIdle: supervisorRef.current.phase === "idle",
40952
+ hasPendingWork: pendingPromptEditRef.current !== null || pendingSteersRef.current.length > 0 || queue2.length > 0
40953
+ })) {
40652
40954
  const pendingEdit = pendingPromptEditRef.current;
40653
40955
  if (pendingEdit) {
40654
40956
  pendingPromptEditRef.current = null;
@@ -40674,7 +40976,7 @@ ${result2.output ?? "(output not captured)"}`,
40674
40976
  });
40675
40977
  }
40676
40978
  }
40677
- }, [busy, queue2, queuePlanDraft, processMessage]);
40979
+ }, [busy, queue2, queuePlanDraft, processMessage, queueDrainRevision]);
40678
40980
  const handleQueuePlanPick = useCallback8(
40679
40981
  (choice) => {
40680
40982
  if (choice === "group" && queuePlanDraft) {
@@ -41131,7 +41433,7 @@ ${result2.output ?? "(output not captured)"}`,
41131
41433
  lsp: {
41132
41434
  servers: cfg?.lspServers ?? {},
41133
41435
  scope: lspScope,
41134
- hasProjectDir: existsSync12(join56(process.cwd(), ".kimiflare"))
41436
+ hasProjectDir: existsSync12(join57(process.cwd(), ".kimiflare"))
41135
41437
  }
41136
41438
  });
41137
41439
  });
@@ -41188,7 +41490,7 @@ ${result2.output ?? "(output not captured)"}`,
41188
41490
  onCommandDelete: handleCommandDelete2,
41189
41491
  lspServers: cfg?.lspServers ?? {},
41190
41492
  lspScope,
41191
- hasProjectDir: existsSync12(join56(process.cwd(), ".kimiflare")),
41493
+ hasProjectDir: existsSync12(join57(process.cwd(), ".kimiflare")),
41192
41494
  onLspSave: handleLspSave2,
41193
41495
  themes: themeList(),
41194
41496
  onPickTheme: handleThemePick,
@@ -41675,11 +41977,11 @@ init_classify();
41675
41977
  init_subagent_policy();
41676
41978
  init_trace();
41677
41979
  init_registry2();
41678
- import { readFile as readFile15 } from "fs/promises";
41679
- import { resolve as resolve6, basename as basename3 } from "path";
41980
+ import { readFile as readFile16 } from "fs/promises";
41981
+ import { resolve as resolve7, basename as basename3 } from "path";
41680
41982
  async function resolveSession(opts2) {
41681
41983
  if (opts2.sessionId) {
41682
- const filePath = resolve6(sessionsDir(), `${opts2.sessionId}.json`);
41984
+ const filePath = resolve7(sessionsDir(), `${opts2.sessionId}.json`);
41683
41985
  try {
41684
41986
  const file = await loadSession(filePath);
41685
41987
  return { sessionFile: file, isNew: false };
@@ -41687,7 +41989,7 @@ async function resolveSession(opts2) {
41687
41989
  }
41688
41990
  }
41689
41991
  if (opts2.continueSession) {
41690
- const cwd = opts2.dir ? resolve6(opts2.dir) : process.cwd();
41992
+ const cwd = opts2.dir ? resolve7(opts2.dir) : process.cwd();
41691
41993
  const sessions = await listSessions(1, cwd);
41692
41994
  if (sessions.length > 0) {
41693
41995
  const filePath = sessions[0].filePath;
@@ -41700,7 +42002,7 @@ async function resolveSession(opts2) {
41700
42002
  return {
41701
42003
  sessionFile: {
41702
42004
  id,
41703
- cwd: opts2.dir ? resolve6(opts2.dir) : process.cwd(),
42005
+ cwd: opts2.dir ? resolve7(opts2.dir) : process.cwd(),
41704
42006
  model: opts2.model,
41705
42007
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
41706
42008
  updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -41714,9 +42016,9 @@ async function resolveFiles(filePatterns, cwd) {
41714
42016
  const resolved = /* @__PURE__ */ new Set();
41715
42017
  for (const pattern of filePatterns) {
41716
42018
  try {
41717
- const stat13 = await import("fs/promises").then((m) => m.stat(resolve6(cwd, pattern)));
41718
- if (stat13.isFile()) {
41719
- resolved.add(resolve6(cwd, pattern));
42019
+ const stat14 = await import("fs/promises").then((m) => m.stat(resolve7(cwd, pattern)));
42020
+ if (stat14.isFile()) {
42021
+ resolved.add(resolve7(cwd, pattern));
41720
42022
  continue;
41721
42023
  }
41722
42024
  } catch {
@@ -41744,7 +42046,7 @@ async function buildUserMessage(prompt, files, cwd) {
41744
42046
  }
41745
42047
  } else {
41746
42048
  try {
41747
- const content = await readFile15(filePath, "utf8");
42049
+ const content = await readFile16(filePath, "utf8");
41748
42050
  const relPath = filePath.startsWith(cwd) ? filePath.slice(cwd.length + 1) : filePath;
41749
42051
  fileContents.push(`
41750
42052
  --- ${relPath} ---
@@ -41779,7 +42081,7 @@ async function runPrintMode(opts2) {
41779
42081
  `
41780
42082
  );
41781
42083
  }
41782
- const cwd = opts2.dir ? resolve6(opts2.dir) : process.cwd();
42084
+ const cwd = opts2.dir ? resolve7(opts2.dir) : process.cwd();
41783
42085
  const baseWorkerTools = getWorkerTools(opts2.workerProfile);
41784
42086
  const { HooksManager: HooksManager2 } = await Promise.resolve().then(() => (init_manager2(), manager_exports));
41785
42087
  const hooks = new HooksManager2(cwd);
@@ -42459,11 +42761,11 @@ async function promptHidden(question) {
42459
42761
  }
42460
42762
  });
42461
42763
  const rl = createInterface4({ input: process.stdin, output, terminal: true });
42462
- return new Promise((resolve19) => {
42764
+ return new Promise((resolve20) => {
42463
42765
  rl.question(question, (answer) => {
42464
42766
  rl.close();
42465
42767
  process.stdout.write("\n");
42466
- resolve19(answer);
42768
+ resolve20(answer);
42467
42769
  });
42468
42770
  muted = true;
42469
42771
  });