@garuda-agent/garuda 0.17.0 → 0.18.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.
Files changed (64) hide show
  1. package/CHANGELOG.md +243 -0
  2. package/README.md +3 -2
  3. package/SECURITY.md +1 -1
  4. package/dist/{acpCommand-7EY3NHPG.js → acpCommand-JAYNMIMP.js} +19 -16
  5. package/dist/advise-HDKJGNBL.js +195 -0
  6. package/dist/brief-RWKESOPT.js +91 -0
  7. package/dist/buildCheck-HB46NWLX.js +19 -0
  8. package/dist/buildInfo-K73FFI5S.js +8 -0
  9. package/dist/chunk-2OYTNNUJ.js +216 -0
  10. package/dist/{chunk-Z66BWTMD.js → chunk-34WBDQBL.js} +135 -78
  11. package/dist/chunk-4QRTTRVK.js +88 -0
  12. package/dist/{chunk-2DYMJMRQ.js → chunk-5UDYQ5MK.js} +405 -70
  13. package/dist/{chunk-J4346IDH.js → chunk-7KBOIPUT.js} +2 -1
  14. package/dist/chunk-CWVXOSAA.js +894 -0
  15. package/dist/{chunk-FARS4R67.js → chunk-DQSCCE77.js} +18 -1
  16. package/dist/chunk-DUYLVGPY.js +821 -0
  17. package/dist/chunk-GKU62MHQ.js +5258 -0
  18. package/dist/chunk-H7LIBGZT.js +9 -0
  19. package/dist/chunk-IKPGHM54.js +334 -0
  20. package/dist/chunk-IYGJWX65.js +9 -0
  21. package/dist/{chunk-U65DQZDB.js → chunk-JMH5W5DG.js} +2 -45
  22. package/dist/chunk-L55VUSX3.js +54 -0
  23. package/dist/{chunk-B4SJY7KT.js → chunk-LMKGSYJC.js} +77 -8
  24. package/dist/{chunk-23FXBNBB.js → chunk-MNE7HHX2.js} +2 -1
  25. package/dist/chunk-NH72AELP.js +48 -0
  26. package/dist/{chunk-735BKABA.js → chunk-NLS7GMF7.js} +12 -106
  27. package/dist/{chunk-ZAE25JM2.js → chunk-QANRZW7W.js} +8 -1
  28. package/dist/{chunk-JRVWH27M.js → chunk-QLBCM2YQ.js} +7 -3
  29. package/dist/{chunk-6XHON3Q6.js → chunk-QXTHEFKP.js} +3 -3
  30. package/dist/{chunk-TJIWD7R7.js → chunk-R7RCW4BQ.js} +10 -8
  31. package/dist/chunk-TLA2PDGM.js +156 -0
  32. package/dist/{chunk-5B5HDTUR.js → chunk-TWQ7V2L6.js} +2 -2
  33. package/dist/chunk-ULAJPMY7.js +107 -0
  34. package/dist/chunk-VISKX36R.js +306 -0
  35. package/dist/{chunk-55CFEEIN.js → chunk-WK5NE6RY.js} +2 -2
  36. package/dist/chunk-Y62J7PTD.js +90 -0
  37. package/dist/chunk-YAQ6QLKB.js +40 -0
  38. package/dist/{chunk-7TH3NHCQ.js → chunk-ZKT4P2PC.js} +2 -2
  39. package/dist/cli/index.js +289 -65
  40. package/dist/config-WV2H64TF.js +23 -0
  41. package/dist/{create-W6BV75QX.js → create-OACSGJ37.js} +5 -5
  42. package/dist/evalCommand-BLJJ4G76.js +696 -0
  43. package/dist/evalTune-W53KAD4V.js +302 -0
  44. package/dist/{export-SJ3DUP6W.js → export-E677HIQS.js} +27 -4
  45. package/dist/exportHtml-BMV73YRO.js +21 -0
  46. package/dist/{inkChat-FNUBK43U.js → inkChat-EVLYDC3K.js} +263 -47
  47. package/dist/{install-TKWN5AYH.js → install-4ST5BNRG.js} +3 -3
  48. package/dist/{jobCommand-FE6XN3YD.js → jobCommand-ILOTYOX3.js} +9 -8
  49. package/dist/{launchd-3A3ONEW5.js → launchd-QG6R5RAK.js} +4 -4
  50. package/dist/{lspCommand-ZZ6R4PA2.js → lspCommand-X4FTTONR.js} +3 -3
  51. package/dist/{manager-73MPYFTP.js → manager-L25IUXHW.js} +11 -11
  52. package/dist/{nightCommand-OODJNWDT.js → nightCommand-XPWT6CQZ.js} +9 -8
  53. package/dist/receiptView-YFDHV253.js +19 -0
  54. package/dist/{remove-42WQNVPX.js → remove-STX5UO7X.js} +3 -3
  55. package/dist/{run-ML6GSPN4.js → run-W4TK52WT.js} +6 -6
  56. package/dist/{server-VEYIJHEU.js → server-ASM73QVY.js} +3 -3
  57. package/dist/{setupCommand-GBQIVYJC.js → setupCommand-OSOMFHDQ.js} +10 -9
  58. package/dist/tour-CEVMAC5S.js +18 -0
  59. package/dist/tune-VX2WQTHS.js +52 -0
  60. package/dist/uiState-YFJQ43D7.js +16 -0
  61. package/package.json +1 -1
  62. package/dist/chunk-4JSUUDFQ.js +0 -118
  63. package/dist/chunk-BSK5T2ZG.js +0 -9
  64. package/dist/evalCommand-YVQAWUZE.js +0 -2833
@@ -0,0 +1,302 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ PROPOSER_SYSTEM,
4
+ parseProposal,
5
+ readAddendum,
6
+ tune
7
+ } from "./chunk-IKPGHM54.js";
8
+ import {
9
+ EVAL_SUITES,
10
+ HELD_OUT_TASKS,
11
+ requiredToolchains
12
+ } from "./chunk-GKU62MHQ.js";
13
+ import {
14
+ formatReport,
15
+ reportV2,
16
+ runEvals
17
+ } from "./chunk-DUYLVGPY.js";
18
+ import {
19
+ DEFAULT_SEED,
20
+ TOOLCHAINS,
21
+ checkToolchains,
22
+ shuffled
23
+ } from "./chunk-CWVXOSAA.js";
24
+ import "./chunk-H7LIBGZT.js";
25
+ import "./chunk-YAQ6QLKB.js";
26
+ import "./chunk-NXJ4XLB5.js";
27
+ import "./chunk-5UDYQ5MK.js";
28
+ import "./chunk-G2AX7MGS.js";
29
+ import "./chunk-ULAJPMY7.js";
30
+ import "./chunk-JMH5W5DG.js";
31
+ import {
32
+ NO_MODEL,
33
+ chooseModel,
34
+ keepProviderKeys,
35
+ loadModelsConfig,
36
+ resolveModel
37
+ } from "./chunk-QLBCM2YQ.js";
38
+ import "./chunk-NH72AELP.js";
39
+ import "./chunk-4QRTTRVK.js";
40
+ import "./chunk-A2QAIRQL.js";
41
+ import {
42
+ newSessionId
43
+ } from "./chunk-NLS7GMF7.js";
44
+ import {
45
+ costOf
46
+ } from "./chunk-7KBOIPUT.js";
47
+ import "./chunk-B25VL4RU.js";
48
+ import "./chunk-MNE7HHX2.js";
49
+ import "./chunk-IYGJWX65.js";
50
+ import "./chunk-5DEWP3YX.js";
51
+ import "./chunk-PZS3V6P3.js";
52
+ import "./chunk-QANRZW7W.js";
53
+ import "./chunk-ATW7BNIG.js";
54
+ import "./chunk-WK5NE6RY.js";
55
+ import "./chunk-AOGFYUKG.js";
56
+ import "./chunk-QXTHEFKP.js";
57
+ import {
58
+ createExecutor
59
+ } from "./chunk-LMKGSYJC.js";
60
+ import "./chunk-BHZ6G65V.js";
61
+ import "./chunk-P6XWWIEK.js";
62
+ import "./chunk-UIRJOQQS.js";
63
+ import "./chunk-4LFJFDCF.js";
64
+ import "./chunk-3NJNVZTK.js";
65
+
66
+ // src/cli/evalTune.ts
67
+ import { mkdirSync, writeFileSync } from "fs";
68
+ import { writeFile } from "fs/promises";
69
+ import { join } from "path";
70
+ import { createInterface } from "readline/promises";
71
+ var DEFAULT_TUNE_PARALLEL = 4;
72
+ function progressLine(label, done, total, r) {
73
+ return `[${label} ${done}/${total}] ${r.passed ? "\u2713" : "\u2717"} ${r.id} (${r.steps} steps)${r.passed ? "" : `: ${(r.reason ?? r.stopReason).split("\n")[0]}`}`;
74
+ }
75
+ var DEFAULT_PROPOSER = "claude-opus-5-5";
76
+ var DEFAULT_TUNE_SUITES = ["basic", "hard", "medium"];
77
+ var whole = (value, fallback, min) => {
78
+ const v = value ?? fallback;
79
+ return Number.isInteger(v) && v >= min ? v : void 0;
80
+ };
81
+ async function askProposer(proposer, input) {
82
+ const client = await proposer.create();
83
+ let response;
84
+ for await (const event of client.stream({
85
+ system: PROPOSER_SYSTEM,
86
+ messages: [{ role: "user", content: [{ type: "text", text: input }] }],
87
+ tools: [],
88
+ maxTokens: 8e3
89
+ })) {
90
+ if (event.type === "response") response = event.response;
91
+ }
92
+ if (response === void 0) return "the proposer gave no answer";
93
+ const text = response.content.filter((b) => b.type === "text").map((b) => b.text).join("");
94
+ const parsed = parseProposal(text);
95
+ if (parsed === void 0) return "the proposer's answer has no <addendum> block";
96
+ const price = proposer.info.price;
97
+ return {
98
+ ...parsed,
99
+ costUsd: price === void 0 ? void 0 : costOf(response.usage, price, response.priceFactor ?? 1)
100
+ };
101
+ }
102
+ async function runEvalTune(options) {
103
+ const rounds = whole(options.rounds, 5, 1);
104
+ const repeat = whole(options.repeat, 3, 1);
105
+ const heldoutRepeat = whole(options.heldoutRepeat, 5, 1);
106
+ const margin = whole(options.margin, 2, 1);
107
+ const seed = whole(options.seed, DEFAULT_SEED, 0);
108
+ const parallel = whole(options.parallel, DEFAULT_TUNE_PARALLEL, 1);
109
+ const maxCost = options.maxCost ?? 20;
110
+ if (rounds === void 0 || repeat === void 0 || heldoutRepeat === void 0 || margin === void 0 || seed === void 0 || parallel === void 0 || !(maxCost > 0)) {
111
+ process.stderr.write(
112
+ "--rounds, --repeat, --heldout-repeat, --margin and --parallel must be whole numbers of 1 or more, --seed 0 or more, and --max-cost above 0.\n"
113
+ );
114
+ return 1;
115
+ }
116
+ const suites = options.suite ?? [...DEFAULT_TUNE_SUITES];
117
+ const devTasks = [];
118
+ for (const name of suites) {
119
+ const tasks = EVAL_SUITES[name];
120
+ if (tasks === void 0) {
121
+ process.stderr.write(`Unknown suite ${name}. Use: ${Object.keys(EVAL_SUITES).join(", ")}.
122
+ `);
123
+ return 1;
124
+ }
125
+ devTasks.push(...tasks);
126
+ }
127
+ const start = await readAddendum(options.addendum, true);
128
+ if ("problem" in start) {
129
+ process.stderr.write(`${start.problem}
130
+ `);
131
+ return 1;
132
+ }
133
+ const models = await loadModelsConfig();
134
+ if (models.problem !== void 0) {
135
+ process.stderr.write(`${models.problem}
136
+ `);
137
+ return 1;
138
+ }
139
+ const modelId = chooseModel(models.config, options.model);
140
+ if (!modelId) {
141
+ process.stderr.write(`${NO_MODEL}
142
+ `);
143
+ return 1;
144
+ }
145
+ let agent;
146
+ let proposer;
147
+ try {
148
+ agent = resolveModel(modelId, models.config);
149
+ proposer = resolveModel(options.proposer ?? DEFAULT_PROPOSER, models.config);
150
+ } catch (error) {
151
+ process.stderr.write(`${error.message}
152
+ `);
153
+ return 1;
154
+ }
155
+ const { assertModelAllowedByPolicy, loadTeamPolicy } = await import("./policy-ZJ7RMOFN.js");
156
+ let team;
157
+ try {
158
+ team = await loadTeamPolicy();
159
+ assertModelAllowedByPolicy(team?.policy, agent.spec);
160
+ assertModelAllowedByPolicy(team?.policy, proposer.spec);
161
+ } catch (error) {
162
+ process.stderr.write(`Team policy: ${error.message}
163
+ `);
164
+ return 1;
165
+ }
166
+ const warning = await keepProviderKeys([agent.def.apiKeyEnv, proposer.def.apiKeyEnv]);
167
+ if (warning !== void 0) process.stderr.write(`${warning}
168
+ `);
169
+ const missing = (await checkToolchains(requiredToolchains([...devTasks, ...HELD_OUT_TASKS]))).filter((s) => !s.ok);
170
+ if (missing.length > 0) {
171
+ for (const status of missing) process.stderr.write(`${TOOLCHAINS[status.id].hint}
172
+ `);
173
+ return 1;
174
+ }
175
+ const perScore = devTasks.length * repeat;
176
+ const heldOutRuns = 2 * HELD_OUT_TASKS.length * heldoutRepeat;
177
+ process.stderr.write(
178
+ [
179
+ `Tuning ${options.addendum} (${start.text.length} characters) with ${agent.spec}; ${proposer.spec} proposes.`,
180
+ `Dev: ${devTasks.length} task(s) from ${suites.join(", ")} \xD7 ${repeat} = ${perScore} runs a score, ${parallel} at a time; up to ${rounds + 1} scores.`,
181
+ `Held-out: ${HELD_OUT_TASKS.length} task(s) \xD7 ${heldoutRepeat}, twice, at the end (${heldOutRuns} runs), if a version is kept.`,
182
+ `Keep rule: +${margin} passing runs, or as many with a lower cost per accepted change (interval below \xD71.0).`,
183
+ `Budget: --max-cost $${maxCost}; the loop stops before a round that would pass it.`,
184
+ `Garuda changes no file outside the run's folder; ${options.addendum} stays as it is.`,
185
+ ""
186
+ ].join("\n")
187
+ );
188
+ if (options.yes !== true) {
189
+ if (!process.stdin.isTTY) {
190
+ process.stderr.write("Add --yes to start without a question.\n");
191
+ return 1;
192
+ }
193
+ const rl = createInterface({ input: process.stdin, output: process.stderr });
194
+ const answer = await rl.question("Start? (y/N) ");
195
+ rl.close();
196
+ if (!/^y(es)?$/i.test(answer.trim())) return 1;
197
+ }
198
+ const { executor, notice } = createExecutor("auto");
199
+ if (notice !== void 0) process.stderr.write(`${notice}
200
+ `);
201
+ const dir = join(process.cwd(), ".garuda", "evals", `tune-${newSessionId()}`);
202
+ mkdirSync(dir, { recursive: true });
203
+ const score = async (addendum, tasks, k, label) => {
204
+ const listed = tasks.flatMap((t) => Array.from({ length: k }, () => t));
205
+ const outDir = join(dir, label);
206
+ let done = 0;
207
+ const results = await runEvals(
208
+ shuffled(listed, seed),
209
+ {
210
+ parallel,
211
+ modelId: agent.spec,
212
+ model: () => agent.create(),
213
+ modelInfo: agent.info,
214
+ ...agent.maxTokens === void 0 ? {} : { maxTokens: agent.maxTokens },
215
+ ...team === void 0 ? {} : { policy: team.policy },
216
+ outDir,
217
+ executor: executor.name === "host" ? "host" : "os",
218
+ ...addendum === "" ? {} : { addendum }
219
+ },
220
+ (r) => {
221
+ done++;
222
+ process.stderr.write(`${progressLine(label, done, listed.length, r)}
223
+ `);
224
+ }
225
+ );
226
+ writeFileSync(
227
+ join(outDir, "report.json"),
228
+ `${JSON.stringify(
229
+ {
230
+ ...await reportV2(
231
+ {
232
+ model: agent.spec,
233
+ provider: agent.provider,
234
+ executor: executor.name,
235
+ isolation: executor.isolation,
236
+ seed,
237
+ shuffle: true,
238
+ split: label.startsWith("heldout") ? "heldout" : "dev",
239
+ ...addendum === "" ? {} : { addendum: { file: `${label}.md`, text: addendum } }
240
+ },
241
+ tasks,
242
+ results
243
+ ),
244
+ results
245
+ },
246
+ null,
247
+ 2
248
+ )}
249
+ `
250
+ );
251
+ process.stderr.write(`
252
+ ${label}:
253
+ ${formatReport(results, { seed })}
254
+
255
+ `);
256
+ return results;
257
+ };
258
+ const result = await tune({
259
+ start: start.text,
260
+ devTasks,
261
+ heldOutTasks: HELD_OUT_TASKS,
262
+ score,
263
+ propose: async (input) => {
264
+ const answer = await askProposer(proposer, input);
265
+ if (typeof answer === "string") {
266
+ return { addendum: "", reason: answer, costUsd: 0 };
267
+ }
268
+ return answer;
269
+ },
270
+ rounds,
271
+ repeat,
272
+ heldoutRepeat,
273
+ margin,
274
+ maxCostUsd: maxCost,
275
+ seed,
276
+ save: (name, text) => writeFile(join(dir, name), text),
277
+ log: (line) => process.stderr.write(`${line}
278
+ `)
279
+ });
280
+ const kept = result.history.filter((h) => h.decision?.kept === true);
281
+ process.stdout.write(
282
+ [
283
+ "",
284
+ `Rounds: ${result.history.length}; kept: ${kept.length === 0 ? "none" : kept.map((h) => h.version).join(", ")}. Spent about $${result.spentUsd.toFixed(2)}${result.stopped === "rounds" ? "" : ` (stopped: ${result.stopped})`}.`,
285
+ ...result.heldOut === void 0 ? [] : ["", "Held-out (the only number to quote):", result.heldOut],
286
+ "",
287
+ `The final addendum: ${join(dir, "final.md")}. To use it, copy it into GARUDA.md yourself.`,
288
+ `Every version, the proposer's inputs and history.json: ${dir}`,
289
+ ""
290
+ ].join("\n")
291
+ );
292
+ return 0;
293
+ }
294
+ export {
295
+ DEFAULT_PROPOSER,
296
+ DEFAULT_TUNE_PARALLEL,
297
+ DEFAULT_TUNE_SUITES,
298
+ askProposer,
299
+ progressLine,
300
+ runEvalTune
301
+ };
302
+ //# sourceMappingURL=evalTune-W53KAD4V.js.map
@@ -2,11 +2,20 @@
2
2
  import {
3
3
  summariseCall,
4
4
  summariseResult
5
- } from "./chunk-FARS4R67.js";
5
+ } from "./chunk-DQSCCE77.js";
6
+ import {
7
+ hasReceipt
8
+ } from "./chunk-4QRTTRVK.js";
6
9
  import {
7
10
  serverCallText,
8
11
  serverResultSummary
9
12
  } from "./chunk-A2QAIRQL.js";
13
+ import {
14
+ receiptText
15
+ } from "./chunk-2OYTNNUJ.js";
16
+ import "./chunk-NLS7GMF7.js";
17
+ import "./chunk-7KBOIPUT.js";
18
+ import "./chunk-BHZ6G65V.js";
10
19
  import {
11
20
  PathOutsideRootError,
12
21
  displayPath,
@@ -98,6 +107,20 @@ function sessionMarkdown(records, sessionId) {
98
107
  case "compaction":
99
108
  out.push("_The conversation was compacted here to fit the context window._", "");
100
109
  break;
110
+ case "fork":
111
+ out.push(
112
+ `_This session starts as a fork of session ${record.from.sessionId}, at turn ${record.from.turn}._`,
113
+ ""
114
+ );
115
+ break;
116
+ case "receipt":
117
+ if (hasReceipt(record.receipt)) {
118
+ out.push(
119
+ ...receiptText(record.receipt).split("\n").map((line) => `> ${line}`),
120
+ ""
121
+ );
122
+ }
123
+ break;
101
124
  case "model":
102
125
  out.push(`_The model changed to ${record.model}._`, "");
103
126
  break;
@@ -129,8 +152,8 @@ function when(iso) {
129
152
  const pad = (n) => String(n).padStart(2, "0");
130
153
  return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`;
131
154
  }
132
- async function writeExport(root, sessionId, markdown, file = "") {
133
- const name = file === "" ? `garuda-${sessionId}.md` : file;
155
+ async function writeExport(root, sessionId, markdown, file = "", ext = ".md") {
156
+ const name = file === "" ? `garuda-${sessionId}${ext}` : file;
134
157
  let absolute;
135
158
  try {
136
159
  absolute = await resolveInRoot(root, name);
@@ -155,4 +178,4 @@ export {
155
178
  sessionMarkdown,
156
179
  writeExport
157
180
  };
158
- //# sourceMappingURL=export-SJ3DUP6W.js.map
181
+ //# sourceMappingURL=export-E677HIQS.js.map
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ OUTPUT_CHARS,
4
+ callChange,
5
+ escapeHtml,
6
+ sessionHtml
7
+ } from "./chunk-TLA2PDGM.js";
8
+ import "./chunk-DQSCCE77.js";
9
+ import "./chunk-4QRTTRVK.js";
10
+ import "./chunk-A2QAIRQL.js";
11
+ import "./chunk-2OYTNNUJ.js";
12
+ import "./chunk-NLS7GMF7.js";
13
+ import "./chunk-7KBOIPUT.js";
14
+ import "./chunk-BHZ6G65V.js";
15
+ export {
16
+ OUTPUT_CHARS,
17
+ callChange,
18
+ escapeHtml,
19
+ sessionHtml
20
+ };
21
+ //# sourceMappingURL=exportHtml-BMV73YRO.js.map