@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.
- package/CHANGELOG.md +319 -0
- package/README.md +56 -1074
- package/SECURITY.md +9 -2
- package/dist/{acpCommand-OTAYW7BS.js → acpCommand-IUZPLPLI.js} +25 -23
- package/dist/{anthropic-NQDBCHJU.js → anthropic-NQIZLD64.js} +12 -6
- package/dist/{chunk-NP6RIC25.js → chunk-2FIV2VZP.js} +11 -7
- package/dist/{chunk-YQTGMCU6.js → chunk-3MRQJKUO.js} +29 -5
- package/dist/{chunk-HE2K657U.js → chunk-4BVCYCQT.js} +47 -16
- package/dist/{chunk-WMOLXTBU.js → chunk-4LFJFDCF.js} +2 -1
- package/dist/{chunk-44QN5SWZ.js → chunk-55CFEEIN.js} +22 -2
- package/dist/{chunk-USCUXCAU.js → chunk-5B5HDTUR.js} +3 -3
- package/dist/chunk-65NUEOI7.js +143 -0
- package/dist/{chunk-TUUEBHG2.js → chunk-6XHON3Q6.js} +2 -2
- package/dist/chunk-7KBOIPUT.js +157 -0
- package/dist/{chunk-B6FA4I7Q.js → chunk-7TH3NHCQ.js} +2 -2
- package/dist/{chunk-OUCV3FCT.js → chunk-AOGFYUKG.js} +3 -3
- package/dist/{chunk-GXZACJUI.js → chunk-B4SJY7KT.js} +322 -39
- package/dist/{chunk-3EQU2GUX.js → chunk-BHZ6G65V.js} +5 -1
- package/dist/chunk-C57GHLKP.js +9 -0
- package/dist/chunk-DOCDCQVM.js +484 -0
- package/dist/chunk-FOPBOB7W.js +332 -0
- package/dist/{chunk-TILFPYWO.js → chunk-NHWHG3SW.js} +1930 -992
- package/dist/{chunk-BQTUOO4G.js → chunk-OQ26W5L4.js} +81 -32
- package/dist/{chunk-HUIK3WXO.js → chunk-P6XWWIEK.js} +20 -3
- package/dist/chunk-Q4P3W657.js +6372 -0
- package/dist/{chunk-ZAE25JM2.js → chunk-QANRZW7W.js} +8 -1
- package/dist/chunk-UIRJOQQS.js +118 -0
- package/dist/chunk-UKIE4AAM.js +472 -0
- package/dist/{chunk-KKB5W47S.js → chunk-VTMD5IHD.js} +26 -2
- package/dist/cli/index.js +148 -57
- package/dist/config-WV2H64TF.js +23 -0
- package/dist/{create-VXIH2GUZ.js → create-W6BV75QX.js} +18 -12
- package/dist/{deadline-F5RJJ2QW.js → deadline-TP7ZGLT2.js} +4 -2
- package/dist/evalCommand-SKJQ6CW2.js +686 -0
- package/dist/evalTune-CZRCPSZ3.js +295 -0
- package/dist/{export-HN3CT7AV.js → export-SJ3DUP6W.js} +2 -2
- package/dist/{inkChat-WEDGQMCY.js → inkChat-WYYAFZXD.js} +20 -19
- package/dist/install-TKWN5AYH.js +19 -0
- package/dist/{job-3NYDMP2M.js → job-7JOI4YIQ.js} +6 -2
- package/dist/jobCommand-2ODQLHB3.js +33 -0
- package/dist/{launchd-SSX362VG.js → launchd-3A3ONEW5.js} +9 -8
- package/dist/{lspCommand-JRXKRSL7.js → lspCommand-ZZ6R4PA2.js} +7 -6
- package/dist/{manager-773PUDFE.js → manager-TCYTA5XU.js} +15 -14
- package/dist/{nightCommand-65MUEV32.js → nightCommand-WJU6VZA6.js} +26 -20
- package/dist/{openaiCompatible-CJWVJP5M.js → openaiCompatible-6TLDDW5U.js} +29 -15
- package/dist/{policy-EJPLEEXP.js → policy-ZJ7RMOFN.js} +10 -4
- package/dist/{remove-6GDSTAIO.js → remove-42WQNVPX.js} +8 -7
- package/dist/{run-ML6GSPN4.js → run-PTMRQCIU.js} +5 -5
- package/dist/{server-NGKVIQEV.js → server-VEYIJHEU.js} +2 -2
- package/dist/{setupCommand-VA7D5MZK.js → setupCommand-YMF6I3MD.js} +45 -13
- package/dist/text-LS35WSRL.js +17 -0
- package/dist/tune-YVI2KWQF.js +31 -0
- package/native/bin/garuda-reap +0 -0
- package/native/garuda-reap.c +113 -0
- package/package.json +39 -13
- package/dist/chunk-EIXUSVFX.js +0 -116
- package/dist/chunk-R7I2NBPX.js +0 -71
- package/dist/chunk-ULAJPMY7.js +0 -107
- package/dist/chunk-VBZCNMUD.js +0 -9
- package/dist/evalCommand-RGMZRYDR.js +0 -2812
- package/dist/install-EWDSPFFZ.js +0 -18
- package/dist/jobCommand-ACSGSBQ4.js +0 -32
- package/dist/text-J2GD647J.js +0 -11
|
@@ -215,7 +215,11 @@ var OpenAICompatibleClient = class {
|
|
|
215
215
|
fetch;
|
|
216
216
|
delays;
|
|
217
217
|
async *stream(request, options) {
|
|
218
|
-
const http = await this.post(
|
|
218
|
+
const http = await this.post(
|
|
219
|
+
toWireBody(this.options.model, request),
|
|
220
|
+
options?.signal,
|
|
221
|
+
options?.meter
|
|
222
|
+
);
|
|
219
223
|
const mode = request.tools.length === 0 ? "off" : this.options.textToolCalls ?? "whole";
|
|
220
224
|
const state = newStreamState();
|
|
221
225
|
const hold = new StreamHold(mode);
|
|
@@ -241,7 +245,7 @@ var OpenAICompatibleClient = class {
|
|
|
241
245
|
}
|
|
242
246
|
yield { type: "response", response };
|
|
243
247
|
}
|
|
244
|
-
async post(body, signal) {
|
|
248
|
+
async post(body, signal, meter) {
|
|
245
249
|
const url = `${this.options.baseUrl.replace(/\/+$/, "")}/chat/completions`;
|
|
246
250
|
const headers = {
|
|
247
251
|
"content-type": "application/json",
|
|
@@ -262,6 +266,7 @@ var OpenAICompatibleClient = class {
|
|
|
262
266
|
const cause = causeCode(error);
|
|
263
267
|
if (attempt < this.delays.length && cause !== "ECONNREFUSED") {
|
|
264
268
|
await sleep(this.delays[attempt] ?? 1e3, signal);
|
|
269
|
+
meter?.retry();
|
|
265
270
|
continue;
|
|
266
271
|
}
|
|
267
272
|
throw new Error(
|
|
@@ -274,6 +279,7 @@ var OpenAICompatibleClient = class {
|
|
|
274
279
|
const retryAfter = Number(response.headers.get("retry-after")) * 1e3;
|
|
275
280
|
const wait = Number.isFinite(retryAfter) && retryAfter > 0 ? Math.min(retryAfter, MAX_RETRY_AFTER_MS) : this.delays[attempt] ?? 1e3;
|
|
276
281
|
await sleep(wait, signal);
|
|
282
|
+
meter?.retry();
|
|
277
283
|
continue;
|
|
278
284
|
}
|
|
279
285
|
throw new Error(
|
|
@@ -378,10 +384,12 @@ function finishResponse(state, request, mode = "whole") {
|
|
|
378
384
|
input: parseArguments(call.args)
|
|
379
385
|
});
|
|
380
386
|
}
|
|
387
|
+
const reported = providerUsage(state.usage);
|
|
381
388
|
return {
|
|
382
389
|
content,
|
|
383
390
|
stopReason: stopReason(state, content),
|
|
384
|
-
usage:
|
|
391
|
+
usage: reported ?? estimatedUsage(request, content),
|
|
392
|
+
...reported === void 0 ? { usageReported: false } : {}
|
|
385
393
|
};
|
|
386
394
|
}
|
|
387
395
|
function toolNames(request) {
|
|
@@ -403,17 +411,23 @@ function stopReason(state, content) {
|
|
|
403
411
|
return "end_turn";
|
|
404
412
|
return "other";
|
|
405
413
|
}
|
|
406
|
-
function
|
|
407
|
-
const
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
414
|
+
function providerUsage(u) {
|
|
415
|
+
const input = u?.prompt_tokens;
|
|
416
|
+
const output = u?.completion_tokens;
|
|
417
|
+
const cached = u?.prompt_tokens_details?.cached_tokens ?? 0;
|
|
418
|
+
if (!tokenCount(input) || !tokenCount(output) || !tokenCount(cached) || cached > input)
|
|
419
|
+
return void 0;
|
|
420
|
+
return {
|
|
421
|
+
inputTokens: input - cached,
|
|
422
|
+
outputTokens: output,
|
|
423
|
+
cacheReadTokens: cached,
|
|
424
|
+
cacheWriteTokens: 0
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
function tokenCount(value) {
|
|
428
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
429
|
+
}
|
|
430
|
+
function estimatedUsage(request, content) {
|
|
417
431
|
const chars = (value) => JSON.stringify(value).length;
|
|
418
432
|
return {
|
|
419
433
|
inputTokens: Math.ceil(
|
|
@@ -498,4 +512,4 @@ export {
|
|
|
498
512
|
toWireMessages,
|
|
499
513
|
toWireTools
|
|
500
514
|
};
|
|
501
|
-
//# sourceMappingURL=openaiCompatible-
|
|
515
|
+
//# sourceMappingURL=openaiCompatible-6TLDDW5U.js.map
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
POLICY_FILE,
|
|
4
|
+
PROFILES,
|
|
4
5
|
assertModelAllowedByPolicy,
|
|
5
6
|
ignoredProjectPolicy,
|
|
6
7
|
isCommandDisallowedByPolicy,
|
|
@@ -8,14 +9,17 @@ import {
|
|
|
8
9
|
isModelAllowedByPolicy,
|
|
9
10
|
isPathDeniedByPolicy,
|
|
10
11
|
isSandboxRequiredByPolicy,
|
|
12
|
+
isStrict,
|
|
11
13
|
loadTeamPolicy,
|
|
12
14
|
managedPolicyPath,
|
|
13
15
|
mergePolicies,
|
|
14
|
-
parsePolicy
|
|
15
|
-
|
|
16
|
+
parsePolicy,
|
|
17
|
+
withProfile
|
|
18
|
+
} from "./chunk-P6XWWIEK.js";
|
|
16
19
|
import "./chunk-3NJNVZTK.js";
|
|
17
20
|
export {
|
|
18
21
|
POLICY_FILE,
|
|
22
|
+
PROFILES,
|
|
19
23
|
assertModelAllowedByPolicy,
|
|
20
24
|
ignoredProjectPolicy,
|
|
21
25
|
isCommandDisallowedByPolicy,
|
|
@@ -23,9 +27,11 @@ export {
|
|
|
23
27
|
isModelAllowedByPolicy,
|
|
24
28
|
isPathDeniedByPolicy,
|
|
25
29
|
isSandboxRequiredByPolicy,
|
|
30
|
+
isStrict,
|
|
26
31
|
loadTeamPolicy,
|
|
27
32
|
managedPolicyPath,
|
|
28
33
|
mergePolicies,
|
|
29
|
-
parsePolicy
|
|
34
|
+
parsePolicy,
|
|
35
|
+
withProfile
|
|
30
36
|
};
|
|
31
|
-
//# sourceMappingURL=policy-
|
|
37
|
+
//# sourceMappingURL=policy-ZJ7RMOFN.js.map
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
git
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import "./chunk-
|
|
6
|
-
import "./chunk-
|
|
7
|
-
import "./chunk-
|
|
8
|
-
import "./chunk-HUIK3WXO.js";
|
|
4
|
+
} from "./chunk-6XHON3Q6.js";
|
|
5
|
+
import "./chunk-B4SJY7KT.js";
|
|
6
|
+
import "./chunk-BHZ6G65V.js";
|
|
7
|
+
import "./chunk-P6XWWIEK.js";
|
|
9
8
|
import {
|
|
10
9
|
JOBS_DIR,
|
|
11
10
|
jobPath
|
|
12
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-VTMD5IHD.js";
|
|
12
|
+
import "./chunk-UIRJOQQS.js";
|
|
13
|
+
import "./chunk-4LFJFDCF.js";
|
|
13
14
|
import "./chunk-3NJNVZTK.js";
|
|
14
15
|
|
|
15
16
|
// src/jobs/remove.ts
|
|
@@ -57,4 +58,4 @@ export {
|
|
|
57
58
|
jobLeftovers,
|
|
58
59
|
removeJob
|
|
59
60
|
};
|
|
60
|
-
//# sourceMappingURL=remove-
|
|
61
|
+
//# sourceMappingURL=remove-42WQNVPX.js.map
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
folderKind
|
|
4
|
+
} from "./chunk-42DSA4EA.js";
|
|
2
5
|
import {
|
|
3
6
|
loadSearchConfig,
|
|
4
7
|
providerLabel,
|
|
@@ -10,11 +13,8 @@ import {
|
|
|
10
13
|
import {
|
|
11
14
|
SERVER_NAME,
|
|
12
15
|
checkServerUrl
|
|
13
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-QANRZW7W.js";
|
|
14
17
|
import "./chunk-ATW7BNIG.js";
|
|
15
|
-
import {
|
|
16
|
-
folderKind
|
|
17
|
-
} from "./chunk-42DSA4EA.js";
|
|
18
18
|
|
|
19
19
|
// src/init/run.ts
|
|
20
20
|
import { existsSync as existsSync3 } from "fs";
|
|
@@ -885,4 +885,4 @@ export {
|
|
|
885
885
|
initPrompt,
|
|
886
886
|
runInit
|
|
887
887
|
};
|
|
888
|
-
//# sourceMappingURL=run-
|
|
888
|
+
//# sourceMappingURL=run-PTMRQCIU.js.map
|
|
@@ -467,7 +467,7 @@ function setupNeeded(message) {
|
|
|
467
467
|
return Object.assign(new Error(message), { authRequired: true });
|
|
468
468
|
}
|
|
469
469
|
var MODES = {
|
|
470
|
-
build: { name: "Build", description: "Edits
|
|
470
|
+
build: { name: "Build", description: "Edits ask first; commands run in the sandbox." },
|
|
471
471
|
plan: {
|
|
472
472
|
name: "Plan",
|
|
473
473
|
description: "Reads and plans. No edits; commands cannot write the project."
|
|
@@ -695,4 +695,4 @@ export {
|
|
|
695
695
|
canRunTerminalAuth,
|
|
696
696
|
setupNeeded
|
|
697
697
|
};
|
|
698
|
-
//# sourceMappingURL=server-
|
|
698
|
+
//# sourceMappingURL=server-VEYIJHEU.js.map
|
|
@@ -11,13 +11,16 @@ import {
|
|
|
11
11
|
resolveModel,
|
|
12
12
|
setDefaultModel,
|
|
13
13
|
writeCredentials
|
|
14
|
-
} from "./chunk-
|
|
15
|
-
import "./chunk-EIXUSVFX.js";
|
|
14
|
+
} from "./chunk-2FIV2VZP.js";
|
|
16
15
|
import {
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
fetchCatalog,
|
|
17
|
+
loadCatalog,
|
|
18
|
+
mergedModels,
|
|
19
|
+
saveCatalog
|
|
20
|
+
} from "./chunk-65NUEOI7.js";
|
|
21
|
+
import "./chunk-7KBOIPUT.js";
|
|
19
22
|
import "./chunk-ATW7BNIG.js";
|
|
20
|
-
import "./chunk-
|
|
23
|
+
import "./chunk-BHZ6G65V.js";
|
|
21
24
|
|
|
22
25
|
// src/cli/setupCommand.ts
|
|
23
26
|
import { homedir } from "os";
|
|
@@ -85,7 +88,9 @@ async function setup(io, config, home, env, fetcher) {
|
|
|
85
88
|
}))
|
|
86
89
|
);
|
|
87
90
|
const def = providers[provider];
|
|
88
|
-
const
|
|
91
|
+
const anthropicKey = def.type === "anthropic" ? def.apiKeyEnv ?? "ANTHROPIC_API_KEY" : void 0;
|
|
92
|
+
const knownKey = anthropicKey === void 0 ? void 0 : (env[anthropicKey] ?? "") !== "" ? env[anthropicKey] : stored.keys[anthropicKey];
|
|
93
|
+
const model = await pickModel(io, provider, def, fetcher, { home, env, key: knownKey });
|
|
89
94
|
const spec = provider === "anthropic" ? model : `${provider}/${model}`;
|
|
90
95
|
try {
|
|
91
96
|
resolveModel(spec, config);
|
|
@@ -111,7 +116,12 @@ async function setup(io, config, home, env, fetcher) {
|
|
|
111
116
|
const key = fromEnv !== "" ? fromEnv : newKey ?? old;
|
|
112
117
|
const result = await checkKey(provider, def, key, env, fetcher);
|
|
113
118
|
io.print(result.message);
|
|
114
|
-
if (result.ok)
|
|
119
|
+
if (result.ok) {
|
|
120
|
+
if (def.type === "anthropic" && knownKey === void 0) {
|
|
121
|
+
await refreshCatalog(io, { home, env, key }, fetcher);
|
|
122
|
+
}
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
115
125
|
const next = await io.select("What now?", [
|
|
116
126
|
...fromEnv === "" ? [{ name: "Enter the key again", value: "again" }] : [],
|
|
117
127
|
{ name: "Store it anyway", value: "store" },
|
|
@@ -146,15 +156,17 @@ async function setup(io, config, home, env, fetcher) {
|
|
|
146
156
|
io.print("Done. Start Garuda with: garuda");
|
|
147
157
|
return 0;
|
|
148
158
|
}
|
|
149
|
-
async function pickModel(io, provider, def, fetcher) {
|
|
159
|
+
async function pickModel(io, provider, def, fetcher, account) {
|
|
150
160
|
let listed = [];
|
|
151
161
|
const notes = /* @__PURE__ */ new Map();
|
|
152
162
|
if (def.type === "anthropic") {
|
|
153
|
-
|
|
163
|
+
let catalog = await loadCatalog(account.home);
|
|
164
|
+
if (account.key !== void 0) {
|
|
165
|
+
catalog = await refreshCatalog(io, account, fetcher) ?? catalog;
|
|
166
|
+
}
|
|
167
|
+
for (const { id, info, known } of mergedModels(catalog)) {
|
|
154
168
|
listed.push(id);
|
|
155
|
-
|
|
156
|
-
notes.set(id, `$${info.price.input} in, $${info.price.output} out per million tokens`);
|
|
157
|
-
}
|
|
169
|
+
notes.set(id, known && info.price !== void 0 ? priceNote(info.price) : UNKNOWN_PRICE);
|
|
158
170
|
}
|
|
159
171
|
} else if (def.local === true && def.baseUrl !== void 0) {
|
|
160
172
|
listed = await localModels(def.baseUrl, fetcher);
|
|
@@ -177,6 +189,26 @@ async function pickModel(io, provider, def, fetcher) {
|
|
|
177
189
|
io.print("Type a model name with no spaces.");
|
|
178
190
|
}
|
|
179
191
|
}
|
|
192
|
+
var UNKNOWN_PRICE = "price unknown to this Garuda version: costs show as unknown (set model.price, or update Garuda)";
|
|
193
|
+
function priceNote(price) {
|
|
194
|
+
const more = price.over === void 0 ? "" : ` (more for prompts over ${price.over.tokens / 1e3}k tokens)`;
|
|
195
|
+
return `$${price.input} in, $${price.output} out per million tokens${more}`;
|
|
196
|
+
}
|
|
197
|
+
async function refreshCatalog(io, account, fetcher) {
|
|
198
|
+
const base = account.env.ANTHROPIC_BASE_URL ?? "";
|
|
199
|
+
const result = await fetchCatalog({
|
|
200
|
+
key: account.key,
|
|
201
|
+
...base === "" ? {} : { baseUrl: base },
|
|
202
|
+
fetcher
|
|
203
|
+
});
|
|
204
|
+
if ("problem" in result) {
|
|
205
|
+
io.print(`The list shows Garuda's own table: ${result.problem}.`);
|
|
206
|
+
return void 0;
|
|
207
|
+
}
|
|
208
|
+
await saveCatalog(result.catalog, account.home);
|
|
209
|
+
io.print(`Models of your account: ${result.catalog.models.length}.`);
|
|
210
|
+
return result.catalog;
|
|
211
|
+
}
|
|
180
212
|
async function localModels(baseUrl, fetcher) {
|
|
181
213
|
try {
|
|
182
214
|
const response = await fetcher(`${baseUrl.replace(/\/+$/, "")}/models`, {
|
|
@@ -300,4 +332,4 @@ export {
|
|
|
300
332
|
setupCommand,
|
|
301
333
|
terminalIO
|
|
302
334
|
};
|
|
303
|
-
//# sourceMappingURL=setupCommand-
|
|
335
|
+
//# sourceMappingURL=setupCommand-YMF6I3MD.js.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
formatCost,
|
|
4
|
+
jobCost,
|
|
5
|
+
jobPrompt,
|
|
6
|
+
jobReport,
|
|
7
|
+
sumCosts
|
|
8
|
+
} from "./chunk-3MRQJKUO.js";
|
|
9
|
+
import "./chunk-AOGFYUKG.js";
|
|
10
|
+
export {
|
|
11
|
+
formatCost,
|
|
12
|
+
jobCost,
|
|
13
|
+
jobPrompt,
|
|
14
|
+
jobReport,
|
|
15
|
+
sumCosts
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=text-LS35WSRL.js.map
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
ADDENDUM_MAX_CHARS,
|
|
4
|
+
PROPOSER_SYSTEM,
|
|
5
|
+
decide,
|
|
6
|
+
parseProposal,
|
|
7
|
+
proposerInput,
|
|
8
|
+
readAddendum,
|
|
9
|
+
rejectReason,
|
|
10
|
+
tune
|
|
11
|
+
} from "./chunk-FOPBOB7W.js";
|
|
12
|
+
import "./chunk-DOCDCQVM.js";
|
|
13
|
+
import "./chunk-C57GHLKP.js";
|
|
14
|
+
import "./chunk-6XHON3Q6.js";
|
|
15
|
+
import "./chunk-B4SJY7KT.js";
|
|
16
|
+
import "./chunk-BHZ6G65V.js";
|
|
17
|
+
import "./chunk-P6XWWIEK.js";
|
|
18
|
+
import "./chunk-UIRJOQQS.js";
|
|
19
|
+
import "./chunk-4LFJFDCF.js";
|
|
20
|
+
import "./chunk-3NJNVZTK.js";
|
|
21
|
+
export {
|
|
22
|
+
ADDENDUM_MAX_CHARS,
|
|
23
|
+
PROPOSER_SYSTEM,
|
|
24
|
+
decide,
|
|
25
|
+
parseProposal,
|
|
26
|
+
proposerInput,
|
|
27
|
+
readAddendum,
|
|
28
|
+
rejectReason,
|
|
29
|
+
tune
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=tune-YVI2KWQF.js.map
|
|
Binary file
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
// garuda-reap (0.17, IPI-04): stop the processes that one sandboxed command left running on macOS.
|
|
2
|
+
//
|
|
3
|
+
// Seatbelt has no process namespace, so a process can leave the command's process group (setsid,
|
|
4
|
+
// setpgid, posix_spawn with POSIX_SPAWN_SETSID or POSIX_SPAWN_SETPGROUP) and outlive the command.
|
|
5
|
+
// It cannot leave its Seatbelt profile. Garuda puts two marker files in each command's profile:
|
|
6
|
+
// reads of <markerA> are denied, reads of <markerB> are allowed. After the command, this helper
|
|
7
|
+
// asks the kernel (sandbox_check) about every process of the current user and sends SIGKILL to
|
|
8
|
+
// each one that has A denied and B allowed. Processes without a sandbox allow both; App Store
|
|
9
|
+
// sandboxes deny both (the markers are outside their containers). So only the command's own
|
|
10
|
+
// processes match. It repeats the scan until a scan finds none (at most 10 scans), so children
|
|
11
|
+
// started during a scan are found in the next one.
|
|
12
|
+
//
|
|
13
|
+
// garuda-reap <markerA> <markerB> stop the matches; prints "killed <n>"
|
|
14
|
+
// garuda-reap --list <markerA> <markerB> only list the matches (tests)
|
|
15
|
+
//
|
|
16
|
+
// Exit codes: 0 done, 2 usage, 3 a marker file is missing, 4 the process list failed.
|
|
17
|
+
#include <errno.h>
|
|
18
|
+
#include <libproc.h>
|
|
19
|
+
#include <signal.h>
|
|
20
|
+
#include <stdio.h>
|
|
21
|
+
#include <stdlib.h>
|
|
22
|
+
#include <string.h>
|
|
23
|
+
#include <sys/proc_info.h>
|
|
24
|
+
#include <sys/stat.h>
|
|
25
|
+
#include <unistd.h>
|
|
26
|
+
|
|
27
|
+
// From libsystem_sandbox (not in the public SDK headers).
|
|
28
|
+
enum sandbox_filter_type { SANDBOX_FILTER_NONE, SANDBOX_FILTER_PATH };
|
|
29
|
+
extern const enum sandbox_filter_type SANDBOX_CHECK_NO_REPORT;
|
|
30
|
+
int sandbox_check(pid_t pid, const char *operation, enum sandbox_filter_type type, ...);
|
|
31
|
+
|
|
32
|
+
#define MAX_SCANS 10
|
|
33
|
+
#define MAX_KILLED 4096
|
|
34
|
+
|
|
35
|
+
// Processes already sent SIGKILL: a killed process can show in the next scan until launchd reaps
|
|
36
|
+
// it, so it is counted once and does not keep the loop going.
|
|
37
|
+
static pid_t killed_pids[MAX_KILLED];
|
|
38
|
+
static int killed_count = 0;
|
|
39
|
+
|
|
40
|
+
static int already_killed(pid_t pid) {
|
|
41
|
+
for (int i = 0; i < killed_count; i++)
|
|
42
|
+
if (killed_pids[i] == pid) return 1;
|
|
43
|
+
return 0;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
static int denied(pid_t pid, const char *path) {
|
|
47
|
+
return sandbox_check(pid, "file-read-data",
|
|
48
|
+
(enum sandbox_filter_type)(SANDBOX_FILTER_PATH | SANDBOX_CHECK_NO_REPORT), path);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// One scan. Returns the number of new matches, or -1 when the process list failed.
|
|
52
|
+
static int scan(const char *a, const char *b, int list_only) {
|
|
53
|
+
int n = proc_listallpids(NULL, 0);
|
|
54
|
+
if (n <= 0) return -1;
|
|
55
|
+
size_t cap = (size_t)n + 256;
|
|
56
|
+
pid_t *pids = calloc(cap, sizeof(pid_t));
|
|
57
|
+
if (pids == NULL) return -1;
|
|
58
|
+
n = proc_listallpids(pids, (int)(cap * sizeof(pid_t)));
|
|
59
|
+
if (n <= 0) {
|
|
60
|
+
free(pids);
|
|
61
|
+
return -1;
|
|
62
|
+
}
|
|
63
|
+
uid_t me = getuid();
|
|
64
|
+
pid_t self = getpid(), parent = getppid();
|
|
65
|
+
int matches = 0;
|
|
66
|
+
for (int i = 0; i < n; i++) {
|
|
67
|
+
pid_t pid = pids[i];
|
|
68
|
+
if (pid <= 1 || pid == self || pid == parent) continue;
|
|
69
|
+
struct proc_bsdinfo info;
|
|
70
|
+
if (proc_pidinfo(pid, PROC_PIDTBSDINFO, 0, &info, sizeof info) != (int)sizeof info) continue;
|
|
71
|
+
if (info.pbi_uid != me) continue;
|
|
72
|
+
if (denied(pid, a) == 1 && denied(pid, b) == 0) {
|
|
73
|
+
if (list_only) {
|
|
74
|
+
matches++;
|
|
75
|
+
printf("match %d %d %s\n", pid, info.pbi_ppid, info.pbi_comm);
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
kill(pid, SIGKILL);
|
|
79
|
+
if (already_killed(pid)) continue;
|
|
80
|
+
matches++;
|
|
81
|
+
if (killed_count < MAX_KILLED) killed_pids[killed_count++] = pid;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
free(pids);
|
|
85
|
+
return matches;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
int main(int argc, char **argv) {
|
|
89
|
+
int list_only = argc == 4 && strcmp(argv[1], "--list") == 0;
|
|
90
|
+
if (argc != 3 && !list_only) {
|
|
91
|
+
fprintf(stderr, "usage: garuda-reap [--list] <markerA> <markerB>\n");
|
|
92
|
+
return 2;
|
|
93
|
+
}
|
|
94
|
+
const char *a = argv[argc - 2], *b = argv[argc - 1];
|
|
95
|
+
struct stat st;
|
|
96
|
+
// A missing marker reads as denied for every process, so nothing would match: refuse instead.
|
|
97
|
+
if (stat(a, &st) != 0 || stat(b, &st) != 0) {
|
|
98
|
+
fprintf(stderr, "garuda-reap: a marker file is missing\n");
|
|
99
|
+
return 3;
|
|
100
|
+
}
|
|
101
|
+
if (list_only) return scan(a, b, 1) < 0 ? 4 : 0;
|
|
102
|
+
for (int i = 0; i < MAX_SCANS; i++) {
|
|
103
|
+
int found = scan(a, b, 0);
|
|
104
|
+
if (found < 0) {
|
|
105
|
+
fprintf(stderr, "garuda-reap: the process list failed (%s)\n", strerror(errno));
|
|
106
|
+
return 4;
|
|
107
|
+
}
|
|
108
|
+
if (found == 0) break;
|
|
109
|
+
usleep(10000);
|
|
110
|
+
}
|
|
111
|
+
printf("killed %d\n", killed_count);
|
|
112
|
+
return 0;
|
|
113
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@garuda-agent/garuda",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.0",
|
|
4
4
|
"description": "Garuda: a terminal coding agent with an OS sandbox, approvals and an audit log.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Madhusudhan Vasanth Kumar",
|
|
@@ -17,7 +17,17 @@
|
|
|
17
17
|
"sandbox",
|
|
18
18
|
"anthropic",
|
|
19
19
|
"claude",
|
|
20
|
-
"mcp"
|
|
20
|
+
"mcp",
|
|
21
|
+
"ai",
|
|
22
|
+
"ai-agent",
|
|
23
|
+
"agent",
|
|
24
|
+
"llm",
|
|
25
|
+
"ollama",
|
|
26
|
+
"openrouter",
|
|
27
|
+
"acp",
|
|
28
|
+
"agent-client-protocol",
|
|
29
|
+
"zed",
|
|
30
|
+
"code-assistant"
|
|
21
31
|
],
|
|
22
32
|
"type": "module",
|
|
23
33
|
"bin": {
|
|
@@ -29,33 +39,40 @@
|
|
|
29
39
|
"NOTICE",
|
|
30
40
|
"README.md",
|
|
31
41
|
"SECURITY.md",
|
|
32
|
-
"CHANGELOG.md"
|
|
42
|
+
"CHANGELOG.md",
|
|
43
|
+
"native/garuda-reap.c",
|
|
44
|
+
"native/bin/garuda-reap"
|
|
33
45
|
],
|
|
34
46
|
"engines": {
|
|
35
|
-
"node": ">=
|
|
47
|
+
"node": "^22.23.4 || ^24.22.1 || >=26.12.1"
|
|
36
48
|
},
|
|
37
49
|
"publishConfig": {
|
|
38
50
|
"access": "public"
|
|
39
51
|
},
|
|
40
52
|
"scripts": {
|
|
41
|
-
"build": "tsup",
|
|
53
|
+
"build": "tsup && node scripts/build-native.mjs",
|
|
42
54
|
"typecheck": "tsc --noEmit",
|
|
43
55
|
"lint": "biome check .",
|
|
44
56
|
"format": "biome format --write .",
|
|
45
|
-
"test": "vitest run",
|
|
57
|
+
"test": "node scripts/build-native.mjs && vitest run",
|
|
46
58
|
"check": "pnpm typecheck && pnpm lint && pnpm test",
|
|
47
59
|
"package": "tsup && node scripts/package.mjs",
|
|
48
60
|
"startup": "node scripts/startup.mjs",
|
|
61
|
+
"models:check": "node scripts/check-models.mjs",
|
|
62
|
+
"ipi:mutations": "node scripts/check-ipi-mutations.mjs",
|
|
49
63
|
"eval": "node dist/cli/index.js eval",
|
|
50
64
|
"baseline:capture": "node scripts/capture-quality-baseline.mjs",
|
|
51
|
-
"
|
|
65
|
+
"code-intelligence:validate": "vitest run test/lspReferenceSample.test.ts test/codeIntelligenceSample.test.ts --reporter=verbose",
|
|
66
|
+
"code-intelligence:capture": "node scripts/capture-reference-oracle.mjs",
|
|
67
|
+
"prepack": "pnpm build",
|
|
68
|
+
"build:native": "node scripts/build-native.mjs"
|
|
52
69
|
},
|
|
53
70
|
"packageManager": "pnpm@10.28.0",
|
|
54
71
|
"dependencies": {
|
|
55
72
|
"@agentclientprotocol/sdk": "1.7.0",
|
|
56
73
|
"@anthropic-ai/sdk": "^0.128.0",
|
|
57
74
|
"@inquirer/prompts": "^8.7.2",
|
|
58
|
-
"@modelcontextprotocol/client": "^2.1
|
|
75
|
+
"@modelcontextprotocol/client": "^2.3.1",
|
|
59
76
|
"commander": "^15.0.0",
|
|
60
77
|
"diff": "^9.0.0",
|
|
61
78
|
"globby": "^16.2.4",
|
|
@@ -65,23 +82,32 @@
|
|
|
65
82
|
"react": "^19.3.0",
|
|
66
83
|
"smol-toml": "^1.9.0",
|
|
67
84
|
"ts6": "npm:typescript@^6.0.3",
|
|
68
|
-
"undici": "^7.30.
|
|
85
|
+
"undici": "^7.30.1",
|
|
69
86
|
"vscode-jsonrpc": "^9.0.3",
|
|
70
|
-
"zod": "^4.6.
|
|
87
|
+
"zod": "^4.6.7"
|
|
71
88
|
},
|
|
72
89
|
"devDependencies": {
|
|
73
90
|
"@biomejs/biome": "^2.5.14",
|
|
74
|
-
"@modelcontextprotocol/server": "^2.1
|
|
91
|
+
"@modelcontextprotocol/server": "^2.3.1",
|
|
75
92
|
"@types/node": "^22.20.4",
|
|
76
93
|
"@types/react": "^19.3.0",
|
|
77
94
|
"ink-testing-library": "^4.0.0",
|
|
78
95
|
"tsup": "^8.5.1",
|
|
79
96
|
"typescript": "^7.0.2",
|
|
80
|
-
"
|
|
97
|
+
"vite": "^8.3.5",
|
|
98
|
+
"vitest": "^5.0.5"
|
|
81
99
|
},
|
|
82
100
|
"pnpm": {
|
|
83
101
|
"onlyBuiltDependencies": [
|
|
84
102
|
"esbuild"
|
|
85
|
-
]
|
|
103
|
+
],
|
|
104
|
+
"overrides": {
|
|
105
|
+
"esbuild": "^0.28.2"
|
|
106
|
+
},
|
|
107
|
+
"auditConfig": {
|
|
108
|
+
"ignoreGhsas": [
|
|
109
|
+
"GHSA-vfj7-8cjw-p6xm"
|
|
110
|
+
]
|
|
111
|
+
}
|
|
86
112
|
}
|
|
87
113
|
}
|