@inerrata-corporation/errata 2.0.2-dev.1024 → 2.0.2-dev.1097
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 +132 -41
- package/package.json +1 -1
package/errata.mjs
CHANGED
|
@@ -19166,7 +19166,8 @@ function ingestDesignProblem(store, flag, opts) {
|
|
|
19166
19166
|
designProblemId: problemId,
|
|
19167
19167
|
sources: [opts.source],
|
|
19168
19168
|
corroborations: 0,
|
|
19169
|
-
scope: {}
|
|
19169
|
+
scope: {},
|
|
19170
|
+
...opts.hostHarness ? { hostHarness: opts.hostHarness } : {}
|
|
19170
19171
|
})
|
|
19171
19172
|
);
|
|
19172
19173
|
}
|
|
@@ -53100,7 +53101,64 @@ function readAssistantTurnsFrom(transcriptPath, fromByte, includeThinking = true
|
|
|
53100
53101
|
losses: { parseFailures: parsed.parseFailures, ioFailed, bytesUnreachable: 0 }
|
|
53101
53102
|
};
|
|
53102
53103
|
}
|
|
53104
|
+
function detectHostHarness(raw2) {
|
|
53105
|
+
const lines = raw2.split(/\r?\n/);
|
|
53106
|
+
let checked = 0;
|
|
53107
|
+
for (const line of lines) {
|
|
53108
|
+
if (!line.trim()) continue;
|
|
53109
|
+
if (checked++ >= 5) break;
|
|
53110
|
+
let obj;
|
|
53111
|
+
try {
|
|
53112
|
+
obj = JSON.parse(line);
|
|
53113
|
+
} catch {
|
|
53114
|
+
continue;
|
|
53115
|
+
}
|
|
53116
|
+
if (obj.type === "response_item" || obj.type === "event_msg" || obj.type === "session_meta" || obj.type === "turn_context" || obj.type === "world_state") {
|
|
53117
|
+
return "codex";
|
|
53118
|
+
}
|
|
53119
|
+
if (obj.type === "user" || obj.type === "assistant" || obj.type === "summary") {
|
|
53120
|
+
return "claude_code";
|
|
53121
|
+
}
|
|
53122
|
+
}
|
|
53123
|
+
return "claude_code";
|
|
53124
|
+
}
|
|
53103
53125
|
function parseAssistantTurns(raw2, includeThinking, skipFirstLineParseFailure = false) {
|
|
53126
|
+
if (!raw2) return { turns: [], parseFailures: 0 };
|
|
53127
|
+
return detectHostHarness(raw2) === "codex" ? parseCodexAssistantTurns(raw2, skipFirstLineParseFailure) : parseClaudeAssistantTurns(raw2, includeThinking, skipFirstLineParseFailure);
|
|
53128
|
+
}
|
|
53129
|
+
function parseCodexAssistantTurns(raw2, skipFirstLineParseFailure = false) {
|
|
53130
|
+
const turns = [];
|
|
53131
|
+
const lines = raw2.split(/\r?\n/);
|
|
53132
|
+
let parseFailures = 0;
|
|
53133
|
+
for (let i2 = 0; i2 < lines.length; i2++) {
|
|
53134
|
+
const line = lines[i2];
|
|
53135
|
+
if (!line) continue;
|
|
53136
|
+
let obj;
|
|
53137
|
+
try {
|
|
53138
|
+
obj = JSON.parse(line);
|
|
53139
|
+
} catch {
|
|
53140
|
+
if (!(i2 === 0 && skipFirstLineParseFailure)) parseFailures++;
|
|
53141
|
+
continue;
|
|
53142
|
+
}
|
|
53143
|
+
if (obj.type !== "response_item") continue;
|
|
53144
|
+
const payload = obj.payload;
|
|
53145
|
+
if (!payload || payload["type"] !== "message" || payload["role"] !== "assistant") continue;
|
|
53146
|
+
const content = payload["content"];
|
|
53147
|
+
if (!Array.isArray(content)) continue;
|
|
53148
|
+
const parts2 = [];
|
|
53149
|
+
for (const b of content) {
|
|
53150
|
+
if (b["type"] === "output_text" && typeof b["text"] === "string") parts2.push(b["text"]);
|
|
53151
|
+
}
|
|
53152
|
+
if (parts2.length === 0) continue;
|
|
53153
|
+
turns.push({
|
|
53154
|
+
uuid: typeof payload["id"] === "string" ? payload["id"] : `codex-${i2}`,
|
|
53155
|
+
text: parts2.join("\n\n"),
|
|
53156
|
+
hostHarness: "codex"
|
|
53157
|
+
});
|
|
53158
|
+
}
|
|
53159
|
+
return { turns, parseFailures };
|
|
53160
|
+
}
|
|
53161
|
+
function parseClaudeAssistantTurns(raw2, includeThinking, skipFirstLineParseFailure = false) {
|
|
53104
53162
|
if (!raw2) return { turns: [], parseFailures: 0 };
|
|
53105
53163
|
const turns = [];
|
|
53106
53164
|
const lines = raw2.split(/\r?\n/);
|
|
@@ -53154,6 +53212,7 @@ function parseAssistantTurns(raw2, includeThinking, skipFirstLineParseFailure =
|
|
|
53154
53212
|
turns.push({
|
|
53155
53213
|
uuid: String(obj.uuid ?? i2),
|
|
53156
53214
|
text: parts2.join("\n\n"),
|
|
53215
|
+
hostHarness: "claude_code",
|
|
53157
53216
|
...lastFile ? { workingFile: lastFile } : {},
|
|
53158
53217
|
...provenance ? { workingFileProvenance: provenance } : {},
|
|
53159
53218
|
...editedFile && editedFileTurnSeq === turnSeq ? { editedFile } : {},
|
|
@@ -56442,7 +56501,7 @@ function createLivenessWatch(deps) {
|
|
|
56442
56501
|
}
|
|
56443
56502
|
|
|
56444
56503
|
// src/engine.ts
|
|
56445
|
-
var DAEMON_VERSION = true ? "2.0.2-dev.
|
|
56504
|
+
var DAEMON_VERSION = true ? "2.0.2-dev.1097" : "2.0.0-alpha.0";
|
|
56446
56505
|
var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
|
|
56447
56506
|
var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
|
|
56448
56507
|
var GIT_OP_MUTE_MS = 4e3;
|
|
@@ -56948,6 +57007,7 @@ function createWorkspaceEngine(opts) {
|
|
|
56948
57007
|
contextDirty = false;
|
|
56949
57008
|
notifyDigest("recall");
|
|
56950
57009
|
};
|
|
57010
|
+
const normStackTokens = (xs) => (xs ?? []).map((t) => t.trim().toLowerCase().replace(/(?!^)[@\s].*$/, "")).filter(Boolean);
|
|
56951
57011
|
const maybeRefreshRemotePriors = () => {
|
|
56952
57012
|
if (opts.skipContextWriter || remoteInFlight) return;
|
|
56953
57013
|
const now = Date.now();
|
|
@@ -56958,10 +57018,13 @@ function createWorkspaceEngine(opts) {
|
|
|
56958
57018
|
remoteInFlight = true;
|
|
56959
57019
|
lastRemoteAt = now;
|
|
56960
57020
|
try {
|
|
56961
|
-
const norm =
|
|
57021
|
+
const norm = normStackTokens;
|
|
56962
57022
|
const seed = store.findNodesByLabel("Problem").sort((a, b) => b.lastUpdatedAt - a.lastUpdatedAt).slice(0, 6).map((p) => p.id);
|
|
56963
57023
|
const q = {
|
|
56964
|
-
stack:
|
|
57024
|
+
// Languages ride the stack list: the cloud's context-affinity matcher
|
|
57025
|
+
// resolves each token against both the Package and Language
|
|
57026
|
+
// namespaces, and the profile keeps them in separate fields.
|
|
57027
|
+
stack: norm([...profile.stack ?? [], ...profile.languages ?? []]),
|
|
56965
57028
|
domains: norm(profile.domains),
|
|
56966
57029
|
kinds: ["Pattern", "Technique", "AntiPattern"],
|
|
56967
57030
|
...seed.length ? { seed } : {},
|
|
@@ -56990,8 +57053,16 @@ function createWorkspaceEngine(opts) {
|
|
|
56990
57053
|
if (typeof cloud.search !== "function") return;
|
|
56991
57054
|
intentRemoteInFlight = true;
|
|
56992
57055
|
cloud.search({
|
|
56993
|
-
|
|
56994
|
-
|
|
57056
|
+
// VS-context-affinity: the intent lane used to send an empty context
|
|
57057
|
+
// while the priming lane sent the profile — opposite postures on the
|
|
57058
|
+
// same method. Under "union derived + stated, canonicalize once"
|
|
57059
|
+
// (VS-intent-fence) the stated intent IS the query and the derived
|
|
57060
|
+
// stack rides along as structured relevanceContext: the cloud no
|
|
57061
|
+
// longer concatenates these tokens into the embedding string, it
|
|
57062
|
+
// re-weights anchored hits with them (stated beats derived — the
|
|
57063
|
+
// intent text drives entry search, the stack only re-ranks).
|
|
57064
|
+
stack: normStackTokens([...profile?.stack ?? [], ...profile?.languages ?? []]),
|
|
57065
|
+
domains: normStackTokens(profile?.domains ?? []),
|
|
56995
57066
|
kinds: ["Pattern", "Technique", "AntiPattern", "Problem", "Solution"],
|
|
56996
57067
|
q: liveIntent,
|
|
56997
57068
|
channel: "intent",
|
|
@@ -57296,7 +57367,8 @@ function createWorkspaceEngine(opts) {
|
|
|
57296
57367
|
const r = ingestDesignProblem(store, flag, {
|
|
57297
57368
|
workspaceId: profile.id,
|
|
57298
57369
|
source: sessionId,
|
|
57299
|
-
ts: t
|
|
57370
|
+
ts: t,
|
|
57371
|
+
hostHarness: turn.hostHarness
|
|
57300
57372
|
});
|
|
57301
57373
|
if (r.created || r.corroborated) minted++;
|
|
57302
57374
|
else if (r.rejected) tagsRejected++;
|
|
@@ -57415,7 +57487,8 @@ function createWorkspaceEngine(opts) {
|
|
|
57415
57487
|
const r = ingestDesignProblem(store, { problem: p.statement, kind: p.kind }, {
|
|
57416
57488
|
workspaceId: profile.id,
|
|
57417
57489
|
source: sessionId,
|
|
57418
|
-
ts: t
|
|
57490
|
+
ts: t,
|
|
57491
|
+
hostHarness: turn.hostHarness
|
|
57419
57492
|
});
|
|
57420
57493
|
if (r.created || r.corroborated) {
|
|
57421
57494
|
minted++;
|
|
@@ -61755,6 +61828,45 @@ function consolidationGapMs(lastPassMs, policy) {
|
|
|
61755
61828
|
return Math.max(policy.baseFloorMs, lastPassMs * policy.dutyFactor);
|
|
61756
61829
|
}
|
|
61757
61830
|
|
|
61831
|
+
// src/hook-commands.ts
|
|
61832
|
+
function hookCurlCommand(port, path2 = "/api/hook") {
|
|
61833
|
+
const url2 = `http://127.0.0.1:${port}${path2}`;
|
|
61834
|
+
return process.platform === "win32" ? `cmd //c "curl -s --connect-timeout 1 --max-time 3 -X POST -H \\"Content-Type: application/json\\" --data-binary @- ${url2} >NUL 2>NUL || exit /b 0"` : `curl -s --connect-timeout 1 --max-time 3 -X POST -H 'Content-Type: application/json' --data-binary @- ${url2} >/dev/null 2>&1 || true`;
|
|
61835
|
+
}
|
|
61836
|
+
function hookRelayCommand(port, path2) {
|
|
61837
|
+
const url2 = `http://127.0.0.1:${port}${path2}`;
|
|
61838
|
+
return process.platform === "win32" ? `cmd //c "curl -s --connect-timeout 1 --max-time 2 -X POST -H \\"Content-Type: application/json\\" --data-binary @- ${url2} 2>NUL || echo {}"` : `curl -s --connect-timeout 1 --max-time 2 -X POST -H 'Content-Type: application/json' --data-binary @- ${url2} 2>/dev/null || echo '{}'`;
|
|
61839
|
+
}
|
|
61840
|
+
var CODEX_HOOKS_BEGIN = `# >>> errata hooks (errata-managed)`;
|
|
61841
|
+
var CODEX_HOOKS_END = `# <<< errata hooks`;
|
|
61842
|
+
function buildCodexHooksToml(port) {
|
|
61843
|
+
const cmd2 = hookCurlCommand(port).replace(/"/g, '\\"');
|
|
61844
|
+
const turnCmd = hookCurlCommand(port, "/api/turn").replace(/"/g, '\\"');
|
|
61845
|
+
return `${CODEX_HOOKS_BEGIN}
|
|
61846
|
+
[[hooks.PreToolUse]]
|
|
61847
|
+
matcher = ".*"
|
|
61848
|
+
|
|
61849
|
+
[[hooks.PreToolUse.hooks]]
|
|
61850
|
+
type = "command"
|
|
61851
|
+
command = "${cmd2}"
|
|
61852
|
+
timeout = 10
|
|
61853
|
+
|
|
61854
|
+
[[hooks.PostToolUse]]
|
|
61855
|
+
matcher = ".*"
|
|
61856
|
+
|
|
61857
|
+
[[hooks.PostToolUse.hooks]]
|
|
61858
|
+
type = "command"
|
|
61859
|
+
command = "${cmd2}"
|
|
61860
|
+
timeout = 10
|
|
61861
|
+
|
|
61862
|
+
[[hooks.PostToolUse.hooks]]
|
|
61863
|
+
type = "command"
|
|
61864
|
+
command = "${turnCmd}"
|
|
61865
|
+
timeout = 10
|
|
61866
|
+
${CODEX_HOOKS_END}
|
|
61867
|
+
`;
|
|
61868
|
+
}
|
|
61869
|
+
|
|
61758
61870
|
// src/cli.ts
|
|
61759
61871
|
var exitCleanOnEpipe = (err2) => {
|
|
61760
61872
|
if (err2.code === "EPIPE") process.exit(0);
|
|
@@ -63846,14 +63958,6 @@ function errataMcpInvocation() {
|
|
|
63846
63958
|
const { cmd: cmd2, args: args2 } = selfArgv("mcp");
|
|
63847
63959
|
return { command: cmd2, args: args2 };
|
|
63848
63960
|
}
|
|
63849
|
-
function hookCurlCommand(port, path2 = "/api/hook") {
|
|
63850
|
-
const url2 = `http://127.0.0.1:${port}${path2}`;
|
|
63851
|
-
return process.platform === "win32" ? `cmd //c "curl -s --connect-timeout 1 --max-time 3 -X POST -H \\"Content-Type: application/json\\" --data-binary @- ${url2} >NUL 2>NUL || exit /b 0"` : `curl -s --connect-timeout 1 --max-time 3 -X POST -H 'Content-Type: application/json' --data-binary @- ${url2} >/dev/null 2>&1 || true`;
|
|
63852
|
-
}
|
|
63853
|
-
function hookRelayCommand(port, path2) {
|
|
63854
|
-
const url2 = `http://127.0.0.1:${port}${path2}`;
|
|
63855
|
-
return process.platform === "win32" ? `cmd //c "curl -s --connect-timeout 1 --max-time 2 -X POST -H \\"Content-Type: application/json\\" --data-binary @- ${url2} 2>NUL || echo {}"` : `curl -s --connect-timeout 1 --max-time 2 -X POST -H 'Content-Type: application/json' --data-binary @- ${url2} 2>/dev/null || echo '{}'`;
|
|
63856
|
-
}
|
|
63857
63961
|
async function installClaudeHooks(port) {
|
|
63858
63962
|
const { mkdirSync: mkdirSync9, existsSync: existsSync31, readFileSync: readFileSync29, writeFileSync: writeFileSync23 } = await import("node:fs");
|
|
63859
63963
|
const { join: join33 } = await import("node:path");
|
|
@@ -63975,45 +64079,32 @@ async function installCodexHooks(port) {
|
|
|
63975
64079
|
const dir = join33(ROOT, ".codex");
|
|
63976
64080
|
if (!existsSync31(dir)) mkdirSync9(dir, { recursive: true });
|
|
63977
64081
|
const file2 = join33(dir, "config.toml");
|
|
63978
|
-
const BEGIN = `# >>> errata hooks (errata-managed)`;
|
|
63979
|
-
const END = `# <<< errata hooks`;
|
|
63980
64082
|
let existing = "";
|
|
63981
64083
|
if (existsSync31(file2)) {
|
|
63982
64084
|
existing = readFileSync29(file2, "utf8");
|
|
63983
|
-
const beginIdx = existing.indexOf(
|
|
63984
|
-
const endIdx = existing.indexOf(
|
|
64085
|
+
const beginIdx = existing.indexOf(CODEX_HOOKS_BEGIN);
|
|
64086
|
+
const endIdx = existing.indexOf(CODEX_HOOKS_END);
|
|
63985
64087
|
if (beginIdx >= 0 && endIdx > beginIdx) {
|
|
63986
|
-
existing = existing.slice(0, beginIdx).trimEnd() + existing.slice(endIdx +
|
|
64088
|
+
existing = existing.slice(0, beginIdx).trimEnd() + existing.slice(endIdx + CODEX_HOOKS_END.length).trimStart();
|
|
63987
64089
|
}
|
|
63988
64090
|
}
|
|
63989
|
-
const
|
|
63990
|
-
const block = `${BEGIN}
|
|
63991
|
-
[[hooks.PreToolUse]]
|
|
63992
|
-
matcher = ".*"
|
|
63993
|
-
|
|
63994
|
-
[[hooks.PreToolUse.hooks]]
|
|
63995
|
-
type = "command"
|
|
63996
|
-
command = "${cmd2}"
|
|
63997
|
-
timeout = 10
|
|
63998
|
-
|
|
63999
|
-
[[hooks.PostToolUse]]
|
|
64000
|
-
matcher = ".*"
|
|
64001
|
-
|
|
64002
|
-
[[hooks.PostToolUse.hooks]]
|
|
64003
|
-
type = "command"
|
|
64004
|
-
command = "${cmd2}"
|
|
64005
|
-
timeout = 10
|
|
64006
|
-
${END}
|
|
64007
|
-
`;
|
|
64091
|
+
const block = buildCodexHooksToml(port);
|
|
64008
64092
|
const final = existing.length > 0 && !existing.endsWith("\n") ? `${existing}
|
|
64009
64093
|
|
|
64010
64094
|
${block}` : existing + (existing.endsWith("\n\n") ? "" : "\n") + block;
|
|
64011
64095
|
writeFileSync23(file2, final, "utf8");
|
|
64012
64096
|
console.log(`installed Codex hooks \u2192 ${file2}`);
|
|
64013
|
-
console.log(` endpoint: http://127.0.0.1:${port}/api/hook`);
|
|
64097
|
+
console.log(` endpoint: http://127.0.0.1:${port}/api/hook (+ /api/turn on PostToolUse)`);
|
|
64014
64098
|
console.log("");
|
|
64015
64099
|
console.log(` Codex reads files via the shell, so the virtual graph surface`);
|
|
64016
64100
|
console.log(` works by \`cat .errata/g/<verb>/<seed>\` (e.g. cat .errata/g/burst/foo).`);
|
|
64101
|
+
console.log("");
|
|
64102
|
+
console.log(` Codex has no Stop/SessionEnd hook at this installed version, so`);
|
|
64103
|
+
console.log(` [!\u2026]/(fix:[\u2026]) tags are harvested via the PostToolUse-triggered`);
|
|
64104
|
+
console.log(` /api/turn call above instead \u2014 every turn with a tool call is`);
|
|
64105
|
+
console.log(` covered; a tool-less final turn is picked up on this workspace's`);
|
|
64106
|
+
console.log(` next daemon boot replay. Re-run this after a Codex upgrade in`);
|
|
64107
|
+
console.log(` case a newer version adds a real turn-boundary hook.`);
|
|
64017
64108
|
console.log(` If [features] hooks=false in your config.toml, set it true. Hook`);
|
|
64018
64109
|
console.log(` schemas evolve \u2014 if hooks stop firing after an update, re-run this.`);
|
|
64019
64110
|
}
|