@garuda-agent/garuda 0.17.0 → 0.18.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +243 -0
- package/README.md +3 -2
- package/SECURITY.md +1 -1
- package/dist/{acpCommand-7EY3NHPG.js → acpCommand-JAYNMIMP.js} +19 -16
- package/dist/advise-HDKJGNBL.js +195 -0
- package/dist/brief-RWKESOPT.js +91 -0
- package/dist/buildCheck-HB46NWLX.js +19 -0
- package/dist/buildInfo-K73FFI5S.js +8 -0
- package/dist/chunk-2OYTNNUJ.js +216 -0
- package/dist/{chunk-Z66BWTMD.js → chunk-34WBDQBL.js} +135 -78
- package/dist/chunk-4QRTTRVK.js +88 -0
- package/dist/{chunk-2DYMJMRQ.js → chunk-5UDYQ5MK.js} +405 -70
- package/dist/{chunk-J4346IDH.js → chunk-7KBOIPUT.js} +2 -1
- package/dist/chunk-CWVXOSAA.js +894 -0
- package/dist/{chunk-FARS4R67.js → chunk-DQSCCE77.js} +18 -1
- package/dist/chunk-DUYLVGPY.js +821 -0
- package/dist/chunk-GKU62MHQ.js +5258 -0
- package/dist/chunk-H7LIBGZT.js +9 -0
- package/dist/chunk-IKPGHM54.js +334 -0
- package/dist/chunk-IYGJWX65.js +9 -0
- package/dist/{chunk-U65DQZDB.js → chunk-JMH5W5DG.js} +2 -45
- package/dist/chunk-L55VUSX3.js +54 -0
- package/dist/{chunk-B4SJY7KT.js → chunk-LMKGSYJC.js} +77 -8
- package/dist/{chunk-23FXBNBB.js → chunk-MNE7HHX2.js} +2 -1
- package/dist/chunk-NH72AELP.js +48 -0
- package/dist/{chunk-735BKABA.js → chunk-NLS7GMF7.js} +12 -106
- package/dist/{chunk-ZAE25JM2.js → chunk-QANRZW7W.js} +8 -1
- package/dist/{chunk-JRVWH27M.js → chunk-QLBCM2YQ.js} +7 -3
- package/dist/{chunk-6XHON3Q6.js → chunk-QXTHEFKP.js} +3 -3
- package/dist/{chunk-TJIWD7R7.js → chunk-R7RCW4BQ.js} +10 -8
- package/dist/chunk-TLA2PDGM.js +156 -0
- package/dist/{chunk-5B5HDTUR.js → chunk-TWQ7V2L6.js} +2 -2
- package/dist/chunk-ULAJPMY7.js +107 -0
- package/dist/chunk-VISKX36R.js +306 -0
- package/dist/{chunk-55CFEEIN.js → chunk-WK5NE6RY.js} +2 -2
- package/dist/chunk-Y62J7PTD.js +90 -0
- package/dist/chunk-YAQ6QLKB.js +40 -0
- package/dist/{chunk-7TH3NHCQ.js → chunk-ZKT4P2PC.js} +2 -2
- package/dist/cli/index.js +289 -65
- package/dist/config-WV2H64TF.js +23 -0
- package/dist/{create-W6BV75QX.js → create-OACSGJ37.js} +5 -5
- package/dist/evalCommand-BLJJ4G76.js +696 -0
- package/dist/evalTune-W53KAD4V.js +302 -0
- package/dist/{export-SJ3DUP6W.js → export-E677HIQS.js} +27 -4
- package/dist/exportHtml-BMV73YRO.js +21 -0
- package/dist/{inkChat-FNUBK43U.js → inkChat-EVLYDC3K.js} +263 -47
- package/dist/{install-TKWN5AYH.js → install-4ST5BNRG.js} +3 -3
- package/dist/{jobCommand-FE6XN3YD.js → jobCommand-ILOTYOX3.js} +9 -8
- package/dist/{launchd-3A3ONEW5.js → launchd-QG6R5RAK.js} +4 -4
- package/dist/{lspCommand-ZZ6R4PA2.js → lspCommand-X4FTTONR.js} +3 -3
- package/dist/{manager-73MPYFTP.js → manager-L25IUXHW.js} +11 -11
- package/dist/{nightCommand-OODJNWDT.js → nightCommand-XPWT6CQZ.js} +9 -8
- package/dist/receiptView-YFDHV253.js +19 -0
- package/dist/{remove-42WQNVPX.js → remove-STX5UO7X.js} +3 -3
- package/dist/{run-ML6GSPN4.js → run-W4TK52WT.js} +6 -6
- package/dist/{server-VEYIJHEU.js → server-ASM73QVY.js} +3 -3
- package/dist/{setupCommand-GBQIVYJC.js → setupCommand-OSOMFHDQ.js} +10 -9
- package/dist/tour-CEVMAC5S.js +18 -0
- package/dist/tune-VX2WQTHS.js +52 -0
- package/dist/uiState-YFJQ43D7.js +16 -0
- package/package.json +1 -1
- package/dist/chunk-4JSUUDFQ.js +0 -118
- package/dist/chunk-BSK5T2ZG.js +0 -9
- package/dist/evalCommand-YVQAWUZE.js +0 -2833
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/cli/approver.ts
|
|
4
|
+
import { styleText } from "util";
|
|
5
|
+
|
|
6
|
+
// src/cli/diffView.ts
|
|
7
|
+
var SIDE_BY_SIDE_COLUMNS = 140;
|
|
8
|
+
function tokens(line) {
|
|
9
|
+
return line.match(/\s+|[\p{L}\p{N}_]+|[^\s\p{L}\p{N}_]/gu) ?? [];
|
|
10
|
+
}
|
|
11
|
+
var MAX_CELLS = 4e4;
|
|
12
|
+
function wordDiff(a, b) {
|
|
13
|
+
const x = tokens(a);
|
|
14
|
+
const y = tokens(b);
|
|
15
|
+
if (x.length * y.length > MAX_CELLS || x.length + y.length === 0) return void 0;
|
|
16
|
+
const n = x.length;
|
|
17
|
+
const m = y.length;
|
|
18
|
+
const table = new Uint16Array((n + 1) * (m + 1));
|
|
19
|
+
const at = (i2, j2) => i2 * (m + 1) + j2;
|
|
20
|
+
for (let i2 = n - 1; i2 >= 0; i2--) {
|
|
21
|
+
for (let j2 = m - 1; j2 >= 0; j2--) {
|
|
22
|
+
table[at(i2, j2)] = x[i2] === y[j2] ? (table[at(i2 + 1, j2 + 1)] ?? 0) + 1 : Math.max(table[at(i2 + 1, j2)] ?? 0, table[at(i2, j2 + 1)] ?? 0);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
const common = table[at(0, 0)] ?? 0;
|
|
26
|
+
const solid = (t) => t.filter((s) => s.trim() !== "").length;
|
|
27
|
+
if (common === 0 || common / Math.max(1, Math.max(solid(x), solid(y))) < 0.4) return void 0;
|
|
28
|
+
const outA = [];
|
|
29
|
+
const outB = [];
|
|
30
|
+
let i = 0;
|
|
31
|
+
let j = 0;
|
|
32
|
+
while (i < n || j < m) {
|
|
33
|
+
if (i < n && j < m && x[i] === y[j]) {
|
|
34
|
+
outA.push({ text: x[i], changed: false });
|
|
35
|
+
outB.push({ text: y[j], changed: false });
|
|
36
|
+
i++;
|
|
37
|
+
j++;
|
|
38
|
+
} else if (j < m && (i >= n || (table[at(i, j + 1)] ?? 0) >= (table[at(i + 1, j)] ?? 0))) {
|
|
39
|
+
outB.push({ text: y[j], changed: true });
|
|
40
|
+
j++;
|
|
41
|
+
} else {
|
|
42
|
+
outA.push({ text: x[i], changed: true });
|
|
43
|
+
i++;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return { a: outA, b: outB };
|
|
47
|
+
}
|
|
48
|
+
function paintParts(parts, base, paint) {
|
|
49
|
+
const runs = [];
|
|
50
|
+
for (const p of parts) {
|
|
51
|
+
const last = runs.at(-1);
|
|
52
|
+
if (last !== void 0 && last.changed === p.changed) last.text += p.text;
|
|
53
|
+
else runs.push({ ...p });
|
|
54
|
+
}
|
|
55
|
+
return runs.map(
|
|
56
|
+
(r) => r.changed && r.text.trim() !== "" ? paint([base, "inverse"], r.text) : paint([base], r.text)
|
|
57
|
+
).join("");
|
|
58
|
+
}
|
|
59
|
+
function unifiedDiff(text, paint) {
|
|
60
|
+
const lines = text.split("\n");
|
|
61
|
+
const out = [];
|
|
62
|
+
let i = 0;
|
|
63
|
+
while (i < lines.length) {
|
|
64
|
+
const line = lines[i];
|
|
65
|
+
if (isFileHeader(line)) {
|
|
66
|
+
out.push(paint(["bold"], line));
|
|
67
|
+
i++;
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
if (line.startsWith("@@")) {
|
|
71
|
+
out.push(paint(["cyan"], line));
|
|
72
|
+
i++;
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
if (line.startsWith("-")) {
|
|
76
|
+
const removed = [];
|
|
77
|
+
while (i < lines.length && isRemoved(lines[i])) removed.push(lines[i++]);
|
|
78
|
+
const added = [];
|
|
79
|
+
while (i < lines.length && isAdded(lines[i])) added.push(lines[i++]);
|
|
80
|
+
const marks = removed.map((r, k) => {
|
|
81
|
+
const a = added[k];
|
|
82
|
+
return a === void 0 ? void 0 : wordDiff(r.slice(1), a.slice(1));
|
|
83
|
+
});
|
|
84
|
+
removed.forEach((r, k) => {
|
|
85
|
+
const m = marks[k];
|
|
86
|
+
out.push(
|
|
87
|
+
m === void 0 ? paint(["red"], r) : paint(["red"], "-") + paintParts(m.a, "red", paint)
|
|
88
|
+
);
|
|
89
|
+
});
|
|
90
|
+
added.forEach((a, k) => {
|
|
91
|
+
const m = marks[k];
|
|
92
|
+
out.push(
|
|
93
|
+
m === void 0 ? paint(["green"], a) : paint(["green"], "+") + paintParts(m.b, "green", paint)
|
|
94
|
+
);
|
|
95
|
+
});
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
out.push(line.startsWith("+") ? paint(["green"], line) : line);
|
|
99
|
+
i++;
|
|
100
|
+
}
|
|
101
|
+
return out.join("\n");
|
|
102
|
+
}
|
|
103
|
+
var isFileHeader = (line) => line.startsWith("+++") || line.startsWith("---") || line.startsWith("diff --git");
|
|
104
|
+
var isRemoved = (line) => line.startsWith("-") && !line.startsWith("---");
|
|
105
|
+
var isAdded = (line) => line.startsWith("+") && !line.startsWith("+++");
|
|
106
|
+
function fitWidth(text, width) {
|
|
107
|
+
const chars = [...text];
|
|
108
|
+
if (chars.length > width) return `${chars.slice(0, Math.max(0, width - 1)).join("")}\u2026`;
|
|
109
|
+
return text + " ".repeat(width - chars.length);
|
|
110
|
+
}
|
|
111
|
+
function sideBySide(text, columns, paint) {
|
|
112
|
+
const half = Math.floor((columns - 3) / 2);
|
|
113
|
+
const body = half - 6;
|
|
114
|
+
const out = [];
|
|
115
|
+
let oldNo = 0;
|
|
116
|
+
let newNo = 0;
|
|
117
|
+
const cell = (no, mark, content, style) => {
|
|
118
|
+
const head = no === void 0 ? " " : String(no).padStart(4);
|
|
119
|
+
const shown = fitWidth(`${mark}${content}`, body + 1);
|
|
120
|
+
return `${paint(["dim"], head)} ${style === void 0 ? shown : paint([style], shown)}`;
|
|
121
|
+
};
|
|
122
|
+
const markedCell = (no, sign, parts, style) => {
|
|
123
|
+
let room = body;
|
|
124
|
+
const kept = [];
|
|
125
|
+
for (const p of parts) {
|
|
126
|
+
if (room <= 0) break;
|
|
127
|
+
const chars = [...p.text];
|
|
128
|
+
const piece = chars.length > room ? `${chars.slice(0, Math.max(0, room - 1)).join("")}\u2026` : p.text;
|
|
129
|
+
kept.push({ text: piece, changed: p.changed });
|
|
130
|
+
room -= [...piece].length;
|
|
131
|
+
}
|
|
132
|
+
const pad = " ".repeat(Math.max(0, room));
|
|
133
|
+
return `${paint(["dim"], String(no).padStart(4))} ${paint([style], sign)}${paintParts(kept, style, paint)}${pad}`;
|
|
134
|
+
};
|
|
135
|
+
const empty = " ".repeat(half);
|
|
136
|
+
const lines = text.split("\n");
|
|
137
|
+
let i = 0;
|
|
138
|
+
while (i < lines.length) {
|
|
139
|
+
const line = lines[i];
|
|
140
|
+
if (isFileHeader(line)) {
|
|
141
|
+
out.push(paint(["bold"], line));
|
|
142
|
+
i++;
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
const hunk = /^@@ -(\d+)(?:,\d+)? \+(\d+)(?:,\d+)? @@/.exec(line);
|
|
146
|
+
if (hunk !== null) {
|
|
147
|
+
oldNo = Number(hunk[1]);
|
|
148
|
+
newNo = Number(hunk[2]);
|
|
149
|
+
out.push(paint(["cyan"], line));
|
|
150
|
+
i++;
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
if (isRemoved(line) || isAdded(line)) {
|
|
154
|
+
const removed = [];
|
|
155
|
+
while (i < lines.length && isRemoved(lines[i])) removed.push(lines[i++]);
|
|
156
|
+
const added = [];
|
|
157
|
+
while (i < lines.length && isAdded(lines[i])) added.push(lines[i++]);
|
|
158
|
+
for (let k = 0; k < Math.max(removed.length, added.length); k++) {
|
|
159
|
+
const r = removed[k];
|
|
160
|
+
const a = added[k];
|
|
161
|
+
const m = r !== void 0 && a !== void 0 ? wordDiff(r.slice(1), a.slice(1)) : void 0;
|
|
162
|
+
const left = r === void 0 ? empty : m !== void 0 ? markedCell(oldNo++, "-", m.a, "red") : cell(oldNo++, "-", r.slice(1), "red");
|
|
163
|
+
const right = a === void 0 ? "" : m !== void 0 ? markedCell(newNo++, "+", m.b, "green") : cell(newNo++, "+", a.slice(1), "green");
|
|
164
|
+
out.push(`${left} ${paint(["dim"], "\u2502")} ${right}`.trimEnd());
|
|
165
|
+
}
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
if (line.startsWith("\\")) {
|
|
169
|
+
out.push(paint(["dim"], line));
|
|
170
|
+
i++;
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
173
|
+
if (i === lines.length - 1 && line === "") break;
|
|
174
|
+
const content = line.startsWith(" ") ? line.slice(1) : line;
|
|
175
|
+
out.push(
|
|
176
|
+
`${cell(oldNo++, " ", content)} ${paint(["dim"], "\u2502")} ${cell(newNo++, " ", content)}`.trimEnd()
|
|
177
|
+
);
|
|
178
|
+
i++;
|
|
179
|
+
}
|
|
180
|
+
return out.join("\n");
|
|
181
|
+
}
|
|
182
|
+
function terminalDiff(text, columns, paint) {
|
|
183
|
+
if (hunkCount(text) === 0) return plainColours(text, paint);
|
|
184
|
+
return columns !== void 0 && columns >= SIDE_BY_SIDE_COLUMNS ? sideBySide(text, columns, paint) : unifiedDiff(text, paint);
|
|
185
|
+
}
|
|
186
|
+
function plainColours(text, paint) {
|
|
187
|
+
return text.split("\n").map(
|
|
188
|
+
(line) => isFileHeader(line) ? paint(["bold"], line) : line.startsWith("+") ? paint(["green"], line) : line.startsWith("-") ? paint(["red"], line) : line
|
|
189
|
+
).join("\n");
|
|
190
|
+
}
|
|
191
|
+
function hunkCount(text) {
|
|
192
|
+
return text.split("\n").filter((line) => line.startsWith("@@")).length;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// src/cli/approver.ts
|
|
196
|
+
var TerminalApprover = class {
|
|
197
|
+
/** Set by the CLI: it aborts the current turn. */
|
|
198
|
+
onInterrupt = () => {
|
|
199
|
+
};
|
|
200
|
+
/** One question at a time (0.14.1, review): two prompts at once mixed their keys. */
|
|
201
|
+
ask(request, signal) {
|
|
202
|
+
const next = this.asking === 0 ? this.askNow(request, signal) : this.queue.then(() => this.askNow(request, signal));
|
|
203
|
+
this.asking++;
|
|
204
|
+
this.queue = next.catch(() => {
|
|
205
|
+
}).finally(() => {
|
|
206
|
+
this.asking--;
|
|
207
|
+
});
|
|
208
|
+
return next;
|
|
209
|
+
}
|
|
210
|
+
asking = 0;
|
|
211
|
+
queue = Promise.resolve();
|
|
212
|
+
async askNow(request, signal) {
|
|
213
|
+
signal.throwIfAborted();
|
|
214
|
+
const out = process.stderr;
|
|
215
|
+
out.write(`
|
|
216
|
+
${header(request)}
|
|
217
|
+
${colorPreview(request, out.columns)}
|
|
218
|
+
`);
|
|
219
|
+
if (!process.stdin.isTTY) {
|
|
220
|
+
out.write("No terminal to ask for approval, so Garuda denies this call.\n");
|
|
221
|
+
return "deny";
|
|
222
|
+
}
|
|
223
|
+
const sessionLabel = request.labels?.session ?? (request.target.kind === "command" ? "Yes, and allow this exact command for this session" : request.target.kind === "url" ? `Yes, and allow ${request.target.host} for this session` : `Yes, and allow all ${request.tool} calls for this session`);
|
|
224
|
+
const { select } = await import("@inquirer/prompts");
|
|
225
|
+
try {
|
|
226
|
+
return await select(
|
|
227
|
+
{
|
|
228
|
+
message: request.question ?? "Allow?",
|
|
229
|
+
choices: [
|
|
230
|
+
{ name: request.labels?.once ?? "Yes, once", value: "once" },
|
|
231
|
+
{ name: sessionLabel, value: "session" },
|
|
232
|
+
{ name: request.labels?.deny ?? "No, deny", value: "deny" }
|
|
233
|
+
].filter((c) => request.choices?.includes(c.value) ?? true)
|
|
234
|
+
},
|
|
235
|
+
{ signal, output: out }
|
|
236
|
+
);
|
|
237
|
+
} catch (error) {
|
|
238
|
+
if (error.name === "ExitPromptError") this.onInterrupt();
|
|
239
|
+
throw error;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
};
|
|
243
|
+
var SwitchApprover = class {
|
|
244
|
+
constructor(current) {
|
|
245
|
+
this.current = current;
|
|
246
|
+
}
|
|
247
|
+
current;
|
|
248
|
+
/** Called before each question: the chat's notifier (0.6). */
|
|
249
|
+
onAsk = () => {
|
|
250
|
+
};
|
|
251
|
+
ask(request, signal) {
|
|
252
|
+
this.onAsk(request);
|
|
253
|
+
return this.current.ask(request, signal);
|
|
254
|
+
}
|
|
255
|
+
};
|
|
256
|
+
function visible(text) {
|
|
257
|
+
return text.replace(/[\u0000-\u0008\u000b-\u001f]/g, (c) => String.fromCodePoint(9216 + c.charCodeAt(0))).replace(/\u007f/g, "\u2421").replace(
|
|
258
|
+
/[\u0080-\u009f\u200b-\u200f\u202a-\u202e\u2060-\u2064\u2066-\u2069\ufeff\u{e0000}-\u{e007f}]/gu,
|
|
259
|
+
(c) => `[U+${(c.codePointAt(0) ?? 0).toString(16).toUpperCase().padStart(4, "0")}]`
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
function hasHidden(text) {
|
|
263
|
+
return visible(text) !== text;
|
|
264
|
+
}
|
|
265
|
+
var HIDDEN_WARNING = "! This holds hidden or control characters, shown as \u240D, \u241B or [U+\u2026]. Read it with care.";
|
|
266
|
+
function headerText(request) {
|
|
267
|
+
const { tool, target, isolation } = request;
|
|
268
|
+
if (request.title !== void 0) return visible(request.title);
|
|
269
|
+
if (target.kind === "command") {
|
|
270
|
+
const where = isolation === "none" ? "on your machine, no sandbox" : target.outsideSandbox ? "OUTSIDE the sandbox: network on, writes anywhere" : `sandbox: ${isolation}`;
|
|
271
|
+
return `${tool} wants to run a command (${where}):`;
|
|
272
|
+
}
|
|
273
|
+
if (target.kind === "input") return `${tool} wants to run with this input:`;
|
|
274
|
+
if (target.kind === "url") return `${tool} wants to fetch from ${visible(target.host)}:`;
|
|
275
|
+
return `${tool} wants to change ${visible(target.path)}:`;
|
|
276
|
+
}
|
|
277
|
+
function header(request) {
|
|
278
|
+
return styleText("bold", headerText(request));
|
|
279
|
+
}
|
|
280
|
+
function colorPreview({ target, preview }, columns) {
|
|
281
|
+
const warning = hasHidden(preview) ? `
|
|
282
|
+
${styleText("yellow", ` ${HIDDEN_WARNING}`)}` : "";
|
|
283
|
+
if (target.kind === "command") return `${styleText("cyan", ` $ ${visible(preview)}`)}${warning}`;
|
|
284
|
+
if (target.kind === "url") return `${visible(preview)}${warning}`;
|
|
285
|
+
return `${colorDiff(visible(preview), columns)}${warning}`;
|
|
286
|
+
}
|
|
287
|
+
var terminalPaint = (styles, text) => styles.length === 0 ? text : styleText([...styles], text);
|
|
288
|
+
function colorDiff(text, columns, paint = terminalPaint) {
|
|
289
|
+
return terminalDiff(text, columns, paint);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
export {
|
|
293
|
+
unifiedDiff,
|
|
294
|
+
hunkCount,
|
|
295
|
+
TerminalApprover,
|
|
296
|
+
SwitchApprover,
|
|
297
|
+
visible,
|
|
298
|
+
hasHidden,
|
|
299
|
+
HIDDEN_WARNING,
|
|
300
|
+
headerText,
|
|
301
|
+
header,
|
|
302
|
+
colorPreview,
|
|
303
|
+
terminalPaint,
|
|
304
|
+
colorDiff
|
|
305
|
+
};
|
|
306
|
+
//# sourceMappingURL=chunk-VISKX36R.js.map
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
JobGitError,
|
|
4
4
|
git
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-QXTHEFKP.js";
|
|
6
6
|
import {
|
|
7
7
|
inWriteScope
|
|
8
8
|
} from "./chunk-UIRJOQQS.js";
|
|
@@ -155,4 +155,4 @@ export {
|
|
|
155
155
|
outsideScope,
|
|
156
156
|
jobChanges
|
|
157
157
|
};
|
|
158
|
-
//# sourceMappingURL=chunk-
|
|
158
|
+
//# sourceMappingURL=chunk-WK5NE6RY.js.map
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
folderKind
|
|
4
|
+
} from "./chunk-42DSA4EA.js";
|
|
5
|
+
import {
|
|
6
|
+
detectTestCommand
|
|
7
|
+
} from "./chunk-AOGFYUKG.js";
|
|
8
|
+
|
|
9
|
+
// src/cli/tour.ts
|
|
10
|
+
import { createHash } from "crypto";
|
|
11
|
+
import { existsSync, readFileSync } from "fs";
|
|
12
|
+
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
13
|
+
import { join } from "path";
|
|
14
|
+
function detectStack(root, profiles) {
|
|
15
|
+
const has = (name) => existsSync(join(root, name));
|
|
16
|
+
const test = detectTestCommand(root, profiles);
|
|
17
|
+
const withTest = (label) => test === void 0 ? { label } : { label, test };
|
|
18
|
+
if (has("package.json")) {
|
|
19
|
+
let deps = {};
|
|
20
|
+
try {
|
|
21
|
+
const pkg = JSON.parse(readFileSync(join(root, "package.json"), "utf8"));
|
|
22
|
+
deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
23
|
+
} catch {
|
|
24
|
+
}
|
|
25
|
+
const language = has("tsconfig.json") || "typescript" in deps ? "TypeScript" : "JavaScript";
|
|
26
|
+
const runner = ["vitest", "jest", "mocha"].find((r) => r in deps);
|
|
27
|
+
const manager = has("pnpm-lock.yaml") ? "pnpm" : has("yarn.lock") ? "yarn" : has("bun.lockb") ? "bun" : "npm";
|
|
28
|
+
const app = "react-native" in deps ? " (React Native)" : "expo" in deps ? " (Expo)" : "";
|
|
29
|
+
return withTest(
|
|
30
|
+
`${language}${app}${runner === void 0 ? "" : ` with ${runner}`} (${manager})`
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
const profile = profiles[0];
|
|
34
|
+
if (profile !== void 0) return withTest(profile.label);
|
|
35
|
+
if (has("go.mod")) return withTest("Go");
|
|
36
|
+
if (has("Cargo.toml")) return withTest("Rust");
|
|
37
|
+
return void 0;
|
|
38
|
+
}
|
|
39
|
+
function tourPrompts(stack) {
|
|
40
|
+
return [
|
|
41
|
+
"Explain how this repository is laid out, in 10 lines or fewer.",
|
|
42
|
+
stack.test === void 0 ? "Find the riskiest function in this codebase and say why, in 5 lines." : `Run the tests (${stack.test}) and explain any failure.`,
|
|
43
|
+
"Find one function that has no test, and write a test for it."
|
|
44
|
+
];
|
|
45
|
+
}
|
|
46
|
+
function tourText(stack, prompts) {
|
|
47
|
+
return [
|
|
48
|
+
`This looks like ${stack.label}. Some first tasks:`,
|
|
49
|
+
...prompts.map((p, i) => ` ${i + 1}. ${p}`),
|
|
50
|
+
"Type a number, or your own task."
|
|
51
|
+
].join("\n");
|
|
52
|
+
}
|
|
53
|
+
var rootKey = (root) => createHash("sha256").update(root).digest("hex").slice(0, 16);
|
|
54
|
+
var MAX_TOURED = 200;
|
|
55
|
+
async function firstRunTour(root, home, profiles) {
|
|
56
|
+
if (folderKind(root) !== "code") return void 0;
|
|
57
|
+
const stack = detectStack(root, profiles);
|
|
58
|
+
if (stack === void 0) return void 0;
|
|
59
|
+
const file = join(home, ".garuda", "ui.json");
|
|
60
|
+
let data = {};
|
|
61
|
+
try {
|
|
62
|
+
data = JSON.parse(await readFile(file, "utf8"));
|
|
63
|
+
} catch {
|
|
64
|
+
}
|
|
65
|
+
const toured = Array.isArray(data.toured) ? data.toured.filter((t) => typeof t === "string") : [];
|
|
66
|
+
const key = rootKey(root);
|
|
67
|
+
if (toured.includes(key)) return void 0;
|
|
68
|
+
try {
|
|
69
|
+
await mkdir(join(home, ".garuda"), { recursive: true, mode: 448 });
|
|
70
|
+
const next = { ...data, toured: [...toured, key].slice(-MAX_TOURED) };
|
|
71
|
+
await writeFile(file, `${JSON.stringify(next)}
|
|
72
|
+
`, { mode: 384 });
|
|
73
|
+
} catch {
|
|
74
|
+
}
|
|
75
|
+
const prompts = tourPrompts(stack);
|
|
76
|
+
return { text: tourText(stack, prompts), prompts };
|
|
77
|
+
}
|
|
78
|
+
function tourChoice(input, prompts) {
|
|
79
|
+
const n = /^\s*([1-9])\s*$/.exec(input)?.[1];
|
|
80
|
+
return prompts !== void 0 && n !== void 0 ? prompts[Number(n) - 1] ?? input : input;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export {
|
|
84
|
+
detectStack,
|
|
85
|
+
tourPrompts,
|
|
86
|
+
tourText,
|
|
87
|
+
firstRunTour,
|
|
88
|
+
tourChoice
|
|
89
|
+
};
|
|
90
|
+
//# sourceMappingURL=chunk-Y62J7PTD.js.map
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
git
|
|
4
|
+
} from "./chunk-QXTHEFKP.js";
|
|
5
|
+
import {
|
|
6
|
+
HostExecutor
|
|
7
|
+
} from "./chunk-LMKGSYJC.js";
|
|
8
|
+
|
|
9
|
+
// src/buildCheck.ts
|
|
10
|
+
import { existsSync } from "fs";
|
|
11
|
+
import { dirname, join } from "path";
|
|
12
|
+
import { fileURLToPath } from "url";
|
|
13
|
+
async function garudaCommit() {
|
|
14
|
+
let dir;
|
|
15
|
+
try {
|
|
16
|
+
dir = dirname(fileURLToPath(import.meta.url));
|
|
17
|
+
} catch {
|
|
18
|
+
return void 0;
|
|
19
|
+
}
|
|
20
|
+
for (let i = 0; i < 4; i++) {
|
|
21
|
+
if (existsSync(join(dir, ".git"))) {
|
|
22
|
+
const r = await git(new HostExecutor(), dir, ["rev-parse", "HEAD"], { check: false });
|
|
23
|
+
return r.exitCode === 0 ? r.stdout.trim() : void 0;
|
|
24
|
+
}
|
|
25
|
+
dir = dirname(dir);
|
|
26
|
+
}
|
|
27
|
+
return void 0;
|
|
28
|
+
}
|
|
29
|
+
function staleBuildNote(build, checkout, what = "The tasks and the code that run are the older ones") {
|
|
30
|
+
if (build === void 0 || checkout === void 0 || build === checkout) return void 0;
|
|
31
|
+
return `This build is from commit ${build.slice(0, 7)}, but the checkout is at ${checkout.slice(0, 7)}. ${what}: run pnpm build first.`;
|
|
32
|
+
}
|
|
33
|
+
var CHAT_STALE = "The code that runs is the older one";
|
|
34
|
+
|
|
35
|
+
export {
|
|
36
|
+
garudaCommit,
|
|
37
|
+
staleBuildNote,
|
|
38
|
+
CHAT_STALE
|
|
39
|
+
};
|
|
40
|
+
//# sourceMappingURL=chunk-YAQ6QLKB.js.map
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
} from "./chunk-EU7PA45O.js";
|
|
7
7
|
import {
|
|
8
8
|
DEFAULT_ENV_ALLOWLIST
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-LMKGSYJC.js";
|
|
10
10
|
|
|
11
11
|
// src/lsp/install.ts
|
|
12
12
|
import { mkdir } from "fs/promises";
|
|
@@ -70,4 +70,4 @@ export {
|
|
|
70
70
|
installCommand,
|
|
71
71
|
installServer
|
|
72
72
|
};
|
|
73
|
-
//# sourceMappingURL=chunk-
|
|
73
|
+
//# sourceMappingURL=chunk-ZKT4P2PC.js.map
|