autopilot-ai 1.22.2 → 1.23.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/README.md CHANGED
@@ -63,6 +63,13 @@ autopilot
63
63
 
64
64
  On first run, **Sign in with OpenRouter**: approve autopilot in your browser and a key is created for you (or paste one from <https://openrouter.ai/keys>). Then pick a model. That's it.
65
65
 
66
+ Or install with Homebrew on macOS or Linux (Homebrew installs Node.js for you):
67
+
68
+ ```sh
69
+ brew install sinameraji/tap/autopilot
70
+ autopilot
71
+ ```
72
+
66
73
  Or run without installing:
67
74
 
68
75
  ```sh
package/dist/index.js CHANGED
@@ -8732,6 +8732,8 @@ var init_web_search = __esm({
8732
8732
  });
8733
8733
 
8734
8734
  // src/tools/github.ts
8735
+ import { execFile as execFileCallback } from "child_process";
8736
+ import { promisify as promisify3 } from "util";
8735
8737
  function getHeaders(token) {
8736
8738
  const headers = {
8737
8739
  Accept: "application/vnd.github+json",
@@ -8743,7 +8745,23 @@ function getHeaders(token) {
8743
8745
  }
8744
8746
  return headers;
8745
8747
  }
8746
- async function githubFetch(path, token) {
8748
+ async function ghApi(path, token, body) {
8749
+ const args = ["api", path.replace(/^\/+/, "")];
8750
+ if (body !== void 0 && typeof body === "object" && body !== null) {
8751
+ args.push("-X", "POST");
8752
+ for (const [key, value] of Object.entries(body)) {
8753
+ if (value === void 0 || value === null) continue;
8754
+ args.push(typeof value === "boolean" ? "-F" : "-f", `${key}=${String(value)}`);
8755
+ }
8756
+ }
8757
+ const result2 = await execFile3("gh", args, {
8758
+ timeout: TIMEOUT_MS3,
8759
+ maxBuffer: 10 * 1024 * 1024,
8760
+ env: token ? { ...process.env, GH_TOKEN: token } : process.env
8761
+ });
8762
+ return JSON.parse(result2.stdout);
8763
+ }
8764
+ async function githubFetch(path, token, cliFallback = ghApi) {
8747
8765
  const controller = new AbortController();
8748
8766
  const timer3 = setTimeout(() => controller.abort(), TIMEOUT_MS3);
8749
8767
  try {
@@ -8756,6 +8774,12 @@ async function githubFetch(path, token) {
8756
8774
  throw new Error(`GitHub API ${res.status}: ${res.statusText}${body ? ` \u2014 ${body.slice(0, 200)}` : ""}`);
8757
8775
  }
8758
8776
  return await res.json();
8777
+ } catch (apiError) {
8778
+ try {
8779
+ return await cliFallback(path, token);
8780
+ } catch (cliError) {
8781
+ throw new Error(`${formatError(apiError)}; gh CLI fallback failed: ${formatError(cliError)}`);
8782
+ }
8759
8783
  } finally {
8760
8784
  clearTimeout(timer3);
8761
8785
  }
@@ -8778,6 +8802,12 @@ async function githubPost(path, body, token) {
8778
8802
  throw new Error(`GitHub API ${res.status}: ${res.statusText}${text ? ` \u2014 ${text.slice(0, 200)}` : ""}`);
8779
8803
  }
8780
8804
  return await res.json();
8805
+ } catch (apiError) {
8806
+ try {
8807
+ return await ghApi(path, token, body);
8808
+ } catch (cliError) {
8809
+ throw new Error(`${formatError(apiError)}; gh CLI fallback failed: ${formatError(cliError)}`);
8810
+ }
8781
8811
  } finally {
8782
8812
  clearTimeout(timer3);
8783
8813
  }
@@ -8793,11 +8823,12 @@ function formatError(err) {
8793
8823
  if (err instanceof Error) return err.message;
8794
8824
  return String(err);
8795
8825
  }
8796
- var GITHUB_API_BASE, TIMEOUT_MS3, githubListMergedPrsTool, githubListReleasesTool, githubReadPrTool, githubReadIssueTool, githubReadCodeTool, githubCreatePrTool;
8826
+ var execFile3, GITHUB_API_BASE, TIMEOUT_MS3, githubListMergedPrsTool, githubListReleasesTool, githubReadPrTool, githubReadIssueTool, githubReadCodeTool, githubCreatePrTool;
8797
8827
  var init_github = __esm({
8798
8828
  "src/tools/github.ts"() {
8799
8829
  "use strict";
8800
8830
  init_version();
8831
+ execFile3 = promisify3(execFileCallback);
8801
8832
  GITHUB_API_BASE = "https://api.github.com";
8802
8833
  TIMEOUT_MS3 = 2e4;
8803
8834
  githubListMergedPrsTool = {
@@ -9725,11 +9756,11 @@ var init_memory = __esm({
9725
9756
  });
9726
9757
 
9727
9758
  // src/tools/hotcell-snapshot.ts
9728
- import { execFile as execFile3 } from "child_process";
9759
+ import { execFile as execFile4 } from "child_process";
9729
9760
  import { mkdtemp, rm as rm2 } from "fs/promises";
9730
9761
  import { tmpdir as tmpdir3 } from "os";
9731
9762
  import { join as join20 } from "path";
9732
- import { promisify as promisify3 } from "util";
9763
+ import { promisify as promisify4 } from "util";
9733
9764
  async function git(args, cwd, env2) {
9734
9765
  const { stdout } = await execFileAsync2("git", args, {
9735
9766
  cwd,
@@ -9831,7 +9862,7 @@ var execFileAsync2, MAX_SNAPSHOT_PATCH_BYTES, MAX_ARCHIVE_BYTES, SECRET_EXCLUDES
9831
9862
  var init_hotcell_snapshot = __esm({
9832
9863
  "src/tools/hotcell-snapshot.ts"() {
9833
9864
  "use strict";
9834
- execFileAsync2 = promisify3(execFile3);
9865
+ execFileAsync2 = promisify4(execFile4);
9835
9866
  MAX_SNAPSHOT_PATCH_BYTES = 4 * 1024 * 1024;
9836
9867
  MAX_ARCHIVE_BYTES = 24 * 1024 * 1024;
9837
9868
  SECRET_EXCLUDES = [
@@ -9930,8 +9961,8 @@ var init_hotcell_worker_cache = __esm({
9930
9961
 
9931
9962
  // src/tools/hotcell-worker.ts
9932
9963
  import { spawn as spawn2 } from "child_process";
9933
- import { promisify as promisify4 } from "util";
9934
- import { execFile as execFile4 } from "child_process";
9964
+ import { promisify as promisify5 } from "util";
9965
+ import { execFile as execFile5 } from "child_process";
9935
9966
  import { resolve as resolve3 } from "path";
9936
9967
  async function runHotcellWorker(options) {
9937
9968
  const workerId = `hotcell-${crypto.randomUUID().slice(0, 8)}`;
@@ -9955,6 +9986,14 @@ async function runHotcellWorker(options) {
9955
9986
  const execute = options.processRunner ?? runProcess;
9956
9987
  const timeoutMs = options.timeoutMs ?? DEFAULT_CELL_TIMEOUT_MS;
9957
9988
  try {
9989
+ const started = await execute(command, ["start", "--defaults"], {
9990
+ cwd,
9991
+ signal: options.signal,
9992
+ timeoutMs: 3e4
9993
+ });
9994
+ if (started.code !== 0 || started.timedOut || started.aborted) {
9995
+ throw new Error(formatSetupFailure(started).replace("Hotcell setup failed", "Hotcell daemon startup failed"));
9996
+ }
9958
9997
  const useArchive = options.useArchive ?? process.env.KIMIFLARE_WORKER_ARCHIVE !== "0";
9959
9998
  const tree = useArchive ? await getWorkingTreeArchive(cwd) : { archive: null, files: 0, bytes: 0 };
9960
9999
  const repo = tree.archive ? null : await getRepositorySnapshot(cwd);
@@ -10346,10 +10385,10 @@ var init_hotcell_worker = __esm({
10346
10385
  init_registry();
10347
10386
  init_hotcell_snapshot();
10348
10387
  init_hotcell_worker_cache();
10349
- execFileAsync3 = promisify4(execFile4);
10388
+ execFileAsync3 = promisify5(execFile5);
10350
10389
  MAX_OUTPUT_BYTES = 1e6;
10351
10390
  MAX_PROMPT_CHARS = 4e4;
10352
- DEFAULT_CELL_TIMEOUT_MS = 3e5;
10391
+ DEFAULT_CELL_TIMEOUT_MS = 6e5;
10353
10392
  DEFAULT_SETUP_TIMEOUT_MS = 3e5;
10354
10393
  WORKER_BIN = `${CACHED_WORKER_DIR}/node_modules/.bin/${CLI_NAME}`;
10355
10394
  PACKAGE_SPEC = /^[\w@./:+~^=<>#-]+$/;
@@ -10584,7 +10623,7 @@ function fromLegacySpawnWorkerArgs(args) {
10584
10623
  }
10585
10624
  function formatWorkerResult(result2, model) {
10586
10625
  const lines = [
10587
- "Subagent " + result2.status + (result2.status === "budget_exhausted" ? " (partial result)" : "") + ".",
10626
+ "Subagent " + result2.status + (result2.status === "budget_exhausted" || result2.status === "spend_exhausted" ? " (partial result)" : "") + ".",
10588
10627
  "Model: " + (result2.model ?? model) + " \xB7 Tokens: " + result2.tokensUsed.toLocaleString() + " \xB7 Cost: " + (result2.costUsd > 0 ? result2.costUsd.toFixed(4) + " total cost" : "unavailable") + ".",
10589
10628
  ...result2.findings.map((finding) => "\n## " + finding.topic + (result2.structured ? " (" + finding.confidence + " confidence)" : "") + "\n" + finding.summary + (finding.sources.length ? "\nFiles: " + finding.sources.join(", ") : ""))
10590
10629
  ];
@@ -10600,7 +10639,7 @@ function formatWorkerResult(result2, model) {
10600
10639
  if (!result2.structured && result2.findings.length) {
10601
10640
  lines.push("\n(The subagent did not return a structured report; findings above are its raw answer and are unverified.)");
10602
10641
  }
10603
- if (result2.status === "budget_exhausted") {
10642
+ if (result2.status === "budget_exhausted" || result2.status === "spend_exhausted") {
10604
10643
  lines.push("\nThe subagent ran out of budget; review partial findings before relying on them.");
10605
10644
  }
10606
10645
  return lines.join("\n");
@@ -10630,7 +10669,7 @@ var init_subagent = __esm({
10630
10669
  init_hotcell_worker();
10631
10670
  init_worker_registry();
10632
10671
  init_subagent_stats();
10633
- DEFAULT_WORKER_TIMEOUT_MS = 3e5;
10672
+ DEFAULT_WORKER_TIMEOUT_MS = 6e5;
10634
10673
  subagentTool = {
10635
10674
  name: "subagent",
10636
10675
  description: [
@@ -10752,7 +10791,7 @@ var init_subagent = __esm({
10752
10791
  if (handle.cancelledByUser && !ctx.signal?.aborted) {
10753
10792
  return textOutput(userCancelledMessage(handle.index, args.mission));
10754
10793
  }
10755
- if (result2.status !== "completed" && result2.status !== "budget_exhausted") {
10794
+ if (result2.status !== "completed" && result2.status !== "budget_exhausted" && !(result2.status === "spend_exhausted" && result2.partialResult && result2.findings.length > 0)) {
10756
10795
  throw new Error("Subagent " + result2.status + ": " + (result2.error ?? "unknown error"));
10757
10796
  }
10758
10797
  return textOutput(formatWorkerResult(result2, model));
@@ -13431,11 +13470,11 @@ var init_retention = __esm({
13431
13470
  });
13432
13471
 
13433
13472
  // src/trace/session-start.ts
13434
- import { execFile as execFile5 } from "child_process";
13473
+ import { execFile as execFile6 } from "child_process";
13435
13474
  import { existsSync as existsSync5 } from "fs";
13436
13475
  import { dirname as dirname13, join as join27 } from "path";
13437
13476
  import { fileURLToPath as fileURLToPath4 } from "url";
13438
- import { promisify as promisify5 } from "util";
13477
+ import { promisify as promisify6 } from "util";
13439
13478
  async function git2(args, cwd) {
13440
13479
  try {
13441
13480
  const { stdout } = await execFileAsync4("git", args, { cwd, timeout: 3e3, windowsHide: true });
@@ -13491,7 +13530,7 @@ var init_session_start = __esm({
13491
13530
  init_version();
13492
13531
  init_blobs();
13493
13532
  init_redact();
13494
- execFileAsync4 = promisify5(execFile5);
13533
+ execFileAsync4 = promisify6(execFile6);
13495
13534
  }
13496
13535
  });
13497
13536
 
@@ -14003,11 +14042,11 @@ var init_tasks2 = __esm({
14003
14042
  });
14004
14043
 
14005
14044
  // src/eval/workspace.ts
14006
- import { execFile as execFile6 } from "child_process";
14045
+ import { execFile as execFile7 } from "child_process";
14007
14046
  import { createHash as createHash4 } from "crypto";
14008
14047
  import { mkdir as mkdir12, rm as rm4, stat as stat8 } from "fs/promises";
14009
14048
  import { isAbsolute as isAbsolute3, join as join30, resolve as resolve9 } from "path";
14010
- import { promisify as promisify6 } from "util";
14049
+ import { promisify as promisify7 } from "util";
14011
14050
  async function git3(args, cwd, timeoutMs = 6e5) {
14012
14051
  const { stdout } = await execFileAsync5("git", args, { cwd, timeout: timeoutMs, maxBuffer: 64 * 1024 * 1024 });
14013
14052
  return stdout.trim();
@@ -14065,7 +14104,7 @@ var execFileAsync5, preparing;
14065
14104
  var init_workspace = __esm({
14066
14105
  "src/eval/workspace.ts"() {
14067
14106
  "use strict";
14068
- execFileAsync5 = promisify6(execFile6);
14107
+ execFileAsync5 = promisify7(execFile7);
14069
14108
  preparing = /* @__PURE__ */ new Map();
14070
14109
  }
14071
14110
  });
@@ -19134,7 +19173,7 @@ var init_openapi = __esm({
19134
19173
  });
19135
19174
 
19136
19175
  // src/runs/worktrees.ts
19137
- import { execFile as execFile7 } from "child_process";
19176
+ import { execFile as execFile8 } from "child_process";
19138
19177
  import { access as access2, chmod as chmod2, mkdir as mkdir16, realpath as realpath4 } from "fs/promises";
19139
19178
  import { homedir as homedir25 } from "os";
19140
19179
  import { isAbsolute as isAbsolute5, join as join40, parse, relative as relative8, resolve as resolve12, sep as sep4 } from "path";
@@ -19151,7 +19190,7 @@ function isWithin2(parent, candidate) {
19151
19190
  }
19152
19191
  function runGit(args, cwd) {
19153
19192
  return new Promise((resolveOutput, reject) => {
19154
- execFile7("git", args, { cwd, encoding: "utf8", timeout: 3e4, maxBuffer: 1024 * 1024 }, (error, stdout, stderr) => {
19193
+ execFile8("git", args, { cwd, encoding: "utf8", timeout: 3e4, maxBuffer: 1024 * 1024 }, (error, stdout, stderr) => {
19155
19194
  if (error) {
19156
19195
  const detail = stderr.trim();
19157
19196
  reject(new Error(`git ${args[0]} failed${detail ? `: ${detail}` : ""}`, { cause: error }));
@@ -20106,9 +20145,9 @@ data: ${JSON.stringify(event.data)}
20106
20145
  });
20107
20146
 
20108
20147
  // src/server/aster-cell-runtime.ts
20109
- import { execFile as execFile8 } from "child_process";
20148
+ import { execFile as execFile9 } from "child_process";
20110
20149
  import { readFile as readFile26 } from "fs/promises";
20111
- import { promisify as promisify7 } from "util";
20150
+ import { promisify as promisify8 } from "util";
20112
20151
  import { randomUUID as randomUUID8 } from "crypto";
20113
20152
  async function writeCellFileChunked(cell, path, content) {
20114
20153
  if (Buffer.byteLength(content, "utf8") <= CELL_FILE_WRITE_CHUNK_CHARS) {
@@ -20198,7 +20237,7 @@ var init_aster_cell_runtime = __esm({
20198
20237
  "use strict";
20199
20238
  init_version();
20200
20239
  init_aster_tools();
20201
- execFileAsync6 = promisify7(execFile8);
20240
+ execFileAsync6 = promisify8(execFile9);
20202
20241
  CELL_WORKSPACE = "/workspace";
20203
20242
  CELL_STATE_DIR = "/workspace/.aster";
20204
20243
  CHECKPOINT_MESSAGE_FILE = `${CELL_STATE_DIR}/checkpoint-message`;
@@ -25952,13 +25991,17 @@ function activityFromSubagent(worker) {
25952
25991
  return {
25953
25992
  id: `agent:${worker.id}`,
25954
25993
  kind: "agent",
25955
- title: `subagent #${worker.index}: ${worker.task}`,
25994
+ title: `subagent #${worker.index}: ${activityTaskPreview(worker.task)}`,
25956
25995
  status: "running",
25957
25996
  stoppable: worker.status === "running",
25958
25997
  ...worker.status === "cancelling" ? { summary: "Stopping\u2026" } : {},
25959
25998
  started_at_ms: worker.startedAt
25960
25999
  };
25961
26000
  }
26001
+ function activityTaskPreview(task) {
26002
+ const oneLine2 = task.replace(/\s+/g, " ").trim();
26003
+ return oneLine2.length > 72 ? `${oneLine2.slice(0, 71)}\u2026` : oneLine2;
26004
+ }
25962
26005
  function diffActivityItems(previous, current, snapshotSent) {
25963
26006
  if (!snapshotSent) return [{ type: "ActivitySnapshot", payload: { items: [...current] } }];
25964
26007
  const next = new Map(current.map((item) => [item.id, item]));
@@ -33031,6 +33074,22 @@ var init_task_list = __esm({
33031
33074
  }
33032
33075
  });
33033
33076
 
33077
+ // src/ui/terminal-title.ts
33078
+ function terminalTitleSequence(title) {
33079
+ const safeTitle = title.replace(/[\u0000-\u001f\u007f\u009b\u009d]/g, " ").trim();
33080
+ return safeTitle ? `\x1B]0;${safeTitle}\x07` : null;
33081
+ }
33082
+ function setTerminalTitle(title) {
33083
+ if (!process.stdout.isTTY) return;
33084
+ const sequence = terminalTitleSequence(title);
33085
+ if (sequence) process.stdout.write(sequence);
33086
+ }
33087
+ var init_terminal_title = __esm({
33088
+ "src/ui/terminal-title.ts"() {
33089
+ "use strict";
33090
+ }
33091
+ });
33092
+
33034
33093
  // src/models/openrouter-oauth.ts
33035
33094
  var openrouter_oauth_exports = {};
33036
33095
  __export(openrouter_oauth_exports, {
@@ -33725,7 +33784,7 @@ var init_loader2 = __esm({
33725
33784
  import { exec } from "child_process";
33726
33785
  import { open as open2, realpath as realpath7 } from "fs/promises";
33727
33786
  import { isAbsolute as isAbsolute7, relative as relative11, resolve as resolvePathJoin, basename as pathBasename } from "path";
33728
- import { promisify as promisify8 } from "util";
33787
+ import { promisify as promisify9 } from "util";
33729
33788
  function tokenizeArgs(s) {
33730
33789
  return [...s.matchAll(ARG_TOKEN_RE)].map((match) => {
33731
33790
  const token = match[0];
@@ -33878,7 +33937,7 @@ var init_renderer2 = __esm({
33878
33937
  "src/commands/renderer.ts"() {
33879
33938
  "use strict";
33880
33939
  init_paths2();
33881
- execAsync = promisify8(exec);
33940
+ execAsync = promisify9(exec);
33882
33941
  ARG_TOKEN_RE = /(?:"[^"]*"|'[^']*'|[^\s"']+)/g;
33883
33942
  POSITIONAL_RE = /\$(\d+)/g;
33884
33943
  HAS_POSITIONAL = /\$\d+/;
@@ -36460,6 +36519,8 @@ function useSessionManager(deps) {
36460
36519
  endTrace(checkpointId ? "restore_checkpoint" : "exit");
36461
36520
  turnHistoryRef.current = [];
36462
36521
  sessionIdRef.current = file.id;
36522
+ sessionTitleRef.current = file.title ?? null;
36523
+ if (file.title) setTerminalTitle(file.title);
36463
36524
  setLogSessionId(file.id);
36464
36525
  sessionCreatedAtRef.current = file.createdAt;
36465
36526
  if (file.sessionState && d.compiledContextRef.current) {
@@ -36641,6 +36702,7 @@ ${summary}`
36641
36702
  setLogSessionId(null);
36642
36703
  sessionCreatedAtRef.current = null;
36643
36704
  sessionTitleRef.current = null;
36705
+ setTerminalTitle("autopilot");
36644
36706
  const d = depsRef.current;
36645
36707
  d.sessionStateRef.current = emptySessionState();
36646
36708
  d.artifactStoreRef.current = new ArtifactStore();
@@ -36678,6 +36740,7 @@ ${summary}`
36678
36740
  var init_use_session_manager = __esm({
36679
36741
  "src/ui/use-session-manager.ts"() {
36680
36742
  "use strict";
36743
+ init_terminal_title();
36681
36744
  init_sessions();
36682
36745
  init_session_state();
36683
36746
  init_llm_auth();
@@ -40015,6 +40078,7 @@ ${result2.output ?? "(output not captured)"}`,
40015
40078
  setIntentTier(classification.tier);
40016
40079
  if (!sessionTitleRef.current) {
40017
40080
  sessionTitleRef.current = generateSessionTitle(trimmed, classification.intent);
40081
+ setTerminalTitle(sessionTitleRef.current);
40018
40082
  }
40019
40083
  const effortForTier = {
40020
40084
  light: "low",
@@ -41415,6 +41479,7 @@ var init_app = __esm({
41415
41479
  init_completion_check();
41416
41480
  init_task_list();
41417
41481
  init_text_input();
41482
+ init_terminal_title();
41418
41483
  init_update_check();
41419
41484
  init_onboarding();
41420
41485
  init_welcome();