autopilot-ai 1.27.0 → 1.27.1

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
@@ -30830,11 +30830,13 @@ var init_activity = __esm({
30830
30830
  // src/camouflage-view.ts
30831
30831
  var camouflage_view_exports = {};
30832
30832
  __export(camouflage_view_exports, {
30833
+ CamouflageCrashed: () => CamouflageCrashed,
30833
30834
  CamouflageUnavailable: () => CamouflageUnavailable,
30834
30835
  executeCodeSummary: () => executeCodeSummary,
30835
30836
  helpOptions: () => helpOptions,
30836
30837
  listMentionDir: () => listMentionDir,
30837
30838
  modelOptions: () => modelOptions,
30839
+ rendererInfo: () => rendererInfo,
30838
30840
  runCamouflageView: () => runCamouflageView,
30839
30841
  shouldSendSubagentPolicyNotice: () => shouldSendSubagentPolicyNotice,
30840
30842
  splitBangResult: () => splitBangResult,
@@ -30845,8 +30847,10 @@ __export(camouflage_view_exports, {
30845
30847
  });
30846
30848
  import { execFileSync as execFileSync3, spawn as spawn10 } from "child_process";
30847
30849
  import { readdir as readdir7 } from "fs/promises";
30850
+ import { existsSync as existsSync11, readFileSync as readFileSync10 } from "fs";
30848
30851
  import { homedir as homedir28 } from "os";
30849
- import { join as join46, resolve as resolve16 } from "path";
30852
+ import { dirname as dirname22, join as join46, resolve as resolve16 } from "path";
30853
+ import { fileURLToPath as fileURLToPath5 } from "url";
30850
30854
  async function loadSdk() {
30851
30855
  const sdk = await import("camouflage-tui").catch((err) => {
30852
30856
  throw new CamouflageUnavailable(`camouflage-tui is not installed (${err.message})`);
@@ -30856,8 +30860,44 @@ async function loadSdk() {
30856
30860
  }
30857
30861
  return sdk;
30858
30862
  }
30863
+ function rendererInfo(env2 = process.env) {
30864
+ let packageVersion = null;
30865
+ let packageBin = null;
30866
+ try {
30867
+ let dir = dirname22(fileURLToPath5(import.meta.resolve("camouflage-tui")));
30868
+ while (!existsSync11(join46(dir, "package.json")) && dirname22(dir) !== dir) dir = dirname22(dir);
30869
+ packageVersion = JSON.parse(readFileSync10(join46(dir, "package.json"), "utf8")).version ?? null;
30870
+ const local = join46(dir, "bin", process.platform === "win32" ? "camouflage-tui.exe" : "camouflage-tui");
30871
+ if (existsSync11(local)) packageBin = local;
30872
+ } catch {
30873
+ }
30874
+ let binary;
30875
+ let source;
30876
+ if (env2.CAMOUFLAGE_BIN) {
30877
+ binary = env2.CAMOUFLAGE_BIN;
30878
+ source = "CAMOUFLAGE_BIN";
30879
+ } else if (packageBin) {
30880
+ binary = packageBin;
30881
+ source = "package";
30882
+ } else {
30883
+ source = "PATH";
30884
+ try {
30885
+ binary = execFileSync3(process.platform === "win32" ? "where" : "which", ["camouflage-tui"], { encoding: "utf8", timeout: 2e3 }).trim().split("\n")[0] || "camouflage-tui";
30886
+ } catch {
30887
+ binary = "camouflage-tui";
30888
+ }
30889
+ }
30890
+ let binaryVersion = null;
30891
+ try {
30892
+ binaryVersion = execFileSync3(binary, ["--version"], { encoding: "utf8", timeout: 2e3, stdio: ["ignore", "pipe", "ignore"] }).trim() || null;
30893
+ } catch {
30894
+ }
30895
+ return { packageVersion, binary, source, binaryVersion };
30896
+ }
30859
30897
  async function runCamouflageView(opts2) {
30860
30898
  const sdk = await loadSdk();
30899
+ const renderer = rendererInfo();
30900
+ logger.info("camouflage.renderer", { ...renderer });
30861
30901
  const restoreConsole = captureConsole();
30862
30902
  let cam;
30863
30903
  try {
@@ -30872,6 +30912,13 @@ async function runCamouflageView(opts2) {
30872
30912
  throw new CamouflageUnavailable(err.message);
30873
30913
  }
30874
30914
  cam.on("stderr", (chunk) => logger.warn("camouflage.stderr", { chunk }));
30915
+ if (renderer.source === "PATH") {
30916
+ logger.warn("camouflage.renderer_from_path", { ...renderer });
30917
+ cam.send("RuntimeError", {
30918
+ message: `camouflage-tui ${renderer.packageVersion ?? ""} has no renderer binary of its own (its install step failed), so ${renderer.binary} from PATH is used and may be outdated. Reinstall autopilot-ai to fix it.`,
30919
+ severity: "warning"
30920
+ });
30921
+ }
30875
30922
  const cwd = process.cwd();
30876
30923
  cam.send("SessionStarted", {
30877
30924
  title: `autopilot ${opts2.version}`,
@@ -30918,21 +30965,48 @@ async function runCamouflageView(opts2) {
30918
30965
  closing = true;
30919
30966
  view.dispose();
30920
30967
  registerTerminalHandoff(null);
30921
- await cam.close().catch(() => void 0);
30968
+ await Promise.race([cam.close().catch(() => void 0), new Promise((r) => setTimeout(r, 1e3).unref())]);
30922
30969
  restoreConsole();
30923
30970
  };
30924
- cam.on("exit", () => {
30925
- void finish().then(() => {
30971
+ let crashed = null;
30972
+ cam.on("exit", (info) => {
30973
+ if (closing) return;
30974
+ const code = info?.code ?? 0;
30975
+ const signal = info?.signal ?? null;
30976
+ if (code === 0 && !signal) {
30977
+ void finish().then(() => {
30978
+ if (view.actions) view.actions.exit();
30979
+ else process.exit(0);
30980
+ });
30981
+ return;
30982
+ }
30983
+ crashed = { code, signal };
30984
+ logger.error("camouflage.crashed", { code, signal, ...renderer });
30985
+ void finish().then(async () => {
30986
+ if (process.stdin.isTTY) process.stdin.setRawMode?.(false);
30987
+ process.stderr.write(
30988
+ `
30989
+ The Camouflage renderer stopped unexpectedly (${signal ?? `exit code ${code}`}). Its crash report is in ${join46(homedir28(), ".camouflage")} (crash-*.txt).
30990
+ ` + (view.busy ? "Finishing the current turn, then reopening this conversation in the classic UI\u2026\n" : "Reopening this conversation in the classic UI\u2026\n")
30991
+ );
30992
+ await view.settle();
30926
30993
  if (view.actions) view.actions.exit();
30927
- else process.exit(0);
30994
+ else crashedBeforeApp();
30928
30995
  });
30929
30996
  });
30997
+ let crashedBeforeApp = () => {
30998
+ };
30999
+ const beforeApp = new Promise((resolve19) => crashedBeforeApp = resolve19);
30930
31000
  try {
30931
- await opts2.runApp(view);
31001
+ await Promise.race([opts2.runApp(view), beforeApp]);
30932
31002
  } finally {
30933
31003
  await finish();
30934
- if (view.hadConversation) process.stdout.write("Resume this conversation with: autopilot -c\n");
30935
31004
  }
31005
+ if (crashed) {
31006
+ const c = crashed;
31007
+ throw new CamouflageCrashed(`renderer exited (${c.signal ?? `code ${c.code}`})`, view.sessionId);
31008
+ }
31009
+ if (view.hadConversation) process.stdout.write("Resume this conversation with: autopilot -c\n");
30936
31010
  }
30937
31011
  function runShell2(command) {
30938
31012
  return new Promise((resolve19) => {
@@ -31165,7 +31239,7 @@ function safeString(v) {
31165
31239
  return String(v);
31166
31240
  }
31167
31241
  }
31168
- var CamouflageUnavailable, View;
31242
+ var CamouflageUnavailable, CamouflageCrashed, View;
31169
31243
  var init_camouflage_view = __esm({
31170
31244
  "src/camouflage-view.ts"() {
31171
31245
  "use strict";
@@ -31192,6 +31266,13 @@ var init_camouflage_view = __esm({
31192
31266
  init_worker_registry();
31193
31267
  CamouflageUnavailable = class extends Error {
31194
31268
  };
31269
+ CamouflageCrashed = class extends Error {
31270
+ constructor(message2, sessionId) {
31271
+ super(message2);
31272
+ this.sessionId = sessionId;
31273
+ }
31274
+ sessionId;
31275
+ };
31195
31276
  View = class {
31196
31277
  constructor(cam, sdk) {
31197
31278
  this.cam = cam;
@@ -31232,7 +31313,27 @@ var init_camouflage_view = __esm({
31232
31313
  connect(actions) {
31233
31314
  this.actions = actions;
31234
31315
  }
31316
+ /** A turn is in flight (from the latest snapshot). */
31317
+ busy = false;
31318
+ /** The session the App is saving. */
31319
+ sessionId = null;
31320
+ idleWaiters = [];
31321
+ /** Resolves once the App is idle (no turn running). */
31322
+ settle(maxWaitMs = 12e4) {
31323
+ if (!this.busy) return Promise.resolve();
31324
+ return new Promise((resolve19) => {
31325
+ this.idleWaiters.push(resolve19);
31326
+ setTimeout(resolve19, maxWaitMs).unref();
31327
+ });
31328
+ }
31235
31329
  sync(s) {
31330
+ this.busy = s.turnRunning;
31331
+ this.sessionId = s.sessionId;
31332
+ if (!s.turnRunning) for (const resolve19 of this.idleWaiters.splice(0)) resolve19();
31333
+ if (this.disposed) {
31334
+ if (s.permission) this.actions?.decidePermission("deny");
31335
+ return;
31336
+ }
31236
31337
  this.syncCommands(s.customCommands);
31237
31338
  this.syncEvents(s.events);
31238
31339
  this.syncStatus(s);
@@ -42173,7 +42274,7 @@ var init_input_handlers = __esm({
42173
42274
  });
42174
42275
 
42175
42276
  // src/init/context-generator.ts
42176
- import { existsSync as existsSync11, statSync as statSync6 } from "fs";
42277
+ import { existsSync as existsSync12, statSync as statSync6 } from "fs";
42177
42278
  import { join as join54 } from "path";
42178
42279
  function detectFlavor(cwd) {
42179
42280
  for (const [flavor, signatures] of Object.entries(FLAVOR_SIGNATURES)) {
@@ -42191,7 +42292,7 @@ function detectFlavor(cwd) {
42191
42292
  }
42192
42293
  } catch {
42193
42294
  }
42194
- } else if (existsSync11(path)) {
42295
+ } else if (existsSync12(path)) {
42195
42296
  return flavor;
42196
42297
  }
42197
42298
  }
@@ -42200,7 +42301,7 @@ function detectFlavor(cwd) {
42200
42301
  }
42201
42302
  function findFile(cwd, candidates) {
42202
42303
  for (const c of candidates) {
42203
- if (existsSync11(join54(cwd, c))) return c;
42304
+ if (existsSync12(join54(cwd, c))) return c;
42204
42305
  }
42205
42306
  return null;
42206
42307
  }
@@ -42218,7 +42319,7 @@ function findSourceRoots(cwd) {
42218
42319
  }
42219
42320
  function findCiConfig(cwd) {
42220
42321
  for (const c of CI_PATHS) {
42221
- if (existsSync11(join54(cwd, c))) {
42322
+ if (existsSync12(join54(cwd, c))) {
42222
42323
  try {
42223
42324
  const s = statSync6(join54(cwd, c));
42224
42325
  return s.isDirectory() ? c : c;
@@ -42357,7 +42458,7 @@ function analyzeProject(cwd) {
42357
42458
  ciConfig: findCiConfig(cwd),
42358
42459
  readme: findFile(cwd, ["README.md", "README.rst", "README.txt", "Readme.md"]),
42359
42460
  sourceRoots: findSourceRoots(cwd),
42360
- hasGit: existsSync11(join54(cwd, ".git"))
42461
+ hasGit: existsSync12(join54(cwd, ".git"))
42361
42462
  };
42362
42463
  }
42363
42464
  function bashDiscoveryCommands(profile) {
@@ -42532,7 +42633,7 @@ function buildInitTasks(targetFilename) {
42532
42633
  }
42533
42634
  function buildInitPrompt(cwd) {
42534
42635
  const existingName = ["AGENTS.md", "KIMI.md", "KIMIFLARE.md", "AGENT.md"].find(
42535
- (n) => existsSync11(join54(cwd, n))
42636
+ (n) => existsSync12(join54(cwd, n))
42536
42637
  );
42537
42638
  const isRefresh = existingName !== void 0;
42538
42639
  const targetFilename = existingName ?? "AGENTS.md";
@@ -42619,7 +42720,7 @@ var init_context_generator = __esm({
42619
42720
  });
42620
42721
 
42621
42722
  // src/init/run-init.ts
42622
- import { existsSync as existsSync12 } from "fs";
42723
+ import { existsSync as existsSync13 } from "fs";
42623
42724
  import { join as join55 } from "path";
42624
42725
  async function runInit(deps) {
42625
42726
  const {
@@ -42824,7 +42925,7 @@ async function runInit(deps) {
42824
42925
  }
42825
42926
  }
42826
42927
  } }));
42827
- if (existsSync12(join55(cwd, targetFilename))) {
42928
+ if (existsSync13(join55(cwd, targetFilename))) {
42828
42929
  if (cacheStableRef.current) {
42829
42930
  messagesRef.current[1] = {
42830
42931
  role: "system",
@@ -43162,7 +43263,7 @@ var init_skills = __esm({
43162
43263
  });
43163
43264
 
43164
43265
  // src/ui/run-startup-tasks.ts
43165
- import { existsSync as existsSync13 } from "fs";
43266
+ import { existsSync as existsSync14 } from "fs";
43166
43267
  import { join as join57 } from "path";
43167
43268
  function runStartupTasks(deps) {
43168
43269
  const {
@@ -43219,7 +43320,7 @@ function runStartupTasks(deps) {
43219
43320
  });
43220
43321
  const cwd = process.cwd();
43221
43322
  sessionStartRecallRef.current = manager.recall({ text: cwd, repoPath: cwd, limit: 5 });
43222
- if (["AGENTS.md", "KIMI.md", "KIMIFLARE.md", "AGENT.md"].some((name) => existsSync13(join57(cwd, name)))) {
43323
+ if (["AGENTS.md", "KIMI.md", "KIMIFLARE.md", "AGENT.md"].some((name) => existsSync14(join57(cwd, name)))) {
43223
43324
  const lastRefresh = manager.getLastKimiMdRefreshTime(cwd);
43224
43325
  const driftCount = manager.countHighSignalMemoriesSince(cwd, lastRefresh);
43225
43326
  if (driftCount >= 5) {
@@ -43915,7 +44016,7 @@ var init_turn_nudges = __esm({
43915
44016
 
43916
44017
  // src/commands/save.ts
43917
44018
  import { mkdir as mkdir19, writeFile as writeFile16, unlink as unlink6 } from "fs/promises";
43918
- import { dirname as dirname23 } from "path";
44019
+ import { dirname as dirname24 } from "path";
43919
44020
  async function saveCustomCommand(opts2) {
43920
44021
  const dir = opts2.source === "project" ? projectCommandsDir(opts2.cwd) : globalCommandsDir();
43921
44022
  const filepath = `${dir}/${opts2.name}.md`;
@@ -43926,7 +44027,7 @@ async function saveCustomCommand(opts2) {
43926
44027
  if (opts2.effort) data.effort = opts2.effort;
43927
44028
  const frontmatter = serializeFrontmatter(data);
43928
44029
  const content = frontmatter + opts2.template;
43929
- await mkdir19(dirname23(filepath), { recursive: true });
44030
+ await mkdir19(dirname24(filepath), { recursive: true });
43930
44031
  await writeFile16(filepath, content, "utf8");
43931
44032
  return { filepath };
43932
44033
  }
@@ -44027,7 +44128,7 @@ __export(app_exports, {
44027
44128
  });
44028
44129
  import React25, { useState as useState27, useRef as useRef9, useEffect as useEffect11, useCallback as useCallback8, useMemo as useMemo7 } from "react";
44029
44130
  import { Box as Box40, Text as Text41, useApp, useInput as useInput18, useWindowSize as useWindowSize2, render } from "ink";
44030
- import { existsSync as existsSync14 } from "fs";
44131
+ import { existsSync as existsSync15 } from "fs";
44031
44132
  import { join as join58, resolve as resolve18 } from "path";
44032
44133
  import { homedir as homedir32 } from "os";
44033
44134
  import { jsx as jsx42, jsxs as jsxs39 } from "react/jsx-runtime";
@@ -44036,7 +44137,8 @@ function App({
44036
44137
  initialUpdateResult,
44037
44138
  initialLspScope,
44038
44139
  initialLspProjectPath,
44039
- bridge
44140
+ bridge,
44141
+ initialResumeSessionId
44040
44142
  }) {
44041
44143
  const { exit } = useApp();
44042
44144
  const { columns } = useWindowSize2();
@@ -44359,6 +44461,23 @@ ${wcagWarnings.join("\n")}` }
44359
44461
  noteTurnEnded
44360
44462
  } = sessionMgr;
44361
44463
  const pendingTextRef = useRef9(/* @__PURE__ */ new Map());
44464
+ const resumedAfterCrashRef = useRef9(false);
44465
+ useEffect11(() => {
44466
+ if (!initialResumeSessionId || resumedAfterCrashRef.current || !cfg) return;
44467
+ resumedAfterCrashRef.current = true;
44468
+ void (async () => {
44469
+ const { sessionsDir: sessionsDir3 } = await Promise.resolve().then(() => (init_sessions(), sessions_exports));
44470
+ try {
44471
+ await doResumeSession(join58(sessionsDir3(), `${initialResumeSessionId}.json`));
44472
+ setEvents((e) => [
44473
+ ...e,
44474
+ { kind: "info", key: mkKey(), text: "The Camouflage renderer crashed, so this conversation reopened here in the classic UI. Nothing was lost." }
44475
+ ]);
44476
+ } catch (err) {
44477
+ setEvents((e) => [...e, { kind: "error", key: mkKey(), text: `Couldn't reopen the conversation after the renderer crash: ${err.message}. Use /resume.` }]);
44478
+ }
44479
+ })();
44480
+ }, [initialResumeSessionId, cfg, doResumeSession]);
44362
44481
  const flushTimeoutRef = useRef9(null);
44363
44482
  const customCommandsRef = useRef9([]);
44364
44483
  const recentFilesRef = useRef9(/* @__PURE__ */ new Map());
@@ -45306,7 +45425,7 @@ ${result2.output ?? "(output not captured)"}`,
45306
45425
  turnCounterRef.current += 1;
45307
45426
  const nudges = turnNudges({
45308
45427
  turn: turnCounterRef.current,
45309
- hasContextFile: ["AGENTS.md", "KIMI.md", "KIMIFLARE.md", "AGENT.md"].some((name) => existsSync14(join58(process.cwd(), name))),
45428
+ hasContextFile: ["AGENTS.md", "KIMI.md", "KIMIFLARE.md", "AGENT.md"].some((name) => existsSync15(join58(process.cwd(), name))),
45310
45429
  contextStale: kimiMdStale,
45311
45430
  mode: modeRef.current,
45312
45431
  freshAfterTurns: cfg?.autoFreshSuggestionTurns ?? DEFAULT_AUTO_FRESH_SUGGESTION_TURNS,
@@ -45960,6 +46079,8 @@ ${result2.output ?? "(output not captured)"}`,
45960
46079
  bridge.sync({
45961
46080
  events,
45962
46081
  busy,
46082
+ turnRunning: busy || supervisorRef.current.isRunning,
46083
+ sessionId: sessionIdRef.current,
45963
46084
  providerSetup: modals.providerSetup,
45964
46085
  workers: runningSubagents,
45965
46086
  mode,
@@ -45986,7 +46107,7 @@ ${result2.output ?? "(output not captured)"}`,
45986
46107
  lsp: {
45987
46108
  servers: cfg?.lspServers ?? {},
45988
46109
  scope: lspScope,
45989
- hasProjectDir: existsSync14(join58(process.cwd(), ".kimiflare"))
46110
+ hasProjectDir: existsSync15(join58(process.cwd(), ".kimiflare"))
45990
46111
  }
45991
46112
  });
45992
46113
  });
@@ -46043,7 +46164,7 @@ ${result2.output ?? "(output not captured)"}`,
46043
46164
  onCommandDelete: handleCommandDelete2,
46044
46165
  lspServers: cfg?.lspServers ?? {},
46045
46166
  lspScope,
46046
- hasProjectDir: existsSync14(join58(process.cwd(), ".kimiflare")),
46167
+ hasProjectDir: existsSync15(join58(process.cwd(), ".kimiflare")),
46047
46168
  onLspSave: handleLspSave2,
46048
46169
  themes: themeList(),
46049
46170
  onPickTheme: handleThemePick,
@@ -46279,7 +46400,7 @@ async function renderAppWithBridge(cfg, bridge, updateResult, lspScope = "global
46279
46400
  );
46280
46401
  await instance.waitUntilExit();
46281
46402
  }
46282
- async function renderApp(cfg, updateResult, lspScope = "global", lspProjectPath = null) {
46403
+ async function renderApp(cfg, updateResult, lspScope = "global", lspProjectPath = null, opts2 = {}) {
46283
46404
  enableUserShellCommands();
46284
46405
  const instance = render(
46285
46406
  /* @__PURE__ */ jsx42(
@@ -46288,7 +46409,8 @@ async function renderApp(cfg, updateResult, lspScope = "global", lspProjectPath
46288
46409
  initialCfg: cfg,
46289
46410
  initialUpdateResult: updateResult,
46290
46411
  initialLspScope: lspScope,
46291
- initialLspProjectPath: lspProjectPath
46412
+ initialLspProjectPath: lspProjectPath,
46413
+ initialResumeSessionId: opts2.resumeSessionId
46292
46414
  }
46293
46415
  ),
46294
46416
  {
@@ -47279,7 +47401,7 @@ async function main() {
47279
47401
  const uiEngine = (opts.ui ?? process.env.KIMIFLARE_UI ?? "camouflage").toLowerCase();
47280
47402
  if (uiEngine !== "ink" && cfg) {
47281
47403
  const model = requireModel(opts.model || cfg.model);
47282
- const { runCamouflageView: runCamouflageView2, CamouflageUnavailable: CamouflageUnavailable2 } = await Promise.resolve().then(() => (init_camouflage_view(), camouflage_view_exports));
47404
+ const { runCamouflageView: runCamouflageView2, CamouflageUnavailable: CamouflageUnavailable2, CamouflageCrashed: CamouflageCrashed2 } = await Promise.resolve().then(() => (init_camouflage_view(), camouflage_view_exports));
47283
47405
  const { renderAppWithBridge: renderAppWithBridge2 } = await Promise.resolve().then(() => (init_app(), app_exports));
47284
47406
  try {
47285
47407
  await runCamouflageView2({
@@ -47289,6 +47411,12 @@ async function main() {
47289
47411
  });
47290
47412
  process.exit(0);
47291
47413
  } catch (err) {
47414
+ if (err instanceof CamouflageCrashed2) {
47415
+ logger.warn("camouflage.crashed_fallback", { error: err.message });
47416
+ const { renderApp: renderApp3 } = await Promise.resolve().then(() => (init_app(), app_exports));
47417
+ await renderApp3({ ...cfg, model }, updateResult, lspScope, lspProjectPath, err.sessionId ? { resumeSessionId: err.sessionId } : {});
47418
+ return;
47419
+ }
47292
47420
  if (!(err instanceof CamouflageUnavailable2)) throw err;
47293
47421
  logger.warn("camouflage.unavailable", { error: err.message });
47294
47422
  }