@garuda-agent/garuda 0.0.1 → 0.15.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 (66) hide show
  1. package/CHANGELOG.md +77 -0
  2. package/LICENSE +202 -0
  3. package/NOTICE +4 -0
  4. package/README.md +1097 -0
  5. package/SECURITY.md +32 -0
  6. package/dist/acpCommand-FZ2P5JFO.js +153 -0
  7. package/dist/anthropic-NQDBCHJU.js +327 -0
  8. package/dist/chunk-23FXBNBB.js +46 -0
  9. package/dist/chunk-2S62ZNTC.js +320 -0
  10. package/dist/chunk-2TAXSFWN.js +49 -0
  11. package/dist/chunk-36GQIVGT.js +526 -0
  12. package/dist/chunk-3CEPHS4C.js +231 -0
  13. package/dist/chunk-3NJNVZTK.js +123 -0
  14. package/dist/chunk-42DSA4EA.js +116 -0
  15. package/dist/chunk-4JSUUDFQ.js +118 -0
  16. package/dist/chunk-4P26OKTP.js +100 -0
  17. package/dist/chunk-5DEWP3YX.js +139 -0
  18. package/dist/chunk-A2QAIRQL.js +45 -0
  19. package/dist/chunk-ATW7BNIG.js +31 -0
  20. package/dist/chunk-B25VL4RU.js +242 -0
  21. package/dist/chunk-EPKWDCV4.js +9 -0
  22. package/dist/chunk-EU7PA45O.js +324 -0
  23. package/dist/chunk-FARS4R67.js +206 -0
  24. package/dist/chunk-G2AX7MGS.js +36 -0
  25. package/dist/chunk-HRGX53VC.js +173 -0
  26. package/dist/chunk-HUIK3WXO.js +234 -0
  27. package/dist/chunk-INRZR772.js +73 -0
  28. package/dist/chunk-K3SIUOAG.js +138 -0
  29. package/dist/chunk-K7KK7U44.js +9358 -0
  30. package/dist/chunk-KKB5W47S.js +231 -0
  31. package/dist/chunk-N4I6YS3E.js +73 -0
  32. package/dist/chunk-NXJ4XLB5.js +19 -0
  33. package/dist/chunk-OUCV3FCT.js +205 -0
  34. package/dist/chunk-PQNT34LY.js +1247 -0
  35. package/dist/chunk-PZS3V6P3.js +46 -0
  36. package/dist/chunk-S77XDSD4.js +157 -0
  37. package/dist/chunk-SI2QJYCR.js +1341 -0
  38. package/dist/chunk-WMOLXTBU.js +61 -0
  39. package/dist/chunk-YFQJXRIJ.js +193 -0
  40. package/dist/chunk-YQTGMCU6.js +111 -0
  41. package/dist/chunk-ZAE25JM2.js +158 -0
  42. package/dist/cli/index.js +1203 -0
  43. package/dist/create-N4I7TIZE.js +223 -0
  44. package/dist/deadline-F5RJJ2QW.js +86 -0
  45. package/dist/detect-LARDSLLZ.js +10 -0
  46. package/dist/evalCommand-3SSFMZQD.js +2798 -0
  47. package/dist/export-HN3CT7AV.js +158 -0
  48. package/dist/inkChat-34BTFG2K.js +1193 -0
  49. package/dist/install-VRPBZY5H.js +17 -0
  50. package/dist/job-3NYDMP2M.js +31 -0
  51. package/dist/jobCommand-XJ5GULS5.js +30 -0
  52. package/dist/launchd-QVHQ3VNN.js +40 -0
  53. package/dist/lspCommand-XNTBHXLA.js +99 -0
  54. package/dist/manager-4PMSXT47.js +14 -0
  55. package/dist/manager-CSI76AWF.js +847 -0
  56. package/dist/nightCommand-CR6ZHYGP.js +247 -0
  57. package/dist/oauth-W6OK6XXO.js +23 -0
  58. package/dist/openaiCompatible-CJWVJP5M.js +501 -0
  59. package/dist/policy-EJPLEEXP.js +31 -0
  60. package/dist/proxy-XJAHCZB2.js +192 -0
  61. package/dist/remove-LE7Q7K46.js +59 -0
  62. package/dist/run-ML6GSPN4.js +888 -0
  63. package/dist/server-R3GNIC33.js +676 -0
  64. package/dist/servers-6YDGWOZ6.js +24 -0
  65. package/dist/text-J2GD647J.js +11 -0
  66. package/package.json +84 -3
@@ -0,0 +1,247 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ msUntil
4
+ } from "./chunk-2S62ZNTC.js";
5
+ import {
6
+ notificationBytes,
7
+ pickChannel
8
+ } from "./chunk-N4I6YS3E.js";
9
+ import "./chunk-HRGX53VC.js";
10
+ import "./chunk-5DEWP3YX.js";
11
+ import "./chunk-PZS3V6P3.js";
12
+ import "./chunk-K3SIUOAG.js";
13
+ import {
14
+ defaultAgentEnv,
15
+ nightSpec,
16
+ removeSpec
17
+ } from "./chunk-S77XDSD4.js";
18
+ import "./chunk-YQTGMCU6.js";
19
+ import {
20
+ testSummary
21
+ } from "./chunk-OUCV3FCT.js";
22
+ import {
23
+ hostCommand,
24
+ shellWord
25
+ } from "./chunk-2TAXSFWN.js";
26
+ import {
27
+ createExecutor
28
+ } from "./chunk-SI2QJYCR.js";
29
+ import "./chunk-WMOLXTBU.js";
30
+ import "./chunk-HUIK3WXO.js";
31
+ import {
32
+ JOBS_DIR,
33
+ listJobs,
34
+ loadJob,
35
+ settleJob
36
+ } from "./chunk-KKB5W47S.js";
37
+ import "./chunk-3NJNVZTK.js";
38
+
39
+ // src/cli/nightCommand.ts
40
+ import { realpathSync } from "fs";
41
+
42
+ // src/jobs/night.ts
43
+ import { writeFile } from "fs/promises";
44
+ import { join } from "path";
45
+ var DEFAULT_NIGHT_PARALLEL = 3;
46
+ var MAX_NIGHT_PARALLEL = 10;
47
+ var JOB_PROCESS_TIMEOUT_MS = 24 * 36e5;
48
+ async function nightQueue(root) {
49
+ const jobs = await listJobs(root);
50
+ return jobs.filter((j) => j.status === "scheduled" && j.queue === true && j.launchd === void 0).sort((a, b) => a.createdAt.localeCompare(b.createdAt));
51
+ }
52
+ function processRunner(executor, env) {
53
+ const program = env.script === "" || env.script === env.node ? shellWord(env.node) : `${shellWord(env.node)} ${shellWord(env.script)}`;
54
+ return async (job) => {
55
+ const log = join(job.root, JOBS_DIR, `${job.id}.log`);
56
+ const result = await executor.run(
57
+ `${program} run ${shellWord(job.id)} >> ${shellWord(log)} 2>&1`,
58
+ {
59
+ root: job.root,
60
+ sandbox: false,
61
+ writePaths: [],
62
+ denyWritePaths: [],
63
+ denyReadPaths: [],
64
+ network: true,
65
+ envAllowlist: [],
66
+ timeoutMs: JOB_PROCESS_TIMEOUT_MS,
67
+ maxOutputBytes: 1e4
68
+ },
69
+ { env: processEnv() }
70
+ );
71
+ return result.exitCode;
72
+ };
73
+ }
74
+ function processEnv() {
75
+ const out = {};
76
+ for (const [k, v] of Object.entries(process.env)) if (typeof v === "string") out[k] = v;
77
+ return out;
78
+ }
79
+ async function runQueue(jobs, run, parallel, report = {}) {
80
+ let next = 0;
81
+ const worker = async () => {
82
+ for (; ; ) {
83
+ const job = jobs[next++];
84
+ if (job === void 0) return;
85
+ report.onStart?.(job);
86
+ let code = null;
87
+ try {
88
+ code = await run(job);
89
+ } catch {
90
+ code = null;
91
+ }
92
+ await report.settle?.(job, code).catch(() => {
93
+ });
94
+ report.onEnd?.(job, code);
95
+ }
96
+ };
97
+ await Promise.all(Array.from({ length: Math.max(1, Math.min(parallel, jobs.length)) }, worker));
98
+ }
99
+ function nightDigest(jobs, started, ended) {
100
+ const ready = jobs.filter((j) => j.result?.proof?.verdict === "ready");
101
+ const cost = jobs.reduce(
102
+ (sum, j) => sum + (j.result?.costUsd ?? 0) + (j.result?.proof?.review?.costUsd ?? 0),
103
+ 0
104
+ );
105
+ const lines = [
106
+ `# Garuda night shift: ${local(started)}`,
107
+ "",
108
+ `${jobs.length} job(s): ${ready.length} ready to merge, ${jobs.length - ready.length} need a look. Time ${Math.round((ended.getTime() - started.getTime()) / 6e4)} min \xB7 cost $${cost.toFixed(4)}.`,
109
+ "",
110
+ "| Job | Verdict | Tests after | Files | Cost | Branch |",
111
+ "| --- | --- | --- | --- | --- | --- |"
112
+ ];
113
+ for (const j of jobs) {
114
+ const r = j.result;
115
+ const verdict = r?.proof === void 0 ? j.status : r.proof.verdict === "ready" ? "ready to merge" : "needs a look";
116
+ const jobCost = r === void 0 ? "\u2013" : `$${((r.costUsd ?? 0) + (r.proof?.review?.costUsd ?? 0)).toFixed(4)}`;
117
+ lines.push(
118
+ `| ${j.id}: ${cell(j.title)} | ${verdict} | ${j.test === void 0 ? "no tests" : testSummary(r?.proof?.after)} | ${r?.files.length ?? 0} | ${jobCost} | ${j.branch} |`
119
+ );
120
+ }
121
+ const looks = jobs.filter((j) => j.result?.proof?.verdict !== "ready");
122
+ if (looks.length > 0) {
123
+ lines.push("", "## Needs a look", "");
124
+ for (const j of looks) {
125
+ const flags = j.result?.proof?.flags.map((f) => f.text) ?? [];
126
+ const summary = /^SUMMARY:\s*(.+)$/m.exec(j.result?.proof?.review?.text ?? "")?.[1];
127
+ const why = [...flags, ...summary === void 0 ? [] : [`Review: ${summary}`]];
128
+ lines.push(`- ${j.id}: ${why.length === 0 ? `status ${j.status}` : why.join(" ")}`);
129
+ }
130
+ }
131
+ lines.push(
132
+ "",
133
+ "## Next",
134
+ "",
135
+ "Each job's report: `/jobs <id>` or `.garuda/jobs/<id>.md`. Merge a ready branch with `git merge <branch>`."
136
+ );
137
+ return lines.join("\n");
138
+ }
139
+ async function writeDigest(root, text, started) {
140
+ const file = join(root, JOBS_DIR, `night-${stamp(started)}.md`);
141
+ await writeFile(file, `${text}
142
+ `, { mode: 384 });
143
+ return file;
144
+ }
145
+ var cell = (text) => text.replace(/\|/g, "\\|").replace(/\n/g, " ");
146
+ var pad = (n) => String(n).padStart(2, "0");
147
+ function local(d) {
148
+ return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`;
149
+ }
150
+ function stamp(d) {
151
+ return `${d.getFullYear()}${pad(d.getMonth() + 1)}${pad(d.getDate())}-${pad(d.getHours())}${pad(d.getMinutes())}`;
152
+ }
153
+
154
+ // src/cli/nightCommand.ts
155
+ async function nightCommand(options, renderer, runner, root = realpathSync(process.cwd()), agent = {}) {
156
+ const code = await runNight(options, renderer, runner, root, agent);
157
+ if (options.fromLaunchd === true) {
158
+ await removeSpec(
159
+ agent.executor ?? createExecutor("host").executor,
160
+ nightSpec(root),
161
+ agent.env ?? defaultAgentEnv()
162
+ );
163
+ }
164
+ return code;
165
+ }
166
+ async function runNight(options, renderer, runner, root, agent) {
167
+ const parallel = options.parallel === void 0 ? DEFAULT_NIGHT_PARALLEL : Number(options.parallel);
168
+ if (!Number.isInteger(parallel) || parallel < 1 || parallel > MAX_NIGHT_PARALLEL) {
169
+ renderer.error(`--parallel takes 1 to ${MAX_NIGHT_PARALLEL}.`);
170
+ return 1;
171
+ }
172
+ if (options.at !== void 0) {
173
+ const m = /^([01]\d|2[0-3]):([0-5]\d)$/.exec(options.at);
174
+ if (m === null) {
175
+ renderer.error(`"${options.at}" is not a time. Use HH:MM, for example 01:00.`);
176
+ return 1;
177
+ }
178
+ const ms = msUntil(Number(m[1]), Number(m[2]));
179
+ renderer.info(
180
+ `The night shift starts at ${options.at} (in ${Math.floor(ms / 36e5)} h ${Math.round(ms % 36e5 / 6e4)} min). Keep this terminal open and the Mac awake and on power. Ctrl-C cancels.`
181
+ );
182
+ const cancelled = await new Promise((resolve) => {
183
+ const timer = setTimeout(() => {
184
+ process.off("SIGINT", cancel);
185
+ resolve(false);
186
+ }, ms);
187
+ const cancel = () => {
188
+ clearTimeout(timer);
189
+ resolve(true);
190
+ };
191
+ process.once("SIGINT", cancel);
192
+ });
193
+ if (cancelled) {
194
+ renderer.warn("The wait was cancelled. The queue is unchanged.");
195
+ return 130;
196
+ }
197
+ }
198
+ const queue = await nightQueue(root);
199
+ if (queue.length === 0) {
200
+ renderer.info("The night queue is empty. Make a plan (/plan), then /schedule adds it.");
201
+ return 0;
202
+ }
203
+ const started = /* @__PURE__ */ new Date();
204
+ renderer.info(
205
+ `Night shift: ${queue.length} job(s), up to ${parallel} at a time. Each job logs to .garuda/jobs/<id>.log.`
206
+ );
207
+ const run = runner ?? processRunner(createExecutor("host").executor, defaultAgentEnv());
208
+ await runQueue(queue, run, parallel, {
209
+ onStart: (job) => renderer.info(`\u25B6 ${job.id}: ${job.title}`),
210
+ onEnd: (job, code) => renderer.info(`\u25A0 ${job.id} ended (exit code ${code ?? "none"})`),
211
+ // A job process that was killed leaves its job "running": mark it failed (0.14.1, review).
212
+ settle: (job, code) => settleJob(root, job.id, code)
213
+ });
214
+ const jobs = await Promise.all(queue.map((j) => loadJob(root, j.id).catch(() => j)));
215
+ const digest = nightDigest(jobs, started, /* @__PURE__ */ new Date());
216
+ const file = await writeDigest(root, digest, started);
217
+ renderer.info(`
218
+ ${digest}
219
+
220
+ Digest: ${file}`);
221
+ const ready = jobs.filter((j) => j.result?.proof?.verdict === "ready").length;
222
+ const note = `Garuda night shift: ${jobs.length} job(s), ${ready} ready to merge`;
223
+ if (process.stdout.isTTY) {
224
+ process.stdout.write(notificationBytes(pickChannel(void 0), note));
225
+ } else if (options.fromLaunchd === true && (agent.platform ?? process.platform) === "darwin") {
226
+ await hostCommand(
227
+ agent.executor ?? createExecutor("host").executor,
228
+ root,
229
+ [
230
+ "osascript",
231
+ "-e",
232
+ "on run argv",
233
+ "-e",
234
+ 'display notification (item 1 of argv) with title "Garuda"',
235
+ "-e",
236
+ "end run",
237
+ note
238
+ ],
239
+ { check: false }
240
+ );
241
+ }
242
+ return 0;
243
+ }
244
+ export {
245
+ nightCommand
246
+ };
247
+ //# sourceMappingURL=nightCommand-CR6ZHYGP.js.map
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ AUTH_FILE,
4
+ AuthStore,
5
+ CallbackError,
6
+ GarudaOAuthProvider,
7
+ SIGN_IN_TIMEOUT_MS,
8
+ authKey,
9
+ freePort,
10
+ waitForCallback
11
+ } from "./chunk-3CEPHS4C.js";
12
+ import "./chunk-PZS3V6P3.js";
13
+ export {
14
+ AUTH_FILE,
15
+ AuthStore,
16
+ CallbackError,
17
+ GarudaOAuthProvider,
18
+ SIGN_IN_TIMEOUT_MS,
19
+ authKey,
20
+ freePort,
21
+ waitForCallback
22
+ };
23
+ //# sourceMappingURL=oauth-W6OK6XXO.js.map