@garuda-agent/garuda 0.0.1 → 0.14.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.
Files changed (61) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/LICENSE +202 -0
  3. package/NOTICE +4 -0
  4. package/README.md +1040 -0
  5. package/SECURITY.md +32 -0
  6. package/dist/anthropic-NQDBCHJU.js +327 -0
  7. package/dist/chunk-35GMLLJW.js +157 -0
  8. package/dist/chunk-36GQIVGT.js +526 -0
  9. package/dist/chunk-3CEPHS4C.js +231 -0
  10. package/dist/chunk-3NJNVZTK.js +123 -0
  11. package/dist/chunk-42DSA4EA.js +116 -0
  12. package/dist/chunk-4P26OKTP.js +100 -0
  13. package/dist/chunk-5DEWP3YX.js +139 -0
  14. package/dist/chunk-6TWBYMY7.js +9 -0
  15. package/dist/chunk-A2QAIRQL.js +45 -0
  16. package/dist/chunk-ATW7BNIG.js +31 -0
  17. package/dist/chunk-D5O5CIWK.js +1339 -0
  18. package/dist/chunk-EU7PA45O.js +324 -0
  19. package/dist/chunk-FARS4R67.js +206 -0
  20. package/dist/chunk-G2AX7MGS.js +36 -0
  21. package/dist/chunk-HUIK3WXO.js +234 -0
  22. package/dist/chunk-ITITLNAR.js +9341 -0
  23. package/dist/chunk-KKB5W47S.js +231 -0
  24. package/dist/chunk-KWRJREUH.js +283 -0
  25. package/dist/chunk-N4I6YS3E.js +73 -0
  26. package/dist/chunk-OUCV3FCT.js +205 -0
  27. package/dist/chunk-PZS3V6P3.js +46 -0
  28. package/dist/chunk-QOW5TK4L.js +320 -0
  29. package/dist/chunk-U4OQVT2T.js +73 -0
  30. package/dist/chunk-V7WPGQLB.js +207 -0
  31. package/dist/chunk-W7BPYQMW.js +173 -0
  32. package/dist/chunk-WMOLXTBU.js +61 -0
  33. package/dist/chunk-YIZWYUBG.js +138 -0
  34. package/dist/chunk-YM6T4J5V.js +1350 -0
  35. package/dist/chunk-YQTGMCU6.js +111 -0
  36. package/dist/chunk-ZAE25JM2.js +158 -0
  37. package/dist/chunk-ZGZ2ZADL.js +49 -0
  38. package/dist/cli/index.js +1191 -0
  39. package/dist/create-Y5SXJUXO.js +223 -0
  40. package/dist/deadline-F5RJJ2QW.js +86 -0
  41. package/dist/detect-LARDSLLZ.js +10 -0
  42. package/dist/evalCommand-5TG2CKZY.js +2795 -0
  43. package/dist/export-HN3CT7AV.js +158 -0
  44. package/dist/inkChat-3J26R24L.js +1190 -0
  45. package/dist/install-XWLU22OH.js +17 -0
  46. package/dist/job-3NYDMP2M.js +31 -0
  47. package/dist/jobCommand-IYWZWTSI.js +30 -0
  48. package/dist/launchd-2FL5UN2U.js +40 -0
  49. package/dist/lspCommand-TJEZBV2E.js +99 -0
  50. package/dist/manager-4PMSXT47.js +14 -0
  51. package/dist/manager-EBTYO2GR.js +847 -0
  52. package/dist/nightCommand-DUNWJASI.js +247 -0
  53. package/dist/oauth-W6OK6XXO.js +23 -0
  54. package/dist/openaiCompatible-CJWVJP5M.js +501 -0
  55. package/dist/policy-EJPLEEXP.js +31 -0
  56. package/dist/proxy-XJAHCZB2.js +192 -0
  57. package/dist/remove-AENULZZE.js +59 -0
  58. package/dist/run-66Y6R2KU.js +886 -0
  59. package/dist/servers-6YDGWOZ6.js +24 -0
  60. package/dist/text-J2GD647J.js +11 -0
  61. package/package.json +83 -3
package/SECURITY.md ADDED
@@ -0,0 +1,32 @@
1
+ # Security policy
2
+
3
+ Garuda runs commands and edits files for a model, so we take security reports seriously.
4
+
5
+ ## Supported versions
6
+
7
+ | Version | Supported |
8
+ | --- | --- |
9
+ | 0.14.x | Yes |
10
+ | Older | No |
11
+
12
+ ## Report a vulnerability
13
+
14
+ Do not open a public issue. Use GitHub's private vulnerability reporting: in this repository, open
15
+ **Security**, then **Report a vulnerability**. Give:
16
+
17
+ - the version (`garuda --version`) and the platform (macOS or Linux, the sandbox in use);
18
+ - the steps to reproduce, and what you expected;
19
+ - the effect, for example a sandbox escape, a permission or team-policy bypass, a secret in a
20
+ session file or the audit log, or a write that the user did not approve.
21
+
22
+ You get an answer within 7 days. We agree a fix and a disclosure date with you, and we credit you in
23
+ the release notes unless you ask us not to.
24
+
25
+ ## Scope
26
+
27
+ In scope: the permission engine and the team policy, the OS sandbox (Seatbelt, bubblewrap), the
28
+ network allowlist and its proxy, secret redaction, the audit log, and the consent for project
29
+ content (hooks, MCP servers, settings, commands, skills, agents).
30
+
31
+ Known limits are listed in the README under the status table. A report about one of them is still
32
+ welcome when it shows a new way to reach the same effect.
@@ -0,0 +1,327 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/model/anthropic.ts
4
+ import Anthropic from "@anthropic-ai/sdk";
5
+ import { Agent, fetch as undiciFetch } from "undici";
6
+ var WEB_SEARCH_TOOL = "web_search_20250305";
7
+ var AnthropicClient = class {
8
+ /** Claude's web search runs on Anthropic's servers (0.6). */
9
+ serverTools = ["web_search"];
10
+ client;
11
+ model;
12
+ constructor(options) {
13
+ this.model = options.model;
14
+ this.client = options.client ?? new Anthropic(clientOptions(options.apiKey));
15
+ }
16
+ async *stream(request, options) {
17
+ const stream = this.client.messages.stream(
18
+ toWireParams(this.model, request),
19
+ options?.signal === void 0 ? {} : { signal: options.signal }
20
+ );
21
+ for await (const event of stream) {
22
+ if (event.type === "content_block_delta" && event.delta.type === "text_delta") {
23
+ yield { type: "text_delta", text: event.delta.text };
24
+ } else if (event.type === "content_block_delta" && event.delta.type === "thinking_delta" && event.delta.thinking !== "" && request.thinking?.hide !== true) {
25
+ yield { type: "thinking_delta", text: event.delta.thinking };
26
+ }
27
+ }
28
+ const final = await stream.finalMessage();
29
+ const response = fromWireMessage(final);
30
+ yield {
31
+ type: "response",
32
+ response: request.thinking?.hide === true ? withHiddenThinking(response) : response
33
+ };
34
+ }
35
+ };
36
+ function withHiddenThinking(response) {
37
+ return {
38
+ ...response,
39
+ content: response.content.map((b) => b.type === "thinking" ? { ...b, text: "" } : b)
40
+ };
41
+ }
42
+ var STREAM_IDLE_MS = 20 * 6e4;
43
+ var dispatchers = /* @__PURE__ */ new Map();
44
+ function streamFetch(idleMs = STREAM_IDLE_MS) {
45
+ let agent = dispatchers.get(idleMs);
46
+ if (agent === void 0) {
47
+ agent = new Agent({ bodyTimeout: idleMs });
48
+ dispatchers.set(idleMs, agent);
49
+ }
50
+ const dispatcher = agent;
51
+ return ((input, init) => undiciFetch(input, { ...init, dispatcher }));
52
+ }
53
+ function clientOptions(apiKey) {
54
+ return { ...apiKey === void 0 ? {} : { apiKey }, fetch: streamFetch() };
55
+ }
56
+ function toWireParams(model, request) {
57
+ const params = {
58
+ model,
59
+ max_tokens: request.maxTokens,
60
+ system: [{ type: "text", text: request.system, cache_control: { type: "ephemeral" } }],
61
+ messages: request.messages.map(toWireMessage)
62
+ };
63
+ const last = params.messages.at(-1);
64
+ if (last !== void 0 && Array.isArray(last.content) && last.content.length > 0) {
65
+ const blocks = last.content;
66
+ const block = blocks.findLast((b) => b.type !== "thinking" && b.type !== "redacted_thinking");
67
+ if (block !== void 0) block.cache_control = { type: "ephemeral" };
68
+ }
69
+ const tools = toWireTools(request.tools, request.serverTools ?? []);
70
+ if (tools.length > 0) params.tools = tools;
71
+ const thinking = request.thinking;
72
+ if (thinking?.adaptive === true || thinking?.display !== void 0) {
73
+ params.thinking = {
74
+ type: "adaptive",
75
+ ...thinking.display === void 0 ? {} : { display: thinking.display }
76
+ };
77
+ }
78
+ if (thinking?.effort !== void 0) params.output_config = { effort: thinking.effort };
79
+ return params;
80
+ }
81
+ function toWireTools(tools, serverTools = []) {
82
+ const out = [
83
+ ...tools.map(
84
+ (tool) => ({
85
+ name: tool.name,
86
+ description: tool.description,
87
+ input_schema: { ...tool.inputSchema, type: "object" }
88
+ })
89
+ ),
90
+ ...serverTools.map(
91
+ (spec) => ({
92
+ type: WEB_SEARCH_TOOL,
93
+ name: "web_search",
94
+ max_uses: spec.maxUses,
95
+ ...spec.allowedDomains === void 0 ? {} : { allowed_domains: [...spec.allowedDomains] },
96
+ ...spec.blockedDomains === void 0 ? {} : { blocked_domains: [...spec.blockedDomains] }
97
+ })
98
+ )
99
+ ];
100
+ const last = out.at(-1);
101
+ if (last !== void 0) last.cache_control = { type: "ephemeral" };
102
+ return out;
103
+ }
104
+ function toWireMessage(message) {
105
+ return { role: message.role, content: message.content.map(toWireBlock) };
106
+ }
107
+ function toWireBlock(block) {
108
+ switch (block.type) {
109
+ case "text":
110
+ return block.citations === void 0 ? { type: "text", text: block.text } : {
111
+ type: "text",
112
+ text: block.text,
113
+ citations: structuredClone(block.citations)
114
+ };
115
+ // Server tool blocks go back exactly as they came (the results hold encrypted content), and so
116
+ // do thinking blocks (0.9: the signature checks them).
117
+ case "server_tool_use":
118
+ case "server_tool_result":
119
+ case "thinking":
120
+ return structuredClone(block.wire);
121
+ case "tool_use":
122
+ return { type: "tool_use", id: block.id, name: block.name, input: block.input };
123
+ case "tool_result":
124
+ return {
125
+ type: "tool_result",
126
+ tool_use_id: block.toolUseId,
127
+ content: block.content,
128
+ is_error: block.isError
129
+ };
130
+ }
131
+ }
132
+ function fromWireMessage(message) {
133
+ const content = [];
134
+ for (const block of message.content) {
135
+ if (block.type === "text") {
136
+ const citations = block.citations ?? [];
137
+ content.push(
138
+ citations.length === 0 ? { type: "text", text: block.text } : { type: "text", text: block.text, citations: structuredClone(citations) }
139
+ );
140
+ } else if (block.type === "tool_use") {
141
+ content.push({ type: "tool_use", id: block.id, name: block.name, input: block.input });
142
+ } else if (block.type === "server_tool_use") {
143
+ content.push({
144
+ type: "server_tool_use",
145
+ id: block.id,
146
+ name: block.name,
147
+ input: block.input,
148
+ wire: structuredClone(block)
149
+ });
150
+ } else if (block.type === "web_search_tool_result") {
151
+ content.push(webSearchResult(block));
152
+ } else if (block.type === "thinking") {
153
+ content.push({ type: "thinking", text: block.thinking, wire: structuredClone(block) });
154
+ } else if (block.type === "redacted_thinking") {
155
+ content.push({ type: "thinking", text: "", wire: structuredClone(block) });
156
+ }
157
+ }
158
+ return {
159
+ content,
160
+ stopReason: fromWireStopReason(message.stop_reason),
161
+ usage: fromWireUsage(message.usage)
162
+ };
163
+ }
164
+ function webSearchResult(block) {
165
+ const wire = structuredClone(block);
166
+ if (!Array.isArray(block.content)) {
167
+ return {
168
+ type: "server_tool_result",
169
+ toolUseId: block.tool_use_id,
170
+ name: "web_search",
171
+ results: [],
172
+ error: block.content.error_code,
173
+ wire
174
+ };
175
+ }
176
+ return {
177
+ type: "server_tool_result",
178
+ toolUseId: block.tool_use_id,
179
+ name: "web_search",
180
+ results: block.content.map((r) => ({
181
+ title: r.title,
182
+ url: r.url,
183
+ ...r.page_age === null || r.page_age === void 0 ? {} : { age: r.page_age }
184
+ })),
185
+ wire
186
+ };
187
+ }
188
+ function fromWireStopReason(reason) {
189
+ switch (reason) {
190
+ case "end_turn":
191
+ case "stop_sequence":
192
+ return "end_turn";
193
+ case "tool_use":
194
+ return "tool_use";
195
+ case "max_tokens":
196
+ case "model_context_window_exceeded":
197
+ return "max_tokens";
198
+ case "refusal":
199
+ return "refusal";
200
+ case "pause_turn":
201
+ return "pause_turn";
202
+ default:
203
+ return "other";
204
+ }
205
+ }
206
+ function fromWireUsage(usage) {
207
+ const searches = usage.server_tool_use?.web_search_requests ?? 0;
208
+ return {
209
+ inputTokens: usage.input_tokens,
210
+ outputTokens: usage.output_tokens,
211
+ cacheReadTokens: usage.cache_read_input_tokens ?? 0,
212
+ cacheWriteTokens: usage.cache_creation_input_tokens ?? 0,
213
+ ...searches > 0 ? { webSearches: searches } : {}
214
+ };
215
+ }
216
+ var BATCH_CHECK_TIMEOUT_MS = 6e4;
217
+ var MAX_FAILED_CHECKS = 10;
218
+ var BATCH_POLL_MS = [5e3, 1e4, 2e4, 3e4];
219
+ var AnthropicBatchClient = class {
220
+ serverTools = ["web_search"];
221
+ client;
222
+ model;
223
+ pollMs;
224
+ onWait;
225
+ noticeMs;
226
+ constructor(options) {
227
+ this.model = options.model;
228
+ this.pollMs = options.pollMs ?? BATCH_POLL_MS;
229
+ this.onWait = options.onWait;
230
+ this.noticeMs = options.noticeMs ?? 6e4;
231
+ this.client = options.client ?? new Anthropic(clientOptions(options.apiKey));
232
+ }
233
+ async *stream(request, options) {
234
+ const signal = options?.signal;
235
+ const params = toWireParams(
236
+ this.model,
237
+ request
238
+ );
239
+ const batch = await this.client.messages.batches.create(
240
+ { requests: [{ custom_id: "garuda", params }] },
241
+ signal === void 0 ? {} : { signal }
242
+ );
243
+ const started = Date.now();
244
+ this.onWait?.({ batchId: batch.id, waitedMs: 0, status: "created" });
245
+ let noticed = 0;
246
+ let failed = 0;
247
+ try {
248
+ for (let i = 0; ; i++) {
249
+ await wait(this.pollMs[Math.min(i, this.pollMs.length - 1)] ?? 3e4, signal);
250
+ let status;
251
+ try {
252
+ const state = await this.client.messages.batches.retrieve(batch.id, void 0, {
253
+ timeout: BATCH_CHECK_TIMEOUT_MS,
254
+ ...signal === void 0 ? {} : { signal }
255
+ });
256
+ status = state.processing_status;
257
+ failed = 0;
258
+ } catch (error) {
259
+ if (signal?.aborted === true || ++failed >= MAX_FAILED_CHECKS) throw error;
260
+ status = "check failed, trying again";
261
+ }
262
+ if (status === "ended") break;
263
+ const waited = Date.now() - started;
264
+ if (waited - noticed >= this.noticeMs) {
265
+ noticed = waited;
266
+ this.onWait?.({ batchId: batch.id, waitedMs: waited, status });
267
+ }
268
+ }
269
+ } catch (error) {
270
+ await this.client.messages.batches.cancel(batch.id).catch(() => void 0);
271
+ throw error;
272
+ }
273
+ const results = await this.client.messages.batches.results(batch.id);
274
+ for await (const item of results) {
275
+ if (item.custom_id !== "garuda") continue;
276
+ const result = item.result;
277
+ if (result.type === "succeeded") {
278
+ const response = { ...fromWireMessage(result.message), priceFactor: 0.5 };
279
+ const text = response.content.map((b) => b.type === "text" ? b.text : "").join("");
280
+ if (text !== "") yield { type: "text_delta", text };
281
+ yield { type: "response", response };
282
+ return;
283
+ }
284
+ if (result.type === "errored") {
285
+ const detail = result.error.error;
286
+ throw Object.assign(new Error(`Batch request failed: ${detail.message}`), {
287
+ error: result.error
288
+ });
289
+ }
290
+ throw new Error(`The batch request was ${result.type}.`);
291
+ }
292
+ throw new Error("The batch ended without a result.");
293
+ }
294
+ };
295
+ function wait(ms, signal) {
296
+ return new Promise((resolve, reject) => {
297
+ if (signal?.aborted) {
298
+ reject(signal.reason);
299
+ return;
300
+ }
301
+ const timer = setTimeout(() => {
302
+ signal?.removeEventListener("abort", onAbort);
303
+ resolve();
304
+ }, ms);
305
+ const onAbort = () => {
306
+ clearTimeout(timer);
307
+ reject(signal?.reason);
308
+ };
309
+ signal?.addEventListener("abort", onAbort, { once: true });
310
+ });
311
+ }
312
+ export {
313
+ AnthropicBatchClient,
314
+ AnthropicClient,
315
+ BATCH_CHECK_TIMEOUT_MS,
316
+ BATCH_POLL_MS,
317
+ STREAM_IDLE_MS,
318
+ WEB_SEARCH_TOOL,
319
+ clientOptions,
320
+ fromWireMessage,
321
+ streamFetch,
322
+ toWireMessage,
323
+ toWireParams,
324
+ toWireTools,
325
+ withHiddenThinking
326
+ };
327
+ //# sourceMappingURL=anthropic-NQDBCHJU.js.map
@@ -0,0 +1,157 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ hostCommand,
4
+ shellWord
5
+ } from "./chunk-ZGZ2ZADL.js";
6
+ import {
7
+ JOBS_DIR
8
+ } from "./chunk-KKB5W47S.js";
9
+
10
+ // src/jobs/launchd.ts
11
+ import { createHash } from "crypto";
12
+ import { existsSync, readFileSync } from "fs";
13
+ import { mkdir, rm, writeFile } from "fs/promises";
14
+ import { homedir } from "os";
15
+ import { basename, join } from "path";
16
+ function defaultAgentEnv() {
17
+ const shell = process.env.SHELL ?? "";
18
+ return {
19
+ home: homedir(),
20
+ uid: process.getuid?.() ?? 501,
21
+ shell: /\/(zsh|bash)$/.test(shell) ? shell : "/bin/zsh",
22
+ node: process.execPath,
23
+ script: process.argv[1] ?? ""
24
+ };
25
+ }
26
+ function agentLabel(id) {
27
+ return `dev.garuda.job.${id}`;
28
+ }
29
+ function agentPath(home, id) {
30
+ return join(home, "Library", "LaunchAgents", `${agentLabel(id)}.plist`);
31
+ }
32
+ function nextTime(at, now = /* @__PURE__ */ new Date()) {
33
+ const [hour, minute] = at.split(":").map(Number);
34
+ const next = new Date(now);
35
+ next.setHours(hour, minute, 0, 0);
36
+ if (next.getTime() <= now.getTime()) next.setDate(next.getDate() + 1);
37
+ return next;
38
+ }
39
+ var xml = (text) => text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
40
+ function jobSpec(job) {
41
+ return {
42
+ label: agentLabel(job.id),
43
+ root: job.root,
44
+ args: ["run", job.id, "--from-launchd"],
45
+ log: join(job.root, JOBS_DIR, `${job.id}.log`)
46
+ };
47
+ }
48
+ function nightSpec(root) {
49
+ const hash = createHash("sha256").update(root).digest("hex").slice(0, 8);
50
+ const name = basename(root).replace(/[^A-Za-z0-9_-]/g, "_").slice(0, 40) || "project";
51
+ return {
52
+ label: `dev.garuda.night.${name}-${hash}`,
53
+ root,
54
+ args: ["night", "--from-launchd"],
55
+ log: join(root, JOBS_DIR, "night.log")
56
+ };
57
+ }
58
+ function specPath(home, spec) {
59
+ return join(home, "Library", "LaunchAgents", `${spec.label}.plist`);
60
+ }
61
+ function agentPlist(job, env, when) {
62
+ return specPlist(jobSpec(job), env, when);
63
+ }
64
+ function specPlist(spec, env, when) {
65
+ const program = env.script === "" || env.script === env.node ? shellWord(env.node) : `${shellWord(env.node)} ${shellWord(env.script)}`;
66
+ const command = `cd ${shellWord(spec.root)} && exec ${program} ${spec.args.map(shellWord).join(" ")}`;
67
+ const args = ["/usr/bin/caffeinate", "-i", env.shell, "-lic", command];
68
+ const int = (key, value) => ` <key>${key}</key><integer>${value}</integer>`;
69
+ return [
70
+ '<?xml version="1.0" encoding="UTF-8"?>',
71
+ '<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">',
72
+ '<plist version="1.0">',
73
+ " <dict>",
74
+ ` <key>Label</key><string>${xml(spec.label)}</string>`,
75
+ " <key>ProgramArguments</key>",
76
+ " <array>",
77
+ ...args.map((a) => ` <string>${xml(a)}</string>`),
78
+ " </array>",
79
+ ` <key>WorkingDirectory</key><string>${xml(spec.root)}</string>`,
80
+ " <key>StartCalendarInterval</key>",
81
+ " <dict>",
82
+ int("Month", when.getMonth() + 1),
83
+ int("Day", when.getDate()),
84
+ int("Hour", when.getHours()),
85
+ int("Minute", when.getMinutes()),
86
+ " </dict>",
87
+ " <key>RunAtLoad</key><false/>",
88
+ ` <key>StandardOutPath</key><string>${xml(spec.log)}</string>`,
89
+ ` <key>StandardErrorPath</key><string>${xml(spec.log)}</string>`,
90
+ " </dict>",
91
+ "</plist>",
92
+ ""
93
+ ].join("\n");
94
+ }
95
+ async function installAgent(executor, job, env, now = /* @__PURE__ */ new Date()) {
96
+ if (job.at === void 0) throw new Error("The job has no time.");
97
+ return installSpec(executor, jobSpec(job), env, nextTime(job.at, now));
98
+ }
99
+ async function installSpec(executor, spec, env, when) {
100
+ const plist = specPath(env.home, spec);
101
+ await mkdir(join(env.home, "Library", "LaunchAgents"), { recursive: true });
102
+ await writeFile(plist, specPlist(spec, env, when), { mode: 420 });
103
+ await hostCommand(executor, spec.root, ["launchctl", "bootout", `gui/${env.uid}/${spec.label}`], {
104
+ check: false
105
+ });
106
+ await hostCommand(executor, spec.root, ["launchctl", "bootstrap", `gui/${env.uid}`, plist]);
107
+ return { plist, when };
108
+ }
109
+ async function removeSpec(executor, spec, env) {
110
+ const plist = specPath(env.home, spec);
111
+ const had = existsSync(plist);
112
+ await rm(plist, { force: true });
113
+ const out = await hostCommand(
114
+ executor,
115
+ spec.root,
116
+ ["launchctl", "bootout", `gui/${env.uid}/${spec.label}`],
117
+ { check: false }
118
+ );
119
+ return had || out.exitCode === 0;
120
+ }
121
+ function nightAgentTime(root, env) {
122
+ let text;
123
+ try {
124
+ text = readFileSync(specPath(env.home, nightSpec(root)), "utf8");
125
+ } catch {
126
+ return void 0;
127
+ }
128
+ const n = (key) => Number(new RegExp(`<key>${key}</key><integer>(\\d+)</integer>`).exec(text)?.[1]);
129
+ const month = n("Month");
130
+ const day = n("Day");
131
+ if (Number.isNaN(month) || Number.isNaN(day)) return void 0;
132
+ const now = /* @__PURE__ */ new Date();
133
+ const when = new Date(now.getFullYear(), month - 1, day, n("Hour"), n("Minute"));
134
+ if (when.getTime() < now.getTime() - 180 * 864e5) when.setFullYear(now.getFullYear() + 1);
135
+ return when;
136
+ }
137
+ async function removeAgent(executor, job, env) {
138
+ return removeSpec(executor, jobSpec(job), env);
139
+ }
140
+
141
+ export {
142
+ defaultAgentEnv,
143
+ agentLabel,
144
+ agentPath,
145
+ nextTime,
146
+ jobSpec,
147
+ nightSpec,
148
+ specPath,
149
+ agentPlist,
150
+ specPlist,
151
+ installAgent,
152
+ installSpec,
153
+ removeSpec,
154
+ nightAgentTime,
155
+ removeAgent
156
+ };
157
+ //# sourceMappingURL=chunk-35GMLLJW.js.map