@garuda-agent/garuda 0.16.1 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/CHANGELOG.md +319 -0
  2. package/README.md +56 -1074
  3. package/SECURITY.md +9 -2
  4. package/dist/{acpCommand-OTAYW7BS.js → acpCommand-IUZPLPLI.js} +25 -23
  5. package/dist/{anthropic-NQDBCHJU.js → anthropic-NQIZLD64.js} +12 -6
  6. package/dist/{chunk-NP6RIC25.js → chunk-2FIV2VZP.js} +11 -7
  7. package/dist/{chunk-YQTGMCU6.js → chunk-3MRQJKUO.js} +29 -5
  8. package/dist/{chunk-HE2K657U.js → chunk-4BVCYCQT.js} +47 -16
  9. package/dist/{chunk-WMOLXTBU.js → chunk-4LFJFDCF.js} +2 -1
  10. package/dist/{chunk-44QN5SWZ.js → chunk-55CFEEIN.js} +22 -2
  11. package/dist/{chunk-USCUXCAU.js → chunk-5B5HDTUR.js} +3 -3
  12. package/dist/chunk-65NUEOI7.js +143 -0
  13. package/dist/{chunk-TUUEBHG2.js → chunk-6XHON3Q6.js} +2 -2
  14. package/dist/chunk-7KBOIPUT.js +157 -0
  15. package/dist/{chunk-B6FA4I7Q.js → chunk-7TH3NHCQ.js} +2 -2
  16. package/dist/{chunk-OUCV3FCT.js → chunk-AOGFYUKG.js} +3 -3
  17. package/dist/{chunk-GXZACJUI.js → chunk-B4SJY7KT.js} +322 -39
  18. package/dist/{chunk-3EQU2GUX.js → chunk-BHZ6G65V.js} +5 -1
  19. package/dist/chunk-C57GHLKP.js +9 -0
  20. package/dist/chunk-DOCDCQVM.js +484 -0
  21. package/dist/chunk-FOPBOB7W.js +332 -0
  22. package/dist/{chunk-TILFPYWO.js → chunk-NHWHG3SW.js} +1930 -992
  23. package/dist/{chunk-BQTUOO4G.js → chunk-OQ26W5L4.js} +81 -32
  24. package/dist/{chunk-HUIK3WXO.js → chunk-P6XWWIEK.js} +20 -3
  25. package/dist/chunk-Q4P3W657.js +6372 -0
  26. package/dist/{chunk-ZAE25JM2.js → chunk-QANRZW7W.js} +8 -1
  27. package/dist/chunk-UIRJOQQS.js +118 -0
  28. package/dist/chunk-UKIE4AAM.js +472 -0
  29. package/dist/{chunk-KKB5W47S.js → chunk-VTMD5IHD.js} +26 -2
  30. package/dist/cli/index.js +148 -57
  31. package/dist/config-WV2H64TF.js +23 -0
  32. package/dist/{create-VXIH2GUZ.js → create-W6BV75QX.js} +18 -12
  33. package/dist/{deadline-F5RJJ2QW.js → deadline-TP7ZGLT2.js} +4 -2
  34. package/dist/evalCommand-SKJQ6CW2.js +686 -0
  35. package/dist/evalTune-CZRCPSZ3.js +295 -0
  36. package/dist/{export-HN3CT7AV.js → export-SJ3DUP6W.js} +2 -2
  37. package/dist/{inkChat-WEDGQMCY.js → inkChat-WYYAFZXD.js} +20 -19
  38. package/dist/install-TKWN5AYH.js +19 -0
  39. package/dist/{job-3NYDMP2M.js → job-7JOI4YIQ.js} +6 -2
  40. package/dist/jobCommand-2ODQLHB3.js +33 -0
  41. package/dist/{launchd-SSX362VG.js → launchd-3A3ONEW5.js} +9 -8
  42. package/dist/{lspCommand-JRXKRSL7.js → lspCommand-ZZ6R4PA2.js} +7 -6
  43. package/dist/{manager-773PUDFE.js → manager-TCYTA5XU.js} +15 -14
  44. package/dist/{nightCommand-65MUEV32.js → nightCommand-WJU6VZA6.js} +26 -20
  45. package/dist/{openaiCompatible-CJWVJP5M.js → openaiCompatible-6TLDDW5U.js} +29 -15
  46. package/dist/{policy-EJPLEEXP.js → policy-ZJ7RMOFN.js} +10 -4
  47. package/dist/{remove-6GDSTAIO.js → remove-42WQNVPX.js} +8 -7
  48. package/dist/{run-ML6GSPN4.js → run-PTMRQCIU.js} +5 -5
  49. package/dist/{server-NGKVIQEV.js → server-VEYIJHEU.js} +2 -2
  50. package/dist/{setupCommand-VA7D5MZK.js → setupCommand-YMF6I3MD.js} +45 -13
  51. package/dist/text-LS35WSRL.js +17 -0
  52. package/dist/tune-YVI2KWQF.js +31 -0
  53. package/native/bin/garuda-reap +0 -0
  54. package/native/garuda-reap.c +113 -0
  55. package/package.json +39 -13
  56. package/dist/chunk-EIXUSVFX.js +0 -116
  57. package/dist/chunk-R7I2NBPX.js +0 -71
  58. package/dist/chunk-ULAJPMY7.js +0 -107
  59. package/dist/chunk-VBZCNMUD.js +0 -9
  60. package/dist/evalCommand-RGMZRYDR.js +0 -2812
  61. package/dist/install-EWDSPFFZ.js +0 -18
  62. package/dist/jobCommand-ACSGSBQ4.js +0 -32
  63. package/dist/text-J2GD647J.js +0 -11
package/dist/cli/index.js CHANGED
@@ -15,7 +15,11 @@ import {
15
15
  runCommand,
16
16
  runTurnInTerminal,
17
17
  stopMessage
18
- } from "../chunk-BQTUOO4G.js";
18
+ } from "../chunk-OQ26W5L4.js";
19
+ import {
20
+ SwitchApprover,
21
+ TerminalApprover
22
+ } from "../chunk-4JSUUDFQ.js";
19
23
  import {
20
24
  PlainRenderer
21
25
  } from "../chunk-FARS4R67.js";
@@ -23,43 +27,44 @@ import {
23
27
  AutoApprover
24
28
  } from "../chunk-NXJ4XLB5.js";
25
29
  import {
26
- Notifier,
27
- pickChannel
28
- } from "../chunk-N4I6YS3E.js";
29
- import {
30
- SwitchApprover,
31
- TerminalApprover
32
- } from "../chunk-4JSUUDFQ.js";
30
+ NO_MODEL,
31
+ chooseModel,
32
+ keepProviderKeys,
33
+ loadModelsConfig,
34
+ providerKeySource,
35
+ resolveModel
36
+ } from "../chunk-2FIV2VZP.js";
33
37
  import {
34
38
  DEFAULT_MAX_TOKENS,
35
- FileSessionStore,
36
39
  Runtime,
37
40
  ToolRegistry,
38
41
  auditDirFor,
39
- closeOpenToolCalls,
40
- createSession,
41
42
  defaultTools,
42
- parseRecords,
43
- popPoint,
44
- pushPoint,
45
43
  rebuildState,
46
- redoPoint,
47
44
  runAgent,
48
45
  signature
49
- } from "../chunk-TILFPYWO.js";
46
+ } from "../chunk-NHWHG3SW.js";
47
+ import {
48
+ loadCatalog
49
+ } from "../chunk-65NUEOI7.js";
50
50
  import "../chunk-G2AX7MGS.js";
51
51
  import "../chunk-A2QAIRQL.js";
52
- import "../chunk-ULAJPMY7.js";
53
52
  import {
54
- NO_MODEL,
55
- chooseModel,
56
- keepProviderKeys,
57
- loadModelsConfig,
58
- providerKeySource,
59
- resolveModel
60
- } from "../chunk-NP6RIC25.js";
61
- import "../chunk-EIXUSVFX.js";
62
- import "../chunk-R7I2NBPX.js";
53
+ Notifier,
54
+ pickChannel
55
+ } from "../chunk-N4I6YS3E.js";
56
+ import {
57
+ FileSessionStore,
58
+ closeOpenToolCalls,
59
+ createSession,
60
+ isCostIncomplete,
61
+ parseRecords,
62
+ pendingChildTokens,
63
+ popPoint,
64
+ pushPoint,
65
+ redoPoint
66
+ } from "../chunk-UKIE4AAM.js";
67
+ import "../chunk-7KBOIPUT.js";
63
68
  import {
64
69
  loadSearchConfig
65
70
  } from "../chunk-B25VL4RU.js";
@@ -69,19 +74,20 @@ import {
69
74
  import "../chunk-EU7PA45O.js";
70
75
  import {
71
76
  VERSION
72
- } from "../chunk-VBZCNMUD.js";
77
+ } from "../chunk-C57GHLKP.js";
73
78
  import "../chunk-5DEWP3YX.js";
74
- import "../chunk-ZAE25JM2.js";
75
- import "../chunk-ATW7BNIG.js";
76
79
  import "../chunk-PZS3V6P3.js";
77
- import "../chunk-OUCV3FCT.js";
80
+ import "../chunk-QANRZW7W.js";
81
+ import "../chunk-ATW7BNIG.js";
82
+ import "../chunk-AOGFYUKG.js";
78
83
  import {
79
84
  JOB_DENIAL
80
- } from "../chunk-GXZACJUI.js";
81
- import "../chunk-WMOLXTBU.js";
82
- import "../chunk-3EQU2GUX.js";
83
- import "../chunk-HUIK3WXO.js";
84
- import "../chunk-KKB5W47S.js";
85
+ } from "../chunk-B4SJY7KT.js";
86
+ import "../chunk-BHZ6G65V.js";
87
+ import "../chunk-P6XWWIEK.js";
88
+ import "../chunk-VTMD5IHD.js";
89
+ import "../chunk-UIRJOQQS.js";
90
+ import "../chunk-4LFJFDCF.js";
85
91
  import "../chunk-3NJNVZTK.js";
86
92
 
87
93
  // src/cli/index.ts
@@ -254,9 +260,41 @@ var NO_PERMISSIONS = {
254
260
  throw new Error("Replay runs no commands.");
255
261
  },
256
262
  deniedByPolicy: () => true,
263
+ writeScopeDenial: async () => "replay: no writes",
257
264
  commandPolicyDenial: () => "Replay runs no commands."
258
265
  };
259
266
 
267
+ // src/nodeFloor.ts
268
+ var NODE_SECURITY = {
269
+ date: "2026-10-21",
270
+ advisory: "https://nodejs.org/en/blog/vulnerability/october-2026-security-releases",
271
+ lines: { 22: "22.23.4", 24: "24.22.1", 26: "26.12.1" }
272
+ };
273
+ function nodeProblem(version = process.versions.node) {
274
+ const [major = 0] = parse(version);
275
+ const lines = Object.keys(NODE_SECURITY.lines).map(Number);
276
+ const floor = NODE_SECURITY.lines[major];
277
+ const use = `Use Node ${lines.map((l) => NODE_SECURITY.lines[l]).join(", ")} or later.`;
278
+ if (floor === void 0) {
279
+ if (major > Math.max(...lines)) return void 0;
280
+ return `Node ${version} gets no security fixes (Garuda supports ${lines.join(", ")}). ${use}`;
281
+ }
282
+ if (compare(parse(version), parse(floor)) < 0) {
283
+ return `Node ${version} does not have the security fixes of ${NODE_SECURITY.date} (${NODE_SECURITY.advisory}). Update to ${floor} or later.`;
284
+ }
285
+ return void 0;
286
+ }
287
+ function parse(version) {
288
+ return version.replace(/^v/, "").split(/[.-]/).slice(0, 3).map((n) => Number.parseInt(n, 10) || 0);
289
+ }
290
+ function compare(a, b) {
291
+ for (let i = 0; i < 3; i++) {
292
+ const d = (a[i] ?? 0) - (b[i] ?? 0);
293
+ if (d !== 0) return d;
294
+ }
295
+ return 0;
296
+ }
297
+
260
298
  // src/cli/banner.ts
261
299
  import { homedir } from "os";
262
300
  var WORDMARK = [
@@ -516,7 +554,8 @@ function assistantLine(response, model) {
516
554
  }),
517
555
  stop_reason: response.stopReason,
518
556
  stop_sequence: null,
519
- usage: apiUsage(response.usage)
557
+ usage: apiUsage(response.usage),
558
+ ...response.usageReported === false ? { usage_is_estimated: true } : {}
520
559
  },
521
560
  parent_tool_use_id: null
522
561
  };
@@ -564,7 +603,12 @@ function resultLine(outcome, info) {
564
603
  ...subtype === "success" ? { result: info.lastText } : {},
565
604
  stop_reason: result?.modelStopReason ?? null,
566
605
  total_cost_usd: info.totalCostUsd,
606
+ ...info.totalCostUnknown === true ? { total_cost_is_unknown: true } : {},
607
+ ...info.totalCostIncomplete === true ? { total_cost_is_incomplete: true } : {},
567
608
  usage: apiUsage(usage),
609
+ ...(result?.unreportedTokens ?? 0) > 0 ? { usage_is_incomplete: true, unreported_budget_tokens: result?.unreportedTokens } : {},
610
+ ...info.runCostUsd === void 0 ? { cost_is_unknown: true } : {},
611
+ ...info.runCostUsd !== void 0 && info.runCostIncomplete === true ? { cost_is_incomplete: true } : {},
568
612
  modelUsage: {
569
613
  [info.model]: {
570
614
  inputTokens: usage.inputTokens,
@@ -729,6 +773,9 @@ function askTerminal(prompt, history, io, completer) {
729
773
 
730
774
  // src/cli/index.ts
731
775
  async function main() {
776
+ const nodeWarning = nodeProblem();
777
+ if (nodeWarning !== void 0) process.stderr.write(`Warning: ${nodeWarning}
778
+ `);
732
779
  const program = new Command().enablePositionalOptions().name("garuda").description("A terminal coding agent. With no task, it starts a chat in the current folder.").version(VERSION).option("-p, --prompt <task>", "run one task and exit").option("-m, --model <id>", "model id (or set GARUDA_MODEL)").option(
733
780
  "--subagent-model <id>",
734
781
  "model of the explore subagent (or set GARUDA_SUBAGENT_MODEL); default: the main model"
@@ -737,10 +784,23 @@ async function main() {
737
784
  ).option("--verbose", "with json output: also show the tool activity on stderr").action(async (options) => {
738
785
  process.exitCode = await start(options, program);
739
786
  });
740
- program.command("eval").description("run the eval tasks in scratch folders and report pass/fail, steps and cost").option("-m, --model <id>", "model id (or set GARUDA_MODEL)").option("-s, --suite <name>", "basic (default), hard, java, python, all or repo").option("-t, --task <ids...>", "run only these tasks (from any suite)").option("--max-steps <n>", "step limit per task", (v) => Number.parseInt(v, 10)).option(
787
+ const evalCommand = program.command("eval").description("run the eval tasks in scratch folders and report pass/fail, steps and cost").option("-m, --model <id>", "model id (or set GARUDA_MODEL)").option("-s, --suite <name>", "basic (default), hard, java, python, medium, all or repo").option(
788
+ "-t, --task <ids...>",
789
+ "run only these tasks (from any dev suite, or the held-out set with --split)"
790
+ ).option("--max-steps <n>", "step limit per task", (v) => Number.parseInt(v, 10)).option(
741
791
  "--repeat <n>",
742
792
  "run each task n times and show the mean",
743
793
  (v) => Number.parseInt(v, 10)
794
+ ).option("--agent <name>", "garuda (default) or claude-code: the baseline on the same tasks").option(
795
+ "--split <name>",
796
+ "dev (default), heldout or all: the held-out tasks run only on request"
797
+ ).option("--addendum <file>", "add this text (4000 characters at most) to the system prompt").option("--mcp <server>", "allow this one server from ~/.garuda/mcp.json (an MCP A/B)").option(
798
+ "--mcp-prepare <command>",
799
+ "with --mcp: run this in each scratch folder before the agent (e.g. graphify update .)"
800
+ ).option("--shuffle", "run the tasks and their repeats in a random order from --seed").option(
801
+ "--seed <n>",
802
+ "seed for --shuffle and the report's interval (default 1)",
803
+ (v) => Number(v)
744
804
  ).option("--index <mode>", "code index tools for the model: off (default), lookup or all").option("--executor <name>", "auto (default), os or host").option("--keep", "keep the scratch folders").option("--list", "list the tasks and exit").option("--subagents <mode>", "the explore subagent: off (default) or on, for A/B runs").option("--subagent-model <id>", "model of the explore subagent; default: the main model").option("--todo <mode>", "the todo_write tool: off (default) or on, for A/B runs").option("--lsp <mode>", "language server errors in edit results: off (default) or on").option(
745
805
  "--format <mode>",
746
806
  "the project's formatter after edits: off (default) or on, for A/B runs"
@@ -772,13 +832,33 @@ async function main() {
772
832
  "--test-command <cmd>",
773
833
  "with --from-git: the test command; {files} takes the test files (default: detected)"
774
834
  ).action(async (options) => {
775
- const { runEvalCommand } = await import("../evalCommand-RGMZRYDR.js");
835
+ const { runEvalCommand } = await import("../evalCommand-SKJQ6CW2.js");
776
836
  process.exitCode = await runEvalCommand({
777
837
  ...options,
778
838
  model: options.model ?? process.env.GARUDA_MODEL,
779
839
  subagentModel: options.subagentModel ?? process.env.GARUDA_SUBAGENT_MODEL
780
840
  });
781
841
  });
842
+ evalCommand.command("tune").description(
843
+ "improve a prompt addendum: a proposer model edits it, an edit stays when the dev score improves, the held-out set is measured once"
844
+ ).requiredOption(
845
+ "--addendum <file>",
846
+ "the starting addendum (a missing file starts empty); never edited"
847
+ ).option("--proposer <model>", "the model that proposes edits (default claude-opus-5-5)").option("-m, --model <id>", "the agent's model (or set GARUDA_MODEL)").option("-s, --suite <names...>", "dev suites (default: basic hard medium)").option("--rounds <n>", "proposals (default 5)", (v) => Number(v)).option("--repeat <n>", "runs of each dev task per score (default 3)", (v) => Number(v)).option("--heldout-repeat <n>", "runs of each held-out task (default 5)", (v) => Number(v)).option("--margin <n>", "more passing runs that keep an edit (default 2)", (v) => Number(v)).option(
848
+ "--max-cost <usd>",
849
+ "stop before a round that would pass this (default 20)",
850
+ (v) => Number(v)
851
+ ).option("--seed <n>", "seed for the run order and the intervals (default 1)", (v) => Number(v)).option("--yes", "start without the question").option("--parallel <n>", "runs at the same time in each score (default 4)", (v) => Number(v)).action(async (options) => {
852
+ const { runEvalTune } = await import("../evalTune-CZRCPSZ3.js");
853
+ process.exitCode = await runEvalTune({
854
+ ...options,
855
+ model: options.model ?? process.env.GARUDA_MODEL
856
+ });
857
+ });
858
+ evalCommand.command("compare").description("compare two eval reports of the same tasks (pass rates with a paired interval)").argument("<a>", "report.json, or its run folder (.garuda/evals/<run-id>)").argument("<b>", "the second report").option("--seed <n>", "seed for the bootstrap (default 1)", (v) => Number(v)).action(async (a, b, options) => {
859
+ const { runEvalCompare } = await import("../evalCommand-SKJQ6CW2.js");
860
+ process.exitCode = await runEvalCompare(a, b, options);
861
+ });
782
862
  program.command("init").description(
783
863
  "set up this folder (AGENTS.md; commands, MCP servers and rules from Claude Code, OpenCode, Codex, Gemini CLI, Tabnine, Cursor, Copilot), then chat"
784
864
  ).option("-m, --model <id>", "model id (or set GARUDA_MODEL)").action(async (options) => {
@@ -794,30 +874,30 @@ async function main() {
794
874
  program.command("night").description(
795
875
  "run this project's night queue (jobs from /schedule), up to 3 at a time, then write one digest"
796
876
  ).option("--at <HH:MM>", "wait until this local time first (keep the terminal open)").option("--parallel <n>", "jobs at the same time (1 to 10, default 3)").addOption(new Option("--from-launchd").hideHelp()).action(async (options) => {
797
- const { nightCommand } = await import("../nightCommand-65MUEV32.js");
877
+ const { nightCommand } = await import("../nightCommand-WJU6VZA6.js");
798
878
  process.exitCode = await nightCommand(options, new PlainRenderer());
799
879
  });
800
880
  program.command("setup").description(
801
881
  "choose a provider and model and store its key (~/.garuda/credentials, only you can read it); editors run it to sign in"
802
882
  ).option("--show", "show the model and where each key comes from (keys masked)").option("--forget [key-name]", "remove a stored key, or all of them").action(async (options) => {
803
- const { setupCommand, terminalIO } = await import("../setupCommand-VA7D5MZK.js");
883
+ const { setupCommand, terminalIO } = await import("../setupCommand-YMF6I3MD.js");
804
884
  process.exitCode = await setupCommand(options, { io: await terminalIO() });
805
885
  });
806
886
  program.command("acp").description(
807
887
  "run as an agent for an editor over the Agent Client Protocol (VS Code with an extension, Zed, JetBrains, Neovim, Emacs); the editor starts it"
808
888
  ).argument("[action]", "setup: run garuda setup (the editor's sign-in, ACP Terminal Auth)").option("-m, --model <id>", "model id (or set GARUDA_MODEL)").action(async (action, options) => {
809
- const { acpCommand } = await import("../acpCommand-OTAYW7BS.js");
889
+ const { acpCommand } = await import("../acpCommand-IUZPLPLI.js");
810
890
  process.exitCode = await acpCommand({
811
891
  ...options,
812
892
  ...action === void 0 ? {} : { action }
813
893
  });
814
894
  });
815
895
  const lsp = program.command("lsp").description("show the language servers for diagnostics (TS/JS, Python, Java)").action(async () => {
816
- const { lspStatusCommand } = await import("../lspCommand-JRXKRSL7.js");
896
+ const { lspStatusCommand } = await import("../lspCommand-ZZ6R4PA2.js");
817
897
  process.exitCode = await lspStatusCommand();
818
898
  });
819
899
  lsp.command("install").description("install a pinned language server into ~/.garuda/lsp (needs the network)").argument("<language>", "typescript, python or java").action(async (language) => {
820
- const { lspInstallCommand } = await import("../lspCommand-JRXKRSL7.js");
900
+ const { lspInstallCommand } = await import("../lspCommand-ZZ6R4PA2.js");
821
901
  process.exitCode = await lspInstallCommand(language);
822
902
  });
823
903
  await program.parseAsync();
@@ -829,7 +909,7 @@ async function start(options, program) {
829
909
  let job;
830
910
  let jobGuard;
831
911
  if (options.job !== void 0) {
832
- const { prepareJob } = await import("../jobCommand-ACSGSBQ4.js");
912
+ const { prepareJob } = await import("../jobCommand-2ODQLHB3.js");
833
913
  const prepared = await prepareJob(
834
914
  mainRoot,
835
915
  options.job,
@@ -841,7 +921,7 @@ async function start(options, program) {
841
921
  );
842
922
  if (typeof prepared === "number") return prepared;
843
923
  job = prepared;
844
- const { failJobSync } = await import("../job-3NYDMP2M.js");
924
+ const { failJobSync } = await import("../job-7JOI4YIQ.js");
845
925
  const preparedJob = prepared;
846
926
  jobGuard = () => {
847
927
  if (preparedJob.job.status === "running") {
@@ -883,13 +963,14 @@ async function start(options, program) {
883
963
  }
884
964
  }
885
965
  const searchConfig = await loadSearchConfig();
966
+ const catalog = await loadCatalog();
886
967
  const credentialsWarning = await keepProviderKeys([
887
968
  resolved.def.apiKeyEnv,
888
969
  sub?.def.apiKeyEnv,
889
970
  "ANTHROPIC_API_KEY"
890
971
  ]);
891
972
  const anthropicKey = providerKeySource("ANTHROPIC_API_KEY");
892
- const { loadTeamPolicy } = await import("../policy-EJPLEEXP.js");
973
+ const { loadTeamPolicy } = await import("../policy-ZJ7RMOFN.js");
893
974
  let team;
894
975
  try {
895
976
  team = await loadTeamPolicy();
@@ -965,7 +1046,9 @@ async function start(options, program) {
965
1046
  ...r.maxTokens === void 0 ? {} : { maxTokens: r.maxTokens }
966
1047
  };
967
1048
  },
968
- configured: Object.keys(models.config.models)
1049
+ configured: Object.keys(models.config.models),
1050
+ // The account's model list from `garuda setup` (0.17); no network call here.
1051
+ ...catalog === void 0 ? {} : { catalog }
969
1052
  },
970
1053
  ...options.resume === void 0 ? {} : { resume: options.resume },
971
1054
  onEvent: (event) => events.event(event),
@@ -982,11 +1065,11 @@ async function start(options, program) {
982
1065
  "A job needs the OS sandbox (Seatbelt or bubblewrap): without it, every command would need an approval, and nobody is there to give it."
983
1066
  );
984
1067
  await runtime.close();
985
- const { saveJob } = await import("../job-3NYDMP2M.js");
1068
+ const { saveJob } = await import("../job-7JOI4YIQ.js");
986
1069
  job.job.status = "failed";
987
1070
  await saveJob(job.job);
988
1071
  if (options.fromLaunchd === true || job.job.launchd !== void 0) {
989
- const { removeAgent, defaultAgentEnv } = await import("../launchd-SSX362VG.js");
1072
+ const { removeAgent, defaultAgentEnv } = await import("../launchd-3A3ONEW5.js");
990
1073
  await removeAgent(runtime.executor, job.job, defaultAgentEnv());
991
1074
  }
992
1075
  return 1;
@@ -1036,11 +1119,19 @@ async function start(options, program) {
1036
1119
  });
1037
1120
  if (output !== void 0) events = output;
1038
1121
  const costBefore = runtime.session?.costUsd ?? 0;
1122
+ const unreportedBefore = runtime.session?.unreportedTokens ?? 0;
1123
+ const incompleteBefore = runtime.session?.costIncomplete ?? false;
1124
+ const pendingBefore = runtime.session === void 0 ? 0 : pendingChildTokens(runtime.session);
1039
1125
  const finish = (outcome2) => {
1040
- const cost = runtime.session?.costUsd;
1126
+ const session2 = runtime.session;
1127
+ const cost = session2?.costUsd;
1128
+ const runIncomplete = session2 !== void 0 && (session2.unreportedTokens > unreportedBefore || pendingChildTokens(session2) > pendingBefore || session2.costIncomplete && !incompleteBefore);
1041
1129
  output?.finish(outcome2, {
1042
1130
  totalCostUsd: cost ?? 0,
1131
+ ...cost === void 0 ? { totalCostUnknown: true } : {},
1132
+ ...session2 !== void 0 && isCostIncomplete(session2) ? { totalCostIncomplete: true } : {},
1043
1133
  runCostUsd: cost === void 0 ? void 0 : cost - costBefore,
1134
+ ...runIncomplete ? { runCostIncomplete: true } : {},
1044
1135
  contextWindow: runtime.limits.contextWindow,
1045
1136
  maxOutputTokens: resolved.maxTokens ?? DEFAULT_MAX_TOKENS,
1046
1137
  ...outcome2.kind === "done" ? { stopMessage: stopMessage(outcome2.result.stopReason, runtime.limits) } : {}
@@ -1057,7 +1148,7 @@ async function start(options, program) {
1057
1148
  if (resolved2.kind === "prompt") prompt = resolved2.prompt;
1058
1149
  }
1059
1150
  if (job !== void 0) {
1060
- const { testsBefore } = await import("../jobCommand-ACSGSBQ4.js");
1151
+ const { testsBefore } = await import("../jobCommand-2ODQLHB3.js");
1061
1152
  await testsBefore(job, runtime, renderer);
1062
1153
  }
1063
1154
  const outcome = await runTurnInTerminal(
@@ -1070,7 +1161,7 @@ async function start(options, program) {
1070
1161
  await runtime.close();
1071
1162
  finish(outcome);
1072
1163
  if (job !== void 0) {
1073
- const { finishJob } = await import("../jobCommand-ACSGSBQ4.js");
1164
+ const { finishJob } = await import("../jobCommand-2ODQLHB3.js");
1074
1165
  await finishJob(job, outcome, runtime, renderer, void 0, {
1075
1166
  fromLaunchd: options.fromLaunchd === true
1076
1167
  });
@@ -1083,7 +1174,7 @@ async function start(options, program) {
1083
1174
  const bannerInfo = {
1084
1175
  version: VERSION,
1085
1176
  model: modelId,
1086
- sandbox: runtime.executor.isolation === "none" ? "none: each command asks first" : `${runtime.executor.name} \xB7 no network`,
1177
+ sandbox: runtime.executor.isolation === "none" ? "none: each command asks first, unless a rule allows it" : `${runtime.executor.name} \xB7 no network`,
1087
1178
  root,
1088
1179
  extras: runtime.extras(),
1089
1180
  subagents: runtime.subagentsSummary(),
@@ -1156,7 +1247,7 @@ function wantsInk() {
1156
1247
  }
1157
1248
  async function loadInk(renderer) {
1158
1249
  try {
1159
- return await import("../inkChat-WEDGQMCY.js");
1250
+ return await import("../inkChat-WYYAFZXD.js");
1160
1251
  } catch (error) {
1161
1252
  renderer.info(`Plain chat (Ink is not available: ${error.message.split("\n")[0]}).`);
1162
1253
  return void 0;
@@ -1187,9 +1278,9 @@ function recordJobDenial(job, tool, target) {
1187
1278
  job.denied.push({ tool, target: shown });
1188
1279
  }
1189
1280
  async function jobBatchClient(job, resolved, renderer) {
1190
- const { DeadlineClient } = await import("../deadline-F5RJJ2QW.js");
1191
- const { nextTime } = await import("../launchd-SSX362VG.js");
1192
- const { DEFAULT_FINISH_BY, DEFAULT_STEP_LIMIT_MINUTES, SWITCH_BEFORE_MS } = await import("../create-VXIH2GUZ.js");
1281
+ const { DeadlineClient } = await import("../deadline-TP7ZGLT2.js");
1282
+ const { nextTime } = await import("../launchd-3A3ONEW5.js");
1283
+ const { DEFAULT_FINISH_BY, DEFAULT_STEP_LIMIT_MINUTES, SWITCH_BEFORE_MS } = await import("../create-W6BV75QX.js");
1193
1284
  const finishBy = job.job.finishBy ?? DEFAULT_FINISH_BY;
1194
1285
  const stepLimit = job.job.stepLimitMinutes ?? DEFAULT_STEP_LIMIT_MINUTES;
1195
1286
  const switchAt = new Date(nextTime(finishBy).getTime() - SWITCH_BEFORE_MS);
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ MCP_FILE,
4
+ SERVER_NAME,
5
+ checkServerUrl,
6
+ commandLine,
7
+ defHash,
8
+ expandEnv,
9
+ isHttp,
10
+ loadMcpConfig
11
+ } from "./chunk-QANRZW7W.js";
12
+ import "./chunk-ATW7BNIG.js";
13
+ export {
14
+ MCP_FILE,
15
+ SERVER_NAME,
16
+ checkServerUrl,
17
+ commandLine,
18
+ defHash,
19
+ expandEnv,
20
+ isHttp,
21
+ loadMcpConfig
22
+ };
23
+ //# sourceMappingURL=config-WV2H64TF.js.map
@@ -3,7 +3,7 @@ import {
3
3
  jobBase,
4
4
  linkCandidates,
5
5
  worktreeDir
6
- } from "./chunk-44QN5SWZ.js";
6
+ } from "./chunk-55CFEEIN.js";
7
7
  import {
8
8
  agentLabel,
9
9
  defaultAgentEnv,
@@ -12,18 +12,17 @@ import {
12
12
  nextTime,
13
13
  nightAgentTime,
14
14
  nightSpec
15
- } from "./chunk-USCUXCAU.js";
15
+ } from "./chunk-5B5HDTUR.js";
16
16
  import {
17
17
  jobPrompt
18
- } from "./chunk-YQTGMCU6.js";
19
- import "./chunk-OUCV3FCT.js";
18
+ } from "./chunk-3MRQJKUO.js";
19
+ import "./chunk-AOGFYUKG.js";
20
20
  import {
21
21
  JobGitError
22
- } from "./chunk-TUUEBHG2.js";
23
- import "./chunk-GXZACJUI.js";
24
- import "./chunk-WMOLXTBU.js";
25
- import "./chunk-3EQU2GUX.js";
26
- import "./chunk-HUIK3WXO.js";
22
+ } from "./chunk-6XHON3Q6.js";
23
+ import "./chunk-B4SJY7KT.js";
24
+ import "./chunk-BHZ6G65V.js";
25
+ import "./chunk-P6XWWIEK.js";
27
26
  import {
28
27
  DEFAULT_JOB_MAX_STEPS,
29
28
  JOBS_DIR,
@@ -32,7 +31,11 @@ import {
32
31
  planPermissions,
33
32
  planTitle,
34
33
  saveJob
35
- } from "./chunk-KKB5W47S.js";
34
+ } from "./chunk-VTMD5IHD.js";
35
+ import {
36
+ proposeWriteScope
37
+ } from "./chunk-UIRJOQQS.js";
38
+ import "./chunk-4LFJFDCF.js";
36
39
  import "./chunk-3NJNVZTK.js";
37
40
 
38
41
  // src/jobs/create.ts
@@ -62,6 +65,7 @@ async function createJob(options) {
62
65
  throw error;
63
66
  }
64
67
  const { rules, problems } = planPermissions(options.plan.plan);
68
+ const proposed = proposeWriteScope(rules, options.root);
65
69
  const id = newJobId(options.now);
66
70
  const links = linkCandidates(options.root);
67
71
  const job = {
@@ -77,6 +81,7 @@ async function createJob(options) {
77
81
  planSession: options.plan.sessionId,
78
82
  model: options.modelId,
79
83
  allow: rules,
84
+ ...proposed.scope === void 0 ? {} : { writeScope: proposed.scope },
80
85
  onUnapproved: "deny-and-continue",
81
86
  ...options.at === void 0 ? {} : { at: options.at },
82
87
  maxSteps: options.maxSteps ?? DEFAULT_JOB_MAX_STEPS,
@@ -98,6 +103,7 @@ async function createJob(options) {
98
103
  ...problems.length === 0 ? [] : ["", "Not rules, left out:", ...problems.map((p) => ` ${p}`)],
99
104
  "",
100
105
  "Any other call that would ask is denied at run time; the job goes on and reports it.",
106
+ proposed.scope === void 0 ? `Write scope: the whole worktree (${proposed.reason}). Commands may write anywhere in it.` : `Write scope: commands (also the test command) and edits may change only ${proposed.scope.length === 0 ? "nothing in the worktree" : proposed.scope.join(", ")} (plus temp folders, caches and the links). The OS sandbox enforces it for commands; no command runs outside the sandbox. A test that writes outside the scope fails.`,
101
107
  job.network === void 0 ? "Network: none for commands." : `Network: ${job.network.join(", ")}, through Garuda's proxy; other hosts are denied and reported.`,
102
108
  "",
103
109
  options.test === void 0 ? 'Proof of work: no test command found (set "test" in the job file); a principal-engineer review of the diff (one model call).' : `Proof of work: \`${options.test}\` runs in the sandbox before and after the job; a principal-engineer review of the diff (one model call).`,
@@ -144,7 +150,7 @@ async function createJob(options) {
144
150
  await saveJob(job);
145
151
  const lines = [
146
152
  `Created job ${id}: ${jobPath(options.root, id)}`,
147
- 'You can edit its approval list ("allow") in that file before the run.'
153
+ 'You can edit its approval list ("allow") and its write scope ("writeScope") in that file before the run.'
148
154
  ];
149
155
  const platform = options.launchd?.platform ?? process.platform;
150
156
  if (options.launchd !== void 0 && options.at !== void 0 && platform === "darwin") {
@@ -221,4 +227,4 @@ export {
221
227
  createJob,
222
228
  switchTime
223
229
  };
224
- //# sourceMappingURL=create-VXIH2GUZ.js.map
230
+ //# sourceMappingURL=create-W6BV75QX.js.map
@@ -41,7 +41,8 @@ var DeadlineClient = class {
41
41
  try {
42
42
  const events = [];
43
43
  for await (const event of this.primary.stream(request, {
44
- signal: AbortSignal.any(signals)
44
+ signal: AbortSignal.any(signals),
45
+ ...options?.meter === void 0 ? {} : { meter: options.meter }
45
46
  })) {
46
47
  events.push(event);
47
48
  }
@@ -49,6 +50,7 @@ var DeadlineClient = class {
49
50
  yield* events;
50
51
  } catch (error) {
51
52
  if (options?.signal?.aborted === true || !timer.signal.aborted) throw error;
53
+ options?.meter?.retry();
52
54
  if (stepOnly) {
53
55
  this.calls.slow++;
54
56
  this.fallbackClient ??= await this.fallback();
@@ -83,4 +85,4 @@ export {
83
85
  DeadlineReached,
84
86
  StepTooSlow
85
87
  };
86
- //# sourceMappingURL=deadline-F5RJJ2QW.js.map
88
+ //# sourceMappingURL=deadline-TP7ZGLT2.js.map