@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
@@ -3,6 +3,7 @@ import {
3
3
  colorDiff
4
4
  } from "./chunk-4JSUUDFQ.js";
5
5
  import {
6
+ AuditDirError,
6
7
  SPECIALIST_SPECS,
7
8
  THINKING_WORDS,
8
9
  callersText,
@@ -16,12 +17,17 @@ import {
16
17
  referencesText,
17
18
  repoMapText,
18
19
  repoMapTool,
19
- verifyAuditFile
20
- } from "./chunk-TILFPYWO.js";
20
+ verifyAuditDir
21
+ } from "./chunk-NHWHG3SW.js";
22
+ import {
23
+ budgetSpent,
24
+ isCostIncomplete,
25
+ pendingChildTokens
26
+ } from "./chunk-UKIE4AAM.js";
21
27
  import {
22
28
  WEB_SEARCH_USD,
23
29
  totalTokens
24
- } from "./chunk-R7I2NBPX.js";
30
+ } from "./chunk-7KBOIPUT.js";
25
31
  import {
26
32
  BUILTIN_COMMANDS
27
33
  } from "./chunk-23FXBNBB.js";
@@ -30,7 +36,7 @@ import {
30
36
  } from "./chunk-EU7PA45O.js";
31
37
  import {
32
38
  listJobs
33
- } from "./chunk-KKB5W47S.js";
39
+ } from "./chunk-VTMD5IHD.js";
34
40
 
35
41
  // src/cli/errors.ts
36
42
  function describeError(error) {
@@ -76,20 +82,32 @@ function formatTokens(n) {
76
82
  if (n < 1e6) return `${(n / 1e3).toFixed(1)}k`;
77
83
  return `${(n / 1e6).toFixed(1)}M`;
78
84
  }
79
- function formatUsd(usd) {
85
+ function formatUsd(usd, incomplete = false) {
80
86
  if (usd === void 0) return "cost unknown";
81
- return usd < 0.01 ? `$${usd.toFixed(4)}` : `$${usd.toFixed(2)}`;
87
+ const amount = usd < 0.01 ? `$${usd.toFixed(4)}` : `$${usd.toFixed(2)}`;
88
+ return incomplete ? `\u2265 ${amount} (incomplete)` : amount;
89
+ }
90
+ function budgetNote(session) {
91
+ const unreported = session.unreportedTokens;
92
+ const children = pendingChildTokens(session);
93
+ if (unreported <= 0 && children <= 0) return void 0;
94
+ const parts = [
95
+ ...unreported > 0 ? [`${formatTokens(unreported)} reserved without reported usage`] : [],
96
+ ...children > 0 ? [`${formatTokens(children)} from subagents with no report`] : []
97
+ ];
98
+ return `budget ${formatTokens(budgetSpent(session))} tokens (${parts.join(", ")})`;
82
99
  }
83
- function usageLine(result, session, runCostUsd, contextWindow) {
100
+ function usageLine(result, session, runCostUsd, contextWindow, runCostIncomplete = false) {
84
101
  const u = result.usage;
85
102
  const input = u.inputTokens + u.cacheReadTokens + u.cacheWriteTokens;
86
103
  const percent = Math.round(session.contextTokens / contextWindow * 100);
87
104
  return [
88
105
  `${result.stopReason} \xB7 ${result.steps} step(s)`,
89
- `${formatTokens(input)} in (${formatTokens(u.cacheReadTokens)} cached) / ${formatTokens(u.outputTokens)} out`,
90
- formatUsd(runCostUsd),
106
+ `${budgetNote(session) !== void 0 ? "reported " : ""}${formatTokens(input)} in (${formatTokens(u.cacheReadTokens)} cached) / ${formatTokens(u.outputTokens)} out`,
107
+ formatUsd(runCostUsd, runCostIncomplete),
91
108
  `context ${percent}% of ${formatTokens(contextWindow)}`,
92
- `session ${formatTokens(totalTokens(session.usage))} tokens, ${formatUsd(session.costUsd)}`
109
+ `session ${formatTokens(totalTokens(session.usage))} tokens, ${formatUsd(session.costUsd, isCostIncomplete(session))}`,
110
+ ...budgetNote(session) === void 0 ? [] : [budgetNote(session)]
93
111
  ].join(" \xB7 ");
94
112
  }
95
113
  function stopMessage(reason, limits) {
@@ -131,13 +149,19 @@ async function runTurn(runtime, approver, renderer, prompt, exitNow) {
131
149
  process.on("SIGINT", stop);
132
150
  approver.onInterrupt = stop;
133
151
  const costBefore = runtime.session?.costUsd ?? 0;
152
+ const unreportedBefore = runtime.session?.unreportedTokens ?? 0;
153
+ const incompleteBefore = runtime.session?.costIncomplete ?? false;
154
+ const pendingBefore = runtime.session === void 0 ? 0 : pendingChildTokens(runtime.session);
134
155
  try {
135
156
  const result = await runtime.runTurn(prompt, controller.signal);
136
157
  const session = runtime.session;
137
158
  if (session !== void 0) {
138
159
  const runCost = session.costUsd === void 0 ? void 0 : session.costUsd - costBefore;
139
- renderer.info(`
140
- [${usageLine(result, session, runCost, runtime.limits.contextWindow)}]`);
160
+ const runIncomplete = session.unreportedTokens > unreportedBefore || pendingChildTokens(session) > pendingBefore || session.costIncomplete && !incompleteBefore;
161
+ renderer.info(
162
+ `
163
+ [${usageLine(result, session, runCost, runtime.limits.contextWindow, runIncomplete)}]`
164
+ );
141
165
  }
142
166
  const message = stopMessage(result.stopReason, runtime.limits);
143
167
  if (message !== void 0) renderer.warn(message);
@@ -200,7 +224,7 @@ var HELP = [
200
224
  " /jobs the scheduled jobs of this project; /jobs <id> shows one; /jobs cancel|delete <id>; /jobs cancel night",
201
225
  " /where X where symbol X is defined (code index, no model call)",
202
226
  " /defs X alias of /where X (definitions of X)",
203
- " /refs X every use of symbol X (code index, no model call)",
227
+ " /refs X indexed uses of symbol X (approximate except JS/TS, no model call)",
204
228
  " /callers X who calls symbol X (code index, no model call)",
205
229
  " /impact X blast radius and affected tests for file or symbol X",
206
230
  " /map [dir] what each code file exports and imports",
@@ -388,7 +412,7 @@ async function sessionsCommand(runtime, renderer, arg, signal) {
388
412
  const facts = [
389
413
  s.id,
390
414
  `${s.turns} turn${s.turns === 1 ? "" : "s"}`,
391
- ...s.costUsd === void 0 || s.costUsd === 0 ? [] : [`$${s.costUsd.toFixed(2)}`],
415
+ ...s.costUsd === void 0 || s.costUsd === 0 && !s.costIncomplete ? [] : [`${s.costIncomplete ? "\u2265 " : ""}$${s.costUsd.toFixed(2)}`],
392
416
  ...s.model === void 0 ? [] : [s.model]
393
417
  ].join(" \xB7 ");
394
418
  return [
@@ -467,7 +491,7 @@ async function diffCommand(runtime, renderer, arg, output) {
467
491
  );
468
492
  }
469
493
  async function jobsCommand(runtime, renderer, id) {
470
- const { listJobs: listJobs2, loadJob, JOBS_DIR } = await import("./job-3NYDMP2M.js");
494
+ const { listJobs: listJobs2, loadJob, JOBS_DIR } = await import("./job-7JOI4YIQ.js");
471
495
  const cancel = /^cancel\s+(\S+)$/.exec(id);
472
496
  if (cancel !== null) {
473
497
  renderer.info(await runtime.cancelJob(cancel[1]));
@@ -481,7 +505,7 @@ async function jobsCommand(runtime, renderer, id) {
481
505
  if (id !== "") {
482
506
  try {
483
507
  const job = await loadJob(runtime.root, id);
484
- const { jobReport } = await import("./text-J2GD647J.js");
508
+ const { jobReport } = await import("./text-LS35WSRL.js");
485
509
  renderer.info(jobReport(job));
486
510
  } catch (error) {
487
511
  renderer.warn(error.message);
@@ -489,7 +513,7 @@ async function jobsCommand(runtime, renderer, id) {
489
513
  return;
490
514
  }
491
515
  const jobs = await listJobs2(runtime.root);
492
- const { defaultAgentEnv, nightAgentTime } = await import("./launchd-SSX362VG.js");
516
+ const { defaultAgentEnv, nightAgentTime } = await import("./launchd-3A3ONEW5.js");
493
517
  const night = nightAgentTime(runtime.root, defaultAgentEnv());
494
518
  const nightLine = night === void 0 ? [] : [
495
519
  `Night shift: launchd starts the queue at ${night.toTimeString().slice(0, 5)} on ${night.toDateString()} (/jobs cancel night removes it).`
@@ -527,7 +551,7 @@ async function exportCommand(runtime, renderer, file) {
527
551
  renderer.info("There is no conversation to export yet.");
528
552
  return;
529
553
  }
530
- const { sessionMarkdown, writeExport } = await import("./export-HN3CT7AV.js");
554
+ const { sessionMarkdown, writeExport } = await import("./export-SJ3DUP6W.js");
531
555
  const result = await writeExport(runtime.root, id, sessionMarkdown(records, id), file);
532
556
  if ("problem" in result) renderer.warn(result.problem);
533
557
  else
@@ -628,7 +652,7 @@ async function lookup(runtime, renderer, command, arg) {
628
652
  } else {
629
653
  text = repoMapText(await repoMapTool.run({ path: arg }, context));
630
654
  }
631
- renderer.info(text);
655
+ renderer.info(text.startsWith("Approximate:") ? `\u2248 ${text}` : text);
632
656
  } catch (error) {
633
657
  renderer.error(error.message);
634
658
  }
@@ -706,22 +730,46 @@ async function auditCommand(runtime, renderer, arg) {
706
730
  }
707
731
  }
708
732
  if (arg === "verify") {
709
- const files = await runtime.audit.files();
710
733
  lines.push("", `Audit files: ${runtime.audit.dir}`);
711
- if (files.length === 0) lines.push(" none yet");
734
+ let results;
735
+ try {
736
+ results = await verifyAuditDir(runtime.audit.dir);
737
+ } catch (error) {
738
+ if (!(error instanceof AuditDirError)) throw error;
739
+ lines.push(` BROKEN the audit folder: ${error.message}`);
740
+ renderer.info(lines.join("\n"));
741
+ return;
742
+ }
743
+ if (results.length === 0) lines.push(" none yet");
712
744
  let broken = 0;
713
- for (const file of files) {
714
- const result = await verifyAuditFile(file);
715
- const name = file.slice(runtime.audit.dir.length + 1);
716
- if (result.ok) {
717
- lines.push(` ok ${name} (${result.lines} lines)`);
745
+ let unchecked = 0;
746
+ for (const result of results) {
747
+ if ("missing" in result) {
748
+ broken++;
749
+ lines.push(` MISSING ${result.file}: the checkpoint names it, but the file is gone`);
750
+ } else if ("brokenCheckpoint" in result) {
751
+ broken++;
752
+ lines.push(` BROKEN ${result.file}: its checkpoint: ${result.brokenCheckpoint}`);
753
+ } else if (result.verdict.ok) {
754
+ if (!result.checkpoint) unchecked++;
755
+ lines.push(
756
+ ` ok ${result.file} (${result.verdict.lines} lines${result.checkpoint ? ", checkpoint" : ""})`
757
+ );
718
758
  } else {
719
759
  broken++;
720
- lines.push(` BROKEN ${name}: line ${result.line}: ${result.why}`);
760
+ lines.push(` BROKEN ${result.file}: line ${result.verdict.line}: ${result.verdict.why}`);
721
761
  }
722
762
  }
723
- if (broken > 0) lines.push(`${broken} file(s) were changed after Garuda wrote them.`);
724
- lines.push("This check cannot see lines cut from the end of a file, or a removed file.");
763
+ if (broken > 0)
764
+ lines.push(`${broken} file(s) were changed or removed after Garuda wrote them.`);
765
+ if (unchecked > 0) {
766
+ lines.push(
767
+ `${unchecked} file(s) have no checkpoint: this check cannot see lines cut from their end, or a removed file. The team policy can turn on "audit": { "checkpoint": true }.`
768
+ );
769
+ }
770
+ lines.push(
771
+ "Someone with your rights can rewrite a file and its checkpoint together; this check cannot see that."
772
+ );
725
773
  renderer.info(lines.join("\n"));
726
774
  return;
727
775
  }
@@ -767,11 +815,12 @@ function usageSummary(runtime) {
767
815
  const session = runtime.session;
768
816
  if (session === void 0) return "No session yet.";
769
817
  const u = session.usage;
770
- const cost = session.costUsd === void 0 ? "cost unknown" : `$${session.costUsd.toFixed(4)}`;
818
+ const cost = session.costUsd === void 0 ? "cost unknown" : isCostIncomplete(session) ? `\u2265 $${session.costUsd.toFixed(4)} (incomplete)` : `$${session.costUsd.toFixed(4)}`;
771
819
  return [
772
- `Session ${session.id}: ${formatTokens(totalTokens(u))} tokens, ${cost}`,
820
+ `Session ${session.id}: ${formatTokens(totalTokens(u))}${budgetNote(session) !== void 0 ? " reported" : ""} tokens, ${cost}`,
773
821
  ` input ${formatTokens(u.inputTokens)}, cache read ${formatTokens(u.cacheReadTokens)}, cache write ${formatTokens(u.cacheWriteTokens)}, output ${formatTokens(u.outputTokens)}`,
774
822
  ` context ${formatTokens(session.contextTokens)} of ${formatTokens(runtime.limits.contextWindow)}`,
823
+ ...budgetNote(session) === void 0 ? [] : [` ${budgetNote(session)}`],
775
824
  ...u.webSearches === void 0 ? [] : [
776
825
  ` Claude web searches: ${u.webSearches} ($${(u.webSearches * WEB_SEARCH_USD).toFixed(2)})`
777
826
  ]
@@ -1244,4 +1293,4 @@ export {
1244
1293
  statusOf,
1245
1294
  CommandArgs
1246
1295
  };
1247
- //# sourceMappingURL=chunk-BQTUOO4G.js.map
1296
+ //# sourceMappingURL=chunk-OQ26W5L4.js.map
@@ -22,7 +22,9 @@ function ignoredProjectPolicy(root) {
22
22
  const file = join(root, POLICY_FILE);
23
23
  return existsSync(file) ? file : void 0;
24
24
  }
25
+ var PROFILES = ["default", "strict"];
25
26
  var policySchema = z.strictObject({
27
+ profile: z.enum(PROFILES).optional(),
26
28
  disallowedCommands: z.array(z.string()).optional(),
27
29
  requireSandbox: z.boolean().optional(),
28
30
  denyPaths: z.array(z.string()).optional(),
@@ -37,7 +39,8 @@ var policySchema = z.strictObject({
37
39
  }).optional(),
38
40
  audit: z.strictObject({
39
41
  enabled: z.boolean().optional(),
40
- level: z.enum(["all", "mutations", "denials"]).optional()
42
+ level: z.enum(["all", "mutations", "denials"]).optional(),
43
+ checkpoint: z.boolean().optional()
41
44
  }).optional()
42
45
  });
43
46
  function parsePolicy(json) {
@@ -47,6 +50,7 @@ function parsePolicy(json) {
47
50
  }
48
51
  const data = result.data;
49
52
  return {
53
+ ...data.profile === void 0 ? {} : { profile: data.profile },
50
54
  ...data.disallowedCommands === void 0 ? {} : { disallowedCommands: data.disallowedCommands },
51
55
  ...data.requireSandbox === void 0 ? {} : { requireSandbox: data.requireSandbox },
52
56
  ...data.denyPaths === void 0 ? {} : { denyPaths: data.denyPaths },
@@ -66,7 +70,8 @@ function parsePolicy(json) {
66
70
  ...data.audit === void 0 ? {} : {
67
71
  audit: {
68
72
  ...data.audit.enabled === void 0 ? {} : { enabled: data.audit.enabled },
69
- ...data.audit.level === void 0 ? {} : { level: data.audit.level }
73
+ ...data.audit.level === void 0 ? {} : { level: data.audit.level },
74
+ ...data.audit.checkpoint === void 0 ? {} : { checkpoint: data.audit.checkpoint }
70
75
  }
71
76
  }
72
77
  };
@@ -106,7 +111,9 @@ function mergePolicies(user, managed) {
106
111
  const maxSteps = lower(user.limits?.maxSteps, managed.limits?.maxSteps);
107
112
  const tokenBudget = lower(user.limits?.tokenBudget, managed.limits?.tokenBudget);
108
113
  const audit = managed.audit ?? user.audit;
114
+ const profile = user.profile === void 0 && managed.profile === void 0 ? void 0 : user.profile === "strict" || managed.profile === "strict" ? "strict" : "default";
109
115
  return {
116
+ ...profile === void 0 ? {} : { profile },
110
117
  ...disallowedCommands === void 0 ? {} : { disallowedCommands },
111
118
  ...requireSandbox === void 0 ? {} : { requireSandbox },
112
119
  ...denyPaths === void 0 ? {} : { denyPaths },
@@ -156,6 +163,13 @@ function isCommandDisallowedByPolicy(policy, command) {
156
163
  }
157
164
  return { disallowed: false };
158
165
  }
166
+ function isStrict(policy) {
167
+ return policy?.profile === "strict";
168
+ }
169
+ function withProfile(policy, projectProfile) {
170
+ if (!isStrict(policy) && projectProfile !== "strict") return policy;
171
+ return { ...policy, profile: "strict", requireSandbox: true };
172
+ }
159
173
  function isSandboxRequiredByPolicy(policy, outsideSandbox) {
160
174
  if (policy.requireSandbox === true && outsideSandbox) {
161
175
  return {
@@ -221,14 +235,17 @@ export {
221
235
  POLICY_FILE,
222
236
  managedPolicyPath,
223
237
  ignoredProjectPolicy,
238
+ PROFILES,
224
239
  parsePolicy,
225
240
  mergePolicies,
226
241
  loadTeamPolicy,
227
242
  isCommandDisallowedByPolicy,
243
+ isStrict,
244
+ withProfile,
228
245
  isSandboxRequiredByPolicy,
229
246
  isPathDeniedByPolicy,
230
247
  isModelAllowedByPolicy,
231
248
  assertModelAllowedByPolicy,
232
249
  isHostBlockedByPolicy
233
250
  };
234
- //# sourceMappingURL=chunk-HUIK3WXO.js.map
251
+ //# sourceMappingURL=chunk-P6XWWIEK.js.map