autopilot-ai 1.24.2 → 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 {
@@ -23422,10 +23727,9 @@ __export(app_helpers_exports, {
23422
23727
  replaceUserPromptEvent: () => replaceUserPromptEvent,
23423
23728
  trackRecentFile: () => trackRecentFile
23424
23729
  });
23425
- import { execSync as execSync3, spawn as spawn7 } from "child_process";
23730
+ import { execSync as execSync3 } from "child_process";
23426
23731
  import { existsSync as existsSync8, readFileSync as readFileSync6, statSync as statSync5 } from "fs";
23427
- import { join as join41 } from "path";
23428
- import { platform as platform3 } from "os";
23732
+ import { join as join42 } from "path";
23429
23733
  function replaceQueuedPrompt(queue2, key, full, display) {
23430
23734
  const index = queue2.findIndex((item) => item.key === key);
23431
23735
  if (index >= 0) {
@@ -23532,7 +23836,7 @@ function buildFilePickerIgnoreList(cwd) {
23532
23836
  ];
23533
23837
  const gitignorePatterns = [];
23534
23838
  try {
23535
- const gitignorePath = join41(cwd, ".gitignore");
23839
+ const gitignorePath = join42(cwd, ".gitignore");
23536
23840
  const stats = statSync5(gitignorePath);
23537
23841
  if (stats.size > MAX_GITIGNORE_SIZE) {
23538
23842
  return hardcoded;
@@ -23563,19 +23867,6 @@ function costLookupFromConfig(cfg, meta) {
23563
23867
  if (resolveCustomEndpoint(cfg)) return void 0;
23564
23868
  return { apiKey: cfg.openrouterApiKey, meta };
23565
23869
  }
23566
- function openBrowser(url) {
23567
- if (process.env.KIMIFLARE_NO_BROWSER === "1" || process.env.BROWSER === "none") return false;
23568
- try {
23569
- const os2 = platform3();
23570
- const [cmd, args] = os2 === "darwin" ? ["open", [url]] : os2 === "win32" ? ["cmd", ["/c", "start", "", url]] : ["xdg-open", [url]];
23571
- const child = spawn7(cmd, args, { detached: true, stdio: "ignore" });
23572
- child.on("error", () => void 0);
23573
- child.unref();
23574
- return true;
23575
- } catch {
23576
- return false;
23577
- }
23578
- }
23579
23870
  function detectGitHubRepo(cachedRepo) {
23580
23871
  if (cachedRepo) {
23581
23872
  const parts = cachedRepo.split("/");
@@ -23694,6 +23985,7 @@ var init_app_helpers = __esm({
23694
23985
  init_system_prompt();
23695
23986
  init_image();
23696
23987
  init_queue_batch();
23988
+ init_open_browser();
23697
23989
  MAX_GITIGNORE_SIZE = 1 * 1024 * 1024;
23698
23990
  CONTEXT_LIMIT = 262e3;
23699
23991
  AUTO_COMPACT_THRESHOLD = 0.8;
@@ -23710,9 +24002,9 @@ var init_app_helpers = __esm({
23710
24002
 
23711
24003
  // src/ui/bang-command.ts
23712
24004
  import { spawn as spawn8 } from "child_process";
23713
- import { mkdtemp as mkdtemp2, readFile as readFile28, rm as rm5 } from "fs/promises";
23714
- import { tmpdir as tmpdir4, platform as platform4 } from "os";
23715
- 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";
23716
24008
  function registerInkInstance(instance) {
23717
24009
  inkInstance = instance;
23718
24010
  }
@@ -23720,13 +24012,13 @@ function registerTerminalHandoff(h) {
23720
24012
  terminalHandoff = h;
23721
24013
  }
23722
24014
  function runCaptured(inv, cwd) {
23723
- return new Promise((resolve19) => {
24015
+ return new Promise((resolve20) => {
23724
24016
  const child = spawn8(inv.file, inv.args, { cwd, stdio: ["ignore", "pipe", "pipe"], env: inv.env ?? process.env });
23725
24017
  let output = "";
23726
24018
  child.stdout?.on("data", (c) => output += c.toString("utf8"));
23727
24019
  child.stderr?.on("data", (c) => output += c.toString("utf8"));
23728
- child.once("error", (e) => resolve19({ code: 127, signal: null, output: `failed to start: ${e.message}` }));
23729
- 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 }));
23730
24022
  });
23731
24023
  }
23732
24024
  function isTerminalHandedOff() {
@@ -23794,10 +24086,10 @@ function swallow() {
23794
24086
  });
23795
24087
  }
23796
24088
  function spawnInherit(inv, cwd) {
23797
- return new Promise((resolve19, reject) => {
24089
+ return new Promise((resolve20, reject) => {
23798
24090
  const child = spawn8(inv.file, inv.args, { cwd, stdio: "inherit", env: inv.env ?? process.env });
23799
24091
  child.once("error", reject);
23800
- child.once("exit", (code, signal) => resolve19({ code, signal }));
24092
+ child.once("exit", (code, signal) => resolve20({ code, signal }));
23801
24093
  });
23802
24094
  }
23803
24095
  async function runBangCommand(command, cwd) {
@@ -23815,8 +24107,8 @@ async function runBangCommand(command, cwd) {
23815
24107
  const origErr = stderr.write;
23816
24108
  const readable = stdin.listeners("readable");
23817
24109
  const wasRaw = stdin.isTTY ? stdin.isRaw : false;
23818
- const logDir2 = isWindows ? null : await mkdtemp2(join42(tmpdir4(), "autopilot-bang-"));
23819
- 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;
23820
24112
  const viaScript = logPath ? scriptInvocation(command, shell, logPath) : null;
23821
24113
  inkInstance?.clear();
23822
24114
  origOut.call(stdout, `
@@ -23858,9 +24150,9 @@ $ ${command}
23858
24150
  }
23859
24151
  let output = spawnError ? `failed to start: ${spawnError}` : null;
23860
24152
  if (captured && logPath) {
23861
- output = cleanTerminalOutput(await readFile28(logPath, "utf8").catch(() => ""));
24153
+ output = cleanTerminalOutput(await readFile29(logPath, "utf8").catch(() => ""));
23862
24154
  }
23863
- if (logDir2) await rm5(logDir2, { recursive: true, force: true }).catch(() => {
24155
+ if (logDir2) await rm6(logDir2, { recursive: true, force: true }).catch(() => {
23864
24156
  });
23865
24157
  return { command, exitCode: result2.code, signal: result2.signal, output };
23866
24158
  }
@@ -26050,10 +26342,10 @@ __export(camouflage_view_exports, {
26050
26342
  toolSummary: () => toolSummary,
26051
26343
  validateCommandName: () => validateCommandName
26052
26344
  });
26053
- import { execFileSync as execFileSync2, spawn as spawn10 } from "child_process";
26054
- 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";
26055
26347
  import { homedir as homedir26 } from "os";
26056
- import { join as join43, resolve as resolve15 } from "path";
26348
+ import { join as join44, resolve as resolve16 } from "path";
26057
26349
  async function loadSdk() {
26058
26350
  const sdk = await import("camouflage-tui").catch((err) => {
26059
26351
  throw new CamouflageUnavailable(`camouflage-tui is not installed (${err.message})`);
@@ -26142,14 +26434,14 @@ async function runCamouflageView(opts2) {
26142
26434
  }
26143
26435
  }
26144
26436
  function runShell2(command) {
26145
- return new Promise((resolve19) => {
26437
+ return new Promise((resolve20) => {
26146
26438
  const { shell, args } = getShellCommand();
26147
26439
  const child = spawn10(shell, [...args, command], { env: process.env });
26148
26440
  let out = "";
26149
26441
  child.stdout?.on("data", (c) => out += c.toString("utf8"));
26150
26442
  child.stderr?.on("data", (c) => out += c.toString("utf8"));
26151
- child.on("close", (code) => resolve19({ ok: code === 0, output: out || (code === 0 ? "" : `Exit code: ${code}`) }));
26152
- 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 }));
26153
26445
  });
26154
26446
  }
26155
26447
  function syncSlashCommands(custom, lastKey, send) {
@@ -26232,10 +26524,10 @@ function truncateText(s, max) {
26232
26524
  async function listMentionDir(cwd, query) {
26233
26525
  const exact = query === "~" || query === "." || query === ".." || query.endsWith("/..");
26234
26526
  const dir = exact ? `${query}/` : query.slice(0, query.lastIndexOf("/") + 1);
26235
- const expanded = dir.startsWith("~") ? join43(homedir26(), dir.slice(1)) : dir;
26236
- const target = resolve15(cwd, expanded || ".");
26527
+ const expanded = dir.startsWith("~") ? join44(homedir26(), dir.slice(1)) : dir;
26528
+ const target = resolve16(cwd, expanded || ".");
26237
26529
  try {
26238
- const items = await readdir7(target, { withFileTypes: true });
26530
+ const items = await readdir8(target, { withFileTypes: true });
26239
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 ? "/" : ""}`);
26240
26532
  return { dir, entries };
26241
26533
  } catch {
@@ -26318,14 +26610,14 @@ function shortPath(p) {
26318
26610
  }
26319
26611
  function gitBranch(cwd) {
26320
26612
  try {
26321
- 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();
26322
26614
  } catch {
26323
26615
  return "";
26324
26616
  }
26325
26617
  }
26326
26618
  function listFiles(cwd) {
26327
26619
  try {
26328
- const out = execFileSync2("git", ["ls-files", "--cached", "--others", "--exclude-standard"], {
26620
+ const out = execFileSync3("git", ["ls-files", "--cached", "--others", "--exclude-standard"], {
26329
26621
  cwd,
26330
26622
  encoding: "utf8",
26331
26623
  timeout: 2e3,
@@ -29224,19 +29516,19 @@ function usePermissionController(getMode, onPlanModeBlocked) {
29224
29516
  const onPlanModeBlockedRef = useRef3(onPlanModeBlocked);
29225
29517
  onPlanModeBlockedRef.current = onPlanModeBlocked;
29226
29518
  const askPermission = useCallback2(
29227
- (req, askOpts) => new Promise((resolve19) => {
29519
+ (req, askOpts) => new Promise((resolve20) => {
29228
29520
  const outcome = decidePermission(req, getModeRef.current(), askOpts);
29229
29521
  if (outcome.kind === "resolve") {
29230
- resolve19(outcome.decision);
29522
+ resolve20(outcome.decision);
29231
29523
  return;
29232
29524
  }
29233
29525
  if (outcome.kind === "plan_blocked") {
29234
29526
  onPlanModeBlockedRef.current(outcome.toolName);
29235
- resolve19(AUTO_DENY);
29527
+ resolve20(AUTO_DENY);
29236
29528
  return;
29237
29529
  }
29238
- resolveRef.current = resolve19;
29239
- setPending({ tool: req.tool, args: req.args, resolve: resolve19 });
29530
+ resolveRef.current = resolve20;
29531
+ setPending({ tool: req.tool, args: req.args, resolve: resolve20 });
29240
29532
  }),
29241
29533
  []
29242
29534
  );
@@ -29581,9 +29873,9 @@ var init_queue_plan_picker = __esm({
29581
29873
  });
29582
29874
 
29583
29875
  // src/agent/jev-context.ts
29584
- import { execFileSync as execFileSync3 } from "child_process";
29585
- import { readFile as readFile29 } from "fs/promises";
29586
- 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";
29587
29879
  function messageText(message2) {
29588
29880
  if (typeof message2.content === "string") return message2.content.trim();
29589
29881
  if (!Array.isArray(message2.content)) return "";
@@ -29594,18 +29886,18 @@ function redactCommonSecrets(text) {
29594
29886
  }
29595
29887
  function projectRoot(cwd) {
29596
29888
  try {
29597
- return execFileSync3("git", ["-C", cwd, "rev-parse", "--show-toplevel"], {
29889
+ return execFileSync4("git", ["-C", cwd, "rev-parse", "--show-toplevel"], {
29598
29890
  encoding: "utf8",
29599
29891
  stdio: ["ignore", "pipe", "ignore"],
29600
29892
  timeout: 1e3
29601
29893
  }).trim();
29602
29894
  } catch {
29603
- return resolve16(cwd);
29895
+ return resolve17(cwd);
29604
29896
  }
29605
29897
  }
29606
29898
  async function readPackageMetadata(root) {
29607
29899
  try {
29608
- const parsed = JSON.parse(await readFile29(join44(root, "package.json"), "utf8"));
29900
+ const parsed = JSON.parse(await readFile30(join45(root, "package.json"), "utf8"));
29609
29901
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return {};
29610
29902
  const pkg = parsed;
29611
29903
  const metadata = {};
@@ -29622,7 +29914,7 @@ async function readPackageMetadata(root) {
29622
29914
  async function readLicenseEvidence(root) {
29623
29915
  for (const name of ["LICENSE", "LICENSE.md", "LICENSE.txt", "LICENCE", "COPYING"]) {
29624
29916
  try {
29625
- const content = (await readFile29(join44(root, name), "utf8")).trim();
29917
+ const content = (await readFile30(join45(root, name), "utf8")).trim();
29626
29918
  if (content) return { source: `project license (${name})`, content: content.slice(0, 700) };
29627
29919
  } catch {
29628
29920
  }
@@ -29655,7 +29947,7 @@ async function buildJevContext(question, messages, cwd = process.cwd()) {
29655
29947
  conversationRemaining -= source.length + content.length + 2;
29656
29948
  }
29657
29949
  }
29658
- const currentDirectory = basename8(resolve16(cwd));
29950
+ const currentDirectory = basename8(resolve17(cwd));
29659
29951
  const escapedDirectory = currentDirectory.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
29660
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);
29661
29953
  if (CURRENT_PROJECT_REFERENCE.test(question) || namesCurrentDirectory) {
@@ -30704,8 +30996,8 @@ var init_frontmatter = __esm({
30704
30996
  });
30705
30997
 
30706
30998
  // src/skills/loader.ts
30707
- import { readFile as readFile30, readdir as readdir8, stat as stat10 } from "fs/promises";
30708
- 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";
30709
31001
  function normalizeManifest(raw, filePath) {
30710
31002
  const name = typeof raw.name === "string" ? raw.name : "";
30711
31003
  const description = typeof raw.description === "string" ? raw.description : "";
@@ -30719,7 +31011,7 @@ function normalizeManifest(raw, filePath) {
30719
31011
  return { name, description, match, scope, priority, enabled: enabled2 };
30720
31012
  }
30721
31013
  async function loadSkillFile(filePath) {
30722
- const raw = await readFile30(filePath, "utf-8");
31014
+ const raw = await readFile31(filePath, "utf-8");
30723
31015
  const parsed = parseFrontmatter(raw);
30724
31016
  const manifest = normalizeManifest(parsed.data, filePath);
30725
31017
  const body = parsed.content.trim();
@@ -30738,11 +31030,11 @@ async function loadSkillFile(filePath) {
30738
31030
  }
30739
31031
  async function loadSkillsFromDir(dirPath) {
30740
31032
  try {
30741
- const entries = await readdir8(dirPath);
31033
+ const entries = await readdir9(dirPath);
30742
31034
  const files = [];
30743
31035
  for (const entry of entries) {
30744
- const full = join45(dirPath, entry);
30745
- const s = await stat10(full);
31036
+ const full = join46(dirPath, entry);
31037
+ const s = await stat11(full);
30746
31038
  if (s.isFile() && extname(entry) === ".md") {
30747
31039
  files.push(full);
30748
31040
  }
@@ -30769,12 +31061,12 @@ var init_loader = __esm({
30769
31061
  });
30770
31062
 
30771
31063
  // src/skills/manager.ts
30772
- import { mkdir as mkdir17, writeFile as writeFile15, unlink as unlink4, readFile as readFile31 } from "fs/promises";
30773
- 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";
30774
31066
  function getSkillDirs(cwd) {
30775
31067
  return {
30776
- projectDir: join46(cwd, ".kimiflare", "skills"),
30777
- globalDir: join46(process.env.HOME ?? "", ".config", "kimiflare", "skills")
31068
+ projectDir: join47(cwd, ".kimiflare", "skills"),
31069
+ globalDir: join47(process.env.HOME ?? "", ".config", "kimiflare", "skills")
30778
31070
  };
30779
31071
  }
30780
31072
  async function listAllSkills(cwd) {
@@ -30788,7 +31080,7 @@ async function listAllSkills(cwd) {
30788
31080
  async function createSkill(opts2) {
30789
31081
  const dirs = getSkillDirs(opts2.cwd);
30790
31082
  const dir = opts2.scope === "project" ? dirs.projectDir : dirs.globalDir;
30791
- const filepath = join46(dir, `${opts2.name}.md`);
31083
+ const filepath = join47(dir, `${opts2.name}.md`);
30792
31084
  const frontmatter = {
30793
31085
  name: opts2.name,
30794
31086
  enabled: true,
@@ -30809,8 +31101,8 @@ ${yaml}
30809
31101
 
30810
31102
  Add your instructions here.
30811
31103
  `;
30812
- await mkdir17(dir, { recursive: true });
30813
- await writeFile15(filepath, content, "utf8");
31104
+ await mkdir18(dir, { recursive: true });
31105
+ await writeFile16(filepath, content, "utf8");
30814
31106
  return { filepath };
30815
31107
  }
30816
31108
  async function deleteSkill(name, cwd) {
@@ -30824,7 +31116,7 @@ async function setSkillEnabled(name, enabled2, cwd) {
30824
31116
  const all = await listAllSkills(cwd);
30825
31117
  const skill = all.project.find((s) => s.name === name) ?? all.global.find((s) => s.name === name);
30826
31118
  if (!skill) throw new Error(`skill "${name}" not found`);
30827
- const raw = await readFile31(skill.filePath, "utf-8");
31119
+ const raw = await readFile32(skill.filePath, "utf-8");
30828
31120
  const parsed = parseFrontmatter(raw);
30829
31121
  parsed.data.enabled = enabled2;
30830
31122
  const yaml = Object.entries(parsed.data).map(([k, v]) => {
@@ -30836,7 +31128,7 @@ ${v.map((item) => ` - ${item}`).join("\n")}`;
30836
31128
  ${yaml}
30837
31129
  ---
30838
31130
  ${parsed.content}`;
30839
- await writeFile15(skill.filePath, content, "utf8");
31131
+ await writeFile16(skill.filePath, content, "utf8");
30840
31132
  return { filepath: skill.filePath };
30841
31133
  }
30842
31134
  async function findSkillFile(name, cwd) {
@@ -31096,15 +31388,15 @@ var tui_report_exports = {};
31096
31388
  __export(tui_report_exports, {
31097
31389
  getCategoryReportText: () => getCategoryReportText
31098
31390
  });
31099
- import { readFile as readFile32 } from "fs/promises";
31100
- import { join as join47 } from "path";
31391
+ import { readFile as readFile33 } from "fs/promises";
31392
+ import { join as join48 } from "path";
31101
31393
  import { homedir as homedir27 } from "os";
31102
31394
  function usageDir3() {
31103
- const xdg = process.env.XDG_DATA_HOME || join47(homedir27(), ".local", "share");
31104
- return join47(xdg, "kimiflare");
31395
+ const xdg = process.env.XDG_DATA_HOME || join48(homedir27(), ".local", "share");
31396
+ return join48(xdg, "kimiflare");
31105
31397
  }
31106
31398
  function usagePath4() {
31107
- return join47(usageDir3(), "usage.json");
31399
+ return join48(usageDir3(), "usage.json");
31108
31400
  }
31109
31401
  function today3() {
31110
31402
  return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
@@ -31116,7 +31408,7 @@ function daysAgo2(n) {
31116
31408
  }
31117
31409
  async function loadLog3() {
31118
31410
  try {
31119
- const raw = await readFile32(usagePath4(), "utf8");
31411
+ const raw = await readFile33(usagePath4(), "utf8");
31120
31412
  return JSON.parse(raw);
31121
31413
  } catch {
31122
31414
  return { version: 1, days: [], sessions: [] };
@@ -31173,7 +31465,7 @@ var init_tui_report = __esm({
31173
31465
  });
31174
31466
 
31175
31467
  // src/ui/slash-commands.ts
31176
- import { join as join48 } from "path";
31468
+ import { join as join49 } from "path";
31177
31469
  import QRCode from "qrcode";
31178
31470
  function executeFreshStart(ctx, planText, overrideMode, opts2 = {}) {
31179
31471
  const oldSessionId = ctx.sessionIdRef.current;
@@ -31644,7 +31936,7 @@ auto (default) lets the coordinator assess substantial tasks and delegate indepe
31644
31936
  const context = noContext ? [] : await buildJevContext(question.prompt, ctx.messagesRef.current, process.cwd());
31645
31937
  const receipt = formatJevContextReceipt(context, showContext);
31646
31938
  setResult(eventKey, { kind: "info", key: eventKey, text: `Jev is evaluating \xB7 ${receipt}`, pending: true });
31647
- await new Promise((resolve19) => setTimeout(resolve19, 0));
31939
+ await new Promise((resolve20) => setTimeout(resolve20, 0));
31648
31940
  const answer = await askJev(apiKey, question, { context });
31649
31941
  const presentation = presentJevAnswer(question, answer);
31650
31942
  setResult(eventKey, {
@@ -32105,7 +32397,7 @@ ${lines.join("\n")}` }]);
32105
32397
  void (async () => {
32106
32398
  try {
32107
32399
  const { sessionsDir: sessionsDir3 } = await Promise.resolve().then(() => (init_sessions(), sessions_exports));
32108
- const file = await loadSession(join48(sessionsDir3(), `${currentId}.json`));
32400
+ const file = await loadSession(join49(sessionsDir3(), `${currentId}.json`));
32109
32401
  const cps = file.checkpoints ?? [];
32110
32402
  if (cps.length === 0) {
32111
32403
  setEvents((e) => [...e, { kind: "info", key: mkKey2(), text: "no checkpoints in this session" }]);
@@ -32150,7 +32442,7 @@ ${lines.join("\n")}` }]);
32150
32442
  try {
32151
32443
  ctx.ensureSessionId();
32152
32444
  const { sessionsDir: sessionsDir3 } = await Promise.resolve().then(() => (init_sessions(), sessions_exports));
32153
- const filePath = join48(sessionsDir3(), `${ctx.sessionIdRef.current}.json`);
32445
+ const filePath = join49(sessionsDir3(), `${ctx.sessionIdRef.current}.json`);
32154
32446
  await addCheckpoint(filePath, cp);
32155
32447
  setEvents((e) => [...e, { kind: "info", key: mkKey2(), text: `checkpoint saved: "${label}"` }]);
32156
32448
  } catch (e) {
@@ -33206,9 +33498,9 @@ async function startLoopbackListener(opts2 = {}) {
33206
33498
  rejectCode(e);
33207
33499
  finish();
33208
33500
  }
33209
- await new Promise((resolve19, reject) => {
33501
+ await new Promise((resolve20, reject) => {
33210
33502
  server.once("error", reject);
33211
- server.listen(0, "127.0.0.1", () => resolve19());
33503
+ server.listen(0, "127.0.0.1", () => resolve20());
33212
33504
  });
33213
33505
  const address = server.address();
33214
33506
  const port = typeof address === "object" && address ? address.port : 0;
@@ -33634,15 +33926,15 @@ var init_frontmatter2 = __esm({
33634
33926
  });
33635
33927
 
33636
33928
  // src/commands/loader.ts
33637
- import { open, realpath as realpath6 } from "fs/promises";
33929
+ import { open, realpath as realpath7 } from "fs/promises";
33638
33930
  import { homedir as homedir28 } from "os";
33639
- 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";
33640
33932
  function projectCommandsDir(cwd = process.cwd()) {
33641
- return join49(cwd, ".kimiflare", "commands");
33933
+ return join50(cwd, ".kimiflare", "commands");
33642
33934
  }
33643
33935
  function globalCommandsDir() {
33644
- const xdg = process.env.XDG_CONFIG_HOME || join49(homedir28(), ".config");
33645
- return join49(xdg, "kimiflare", "commands");
33936
+ const xdg = process.env.XDG_CONFIG_HOME || join50(homedir28(), ".config");
33937
+ return join50(xdg, "kimiflare", "commands");
33646
33938
  }
33647
33939
  async function loadCustomCommands(cwd = process.cwd()) {
33648
33940
  const warnings = [];
@@ -33681,7 +33973,7 @@ async function loadCustomCommands(cwd = process.cwd()) {
33681
33973
  async function resolveSafeDir(dir, source, cwd, warnings) {
33682
33974
  let realDir;
33683
33975
  try {
33684
- realDir = await realpath6(dir);
33976
+ realDir = await realpath7(dir);
33685
33977
  } catch (err) {
33686
33978
  const code = err.code;
33687
33979
  if (code !== "ENOENT" && code !== "ENOTDIR") {
@@ -33692,11 +33984,11 @@ async function resolveSafeDir(dir, source, cwd, warnings) {
33692
33984
  if (source === "project") {
33693
33985
  let realCwd;
33694
33986
  try {
33695
- realCwd = await realpath6(cwd);
33987
+ realCwd = await realpath7(cwd);
33696
33988
  } catch {
33697
33989
  return null;
33698
33990
  }
33699
- const rel = relative10(realCwd, realDir);
33991
+ const rel = relative11(realCwd, realDir);
33700
33992
  if (rel !== "" && isPathOutside(rel)) {
33701
33993
  warnings.push(`commands dir ${dir} escapes workspace via symlink \u2014 skipped`);
33702
33994
  return null;
@@ -33771,10 +34063,10 @@ async function loadOne(file, rootDir, source, warnings) {
33771
34063
  return cmd;
33772
34064
  }
33773
34065
  function filenameToCommandName(file, rootDir) {
33774
- const rel = relative10(rootDir, file);
34066
+ const rel = relative11(rootDir, file);
33775
34067
  if (!rel || isPathOutside(rel)) return null;
33776
34068
  const noExt = rel.replace(/\.md$/i, "");
33777
- const parts = noExt.split(sep6).filter((p) => p.length > 0);
34069
+ const parts = noExt.split(sep7).filter((p) => p.length > 0);
33778
34070
  if (parts.length === 0) return null;
33779
34071
  if (parts.some((p) => !/^[\w.-]+$/.test(p))) return null;
33780
34072
  return parts.join("/");
@@ -33794,8 +34086,8 @@ var init_loader2 = __esm({
33794
34086
 
33795
34087
  // src/commands/renderer.ts
33796
34088
  import { exec } from "child_process";
33797
- import { open as open2, realpath as realpath7 } from "fs/promises";
33798
- 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";
33799
34091
  import { promisify as promisify9 } from "util";
33800
34092
  function tokenizeArgs(s) {
33801
34093
  return [...s.matchAll(ARG_TOKEN_RE)].map((match) => {
@@ -33886,7 +34178,7 @@ async function replaceFiles(prompt, warnings, cmd, cwd, maxFileBytes) {
33886
34178
  return "" + trailing;
33887
34179
  });
33888
34180
  }
33889
- const realCwd = await realpath7(cwd).catch(() => cwd);
34181
+ const realCwd = await realpath8(cwd).catch(() => cwd);
33890
34182
  const replacements = await Promise.all(
33891
34183
  matches.map(async (match) => {
33892
34184
  const rawPath = match[1] ?? "";
@@ -33895,23 +34187,23 @@ async function replaceFiles(prompt, warnings, cmd, cwd, maxFileBytes) {
33895
34187
  warnings.push(`file inclusion blocked: @${rawPath} \u2014 secret file pattern`);
33896
34188
  return "";
33897
34189
  }
33898
- if (isAbsolute7(rawPath) || rawPath.startsWith("~")) {
34190
+ if (isAbsolute8(rawPath) || rawPath.startsWith("~")) {
33899
34191
  warnings.push(`file inclusion skipped: @${rawPath} \u2014 outside workspace`);
33900
34192
  return "";
33901
34193
  }
33902
34194
  const resolved = resolvePathJoin(cwd, rawPath);
33903
- if (isPathOutside(relative11(cwd, resolved))) {
34195
+ if (isPathOutside(relative12(cwd, resolved))) {
33904
34196
  warnings.push(`file inclusion skipped: @${rawPath} \u2014 outside workspace`);
33905
34197
  return "";
33906
34198
  }
33907
34199
  let real;
33908
34200
  try {
33909
- real = await realpath7(resolved);
34201
+ real = await realpath8(resolved);
33910
34202
  } catch (error) {
33911
34203
  warnings.push(`file inclusion failed: @${rawPath} \u2014 ${message(error)}`);
33912
34204
  return "";
33913
34205
  }
33914
- if (isPathOutside(relative11(realCwd, real))) {
34206
+ if (isPathOutside(relative12(realCwd, real))) {
33915
34207
  warnings.push(`file inclusion skipped: @${rawPath} \u2014 symlink escapes workspace`);
33916
34208
  return "";
33917
34209
  }
@@ -34024,11 +34316,11 @@ var init_wcag = __esm({
34024
34316
  });
34025
34317
 
34026
34318
  // src/ui/theme-loader.ts
34027
- import { readFile as readFile33, readdir as readdir9 } from "fs/promises";
34028
- import { join as join50 } from "path";
34319
+ import { readFile as readFile34, readdir as readdir10 } from "fs/promises";
34320
+ import { join as join51 } from "path";
34029
34321
  import { homedir as homedir29 } from "os";
34030
34322
  function projectThemesDir(cwd = process.cwd()) {
34031
- return join50(cwd, ".kimiflare", "themes");
34323
+ return join51(cwd, ".kimiflare", "themes");
34032
34324
  }
34033
34325
  function isHexColor(c) {
34034
34326
  return /^#[0-9a-fA-F]{6}$/.test(c);
@@ -34112,15 +34404,15 @@ async function loadThemesFromDir(dir, source) {
34112
34404
  const errors = [];
34113
34405
  let files;
34114
34406
  try {
34115
- files = await readdir9(dir);
34407
+ files = await readdir10(dir);
34116
34408
  } catch {
34117
34409
  return { themes, errors };
34118
34410
  }
34119
34411
  for (const file of files.filter((f) => f.endsWith(".json"))) {
34120
- const path = join50(dir, file);
34412
+ const path = join51(dir, file);
34121
34413
  let raw;
34122
34414
  try {
34123
- raw = await readFile33(path, "utf-8");
34415
+ raw = await readFile34(path, "utf-8");
34124
34416
  } catch (e) {
34125
34417
  errors.push(`${path}: ${e instanceof Error ? e.message : String(e)}`);
34126
34418
  continue;
@@ -34266,8 +34558,8 @@ var init_theme_loader = __esm({
34266
34558
  "use strict";
34267
34559
  init_wcag();
34268
34560
  init_theme();
34269
- USER_THEMES_DIR = join50(
34270
- process.env.XDG_CONFIG_HOME || join50(homedir29(), ".config"),
34561
+ USER_THEMES_DIR = join51(
34562
+ process.env.XDG_CONFIG_HOME || join51(homedir29(), ".config"),
34271
34563
  "kimiflare",
34272
34564
  "themes"
34273
34565
  );
@@ -36798,9 +37090,9 @@ var init_resume_progress = __esm({
36798
37090
  });
36799
37091
 
36800
37092
  // src/agent/supervisor.ts
36801
- 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";
36802
37094
  import { createHash as createHash7 } from "crypto";
36803
- import { resolve as resolve17, join as join51 } from "path";
37095
+ import { resolve as resolve18, join as join52 } from "path";
36804
37096
  var TurnSupervisor;
36805
37097
  var init_supervisor = __esm({
36806
37098
  "src/agent/supervisor.ts"() {
@@ -37190,12 +37482,12 @@ var init_input_handlers = __esm({
37190
37482
 
37191
37483
  // src/init/context-generator.ts
37192
37484
  import { existsSync as existsSync9, statSync as statSync6 } from "fs";
37193
- import { join as join52 } from "path";
37485
+ import { join as join53 } from "path";
37194
37486
  function detectFlavor(cwd) {
37195
37487
  for (const [flavor, signatures] of Object.entries(FLAVOR_SIGNATURES)) {
37196
37488
  if (flavor === "generic") continue;
37197
37489
  for (const sig of signatures) {
37198
- const path = join52(cwd, sig);
37490
+ const path = join53(cwd, sig);
37199
37491
  if (sig.includes("*")) {
37200
37492
  try {
37201
37493
  const parts = sig.split("*");
@@ -37216,14 +37508,14 @@ function detectFlavor(cwd) {
37216
37508
  }
37217
37509
  function findFile(cwd, candidates) {
37218
37510
  for (const c of candidates) {
37219
- if (existsSync9(join52(cwd, c))) return c;
37511
+ if (existsSync9(join53(cwd, c))) return c;
37220
37512
  }
37221
37513
  return null;
37222
37514
  }
37223
37515
  function findSourceRoots(cwd) {
37224
37516
  const roots = [];
37225
37517
  for (const r of SOURCE_ROOT_CANDIDATES) {
37226
- const p = join52(cwd, r);
37518
+ const p = join53(cwd, r);
37227
37519
  try {
37228
37520
  const s = statSync6(p);
37229
37521
  if (s.isDirectory()) roots.push(r);
@@ -37234,9 +37526,9 @@ function findSourceRoots(cwd) {
37234
37526
  }
37235
37527
  function findCiConfig(cwd) {
37236
37528
  for (const c of CI_PATHS) {
37237
- if (existsSync9(join52(cwd, c))) {
37529
+ if (existsSync9(join53(cwd, c))) {
37238
37530
  try {
37239
- const s = statSync6(join52(cwd, c));
37531
+ const s = statSync6(join53(cwd, c));
37240
37532
  return s.isDirectory() ? c : c;
37241
37533
  } catch {
37242
37534
  }
@@ -37373,7 +37665,7 @@ function analyzeProject(cwd) {
37373
37665
  ciConfig: findCiConfig(cwd),
37374
37666
  readme: findFile(cwd, ["README.md", "README.rst", "README.txt", "Readme.md"]),
37375
37667
  sourceRoots: findSourceRoots(cwd),
37376
- hasGit: existsSync9(join52(cwd, ".git"))
37668
+ hasGit: existsSync9(join53(cwd, ".git"))
37377
37669
  };
37378
37670
  }
37379
37671
  function bashDiscoveryCommands(profile) {
@@ -37538,7 +37830,7 @@ Aim for 100\u2013200 lines total. Use markdown tables where they save space.
37538
37830
  }
37539
37831
  function buildInitPrompt(cwd) {
37540
37832
  const existingName = ["AGENTS.md", "KIMI.md", "KIMIFLARE.md", "AGENT.md"].find(
37541
- (n) => existsSync9(join52(cwd, n))
37833
+ (n) => existsSync9(join53(cwd, n))
37542
37834
  );
37543
37835
  const isRefresh = existingName !== void 0;
37544
37836
  const targetFilename = existingName ?? "AGENTS.md";
@@ -37622,7 +37914,7 @@ var init_context_generator = __esm({
37622
37914
 
37623
37915
  // src/init/run-init.ts
37624
37916
  import { existsSync as existsSync10 } from "fs";
37625
- import { join as join53 } from "path";
37917
+ import { join as join54 } from "path";
37626
37918
  async function runInit(deps) {
37627
37919
  const {
37628
37920
  cfg,
@@ -37715,7 +38007,7 @@ async function runInit(deps) {
37715
38007
  lspManagerRef.current.notifyChange(path, content);
37716
38008
  } else {
37717
38009
  void import("fs/promises").then(
37718
- ({ 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(() => {
37719
38011
  })
37720
38012
  );
37721
38013
  }
@@ -37820,7 +38112,7 @@ async function runInit(deps) {
37820
38112
  }
37821
38113
  }
37822
38114
  });
37823
- if (existsSync10(join53(cwd, targetFilename))) {
38115
+ if (existsSync10(join54(cwd, targetFilename))) {
37824
38116
  if (cacheStableRef.current) {
37825
38117
  messagesRef.current[1] = {
37826
38118
  role: "system",
@@ -37912,11 +38204,11 @@ var init_run_init = __esm({
37912
38204
  });
37913
38205
 
37914
38206
  // src/skills/discovery.ts
37915
- import { readdir as readdir11, stat as stat12, readFile as readFile35 } from "fs/promises";
37916
- 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";
37917
38209
  async function dirExists(path) {
37918
38210
  try {
37919
- const s = await stat12(path);
38211
+ const s = await stat13(path);
37920
38212
  return s.isDirectory();
37921
38213
  } catch {
37922
38214
  return false;
@@ -37924,7 +38216,7 @@ async function dirExists(path) {
37924
38216
  }
37925
38217
  async function fileExists(path) {
37926
38218
  try {
37927
- const s = await stat12(path);
38219
+ const s = await stat13(path);
37928
38220
  return s.isFile();
37929
38221
  } catch {
37930
38222
  return false;
@@ -37932,25 +38224,25 @@ async function fileExists(path) {
37932
38224
  }
37933
38225
  async function scanSkillDir(dirPath, source) {
37934
38226
  if (!await dirExists(dirPath)) return [];
37935
- const entries = await readdir11(dirPath, { withFileTypes: true });
38227
+ const entries = await readdir12(dirPath, { withFileTypes: true });
37936
38228
  const files = [];
37937
38229
  for (const entry of entries) {
37938
38230
  if (!entry.isFile()) continue;
37939
38231
  if (!SKILL_EXTENSIONS.has(extname2(entry.name))) continue;
37940
- files.push({ filePath: join54(dirPath, entry.name), source });
38232
+ files.push({ filePath: join55(dirPath, entry.name), source });
37941
38233
  }
37942
38234
  return files;
37943
38235
  }
37944
38236
  async function discoverSkills(cwd) {
37945
- const agentsSkills = await scanSkillDir(join54(cwd, ".agents", "skills"), "agents");
37946
- const agentsMd = await fileExists(join54(cwd, "AGENTS.md")) ? [{ filePath: join54(cwd, "AGENTS.md"), source: "agents-md" }] : [];
37947
- const githubSkills = await scanSkillDir(join54(cwd, ".github", "skills"), "github");
37948
- 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");
37949
38241
  const ordered = [...agentsSkills, ...agentsMd, ...githubSkills, ...kimiflareSkills];
37950
38242
  return ordered;
37951
38243
  }
37952
38244
  async function readSkillFile(filePath) {
37953
- const bytes = await readFile35(filePath);
38245
+ const bytes = await readFile36(filePath);
37954
38246
  return { bytes, text: bytes.toString("utf-8") };
37955
38247
  }
37956
38248
  var SKILL_EXTENSIONS;
@@ -38156,7 +38448,7 @@ var init_skills = __esm({
38156
38448
 
38157
38449
  // src/ui/run-startup-tasks.ts
38158
38450
  import { existsSync as existsSync11 } from "fs";
38159
- import { join as join55 } from "path";
38451
+ import { join as join56 } from "path";
38160
38452
  function runStartupTasks(deps) {
38161
38453
  const {
38162
38454
  cfg,
@@ -38179,7 +38471,7 @@ function runStartupTasks(deps) {
38179
38471
  }
38180
38472
  });
38181
38473
  if (cfg.memoryEnabled) {
38182
- const dbPath = cfg.memoryDbPath ?? join55(process.cwd(), ".kimiflare", "memory.db");
38474
+ const dbPath = cfg.memoryDbPath ?? join56(process.cwd(), ".kimiflare", "memory.db");
38183
38475
  const manager = new MemoryManager({
38184
38476
  dbPath,
38185
38477
  ...auth,
@@ -38211,7 +38503,7 @@ function runStartupTasks(deps) {
38211
38503
  });
38212
38504
  const cwd = process.cwd();
38213
38505
  sessionStartRecallRef.current = manager.recall({ text: cwd, repoPath: cwd, limit: 5 });
38214
- 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)))) {
38215
38507
  const lastRefresh = manager.getLastKimiMdRefreshTime(cwd);
38216
38508
  const driftCount = manager.countHighSignalMemoriesSince(cwd, lastRefresh);
38217
38509
  if (driftCount >= 5) {
@@ -38222,7 +38514,7 @@ function runStartupTasks(deps) {
38222
38514
  memoryManagerRef.current?.close();
38223
38515
  memoryManagerRef.current = null;
38224
38516
  }
38225
- const skillDbPath = cfg.memoryDbPath ?? join55(process.cwd(), ".kimiflare", "memory.db");
38517
+ const skillDbPath = cfg.memoryDbPath ?? join56(process.cwd(), ".kimiflare", "memory.db");
38226
38518
  const skillDb = getMemoryDb() ?? openMemoryDb(skillDbPath);
38227
38519
  initSkillsSchema(skillDb);
38228
38520
  void indexSkills({
@@ -38579,7 +38871,7 @@ var init_run_compact = __esm({
38579
38871
  });
38580
38872
 
38581
38873
  // src/commands/save.ts
38582
- 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";
38583
38875
  import { dirname as dirname21 } from "path";
38584
38876
  async function saveCustomCommand(opts2) {
38585
38877
  const dir = opts2.source === "project" ? projectCommandsDir(opts2.cwd) : globalCommandsDir();
@@ -38591,8 +38883,8 @@ async function saveCustomCommand(opts2) {
38591
38883
  if (opts2.effort) data.effort = opts2.effort;
38592
38884
  const frontmatter = serializeFrontmatter(data);
38593
38885
  const content = frontmatter + opts2.template;
38594
- await mkdir18(dirname21(filepath), { recursive: true });
38595
- await writeFile16(filepath, content, "utf8");
38886
+ await mkdir19(dirname21(filepath), { recursive: true });
38887
+ await writeFile17(filepath, content, "utf8");
38596
38888
  return { filepath };
38597
38889
  }
38598
38890
  async function deleteCustomCommand(cmd) {
@@ -38715,7 +39007,7 @@ __export(app_exports, {
38715
39007
  import React25, { useState as useState27, useRef as useRef9, useEffect as useEffect11, useCallback as useCallback8, useMemo as useMemo6 } from "react";
38716
39008
  import { Box as Box40, Text as Text41, useApp, useInput as useInput19, useWindowSize as useWindowSize2, render } from "ink";
38717
39009
  import { existsSync as existsSync12 } from "fs";
38718
- import { join as join56, resolve as resolve18 } from "path";
39010
+ import { join as join57, resolve as resolve19 } from "path";
38719
39011
  import { homedir as homedir30 } from "os";
38720
39012
  import { jsx as jsx42, jsxs as jsxs39 } from "react/jsx-runtime";
38721
39013
  function App({
@@ -39043,8 +39335,8 @@ ${wcagWarnings.join("\n")}` }
39043
39335
  const exactDirectory = query === "~" || query === "." || query === ".." || query.endsWith("/..");
39044
39336
  const prefix = exactDirectory ? `${query.replace(/\/$/, "")}/` : slash >= 0 ? query.slice(0, slash + 1) : "";
39045
39337
  const directory = exactDirectory ? query : slash >= 0 ? query.slice(0, slash + 1) : query;
39046
- const expanded = directory.startsWith("~") ? join56(homedir30(), directory.slice(1)) : directory;
39047
- const target = resolve18(cwd, expanded || ".");
39338
+ const expanded = directory.startsWith("~") ? join57(homedir30(), directory.slice(1)) : directory;
39339
+ const target = resolve19(cwd, expanded || ".");
39048
39340
  const entries2 = await glob("*", {
39049
39341
  cwd: target,
39050
39342
  dot: false,
@@ -40026,7 +40318,7 @@ ${result2.output ?? "(output not captured)"}`,
40026
40318
  }
40027
40319
  }
40028
40320
  turnCounterRef.current += 1;
40029
- 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) {
40030
40322
  setEvents((e) => [
40031
40323
  ...e,
40032
40324
  { kind: "info", key: mkKey(), text: "Tip: Rerunning /init occasionally helps autopilot (formerly kimiflare) stay accurate as your project evolves." }
@@ -40050,7 +40342,7 @@ ${result2.output ?? "(output not captured)"}`,
40050
40342
  };
40051
40343
  ensureSessionId();
40052
40344
  const { sessionsDir: sessionsDir3 } = await Promise.resolve().then(() => (init_sessions(), sessions_exports));
40053
- const filePath = join56(sessionsDir3(), `${sessionIdRef.current}.json`);
40345
+ const filePath = join57(sessionsDir3(), `${sessionIdRef.current}.json`);
40054
40346
  await addCheckpoint(filePath, cp);
40055
40347
  }
40056
40348
  const summary = await generateContinuationSummary({
@@ -40381,7 +40673,7 @@ ${result2.output ?? "(output not captured)"}`,
40381
40673
  lspManagerRef.current.notifyChange(path, content2);
40382
40674
  } else {
40383
40675
  void import("fs/promises").then(
40384
- ({ 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(() => {
40385
40677
  })
40386
40678
  );
40387
40679
  }
@@ -40574,7 +40866,7 @@ ${result2.output ?? "(output not captured)"}`,
40574
40866
  };
40575
40867
  ensureSessionId();
40576
40868
  const { sessionsDir: sessionsDir3 } = await Promise.resolve().then(() => (init_sessions(), sessions_exports));
40577
- const filePath = join56(sessionsDir3(), `${sessionIdRef.current}.json`);
40869
+ const filePath = join57(sessionsDir3(), `${sessionIdRef.current}.json`);
40578
40870
  await addCheckpoint(filePath, cp);
40579
40871
  }
40580
40872
  const summary = await generateContinuationSummary({
@@ -41141,7 +41433,7 @@ ${result2.output ?? "(output not captured)"}`,
41141
41433
  lsp: {
41142
41434
  servers: cfg?.lspServers ?? {},
41143
41435
  scope: lspScope,
41144
- hasProjectDir: existsSync12(join56(process.cwd(), ".kimiflare"))
41436
+ hasProjectDir: existsSync12(join57(process.cwd(), ".kimiflare"))
41145
41437
  }
41146
41438
  });
41147
41439
  });
@@ -41198,7 +41490,7 @@ ${result2.output ?? "(output not captured)"}`,
41198
41490
  onCommandDelete: handleCommandDelete2,
41199
41491
  lspServers: cfg?.lspServers ?? {},
41200
41492
  lspScope,
41201
- hasProjectDir: existsSync12(join56(process.cwd(), ".kimiflare")),
41493
+ hasProjectDir: existsSync12(join57(process.cwd(), ".kimiflare")),
41202
41494
  onLspSave: handleLspSave2,
41203
41495
  themes: themeList(),
41204
41496
  onPickTheme: handleThemePick,
@@ -41685,11 +41977,11 @@ init_classify();
41685
41977
  init_subagent_policy();
41686
41978
  init_trace();
41687
41979
  init_registry2();
41688
- import { readFile as readFile15 } from "fs/promises";
41689
- 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";
41690
41982
  async function resolveSession(opts2) {
41691
41983
  if (opts2.sessionId) {
41692
- const filePath = resolve6(sessionsDir(), `${opts2.sessionId}.json`);
41984
+ const filePath = resolve7(sessionsDir(), `${opts2.sessionId}.json`);
41693
41985
  try {
41694
41986
  const file = await loadSession(filePath);
41695
41987
  return { sessionFile: file, isNew: false };
@@ -41697,7 +41989,7 @@ async function resolveSession(opts2) {
41697
41989
  }
41698
41990
  }
41699
41991
  if (opts2.continueSession) {
41700
- const cwd = opts2.dir ? resolve6(opts2.dir) : process.cwd();
41992
+ const cwd = opts2.dir ? resolve7(opts2.dir) : process.cwd();
41701
41993
  const sessions = await listSessions(1, cwd);
41702
41994
  if (sessions.length > 0) {
41703
41995
  const filePath = sessions[0].filePath;
@@ -41710,7 +42002,7 @@ async function resolveSession(opts2) {
41710
42002
  return {
41711
42003
  sessionFile: {
41712
42004
  id,
41713
- cwd: opts2.dir ? resolve6(opts2.dir) : process.cwd(),
42005
+ cwd: opts2.dir ? resolve7(opts2.dir) : process.cwd(),
41714
42006
  model: opts2.model,
41715
42007
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
41716
42008
  updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -41724,9 +42016,9 @@ async function resolveFiles(filePatterns, cwd) {
41724
42016
  const resolved = /* @__PURE__ */ new Set();
41725
42017
  for (const pattern of filePatterns) {
41726
42018
  try {
41727
- const stat13 = await import("fs/promises").then((m) => m.stat(resolve6(cwd, pattern)));
41728
- if (stat13.isFile()) {
41729
- 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));
41730
42022
  continue;
41731
42023
  }
41732
42024
  } catch {
@@ -41754,7 +42046,7 @@ async function buildUserMessage(prompt, files, cwd) {
41754
42046
  }
41755
42047
  } else {
41756
42048
  try {
41757
- const content = await readFile15(filePath, "utf8");
42049
+ const content = await readFile16(filePath, "utf8");
41758
42050
  const relPath = filePath.startsWith(cwd) ? filePath.slice(cwd.length + 1) : filePath;
41759
42051
  fileContents.push(`
41760
42052
  --- ${relPath} ---
@@ -41789,7 +42081,7 @@ async function runPrintMode(opts2) {
41789
42081
  `
41790
42082
  );
41791
42083
  }
41792
- const cwd = opts2.dir ? resolve6(opts2.dir) : process.cwd();
42084
+ const cwd = opts2.dir ? resolve7(opts2.dir) : process.cwd();
41793
42085
  const baseWorkerTools = getWorkerTools(opts2.workerProfile);
41794
42086
  const { HooksManager: HooksManager2 } = await Promise.resolve().then(() => (init_manager2(), manager_exports));
41795
42087
  const hooks = new HooksManager2(cwd);
@@ -42469,11 +42761,11 @@ async function promptHidden(question) {
42469
42761
  }
42470
42762
  });
42471
42763
  const rl = createInterface4({ input: process.stdin, output, terminal: true });
42472
- return new Promise((resolve19) => {
42764
+ return new Promise((resolve20) => {
42473
42765
  rl.question(question, (answer) => {
42474
42766
  rl.close();
42475
42767
  process.stdout.write("\n");
42476
- resolve19(answer);
42768
+ resolve20(answer);
42477
42769
  });
42478
42770
  muted = true;
42479
42771
  });