opencode-swarm 7.124.0 → 7.125.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/.opencode/skills/critic-gate/SKILL.md +8 -0
- package/.opencode/skills/swarm/SKILL.md +12 -8
- package/.opencode/skills/swarm-pr-feedback/SKILL.md +245 -171
- package/.opencode/skills/swarm-pr-feedback/references/bot-claim-verification.md +71 -0
- package/.opencode/skills/swarm-pr-feedback/references/operational-gotchas.md +49 -0
- package/.opencode/skills/swarm-pr-review/SKILL.md +238 -412
- package/.opencode/skills/swarm-pr-review/references/parser-dry-run.md +235 -0
- package/.opencode/skills/swarm-pr-review/references/prompt-templates.md +103 -0
- package/.opencode/skills/writing-tests/SKILL.md +4 -123
- package/.opencode/skills/writing-tests/references/mock-and-seam-inventory.md +43 -0
- package/README.md +3 -1
- package/dist/background/lane-output-store.d.ts +10 -0
- package/dist/background/pending-delegations.d.ts +3 -0
- package/dist/background/workspace-snapshot.d.ts +59 -0
- package/dist/cli/{config-doctor-53mnpeke.js → config-doctor-g3m2q646.js} +2 -2
- package/dist/cli/{curation-policy-ny033330.js → curation-policy-vgbx8530.js} +2 -2
- package/dist/cli/{curator-llm-factory-e0tjz8qq.js → curator-llm-factory-7pvqy94w.js} +15 -14
- package/dist/cli/{curator-nvn1pdq6.js → curator-xk4g1nx2.js} +15 -14
- package/dist/cli/{evidence-summary-service-9hq7n9k9.js → evidence-summary-service-v4h2w487.js} +1 -1
- package/dist/cli/{guardrail-explain-d3dd57nf.js → guardrail-explain-wfk16bpr.js} +16 -15
- package/dist/cli/{guardrail-log-3q2z9axs.js → guardrail-log-5zz9xx6z.js} +3 -3
- package/dist/cli/{hive-promoter-9gbpepgm.js → hive-promoter-njwc5rt0.js} +15 -14
- package/dist/cli/{pending-delegations-e3bcqj77.js → index-0cz1ws47.js} +4 -18
- package/dist/cli/{index-3yyr4ynk.js → index-3k8pg467.js} +1 -1
- package/dist/cli/{index-x2mmnrnx.js → index-83rwq7pb.js} +1 -1
- package/dist/cli/{index-c6crt5rs.js → index-8yvqkbw7.js} +12 -2
- package/dist/cli/{index-z0m4angq.js → index-93cq8t5b.js} +5 -5
- package/dist/cli/{index-8pz0ypxz.js → index-cz6fv84h.js} +17 -16
- package/dist/cli/{index-mkkx1a4f.js → index-dsf1yv4s.js} +1588 -891
- package/dist/cli/{index-4rzzzjtg.js → index-fs02c7tz.js} +277 -16
- package/dist/cli/{index-zjedv2bd.js → index-ghteqdy1.js} +2 -2
- package/dist/cli/{index-13d2g7k9.js → index-kvrk3h8p.js} +1 -1
- package/dist/cli/{index-eeg04r0x.js → index-kws8zn6y.js} +1 -1
- package/dist/cli/index-mg54y5gc.js +564 -0
- package/dist/cli/{index-qd77aft9.js → index-mhhmecsw.js} +2 -2
- package/dist/cli/{index-2x4maxte.js → index-mwdcvh0e.js} +4 -4
- package/dist/cli/{index-e19mxn9f.js → index-pbjenws7.js} +1 -1
- package/dist/cli/{index-wqwpzhv1.js → index-rpg8qqjs.js} +2 -2
- package/dist/cli/{index-tyg0zezw.js → index-tn3shyqj.js} +3 -3
- package/dist/cli/{index-htbjqftb.js → index-txragda9.js} +1 -1
- package/dist/cli/{index-v5ecczts.js → index-z4sc6yxc.js} +1 -1
- package/dist/cli/index.js +15 -14
- package/dist/cli/{knowledge-escalator-r1s01m3z.js → knowledge-escalator-jtyykzqc.js} +3 -3
- package/dist/cli/{knowledge-events-a9hmxvke.js → knowledge-events-qhr97sy9.js} +1 -1
- package/dist/cli/{knowledge-store-jt31br5k.js → knowledge-store-332x3pjv.js} +1 -1
- package/dist/cli/{knowledge-validator-9vrwxr3z.js → knowledge-validator-3t8tgzsz.js} +4 -4
- package/dist/cli/pending-delegations-7j8xqg5f.js +34 -0
- package/dist/cli/{scan-cursor-bkjtsawg.js → scan-cursor-q21c9k9q.js} +2 -2
- package/dist/cli/{schema-y3z416z7.js → schema-y2d7j2jk.js} +1 -1
- package/dist/cli/{skill-generator-794hyndw.js → skill-generator-3gkxx98d.js} +5 -5
- package/dist/cli/workspace-snapshot-c9pxxt9a.js +48 -0
- package/dist/commands/close.d.ts +4 -2
- package/dist/commands/registry.d.ts +1 -1
- package/dist/config/schema.d.ts +4 -0
- package/dist/evidence/documents-retention.d.ts +116 -0
- package/dist/evidence/manager.d.ts +17 -0
- package/dist/hooks/pr-workflow-gate.d.ts +211 -0
- package/dist/hooks/pr-workflow-response-gate.d.ts +23 -0
- package/dist/hooks/pr-workflow-session-resolver.d.ts +14 -0
- package/dist/index.js +563 -523
- package/dist/tools/complete-pr-workflow.d.ts +5 -0
- package/dist/tools/dispatch-lanes.d.ts +44 -0
- package/dist/tools/index.d.ts +2 -0
- package/dist/tools/manifest.d.ts +2 -0
- package/dist/tools/run-pr-feedback-stage-a.d.ts +69 -0
- package/dist/tools/tool-metadata.d.ts +8 -0
- package/dist/tools/write-pr-review-trigger-eval.d.ts +56 -46
- package/package.json +1 -1
- package/dist/cli/index-dqh3zhhc.js +0 -133
- package/dist/cli/workspace-snapshot-eyf6gd0d.js +0 -22
|
@@ -0,0 +1,564 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// src/background/workspace-snapshot.ts
|
|
3
|
+
import * as child_process from "child_process";
|
|
4
|
+
import { createHash } from "crypto";
|
|
5
|
+
import * as fs from "fs";
|
|
6
|
+
import * as path from "path";
|
|
7
|
+
var GIT_SNAPSHOT_TIMEOUT_MS = 3000;
|
|
8
|
+
var GIT_SNAPSHOT_MAX_BUFFER = 512 * 1024;
|
|
9
|
+
var REVISION_MAX_FILES = 5000;
|
|
10
|
+
var REVISION_MAX_TOTAL_BYTES = 64 * 1024 * 1024;
|
|
11
|
+
var REVISION_READ_CHUNK_BYTES = 64 * 1024;
|
|
12
|
+
var REVISION_YIELD_EVERY_CHUNKS = 16;
|
|
13
|
+
function runGit(directory, args, timeoutMs = GIT_SNAPSHOT_TIMEOUT_MS) {
|
|
14
|
+
const result = _internals.spawnSync("git", ["-C", directory, ...args], {
|
|
15
|
+
cwd: directory,
|
|
16
|
+
encoding: "utf-8",
|
|
17
|
+
timeout: timeoutMs,
|
|
18
|
+
maxBuffer: GIT_SNAPSHOT_MAX_BUFFER,
|
|
19
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
20
|
+
});
|
|
21
|
+
if (result.error || result.status !== 0)
|
|
22
|
+
return null;
|
|
23
|
+
return typeof result.stdout === "string" ? result.stdout.trimEnd() : null;
|
|
24
|
+
}
|
|
25
|
+
async function runGitAsync(directory, args, timeoutMs = GIT_SNAPSHOT_TIMEOUT_MS) {
|
|
26
|
+
return await new Promise((resolve2) => {
|
|
27
|
+
let settled = false;
|
|
28
|
+
let stdout = "";
|
|
29
|
+
let stderrBytes = 0;
|
|
30
|
+
let timeout;
|
|
31
|
+
let child;
|
|
32
|
+
const finish = (value) => {
|
|
33
|
+
if (settled)
|
|
34
|
+
return;
|
|
35
|
+
settled = true;
|
|
36
|
+
if (timeout)
|
|
37
|
+
clearTimeout(timeout);
|
|
38
|
+
try {
|
|
39
|
+
child?.kill();
|
|
40
|
+
} catch {}
|
|
41
|
+
resolve2(value);
|
|
42
|
+
};
|
|
43
|
+
try {
|
|
44
|
+
child = child_process.spawn("git", ["-C", directory, ...args], {
|
|
45
|
+
cwd: directory,
|
|
46
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
47
|
+
windowsHide: true
|
|
48
|
+
});
|
|
49
|
+
} catch {
|
|
50
|
+
finish(null);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
timeout = setTimeout(() => finish(null), timeoutMs);
|
|
54
|
+
child.stdout?.setEncoding("utf-8");
|
|
55
|
+
child.stdout?.on("data", (chunk) => {
|
|
56
|
+
stdout += chunk;
|
|
57
|
+
if (Buffer.byteLength(stdout, "utf-8") > GIT_SNAPSHOT_MAX_BUFFER) {
|
|
58
|
+
finish(null);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
child.stderr?.on("data", (chunk) => {
|
|
62
|
+
stderrBytes += chunk.length;
|
|
63
|
+
if (stderrBytes > GIT_SNAPSHOT_MAX_BUFFER) {
|
|
64
|
+
finish(null);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
child.once("error", () => finish(null));
|
|
68
|
+
child.once("close", (code) => finish(code === 0 ? stdout.trimEnd() : null));
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
function readGitTextAtRevision(directory, revision, relativePath) {
|
|
72
|
+
if (!isSafeGitRevisionToken(revision) || !/^\.?(?:[A-Za-z0-9][A-Za-z0-9._-]*\/)*[A-Za-z0-9][A-Za-z0-9._-]*$/.test(relativePath) || relativePath.split("/").includes("..")) {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
const result = _internals.spawnSync("git", ["-C", directory, "show", `${revision}:${relativePath}`], {
|
|
76
|
+
cwd: directory,
|
|
77
|
+
encoding: "utf-8",
|
|
78
|
+
timeout: GIT_SNAPSHOT_TIMEOUT_MS,
|
|
79
|
+
maxBuffer: GIT_SNAPSHOT_MAX_BUFFER,
|
|
80
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
81
|
+
});
|
|
82
|
+
if (result.error || result.status !== 0 || typeof result.stdout !== "string")
|
|
83
|
+
return null;
|
|
84
|
+
return result.stdout;
|
|
85
|
+
}
|
|
86
|
+
function resolveCurrentGitHead(directory) {
|
|
87
|
+
return runGit(directory, ["rev-parse", "--verify", "HEAD^{commit}"]);
|
|
88
|
+
}
|
|
89
|
+
function resolveExactMergeBase(directory, baseRef, prHeadSha) {
|
|
90
|
+
if (!isSafeGitRevisionToken(baseRef) || !isSafeGitRevisionToken(prHeadSha))
|
|
91
|
+
return null;
|
|
92
|
+
const mergeBase = runGit(directory, ["merge-base", "--", baseRef, prHeadSha]);
|
|
93
|
+
return mergeBase && /^[0-9a-f]{6,64}$/i.test(mergeBase) ? mergeBase : null;
|
|
94
|
+
}
|
|
95
|
+
function isSafeGitRevisionToken(value) {
|
|
96
|
+
return /^(?!-)[A-Za-z0-9][A-Za-z0-9._/-]{0,255}$/.test(value) && !value.includes("..") && !value.includes("//") && !value.includes("@{");
|
|
97
|
+
}
|
|
98
|
+
function resolveCurrentUpstreamRemoteRef(directory) {
|
|
99
|
+
const upstream = runGit(directory, [
|
|
100
|
+
"rev-parse",
|
|
101
|
+
"--symbolic-full-name",
|
|
102
|
+
"@{upstream}"
|
|
103
|
+
]);
|
|
104
|
+
if (!upstream?.startsWith("refs/remotes/") || upstream.endsWith("/HEAD")) {
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
return upstream;
|
|
108
|
+
}
|
|
109
|
+
function resolveCurrentUpstreamPushTarget(directory) {
|
|
110
|
+
const localBranchRef = runGit(directory, ["symbolic-ref", "--quiet", "HEAD"]);
|
|
111
|
+
if (!localBranchRef?.startsWith("refs/heads/"))
|
|
112
|
+
return null;
|
|
113
|
+
const encoded = runGit(directory, [
|
|
114
|
+
"for-each-ref",
|
|
115
|
+
"--format=%(upstream:remotename)%00%(upstream:remoteref)%00%(upstream)",
|
|
116
|
+
localBranchRef
|
|
117
|
+
]);
|
|
118
|
+
if (!encoded)
|
|
119
|
+
return null;
|
|
120
|
+
const [remoteName, remoteBranchRef, remoteTrackingRef, ...extras] = encoded.split("\x00");
|
|
121
|
+
if (extras.length > 0 || !remoteName || remoteName.startsWith("-") || /[\s;&|<>`]/.test(remoteName) || !remoteBranchRef?.startsWith("refs/heads/") || remoteBranchRef === "refs/heads/" || /[\s;&|<>`]/.test(remoteBranchRef) || !remoteTrackingRef?.startsWith("refs/remotes/") || remoteTrackingRef.endsWith("/HEAD")) {
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
return { remoteName, remoteBranchRef, remoteTrackingRef };
|
|
125
|
+
}
|
|
126
|
+
function resolveExactRemoteBranchHead(directory, remoteName, remoteBranchRef) {
|
|
127
|
+
if (!remoteName || remoteName.startsWith("-") || /[\s;&|<>`]/.test(remoteName) || !remoteBranchRef.startsWith("refs/heads/") || remoteBranchRef === "refs/heads/" || /[\s;&|<>`]/.test(remoteBranchRef)) {
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
const output = runGit(directory, ["ls-remote", "--exit-code", "--heads", remoteName, remoteBranchRef], 20000);
|
|
131
|
+
if (!output)
|
|
132
|
+
return null;
|
|
133
|
+
const rows = output.split(/\r?\n/).filter(Boolean);
|
|
134
|
+
if (rows.length !== 1)
|
|
135
|
+
return null;
|
|
136
|
+
const [objectName, refName, ...extras] = rows[0].split(/\s+/);
|
|
137
|
+
if (extras.length > 0 || refName !== remoteBranchRef || !objectName || !(/^[0-9a-f]{40}$/i.test(objectName) || /^[0-9a-f]{64}$/i.test(objectName))) {
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
return objectName;
|
|
141
|
+
}
|
|
142
|
+
function resolveGitControlStateDigest(directory) {
|
|
143
|
+
const head = runGit(directory, ["rev-parse", "--verify", "HEAD^{commit}"]);
|
|
144
|
+
const symbolicHead = runGit(directory, ["symbolic-ref", "--quiet", "HEAD"]);
|
|
145
|
+
const upstream = resolveCurrentUpstreamPushTarget(directory);
|
|
146
|
+
const refs = runGit(directory, [
|
|
147
|
+
"for-each-ref",
|
|
148
|
+
"--format=%(refname)%00%(objectname)",
|
|
149
|
+
"refs/heads",
|
|
150
|
+
"refs/remotes",
|
|
151
|
+
"refs/tags"
|
|
152
|
+
]);
|
|
153
|
+
const config = runGit(directory, [
|
|
154
|
+
"config",
|
|
155
|
+
"--null",
|
|
156
|
+
"--show-origin",
|
|
157
|
+
"--show-scope",
|
|
158
|
+
"--list"
|
|
159
|
+
]);
|
|
160
|
+
const index = runGit(directory, ["ls-files", "--stage", "-z"]);
|
|
161
|
+
if (head === null || symbolicHead === null || !upstream || refs === null || config === null || index === null) {
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
return digest(`head\x00${head}\x00symbolic\x00${symbolicHead}\x00upstream\x00${upstream.remoteName}\x00${upstream.remoteBranchRef}\x00${upstream.remoteTrackingRef}\x00refs\x00${refs}\x00config\x00${config}\x00index\x00${index}`);
|
|
165
|
+
}
|
|
166
|
+
function resolveIsWorkingTreeClean(directory) {
|
|
167
|
+
const status = runGit(directory, [
|
|
168
|
+
"status",
|
|
169
|
+
"--porcelain=v1",
|
|
170
|
+
"--untracked-files=all"
|
|
171
|
+
]);
|
|
172
|
+
return status === null ? null : status.length === 0;
|
|
173
|
+
}
|
|
174
|
+
function resolveCommitCountSince(directory, baseHeadSha, currentHeadSha) {
|
|
175
|
+
const output = runGit(directory, [
|
|
176
|
+
"rev-list",
|
|
177
|
+
"--count",
|
|
178
|
+
"--ancestry-path",
|
|
179
|
+
`${baseHeadSha}..${currentHeadSha}`
|
|
180
|
+
]);
|
|
181
|
+
if (!output || !/^\d+$/.test(output))
|
|
182
|
+
return null;
|
|
183
|
+
const count = Number(output);
|
|
184
|
+
return Number.isSafeInteger(count) ? count : null;
|
|
185
|
+
}
|
|
186
|
+
function resolveIsExactSingleChildCommit(directory, baseHeadSha, currentHeadSha) {
|
|
187
|
+
const base = runGit(directory, [
|
|
188
|
+
"rev-parse",
|
|
189
|
+
"--verify",
|
|
190
|
+
`${baseHeadSha}^{commit}`
|
|
191
|
+
]);
|
|
192
|
+
const current = runGit(directory, [
|
|
193
|
+
"rev-parse",
|
|
194
|
+
"--verify",
|
|
195
|
+
`${currentHeadSha}^{commit}`
|
|
196
|
+
]);
|
|
197
|
+
if (!base || !current)
|
|
198
|
+
return null;
|
|
199
|
+
const commitAndParents = runGit(directory, [
|
|
200
|
+
"rev-list",
|
|
201
|
+
"--parents",
|
|
202
|
+
"-n",
|
|
203
|
+
"1",
|
|
204
|
+
current
|
|
205
|
+
]);
|
|
206
|
+
if (commitAndParents === null)
|
|
207
|
+
return null;
|
|
208
|
+
const fields = commitAndParents.trim().split(/\s+/);
|
|
209
|
+
return fields.length === 2 && fields[0]?.toLowerCase() === current.toLowerCase() && fields[1]?.toLowerCase() === base.toLowerCase();
|
|
210
|
+
}
|
|
211
|
+
function resolveRemoteRefsContainingHead(directory, headSha) {
|
|
212
|
+
const output = runGit(directory, [
|
|
213
|
+
"for-each-ref",
|
|
214
|
+
"--format=%(refname)%09%(objectname)",
|
|
215
|
+
"refs/remotes"
|
|
216
|
+
]);
|
|
217
|
+
if (output === null)
|
|
218
|
+
return null;
|
|
219
|
+
return output.split(/\r?\n/).map((line) => line.trim().split("\t")).filter(([ref, objectName]) => ref?.startsWith("refs/remotes/") && !ref.endsWith("/HEAD") && objectName?.toLowerCase() === headSha.toLowerCase()).map(([ref]) => ref);
|
|
220
|
+
}
|
|
221
|
+
function resolvePrWorkflowRevisionDigest(directory, baseHeadSha) {
|
|
222
|
+
const projectRoot = path.resolve(directory);
|
|
223
|
+
const baseHead = runGit(projectRoot, [
|
|
224
|
+
"rev-parse",
|
|
225
|
+
"--verify",
|
|
226
|
+
`${baseHeadSha}^{commit}`
|
|
227
|
+
]);
|
|
228
|
+
const diffNames = runGit(projectRoot, [
|
|
229
|
+
"diff",
|
|
230
|
+
"--no-ext-diff",
|
|
231
|
+
"--name-only",
|
|
232
|
+
"-z",
|
|
233
|
+
baseHeadSha
|
|
234
|
+
]);
|
|
235
|
+
const porcelain = runGit(projectRoot, [
|
|
236
|
+
"status",
|
|
237
|
+
"--porcelain=v1",
|
|
238
|
+
"-z",
|
|
239
|
+
"--untracked-files=all"
|
|
240
|
+
]);
|
|
241
|
+
if (!baseHead || diffNames === null || porcelain === null)
|
|
242
|
+
return null;
|
|
243
|
+
const porcelainPaths = parsePorcelainPaths(porcelain);
|
|
244
|
+
if (!porcelainPaths)
|
|
245
|
+
return null;
|
|
246
|
+
const changedPaths = [
|
|
247
|
+
...new Set([...parseNulPaths(diffNames), ...porcelainPaths])
|
|
248
|
+
].sort((left, right) => left.localeCompare(right));
|
|
249
|
+
if (changedPaths.length > REVISION_MAX_FILES)
|
|
250
|
+
return null;
|
|
251
|
+
const hash = createHash("sha256");
|
|
252
|
+
hash.update(`base\x00${baseHead}\x00`);
|
|
253
|
+
let totalBytes = 0;
|
|
254
|
+
for (const relativePath of changedPaths) {
|
|
255
|
+
const resolvedPath = path.resolve(projectRoot, relativePath);
|
|
256
|
+
const relativeToRoot = path.relative(projectRoot, resolvedPath);
|
|
257
|
+
if (!relativeToRoot || relativeToRoot.startsWith("..") || path.isAbsolute(relativeToRoot))
|
|
258
|
+
return null;
|
|
259
|
+
hash.update(`path\x00${relativePath}\x00`);
|
|
260
|
+
let stats;
|
|
261
|
+
try {
|
|
262
|
+
stats = fs.lstatSync(resolvedPath);
|
|
263
|
+
} catch (error) {
|
|
264
|
+
if (error.code === "ENOENT") {
|
|
265
|
+
hash.update("deleted\x00");
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
268
|
+
return null;
|
|
269
|
+
}
|
|
270
|
+
if (stats.isSymbolicLink()) {
|
|
271
|
+
try {
|
|
272
|
+
hash.update(`symlink\x00${fs.readlinkSync(resolvedPath)}\x00`);
|
|
273
|
+
continue;
|
|
274
|
+
} catch {
|
|
275
|
+
return null;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
if (!stats.isFile()) {
|
|
279
|
+
hash.update(`node\x00${stats.mode}\x00`);
|
|
280
|
+
continue;
|
|
281
|
+
}
|
|
282
|
+
totalBytes += stats.size;
|
|
283
|
+
if (totalBytes > REVISION_MAX_TOTAL_BYTES)
|
|
284
|
+
return null;
|
|
285
|
+
try {
|
|
286
|
+
hash.update(`file\x00${stats.mode}\x00`);
|
|
287
|
+
hash.update(fs.readFileSync(resolvedPath));
|
|
288
|
+
hash.update("\x00");
|
|
289
|
+
} catch {
|
|
290
|
+
return null;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
return hash.digest("hex");
|
|
294
|
+
}
|
|
295
|
+
async function resolvePrWorkflowRevisionDigestAsync(directory, baseHeadSha) {
|
|
296
|
+
const projectRoot = path.resolve(directory);
|
|
297
|
+
const [baseHead, diffNames, porcelain] = await Promise.all([
|
|
298
|
+
runGitAsync(projectRoot, [
|
|
299
|
+
"rev-parse",
|
|
300
|
+
"--verify",
|
|
301
|
+
`${baseHeadSha}^{commit}`
|
|
302
|
+
]),
|
|
303
|
+
runGitAsync(projectRoot, [
|
|
304
|
+
"diff",
|
|
305
|
+
"--no-ext-diff",
|
|
306
|
+
"--name-only",
|
|
307
|
+
"-z",
|
|
308
|
+
baseHeadSha
|
|
309
|
+
]),
|
|
310
|
+
runGitAsync(projectRoot, [
|
|
311
|
+
"status",
|
|
312
|
+
"--porcelain=v1",
|
|
313
|
+
"-z",
|
|
314
|
+
"--untracked-files=all"
|
|
315
|
+
])
|
|
316
|
+
]);
|
|
317
|
+
if (!baseHead || diffNames === null || porcelain === null)
|
|
318
|
+
return null;
|
|
319
|
+
const porcelainPaths = parsePorcelainPaths(porcelain);
|
|
320
|
+
if (!porcelainPaths)
|
|
321
|
+
return null;
|
|
322
|
+
const changedPaths = [
|
|
323
|
+
...new Set([...parseNulPaths(diffNames), ...porcelainPaths])
|
|
324
|
+
].sort((left, right) => left.localeCompare(right));
|
|
325
|
+
if (changedPaths.length > REVISION_MAX_FILES)
|
|
326
|
+
return null;
|
|
327
|
+
const hash = createHash("sha256");
|
|
328
|
+
hash.update(`base\x00${baseHead}\x00`);
|
|
329
|
+
let totalBytes = 0;
|
|
330
|
+
let chunksSinceYield = 0;
|
|
331
|
+
for (const relativePath of changedPaths) {
|
|
332
|
+
const resolvedPath = path.resolve(projectRoot, relativePath);
|
|
333
|
+
const relativeToRoot = path.relative(projectRoot, resolvedPath);
|
|
334
|
+
if (!relativeToRoot || relativeToRoot.startsWith("..") || path.isAbsolute(relativeToRoot))
|
|
335
|
+
return null;
|
|
336
|
+
hash.update(`path\x00${relativePath}\x00`);
|
|
337
|
+
let stats;
|
|
338
|
+
try {
|
|
339
|
+
stats = await fs.promises.lstat(resolvedPath);
|
|
340
|
+
} catch (error) {
|
|
341
|
+
if (error.code === "ENOENT") {
|
|
342
|
+
hash.update("deleted\x00");
|
|
343
|
+
continue;
|
|
344
|
+
}
|
|
345
|
+
return null;
|
|
346
|
+
}
|
|
347
|
+
if (stats.isSymbolicLink()) {
|
|
348
|
+
try {
|
|
349
|
+
hash.update(`symlink\x00${await fs.promises.readlink(resolvedPath)}\x00`);
|
|
350
|
+
continue;
|
|
351
|
+
} catch {
|
|
352
|
+
return null;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
if (!stats.isFile()) {
|
|
356
|
+
hash.update(`node\x00${stats.mode}\x00`);
|
|
357
|
+
continue;
|
|
358
|
+
}
|
|
359
|
+
totalBytes += stats.size;
|
|
360
|
+
if (totalBytes > REVISION_MAX_TOTAL_BYTES)
|
|
361
|
+
return null;
|
|
362
|
+
hash.update(`file\x00${stats.mode}\x00`);
|
|
363
|
+
let handle;
|
|
364
|
+
try {
|
|
365
|
+
handle = await fs.promises.open(resolvedPath, "r");
|
|
366
|
+
const buffer = Buffer.allocUnsafe(REVISION_READ_CHUNK_BYTES);
|
|
367
|
+
for (let position = 0;position < stats.size; ) {
|
|
368
|
+
const length = Math.min(REVISION_READ_CHUNK_BYTES, stats.size - position);
|
|
369
|
+
const { bytesRead } = await handle.read(buffer, 0, length, position);
|
|
370
|
+
if (bytesRead <= 0)
|
|
371
|
+
return null;
|
|
372
|
+
hash.update(buffer.subarray(0, bytesRead));
|
|
373
|
+
position += bytesRead;
|
|
374
|
+
chunksSinceYield++;
|
|
375
|
+
if (chunksSinceYield >= REVISION_YIELD_EVERY_CHUNKS) {
|
|
376
|
+
chunksSinceYield = 0;
|
|
377
|
+
await _internals.yieldControl();
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
hash.update("\x00");
|
|
381
|
+
} catch {
|
|
382
|
+
return null;
|
|
383
|
+
} finally {
|
|
384
|
+
await handle?.close().catch(() => {
|
|
385
|
+
return;
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
return hash.digest("hex");
|
|
390
|
+
}
|
|
391
|
+
function parseNulPaths(output) {
|
|
392
|
+
return output.split("\x00").filter((entry) => entry.length > 0);
|
|
393
|
+
}
|
|
394
|
+
function parsePorcelainPaths(output) {
|
|
395
|
+
const entries = parseNulPaths(output);
|
|
396
|
+
const paths = [];
|
|
397
|
+
for (let index = 0;index < entries.length; index++) {
|
|
398
|
+
const entry = entries[index];
|
|
399
|
+
if (entry.length < 4 || entry[2] !== " ")
|
|
400
|
+
return null;
|
|
401
|
+
const status = entry.slice(0, 2);
|
|
402
|
+
const changedPath = entry.slice(3);
|
|
403
|
+
if (!changedPath)
|
|
404
|
+
return null;
|
|
405
|
+
paths.push(changedPath);
|
|
406
|
+
if (status.includes("R") || status.includes("C")) {
|
|
407
|
+
const originalPath = entries[++index];
|
|
408
|
+
if (!originalPath)
|
|
409
|
+
return null;
|
|
410
|
+
paths.push(originalPath);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
return [...new Set(paths)];
|
|
414
|
+
}
|
|
415
|
+
function parsePorcelainV2Snapshot(output) {
|
|
416
|
+
const records = output.split("\x00");
|
|
417
|
+
const headers = [];
|
|
418
|
+
while (records[0]?.startsWith("# ")) {
|
|
419
|
+
headers.push(records.shift());
|
|
420
|
+
}
|
|
421
|
+
const oidMatch = headers.join(`
|
|
422
|
+
`).match(/^# branch\.oid (.+)$/m);
|
|
423
|
+
if (!oidMatch)
|
|
424
|
+
return null;
|
|
425
|
+
const gitHead = /^[0-9a-f]{6,64}$/i.test(oidMatch[1]) ? oidMatch[1] : oidMatch[1] === "(initial)" ? null : null;
|
|
426
|
+
const paths = [];
|
|
427
|
+
for (let index = 0;index < records.length; index++) {
|
|
428
|
+
const record = records[index];
|
|
429
|
+
if (!record)
|
|
430
|
+
continue;
|
|
431
|
+
if (record.startsWith("? ")) {
|
|
432
|
+
paths.push(record.slice(2));
|
|
433
|
+
continue;
|
|
434
|
+
}
|
|
435
|
+
if (record.startsWith("1 ")) {
|
|
436
|
+
const changedPath = porcelainV2PathAfterFields(record, 8);
|
|
437
|
+
if (!changedPath)
|
|
438
|
+
return null;
|
|
439
|
+
paths.push(changedPath);
|
|
440
|
+
continue;
|
|
441
|
+
}
|
|
442
|
+
if (record.startsWith("2 ")) {
|
|
443
|
+
const changedPath = porcelainV2PathAfterFields(record, 9);
|
|
444
|
+
const originalPath = records[++index];
|
|
445
|
+
if (!changedPath || !originalPath)
|
|
446
|
+
return null;
|
|
447
|
+
paths.push(changedPath, originalPath);
|
|
448
|
+
continue;
|
|
449
|
+
}
|
|
450
|
+
if (record.startsWith("u ")) {
|
|
451
|
+
const changedPath = porcelainV2PathAfterFields(record, 10);
|
|
452
|
+
if (!changedPath)
|
|
453
|
+
return null;
|
|
454
|
+
paths.push(changedPath);
|
|
455
|
+
continue;
|
|
456
|
+
}
|
|
457
|
+
return null;
|
|
458
|
+
}
|
|
459
|
+
return { gitHead, changedFiles: [...new Set(paths)] };
|
|
460
|
+
}
|
|
461
|
+
function porcelainV2PathAfterFields(record, fields) {
|
|
462
|
+
let offset = 0;
|
|
463
|
+
for (let index = 0;index < fields; index++) {
|
|
464
|
+
const delimiter = record.indexOf(" ", offset);
|
|
465
|
+
if (delimiter < 0)
|
|
466
|
+
return null;
|
|
467
|
+
offset = delimiter + 1;
|
|
468
|
+
}
|
|
469
|
+
const pathValue = record.slice(offset);
|
|
470
|
+
return pathValue || null;
|
|
471
|
+
}
|
|
472
|
+
function captureWorkspaceSnapshot(directory, optionsOrScope = null, prHeadShaArg = null) {
|
|
473
|
+
const scope = typeof optionsOrScope === "object" && optionsOrScope !== null ? optionsOrScope.scope ?? null : optionsOrScope;
|
|
474
|
+
const configuredPrHeadSha = (() => {
|
|
475
|
+
if (typeof optionsOrScope !== "object" || optionsOrScope === null) {
|
|
476
|
+
return prHeadShaArg;
|
|
477
|
+
}
|
|
478
|
+
return optionsOrScope.prHeadSha ?? null;
|
|
479
|
+
})();
|
|
480
|
+
const resolveCurrentPrHeadSha = typeof optionsOrScope === "object" && optionsOrScope !== null && optionsOrScope.resolveCurrentPrHeadSha === true;
|
|
481
|
+
const upstreamBefore = resolveCurrentPrHeadSha ? runGit(directory, ["rev-parse", "@{upstream}"]) : null;
|
|
482
|
+
const porcelain = runGit(directory, [
|
|
483
|
+
"status",
|
|
484
|
+
"--porcelain=v2",
|
|
485
|
+
"--branch",
|
|
486
|
+
"-z",
|
|
487
|
+
"--untracked-files=all"
|
|
488
|
+
]);
|
|
489
|
+
const snapshot = porcelain === null ? null : parsePorcelainV2Snapshot(porcelain);
|
|
490
|
+
const upstreamAfter = resolveCurrentPrHeadSha ? runGit(directory, ["rev-parse", "@{upstream}"]) : null;
|
|
491
|
+
const prHeadSha = resolveCurrentPrHeadSha ? upstreamBefore && upstreamBefore === upstreamAfter ? upstreamBefore : null : configuredPrHeadSha;
|
|
492
|
+
return {
|
|
493
|
+
directory: path.resolve(directory),
|
|
494
|
+
gitHead: snapshot?.gitHead ?? null,
|
|
495
|
+
dirtyHash: porcelain === null ? null : digest(porcelain),
|
|
496
|
+
changedFiles: snapshot?.changedFiles ?? null,
|
|
497
|
+
prHeadSha,
|
|
498
|
+
scope
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
function changedFilesSinceSnapshot(directory, baseline) {
|
|
502
|
+
if (!baseline?.gitHead || baseline.changedFiles == null)
|
|
503
|
+
return null;
|
|
504
|
+
if (baseline.changedFiles.length > 0)
|
|
505
|
+
return null;
|
|
506
|
+
const current = captureWorkspaceSnapshot(directory);
|
|
507
|
+
if (!current.gitHead || current.changedFiles == null)
|
|
508
|
+
return null;
|
|
509
|
+
const changed = new Set(current.changedFiles);
|
|
510
|
+
if (baseline.gitHead !== current.gitHead) {
|
|
511
|
+
const committed = runGit(directory, [
|
|
512
|
+
"diff",
|
|
513
|
+
"--name-only",
|
|
514
|
+
"-z",
|
|
515
|
+
baseline.gitHead,
|
|
516
|
+
current.gitHead
|
|
517
|
+
]);
|
|
518
|
+
if (committed === null)
|
|
519
|
+
return null;
|
|
520
|
+
for (const changedPath of parseNulPaths(committed))
|
|
521
|
+
changed.add(changedPath);
|
|
522
|
+
}
|
|
523
|
+
return [...changed];
|
|
524
|
+
}
|
|
525
|
+
function workspaceSnapshotMatches(expected, current) {
|
|
526
|
+
if (!expected)
|
|
527
|
+
return { ok: true };
|
|
528
|
+
if (path.resolve(expected.directory) !== path.resolve(current.directory)) {
|
|
529
|
+
return {
|
|
530
|
+
ok: false,
|
|
531
|
+
reason: `directory changed: expected ${expected.directory}, got ${current.directory}`
|
|
532
|
+
};
|
|
533
|
+
}
|
|
534
|
+
const checks = ["gitHead", "dirtyHash", "prHeadSha"];
|
|
535
|
+
for (const key of checks) {
|
|
536
|
+
const expectedValue = expected[key];
|
|
537
|
+
if (expectedValue === null)
|
|
538
|
+
continue;
|
|
539
|
+
if (current[key] !== expectedValue) {
|
|
540
|
+
return {
|
|
541
|
+
ok: false,
|
|
542
|
+
reason: `${key} changed: expected ${expectedValue}, got ${current[key] ?? "unknown"}`
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
return { ok: true };
|
|
547
|
+
}
|
|
548
|
+
var compareWorkspaceSnapshot = workspaceSnapshotMatches;
|
|
549
|
+
function compareWorkspaceSnapshots(expected, current) {
|
|
550
|
+
const result = workspaceSnapshotMatches(expected, current);
|
|
551
|
+
if (result.ok)
|
|
552
|
+
return { stale: false };
|
|
553
|
+
return { stale: true, reason: result.reason };
|
|
554
|
+
}
|
|
555
|
+
function digest(text) {
|
|
556
|
+
return createHash("sha256").update(text).digest("hex");
|
|
557
|
+
}
|
|
558
|
+
var _internals = {
|
|
559
|
+
spawnSync: child_process.spawnSync,
|
|
560
|
+
yieldControl: () => new Promise((resolve2) => setImmediate(resolve2)),
|
|
561
|
+
parsePorcelainV2Snapshot
|
|
562
|
+
};
|
|
563
|
+
|
|
564
|
+
export { readGitTextAtRevision, resolveCurrentGitHead, resolveExactMergeBase, resolveCurrentUpstreamRemoteRef, resolveCurrentUpstreamPushTarget, resolveExactRemoteBranchHead, resolveGitControlStateDigest, resolveIsWorkingTreeClean, resolveCommitCountSince, resolveIsExactSingleChildCommit, resolveRemoteRefsContainingHead, resolvePrWorkflowRevisionDigest, resolvePrWorkflowRevisionDigestAsync, parsePorcelainPaths, captureWorkspaceSnapshot, changedFilesSinceSnapshot, workspaceSnapshotMatches, compareWorkspaceSnapshot, compareWorkspaceSnapshots, digest, _internals };
|
|
@@ -12,14 +12,14 @@ import {
|
|
|
12
12
|
detectPosixWrites,
|
|
13
13
|
detectWindowsWrites,
|
|
14
14
|
resolveWriteTargets
|
|
15
|
-
} from "./index-
|
|
15
|
+
} from "./index-dsf1yv4s.js";
|
|
16
16
|
import {
|
|
17
17
|
checkFileAuthority,
|
|
18
18
|
classifyFile,
|
|
19
19
|
isInDeclaredScope,
|
|
20
20
|
redactPath,
|
|
21
21
|
redactShellCommand
|
|
22
|
-
} from "./index-
|
|
22
|
+
} from "./index-pbjenws7.js";
|
|
23
23
|
|
|
24
24
|
// src/services/guardrail-explain-service.ts
|
|
25
25
|
import path from "path";
|
|
@@ -650,7 +650,7 @@ async function applyConfidenceFloorAction(directory, touched, options) {
|
|
|
650
650
|
const recovered = touched.filter((e) => e.confidence > CONFIDENCE_FLOOR + FLOOR_EPSILON && e.confidence_floor_demoted);
|
|
651
651
|
if (atFloor.length === 0 && recovered.length === 0)
|
|
652
652
|
return;
|
|
653
|
-
const { readKnowledgeCounterRollups, effectiveRetrievalOutcomes } = await import("./knowledge-events-
|
|
653
|
+
const { readKnowledgeCounterRollups, effectiveRetrievalOutcomes } = await import("./knowledge-events-qhr97sy9.js");
|
|
654
654
|
const rollups = await readKnowledgeCounterRollups(directory);
|
|
655
655
|
const flagIds = new Set;
|
|
656
656
|
for (const e of atFloor) {
|
|
@@ -717,11 +717,11 @@ async function applyConfidenceFloorAction(directory, touched, options) {
|
|
|
717
717
|
});
|
|
718
718
|
}
|
|
719
719
|
if (action === "quarantine" && toQuarantine.length > 0) {
|
|
720
|
-
const { quarantineEntry } = await import("./knowledge-validator-
|
|
721
|
-
const { KnowledgeConfigSchema } = await import("./schema-
|
|
720
|
+
const { quarantineEntry } = await import("./knowledge-validator-3t8tgzsz.js");
|
|
721
|
+
const { KnowledgeConfigSchema } = await import("./schema-y2d7j2jk.js");
|
|
722
722
|
let config;
|
|
723
723
|
try {
|
|
724
|
-
const { loadPluginConfigWithMeta } = await import("./index-
|
|
724
|
+
const { loadPluginConfigWithMeta } = await import("./index-rpg8qqjs.js");
|
|
725
725
|
const { config: loadedConfig } = loadPluginConfigWithMeta(directory);
|
|
726
726
|
config = KnowledgeConfigSchema.parse(loadedConfig.knowledge ?? {});
|
|
727
727
|
} catch {
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
loadPluginConfigWithMeta,
|
|
7
7
|
loadPluginConfigWithMetaAsync,
|
|
8
8
|
resolveWorktreeIsolationConfig
|
|
9
|
-
} from "./index-
|
|
9
|
+
} from "./index-3k8pg467.js";
|
|
10
10
|
import {
|
|
11
11
|
ApprovalEvidenceSchema,
|
|
12
12
|
BaseEvidenceSchema,
|
|
@@ -58,7 +58,7 @@ import {
|
|
|
58
58
|
WorktreeIsolationConfigSchema,
|
|
59
59
|
isQAAgent,
|
|
60
60
|
isSubagent
|
|
61
|
-
} from "./index-
|
|
61
|
+
} from "./index-8yvqkbw7.js";
|
|
62
62
|
import"./index-bk5tah7q.js";
|
|
63
63
|
import {
|
|
64
64
|
MigrationStatusSchema,
|
|
@@ -2,18 +2,18 @@
|
|
|
2
2
|
import {
|
|
3
3
|
ALLOWED_SKILL_PATH_PREFIXES,
|
|
4
4
|
validateSkillPath
|
|
5
|
-
} from "./index-
|
|
5
|
+
} from "./index-ghteqdy1.js";
|
|
6
6
|
import {
|
|
7
7
|
computeOutcomeSignal,
|
|
8
8
|
readKnowledge,
|
|
9
9
|
resolveHiveKnowledgePath,
|
|
10
10
|
resolveSwarmKnowledgePath,
|
|
11
11
|
transactKnowledge
|
|
12
|
-
} from "./index-
|
|
12
|
+
} from "./index-mwdcvh0e.js";
|
|
13
13
|
import {
|
|
14
14
|
effectiveRetrievalOutcomes,
|
|
15
15
|
readKnowledgeCounterRollups
|
|
16
|
-
} from "./index-
|
|
16
|
+
} from "./index-83rwq7pb.js";
|
|
17
17
|
import {
|
|
18
18
|
init_knowledge_types,
|
|
19
19
|
isActiveStatus
|