@inerrata-corporation/errata 2.0.2-dev.227 → 2.0.2-dev.245
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 +129 -15
- package/package.json +1 -1
package/errata.mjs
CHANGED
|
@@ -21643,6 +21643,7 @@ var init_oauth = __esm({
|
|
|
21643
21643
|
|
|
21644
21644
|
// ../../packages/cloud-client/src/client.ts
|
|
21645
21645
|
import { randomUUID } from "node:crypto";
|
|
21646
|
+
import { gzipSync } from "node:zlib";
|
|
21646
21647
|
function wirePerContext(value) {
|
|
21647
21648
|
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
21648
21649
|
const out2 = {};
|
|
@@ -21840,6 +21841,11 @@ function normalizeSolution(input) {
|
|
|
21840
21841
|
validationSource: input.validationSource
|
|
21841
21842
|
};
|
|
21842
21843
|
}
|
|
21844
|
+
function isIntermediaryRejection(err2) {
|
|
21845
|
+
if (!(err2 instanceof CloudError)) return false;
|
|
21846
|
+
if (err2.status < 400 || err2.status >= 500) return false;
|
|
21847
|
+
return /<!DOCTYPE html|<html/i.test(err2.message);
|
|
21848
|
+
}
|
|
21843
21849
|
function chunkArray(items, size) {
|
|
21844
21850
|
if (items.length <= size) return items.length ? [[...items]] : [];
|
|
21845
21851
|
const out2 = [];
|
|
@@ -21857,7 +21863,7 @@ function provenanceHeaders(provenance) {
|
|
|
21857
21863
|
...provenance.agentModel ? { "x-inerrata-agent-model": provenance.agentModel } : {}
|
|
21858
21864
|
};
|
|
21859
21865
|
}
|
|
21860
|
-
var asWireCount, INGEST_NODE_CHUNK, CloudClient, CloudError;
|
|
21866
|
+
var asWireCount, INGEST_NODE_CHUNK, COMPRESS_MIN_BYTES, CloudClient, CloudError;
|
|
21861
21867
|
var init_client = __esm({
|
|
21862
21868
|
"../../packages/cloud-client/src/client.ts"() {
|
|
21863
21869
|
"use strict";
|
|
@@ -21865,6 +21871,7 @@ var init_client = __esm({
|
|
|
21865
21871
|
init_src();
|
|
21866
21872
|
asWireCount = (n) => typeof n === "number" && Number.isFinite(n) && n >= 0 ? Math.floor(n) : null;
|
|
21867
21873
|
INGEST_NODE_CHUNK = 8;
|
|
21874
|
+
COMPRESS_MIN_BYTES = 4096;
|
|
21868
21875
|
CloudClient = class {
|
|
21869
21876
|
baseUrl;
|
|
21870
21877
|
apiKey;
|
|
@@ -21879,6 +21886,8 @@ var init_client = __esm({
|
|
|
21879
21886
|
daemonVersion;
|
|
21880
21887
|
daemonChannel;
|
|
21881
21888
|
provenance;
|
|
21889
|
+
/** Cleared for the process once a server proves it cannot inflate (see `json`). */
|
|
21890
|
+
compressRequests;
|
|
21882
21891
|
constructor(opts) {
|
|
21883
21892
|
this.baseUrl = opts.baseUrl.replace(/\/+$/, "");
|
|
21884
21893
|
if (opts.apiKey !== void 0) this.apiKey = opts.apiKey;
|
|
@@ -21892,6 +21901,7 @@ var init_client = __esm({
|
|
|
21892
21901
|
this.timeoutMs = opts.timeoutMs ?? 15e3;
|
|
21893
21902
|
this.daemonVersion = opts.daemonVersion;
|
|
21894
21903
|
this.daemonChannel = opts.daemonChannel;
|
|
21904
|
+
this.compressRequests = opts.compressRequests ?? true;
|
|
21895
21905
|
this.provenance = opts.provenance ?? {
|
|
21896
21906
|
clientProduct: "inerrata_cloud_client",
|
|
21897
21907
|
clientKind: "sdk",
|
|
@@ -22029,18 +22039,24 @@ var init_client = __esm({
|
|
|
22029
22039
|
const startedAt = Date.now();
|
|
22030
22040
|
const totalChunks = Math.max(1, Math.ceil(batch.nodes.length / INGEST_NODE_CHUNK)) + Math.ceil(Math.max(0, batch.edges.length - MAX_EDGES_PER_PAYLOAD) / MAX_EDGES_PER_PAYLOAD);
|
|
22031
22041
|
let chunkIndex = 0;
|
|
22042
|
+
const blocked = [];
|
|
22032
22043
|
const emit = (nodeIds, accepted) => {
|
|
22033
22044
|
chunkIndex++;
|
|
22045
|
+
const refused = blocked.splice(0, blocked.length);
|
|
22046
|
+
const refusedSet = new Set(refused);
|
|
22034
22047
|
opts.onChunk?.({
|
|
22035
22048
|
chunkIndex,
|
|
22036
22049
|
totalChunks,
|
|
22037
|
-
|
|
22050
|
+
// Watermark only what actually landed — a blocked node never reached the
|
|
22051
|
+
// door, and marking it contributed would lose it permanently and silently.
|
|
22052
|
+
nodeIds: refusedSet.size ? nodeIds.filter((id) => !refusedSet.has(id)) : nodeIds,
|
|
22038
22053
|
accepted,
|
|
22039
|
-
elapsedMs: Date.now() - startedAt
|
|
22054
|
+
elapsedMs: Date.now() - startedAt,
|
|
22055
|
+
...refused.length ? { blockedNodeIds: refused } : {}
|
|
22040
22056
|
});
|
|
22041
22057
|
};
|
|
22042
22058
|
if (batch.nodes.length <= INGEST_NODE_CHUNK && batch.edges.length <= MAX_EDGES_PER_PAYLOAD) {
|
|
22043
|
-
const result = await this.ingestWithSplit(batch, batch.nodes, batch.edges);
|
|
22059
|
+
const result = await this.ingestWithSplit(batch, batch.nodes, batch.edges, blocked);
|
|
22044
22060
|
const summary = summarizeIngestResult(result);
|
|
22045
22061
|
emit(batch.nodes.map((n) => n.id), summary.accepted);
|
|
22046
22062
|
return { ...summary, result };
|
|
@@ -22055,7 +22071,7 @@ var init_client = __esm({
|
|
|
22055
22071
|
const shipped = new Set(inChunk);
|
|
22056
22072
|
pendingEdges = pendingEdges.filter((e) => !shipped.has(e));
|
|
22057
22073
|
}
|
|
22058
|
-
const r = await this.ingestWithSplit(batch, nodeChunk, inChunk);
|
|
22074
|
+
const r = await this.ingestWithSplit(batch, nodeChunk, inChunk, blocked);
|
|
22059
22075
|
emit(nodeChunk.map((n) => n.id), summarizeIngestResult(r).accepted);
|
|
22060
22076
|
merged.nodes.push(...r.nodes);
|
|
22061
22077
|
merged.edges.push(...r.edges);
|
|
@@ -22098,16 +22114,21 @@ var init_client = __esm({
|
|
|
22098
22114
|
* a verdict about the payload — splitting it would just re-send a rejected batch
|
|
22099
22115
|
* N more times — and a 409/413 has its own handling upstream.
|
|
22100
22116
|
*/
|
|
22101
|
-
async ingestWithSplit(batch, nodes, edges) {
|
|
22117
|
+
async ingestWithSplit(batch, nodes, edges, blocked) {
|
|
22102
22118
|
try {
|
|
22103
22119
|
return await this.ingestWire(toWirePayload({ ...batch, nodes, edges }, randomUUID()));
|
|
22104
22120
|
} catch (err2) {
|
|
22105
22121
|
const status = err2 instanceof CloudError ? err2.status : 0;
|
|
22106
22122
|
const timedOut = status === 502 || status === 504 || status === 408 || status === 0;
|
|
22107
|
-
|
|
22123
|
+
const refusedAtEdge = blocked !== void 0 && isIntermediaryRejection(err2);
|
|
22124
|
+
if (refusedAtEdge && nodes.length === 1 && nodes[0]) {
|
|
22125
|
+
blocked.push(nodes[0].id);
|
|
22126
|
+
return { runId: randomUUID(), nodes: [], edges: [] };
|
|
22127
|
+
}
|
|
22128
|
+
if (!timedOut && !refusedAtEdge || nodes.length <= 1) throw err2;
|
|
22108
22129
|
const mid = Math.ceil(nodes.length / 2);
|
|
22109
|
-
const a = await this.ingestWithSplit(batch, nodes.slice(0, mid), edges);
|
|
22110
|
-
const b = await this.ingestWithSplit(batch, nodes.slice(mid), []);
|
|
22130
|
+
const a = await this.ingestWithSplit(batch, nodes.slice(0, mid), edges, blocked);
|
|
22131
|
+
const b = await this.ingestWithSplit(batch, nodes.slice(mid), [], blocked);
|
|
22111
22132
|
return {
|
|
22112
22133
|
runId: a.runId,
|
|
22113
22134
|
nodes: [...a.nodes, ...b.nodes],
|
|
@@ -22409,15 +22430,43 @@ var init_client = __esm({
|
|
|
22409
22430
|
const token = opts?.bearerToken ?? await this.authToken();
|
|
22410
22431
|
if (token) headers["authorization"] = `Bearer ${token}`;
|
|
22411
22432
|
}
|
|
22433
|
+
let payload;
|
|
22434
|
+
if (body2 !== void 0) {
|
|
22435
|
+
const raw2 = JSON.stringify(body2);
|
|
22436
|
+
if (this.compressRequests && Buffer.byteLength(raw2) >= COMPRESS_MIN_BYTES) {
|
|
22437
|
+
payload = gzipSync(Buffer.from(raw2));
|
|
22438
|
+
headers["content-encoding"] = "gzip";
|
|
22439
|
+
} else {
|
|
22440
|
+
payload = raw2;
|
|
22441
|
+
}
|
|
22442
|
+
}
|
|
22412
22443
|
const ac = new AbortController();
|
|
22413
22444
|
const tid = setTimeout(() => ac.abort(), this.timeoutMs);
|
|
22414
22445
|
try {
|
|
22415
22446
|
const res = await this.fetchFn(url2, {
|
|
22416
22447
|
method,
|
|
22417
22448
|
headers,
|
|
22418
|
-
body:
|
|
22449
|
+
body: payload,
|
|
22419
22450
|
signal: ac.signal
|
|
22420
22451
|
});
|
|
22452
|
+
if (res.status === 400 && headers["content-encoding"] === "gzip") {
|
|
22453
|
+
delete headers["content-encoding"];
|
|
22454
|
+
const retry = await this.fetchFn(url2, {
|
|
22455
|
+
method,
|
|
22456
|
+
headers,
|
|
22457
|
+
body: JSON.stringify(body2),
|
|
22458
|
+
signal: ac.signal
|
|
22459
|
+
});
|
|
22460
|
+
if (!retry.ok) {
|
|
22461
|
+
const text = await retry.text();
|
|
22462
|
+
throw new CloudError(
|
|
22463
|
+
`${method} ${path2} failed: HTTP ${retry.status} ${text.slice(0, 200)}`,
|
|
22464
|
+
retry.status
|
|
22465
|
+
);
|
|
22466
|
+
}
|
|
22467
|
+
this.compressRequests = false;
|
|
22468
|
+
return await retry.json();
|
|
22469
|
+
}
|
|
22421
22470
|
if (!res.ok) {
|
|
22422
22471
|
const text = await res.text();
|
|
22423
22472
|
throw new CloudError(
|
|
@@ -52458,7 +52507,7 @@ function startLoopLagMonitor(thresholdMs = 1e3) {
|
|
|
52458
52507
|
}
|
|
52459
52508
|
|
|
52460
52509
|
// src/engine.ts
|
|
52461
|
-
var DAEMON_VERSION = true ? "2.0.2-dev.
|
|
52510
|
+
var DAEMON_VERSION = true ? "2.0.2-dev.245" : "2.0.0-alpha.0";
|
|
52462
52511
|
var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
|
|
52463
52512
|
var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
|
|
52464
52513
|
var GIT_OP_MUTE_MS = 4e3;
|
|
@@ -54729,6 +54778,39 @@ init_config();
|
|
|
54729
54778
|
// src/update.ts
|
|
54730
54779
|
import { spawn as spawn2 } from "node:child_process";
|
|
54731
54780
|
var PACKAGE_NAME = "@inerrata-corporation/errata";
|
|
54781
|
+
function parse3(v) {
|
|
54782
|
+
const m = /^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z][0-9A-Za-z.-]*))?/.exec(v.trim());
|
|
54783
|
+
if (!m) return null;
|
|
54784
|
+
return {
|
|
54785
|
+
base: [Number(m[1]), Number(m[2]), Number(m[3])],
|
|
54786
|
+
pre: m[4] === void 0 ? null : m[4].split(/[.-]/).map((p) => /^\d+$/.test(p) ? Number(p) : p)
|
|
54787
|
+
};
|
|
54788
|
+
}
|
|
54789
|
+
function compareVersions(a, b) {
|
|
54790
|
+
const pa = parse3(a);
|
|
54791
|
+
const pb = parse3(b);
|
|
54792
|
+
if (!pa || !pb) return 0;
|
|
54793
|
+
const [aMaj, aMin, aPatch] = pa.base;
|
|
54794
|
+
const [bMaj, bMin, bPatch] = pb.base;
|
|
54795
|
+
if (aMaj !== bMaj) return aMaj - bMaj;
|
|
54796
|
+
if (aMin !== bMin) return aMin - bMin;
|
|
54797
|
+
if (aPatch !== bPatch) return aPatch - bPatch;
|
|
54798
|
+
if (pa.pre === null && pb.pre === null) return 0;
|
|
54799
|
+
if (pa.pre === null) return 1;
|
|
54800
|
+
if (pb.pre === null) return -1;
|
|
54801
|
+
for (let i2 = 0; i2 < Math.max(pa.pre.length, pb.pre.length); i2++) {
|
|
54802
|
+
const x = pa.pre[i2];
|
|
54803
|
+
const y = pb.pre[i2];
|
|
54804
|
+
if (x === void 0) return -1;
|
|
54805
|
+
if (y === void 0) return 1;
|
|
54806
|
+
if (x === y) continue;
|
|
54807
|
+
if (typeof x === "number" && typeof y === "number") return x - y;
|
|
54808
|
+
if (typeof x === "number") return -1;
|
|
54809
|
+
if (typeof y === "number") return 1;
|
|
54810
|
+
return x < y ? -1 : 1;
|
|
54811
|
+
}
|
|
54812
|
+
return 0;
|
|
54813
|
+
}
|
|
54732
54814
|
async function latestPublished(channel, timeoutMs = 4e3) {
|
|
54733
54815
|
const ctrl = new AbortController();
|
|
54734
54816
|
const timer = setTimeout(() => ctrl.abort(), timeoutMs);
|
|
@@ -54748,10 +54830,14 @@ async function latestPublished(channel, timeoutMs = 4e3) {
|
|
|
54748
54830
|
}
|
|
54749
54831
|
async function checkForUpdate(channel) {
|
|
54750
54832
|
const latest = await latestPublished(channel);
|
|
54833
|
+
const direction = latest === null ? 0 : compareVersions(latest, DAEMON_VERSION);
|
|
54751
54834
|
return {
|
|
54752
54835
|
current: DAEMON_VERSION,
|
|
54753
54836
|
latest,
|
|
54754
|
-
|
|
54837
|
+
// `compareVersions` returns 0 for unparseable input, so an unrecognizable tag
|
|
54838
|
+
// is treated as "nothing to do" rather than gambling on a direction.
|
|
54839
|
+
updateAvailable: latest !== null && direction > 0,
|
|
54840
|
+
downgradeAvailable: latest !== null && direction < 0
|
|
54755
54841
|
};
|
|
54756
54842
|
}
|
|
54757
54843
|
var POLL_INTERVAL_MS = {
|
|
@@ -55733,6 +55819,11 @@ async function startMultiDaemon(opts = {}) {
|
|
|
55733
55819
|
if (!local) continue;
|
|
55734
55820
|
store.updateNode(localId, { attrs: { ...local.attrs, contributedAtSeq: seq } });
|
|
55735
55821
|
}
|
|
55822
|
+
if (p.blockedNodeIds?.length) {
|
|
55823
|
+
console.log(
|
|
55824
|
+
`[sync\u2192cloud] [${projectName}] context: ${p.blockedNodeIds.length} node(s) refused by an edge/CDN filter on content \u2014 left pending, will retry`
|
|
55825
|
+
);
|
|
55826
|
+
}
|
|
55736
55827
|
noteFlushProgress(p.accepted, p.nodeIds.length, `context ${p.chunkIndex}/${p.totalChunks}`);
|
|
55737
55828
|
}
|
|
55738
55829
|
});
|
|
@@ -55762,9 +55853,18 @@ async function startMultiDaemon(opts = {}) {
|
|
|
55762
55853
|
if (instances) {
|
|
55763
55854
|
if (project) instances.projectId = project.projectId;
|
|
55764
55855
|
await lane("instances", projectName, async () => {
|
|
55856
|
+
const blocked = /* @__PURE__ */ new Set();
|
|
55765
55857
|
const res = await client.ingest(instances, {
|
|
55766
|
-
onChunk: (p) =>
|
|
55858
|
+
onChunk: (p) => {
|
|
55859
|
+
for (const id of p.blockedNodeIds ?? []) blocked.add(id);
|
|
55860
|
+
noteFlushProgress(p.accepted, p.nodeIds.length, `instances ${p.chunkIndex}/${p.totalChunks}`);
|
|
55861
|
+
}
|
|
55767
55862
|
});
|
|
55863
|
+
if (blocked.size > 0) {
|
|
55864
|
+
console.log(
|
|
55865
|
+
`[sync\u2192cloud] [${projectName}] instances: ${blocked.size} node(s) refused by an edge/CDN filter on content \u2014 left pending, will retry. First: ${store.getNode([...blocked][0])?.description.slice(0, 120) ?? [...blocked][0]}`
|
|
55866
|
+
);
|
|
55867
|
+
}
|
|
55768
55868
|
uploaded += res.accepted;
|
|
55769
55869
|
const seq = store.currentIngestSeq();
|
|
55770
55870
|
const cloudIdByLocal = new Map(
|
|
@@ -55773,6 +55873,7 @@ async function startMultiDaemon(opts = {}) {
|
|
|
55773
55873
|
for (const n of instances.nodes) {
|
|
55774
55874
|
const local = store.getNode(n.id);
|
|
55775
55875
|
if (!local || !["Problem", "Solution", "RootCause"].includes(local.label)) continue;
|
|
55876
|
+
if (blocked.has(n.id)) continue;
|
|
55776
55877
|
const cloudNodeId = cloudIdByLocal.get(n.id);
|
|
55777
55878
|
store.updateNode(n.id, {
|
|
55778
55879
|
attrs: {
|
|
@@ -57214,9 +57315,11 @@ async function cmdUpdate(args2) {
|
|
|
57214
57315
|
const cfg = loadConfig();
|
|
57215
57316
|
let channel = cfg.updateChannel;
|
|
57216
57317
|
let checkOnly = false;
|
|
57318
|
+
let allowDowngrade = false;
|
|
57217
57319
|
for (let i2 = 0; i2 < args2.length; i2++) {
|
|
57218
57320
|
const a = args2[i2];
|
|
57219
57321
|
if (a === "--check") checkOnly = true;
|
|
57322
|
+
else if (a === "--allow-downgrade") allowDowngrade = true;
|
|
57220
57323
|
else if (a === "--channel") {
|
|
57221
57324
|
const v = args2[++i2];
|
|
57222
57325
|
if (v === "dev" || v === "latest") channel = v;
|
|
@@ -57237,8 +57340,19 @@ async function cmdUpdate(args2) {
|
|
|
57237
57340
|
return;
|
|
57238
57341
|
}
|
|
57239
57342
|
if (!status.updateAvailable) {
|
|
57240
|
-
|
|
57241
|
-
|
|
57343
|
+
if (status.downgradeAvailable) {
|
|
57344
|
+
console.log(
|
|
57345
|
+
`channel '${channel}' points at ${status.latest}, which is OLDER than the running ${status.current}.`
|
|
57346
|
+
);
|
|
57347
|
+
console.log(` not installing \u2014 a downgrade past a store migration cannot open its own graph.`);
|
|
57348
|
+
console.log(` if this is a deliberate rollback: errata update --allow-downgrade`);
|
|
57349
|
+
if (!allowDowngrade) return;
|
|
57350
|
+
console.log(`
|
|
57351
|
+
--allow-downgrade given; proceeding.`);
|
|
57352
|
+
} else {
|
|
57353
|
+
console.log(`errata is up to date \u2014 ${status.current} (channel: ${channel})`);
|
|
57354
|
+
return;
|
|
57355
|
+
}
|
|
57242
57356
|
}
|
|
57243
57357
|
console.log(`update available: ${status.current} \u2192 ${status.latest} (channel: ${channel})`);
|
|
57244
57358
|
if (checkOnly) {
|