@garuda-agent/garuda 0.16.0 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +188 -0
- package/README.md +56 -1074
- package/SECURITY.md +9 -2
- package/dist/{acpCommand-AJJBKAE5.js → acpCommand-7EY3NHPG.js} +18 -16
- package/dist/{anthropic-NQDBCHJU.js → anthropic-NQIZLD64.js} +12 -6
- package/dist/{chunk-WIJL72ZE.js → chunk-2DYMJMRQ.js} +1880 -982
- package/dist/{chunk-YQTGMCU6.js → chunk-3MRQJKUO.js} +29 -5
- package/dist/{chunk-WMOLXTBU.js → chunk-4LFJFDCF.js} +2 -1
- package/dist/{chunk-44QN5SWZ.js → chunk-55CFEEIN.js} +22 -2
- package/dist/{chunk-USCUXCAU.js → chunk-5B5HDTUR.js} +3 -3
- package/dist/{chunk-TUUEBHG2.js → chunk-6XHON3Q6.js} +2 -2
- package/dist/chunk-735BKABA.js +472 -0
- package/dist/{chunk-B6FA4I7Q.js → chunk-7TH3NHCQ.js} +2 -2
- package/dist/{chunk-OUCV3FCT.js → chunk-AOGFYUKG.js} +3 -3
- package/dist/{chunk-GXZACJUI.js → chunk-B4SJY7KT.js} +322 -39
- package/dist/{chunk-3EQU2GUX.js → chunk-BHZ6G65V.js} +5 -1
- package/dist/chunk-BSK5T2ZG.js +9 -0
- package/dist/chunk-J4346IDH.js +156 -0
- package/dist/{chunk-NP6RIC25.js → chunk-JRVWH27M.js} +7 -7
- package/dist/{chunk-HUIK3WXO.js → chunk-P6XWWIEK.js} +20 -3
- package/dist/{chunk-HE2K657U.js → chunk-TJIWD7R7.js} +47 -16
- package/dist/chunk-U65DQZDB.js +143 -0
- package/dist/chunk-UIRJOQQS.js +118 -0
- package/dist/{chunk-KKB5W47S.js → chunk-VTMD5IHD.js} +26 -2
- package/dist/{chunk-ENLDPN4S.js → chunk-Z66BWTMD.js} +81 -32
- package/dist/cli/index.js +99 -41
- package/dist/{create-VXIH2GUZ.js → create-W6BV75QX.js} +18 -12
- package/dist/{deadline-F5RJJ2QW.js → deadline-TP7ZGLT2.js} +4 -2
- package/dist/{evalCommand-OX2LQYEK.js → evalCommand-YVQAWUZE.js} +50 -29
- package/dist/{export-HN3CT7AV.js → export-SJ3DUP6W.js} +2 -2
- package/dist/{inkChat-YMMMGU7Y.js → inkChat-FNUBK43U.js} +14 -13
- package/dist/install-TKWN5AYH.js +19 -0
- package/dist/{job-3NYDMP2M.js → job-7JOI4YIQ.js} +6 -2
- package/dist/jobCommand-FE6XN3YD.js +33 -0
- package/dist/{launchd-SSX362VG.js → launchd-3A3ONEW5.js} +9 -8
- package/dist/{lspCommand-JRXKRSL7.js → lspCommand-ZZ6R4PA2.js} +7 -6
- package/dist/{manager-AWU4NHHK.js → manager-73MPYFTP.js} +7 -6
- package/dist/{nightCommand-65MUEV32.js → nightCommand-OODJNWDT.js} +26 -20
- package/dist/{openaiCompatible-CJWVJP5M.js → openaiCompatible-6TLDDW5U.js} +29 -15
- package/dist/{policy-EJPLEEXP.js → policy-ZJ7RMOFN.js} +10 -4
- package/dist/{remove-6GDSTAIO.js → remove-42WQNVPX.js} +8 -7
- package/dist/{server-KHHNHUYV.js → server-VEYIJHEU.js} +7 -3
- package/dist/{setupCommand-VA7D5MZK.js → setupCommand-GBQIVYJC.js} +45 -13
- package/dist/text-LS35WSRL.js +17 -0
- package/native/bin/garuda-reap +0 -0
- package/native/garuda-reap.c +113 -0
- package/package.json +39 -13
- package/dist/chunk-EIXUSVFX.js +0 -116
- package/dist/chunk-R7I2NBPX.js +0 -71
- package/dist/chunk-ULAJPMY7.js +0 -107
- package/dist/chunk-XOK5OZOC.js +0 -9
- package/dist/install-EWDSPFFZ.js +0 -18
- package/dist/jobCommand-ACSGSBQ4.js +0 -32
- package/dist/text-J2GD647J.js +0 -11
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
realpathOfNearestExisting
|
|
4
|
+
} from "./chunk-4LFJFDCF.js";
|
|
5
|
+
|
|
6
|
+
// src/permissions/writeScope.ts
|
|
7
|
+
import { existsSync, lstatSync, mkdirSync, realpathSync } from "fs";
|
|
8
|
+
import { realpath } from "fs/promises";
|
|
9
|
+
import { isAbsolute, join, relative, resolve, sep } from "path";
|
|
10
|
+
function scopeEntryProblem(entry) {
|
|
11
|
+
if (entry === "" || entry === "/" || entry === "." || entry === "./") {
|
|
12
|
+
return `"${entry}" is the whole worktree, not a scope`;
|
|
13
|
+
}
|
|
14
|
+
if (entry.startsWith("/") || /^[A-Za-z]:/.test(entry)) return `"${entry}" is not relative`;
|
|
15
|
+
const control = [...entry].some((c) => c.charCodeAt(0) < 32 || c.charCodeAt(0) === 127);
|
|
16
|
+
if (entry.includes("\\") || control) {
|
|
17
|
+
return `"${entry}" has a backslash or a control character`;
|
|
18
|
+
}
|
|
19
|
+
const parts = entry.replace(/\/$/, "").split("/");
|
|
20
|
+
if (parts.some((p) => p === "" || p === "." || p === "..")) {
|
|
21
|
+
return `"${entry}" has an empty, "." or ".." part`;
|
|
22
|
+
}
|
|
23
|
+
if (parts[0] === ".git" || parts[0] === ".garuda") return `"${entry}" is a protected folder`;
|
|
24
|
+
return void 0;
|
|
25
|
+
}
|
|
26
|
+
function inWriteScope(path, scope) {
|
|
27
|
+
const clean = path.replace(/^\.\//, "").replace(/\/+$/, "");
|
|
28
|
+
return scope.some(
|
|
29
|
+
(entry) => entry.endsWith("/") ? clean === entry.slice(0, -1) || clean.startsWith(entry) : clean === entry
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
function scopePaths(root, scope) {
|
|
33
|
+
return scope.map((entry) => join(root, ...entry.replace(/\/$/, "").split("/")));
|
|
34
|
+
}
|
|
35
|
+
function prepareWriteScope(root, scope) {
|
|
36
|
+
for (const entry of scope) {
|
|
37
|
+
const problem = scopeEntryProblem(entry);
|
|
38
|
+
if (problem !== void 0) return problem;
|
|
39
|
+
}
|
|
40
|
+
const realRoot = realpathSync(root);
|
|
41
|
+
for (const [i, path] of scopePaths(root, scope).entries()) {
|
|
42
|
+
const entry = scope[i];
|
|
43
|
+
let current = root;
|
|
44
|
+
for (const part of entry.replace(/\/$/, "").split("/")) {
|
|
45
|
+
current = join(current, part);
|
|
46
|
+
if (existsSync(current) && lstatSync(current).isSymbolicLink()) {
|
|
47
|
+
return `"${entry}" goes through a symbolic link (${current})`;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
if (!existsSync(path) && entry.endsWith("/")) mkdirSync(path, { recursive: true });
|
|
51
|
+
if (existsSync(path)) {
|
|
52
|
+
const real = realpathSync(path);
|
|
53
|
+
if (real !== realRoot && !real.startsWith(`${realRoot}${sep}`)) {
|
|
54
|
+
return `"${entry}" is outside the worktree`;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return void 0;
|
|
59
|
+
}
|
|
60
|
+
var BUILD_OUTPUTS = [
|
|
61
|
+
{ marker: "pom.xml", folders: ["target/"] },
|
|
62
|
+
{ marker: "build.gradle", folders: ["build/", ".gradle/"] },
|
|
63
|
+
{ marker: "build.gradle.kts", folders: ["build/", ".gradle/"] },
|
|
64
|
+
{ marker: "package.json", folders: ["dist/", "coverage/"] },
|
|
65
|
+
{ marker: "pyproject.toml", folders: ["build/", "dist/", ".pytest_cache/"] },
|
|
66
|
+
{ marker: "setup.py", folders: ["build/", "dist/", ".pytest_cache/"] },
|
|
67
|
+
{ marker: "Cargo.toml", folders: ["target/"] },
|
|
68
|
+
{ marker: "go.mod", folders: [] }
|
|
69
|
+
];
|
|
70
|
+
function proposeWriteScope(rules, root) {
|
|
71
|
+
const entries = /* @__PURE__ */ new Set();
|
|
72
|
+
for (const rule of rules) {
|
|
73
|
+
const m = /^(edit_file|write_file)\((.*)\)$/.exec(rule.trim());
|
|
74
|
+
if (m === null) continue;
|
|
75
|
+
const pattern = m[2].replace(/^\.\//, "");
|
|
76
|
+
const glob = pattern.search(/[*?[{]/);
|
|
77
|
+
const entry = glob === -1 ? pattern : pattern.slice(0, pattern.lastIndexOf("/", glob) + 1);
|
|
78
|
+
if (entry === "" || scopeEntryProblem(entry) !== void 0) {
|
|
79
|
+
return { scope: void 0, reason: `the rule ${rule} names no folder` };
|
|
80
|
+
}
|
|
81
|
+
entries.add(entry);
|
|
82
|
+
}
|
|
83
|
+
for (const { marker, folders } of BUILD_OUTPUTS) {
|
|
84
|
+
if (existsSync(join(root, marker))) for (const f of folders) entries.add(f);
|
|
85
|
+
}
|
|
86
|
+
return { scope: [...entries].sort() };
|
|
87
|
+
}
|
|
88
|
+
async function scopeDenial(root, path, scope) {
|
|
89
|
+
const absolute = isAbsolute(path) ? path : resolve(root, path);
|
|
90
|
+
const named = relative(root, absolute).split(sep).join("/");
|
|
91
|
+
const outside = (shown) => `${shown} is outside this job's write scope (${scope.join(", ")})`;
|
|
92
|
+
if (named.startsWith("..") || !inWriteScope(named, scope)) return outside(named);
|
|
93
|
+
let realRoot;
|
|
94
|
+
let real;
|
|
95
|
+
try {
|
|
96
|
+
realRoot = await realpath(root);
|
|
97
|
+
real = await realpathOfNearestExisting(absolute);
|
|
98
|
+
} catch {
|
|
99
|
+
return `${named}: its real place cannot be checked`;
|
|
100
|
+
}
|
|
101
|
+
const reached = relative(realRoot, real).split(sep).join("/");
|
|
102
|
+
if (reached === "" || reached.startsWith("..") || isAbsolute(reached)) {
|
|
103
|
+
return `${named} leads outside the worktree`;
|
|
104
|
+
}
|
|
105
|
+
if (!inWriteScope(reached, scope))
|
|
106
|
+
return `${named} leads to ${reached}, which ${outside(reached).slice(reached.length + 1)}`;
|
|
107
|
+
return void 0;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export {
|
|
111
|
+
scopeEntryProblem,
|
|
112
|
+
inWriteScope,
|
|
113
|
+
scopePaths,
|
|
114
|
+
prepareWriteScope,
|
|
115
|
+
proposeWriteScope,
|
|
116
|
+
scopeDenial
|
|
117
|
+
};
|
|
118
|
+
//# sourceMappingURL=chunk-UIRJOQQS.js.map
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
scopeEntryProblem
|
|
4
|
+
} from "./chunk-UIRJOQQS.js";
|
|
2
5
|
import {
|
|
3
6
|
parseRule
|
|
4
7
|
} from "./chunk-3NJNVZTK.js";
|
|
@@ -29,6 +32,8 @@ var resultSchema = z.object({
|
|
|
29
32
|
steps: z.number(),
|
|
30
33
|
tokens: z.number(),
|
|
31
34
|
costUsd: z.number().optional(),
|
|
35
|
+
/** The cost leaves out some spending: `costUsd` is a minimum (review of 1370184). */
|
|
36
|
+
costIncomplete: z.boolean().optional(),
|
|
32
37
|
durationMs: z.number(),
|
|
33
38
|
sessionId: z.string().optional(),
|
|
34
39
|
commit: z.string().optional(),
|
|
@@ -55,7 +60,12 @@ var resultSchema = z.object({
|
|
|
55
60
|
text: z.string(),
|
|
56
61
|
costUsd: z.number().optional()
|
|
57
62
|
}).optional(),
|
|
58
|
-
reviewError: z.string().optional()
|
|
63
|
+
reviewError: z.string().optional(),
|
|
64
|
+
/**
|
|
65
|
+
* The review spent tokens with no reported usage (a failed attempt, an estimate): its cost is
|
|
66
|
+
* a minimum or unrecorded (review of 3a9f51b).
|
|
67
|
+
*/
|
|
68
|
+
reviewCostIncomplete: z.boolean().optional()
|
|
59
69
|
}).optional()
|
|
60
70
|
});
|
|
61
71
|
var jobSchema = z.object({
|
|
@@ -76,6 +86,16 @@ var jobSchema = z.object({
|
|
|
76
86
|
model: z.string().optional(),
|
|
77
87
|
/** Permission rules for this job only, in the settings format ("edit_file(src/**)"). */
|
|
78
88
|
allow: z.array(z.string()),
|
|
89
|
+
/**
|
|
90
|
+
* The write scope (0.17, review T6): the paths in the worktree that the job's commands and edits
|
|
91
|
+
* may change ("src/" is a folder, "README.md" one file). The OS sandbox enforces it for commands.
|
|
92
|
+
* Absent (a job made before 0.17, or a plan whose rules name no folder): the whole worktree.
|
|
93
|
+
*/
|
|
94
|
+
writeScope: z.array(
|
|
95
|
+
z.string().refine((entry) => scopeEntryProblem(entry) === void 0, {
|
|
96
|
+
message: 'a scope entry is a path in the worktree, such as "src/" or "README.md"'
|
|
97
|
+
})
|
|
98
|
+
).optional(),
|
|
79
99
|
onUnapproved: z.literal("deny-and-continue"),
|
|
80
100
|
/** "01:00" (local time) for `garuda run --at`, when the user gave one. */
|
|
81
101
|
at: z.string().regex(/^([01]\d|2[0-3]):[0-5]\d$/).optional(),
|
|
@@ -114,6 +134,9 @@ var jobSchema = z.object({
|
|
|
114
134
|
endedAt: z.string().optional(),
|
|
115
135
|
result: resultSchema.optional()
|
|
116
136
|
});
|
|
137
|
+
function parseJob(json) {
|
|
138
|
+
return jobSchema.parse(json);
|
|
139
|
+
}
|
|
117
140
|
function newJobId(now = /* @__PURE__ */ new Date()) {
|
|
118
141
|
const pad = (n) => String(n).padStart(2, "0");
|
|
119
142
|
const date = `${now.getFullYear()}${pad(now.getMonth() + 1)}${pad(now.getDate())}`;
|
|
@@ -218,6 +241,7 @@ export {
|
|
|
218
241
|
JOBS_DIR,
|
|
219
242
|
DEFAULT_JOB_MAX_STEPS,
|
|
220
243
|
JOB_STATUSES,
|
|
244
|
+
parseJob,
|
|
221
245
|
newJobId,
|
|
222
246
|
jobPath,
|
|
223
247
|
failJobSync,
|
|
@@ -228,4 +252,4 @@ export {
|
|
|
228
252
|
planPermissions,
|
|
229
253
|
planTitle
|
|
230
254
|
};
|
|
231
|
-
//# sourceMappingURL=chunk-
|
|
255
|
+
//# sourceMappingURL=chunk-VTMD5IHD.js.map
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
colorDiff
|
|
4
4
|
} from "./chunk-4JSUUDFQ.js";
|
|
5
5
|
import {
|
|
6
|
+
AuditDirError,
|
|
6
7
|
SPECIALIST_SPECS,
|
|
7
8
|
THINKING_WORDS,
|
|
8
9
|
callersText,
|
|
@@ -16,12 +17,17 @@ import {
|
|
|
16
17
|
referencesText,
|
|
17
18
|
repoMapText,
|
|
18
19
|
repoMapTool,
|
|
19
|
-
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
verifyAuditDir
|
|
21
|
+
} from "./chunk-2DYMJMRQ.js";
|
|
22
|
+
import {
|
|
23
|
+
budgetSpent,
|
|
24
|
+
isCostIncomplete,
|
|
25
|
+
pendingChildTokens
|
|
26
|
+
} from "./chunk-735BKABA.js";
|
|
21
27
|
import {
|
|
22
28
|
WEB_SEARCH_USD,
|
|
23
29
|
totalTokens
|
|
24
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-J4346IDH.js";
|
|
25
31
|
import {
|
|
26
32
|
BUILTIN_COMMANDS
|
|
27
33
|
} from "./chunk-23FXBNBB.js";
|
|
@@ -30,7 +36,7 @@ import {
|
|
|
30
36
|
} from "./chunk-EU7PA45O.js";
|
|
31
37
|
import {
|
|
32
38
|
listJobs
|
|
33
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-VTMD5IHD.js";
|
|
34
40
|
|
|
35
41
|
// src/cli/errors.ts
|
|
36
42
|
function describeError(error) {
|
|
@@ -76,20 +82,32 @@ function formatTokens(n) {
|
|
|
76
82
|
if (n < 1e6) return `${(n / 1e3).toFixed(1)}k`;
|
|
77
83
|
return `${(n / 1e6).toFixed(1)}M`;
|
|
78
84
|
}
|
|
79
|
-
function formatUsd(usd) {
|
|
85
|
+
function formatUsd(usd, incomplete = false) {
|
|
80
86
|
if (usd === void 0) return "cost unknown";
|
|
81
|
-
|
|
87
|
+
const amount = usd < 0.01 ? `$${usd.toFixed(4)}` : `$${usd.toFixed(2)}`;
|
|
88
|
+
return incomplete ? `\u2265 ${amount} (incomplete)` : amount;
|
|
89
|
+
}
|
|
90
|
+
function budgetNote(session) {
|
|
91
|
+
const unreported = session.unreportedTokens;
|
|
92
|
+
const children = pendingChildTokens(session);
|
|
93
|
+
if (unreported <= 0 && children <= 0) return void 0;
|
|
94
|
+
const parts = [
|
|
95
|
+
...unreported > 0 ? [`${formatTokens(unreported)} reserved without reported usage`] : [],
|
|
96
|
+
...children > 0 ? [`${formatTokens(children)} from subagents with no report`] : []
|
|
97
|
+
];
|
|
98
|
+
return `budget ${formatTokens(budgetSpent(session))} tokens (${parts.join(", ")})`;
|
|
82
99
|
}
|
|
83
|
-
function usageLine(result, session, runCostUsd, contextWindow) {
|
|
100
|
+
function usageLine(result, session, runCostUsd, contextWindow, runCostIncomplete = false) {
|
|
84
101
|
const u = result.usage;
|
|
85
102
|
const input = u.inputTokens + u.cacheReadTokens + u.cacheWriteTokens;
|
|
86
103
|
const percent = Math.round(session.contextTokens / contextWindow * 100);
|
|
87
104
|
return [
|
|
88
105
|
`${result.stopReason} \xB7 ${result.steps} step(s)`,
|
|
89
|
-
`${formatTokens(input)} in (${formatTokens(u.cacheReadTokens)} cached) / ${formatTokens(u.outputTokens)} out`,
|
|
90
|
-
formatUsd(runCostUsd),
|
|
106
|
+
`${budgetNote(session) !== void 0 ? "reported " : ""}${formatTokens(input)} in (${formatTokens(u.cacheReadTokens)} cached) / ${formatTokens(u.outputTokens)} out`,
|
|
107
|
+
formatUsd(runCostUsd, runCostIncomplete),
|
|
91
108
|
`context ${percent}% of ${formatTokens(contextWindow)}`,
|
|
92
|
-
`session ${formatTokens(totalTokens(session.usage))} tokens, ${formatUsd(session.costUsd)}
|
|
109
|
+
`session ${formatTokens(totalTokens(session.usage))} tokens, ${formatUsd(session.costUsd, isCostIncomplete(session))}`,
|
|
110
|
+
...budgetNote(session) === void 0 ? [] : [budgetNote(session)]
|
|
93
111
|
].join(" \xB7 ");
|
|
94
112
|
}
|
|
95
113
|
function stopMessage(reason, limits) {
|
|
@@ -131,13 +149,19 @@ async function runTurn(runtime, approver, renderer, prompt, exitNow) {
|
|
|
131
149
|
process.on("SIGINT", stop);
|
|
132
150
|
approver.onInterrupt = stop;
|
|
133
151
|
const costBefore = runtime.session?.costUsd ?? 0;
|
|
152
|
+
const unreportedBefore = runtime.session?.unreportedTokens ?? 0;
|
|
153
|
+
const incompleteBefore = runtime.session?.costIncomplete ?? false;
|
|
154
|
+
const pendingBefore = runtime.session === void 0 ? 0 : pendingChildTokens(runtime.session);
|
|
134
155
|
try {
|
|
135
156
|
const result = await runtime.runTurn(prompt, controller.signal);
|
|
136
157
|
const session = runtime.session;
|
|
137
158
|
if (session !== void 0) {
|
|
138
159
|
const runCost = session.costUsd === void 0 ? void 0 : session.costUsd - costBefore;
|
|
139
|
-
|
|
140
|
-
|
|
160
|
+
const runIncomplete = session.unreportedTokens > unreportedBefore || pendingChildTokens(session) > pendingBefore || session.costIncomplete && !incompleteBefore;
|
|
161
|
+
renderer.info(
|
|
162
|
+
`
|
|
163
|
+
[${usageLine(result, session, runCost, runtime.limits.contextWindow, runIncomplete)}]`
|
|
164
|
+
);
|
|
141
165
|
}
|
|
142
166
|
const message = stopMessage(result.stopReason, runtime.limits);
|
|
143
167
|
if (message !== void 0) renderer.warn(message);
|
|
@@ -200,7 +224,7 @@ var HELP = [
|
|
|
200
224
|
" /jobs the scheduled jobs of this project; /jobs <id> shows one; /jobs cancel|delete <id>; /jobs cancel night",
|
|
201
225
|
" /where X where symbol X is defined (code index, no model call)",
|
|
202
226
|
" /defs X alias of /where X (definitions of X)",
|
|
203
|
-
" /refs X
|
|
227
|
+
" /refs X indexed uses of symbol X (approximate except JS/TS, no model call)",
|
|
204
228
|
" /callers X who calls symbol X (code index, no model call)",
|
|
205
229
|
" /impact X blast radius and affected tests for file or symbol X",
|
|
206
230
|
" /map [dir] what each code file exports and imports",
|
|
@@ -388,7 +412,7 @@ async function sessionsCommand(runtime, renderer, arg, signal) {
|
|
|
388
412
|
const facts = [
|
|
389
413
|
s.id,
|
|
390
414
|
`${s.turns} turn${s.turns === 1 ? "" : "s"}`,
|
|
391
|
-
...s.costUsd === void 0 || s.costUsd === 0 ? [] : [
|
|
415
|
+
...s.costUsd === void 0 || s.costUsd === 0 && !s.costIncomplete ? [] : [`${s.costIncomplete ? "\u2265 " : ""}$${s.costUsd.toFixed(2)}`],
|
|
392
416
|
...s.model === void 0 ? [] : [s.model]
|
|
393
417
|
].join(" \xB7 ");
|
|
394
418
|
return [
|
|
@@ -467,7 +491,7 @@ async function diffCommand(runtime, renderer, arg, output) {
|
|
|
467
491
|
);
|
|
468
492
|
}
|
|
469
493
|
async function jobsCommand(runtime, renderer, id) {
|
|
470
|
-
const { listJobs: listJobs2, loadJob, JOBS_DIR } = await import("./job-
|
|
494
|
+
const { listJobs: listJobs2, loadJob, JOBS_DIR } = await import("./job-7JOI4YIQ.js");
|
|
471
495
|
const cancel = /^cancel\s+(\S+)$/.exec(id);
|
|
472
496
|
if (cancel !== null) {
|
|
473
497
|
renderer.info(await runtime.cancelJob(cancel[1]));
|
|
@@ -481,7 +505,7 @@ async function jobsCommand(runtime, renderer, id) {
|
|
|
481
505
|
if (id !== "") {
|
|
482
506
|
try {
|
|
483
507
|
const job = await loadJob(runtime.root, id);
|
|
484
|
-
const { jobReport } = await import("./text-
|
|
508
|
+
const { jobReport } = await import("./text-LS35WSRL.js");
|
|
485
509
|
renderer.info(jobReport(job));
|
|
486
510
|
} catch (error) {
|
|
487
511
|
renderer.warn(error.message);
|
|
@@ -489,7 +513,7 @@ async function jobsCommand(runtime, renderer, id) {
|
|
|
489
513
|
return;
|
|
490
514
|
}
|
|
491
515
|
const jobs = await listJobs2(runtime.root);
|
|
492
|
-
const { defaultAgentEnv, nightAgentTime } = await import("./launchd-
|
|
516
|
+
const { defaultAgentEnv, nightAgentTime } = await import("./launchd-3A3ONEW5.js");
|
|
493
517
|
const night = nightAgentTime(runtime.root, defaultAgentEnv());
|
|
494
518
|
const nightLine = night === void 0 ? [] : [
|
|
495
519
|
`Night shift: launchd starts the queue at ${night.toTimeString().slice(0, 5)} on ${night.toDateString()} (/jobs cancel night removes it).`
|
|
@@ -527,7 +551,7 @@ async function exportCommand(runtime, renderer, file) {
|
|
|
527
551
|
renderer.info("There is no conversation to export yet.");
|
|
528
552
|
return;
|
|
529
553
|
}
|
|
530
|
-
const { sessionMarkdown, writeExport } = await import("./export-
|
|
554
|
+
const { sessionMarkdown, writeExport } = await import("./export-SJ3DUP6W.js");
|
|
531
555
|
const result = await writeExport(runtime.root, id, sessionMarkdown(records, id), file);
|
|
532
556
|
if ("problem" in result) renderer.warn(result.problem);
|
|
533
557
|
else
|
|
@@ -628,7 +652,7 @@ async function lookup(runtime, renderer, command, arg) {
|
|
|
628
652
|
} else {
|
|
629
653
|
text = repoMapText(await repoMapTool.run({ path: arg }, context));
|
|
630
654
|
}
|
|
631
|
-
renderer.info(text);
|
|
655
|
+
renderer.info(text.startsWith("Approximate:") ? `\u2248 ${text}` : text);
|
|
632
656
|
} catch (error) {
|
|
633
657
|
renderer.error(error.message);
|
|
634
658
|
}
|
|
@@ -706,22 +730,46 @@ async function auditCommand(runtime, renderer, arg) {
|
|
|
706
730
|
}
|
|
707
731
|
}
|
|
708
732
|
if (arg === "verify") {
|
|
709
|
-
const files = await runtime.audit.files();
|
|
710
733
|
lines.push("", `Audit files: ${runtime.audit.dir}`);
|
|
711
|
-
|
|
734
|
+
let results;
|
|
735
|
+
try {
|
|
736
|
+
results = await verifyAuditDir(runtime.audit.dir);
|
|
737
|
+
} catch (error) {
|
|
738
|
+
if (!(error instanceof AuditDirError)) throw error;
|
|
739
|
+
lines.push(` BROKEN the audit folder: ${error.message}`);
|
|
740
|
+
renderer.info(lines.join("\n"));
|
|
741
|
+
return;
|
|
742
|
+
}
|
|
743
|
+
if (results.length === 0) lines.push(" none yet");
|
|
712
744
|
let broken = 0;
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
lines.push(`
|
|
745
|
+
let unchecked = 0;
|
|
746
|
+
for (const result of results) {
|
|
747
|
+
if ("missing" in result) {
|
|
748
|
+
broken++;
|
|
749
|
+
lines.push(` MISSING ${result.file}: the checkpoint names it, but the file is gone`);
|
|
750
|
+
} else if ("brokenCheckpoint" in result) {
|
|
751
|
+
broken++;
|
|
752
|
+
lines.push(` BROKEN ${result.file}: its checkpoint: ${result.brokenCheckpoint}`);
|
|
753
|
+
} else if (result.verdict.ok) {
|
|
754
|
+
if (!result.checkpoint) unchecked++;
|
|
755
|
+
lines.push(
|
|
756
|
+
` ok ${result.file} (${result.verdict.lines} lines${result.checkpoint ? ", checkpoint" : ""})`
|
|
757
|
+
);
|
|
718
758
|
} else {
|
|
719
759
|
broken++;
|
|
720
|
-
lines.push(` BROKEN ${
|
|
760
|
+
lines.push(` BROKEN ${result.file}: line ${result.verdict.line}: ${result.verdict.why}`);
|
|
721
761
|
}
|
|
722
762
|
}
|
|
723
|
-
if (broken > 0)
|
|
724
|
-
|
|
763
|
+
if (broken > 0)
|
|
764
|
+
lines.push(`${broken} file(s) were changed or removed after Garuda wrote them.`);
|
|
765
|
+
if (unchecked > 0) {
|
|
766
|
+
lines.push(
|
|
767
|
+
`${unchecked} file(s) have no checkpoint: this check cannot see lines cut from their end, or a removed file. The team policy can turn on "audit": { "checkpoint": true }.`
|
|
768
|
+
);
|
|
769
|
+
}
|
|
770
|
+
lines.push(
|
|
771
|
+
"Someone with your rights can rewrite a file and its checkpoint together; this check cannot see that."
|
|
772
|
+
);
|
|
725
773
|
renderer.info(lines.join("\n"));
|
|
726
774
|
return;
|
|
727
775
|
}
|
|
@@ -767,11 +815,12 @@ function usageSummary(runtime) {
|
|
|
767
815
|
const session = runtime.session;
|
|
768
816
|
if (session === void 0) return "No session yet.";
|
|
769
817
|
const u = session.usage;
|
|
770
|
-
const cost = session.costUsd === void 0 ? "cost unknown" : `$${session.costUsd.toFixed(4)}`;
|
|
818
|
+
const cost = session.costUsd === void 0 ? "cost unknown" : isCostIncomplete(session) ? `\u2265 $${session.costUsd.toFixed(4)} (incomplete)` : `$${session.costUsd.toFixed(4)}`;
|
|
771
819
|
return [
|
|
772
|
-
`Session ${session.id}: ${formatTokens(totalTokens(u))} tokens, ${cost}`,
|
|
820
|
+
`Session ${session.id}: ${formatTokens(totalTokens(u))}${budgetNote(session) !== void 0 ? " reported" : ""} tokens, ${cost}`,
|
|
773
821
|
` input ${formatTokens(u.inputTokens)}, cache read ${formatTokens(u.cacheReadTokens)}, cache write ${formatTokens(u.cacheWriteTokens)}, output ${formatTokens(u.outputTokens)}`,
|
|
774
822
|
` context ${formatTokens(session.contextTokens)} of ${formatTokens(runtime.limits.contextWindow)}`,
|
|
823
|
+
...budgetNote(session) === void 0 ? [] : [` ${budgetNote(session)}`],
|
|
775
824
|
...u.webSearches === void 0 ? [] : [
|
|
776
825
|
` Claude web searches: ${u.webSearches} ($${(u.webSearches * WEB_SEARCH_USD).toFixed(2)})`
|
|
777
826
|
]
|
|
@@ -1244,4 +1293,4 @@ export {
|
|
|
1244
1293
|
statusOf,
|
|
1245
1294
|
CommandArgs
|
|
1246
1295
|
};
|
|
1247
|
-
//# sourceMappingURL=chunk-
|
|
1296
|
+
//# sourceMappingURL=chunk-Z66BWTMD.js.map
|