@inerrata-corporation/errata 2.0.6-dev.2657 → 2.0.6-dev.2681
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/errata.mjs +304 -66
- package/package.json +1 -1
package/errata.mjs
CHANGED
|
@@ -71184,7 +71184,7 @@ var init_report_render = __esm({
|
|
|
71184
71184
|
init_src6();
|
|
71185
71185
|
import { closeSync as closeSync2, existsSync as existsSync34, openSync as openSync2, readFileSync as readFileSync34, renameSync as renameSync4, statSync as statSync8 } from "node:fs";
|
|
71186
71186
|
import { join as join39, resolve as pathResolve2 } from "node:path";
|
|
71187
|
-
import { spawn as
|
|
71187
|
+
import { spawn as spawn4 } from "node:child_process";
|
|
71188
71188
|
|
|
71189
71189
|
// src/daemon.ts
|
|
71190
71190
|
import { existsSync as existsSync26, writeFileSync as writeFileSync22 } from "node:fs";
|
|
@@ -78536,7 +78536,7 @@ function createWatchBreaker(deps) {
|
|
|
78536
78536
|
}
|
|
78537
78537
|
|
|
78538
78538
|
// src/engine.ts
|
|
78539
|
-
var DAEMON_VERSION = true ? "2.0.6-dev.
|
|
78539
|
+
var DAEMON_VERSION = true ? "2.0.6-dev.2681" : "2.0.0-alpha.0";
|
|
78540
78540
|
var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
|
|
78541
78541
|
var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
|
|
78542
78542
|
var GIT_OP_MUTE_MS = 4e3;
|
|
@@ -82710,6 +82710,17 @@ function isGeneratedPath(path2) {
|
|
|
82710
82710
|
function isReleaseSubject(subject) {
|
|
82711
82711
|
return RELEASE_SUBJECT_RE.test(subject.trim());
|
|
82712
82712
|
}
|
|
82713
|
+
var FORGE_MARK_RES = [/^See merge request \S+!\d+$/i, /^Merge pull request #\d+ from \S+$/i];
|
|
82714
|
+
var TRAILER_RES = [
|
|
82715
|
+
/^(Closes|Fixes|Resolves|Related to|Part of)\b.*$/i,
|
|
82716
|
+
/^(Co-Authored-By|Signed-off-by|Reviewed-by|Approved-by):/i
|
|
82717
|
+
];
|
|
82718
|
+
function isForgeTrailerBody(body2) {
|
|
82719
|
+
const lines = body2.split("\n").map((l) => l.trim()).filter((l) => l.length > 0);
|
|
82720
|
+
if (!lines.some((l) => FORGE_MARK_RES.some((re) => re.test(l)))) return false;
|
|
82721
|
+
const own = lines.filter((l) => !FORGE_MARK_RES.some((re) => re.test(l)) && !TRAILER_RES.some((re) => re.test(l)));
|
|
82722
|
+
return own.length <= 1;
|
|
82723
|
+
}
|
|
82713
82724
|
function classifySkip(subject, files, tags) {
|
|
82714
82725
|
if (files.length > 0 && files.every((f) => f.binary || isLockfilePath(f.path) || isGeneratedPath(f.path))) {
|
|
82715
82726
|
return "lockfile-only";
|
|
@@ -82718,6 +82729,7 @@ function classifySkip(subject, files, tags) {
|
|
|
82718
82729
|
return void 0;
|
|
82719
82730
|
}
|
|
82720
82731
|
var GIT_OPTS = ["-c", "core.quotepath=false", "-c", "color.ui=never", "--no-pager"];
|
|
82732
|
+
var MERGE_SIDE_CONCURRENCY = 6;
|
|
82721
82733
|
var META_FMT = ["%H", "%P", "%aI", "%s", "%b"].join("%x00") + "%x00";
|
|
82722
82734
|
function parseMeta(head2) {
|
|
82723
82735
|
const [sha2, parents, authorDate, subject, body2] = head2.split("\0");
|
|
@@ -82756,6 +82768,38 @@ async function readCommit(root, sha2) {
|
|
|
82756
82768
|
const rest2 = parts2.slice(5).join("\0");
|
|
82757
82769
|
return { ...parseMeta(head2), files: parseNumstat(rest2) };
|
|
82758
82770
|
}
|
|
82771
|
+
async function readCommitsBulk(root, branch, since) {
|
|
82772
|
+
const out2 = await git(root, [
|
|
82773
|
+
...GIT_OPTS,
|
|
82774
|
+
"log",
|
|
82775
|
+
"--numstat",
|
|
82776
|
+
"-M",
|
|
82777
|
+
"--diff-merges=first-parent",
|
|
82778
|
+
`--format=%x1e${META_FMT}`,
|
|
82779
|
+
...since ? [`^${since}`] : [],
|
|
82780
|
+
branch
|
|
82781
|
+
]);
|
|
82782
|
+
const map2 = /* @__PURE__ */ new Map();
|
|
82783
|
+
for (const rec of out2.split("")) {
|
|
82784
|
+
if (!rec) continue;
|
|
82785
|
+
const parts2 = rec.split("\0");
|
|
82786
|
+
const meta3 = parseMeta(parts2.slice(0, 5).join("\0"));
|
|
82787
|
+
if (meta3.sha) map2.set(meta3.sha, { ...meta3, files: parseNumstat(parts2.slice(5).join("\0")) });
|
|
82788
|
+
}
|
|
82789
|
+
return map2;
|
|
82790
|
+
}
|
|
82791
|
+
async function mapBounded(items, limit, fn) {
|
|
82792
|
+
const out2 = new Array(items.length);
|
|
82793
|
+
let next = 0;
|
|
82794
|
+
const worker = async () => {
|
|
82795
|
+
while (next < items.length) {
|
|
82796
|
+
const i2 = next++;
|
|
82797
|
+
out2[i2] = await fn(items[i2]);
|
|
82798
|
+
}
|
|
82799
|
+
};
|
|
82800
|
+
await Promise.all(Array.from({ length: Math.min(limit, items.length) }, worker));
|
|
82801
|
+
return out2;
|
|
82802
|
+
}
|
|
82759
82803
|
async function firstParentLine(root, branch) {
|
|
82760
82804
|
const out2 = await git(root, [...GIT_OPTS, "rev-list", "--first-parent", "--reverse", "--parents", branch]);
|
|
82761
82805
|
return out2.split(/\r?\n/).filter((l) => l.trim().length > 0).map((l) => {
|
|
@@ -82795,11 +82839,18 @@ async function enumerateUnits(root, opts = {}) {
|
|
|
82795
82839
|
}
|
|
82796
82840
|
const tags = await tagsByCommit(root);
|
|
82797
82841
|
const tagsOf = (sha2) => tags.get(sha2) ?? [];
|
|
82842
|
+
if (start2 >= line.length) return [];
|
|
82843
|
+
const commits = await readCommitsBulk(root, branch, start2 > 0 ? line[start2 - 1].sha : null);
|
|
82844
|
+
const commit = async (sha2) => commits.get(sha2) ?? await readCommit(root, sha2);
|
|
82845
|
+
const merges = line.slice(start2).filter((c) => c.parents.length >= 2);
|
|
82846
|
+
const sides = /* @__PURE__ */ new Map();
|
|
82847
|
+
const sideLists = await mapBounded(merges, MERGE_SIDE_CONCURRENCY, (m) => mergeSide(root, m.parents[0], m.parents[1]));
|
|
82848
|
+
merges.forEach((m, i2) => sides.set(m.sha, sideLists[i2]));
|
|
82798
82849
|
const units = [];
|
|
82799
82850
|
for (let index = start2; index < line.length; index++) {
|
|
82800
82851
|
const { sha: sha2, parents } = line[index];
|
|
82801
82852
|
if (parents.length < 2) {
|
|
82802
|
-
const c = await
|
|
82853
|
+
const c = await commit(sha2);
|
|
82803
82854
|
const skip = classifySkip(c.subject, c.files, tagsOf(sha2));
|
|
82804
82855
|
units.push({
|
|
82805
82856
|
index,
|
|
@@ -82815,11 +82866,11 @@ async function enumerateUnits(root, opts = {}) {
|
|
|
82815
82866
|
});
|
|
82816
82867
|
continue;
|
|
82817
82868
|
}
|
|
82818
|
-
const side = await mergeSide(root, parents[0], parents[1]);
|
|
82869
|
+
const side = sides.get(sha2) ?? await mergeSide(root, parents[0], parents[1]);
|
|
82819
82870
|
const group = [];
|
|
82820
82871
|
for (const s of side) {
|
|
82821
82872
|
if (s.parents.length >= 2) continue;
|
|
82822
|
-
const c = await
|
|
82873
|
+
const c = await commit(s.sha);
|
|
82823
82874
|
const skip = classifySkip(c.subject, c.files, tagsOf(s.sha));
|
|
82824
82875
|
group.push({
|
|
82825
82876
|
index,
|
|
@@ -82835,8 +82886,9 @@ async function enumerateUnits(root, opts = {}) {
|
|
|
82835
82886
|
groupSha: sha2
|
|
82836
82887
|
});
|
|
82837
82888
|
}
|
|
82838
|
-
const merge2 = await
|
|
82839
|
-
|
|
82889
|
+
const merge2 = await commit(sha2);
|
|
82890
|
+
const hasMembers = group.some((g) => !g.skip);
|
|
82891
|
+
if (merge2.body.length > 0 && !(hasMembers && isForgeTrailerBody(merge2.body))) {
|
|
82840
82892
|
const skip = classifySkip(merge2.subject, merge2.files, tagsOf(sha2));
|
|
82841
82893
|
group.push({
|
|
82842
82894
|
index,
|
|
@@ -84068,13 +84120,115 @@ async function buildUnitBundle(root, unit, opts = {}) {
|
|
|
84068
84120
|
};
|
|
84069
84121
|
}
|
|
84070
84122
|
|
|
84123
|
+
// src/git-batch.ts
|
|
84124
|
+
import { spawn as spawn3 } from "node:child_process";
|
|
84125
|
+
var GitBlobReader = class {
|
|
84126
|
+
constructor(root, maxCached = 4096) {
|
|
84127
|
+
this.root = root;
|
|
84128
|
+
this.maxCached = maxCached;
|
|
84129
|
+
}
|
|
84130
|
+
proc = null;
|
|
84131
|
+
buf = Buffer.alloc(0);
|
|
84132
|
+
queue = [];
|
|
84133
|
+
cache = /* @__PURE__ */ new Map();
|
|
84134
|
+
failed = null;
|
|
84135
|
+
start() {
|
|
84136
|
+
if (this.proc) return this.proc;
|
|
84137
|
+
const proc = spawn3("git", ["-C", this.root, "cat-file", "--batch"], { windowsHide: true });
|
|
84138
|
+
proc.stdout.on("data", (chunk) => {
|
|
84139
|
+
this.buf = this.buf.length === 0 ? chunk : Buffer.concat([this.buf, chunk]);
|
|
84140
|
+
this.drain();
|
|
84141
|
+
});
|
|
84142
|
+
const fail = (err2) => {
|
|
84143
|
+
this.failed = err2;
|
|
84144
|
+
this.proc = null;
|
|
84145
|
+
for (const p of this.queue.splice(0)) p.reject(err2);
|
|
84146
|
+
};
|
|
84147
|
+
proc.on("error", fail);
|
|
84148
|
+
proc.stdin.on("error", fail);
|
|
84149
|
+
proc.on("exit", (code) => {
|
|
84150
|
+
if (this.queue.length > 0) fail(new Error(`git cat-file --batch exited (${code}) with ${this.queue.length} reads pending`));
|
|
84151
|
+
this.proc = null;
|
|
84152
|
+
});
|
|
84153
|
+
this.proc = proc;
|
|
84154
|
+
return proc;
|
|
84155
|
+
}
|
|
84156
|
+
drain() {
|
|
84157
|
+
for (; ; ) {
|
|
84158
|
+
const nl = this.buf.indexOf(10);
|
|
84159
|
+
if (nl < 0 || this.queue.length === 0) return;
|
|
84160
|
+
const header = this.buf.subarray(0, nl).toString("utf8");
|
|
84161
|
+
if (header.endsWith(" missing") || header.endsWith(" ambiguous")) {
|
|
84162
|
+
this.buf = this.buf.subarray(nl + 1);
|
|
84163
|
+
this.queue.shift().resolve(null);
|
|
84164
|
+
continue;
|
|
84165
|
+
}
|
|
84166
|
+
const size = Number(header.slice(header.lastIndexOf(" ") + 1));
|
|
84167
|
+
if (!Number.isFinite(size)) {
|
|
84168
|
+
const err2 = new Error(`git cat-file --batch: unexpected header ${JSON.stringify(header.slice(0, 120))}`);
|
|
84169
|
+
this.queue.shift().reject(err2);
|
|
84170
|
+
this.buf = this.buf.subarray(nl + 1);
|
|
84171
|
+
continue;
|
|
84172
|
+
}
|
|
84173
|
+
if (this.buf.length < nl + 1 + size + 1) return;
|
|
84174
|
+
const body2 = this.buf.subarray(nl + 1, nl + 1 + size).toString("utf8");
|
|
84175
|
+
this.buf = this.buf.subarray(nl + 1 + size + 1);
|
|
84176
|
+
const oid = header.slice(0, header.indexOf(" "));
|
|
84177
|
+
this.remember(oid, body2);
|
|
84178
|
+
this.queue.shift().resolve(body2);
|
|
84179
|
+
}
|
|
84180
|
+
}
|
|
84181
|
+
remember(oid, text) {
|
|
84182
|
+
if (this.cache.size >= this.maxCached) {
|
|
84183
|
+
const first = this.cache.keys().next().value;
|
|
84184
|
+
if (first !== void 0) this.cache.delete(first);
|
|
84185
|
+
}
|
|
84186
|
+
this.cache.set(oid, text);
|
|
84187
|
+
}
|
|
84188
|
+
/** Read one object by blob id (served from cache when seen) or `<rev>:<path>`. */
|
|
84189
|
+
read(spec) {
|
|
84190
|
+
const hit = this.cache.get(spec);
|
|
84191
|
+
if (hit !== void 0) return Promise.resolve(hit);
|
|
84192
|
+
if (this.failed) return Promise.reject(this.failed);
|
|
84193
|
+
if (/[\r\n]/.test(spec)) return Promise.resolve(null);
|
|
84194
|
+
const proc = this.start();
|
|
84195
|
+
return new Promise((resolve7, reject) => {
|
|
84196
|
+
this.queue.push({ resolve: resolve7, reject });
|
|
84197
|
+
proc.stdin.write(`${spec}
|
|
84198
|
+
`);
|
|
84199
|
+
});
|
|
84200
|
+
}
|
|
84201
|
+
/**
|
|
84202
|
+
* End the process and wait for it to exit: on Windows a live cat-file keeps
|
|
84203
|
+
* the repo's pack files open, so a caller that removes or moves the checkout
|
|
84204
|
+
* right after the walk (EPERM) must not race it. Bounded, never throws.
|
|
84205
|
+
*/
|
|
84206
|
+
close(timeoutMs = 5e3) {
|
|
84207
|
+
const proc = this.proc;
|
|
84208
|
+
this.proc = null;
|
|
84209
|
+
if (!proc || proc.exitCode !== null) return Promise.resolve();
|
|
84210
|
+
return new Promise((resolve7) => {
|
|
84211
|
+
const timer = setTimeout(() => {
|
|
84212
|
+
proc.kill();
|
|
84213
|
+
resolve7();
|
|
84214
|
+
}, timeoutMs);
|
|
84215
|
+
proc.once("exit", () => {
|
|
84216
|
+
clearTimeout(timer);
|
|
84217
|
+
resolve7();
|
|
84218
|
+
});
|
|
84219
|
+
proc.stdin.end();
|
|
84220
|
+
});
|
|
84221
|
+
}
|
|
84222
|
+
};
|
|
84223
|
+
|
|
84071
84224
|
// src/project-history.ts
|
|
84072
84225
|
init_profile2();
|
|
84073
84226
|
var execFileAsync = promisify(execFile3);
|
|
84074
|
-
var HISTORY_EXTRACTOR_VERSION = "history-
|
|
84227
|
+
var HISTORY_EXTRACTOR_VERSION = "history-2";
|
|
84075
84228
|
var LEASE_POLL_MS = 2e4;
|
|
84076
84229
|
var RECOVERY_DEADLINE_MS = 15 * 6e4;
|
|
84077
84230
|
var MAX_ANCHORS_PER_TOKEN = 20;
|
|
84231
|
+
var DEFAULT_LOOKAHEAD = 2;
|
|
84078
84232
|
async function defaultGit(root, args2) {
|
|
84079
84233
|
const { stdout } = await execFileAsync("git", ["-C", root, ...args2], { maxBuffer: 64 * 1024 * 1024, windowsHide: true });
|
|
84080
84234
|
return stdout;
|
|
@@ -84087,27 +84241,38 @@ function readIgnoreLines(root, profile) {
|
|
|
84087
84241
|
}
|
|
84088
84242
|
return [...lines, ...profile.ignoreExtra ?? []].map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
|
|
84089
84243
|
}
|
|
84090
|
-
|
|
84091
|
-
|
|
84092
|
-
const manifestPaths2 = listing.split("\n").map((l) => l.trim()).filter((p) => p && isManifestPath(p));
|
|
84093
|
-
if (manifestPaths2.length === 0) return void 0;
|
|
84094
|
-
const texts = /* @__PURE__ */ new Map();
|
|
84095
|
-
for (const p of manifestPaths2) {
|
|
84244
|
+
function readBlobViaGit(git3, root) {
|
|
84245
|
+
return async (spec) => {
|
|
84096
84246
|
try {
|
|
84097
|
-
|
|
84247
|
+
return await git3(root, ["show", spec]);
|
|
84098
84248
|
} catch {
|
|
84249
|
+
return null;
|
|
84099
84250
|
}
|
|
84251
|
+
};
|
|
84252
|
+
}
|
|
84253
|
+
function manifestBlobs(listing) {
|
|
84254
|
+
const out2 = /* @__PURE__ */ new Map();
|
|
84255
|
+
for (const line of listing.split("\n")) {
|
|
84256
|
+
const tab = line.indexOf(" ");
|
|
84257
|
+
if (tab < 0) continue;
|
|
84258
|
+
const path2 = line.slice(tab + 1).trim();
|
|
84259
|
+
const [, type, oid] = line.slice(0, tab).split(" ");
|
|
84260
|
+
if (type === "blob" && oid && path2 && isManifestPath(path2)) out2.set(path2, oid);
|
|
84100
84261
|
}
|
|
84262
|
+
return out2;
|
|
84263
|
+
}
|
|
84264
|
+
async function spineForUnit(git3, root, unit, readBlob) {
|
|
84265
|
+
const blobs = manifestBlobs(await git3(root, ["ls-tree", "-r", unit.sha]));
|
|
84266
|
+
if (blobs.size === 0) return void 0;
|
|
84267
|
+
const texts = /* @__PURE__ */ new Map();
|
|
84268
|
+
const read2 = await Promise.all([...blobs].map(async ([p, oid]) => [p, await readBlob(oid).catch(() => null)]));
|
|
84269
|
+
for (const [p, text] of read2) if (text !== null) texts.set(p, text);
|
|
84101
84270
|
const spine = buildSpine(unit.sha, [...texts.keys()], (p) => texts.get(p) ?? "");
|
|
84102
84271
|
const parentTexts = /* @__PURE__ */ new Map();
|
|
84103
84272
|
const readParent = (p) => parentTexts.get(p) ?? null;
|
|
84104
84273
|
for (const f of unit.files) {
|
|
84105
84274
|
if (!isManifestPath(f.path) || parentTexts.has(f.path)) continue;
|
|
84106
|
-
|
|
84107
|
-
parentTexts.set(f.path, await git3(root, ["show", `${unit.sha}^:${f.path}`]));
|
|
84108
|
-
} catch {
|
|
84109
|
-
parentTexts.set(f.path, null);
|
|
84110
|
-
}
|
|
84275
|
+
parentTexts.set(f.path, await readBlob(`${unit.sha}^:${f.path}`).catch(() => null));
|
|
84111
84276
|
}
|
|
84112
84277
|
const rings = depsForUnit(spine, unit.files.map((f) => f.path), readParent);
|
|
84113
84278
|
const wire = (d) => ({ ecosystem: d.ecosystem, name: d.name, version: d.version, kind: d.kind, manifest: d.manifest });
|
|
@@ -84150,16 +84315,37 @@ function stage(profile, patch, now) {
|
|
|
84150
84315
|
headSha: patch.headSha !== void 0 ? patch.headSha : prev?.headSha ?? null,
|
|
84151
84316
|
startedAt: prev?.startedAt ?? at,
|
|
84152
84317
|
updatedAt: at,
|
|
84153
|
-
|
|
84318
|
+
// `lastError: undefined` in the patch CLEARS it (a resumed walk must not
|
|
84319
|
+
// keep showing the error it recovered from); an absent key keeps it.
|
|
84320
|
+
..."lastError" in patch ? patch.lastError ? { lastError: patch.lastError } : {} : prev?.lastError ? { lastError: prev.lastError } : {},
|
|
84154
84321
|
...patch.counts ? { counts: patch.counts } : prev?.counts ? { counts: prev.counts } : {}
|
|
84155
84322
|
}
|
|
84156
84323
|
};
|
|
84157
84324
|
}
|
|
84325
|
+
function unitTiming(postStarted, prepMs, receipt) {
|
|
84326
|
+
const s = (ms) => `${(ms / 1e3).toFixed(1)}s`;
|
|
84327
|
+
const parts2 = [`local ${s(prepMs)}`];
|
|
84328
|
+
const g = receipt.gate;
|
|
84329
|
+
if (g) parts2.push(g.pRoutine === null ? `jev ${g.error ?? "n/a"}` : `jev ${s(g.ms)} p=${g.pRoutine}${g.skipped ? " skipped" : ""}`);
|
|
84330
|
+
if (receipt.timing?.modelMs !== void 0) parts2.push(`model ${s(receipt.timing.modelMs)}`);
|
|
84331
|
+
if (receipt.timing?.orderWaitMs) parts2.push(`waited ${s(receipt.timing.orderWaitMs)} for the previous write`);
|
|
84332
|
+
if (receipt.timing?.ingestMs !== void 0) parts2.push(`ingest ${s(receipt.timing.ingestMs)}`);
|
|
84333
|
+
return ` in ${s(Date.now() - postStarted + prepMs)} (${parts2.join(", ")})`;
|
|
84334
|
+
}
|
|
84158
84335
|
function addCounts(a, b) {
|
|
84159
84336
|
const sum = (k) => (a[k] ?? 0) + (b[k] ?? 0);
|
|
84160
84337
|
return { commitsWalked: sum("commitsWalked"), changesExtracted: sum("changesExtracted"), pairs: sum("pairs"), claims: sum("claims"), anchors: sum("anchors"), packages: sum("packages") };
|
|
84161
84338
|
}
|
|
84162
84339
|
async function runHistoryWalk(root, input, client, opts = {}) {
|
|
84340
|
+
const reader = opts.git ? null : new GitBlobReader(root);
|
|
84341
|
+
const readBlob = reader ? (spec) => reader.read(spec) : readBlobViaGit(opts.git ?? defaultGit, root);
|
|
84342
|
+
try {
|
|
84343
|
+
return await walk10(root, input, client, opts, readBlob);
|
|
84344
|
+
} finally {
|
|
84345
|
+
await reader?.close();
|
|
84346
|
+
}
|
|
84347
|
+
}
|
|
84348
|
+
async function walk10(root, input, client, opts, readBlob) {
|
|
84163
84349
|
const log = opts.log ?? ((line) => console.warn(line));
|
|
84164
84350
|
const now = opts.now ?? (() => /* @__PURE__ */ new Date());
|
|
84165
84351
|
const sleep = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
@@ -84199,8 +84385,77 @@ async function runHistoryWalk(root, input, client, opts = {}) {
|
|
|
84199
84385
|
let processed = 0;
|
|
84200
84386
|
const byIndex = /* @__PURE__ */ new Map();
|
|
84201
84387
|
for (const u of units) byIndex.set(u.index, [...byIndex.get(u.index) ?? [], u]);
|
|
84202
|
-
|
|
84203
|
-
|
|
84388
|
+
const lookahead = dryRun ? 0 : Math.max(0, opts.lookahead ?? DEFAULT_LOOKAHEAD);
|
|
84389
|
+
let doorOrders = false;
|
|
84390
|
+
const settle = (p) => p.then((res) => ({ res }), (err2) => ({ err: err2 }));
|
|
84391
|
+
const prepared = /* @__PURE__ */ new Map();
|
|
84392
|
+
const launched = /* @__PURE__ */ new Map();
|
|
84393
|
+
const cap = opts.maxUnits;
|
|
84394
|
+
const predecessor = (k) => {
|
|
84395
|
+
for (let j = k - 1; j >= 0; j--) if (!units[j].skip) return units[j];
|
|
84396
|
+
return void 0;
|
|
84397
|
+
};
|
|
84398
|
+
const prepare = (k) => {
|
|
84399
|
+
const hit = prepared.get(k);
|
|
84400
|
+
if (hit) return hit;
|
|
84401
|
+
const p = (async () => {
|
|
84402
|
+
const u = units[k];
|
|
84403
|
+
const prepStarted = Date.now();
|
|
84404
|
+
const group = byIndex.get(u.index) ?? [u];
|
|
84405
|
+
const bundle = await buildUnitBundle(root, u, {
|
|
84406
|
+
ignorePatterns: ignoreLines,
|
|
84407
|
+
narrative: narrative(u, u.isMerge ? group : void 0)
|
|
84408
|
+
});
|
|
84409
|
+
const prev = dryRun ? void 0 : predecessor(k);
|
|
84410
|
+
const body2 = {
|
|
84411
|
+
unit: {
|
|
84412
|
+
sha: u.sha,
|
|
84413
|
+
index: u.index,
|
|
84414
|
+
subIndex: u.subIndex,
|
|
84415
|
+
isMerge: u.isMerge,
|
|
84416
|
+
...u.groupSha ? { groupSha: u.groupSha } : {},
|
|
84417
|
+
...u.authorDate ? { authorDate: u.authorDate } : {}
|
|
84418
|
+
},
|
|
84419
|
+
narrative: bundle.narrative,
|
|
84420
|
+
fileList: bundle.fileList,
|
|
84421
|
+
diff: bundle.diff,
|
|
84422
|
+
pathTokens: Object.keys(bundle.pathTokens),
|
|
84423
|
+
extractorVersion: HISTORY_EXTRACTOR_VERSION,
|
|
84424
|
+
...opts.frame ? { frame: opts.frame } : {},
|
|
84425
|
+
...dryRun ? { dryRun: true } : {},
|
|
84426
|
+
...prev ? { after: { sha: prev.sha, subIndex: prev.subIndex } } : {}
|
|
84427
|
+
};
|
|
84428
|
+
const spine = await spineForUnit(git3, root, u, readBlob);
|
|
84429
|
+
if (spine) body2.spine = spine;
|
|
84430
|
+
const anchors = anchorsFor(bundle.pathTokens, ignoreLines, projectId, opts.anchors);
|
|
84431
|
+
if (anchors) {
|
|
84432
|
+
body2.anchors = anchors;
|
|
84433
|
+
body2.observedAtCommit = headSha;
|
|
84434
|
+
}
|
|
84435
|
+
return { body: body2, prepMs: Date.now() - prepStarted };
|
|
84436
|
+
})();
|
|
84437
|
+
prepared.set(k, p);
|
|
84438
|
+
return p;
|
|
84439
|
+
};
|
|
84440
|
+
const launch = async (k) => {
|
|
84441
|
+
if (launched.has(k)) return;
|
|
84442
|
+
const { body: body2 } = await prepare(k);
|
|
84443
|
+
if (launched.has(k)) return;
|
|
84444
|
+
launched.set(k, { at: Date.now(), settled: settle(Promise.resolve().then(() => post(projectId, body2))) });
|
|
84445
|
+
};
|
|
84446
|
+
const launchAhead = async (k) => {
|
|
84447
|
+
if (!doorOrders || lookahead === 0) return;
|
|
84448
|
+
let ahead = 0;
|
|
84449
|
+
for (let j = k + 1; j < units.length && ahead < lookahead; j++) {
|
|
84450
|
+
if (cap !== void 0 && processed + (j - k) >= cap) break;
|
|
84451
|
+
if (units[j].skip) continue;
|
|
84452
|
+
ahead += 1;
|
|
84453
|
+
await launch(j);
|
|
84454
|
+
}
|
|
84455
|
+
};
|
|
84456
|
+
for (let k = 0; k < units.length; k++) {
|
|
84457
|
+
const u = units[k];
|
|
84458
|
+
if (cap !== void 0 && processed >= cap) break;
|
|
84204
84459
|
const label = `${u.sha.slice(0, 12)}${u.subIndex ? `/${u.subIndex}` : ""}`;
|
|
84205
84460
|
const doneSoFar = (profile.historyStage?.unitsDone ?? 0) + 1;
|
|
84206
84461
|
const group = byIndex.get(u.index) ?? [u];
|
|
@@ -84214,34 +84469,7 @@ async function runHistoryWalk(root, input, client, opts = {}) {
|
|
|
84214
84469
|
log(`[errata] history ${label} skipped (${u.skip})`);
|
|
84215
84470
|
continue;
|
|
84216
84471
|
}
|
|
84217
|
-
const
|
|
84218
|
-
ignorePatterns: ignoreLines,
|
|
84219
|
-
narrative: narrative(u, u.isMerge ? group : void 0)
|
|
84220
|
-
});
|
|
84221
|
-
const body2 = {
|
|
84222
|
-
unit: {
|
|
84223
|
-
sha: u.sha,
|
|
84224
|
-
index: u.index,
|
|
84225
|
-
subIndex: u.subIndex,
|
|
84226
|
-
isMerge: u.isMerge,
|
|
84227
|
-
...u.groupSha ? { groupSha: u.groupSha } : {},
|
|
84228
|
-
...u.authorDate ? { authorDate: u.authorDate } : {}
|
|
84229
|
-
},
|
|
84230
|
-
narrative: bundle.narrative,
|
|
84231
|
-
fileList: bundle.fileList,
|
|
84232
|
-
diff: bundle.diff,
|
|
84233
|
-
pathTokens: Object.keys(bundle.pathTokens),
|
|
84234
|
-
extractorVersion: HISTORY_EXTRACTOR_VERSION,
|
|
84235
|
-
...opts.frame ? { frame: opts.frame } : {},
|
|
84236
|
-
...dryRun ? { dryRun: true } : {}
|
|
84237
|
-
};
|
|
84238
|
-
const spine = await spineForUnit(git3, root, u);
|
|
84239
|
-
if (spine) body2.spine = spine;
|
|
84240
|
-
const anchors = anchorsFor(bundle.pathTokens, ignoreLines, projectId, opts.anchors);
|
|
84241
|
-
if (anchors) {
|
|
84242
|
-
body2.anchors = anchors;
|
|
84243
|
-
body2.observedAtCommit = headSha;
|
|
84244
|
-
}
|
|
84472
|
+
const { body: body2, prepMs } = await prepare(k);
|
|
84245
84473
|
profile = stage(profile, { state: dryRun ? "extracting" : "contributing", unitsDone: doneSoFar - 1, lastError: void 0 }, now);
|
|
84246
84474
|
persist(profile);
|
|
84247
84475
|
response = await reportHistoryStage(client, profile, log);
|
|
@@ -84251,15 +84479,21 @@ async function runHistoryWalk(root, input, client, opts = {}) {
|
|
|
84251
84479
|
await reportHistoryStage(client, profile, log);
|
|
84252
84480
|
return { profile, processed, state: "refused" };
|
|
84253
84481
|
}
|
|
84254
|
-
|
|
84482
|
+
await launch(k);
|
|
84483
|
+
await launchAhead(k);
|
|
84484
|
+
const head2 = launched.get(k);
|
|
84485
|
+
launched.delete(k);
|
|
84486
|
+
prepared.delete(k);
|
|
84487
|
+
const started2 = head2.at;
|
|
84488
|
+
let first = head2.settled;
|
|
84255
84489
|
let outcome = null;
|
|
84256
84490
|
let attempt = 0;
|
|
84257
84491
|
while (outcome === null) {
|
|
84258
84492
|
attempt += 1;
|
|
84259
|
-
|
|
84260
|
-
|
|
84261
|
-
|
|
84262
|
-
|
|
84493
|
+
const settled = await (first ?? settle(Promise.resolve().then(() => post(projectId, body2))));
|
|
84494
|
+
first = null;
|
|
84495
|
+
if ("err" in settled) {
|
|
84496
|
+
const err2 = settled.err;
|
|
84263
84497
|
const status = err2 instanceof CloudError ? err2.status : 0;
|
|
84264
84498
|
const elapsed = Math.round((Date.now() - started2) / 1e3);
|
|
84265
84499
|
if (Date.now() - started2 > RECOVERY_DEADLINE_MS) {
|
|
@@ -84272,6 +84506,8 @@ async function runHistoryWalk(root, input, client, opts = {}) {
|
|
|
84272
84506
|
await sleep(attempt === 1 ? 1e4 : Math.min(3e4 * attempt, 12e4));
|
|
84273
84507
|
continue;
|
|
84274
84508
|
}
|
|
84509
|
+
const res = settled.res;
|
|
84510
|
+
if (res.ordered) doorOrders = true;
|
|
84275
84511
|
if (res.status === "in_progress") {
|
|
84276
84512
|
const retryAt = new Date(Date.now() + res.retryAfterMs).toISOString();
|
|
84277
84513
|
if (Date.now() - started2 > RECOVERY_DEADLINE_MS) {
|
|
@@ -84280,12 +84516,14 @@ async function runHistoryWalk(root, input, client, opts = {}) {
|
|
|
84280
84516
|
await reportHistoryStage(client, profile, log);
|
|
84281
84517
|
return { profile, processed, state: "paused" };
|
|
84282
84518
|
}
|
|
84283
|
-
|
|
84519
|
+
const why = res.waitingOn === "predecessor" ? `sent ahead, its predecessor ${res.predecessor === "failed" ? "failed" : "had not landed"} \u2014 re-POSTing in turn` : "run held by the door (lease)";
|
|
84520
|
+
log(`[errata] history ${label}: ${why}, polling in ${Math.min(LEASE_POLL_MS, res.retryAfterMs) / 1e3}s`);
|
|
84284
84521
|
await sleep(Math.min(LEASE_POLL_MS, Math.max(1e3, res.retryAfterMs)));
|
|
84285
84522
|
continue;
|
|
84286
84523
|
}
|
|
84287
84524
|
outcome = res;
|
|
84288
84525
|
}
|
|
84526
|
+
await launchAhead(k);
|
|
84289
84527
|
switch (outcome.status) {
|
|
84290
84528
|
case "completed": {
|
|
84291
84529
|
if (outcome.result.nodes.length !== outcome.counts.nodes || outcome.result.edges.length !== outcome.counts.edges) {
|
|
@@ -84296,7 +84534,7 @@ async function runHistoryWalk(root, input, client, opts = {}) {
|
|
|
84296
84534
|
}
|
|
84297
84535
|
const packages = new Set(outcome.result.nodes.filter((n) => n.decision !== "rejected" && n.canonicalId.startsWith("pkg:")).map((n) => n.canonicalId)).size;
|
|
84298
84536
|
counts = addCounts(counts, { commitsWalked: 1, changesExtracted: 1, pairs: outcome.receipt.keptPairs, claims: outcome.receipt.claims, anchors: outcome.receipt.anchors, packages });
|
|
84299
|
-
log(`[errata] history ${label}: ${outcome.result.nodes.length} nodes, ${outcome.result.edges.length} edges (${outcome.receipt.keptPairs} pairs, ${outcome.receipt.claims} claims)`);
|
|
84537
|
+
log(`[errata] history ${label}: ${outcome.result.nodes.length} nodes, ${outcome.result.edges.length} edges (${outcome.receipt.keptPairs} pairs, ${outcome.receipt.claims} claims)${unitTiming(started2, prepMs, outcome.receipt)}`);
|
|
84300
84538
|
break;
|
|
84301
84539
|
}
|
|
84302
84540
|
case "replayed": {
|
|
@@ -84307,7 +84545,7 @@ async function runHistoryWalk(root, input, client, opts = {}) {
|
|
|
84307
84545
|
case "empty":
|
|
84308
84546
|
case "dry-run":
|
|
84309
84547
|
counts = addCounts(counts, { commitsWalked: 1, changesExtracted: outcome.status === "dry-run" ? 1 : 0, pairs: outcome.receipt.keptPairs, claims: outcome.receipt.claims });
|
|
84310
|
-
log(`[errata] history ${label}: ${outcome.status} (${outcome.receipt.keptPairs} pairs, dropped ${outcome.receipt.droppedByEvidence} by evidence, ${outcome.receipt.droppedByAnchor} by anchor)`);
|
|
84548
|
+
log(`[errata] history ${label}: ${outcome.status} (${outcome.receipt.keptPairs} pairs, dropped ${outcome.receipt.droppedByEvidence} by evidence, ${outcome.receipt.droppedByAnchor} by anchor)${unitTiming(started2, prepMs, outcome.receipt)}`);
|
|
84311
84549
|
break;
|
|
84312
84550
|
case "refused":
|
|
84313
84551
|
profile = stage(profile, { state: "refused", lastError: `unit ${label} refused: ${outcome.reason}` }, now);
|
|
@@ -84389,12 +84627,12 @@ function applyStopRequest(profile, now = () => /* @__PURE__ */ new Date()) {
|
|
|
84389
84627
|
}
|
|
84390
84628
|
};
|
|
84391
84629
|
}
|
|
84392
|
-
async function startHistoryStage(root, input, client,
|
|
84630
|
+
async function startHistoryStage(root, input, client, walk11 = {}) {
|
|
84393
84631
|
let profile = input;
|
|
84394
84632
|
if (!profile.projectId) return { started: false, reason: "no-project", profile };
|
|
84395
84633
|
const response = await reportHistoryStage(client, profile);
|
|
84396
|
-
if (response?.consents &&
|
|
84397
|
-
profile =
|
|
84634
|
+
if (response?.consents && walk11.applyConsents) {
|
|
84635
|
+
profile = walk11.applyConsents(profile, response.consents);
|
|
84398
84636
|
}
|
|
84399
84637
|
const consents = historyConsents(profile);
|
|
84400
84638
|
if (response?.stopRequested && profile.historyStage && profile.historyStage.state !== "refused") {
|
|
@@ -84403,7 +84641,7 @@ async function startHistoryStage(root, input, client, walk10 = {}) {
|
|
|
84403
84641
|
return { started: false, reason: "stopped", profile: stopped };
|
|
84404
84642
|
}
|
|
84405
84643
|
if (!consents.mineHistory) return { started: false, reason: "consent-pending", profile };
|
|
84406
|
-
const outcome = await runHistoryWalk(root, profile, client,
|
|
84644
|
+
const outcome = await runHistoryWalk(root, profile, client, walk11);
|
|
84407
84645
|
return { started: true, profile: outcome.profile };
|
|
84408
84646
|
}
|
|
84409
84647
|
|
|
@@ -87100,9 +87338,9 @@ function deriveAuthBase(verificationUri) {
|
|
|
87100
87338
|
}
|
|
87101
87339
|
function openInBrowser(url2) {
|
|
87102
87340
|
try {
|
|
87103
|
-
void import("node:child_process").then(({ spawn:
|
|
87341
|
+
void import("node:child_process").then(({ spawn: spawn5 }) => {
|
|
87104
87342
|
const [cmd2, args2] = process.platform === "win32" ? ["cmd", ["/c", "start", "", url2]] : process.platform === "darwin" ? ["open", [url2]] : ["xdg-open", [url2]];
|
|
87105
|
-
|
|
87343
|
+
spawn5(cmd2, args2, { detached: true, stdio: "ignore" }).unref();
|
|
87106
87344
|
});
|
|
87107
87345
|
} catch {
|
|
87108
87346
|
}
|
|
@@ -89745,7 +89983,7 @@ function spawnDaemonDetached(options = {}) {
|
|
|
89745
89983
|
out2 = openSync2(logPath, "a");
|
|
89746
89984
|
} catch {
|
|
89747
89985
|
}
|
|
89748
|
-
|
|
89986
|
+
spawn4(cmd2, args2, {
|
|
89749
89987
|
detached: true,
|
|
89750
89988
|
stdio: ["ignore", out2, out2],
|
|
89751
89989
|
windowsHide: true,
|