@garuda-agent/garuda 0.14.1 → 0.16.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 (38) hide show
  1. package/CHANGELOG.md +49 -1
  2. package/README.md +78 -8
  3. package/dist/acpCommand-AJJBKAE5.js +191 -0
  4. package/dist/chunk-23FXBNBB.js +46 -0
  5. package/dist/chunk-3EQU2GUX.js +27 -0
  6. package/dist/{chunk-YIZWYUBG.js → chunk-44QN5SWZ.js} +2 -2
  7. package/dist/chunk-4JSUUDFQ.js +118 -0
  8. package/dist/{chunk-KWRJREUH.js → chunk-B25VL4RU.js} +1 -42
  9. package/dist/{chunk-U4OQVT2T.js → chunk-B6FA4I7Q.js} +2 -2
  10. package/dist/chunk-EIXUSVFX.js +116 -0
  11. package/dist/{chunk-YM6T4J5V.js → chunk-ENLDPN4S.js} +8 -111
  12. package/dist/{chunk-D5O5CIWK.js → chunk-GXZACJUI.js} +8 -25
  13. package/dist/{chunk-QOW5TK4L.js → chunk-HE2K657U.js} +9 -7
  14. package/dist/chunk-NP6RIC25.js +331 -0
  15. package/dist/chunk-NXJ4XLB5.js +19 -0
  16. package/dist/chunk-R7I2NBPX.js +71 -0
  17. package/dist/{chunk-ZGZ2ZADL.js → chunk-TUUEBHG2.js} +2 -2
  18. package/dist/{chunk-W7BPYQMW.js → chunk-ULAJPMY7.js} +1 -67
  19. package/dist/{chunk-35GMLLJW.js → chunk-USCUXCAU.js} +2 -2
  20. package/dist/{chunk-ITITLNAR.js → chunk-WIJL72ZE.js} +150 -234
  21. package/dist/chunk-XOK5OZOC.js +9 -0
  22. package/dist/cli/index.js +68 -39
  23. package/dist/{create-Y5SXJUXO.js → create-VXIH2GUZ.js} +6 -5
  24. package/dist/{evalCommand-5TG2CKZY.js → evalCommand-OX2LQYEK.js} +35 -18
  25. package/dist/{inkChat-3J26R24L.js → inkChat-YMMMGU7Y.js} +16 -10
  26. package/dist/{install-XWLU22OH.js → install-EWDSPFFZ.js} +4 -3
  27. package/dist/{jobCommand-IYWZWTSI.js → jobCommand-ACSGSBQ4.js} +9 -7
  28. package/dist/{launchd-2FL5UN2U.js → launchd-SSX362VG.js} +5 -4
  29. package/dist/{lspCommand-TJEZBV2E.js → lspCommand-JRXKRSL7.js} +4 -3
  30. package/dist/{manager-EBTYO2GR.js → manager-AWU4NHHK.js} +4 -3
  31. package/dist/{nightCommand-DUNWJASI.js → nightCommand-65MUEV32.js} +9 -7
  32. package/dist/{remove-AENULZZE.js → remove-6GDSTAIO.js} +4 -3
  33. package/dist/{run-66Y6R2KU.js → run-ML6GSPN4.js} +5 -3
  34. package/dist/server-KHHNHUYV.js +694 -0
  35. package/dist/setupCommand-VA7D5MZK.js +303 -0
  36. package/package.json +2 -1
  37. package/dist/chunk-6TWBYMY7.js +0 -9
  38. package/dist/chunk-V7WPGQLB.js +0 -207
@@ -1,32 +1,41 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ loadLspConfig
4
+ } from "./chunk-G2AX7MGS.js";
2
5
  import {
3
6
  hasServerBlocks,
4
7
  serverCallText,
5
8
  serverPairText,
6
9
  withoutServerBlocks
7
10
  } from "./chunk-A2QAIRQL.js";
11
+ import {
12
+ gateProjectSettings
13
+ } from "./chunk-ULAJPMY7.js";
14
+ import {
15
+ REDACTED,
16
+ Redactor,
17
+ writeFileAtomic
18
+ } from "./chunk-EIXUSVFX.js";
8
19
  import {
9
20
  aliasModel,
10
21
  contextSize,
11
- gateProjectSettings,
12
22
  knownModels,
13
23
  lookupModel,
14
24
  responseCost,
15
25
  totalTokens
16
- } from "./chunk-W7BPYQMW.js";
17
- import {
18
- loadLspConfig
19
- } from "./chunk-G2AX7MGS.js";
26
+ } from "./chunk-R7I2NBPX.js";
20
27
  import {
21
- BUILTIN_COMMANDS,
22
28
  MAX_RESULTS,
23
29
  providerLabel,
24
30
  saveSearchUse,
25
31
  search
26
- } from "./chunk-KWRJREUH.js";
32
+ } from "./chunk-B25VL4RU.js";
33
+ import {
34
+ BUILTIN_COMMANDS
35
+ } from "./chunk-23FXBNBB.js";
27
36
  import {
28
37
  VERSION
29
- } from "./chunk-6TWBYMY7.js";
38
+ } from "./chunk-XOK5OZOC.js";
30
39
  import {
31
40
  TrustStore
32
41
  } from "./chunk-5DEWP3YX.js";
@@ -50,24 +59,26 @@ import {
50
59
  } from "./chunk-OUCV3FCT.js";
51
60
  import {
52
61
  DEFAULT_ENV_ALLOWLIST,
53
- EFFORTS,
54
62
  NETWORK_PORTS,
55
63
  PermissionEngine,
56
- ZERO_USAGE,
57
- addUsage,
58
64
  createExecutor,
59
65
  describeAllowlist,
60
66
  expandAllowlist,
61
67
  hostAllowed,
62
68
  isSensitive,
63
69
  loadSettings
64
- } from "./chunk-D5O5CIWK.js";
70
+ } from "./chunk-GXZACJUI.js";
65
71
  import {
66
72
  PathOutsideRootError,
67
73
  displayPath,
68
74
  isInside,
69
75
  resolveInRoot
70
76
  } from "./chunk-WMOLXTBU.js";
77
+ import {
78
+ EFFORTS,
79
+ ZERO_USAGE,
80
+ addUsage
81
+ } from "./chunk-3EQU2GUX.js";
71
82
  import {
72
83
  assertModelAllowedByPolicy,
73
84
  ignoredProjectPolicy,
@@ -84,71 +95,6 @@ import { randomBytes } from "crypto";
84
95
  import { appendFileSync, mkdirSync } from "fs";
85
96
  import { readdir, readFile, rm, stat, utimes } from "fs/promises";
86
97
  import { basename, join } from "path";
87
-
88
- // src/session/redact.ts
89
- var REDACTED = "[REDACTED]";
90
- var PATTERNS = [
91
- /-----BEGIN [A-Z0-9 ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z0-9 ]*PRIVATE KEY-----/g,
92
- /sk-ant-[A-Za-z0-9_-]{16,}/g,
93
- /\bsk-(?:proj-)?[A-Za-z0-9_-]{20,}/g,
94
- /\bAKIA[0-9A-Z]{16}\b/g,
95
- /\bgh[pousr]_[A-Za-z0-9]{30,}\b/g,
96
- /\bgithub_pat_[A-Za-z0-9_]{30,}\b/g,
97
- /\bxox[abprs]-[A-Za-z0-9-]{10,}/g,
98
- /\bAIza[0-9A-Za-z_-]{35}\b/g,
99
- /\beyJ[A-Za-z0-9_-]{10,}\.eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}/g
100
- ];
101
- var ASSIGNMENT = /\b([A-Za-z0-9_]*(?:api[_-]?key|secret|token|password|passwd)[A-Za-z0-9_]*)(["']?\s*[:=]\s*["']?)([^\s"'`,;]{8,})/gi;
102
- var OPAQUE_KEYS = /* @__PURE__ */ new Set(["encrypted_content", "encrypted_index", "signature"]);
103
- function looksLikeCode(name, value, next) {
104
- if (/^[\d_.]+$/.test(value)) return !/pass|secret/i.test(name);
105
- if (value.includes("(") || next === "(") return true;
106
- return /^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)+$/.test(value) && !/\d{4,}/.test(value);
107
- }
108
- var SECRET_ENV_NAME = /(KEY|TOKEN|SECRET|PASSWORD|PASSWD|CREDENTIAL)/i;
109
- var movedSecrets = /* @__PURE__ */ new Map();
110
- function keepSecretForRedaction(name, value) {
111
- movedSecrets.set(name, value);
112
- }
113
- var Redactor = class {
114
- literals;
115
- /**
116
- * `env`: variables whose names look secret have their values removed wherever they appear.
117
- * Default: this process's environment and the secrets moved out of it.
118
- */
119
- constructor(env = { ...process.env, ...Object.fromEntries(movedSecrets) }) {
120
- this.literals = Object.entries(env).filter(([name, value]) => SECRET_ENV_NAME.test(name) && (value?.length ?? 0) >= 8).map(([, value]) => value).sort((a, b) => b.length - a.length);
121
- }
122
- text(input12) {
123
- let out = input12;
124
- for (const literal of this.literals) out = out.split(literal).join(REDACTED);
125
- for (const pattern of PATTERNS) out = out.replace(pattern, REDACTED);
126
- return out.replace(
127
- ASSIGNMENT,
128
- (all, name, sep4, value, at) => looksLikeCode(name, value, out[at + all.length]) ? all : `${name}${sep4}${REDACTED}`
129
- );
130
- }
131
- /** A copy of `value` with every string redacted. */
132
- value(value) {
133
- return this.walk(value);
134
- }
135
- walk(value) {
136
- if (typeof value === "string") return this.text(value);
137
- if (Array.isArray(value)) return value.map((item) => this.walk(item));
138
- if (value !== null && typeof value === "object") {
139
- const redactedThinking = value.type === "redacted_thinking";
140
- return Object.fromEntries(
141
- Object.entries(value).map(([k, v]) => [
142
- k,
143
- (OPAQUE_KEYS.has(k) || redactedThinking && k === "data") && typeof v === "string" ? v : this.walk(v)
144
- ])
145
- );
146
- }
147
- return value;
148
- }
149
- };
150
-
151
- // src/session/store.ts
152
98
  var SESSIONS_DIR = join(".garuda", "sessions");
153
99
  var FileSessionStore = class {
154
100
  dir;
@@ -1392,15 +1338,22 @@ ${z.prettifyError(parsed.error)}`,
1392
1338
  }
1393
1339
  const readOnly = tool.readOnly && info?.mutates !== true;
1394
1340
  const decision = await context.permissions.check(
1395
- info === void 0 ? { tool: tool.name, readOnly } : { tool: tool.name, readOnly, info },
1341
+ {
1342
+ tool: tool.name,
1343
+ readOnly,
1344
+ ...info === void 0 ? {} : { info },
1345
+ // The question names this call (0.15: ACP shows it next to the right tool call).
1346
+ callId: call.id
1347
+ },
1396
1348
  context.signal
1397
1349
  );
1398
1350
  if (!decision.allowed) {
1399
1351
  return { content: `Permission denied: ${decision.reason}`, isError: true, denied: true };
1400
1352
  }
1401
1353
  startTime = Date.now();
1402
- const runContext = decision.hunks === void 0 ? context : {
1354
+ const runContext = decision.hunks === void 0 ? { ...context, callId: call.id } : {
1403
1355
  ...context,
1356
+ callId: call.id,
1404
1357
  approvedHunks: decision.hunks,
1405
1358
  ...info?.preview === void 0 ? {} : { approvedPreview: info.preview }
1406
1359
  };
@@ -1927,50 +1880,6 @@ var repoMapTool = {
1927
1880
  // src/tools/editFile.ts
1928
1881
  import { readFile as readFile3 } from "fs/promises";
1929
1882
  import { z as z4 } from "zod";
1930
-
1931
- // src/tools/atomicWrite.ts
1932
- import { randomBytes as randomBytes3 } from "crypto";
1933
- import { chmod, link, realpath, rename, stat as stat2, unlink, writeFile } from "fs/promises";
1934
- import { basename as basename3, dirname, join as join4 } from "path";
1935
- async function writeFileAtomic(path, content, { createOnly }) {
1936
- const target = createOnly ? path : await realpath(path);
1937
- const temp = join4(
1938
- dirname(target),
1939
- `.${basename3(target)}.garuda-${randomBytes3(4).toString("hex")}.tmp`
1940
- );
1941
- const mode = createOnly ? void 0 : (await stat2(target)).mode & 4095;
1942
- await writeFile(temp, content, { flag: "wx", ...mode === void 0 ? {} : { mode } });
1943
- try {
1944
- if (createOnly) {
1945
- try {
1946
- await link(temp, target);
1947
- } catch (error) {
1948
- const code = error.code;
1949
- if (code !== "EPERM" && code !== "ENOTSUP" && code !== "EXDEV") throw error;
1950
- if (await exists(target)) throw Object.assign(new Error("EEXIST"), { code: "EEXIST" });
1951
- await rename(temp, target);
1952
- return;
1953
- }
1954
- } else {
1955
- await chmod(temp, mode ?? 420);
1956
- await rename(temp, target);
1957
- return;
1958
- }
1959
- } finally {
1960
- await unlink(temp).catch(() => {
1961
- });
1962
- }
1963
- }
1964
- async function exists(path) {
1965
- try {
1966
- await stat2(path);
1967
- return true;
1968
- } catch {
1969
- return false;
1970
- }
1971
- }
1972
-
1973
- // src/tools/editFile.ts
1974
1883
  var input2 = z4.object({
1975
1884
  path: z4.string().min(1).describe("File path, relative to the working root."),
1976
1885
  old_string: z4.string().min(1).describe("The exact text to replace. It must occur exactly once in the file."),
@@ -1994,6 +1903,7 @@ var editFileTool = {
1994
1903
  return {
1995
1904
  target: { kind: "path", path: edit.shown },
1996
1905
  preview,
1906
+ change: { path: edit.absolute, oldText: edit.before, newText: edit.after },
1997
1907
  // Hunk-by-hunk approval only when the user sees every hunk (U0).
1998
1908
  ...previewIsComplete(preview) ? { hunks: true } : {}
1999
1909
  };
@@ -2075,11 +1985,11 @@ function countOccurrences(text, search3) {
2075
1985
  }
2076
1986
 
2077
1987
  // src/tools/glob.ts
2078
- import { stat as stat4 } from "fs/promises";
1988
+ import { stat as stat3 } from "fs/promises";
2079
1989
  import { z as z5 } from "zod";
2080
1990
 
2081
1991
  // src/tools/files.ts
2082
- import { stat as stat3 } from "fs/promises";
1992
+ import { stat as stat2 } from "fs/promises";
2083
1993
  import { globby } from "globby";
2084
1994
  async function listFiles(base, pattern, root) {
2085
1995
  assertSafePattern(pattern);
@@ -2104,7 +2014,7 @@ function assertSafePattern(pattern) {
2104
2014
  }
2105
2015
  async function isDirectory(path) {
2106
2016
  try {
2107
- return (await stat3(path)).isDirectory();
2017
+ return (await stat2(path)).isDirectory();
2108
2018
  } catch {
2109
2019
  return false;
2110
2020
  }
@@ -2130,7 +2040,7 @@ var globTool = {
2130
2040
  (p) => !permissions.deniedByPolicy(displayPath(root, p))
2131
2041
  );
2132
2042
  const withTimes = await Promise.all(
2133
- paths.map(async (p) => ({ p, mtime: (await stat4(p).catch(() => void 0))?.mtimeMs ?? 0 }))
2043
+ paths.map(async (p) => ({ p, mtime: (await stat3(p).catch(() => void 0))?.mtimeMs ?? 0 }))
2134
2044
  );
2135
2045
  withTimes.sort((a, b) => b.mtime - a.mtime || a.p.localeCompare(b.p));
2136
2046
  return {
@@ -2148,7 +2058,7 @@ var globTool = {
2148
2058
  };
2149
2059
 
2150
2060
  // src/tools/grep.ts
2151
- import { lstat, readFile as readFile4, realpath as realpath2, stat as stat5 } from "fs/promises";
2061
+ import { lstat, readFile as readFile4, realpath, stat as stat4 } from "fs/promises";
2152
2062
  import { z as z6 } from "zod";
2153
2063
 
2154
2064
  // src/tools/regexWorker.ts
@@ -2298,13 +2208,13 @@ async function search2(args, root, signal, permissions, matcher, mode, max, cont
2298
2208
  const shownPath = displayPath(root, file2);
2299
2209
  if (isSensitive(shownPath) || permissions.deniedByPolicy(shownPath)) continue;
2300
2210
  if ((await lstat(file2).catch(() => void 0))?.isSymbolicLink() === true) {
2301
- realRoot ??= await realpath2(root);
2302
- const real = await realpath2(file2).catch(() => void 0);
2211
+ realRoot ??= await realpath(root);
2212
+ const real = await realpath(file2).catch(() => void 0);
2303
2213
  if (real === void 0 || !isInside(realRoot, real)) continue;
2304
2214
  const realShown = displayPath(realRoot, real);
2305
2215
  if (isSensitive(realShown) || permissions.deniedByPolicy(realShown)) continue;
2306
2216
  }
2307
- const info = await stat5(file2).catch(() => void 0);
2217
+ const info = await stat4(file2).catch(() => void 0);
2308
2218
  if (info === void 0 || !info.isFile() || info.size > LIMITS.grepFileBytes) continue;
2309
2219
  const buffer = await readFile4(file2);
2310
2220
  if (looksBinary(buffer)) continue;
@@ -2577,7 +2487,7 @@ var processManagerTool = {
2577
2487
  };
2578
2488
 
2579
2489
  // src/tools/readFile.ts
2580
- import { readFile as readFile5, stat as stat6 } from "fs/promises";
2490
+ import { readFile as readFile5, stat as stat5 } from "fs/promises";
2581
2491
  import { z as z9 } from "zod";
2582
2492
  var input6 = z9.object({
2583
2493
  path: z9.string().min(1).describe("File path, relative to the working root."),
@@ -2599,7 +2509,7 @@ var readFileTool = {
2599
2509
  async run({ path, offset = 1, limit = LIMITS.readLines }, { root, files }) {
2600
2510
  const absolute = await resolveInRoot(root, path);
2601
2511
  const shown = displayPath(root, absolute);
2602
- const info = await stat6(absolute).catch(() => void 0);
2512
+ const info = await stat5(absolute).catch(() => void 0);
2603
2513
  if (info === void 0) throw new Error(`${shown} does not exist.`);
2604
2514
  if (info.isDirectory()) throw new Error(`${shown} is a folder. Use glob to list its files.`);
2605
2515
  if (info.size > LIMITS.readFileBytes) {
@@ -2632,23 +2542,23 @@ var readFileTool = {
2632
2542
 
2633
2543
  // src/tools/remember.ts
2634
2544
  import { mkdir as mkdir2, readFile as readFile7 } from "fs/promises";
2635
- import { dirname as dirname2 } from "path";
2545
+ import { dirname } from "path";
2636
2546
  import { z as z10 } from "zod";
2637
2547
 
2638
2548
  // src/context/instructions.ts
2639
- import { readFile as readFile6, realpath as realpath3 } from "fs/promises";
2640
- import { join as join5 } from "path";
2549
+ import { readFile as readFile6, realpath as realpath2 } from "fs/promises";
2550
+ import { join as join4 } from "path";
2641
2551
  async function readInRoot(root, name) {
2642
- const file2 = join5(root, name);
2552
+ const file2 = join4(root, name);
2643
2553
  let real;
2644
2554
  try {
2645
- real = await realpath3(file2);
2555
+ real = await realpath2(file2);
2646
2556
  } catch (error) {
2647
2557
  const code = error.code;
2648
2558
  if (code === "ENOENT" || code === "ENOTDIR") return void 0;
2649
2559
  throw error;
2650
2560
  }
2651
- if (!isInside(await realpath3(root), real)) return void 0;
2561
+ if (!isInside(await realpath2(root), real)) return void 0;
2652
2562
  try {
2653
2563
  return await readFile6(real, "utf8");
2654
2564
  } catch (error) {
@@ -2862,7 +2772,7 @@ var rememberTool = {
2862
2772
  `The project memory is full (${MEMORY_MAX_CHARS} characters). Ask the user to clean up ${MEMORY_FILE}.`
2863
2773
  );
2864
2774
  }
2865
- await mkdir2(dirname2(path), { recursive: true });
2775
+ await mkdir2(dirname(path), { recursive: true });
2866
2776
  await writeFileAtomic(path, next, { createOnly: current === "" });
2867
2777
  return `Saved to ${MEMORY_FILE}. It loads in the next session.`;
2868
2778
  }
@@ -3183,7 +3093,8 @@ function createWebFetchTool(options = {}) {
3183
3093
  target: { kind: "url", url: next.toString(), host: next.hostname },
3184
3094
  preview: ` GET ${next.toString()}
3185
3095
  (a redirect from ${new URL(key).host})`
3186
- }
3096
+ },
3097
+ ...context.callId === void 0 ? {} : { callId: context.callId }
3187
3098
  },
3188
3099
  context.signal
3189
3100
  );
@@ -3224,7 +3135,7 @@ function pageText(page, start, maxChars) {
3224
3135
 
3225
3136
  // src/tools/writeFile.ts
3226
3137
  import { mkdir as mkdir3 } from "fs/promises";
3227
- import { dirname as dirname3 } from "path";
3138
+ import { dirname as dirname2 } from "path";
3228
3139
  import { z as z13 } from "zod";
3229
3140
  var input9 = z13.object({
3230
3141
  path: z13.string().min(1).describe("Path of the new file, relative to the working root."),
@@ -3240,14 +3151,20 @@ var writeFileTool = {
3240
3151
  inputSchema: input9,
3241
3152
  readOnly: false,
3242
3153
  async describe({ path, content }, { root }) {
3243
- const shown = displayPath(root, await resolveInRoot(root, path));
3244
- return { target: { kind: "path", path: shown }, preview: unifiedDiff(shown, "", content) };
3154
+ const absolute = await resolveInRoot(root, path);
3155
+ const shown = displayPath(root, absolute);
3156
+ return {
3157
+ target: { kind: "path", path: shown },
3158
+ preview: unifiedDiff(shown, "", content),
3159
+ // write_file only creates files, so there is no old text (0.15: ACP's diff view).
3160
+ change: { path: absolute, oldText: null, newText: content }
3161
+ };
3245
3162
  },
3246
3163
  async run({ path, content }, context) {
3247
3164
  const { root, files } = context;
3248
3165
  const absolute = await resolveInRoot(root, path);
3249
3166
  const shown = displayPath(root, absolute);
3250
- await mkdir3(dirname3(absolute), { recursive: true });
3167
+ await mkdir3(dirname2(absolute), { recursive: true });
3251
3168
  try {
3252
3169
  await writeFileAtomic(absolute, content, { createOnly: true });
3253
3170
  } catch (error) {
@@ -3300,7 +3217,7 @@ function defaultTools({
3300
3217
  // src/app/runtime.ts
3301
3218
  import { readFile as readFile16 } from "fs/promises";
3302
3219
  import { homedir as homedir4 } from "os";
3303
- import { join as join18 } from "path";
3220
+ import { join as join17 } from "path";
3304
3221
 
3305
3222
  // src/agents/agentTool.ts
3306
3223
  import { z as z14 } from "zod";
@@ -3461,7 +3378,7 @@ function describeCall(call) {
3461
3378
  // src/agents/custom.ts
3462
3379
  import { createHash as createHash3 } from "crypto";
3463
3380
  import { lstat as lstat2, readdir as readdir3, readFile as readFile8 } from "fs/promises";
3464
- import { join as join6 } from "path";
3381
+ import { join as join5 } from "path";
3465
3382
 
3466
3383
  // src/skills/frontmatter.ts
3467
3384
  function parseFrontmatterBlock(text) {
@@ -3548,10 +3465,10 @@ var READ_ONLY_AGENT_TOOLS = [
3548
3465
  ];
3549
3466
  function agentDirs(home, root) {
3550
3467
  return [
3551
- { dir: join6(home, ".garuda", "agents"), shown: "~/.garuda/agents", source: "user" },
3552
- { dir: join6(home, ".claude", "agents"), shown: "~/.claude/agents", source: "user" },
3553
- { dir: join6(root, ".garuda", "agents"), shown: ".garuda/agents", source: "project" },
3554
- { dir: join6(root, ".claude", "agents"), shown: ".claude/agents", source: "project" }
3468
+ { dir: join5(home, ".garuda", "agents"), shown: "~/.garuda/agents", source: "user" },
3469
+ { dir: join5(home, ".claude", "agents"), shown: "~/.claude/agents", source: "user" },
3470
+ { dir: join5(root, ".garuda", "agents"), shown: ".garuda/agents", source: "project" },
3471
+ { dir: join5(root, ".claude", "agents"), shown: ".claude/agents", source: "project" }
3555
3472
  ];
3556
3473
  }
3557
3474
  async function loadAgents(options) {
@@ -3568,7 +3485,7 @@ async function loadAgents(options) {
3568
3485
  continue;
3569
3486
  }
3570
3487
  for (const entry of entries) {
3571
- const file2 = join6(place.dir, entry);
3488
+ const file2 = join5(place.dir, entry);
3572
3489
  const shown = `${place.shown}/${entry}`;
3573
3490
  try {
3574
3491
  const info = await lstat2(file2);
@@ -4151,16 +4068,16 @@ function createMoeDispatchTool(options) {
4151
4068
 
4152
4069
  // src/commands/custom.ts
4153
4070
  import { createHash as createHash4 } from "crypto";
4154
- import { lstat as lstat3, readdir as readdir4, readFile as readFile9, stat as stat7 } from "fs/promises";
4155
- import { join as join7, relative, sep } from "path";
4156
- var COMMANDS_DIR = join7(".garuda", "commands");
4071
+ import { lstat as lstat3, readdir as readdir4, readFile as readFile9, stat as stat6 } from "fs/promises";
4072
+ import { join as join6, relative, sep } from "path";
4073
+ var COMMANDS_DIR = join6(".garuda", "commands");
4157
4074
  var COMMAND_MAX_CHARS = 2e4;
4158
4075
  var MAX_FILES = 200;
4159
4076
  var NAME = /^[a-z0-9][a-z0-9_-]*(?::[a-z0-9][a-z0-9_-]*)*$/;
4160
4077
  async function loadCommands(options) {
4161
4078
  const problems = [];
4162
- const user = await loadDir(join7(options.home, COMMANDS_DIR), "user", problems);
4163
- const project = join7(options.home, COMMANDS_DIR) === join7(options.root, COMMANDS_DIR) ? [] : await loadDir(join7(options.root, COMMANDS_DIR), "project", problems);
4079
+ const user = await loadDir(join6(options.home, COMMANDS_DIR), "user", problems);
4080
+ const project = join6(options.home, COMMANDS_DIR) === join6(options.root, COMMANDS_DIR) ? [] : await loadDir(join6(options.root, COMMANDS_DIR), "project", problems);
4164
4081
  const byName = /* @__PURE__ */ new Map();
4165
4082
  for (const command of [...user, ...project]) {
4166
4083
  if (options.builtins.includes(command.name)) {
@@ -4190,7 +4107,7 @@ async function loadDir(dir, source, problems) {
4190
4107
  }
4191
4108
  const out = [];
4192
4109
  for (const rel of files) {
4193
- const file2 = join7(dir, rel);
4110
+ const file2 = join6(dir, rel);
4194
4111
  const name = relative(dir, file2).slice(0, -3).split(sep).join(":").toLowerCase();
4195
4112
  if (!NAME.test(name)) {
4196
4113
  problems.push(`${file2}: a command name may hold only a\u2013z, 0\u20139, "-" and "_".`);
@@ -4201,7 +4118,7 @@ async function loadDir(dir, source, problems) {
4201
4118
  problems.push(`${file2}: a project command may not be a symbolic link; ignored.`);
4202
4119
  continue;
4203
4120
  }
4204
- if (!(await stat7(file2)).isFile()) continue;
4121
+ if (!(await stat6(file2)).isFile()) continue;
4205
4122
  const text = await readFile9(file2, "utf8");
4206
4123
  if (text.length > COMMAND_MAX_CHARS) {
4207
4124
  problems.push(`${file2}: longer than ${COMMAND_MAX_CHARS} characters; ignored.`);
@@ -4293,18 +4210,18 @@ function commandConsent(command, changed, isolation) {
4293
4210
 
4294
4211
  // src/format/formatters.ts
4295
4212
  import { existsSync as existsSync2, readFileSync as readFileSync2, statSync } from "fs";
4296
- import { delimiter, extname, join as join8 } from "path";
4213
+ import { delimiter, extname, join as join7 } from "path";
4297
4214
  var JS_EXTENSIONS = ["js", "jsx", "mjs", "cjs", "ts", "tsx", "mts", "cts"];
4298
4215
  function detectFormatters(root, path, settings = {}) {
4299
4216
  const found = [];
4300
4217
  const onPath = (name) => findOnPath(name, path);
4301
4218
  const local = (name) => {
4302
- const file2 = join8(root, "node_modules", ".bin", name);
4219
+ const file2 = join7(root, "node_modules", ".bin", name);
4303
4220
  return isFile(file2) ? file2 : void 0;
4304
4221
  };
4305
- const venv = (name) => [join8(root, ".venv", "bin", name), join8(root, "venv", "bin", name)].find(isFile);
4222
+ const venv = (name) => [join7(root, ".venv", "bin", name), join7(root, "venv", "bin", name)].find(isFile);
4306
4223
  const biome = local("biome");
4307
- if (biome !== void 0 && ["biome.json", "biome.jsonc"].some((f) => isFile(join8(root, f)))) {
4224
+ if (biome !== void 0 && ["biome.json", "biome.jsonc"].some((f) => isFile(join7(root, f)))) {
4308
4225
  found.push({
4309
4226
  name: "biome",
4310
4227
  extensions: [...JS_EXTENSIONS, "json", "jsonc", "css"],
@@ -4330,9 +4247,9 @@ function detectFormatters(root, path, settings = {}) {
4330
4247
  command: [prettier, "--write", "$FILE"]
4331
4248
  });
4332
4249
  }
4333
- const pyproject = readText(join8(root, "pyproject.toml"));
4250
+ const pyproject = readText(join7(root, "pyproject.toml"));
4334
4251
  const ruff = venv("ruff") ?? onPath("ruff");
4335
- if (ruff !== void 0 && (pyproject.includes("[tool.ruff") || ["ruff.toml", ".ruff.toml"].some((f) => isFile(join8(root, f))))) {
4252
+ if (ruff !== void 0 && (pyproject.includes("[tool.ruff") || ["ruff.toml", ".ruff.toml"].some((f) => isFile(join7(root, f))))) {
4336
4253
  found.push({ name: "ruff", extensions: ["py", "pyi"], command: [ruff, "format", "$FILE"] });
4337
4254
  }
4338
4255
  const black = venv("black") ?? onPath("black");
@@ -4340,11 +4257,11 @@ function detectFormatters(root, path, settings = {}) {
4340
4257
  found.push({ name: "black", extensions: ["py", "pyi"], command: [black, "-q", "$FILE"] });
4341
4258
  }
4342
4259
  const gofmt = onPath("gofmt");
4343
- if (gofmt !== void 0 && isFile(join8(root, "go.mod"))) {
4260
+ if (gofmt !== void 0 && isFile(join7(root, "go.mod"))) {
4344
4261
  found.push({ name: "gofmt", extensions: ["go"], command: [gofmt, "-w", "$FILE"] });
4345
4262
  }
4346
4263
  const rustfmt = onPath("rustfmt");
4347
- const cargo = readText(join8(root, "Cargo.toml"));
4264
+ const cargo = readText(join7(root, "Cargo.toml"));
4348
4265
  if (rustfmt !== void 0 && cargo !== "") {
4349
4266
  const edition = /^\s*edition\s*=\s*"(\d{4})"/m.exec(cargo)?.[1] ?? "2021";
4350
4267
  found.push({
@@ -4390,9 +4307,9 @@ function hasPrettierConfig(root) {
4390
4307
  "prettier.config.cjs",
4391
4308
  "prettier.config.mjs"
4392
4309
  ];
4393
- if (files.some((f) => isFile(join8(root, f)))) return true;
4310
+ if (files.some((f) => isFile(join7(root, f)))) return true;
4394
4311
  try {
4395
- const pkg = JSON.parse(readText(join8(root, "package.json")) || "{}");
4312
+ const pkg = JSON.parse(readText(join7(root, "package.json")) || "{}");
4396
4313
  return pkg.prettier !== void 0;
4397
4314
  } catch {
4398
4315
  return false;
@@ -4401,7 +4318,7 @@ function hasPrettierConfig(root) {
4401
4318
  function findOnPath(name, path) {
4402
4319
  for (const dir of (path ?? "").split(delimiter)) {
4403
4320
  if (dir === "") continue;
4404
- const file2 = join8(dir, name);
4321
+ const file2 = join7(dir, name);
4405
4322
  if (isFile(file2)) return file2;
4406
4323
  }
4407
4324
  return void 0;
@@ -4424,9 +4341,9 @@ function readText(file2) {
4424
4341
  // src/hooks/config.ts
4425
4342
  import { createHash as createHash5 } from "crypto";
4426
4343
  import { readFile as readFile10 } from "fs/promises";
4427
- import { join as join9 } from "path";
4344
+ import { join as join8 } from "path";
4428
4345
  import { z as z17 } from "zod";
4429
- var HOOKS_FILE = join9(".garuda", "hooks.json");
4346
+ var HOOKS_FILE = join8(".garuda", "hooks.json");
4430
4347
  var HOOK_EVENTS = ["preToolUse", "postToolUse"];
4431
4348
  var hookSchema = z17.strictObject({
4432
4349
  command: z17.string().min(1),
@@ -4472,8 +4389,8 @@ async function readHooks(file2, source) {
4472
4389
  return { hooks, problems };
4473
4390
  }
4474
4391
  async function loadHooks(home, root) {
4475
- const user = await readHooks(join9(home, HOOKS_FILE), "user");
4476
- const project = home === root ? { hooks: [], problems: [] } : await readHooks(join9(root, HOOKS_FILE), "project");
4392
+ const user = await readHooks(join8(home, HOOKS_FILE), "user");
4393
+ const project = home === root ? { hooks: [], problems: [] } : await readHooks(join8(root, HOOKS_FILE), "project");
4477
4394
  return {
4478
4395
  user: user.hooks,
4479
4396
  project: project.hooks,
@@ -4486,10 +4403,10 @@ function hooksHash(hooks) {
4486
4403
  }
4487
4404
 
4488
4405
  // src/hooks/runner.ts
4489
- import { randomBytes as randomBytes4 } from "crypto";
4490
- import { rm as rm2, writeFile as writeFile2 } from "fs/promises";
4406
+ import { randomBytes as randomBytes3 } from "crypto";
4407
+ import { rm as rm2, writeFile } from "fs/promises";
4491
4408
  import { tmpdir } from "os";
4492
- import { isAbsolute as isAbsolute2, join as join10 } from "path";
4409
+ import { isAbsolute as isAbsolute2, join as join9 } from "path";
4493
4410
  var OUTPUT_BYTES = 8e3;
4494
4411
  var FEEDBACK_CHARS = 4e3;
4495
4412
  var HookRunner = class {
@@ -4560,7 +4477,7 @@ ${clean2(r.stderr)}
4560
4477
  });
4561
4478
  return { exitCode: null, signal: "refused by the team policy", timedOut: false, stderr: "" };
4562
4479
  }
4563
- const file2 = join10(tmpdir(), `garuda-hook-${randomBytes4(6).toString("hex")}.json`);
4480
+ const file2 = join9(tmpdir(), `garuda-hook-${randomBytes3(6).toString("hex")}.json`);
4564
4481
  const data = {
4565
4482
  event: hook.event,
4566
4483
  tool: call.tool,
@@ -4569,14 +4486,14 @@ ${clean2(r.stderr)}
4569
4486
  ...outcome === void 0 ? {} : { result: outcome },
4570
4487
  root
4571
4488
  };
4572
- await writeFile2(file2, JSON.stringify(data), { mode: 384 });
4489
+ await writeFile(file2, JSON.stringify(data), { mode: 384 });
4573
4490
  const env = {
4574
4491
  GARUDA_HOOK_EVENT: hook.event,
4575
4492
  GARUDA_TOOL: call.tool,
4576
4493
  GARUDA_HOOK_INPUT: file2
4577
4494
  };
4578
4495
  if (target?.kind === "path") {
4579
- env.GARUDA_FILE = isAbsolute2(target.path) ? target.path : join10(root, target.path);
4496
+ env.GARUDA_FILE = isAbsolute2(target.path) ? target.path : join9(root, target.path);
4580
4497
  }
4581
4498
  if (target?.kind === "command") env.GARUDA_COMMAND = target.command;
4582
4499
  if (target?.kind === "url") env.GARUDA_URL = target.url;
@@ -4642,8 +4559,8 @@ function hooksConsent(hooks, file2, isolation, changed) {
4642
4559
 
4643
4560
  // src/knowledge/index.ts
4644
4561
  import { createHash as createHash7 } from "crypto";
4645
- import { mkdir as mkdir4, readFile as readFile12, stat as stat8, writeFile as writeFile3 } from "fs/promises";
4646
- import { dirname as dirname5, extname as extname3, join as join13 } from "path";
4562
+ import { mkdir as mkdir4, readFile as readFile12, stat as stat7, writeFile as writeFile2 } from "fs/promises";
4563
+ import { dirname as dirname4, extname as extname3, join as join12 } from "path";
4647
4564
 
4648
4565
  // src/knowledge/java.ts
4649
4566
  import { readFileSync as readFileSync3, statSync as statSync2 } from "fs";
@@ -5325,7 +5242,7 @@ function createRustExpert(root) {
5325
5242
  // src/knowledge/plugins.ts
5326
5243
  import { createHash as createHash6 } from "crypto";
5327
5244
  import { readdir as readdir5, readFile as readFile11 } from "fs/promises";
5328
- import { basename as basename4, extname as extname2, join as join12 } from "path";
5245
+ import { basename as basename3, extname as extname2, join as join11 } from "path";
5329
5246
  import { pathToFileURL } from "url";
5330
5247
 
5331
5248
  // src/knowledge/python.ts
@@ -5568,7 +5485,7 @@ function openTripleQuote(line) {
5568
5485
 
5569
5486
  // src/knowledge/typescript.ts
5570
5487
  import { readFileSync as readFileSync7, statSync as statSync6 } from "fs";
5571
- import { dirname as dirname4, isAbsolute as isAbsolute7, join as join11, relative as relative2, sep as sep2 } from "path";
5488
+ import { dirname as dirname3, isAbsolute as isAbsolute7, join as join10, relative as relative2, sep as sep2 } from "path";
5572
5489
  async function createTypeScriptExpert(root) {
5573
5490
  const ts = (await import("ts6")).default;
5574
5491
  return new TypeScriptExpert(ts, root);
@@ -5734,7 +5651,7 @@ var TypeScriptExpert = class {
5734
5651
  };
5735
5652
  }
5736
5653
  abs(path) {
5737
- return isAbsolute7(path) ? path : join11(this.root, path);
5654
+ return isAbsolute7(path) ? path : join10(this.root, path);
5738
5655
  }
5739
5656
  rel(file2) {
5740
5657
  return relative2(this.root, file2).split(sep2).join("/");
@@ -5758,7 +5675,7 @@ function declarationKind(ts, node) {
5758
5675
  function compilerOptions(ts, root) {
5759
5676
  let base = {};
5760
5677
  const configPath = ts.findConfigFile(root, (f) => ts.sys.fileExists(f));
5761
- if (configPath !== void 0 && dirname4(configPath) === root) {
5678
+ if (configPath !== void 0 && dirname3(configPath) === root) {
5762
5679
  const read = ts.readConfigFile(configPath, (f) => ts.sys.readFile(f));
5763
5680
  if (read.config !== void 0) {
5764
5681
  base = ts.parseJsonConfigFileContent(read.config, ts.sys, root).options;
@@ -5821,12 +5738,12 @@ async function discoverPlugins({
5821
5738
  }) {
5822
5739
  const plugins = includeBuiltins ? [...BUILTIN_PLUGINS] : [];
5823
5740
  const warnings = [];
5824
- const userDir = join12(home, ".garuda", "languages");
5741
+ const userDir = join11(home, ".garuda", "languages");
5825
5742
  const userFiles = await safeReaddir(userDir);
5826
5743
  for (const filename of userFiles) {
5827
5744
  if (!isPluginFile(filename)) continue;
5828
- const fullPath = join12(userDir, filename);
5829
- const id = basename4(filename, extname2(filename));
5745
+ const fullPath = join11(userDir, filename);
5746
+ const id = basename3(filename, extname2(filename));
5830
5747
  try {
5831
5748
  const plugin = await loadPluginModule(fullPath, id, "user", root);
5832
5749
  if (plugin) {
@@ -5836,7 +5753,7 @@ async function discoverPlugins({
5836
5753
  warnings.push(`Failed to load user language plugin "${id}": ${error.message}`);
5837
5754
  }
5838
5755
  }
5839
- const projDir = join12(root, ".garuda", "languages");
5756
+ const projDir = join11(root, ".garuda", "languages");
5840
5757
  const projFiles = (await safeReaddir(projDir)).filter(isPluginFile);
5841
5758
  if (!projectPlugins) {
5842
5759
  if (projFiles.length > 0) {
@@ -5848,8 +5765,8 @@ async function discoverPlugins({
5848
5765
  }
5849
5766
  for (const filename of projFiles) {
5850
5767
  if (!isPluginFile(filename)) continue;
5851
- const fullPath = join12(projDir, filename);
5852
- const id = basename4(filename, extname2(filename));
5768
+ const fullPath = join11(projDir, filename);
5769
+ const id = basename3(filename, extname2(filename));
5853
5770
  try {
5854
5771
  const content = await readFile11(fullPath, "utf8");
5855
5772
  const hash2 = createHash6("sha256").update(content).digest("hex");
@@ -6084,7 +6001,7 @@ var KnowledgeIndex = class {
6084
6001
  const callableSymbols = fileSymbols.filter(
6085
6002
  (s) => s.kind === "function" || s.kind === "method" || s.kind === "constructor" || s.kind === "class"
6086
6003
  );
6087
- const content = await readFile12(join13(this.root, filePath), "utf8").catch(() => "");
6004
+ const content = await readFile12(join12(this.root, filePath), "utf8").catch(() => "");
6088
6005
  const lines = content.split("\n");
6089
6006
  for (const site of sites) {
6090
6007
  const enclosing = enclosingSymbol(filePath, content, lines, site.line, callableSymbols);
@@ -6274,7 +6191,7 @@ var KnowledgeIndex = class {
6274
6191
  const prefix = dir.replace(/^\.?\/?/, "").replace(/\/?$/, dir === "" || dir === "." ? "" : "/");
6275
6192
  for (const { expert, files } of await this.byExpert()) {
6276
6193
  for (const path of files) {
6277
- const content = await readFile12(join13(this.root, path), "utf8").catch(() => void 0);
6194
+ const content = await readFile12(join12(this.root, path), "utf8").catch(() => void 0);
6278
6195
  if (content === void 0) continue;
6279
6196
  const hash2 = createHash7("sha256").update(content).digest("hex");
6280
6197
  const cached = cache.files[path];
@@ -6346,7 +6263,7 @@ var KnowledgeIndex = class {
6346
6263
  const ext = extname3(path);
6347
6264
  const group = groups.find((g) => g.expert.extensions.includes(ext));
6348
6265
  if (group === void 0) continue;
6349
- const info = await stat8(absolute).catch(() => void 0);
6266
+ const info = await stat7(absolute).catch(() => void 0);
6350
6267
  if (info === void 0 || info.size > MAX_FILE_BYTES) continue;
6351
6268
  group.files.push(path);
6352
6269
  if (++count >= MAX_FILES2) break;
@@ -6355,7 +6272,7 @@ var KnowledgeIndex = class {
6355
6272
  }
6356
6273
  async loadCache() {
6357
6274
  try {
6358
- const cache = JSON.parse(await readFile12(join13(this.root, GRAPH_FILE), "utf8"));
6275
+ const cache = JSON.parse(await readFile12(join12(this.root, GRAPH_FILE), "utf8"));
6359
6276
  if (cache.version === GRAPH_VERSION) return cache;
6360
6277
  } catch {
6361
6278
  }
@@ -6363,10 +6280,10 @@ var KnowledgeIndex = class {
6363
6280
  }
6364
6281
  /** Best effort (0.14, review): a read-only checkout gives the map without a cache, not an error. */
6365
6282
  async saveCache(cache) {
6366
- const path = join13(this.root, GRAPH_FILE);
6283
+ const path = join12(this.root, GRAPH_FILE);
6367
6284
  try {
6368
- await mkdir4(dirname5(path), { recursive: true });
6369
- await writeFile3(path, JSON.stringify(cache));
6285
+ await mkdir4(dirname4(path), { recursive: true });
6286
+ await writeFile2(path, JSON.stringify(cache));
6370
6287
  } catch {
6371
6288
  }
6372
6289
  }
@@ -6603,8 +6520,8 @@ function repairServerBlocks(message) {
6603
6520
 
6604
6521
  // src/skills/load.ts
6605
6522
  import { createHash as createHash8 } from "crypto";
6606
- import { lstat as lstat4, readdir as readdir6, readFile as readFile13, stat as stat9 } from "fs/promises";
6607
- import { join as join14 } from "path";
6523
+ import { lstat as lstat4, readdir as readdir6, readFile as readFile13, stat as stat8 } from "fs/promises";
6524
+ import { join as join13 } from "path";
6608
6525
  var SKILL_FILE = "SKILL.md";
6609
6526
  var SKILL_NAME = /^(?!-)(?!.*--)[a-z0-9-]{1,64}(?<!-)$/;
6610
6527
  var SKILL_MAX_CHARS = 5e4;
@@ -6612,10 +6529,10 @@ var DESCRIPTION_MAX_CHARS2 = 1536;
6612
6529
  var MAX_SKILLS = 100;
6613
6530
  function skillDirs(home, root) {
6614
6531
  return [
6615
- { dir: join14(home, ".garuda", "skills"), shown: "~/.garuda/skills", source: "user" },
6616
- { dir: join14(home, ".claude", "skills"), shown: "~/.claude/skills", source: "user" },
6617
- { dir: join14(root, ".garuda", "skills"), shown: ".garuda/skills", source: "project" },
6618
- { dir: join14(root, ".claude", "skills"), shown: ".claude/skills", source: "project" }
6532
+ { dir: join13(home, ".garuda", "skills"), shown: "~/.garuda/skills", source: "user" },
6533
+ { dir: join13(home, ".claude", "skills"), shown: "~/.claude/skills", source: "user" },
6534
+ { dir: join13(root, ".garuda", "skills"), shown: ".garuda/skills", source: "project" },
6535
+ { dir: join13(root, ".claude", "skills"), shown: ".claude/skills", source: "project" }
6619
6536
  ];
6620
6537
  }
6621
6538
  async function loadSkills(options) {
@@ -6655,11 +6572,11 @@ async function loadDir2(place, problems) {
6655
6572
  const out = [];
6656
6573
  for (const entry of entries) {
6657
6574
  if (entry.startsWith(".")) continue;
6658
- const dir = join14(place.dir, entry);
6575
+ const dir = join13(place.dir, entry);
6659
6576
  const shown = `${place.shown}/${entry}`;
6660
- const file2 = join14(dir, SKILL_FILE);
6577
+ const file2 = join13(dir, SKILL_FILE);
6661
6578
  try {
6662
- if (!(await stat9(dir)).isDirectory()) continue;
6579
+ if (!(await stat8(dir)).isDirectory()) continue;
6663
6580
  if (place.source === "project" && ((await lstat4(dir)).isSymbolicLink() || (await lstat4(file2)).isSymbolicLink())) {
6664
6581
  problems.push(`${shown}: a project skill may not be a symbolic link; ignored.`);
6665
6582
  continue;
@@ -6757,8 +6674,8 @@ function skillConsent(skill, changed, isolation) {
6757
6674
  }
6758
6675
 
6759
6676
  // src/skills/tool.ts
6760
- import { readdir as readdir7, readFile as readFile14, realpath as realpath4, stat as stat10 } from "fs/promises";
6761
- import { join as join15, relative as relative3, resolve, sep as sep3 } from "path";
6677
+ import { readdir as readdir7, readFile as readFile14, realpath as realpath3, stat as stat9 } from "fs/promises";
6678
+ import { join as join14, relative as relative3, resolve, sep as sep3 } from "path";
6762
6679
  import { z as z18 } from "zod";
6763
6680
  var input10 = z18.object({
6764
6681
  name: z18.string().min(1).describe("The skill name from the list."),
@@ -6828,11 +6745,11 @@ async function skillText(skill, args, place) {
6828
6745
  async function readSkillFile(skill, file2) {
6829
6746
  const target = resolve(skill.dir, file2);
6830
6747
  try {
6831
- const [realDir, realTarget] = await Promise.all([realpath4(skill.dir), realpath4(target)]);
6748
+ const [realDir, realTarget] = await Promise.all([realpath3(skill.dir), realpath3(target)]);
6832
6749
  if (!isInside(realDir, realTarget) || !isInside(skill.dir, target)) {
6833
6750
  return { error: true, text: `"${file2}" is outside the skill folder.` };
6834
6751
  }
6835
- if (!(await stat10(realTarget)).isFile()) {
6752
+ if (!(await stat9(realTarget)).isFile()) {
6836
6753
  return { error: true, text: `"${file2}" is not a file.` };
6837
6754
  }
6838
6755
  const buffer = await readFile14(realTarget);
@@ -6869,8 +6786,8 @@ async function listFiles2(dir) {
6869
6786
  for (const name of entries) {
6870
6787
  if (out.length >= MAX_FILES_LISTED) return;
6871
6788
  if (name.startsWith(".")) continue;
6872
- const full = join15(current, name);
6873
- const info = await stat10(full).catch(() => void 0);
6789
+ const full = join14(current, name);
6790
+ const info = await stat9(full).catch(() => void 0);
6874
6791
  if (info?.isDirectory()) {
6875
6792
  if (depth < 3) await walk(full, depth + 1);
6876
6793
  } else if (info?.isFile()) {
@@ -6960,9 +6877,9 @@ No results.
6960
6877
 
6961
6878
  // src/undo/snapshots.ts
6962
6879
  import { createHash as createHash9 } from "crypto";
6963
- import { mkdir as mkdir5, writeFile as writeFile4 } from "fs/promises";
6880
+ import { mkdir as mkdir5, writeFile as writeFile3 } from "fs/promises";
6964
6881
  import { homedir as homedir3 } from "os";
6965
- import { join as join16 } from "path";
6882
+ import { join as join15 } from "path";
6966
6883
  var SNAPSHOT_EXCLUDES = [
6967
6884
  ".git",
6968
6885
  ".garuda/sessions/",
@@ -7059,7 +6976,7 @@ var SnapshotStore = class {
7059
6976
  this.ready ??= (async () => {
7060
6977
  await mkdir5(this.dir, { recursive: true, mode: 448 });
7061
6978
  await this.git("init -q", signal, true);
7062
- await writeFile4(join16(this.dir, "info", "exclude"), `${SNAPSHOT_EXCLUDES.join("\n")}
6979
+ await writeFile3(join15(this.dir, "info", "exclude"), `${SNAPSHOT_EXCLUDES.join("\n")}
7063
6980
  `);
7064
6981
  })().catch((error) => {
7065
6982
  this.ready = void 0;
@@ -7113,7 +7030,7 @@ var SnapshotStore = class {
7113
7030
  };
7114
7031
  function storeDir(root, home = homedir3()) {
7115
7032
  const id = createHash9("sha256").update(root).digest("hex").slice(0, 16);
7116
- return join16(home, ".garuda", "snapshots", id);
7033
+ return join15(home, ".garuda", "snapshots", id);
7117
7034
  }
7118
7035
  function shellQuote(text) {
7119
7036
  return `'${text.replace(/'/g, "'\\''")}'`;
@@ -7124,7 +7041,7 @@ function tree(id) {
7124
7041
  }
7125
7042
 
7126
7043
  // src/app/mentions.ts
7127
- import { readdir as readdir8, readFile as readFile15, stat as stat11 } from "fs/promises";
7044
+ import { readdir as readdir8, readFile as readFile15, stat as stat10 } from "fs/promises";
7128
7045
  var MAX_ATTACHMENTS = 10;
7129
7046
  var MAX_TOTAL_CHARS = 15e4;
7130
7047
  var MAX_FOLDER_ENTRIES = 200;
@@ -7150,7 +7067,7 @@ async function attachMentions(prompt, root, files, denial = async () => void 0)
7150
7067
  }
7151
7068
  continue;
7152
7069
  }
7153
- const info = await stat11(absolute).catch(() => void 0);
7070
+ const info = await stat10(absolute).catch(() => void 0);
7154
7071
  if (info === void 0) continue;
7155
7072
  const shown = displayPath(root, absolute);
7156
7073
  if (attachments.length >= MAX_ATTACHMENTS) {
@@ -7353,7 +7270,7 @@ var ModelState = class {
7353
7270
  // src/app/network.ts
7354
7271
  import { createHash as createHash10 } from "crypto";
7355
7272
  import { existsSync as existsSync3 } from "fs";
7356
- import { basename as basename5, delimiter as delimiter2, join as join17 } from "path";
7273
+ import { basename as basename4, delimiter as delimiter2, join as join16 } from "path";
7357
7274
  function networkHash(entries) {
7358
7275
  const canonical = [...new Set(entries.map((e) => e.trim().toLowerCase()))].sort();
7359
7276
  return createHash10("sha256").update(JSON.stringify(canonical)).digest("hex");
@@ -7388,10 +7305,10 @@ function networkConsent(entries, isolation, changed) {
7388
7305
  };
7389
7306
  }
7390
7307
  function nodeBinary(execPath = process.execPath, path = process.env.PATH ?? "") {
7391
- if (/^node(\.exe)?$/.test(basename5(execPath))) return execPath;
7308
+ if (/^node(\.exe)?$/.test(basename4(execPath))) return execPath;
7392
7309
  for (const dir of path.split(delimiter2)) {
7393
7310
  if (dir === "") continue;
7394
- const candidate = join17(dir, "node");
7311
+ const candidate = join16(dir, "node");
7395
7312
  if (existsSync3(candidate)) return candidate;
7396
7313
  }
7397
7314
  return void 0;
@@ -8605,7 +8522,7 @@ ${neutralizeTags(output)}`
8605
8522
  text: "There is no finished plan in this chat. Make one in plan mode (/plan), then type /schedule."
8606
8523
  };
8607
8524
  }
8608
- const { createJob } = await import("./create-Y5SXJUXO.js");
8525
+ const { createJob } = await import("./create-VXIH2GUZ.js");
8609
8526
  const created = await createJob({
8610
8527
  root: this.root,
8611
8528
  executor: this.executor,
@@ -8672,7 +8589,7 @@ ${result.stderr.text}`)
8672
8589
  */
8673
8590
  async cancelJob(id, agent = {}) {
8674
8591
  const { loadJob, saveJob } = await import("./job-3NYDMP2M.js");
8675
- const { defaultAgentEnv, nightSpec, removeAgent, removeSpec } = await import("./launchd-2FL5UN2U.js");
8592
+ const { defaultAgentEnv, nightSpec, removeAgent, removeSpec } = await import("./launchd-SSX362VG.js");
8676
8593
  if (id === "night") {
8677
8594
  const removed = await removeSpec(
8678
8595
  agent.executor ?? this.executor,
@@ -8704,8 +8621,8 @@ ${result.stderr.text}`)
8704
8621
  */
8705
8622
  async deleteJob(id, signal, agent = {}) {
8706
8623
  const { loadJob } = await import("./job-3NYDMP2M.js");
8707
- const { defaultAgentEnv, removeAgent } = await import("./launchd-2FL5UN2U.js");
8708
- const { jobLeftovers, removeJob } = await import("./remove-AENULZZE.js");
8624
+ const { defaultAgentEnv, removeAgent } = await import("./launchd-SSX362VG.js");
8625
+ const { jobLeftovers, removeJob } = await import("./remove-6GDSTAIO.js");
8709
8626
  let job;
8710
8627
  try {
8711
8628
  job = await loadJob(this.root, id);
@@ -8840,7 +8757,7 @@ ${result.stderr.text}`)
8840
8757
  if (known === hash2) {
8841
8758
  active = [...active, ...project];
8842
8759
  } else {
8843
- const file2 = join18(this.root, HOOKS_FILE);
8760
+ const file2 = join17(this.root, HOOKS_FILE);
8844
8761
  const request = hooksConsent(project, file2, this.executor.isolation, known !== void 0);
8845
8762
  const choice = await this.approver.ask(request, signal);
8846
8763
  if (choice !== "deny") active = [...active, ...project];
@@ -8877,7 +8794,7 @@ ${result.stderr.text}`)
8877
8794
  * The files it writes are new only; the turn's own writes go through the normal approvals.
8878
8795
  */
8879
8796
  async init(signal) {
8880
- const { runInit } = await import("./run-66Y6R2KU.js");
8797
+ const { runInit } = await import("./run-ML6GSPN4.js");
8881
8798
  const result = await runInit({
8882
8799
  root: this.root,
8883
8800
  home: this.commandsHome,
@@ -9032,7 +8949,7 @@ ${result.stderr.text}`)
9032
8949
  }
9033
8950
  /** Install a language server into ~/.garuda/lsp (the user asked for it). */
9034
8951
  async installLsp(language, signal) {
9035
- const { installServer } = await import("./install-XWLU22OH.js");
8952
+ const { installServer } = await import("./install-EWDSPFFZ.js");
9036
8953
  const result = await installServer(language, {
9037
8954
  executor: this.executor,
9038
8955
  home: this.lspHome,
@@ -9043,7 +8960,7 @@ ${result.stderr.text}`)
9043
8960
  }
9044
8961
  /** autoInstall (~/.garuda/lsp.json): ask before a managed install. */
9045
8962
  async askInstall(language, signal) {
9046
- const { installCommand } = await import("./install-XWLU22OH.js");
8963
+ const { installCommand } = await import("./install-EWDSPFFZ.js");
9047
8964
  const { LANGUAGE_LABELS } = await import("./manager-4PMSXT47.js");
9048
8965
  const { managedLabel, managedDir } = await import("./servers-6YDGWOZ6.js");
9049
8966
  const dir = managedDir(language, this.lspHome);
@@ -9076,7 +8993,7 @@ ${result.stderr.text}`)
9076
8993
  async startMcp(signal) {
9077
8994
  if (this.mcpServers.length === 0) return;
9078
8995
  this.mcpStarted ??= (async () => {
9079
- const { McpManager } = await import("./manager-EBTYO2GR.js");
8996
+ const { McpManager } = await import("./manager-AWU4NHHK.js");
9080
8997
  const { AuthStore } = await import("./oauth-W6OK6XXO.js");
9081
8998
  const manager = new McpManager({
9082
8999
  root: this.root,
@@ -9303,7 +9220,6 @@ async function gatedProjectSettings(options) {
9303
9220
  }
9304
9221
 
9305
9222
  export {
9306
- keepSecretForRedaction,
9307
9223
  FileSessionStore,
9308
9224
  parseRecords,
9309
9225
  newSessionId,
@@ -9338,4 +9254,4 @@ export {
9338
9254
  modelFacts,
9339
9255
  Runtime
9340
9256
  };
9341
- //# sourceMappingURL=chunk-ITITLNAR.js.map
9257
+ //# sourceMappingURL=chunk-WIJL72ZE.js.map