@garuda-agent/garuda 0.16.1 → 0.17.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 (54) hide show
  1. package/CHANGELOG.md +182 -0
  2. package/README.md +56 -1074
  3. package/SECURITY.md +9 -2
  4. package/dist/{acpCommand-OTAYW7BS.js → acpCommand-7EY3NHPG.js} +18 -16
  5. package/dist/{anthropic-NQDBCHJU.js → anthropic-NQIZLD64.js} +12 -6
  6. package/dist/{chunk-TILFPYWO.js → chunk-2DYMJMRQ.js} +1880 -982
  7. package/dist/{chunk-YQTGMCU6.js → chunk-3MRQJKUO.js} +29 -5
  8. package/dist/{chunk-WMOLXTBU.js → chunk-4LFJFDCF.js} +2 -1
  9. package/dist/{chunk-44QN5SWZ.js → chunk-55CFEEIN.js} +22 -2
  10. package/dist/{chunk-USCUXCAU.js → chunk-5B5HDTUR.js} +3 -3
  11. package/dist/{chunk-TUUEBHG2.js → chunk-6XHON3Q6.js} +2 -2
  12. package/dist/chunk-735BKABA.js +472 -0
  13. package/dist/{chunk-B6FA4I7Q.js → chunk-7TH3NHCQ.js} +2 -2
  14. package/dist/{chunk-OUCV3FCT.js → chunk-AOGFYUKG.js} +3 -3
  15. package/dist/{chunk-GXZACJUI.js → chunk-B4SJY7KT.js} +322 -39
  16. package/dist/{chunk-3EQU2GUX.js → chunk-BHZ6G65V.js} +5 -1
  17. package/dist/chunk-BSK5T2ZG.js +9 -0
  18. package/dist/chunk-J4346IDH.js +156 -0
  19. package/dist/{chunk-NP6RIC25.js → chunk-JRVWH27M.js} +7 -7
  20. package/dist/{chunk-HUIK3WXO.js → chunk-P6XWWIEK.js} +20 -3
  21. package/dist/{chunk-HE2K657U.js → chunk-TJIWD7R7.js} +47 -16
  22. package/dist/chunk-U65DQZDB.js +143 -0
  23. package/dist/chunk-UIRJOQQS.js +118 -0
  24. package/dist/{chunk-KKB5W47S.js → chunk-VTMD5IHD.js} +26 -2
  25. package/dist/{chunk-BQTUOO4G.js → chunk-Z66BWTMD.js} +81 -32
  26. package/dist/cli/index.js +99 -41
  27. package/dist/{create-VXIH2GUZ.js → create-W6BV75QX.js} +18 -12
  28. package/dist/{deadline-F5RJJ2QW.js → deadline-TP7ZGLT2.js} +4 -2
  29. package/dist/{evalCommand-RGMZRYDR.js → evalCommand-YVQAWUZE.js} +50 -29
  30. package/dist/{export-HN3CT7AV.js → export-SJ3DUP6W.js} +2 -2
  31. package/dist/{inkChat-WEDGQMCY.js → inkChat-FNUBK43U.js} +14 -13
  32. package/dist/install-TKWN5AYH.js +19 -0
  33. package/dist/{job-3NYDMP2M.js → job-7JOI4YIQ.js} +6 -2
  34. package/dist/jobCommand-FE6XN3YD.js +33 -0
  35. package/dist/{launchd-SSX362VG.js → launchd-3A3ONEW5.js} +9 -8
  36. package/dist/{lspCommand-JRXKRSL7.js → lspCommand-ZZ6R4PA2.js} +7 -6
  37. package/dist/{manager-773PUDFE.js → manager-73MPYFTP.js} +7 -6
  38. package/dist/{nightCommand-65MUEV32.js → nightCommand-OODJNWDT.js} +26 -20
  39. package/dist/{openaiCompatible-CJWVJP5M.js → openaiCompatible-6TLDDW5U.js} +29 -15
  40. package/dist/{policy-EJPLEEXP.js → policy-ZJ7RMOFN.js} +10 -4
  41. package/dist/{remove-6GDSTAIO.js → remove-42WQNVPX.js} +8 -7
  42. package/dist/{server-NGKVIQEV.js → server-VEYIJHEU.js} +2 -2
  43. package/dist/{setupCommand-VA7D5MZK.js → setupCommand-GBQIVYJC.js} +45 -13
  44. package/dist/text-LS35WSRL.js +17 -0
  45. package/native/bin/garuda-reap +0 -0
  46. package/native/garuda-reap.c +113 -0
  47. package/package.json +39 -13
  48. package/dist/chunk-EIXUSVFX.js +0 -116
  49. package/dist/chunk-R7I2NBPX.js +0 -71
  50. package/dist/chunk-ULAJPMY7.js +0 -107
  51. package/dist/chunk-VBZCNMUD.js +0 -9
  52. package/dist/install-EWDSPFFZ.js +0 -18
  53. package/dist/jobCommand-ACSGSBQ4.js +0 -32
  54. package/dist/text-J2GD647J.js +0 -11
@@ -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.16.1",
3
+ "version": "0.17.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": ">=22"
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
- "prepack": "pnpm build"
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.0",
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.0",
85
+ "undici": "^7.30.1",
69
86
  "vscode-jsonrpc": "^9.0.3",
70
- "zod": "^4.6.5"
87
+ "zod": "^4.6.7"
71
88
  },
72
89
  "devDependencies": {
73
90
  "@biomejs/biome": "^2.5.14",
74
- "@modelcontextprotocol/server": "^2.1.0",
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
- "vitest": "^5.0.1"
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
  }
@@ -1,116 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- // src/session/redact.ts
4
- var REDACTED = "[REDACTED]";
5
- var PATTERNS = [
6
- /-----BEGIN [A-Z0-9 ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z0-9 ]*PRIVATE KEY-----/g,
7
- /sk-ant-[A-Za-z0-9_-]{16,}/g,
8
- /\bsk-(?:proj-)?[A-Za-z0-9_-]{20,}/g,
9
- /\bAKIA[0-9A-Z]{16}\b/g,
10
- /\bgh[pousr]_[A-Za-z0-9]{30,}\b/g,
11
- /\bgithub_pat_[A-Za-z0-9_]{30,}\b/g,
12
- /\bxox[abprs]-[A-Za-z0-9-]{10,}/g,
13
- /\bAIza[0-9A-Za-z_-]{35}\b/g,
14
- /\beyJ[A-Za-z0-9_-]{10,}\.eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}/g
15
- ];
16
- var ASSIGNMENT = /\b([A-Za-z0-9_]*(?:api[_-]?key|secret|token|password|passwd)[A-Za-z0-9_]*)(["']?\s*[:=]\s*["']?)([^\s"'`,;]{8,})/gi;
17
- var OPAQUE_KEYS = /* @__PURE__ */ new Set(["encrypted_content", "encrypted_index", "signature"]);
18
- function looksLikeCode(name, value, next) {
19
- if (/^[\d_.]+$/.test(value)) return !/pass|secret/i.test(name);
20
- if (value.includes("(") || next === "(") return true;
21
- return /^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)+$/.test(value) && !/\d{4,}/.test(value);
22
- }
23
- var SECRET_ENV_NAME = /(KEY|TOKEN|SECRET|PASSWORD|PASSWD|CREDENTIAL)/i;
24
- var movedSecrets = /* @__PURE__ */ new Map();
25
- function keepSecretForRedaction(name, value) {
26
- movedSecrets.set(name, value);
27
- }
28
- var Redactor = class {
29
- literals;
30
- /**
31
- * `env`: variables whose names look secret have their values removed wherever they appear.
32
- * Default: this process's environment and the secrets moved out of it.
33
- */
34
- constructor(env = { ...process.env, ...Object.fromEntries(movedSecrets) }) {
35
- this.literals = Object.entries(env).filter(
36
- ([name, value]) => (SECRET_ENV_NAME.test(name) || value !== void 0 && movedSecrets.get(name) === value) && (value?.length ?? 0) >= 8
37
- ).map(([, value]) => value).sort((a, b) => b.length - a.length);
38
- }
39
- text(input) {
40
- let out = input;
41
- for (const literal of this.literals) out = out.split(literal).join(REDACTED);
42
- for (const pattern of PATTERNS) out = out.replace(pattern, REDACTED);
43
- return out.replace(
44
- ASSIGNMENT,
45
- (all, name, sep, value, at) => looksLikeCode(name, value, out[at + all.length]) ? all : `${name}${sep}${REDACTED}`
46
- );
47
- }
48
- /** A copy of `value` with every string redacted. */
49
- value(value) {
50
- return this.walk(value);
51
- }
52
- walk(value) {
53
- if (typeof value === "string") return this.text(value);
54
- if (Array.isArray(value)) return value.map((item) => this.walk(item));
55
- if (value !== null && typeof value === "object") {
56
- const redactedThinking = value.type === "redacted_thinking";
57
- return Object.fromEntries(
58
- Object.entries(value).map(([k, v]) => [
59
- k,
60
- (OPAQUE_KEYS.has(k) || redactedThinking && k === "data") && typeof v === "string" ? v : this.walk(v)
61
- ])
62
- );
63
- }
64
- return value;
65
- }
66
- };
67
-
68
- // src/tools/atomicWrite.ts
69
- import { randomBytes } from "crypto";
70
- import { chmod, link, realpath, rename, stat, unlink, writeFile } from "fs/promises";
71
- import { basename, dirname, join } from "path";
72
- async function writeFileAtomic(path, content, { createOnly }) {
73
- const target = createOnly ? path : await realpath(path);
74
- const temp = join(
75
- dirname(target),
76
- `.${basename(target)}.garuda-${randomBytes(4).toString("hex")}.tmp`
77
- );
78
- const mode = createOnly ? void 0 : (await stat(target)).mode & 4095;
79
- await writeFile(temp, content, { flag: "wx", ...mode === void 0 ? {} : { mode } });
80
- try {
81
- if (createOnly) {
82
- try {
83
- await link(temp, target);
84
- } catch (error) {
85
- const code = error.code;
86
- if (code !== "EPERM" && code !== "ENOTSUP" && code !== "EXDEV") throw error;
87
- if (await exists(target)) throw Object.assign(new Error("EEXIST"), { code: "EEXIST" });
88
- await rename(temp, target);
89
- return;
90
- }
91
- } else {
92
- await chmod(temp, mode ?? 420);
93
- await rename(temp, target);
94
- return;
95
- }
96
- } finally {
97
- await unlink(temp).catch(() => {
98
- });
99
- }
100
- }
101
- async function exists(path) {
102
- try {
103
- await stat(path);
104
- return true;
105
- } catch {
106
- return false;
107
- }
108
- }
109
-
110
- export {
111
- REDACTED,
112
- keepSecretForRedaction,
113
- Redactor,
114
- writeFileAtomic
115
- };
116
- //# sourceMappingURL=chunk-EIXUSVFX.js.map
@@ -1,71 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- EFFORTS
4
- } from "./chunk-3EQU2GUX.js";
5
-
6
- // src/model/pricing.ts
7
- var DEFAULT_CONTEXT_WINDOW = 2e5;
8
- var M = 1e6;
9
- var ALWAYS = { mode: "always", efforts: EFFORTS };
10
- var OPTIONAL = { mode: "optional", efforts: EFFORTS };
11
- var OPTIONAL_46 = {
12
- mode: "optional",
13
- efforts: EFFORTS.filter((e) => e !== "xhigh")
14
- };
15
- var KNOWN = [
16
- ["claude-fable-5-1", { price: p(10, 50, 0.25, 12.5), contextWindow: M, thinking: ALWAYS }],
17
- ["claude-fable-5", { price: p(10, 50, 1, 12.5), contextWindow: M, thinking: ALWAYS }],
18
- ["claude-opus-5-5", { price: p(4, 20, 0.2, 5), contextWindow: M, thinking: ALWAYS }],
19
- ["claude-opus-5", { price: p(5, 25, 0.5, 6.25), contextWindow: M, thinking: ALWAYS }],
20
- ["claude-opus-4-8", { price: p(5, 25, 0.5, 6.25), contextWindow: M, thinking: OPTIONAL }],
21
- ["claude-opus-4-7", { price: p(5, 25, 0.5, 6.25), contextWindow: M, thinking: OPTIONAL }],
22
- ["claude-opus-4-6", { price: p(5, 25, 0.5, 6.25), contextWindow: M, thinking: OPTIONAL_46 }],
23
- ["claude-opus-4-5", { price: p(5, 25, 0.5, 6.25), contextWindow: 2e5 }],
24
- ["claude-sonnet-5", { price: p(2, 10, 0.2, 2.5), contextWindow: M, thinking: ALWAYS }],
25
- ["claude-sonnet-4-6", { price: p(3, 15, 0.3, 3.75), contextWindow: M, thinking: OPTIONAL_46 }],
26
- ["claude-sonnet-4-5", { price: p(3, 15, 0.3, 3.75), contextWindow: 2e5 }],
27
- ["claude-haiku-4-5", { price: p(1, 5, 0.1, 1.25), contextWindow: 2e5 }]
28
- ];
29
- function p(input, output, cacheRead, cacheWrite) {
30
- return { input, output, cacheRead, cacheWrite };
31
- }
32
- function aliasModel(alias) {
33
- if (!/^(haiku|sonnet|opus|fable)$/.test(alias)) return void 0;
34
- return KNOWN.find(([prefix]) => prefix.startsWith(`claude-${alias}-`))?.[0];
35
- }
36
- function knownModels() {
37
- return KNOWN.map(([id, info]) => ({ id, info }));
38
- }
39
- function lookupModel(modelId) {
40
- let best;
41
- for (const [prefix, info] of KNOWN) {
42
- if (modelId.startsWith(prefix) && prefix.length > (best?.prefix.length ?? 0)) {
43
- best = { prefix, info };
44
- }
45
- }
46
- return best?.info ?? { contextWindow: DEFAULT_CONTEXT_WINDOW };
47
- }
48
- var WEB_SEARCH_USD = 0.01;
49
- function costOf(usage, price, factor = 1) {
50
- return (usage.inputTokens * price.input + usage.outputTokens * price.output + usage.cacheReadTokens * price.cacheRead + usage.cacheWriteTokens * price.cacheWrite) / M * factor + (usage.webSearches ?? 0) * WEB_SEARCH_USD;
51
- }
52
- function responseCost(response, price) {
53
- return costOf(response.usage, price, response.priceFactor ?? 1);
54
- }
55
- function totalTokens(usage) {
56
- return usage.inputTokens + usage.outputTokens + usage.cacheReadTokens + usage.cacheWriteTokens;
57
- }
58
- function contextSize(usage) {
59
- return totalTokens(usage);
60
- }
61
-
62
- export {
63
- aliasModel,
64
- knownModels,
65
- lookupModel,
66
- WEB_SEARCH_USD,
67
- responseCost,
68
- totalTokens,
69
- contextSize
70
- };
71
- //# sourceMappingURL=chunk-R7I2NBPX.js.map
@@ -1,107 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- cleanLine
4
- } from "./chunk-PZS3V6P3.js";
5
- import {
6
- formatRule
7
- } from "./chunk-3NJNVZTK.js";
8
-
9
- // src/permissions/projectSettings.ts
10
- import { createHash } from "crypto";
11
- function settingsRisk(settings) {
12
- const risk = {
13
- executorHost: settings.executor === "host",
14
- allow: settings.allow.map(formatRule),
15
- writePaths: [...settings.sandbox?.writePaths ?? []],
16
- envAllow: [...settings.envAllow],
17
- allowLocalhost: settings.web?.allowLocalhost === true
18
- };
19
- const formatterCommands = Object.entries(settings.formatters?.commands ?? {}).flatMap(
20
- ([name, f]) => f === false ? [] : [`${name}: ${f.command.join(" ")}`]
21
- );
22
- if (formatterCommands.length > 0) risk.formatterCommands = formatterCommands;
23
- const none = !risk.executorHost && risk.allow.length === 0 && risk.writePaths.length === 0 && risk.envAllow.length === 0 && !risk.allowLocalhost && risk.formatterCommands === void 0;
24
- return none ? void 0 : risk;
25
- }
26
- function settingsRiskHash(risk) {
27
- return createHash("sha256").update(JSON.stringify(risk)).digest("hex");
28
- }
29
- function settingsRiskLines(risk) {
30
- const lines = [];
31
- if (risk.executorHost) lines.push('executor: "host" (commands run with no OS sandbox)');
32
- if (risk.allow.length > 0) {
33
- lines.push(`permissions.allow (no question for these): ${risk.allow.join(", ")}`);
34
- }
35
- if (risk.writePaths.length > 0) {
36
- lines.push(`sandbox.writePaths (commands may write there): ${risk.writePaths.join(", ")}`);
37
- }
38
- if (risk.envAllow.length > 0) {
39
- lines.push(`env.allow (commands see these variables): ${risk.envAllow.join(", ")}`);
40
- }
41
- if (risk.allowLocalhost) lines.push("web.allowLocalhost (web_fetch may reach this machine)");
42
- if (risk.formatterCommands !== void 0) {
43
- lines.push(
44
- `formatters.commands (run after each edit): ${risk.formatterCommands.map(cleanLine).join("; ")}`
45
- );
46
- }
47
- return lines;
48
- }
49
- function withoutRisk(settings) {
50
- const { sandbox, web, formatters, ...rest } = settings;
51
- const { writePaths: _writePaths, ...sandboxRest } = sandbox ?? {};
52
- const keptCommands = Object.fromEntries(
53
- Object.entries(formatters?.commands ?? {}).filter(([, f]) => f === false)
54
- );
55
- return {
56
- ...rest,
57
- ...formatters === void 0 ? {} : { formatters: { ...formatters, commands: keptCommands } },
58
- executor: settings.executor === "host" ? "auto" : settings.executor,
59
- allow: [],
60
- envAllow: [],
61
- ...sandbox === void 0 ? {} : { sandbox: sandboxRest },
62
- ...web === void 0 ? {} : { web: { ...web, allowLocalhost: false } }
63
- };
64
- }
65
- async function gateProjectSettings(options) {
66
- const risk = settingsRisk(options.settings);
67
- if (risk === void 0) return { settings: options.settings };
68
- const hash = settingsRiskHash(risk);
69
- const known = options.trust?.settingsHash(options.root);
70
- if (known === hash) return { settings: options.settings };
71
- const lines = settingsRiskLines(risk);
72
- if (options.ask !== void 0) {
73
- const choice = await options.ask({
74
- tool: "settings",
75
- target: { kind: "input", json: "" },
76
- title: "Project settings that loosen safety",
77
- preview: [
78
- `This project's .garuda/settings.json ${known === void 0 ? "asks for" : "changed and now asks for"}:`,
79
- ...lines.map((line) => ` - ${line}`),
80
- "A cloned repository can ship this file. Without your yes, Garuda uses safe defaults for these",
81
- "parts; the rest of the file applies."
82
- ].join("\n"),
83
- isolation: options.isolation ?? "os",
84
- question: "Use these project settings?",
85
- choices: ["once", "session", "deny"],
86
- labels: {
87
- once: "Yes, for this run",
88
- session: "Yes, and remember (asks again when they change)",
89
- deny: "No, use safe defaults"
90
- }
91
- });
92
- if (choice === "session") await options.trust?.setSettingsHash(options.root, hash);
93
- if (choice !== "deny") return { settings: options.settings };
94
- }
95
- return {
96
- settings: withoutRisk(options.settings),
97
- notice: [
98
- `Project settings not applied (not approved): ${lines.join("; ")}.`,
99
- "Start the chat in a terminal and answer yes to use them."
100
- ].join(" ")
101
- };
102
- }
103
-
104
- export {
105
- gateProjectSettings
106
- };
107
- //# sourceMappingURL=chunk-ULAJPMY7.js.map
@@ -1,9 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- // src/version.ts
4
- var VERSION = "0.16.1";
5
-
6
- export {
7
- VERSION
8
- };
9
- //# sourceMappingURL=chunk-VBZCNMUD.js.map
@@ -1,18 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- INSTALL_TIMEOUT_MS,
4
- installCommand,
5
- installServer
6
- } from "./chunk-B6FA4I7Q.js";
7
- import "./chunk-EU7PA45O.js";
8
- import "./chunk-GXZACJUI.js";
9
- import "./chunk-WMOLXTBU.js";
10
- import "./chunk-3EQU2GUX.js";
11
- import "./chunk-HUIK3WXO.js";
12
- import "./chunk-3NJNVZTK.js";
13
- export {
14
- INSTALL_TIMEOUT_MS,
15
- installCommand,
16
- installServer
17
- };
18
- //# sourceMappingURL=install-EWDSPFFZ.js.map
@@ -1,32 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- JOB_TEST_TIMEOUT_MS,
4
- finishJob,
5
- msUntil,
6
- prepareJob,
7
- testsBefore
8
- } from "./chunk-HE2K657U.js";
9
- import "./chunk-N4I6YS3E.js";
10
- import "./chunk-ULAJPMY7.js";
11
- import "./chunk-R7I2NBPX.js";
12
- import "./chunk-5DEWP3YX.js";
13
- import "./chunk-PZS3V6P3.js";
14
- import "./chunk-44QN5SWZ.js";
15
- import "./chunk-USCUXCAU.js";
16
- import "./chunk-YQTGMCU6.js";
17
- import "./chunk-OUCV3FCT.js";
18
- import "./chunk-TUUEBHG2.js";
19
- import "./chunk-GXZACJUI.js";
20
- import "./chunk-WMOLXTBU.js";
21
- import "./chunk-3EQU2GUX.js";
22
- import "./chunk-HUIK3WXO.js";
23
- import "./chunk-KKB5W47S.js";
24
- import "./chunk-3NJNVZTK.js";
25
- export {
26
- JOB_TEST_TIMEOUT_MS,
27
- finishJob,
28
- msUntil,
29
- prepareJob,
30
- testsBefore
31
- };
32
- //# sourceMappingURL=jobCommand-ACSGSBQ4.js.map
@@ -1,11 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- jobPrompt,
4
- jobReport
5
- } from "./chunk-YQTGMCU6.js";
6
- import "./chunk-OUCV3FCT.js";
7
- export {
8
- jobPrompt,
9
- jobReport
10
- };
11
- //# sourceMappingURL=text-J2GD647J.js.map