omnius 1.0.457 → 1.0.458
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/dist/index.js +469 -32
- package/npm-shrinkwrap.json +5 -5
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -14315,7 +14315,7 @@ var init_file_edit = __esm({
|
|
|
14315
14315
|
path: { type: "string", description: "Absolute or relative file path" },
|
|
14316
14316
|
old_string: {
|
|
14317
14317
|
type: "string",
|
|
14318
|
-
description: "The exact string to search for and replace. Must be unique in the file (or use replace_all). Use old_string_base64 when JSON escaping is fragile."
|
|
14318
|
+
description: "The exact current string to search for and replace, copied from the most recent file_read for this file. Must be unique in the file (or use replace_all). Use old_string_base64 when JSON escaping is fragile."
|
|
14319
14319
|
},
|
|
14320
14320
|
old_string_base64: {
|
|
14321
14321
|
type: "string",
|
|
@@ -14340,14 +14340,14 @@ var init_file_edit = __esm({
|
|
|
14340
14340
|
},
|
|
14341
14341
|
expected_hash: {
|
|
14342
14342
|
type: "string",
|
|
14343
|
-
description: "
|
|
14343
|
+
description: "SHA-256 from the most recent file_read for this file. The runner refuses unverified exact replacements that omit or mismatch this hash."
|
|
14344
14344
|
},
|
|
14345
14345
|
dry_run: {
|
|
14346
14346
|
type: "boolean",
|
|
14347
14347
|
description: "Validate the edit and preview the diff without modifying disk."
|
|
14348
14348
|
}
|
|
14349
14349
|
},
|
|
14350
|
-
required: ["path"],
|
|
14350
|
+
required: ["path", "expected_hash"],
|
|
14351
14351
|
allOf: [
|
|
14352
14352
|
{ anyOf: [{ required: ["old_string"] }, { required: ["old_string_base64"] }] },
|
|
14353
14353
|
{ anyOf: [{ required: ["new_string"] }, { required: ["new_string_base64"] }] }
|
|
@@ -28570,7 +28570,7 @@ var init_batch_edit = __esm({
|
|
|
28570
28570
|
},
|
|
28571
28571
|
old_string: {
|
|
28572
28572
|
type: "string",
|
|
28573
|
-
description: "Exact string to find and replace
|
|
28573
|
+
description: "Exact current string to find and replace, copied from the most recent file_read for this file. Must be unique unless replace_all. Use old_string_base64 when JSON escaping is fragile."
|
|
28574
28574
|
},
|
|
28575
28575
|
old_string_base64: {
|
|
28576
28576
|
type: "string",
|
|
@@ -28595,10 +28595,10 @@ var init_batch_edit = __esm({
|
|
|
28595
28595
|
},
|
|
28596
28596
|
expected_hash: {
|
|
28597
28597
|
type: "string",
|
|
28598
|
-
description: "SHA-256 from the most recent file_read for this file. All edits for a file must use the same hash
|
|
28598
|
+
description: "SHA-256 from the most recent file_read for this file. All edits for a file must use the same verified hash."
|
|
28599
28599
|
}
|
|
28600
28600
|
},
|
|
28601
|
-
required: ["path"],
|
|
28601
|
+
required: ["path", "expected_hash"],
|
|
28602
28602
|
allOf: [
|
|
28603
28603
|
{ anyOf: [{ required: ["old_string"] }, { required: ["old_string_base64"] }] },
|
|
28604
28604
|
{ anyOf: [{ required: ["new_string"] }, { required: ["new_string_base64"] }] }
|
|
@@ -566824,6 +566824,7 @@ function shouldIgnore(relPath, base3, patterns) {
|
|
|
566824
566824
|
function scanWorkspace(opts) {
|
|
566825
566825
|
const root = opts.root;
|
|
566826
566826
|
const maxFiles = Math.max(1, Math.min(2e3, opts.maxFiles ?? 200));
|
|
566827
|
+
const maxDirs = Math.max(1, Math.min(5e3, opts.maxDirs ?? 1e3));
|
|
566827
566828
|
const noGitignore = opts.noGitignore === true;
|
|
566828
566829
|
const noDefaults = opts.noDefaults === true;
|
|
566829
566830
|
const patterns = [];
|
|
@@ -566834,6 +566835,7 @@ function scanWorkspace(opts) {
|
|
|
566834
566835
|
if (opts.extraIgnore)
|
|
566835
566836
|
patterns.push(...opts.extraIgnore);
|
|
566836
566837
|
const files = [];
|
|
566838
|
+
const dirs = [];
|
|
566837
566839
|
let totalBytes = 0;
|
|
566838
566840
|
let truncated = false;
|
|
566839
566841
|
let dirsVisited = 0;
|
|
@@ -566849,6 +566851,17 @@ function scanWorkspace(opts) {
|
|
|
566849
566851
|
continue;
|
|
566850
566852
|
visited.add(dir);
|
|
566851
566853
|
dirsVisited++;
|
|
566854
|
+
if (dirs.length < maxDirs) {
|
|
566855
|
+
try {
|
|
566856
|
+
const st = statSync32(dir);
|
|
566857
|
+
dirs.push({
|
|
566858
|
+
abs: dir,
|
|
566859
|
+
rel: relative8(root, dir) || ".",
|
|
566860
|
+
mtimeMs: st.mtimeMs
|
|
566861
|
+
});
|
|
566862
|
+
} catch {
|
|
566863
|
+
}
|
|
566864
|
+
}
|
|
566852
566865
|
let entries = [];
|
|
566853
566866
|
try {
|
|
566854
566867
|
entries = readdirSync30(dir);
|
|
@@ -566883,7 +566896,87 @@ function scanWorkspace(opts) {
|
|
|
566883
566896
|
}
|
|
566884
566897
|
}
|
|
566885
566898
|
files.sort((a2, b) => a2.rel.localeCompare(b.rel));
|
|
566886
|
-
|
|
566899
|
+
dirs.sort((a2, b) => a2.rel.localeCompare(b.rel));
|
|
566900
|
+
return { files, dirs, totalBytes, truncated, dirsVisited };
|
|
566901
|
+
}
|
|
566902
|
+
function humanBytes(n2) {
|
|
566903
|
+
if (n2 < 1024)
|
|
566904
|
+
return `${n2}B`;
|
|
566905
|
+
if (n2 < 1024 * 1024)
|
|
566906
|
+
return `${(n2 / 1024).toFixed(1)}KB`;
|
|
566907
|
+
return `${(n2 / 1024 / 1024).toFixed(1)}MB`;
|
|
566908
|
+
}
|
|
566909
|
+
function ensureTreeNode(root, rel) {
|
|
566910
|
+
if (!rel || rel === ".")
|
|
566911
|
+
return root;
|
|
566912
|
+
let node = root;
|
|
566913
|
+
for (const part of rel.split("/").filter(Boolean)) {
|
|
566914
|
+
let child = node.children.get(part);
|
|
566915
|
+
if (!child) {
|
|
566916
|
+
child = { name: part, children: /* @__PURE__ */ new Map(), directory: true };
|
|
566917
|
+
node.children.set(part, child);
|
|
566918
|
+
}
|
|
566919
|
+
node = child;
|
|
566920
|
+
}
|
|
566921
|
+
return node;
|
|
566922
|
+
}
|
|
566923
|
+
function renderWorkspaceTree(scan, opts = {}) {
|
|
566924
|
+
const maxLines = Math.max(10, Math.min(2e3, opts.maxLines ?? 120));
|
|
566925
|
+
const includeFileSizes = opts.includeFileSizes !== false;
|
|
566926
|
+
const root = {
|
|
566927
|
+
name: ".",
|
|
566928
|
+
children: /* @__PURE__ */ new Map(),
|
|
566929
|
+
directory: true
|
|
566930
|
+
};
|
|
566931
|
+
for (const dir of scan.dirs)
|
|
566932
|
+
ensureTreeNode(root, dir.rel).directory = true;
|
|
566933
|
+
for (const file of scan.files) {
|
|
566934
|
+
const parts = file.rel.split("/").filter(Boolean);
|
|
566935
|
+
const name10 = parts.pop();
|
|
566936
|
+
if (!name10)
|
|
566937
|
+
continue;
|
|
566938
|
+
const parent = ensureTreeNode(root, parts.join("/"));
|
|
566939
|
+
parent.children.set(name10, {
|
|
566940
|
+
name: name10,
|
|
566941
|
+
children: /* @__PURE__ */ new Map(),
|
|
566942
|
+
file,
|
|
566943
|
+
directory: false
|
|
566944
|
+
});
|
|
566945
|
+
}
|
|
566946
|
+
const lines = ["./"];
|
|
566947
|
+
let truncated = false;
|
|
566948
|
+
const walk2 = (node, depth) => {
|
|
566949
|
+
const children2 = [...node.children.values()].sort((a2, b) => {
|
|
566950
|
+
if (a2.directory !== b.directory)
|
|
566951
|
+
return a2.directory ? -1 : 1;
|
|
566952
|
+
return a2.name.localeCompare(b.name);
|
|
566953
|
+
});
|
|
566954
|
+
for (const child of children2) {
|
|
566955
|
+
if (lines.length >= maxLines) {
|
|
566956
|
+
truncated = true;
|
|
566957
|
+
return;
|
|
566958
|
+
}
|
|
566959
|
+
const indent2 = " ".repeat(depth);
|
|
566960
|
+
if (child.directory) {
|
|
566961
|
+
lines.push(`${indent2}${child.name}/`);
|
|
566962
|
+
walk2(child, depth + 1);
|
|
566963
|
+
if (truncated)
|
|
566964
|
+
return;
|
|
566965
|
+
} else {
|
|
566966
|
+
const size = includeFileSizes && child.file ? ` (${humanBytes(child.file.bytes)})` : "";
|
|
566967
|
+
lines.push(`${indent2}${child.name}${size}`);
|
|
566968
|
+
}
|
|
566969
|
+
}
|
|
566970
|
+
};
|
|
566971
|
+
walk2(root, 1);
|
|
566972
|
+
if (truncated || scan.truncated) {
|
|
566973
|
+
if (lines.length >= maxLines)
|
|
566974
|
+
lines[lines.length - 1] = "... [workspace tree truncated]";
|
|
566975
|
+
else
|
|
566976
|
+
lines.push("... [workspace tree truncated]");
|
|
566977
|
+
truncated = true;
|
|
566978
|
+
}
|
|
566979
|
+
return { text: lines.join("\n"), lineCount: lines.length, truncated };
|
|
566887
566980
|
}
|
|
566888
566981
|
var UNIVERSAL_DEFAULTS;
|
|
566889
566982
|
var init_world_state_disk_scan = __esm({
|
|
@@ -567578,9 +567671,9 @@ function regenerate(opts) {
|
|
|
567578
567671
|
lines.push(` No files found in workspace (excluding ignored paths).`);
|
|
567579
567672
|
} else {
|
|
567580
567673
|
const totalBytes = files.reduce((sum, f2) => sum + f2.bytes, 0);
|
|
567581
|
-
lines.push(` ${files.length} file(s)${truncated ? " (truncated — more exist)" : ""}, total ${
|
|
567674
|
+
lines.push(` ${files.length} file(s)${truncated ? " (truncated — more exist)" : ""}, total ${humanBytes2(totalBytes)}.`);
|
|
567582
567675
|
if (lastWriteFile) {
|
|
567583
|
-
lines.push(` Most recently modified: ${lastWriteFile.rel} (${
|
|
567676
|
+
lines.push(` Most recently modified: ${lastWriteFile.rel} (${humanBytes2(lastWriteFile.bytes)}, ${ago(nowMs - lastWriteFile.mtimeMs)}).`);
|
|
567584
567677
|
}
|
|
567585
567678
|
const topDirs = /* @__PURE__ */ new Map();
|
|
567586
567679
|
for (const f2 of files) {
|
|
@@ -567676,7 +567769,7 @@ function reconciledMark(t2) {
|
|
|
567676
567769
|
return "BLOCK";
|
|
567677
567770
|
}
|
|
567678
567771
|
}
|
|
567679
|
-
function
|
|
567772
|
+
function humanBytes2(n2) {
|
|
567680
567773
|
if (n2 < 1024)
|
|
567681
567774
|
return `${n2}B`;
|
|
567682
567775
|
if (n2 < 1024 * 1024)
|
|
@@ -573437,6 +573530,7 @@ var init_evidenceLedger = __esm({
|
|
|
573437
573530
|
this.entries.set(path12, {
|
|
573438
573531
|
...existing,
|
|
573439
573532
|
content: keepNew ? built.text : existing.content,
|
|
573533
|
+
contentHash: input.contentHash ?? existing.contentHash,
|
|
573440
573534
|
fidelity: keepNew ? built.fidelity : existing.fidelity,
|
|
573441
573535
|
ranges: mergeRanges([...existing.ranges, range]),
|
|
573442
573536
|
lastReadTurn: turn,
|
|
@@ -573447,6 +573541,7 @@ var init_evidenceLedger = __esm({
|
|
|
573447
573541
|
}
|
|
573448
573542
|
this.entries.set(path12, {
|
|
573449
573543
|
path: path12,
|
|
573544
|
+
contentHash: input.contentHash,
|
|
573450
573545
|
readVersion: fileVersion,
|
|
573451
573546
|
mtimeMs: input.mtimeMs ?? 0,
|
|
573452
573547
|
lastReadTurn: turn,
|
|
@@ -573475,7 +573570,7 @@ var init_evidenceLedger = __esm({
|
|
|
573475
573570
|
* like a manual chmod, device reconnect, or human edit), mark as stale.
|
|
573476
573571
|
* Returns true if evidence was valid, false if became stale or stat failed.
|
|
573477
573572
|
*/
|
|
573478
|
-
validateFreshness(path12) {
|
|
573573
|
+
validateFreshness(path12, statPath = path12) {
|
|
573479
573574
|
const e2 = this.entries.get(path12);
|
|
573480
573575
|
if (!e2)
|
|
573481
573576
|
return false;
|
|
@@ -573484,7 +573579,7 @@ var init_evidenceLedger = __esm({
|
|
|
573484
573579
|
if (e2.mtimeMs <= 0)
|
|
573485
573580
|
return true;
|
|
573486
573581
|
try {
|
|
573487
|
-
const st = statSync36(
|
|
573582
|
+
const st = statSync36(statPath, { throwIfNoEntry: false });
|
|
573488
573583
|
if (!st)
|
|
573489
573584
|
return true;
|
|
573490
573585
|
if (st.mtimeMs > e2.mtimeMs) {
|
|
@@ -573499,6 +573594,11 @@ var init_evidenceLedger = __esm({
|
|
|
573499
573594
|
get(path12) {
|
|
573500
573595
|
return this.entries.get(path12);
|
|
573501
573596
|
}
|
|
573597
|
+
markStale(path12) {
|
|
573598
|
+
const e2 = this.entries.get(path12);
|
|
573599
|
+
if (e2)
|
|
573600
|
+
e2.stale = true;
|
|
573601
|
+
}
|
|
573502
573602
|
size() {
|
|
573503
573603
|
return this.entries.size;
|
|
573504
573604
|
}
|
|
@@ -573521,12 +573621,12 @@ var init_evidenceLedger = __esm({
|
|
|
573521
573621
|
];
|
|
573522
573622
|
let used = lines.join("\n").length;
|
|
573523
573623
|
for (const e2 of sorted) {
|
|
573524
|
-
const header = e2.stale ? `▸ ${e2.path} @v${e2.readVersion} [STALE — changed since read; re-read needed] (${rangeLabel(e2.ranges)})` : `▸ ${e2.path} @v${e2.readVersion} [FRESH] (${rangeLabel(e2.ranges)}):`;
|
|
573624
|
+
const header = e2.stale ? `▸ ${e2.path} @v${e2.readVersion} [STALE — changed since read; re-read needed] (${rangeLabel(e2.ranges)})` : `▸ ${e2.path} @v${e2.readVersion} [FRESH${e2.contentHash ? ` sha256=${e2.contentHash}` : ""}] (${rangeLabel(e2.ranges)}):`;
|
|
573525
573625
|
const body = e2.stale ? "" : "\n" + indent(e2.content);
|
|
573526
573626
|
const chunk = `${header}${body}
|
|
573527
573627
|
`;
|
|
573528
573628
|
if (used + chunk.length > maxChars) {
|
|
573529
|
-
const stub = `▸ ${e2.path} @v${e2.readVersion} [${e2.stale ? "STALE" :
|
|
573629
|
+
const stub = `▸ ${e2.path} @v${e2.readVersion} [${e2.stale ? "STALE" : `FRESH${e2.contentHash ? ` sha256=${e2.contentHash}` : ""}`}] (${rangeLabel(e2.ranges)})
|
|
573530
573630
|
`;
|
|
573531
573631
|
if (used + stub.length <= maxChars) {
|
|
573532
573632
|
lines.push(stub);
|
|
@@ -574603,9 +574703,22 @@ ${input.error}`;
|
|
|
574603
574703
|
}
|
|
574604
574704
|
if (input.realFileMutation)
|
|
574605
574705
|
diagnoses.add("project-file-mutation");
|
|
574606
|
-
const
|
|
574607
|
-
|
|
574608
|
-
|
|
574706
|
+
const focusDecision = input.focusDecision && typeof input.focusDecision === "object" ? input.focusDecision : null;
|
|
574707
|
+
const focusDecisionKind = typeof focusDecision?.["kind"] === "string" ? focusDecision["kind"] : null;
|
|
574708
|
+
if (focusDecisionKind === "block_tool_call") {
|
|
574709
|
+
if (focusDecision?.["success"] === true || input.success) {
|
|
574710
|
+
diagnoses.add("focus-supervisor-cached-evidence");
|
|
574711
|
+
} else {
|
|
574712
|
+
diagnoses.add("focus-supervisor-block");
|
|
574713
|
+
}
|
|
574714
|
+
} else {
|
|
574715
|
+
const focusDecisionJson = previewJson(input.focusDecision ?? {});
|
|
574716
|
+
if (focusDecisionJson.includes("block_tool_call")) {
|
|
574717
|
+
if (input.success)
|
|
574718
|
+
diagnoses.add("focus-supervisor-cached-evidence");
|
|
574719
|
+
else
|
|
574720
|
+
diagnoses.add("focus-supervisor-block");
|
|
574721
|
+
}
|
|
574609
574722
|
}
|
|
574610
574723
|
const focusJson = previewJson(input.focusSupervisor ?? {});
|
|
574611
574724
|
if (focusJson.includes("block_tool_call") || focusJson.includes("requiredNextAction")) {
|
|
@@ -574736,7 +574849,8 @@ function writeContract(contractPath) {
|
|
|
574736
574849
|
"",
|
|
574737
574850
|
"- `shell-brace-whitespace`: a shell command used brace expansion containing whitespace, which can split an intended path set into unrelated shell words.",
|
|
574738
574851
|
"- `successful-command-needs-post-state-audit`: the command exited zero but its shape is risky enough that filesystem state should be inspected.",
|
|
574739
|
-
"- `focus-supervisor-block`: the tool result or supervisor state shows
|
|
574852
|
+
"- `focus-supervisor-block`: the tool result or supervisor state shows an unsuccessful blocked next action.",
|
|
574853
|
+
"- `focus-supervisor-cached-evidence`: the focus supervisor short-circuited a call successfully by reusing current cached evidence.",
|
|
574740
574854
|
"- `background-task-id-missing`: task status lookup could not find the spawned task id.",
|
|
574741
574855
|
"- `raw-discovery-dominates-context`: context-window metrics show low signal/noise around raw discovery output.",
|
|
574742
574856
|
""
|
|
@@ -577523,7 +577637,7 @@ RECOVERY: cd to the directory containing '${file}', run a plain install with no
|
|
|
577523
577637
|
import { existsSync as _fsExistsSync, readFileSync as _fsReadFileSync, writeFileSync as _fsWriteFileSync, appendFileSync as _fsAppendFileSync, unlinkSync as _fsUnlinkSync, mkdirSync as _fsMkdirSync, statSync as _fsStatSync, readdirSync as _fsReaddirSync } from "node:fs";
|
|
577524
577638
|
import { execFile as _execFile, spawn as _spawn } from "node:child_process";
|
|
577525
577639
|
import { createHash as _createHash } from "node:crypto";
|
|
577526
|
-
import { join as _pathJoin, resolve as _pathResolve } from "node:path";
|
|
577640
|
+
import { join as _pathJoin, relative as _pathRelative, resolve as _pathResolve } from "node:path";
|
|
577527
577641
|
import { tmpdir as _osTmpdir } from "node:os";
|
|
577528
577642
|
import { homedir as _osHomedir } from "node:os";
|
|
577529
577643
|
import { z as z17 } from "zod";
|
|
@@ -578186,6 +578300,7 @@ var init_agenticRunner = __esm({
|
|
|
578186
578300
|
init_lesson_bank();
|
|
578187
578301
|
init_intervention_replay();
|
|
578188
578302
|
init_world_state_regenerator();
|
|
578303
|
+
init_world_state_disk_scan();
|
|
578189
578304
|
init_backward_pass_runner();
|
|
578190
578305
|
init_world_state_plan_reconciler();
|
|
578191
578306
|
init_process_async2();
|
|
@@ -581019,7 +581134,7 @@ ${result.error ?? ""}`;
|
|
|
581019
581134
|
if (result.success !== true)
|
|
581020
581135
|
return false;
|
|
581021
581136
|
if (toolName === "file_read") {
|
|
581022
|
-
return targetPaths.length > 0 && targetPaths.some((path12) => this._evidenceLedger.hasFresh(path12));
|
|
581137
|
+
return targetPaths.length > 0 && targetPaths.some((path12) => this._evidenceLedger.hasFresh(this._normalizeEvidencePath(path12)));
|
|
581023
581138
|
}
|
|
581024
581139
|
return toolName === "list_directory" || toolName === "find_files" || toolName === "grep_search";
|
|
581025
581140
|
}
|
|
@@ -583128,6 +583243,133 @@ ${latest.output || ""}`.trim();
|
|
|
583128
583243
|
return null;
|
|
583129
583244
|
}
|
|
583130
583245
|
}
|
|
583246
|
+
/**
|
|
583247
|
+
* Render a fresh, bounded workspace tree from disk for the active context
|
|
583248
|
+
* frame, and persist the fuller capped tree under .omnius/world-state/tree.
|
|
583249
|
+
* This is deliberately independent of tool history: it answers "what exists
|
|
583250
|
+
* where right now?" without forcing the model to list_directory for basic
|
|
583251
|
+
* orientation.
|
|
583252
|
+
*/
|
|
583253
|
+
_renderWorkspaceTreeBlock(turn) {
|
|
583254
|
+
const rawEnabled = String(process.env["OMNIUS_CONTEXT_WORKSPACE_TREE"] ?? "1").trim().toLowerCase();
|
|
583255
|
+
if (rawEnabled === "0" || rawEnabled === "false" || rawEnabled === "off") {
|
|
583256
|
+
return null;
|
|
583257
|
+
}
|
|
583258
|
+
const intEnv = (name10, fallback, min, max) => {
|
|
583259
|
+
const parsed = Number.parseInt(process.env[name10] ?? "", 10);
|
|
583260
|
+
return Number.isFinite(parsed) ? Math.max(min, Math.min(max, parsed)) : fallback;
|
|
583261
|
+
};
|
|
583262
|
+
const root = this.authoritativeWorkingDirectory();
|
|
583263
|
+
const maxFiles = intEnv("OMNIUS_CONTEXT_TREE_MAX_FILES", 1e3, 20, 2e3);
|
|
583264
|
+
const maxDirs = intEnv("OMNIUS_CONTEXT_TREE_MAX_DIRS", 1500, 20, 5e3);
|
|
583265
|
+
const contextLines = intEnv("OMNIUS_CONTEXT_TREE_LINES", 90, 20, 400);
|
|
583266
|
+
const artifactLines = intEnv("OMNIUS_CONTEXT_TREE_ARTIFACT_LINES", 1800, 100, 4e3);
|
|
583267
|
+
try {
|
|
583268
|
+
const scan = scanWorkspace({ root, maxFiles, maxDirs });
|
|
583269
|
+
const compactTree = renderWorkspaceTree(scan, { maxLines: contextLines });
|
|
583270
|
+
const fullTree = renderWorkspaceTree(scan, { maxLines: artifactLines });
|
|
583271
|
+
const totalBytes = scan.files.reduce((sum, file) => sum + file.bytes, 0);
|
|
583272
|
+
const generatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
583273
|
+
const focusSnapshot = this._focusSupervisor?.snapshot();
|
|
583274
|
+
const recentActions = this._adversaryToolOutcomes.slice(-12).map((item) => ({
|
|
583275
|
+
turn: item.turn,
|
|
583276
|
+
tool: item.tool,
|
|
583277
|
+
success: item.succeeded,
|
|
583278
|
+
path: item.path,
|
|
583279
|
+
stateVersion: item.stateVersion,
|
|
583280
|
+
preview: item.preview.slice(0, 240)
|
|
583281
|
+
}));
|
|
583282
|
+
const recentActionLines = recentActions.slice(-6).map((item) => {
|
|
583283
|
+
const path12 = item.path ? ` path=${item.path}` : "";
|
|
583284
|
+
return `- turn=${item.turn} ${item.tool} ${item.success ? "ok" : "err"}${path12}: ${item.preview.replace(/\s+/g, " ").slice(0, 160)}`;
|
|
583285
|
+
});
|
|
583286
|
+
const treeDir = _pathJoin(this.omniusStateDir(), "world-state", "tree");
|
|
583287
|
+
const turnName = `turn-${String(turn).padStart(4, "0")}`;
|
|
583288
|
+
const latestTextPath = _pathJoin(treeDir, "latest.txt");
|
|
583289
|
+
const latestJsonPath = _pathJoin(treeDir, "latest.json");
|
|
583290
|
+
const turnTextPath = _pathJoin(treeDir, `${turnName}.txt`);
|
|
583291
|
+
const turnJsonPath = _pathJoin(treeDir, `${turnName}.json`);
|
|
583292
|
+
let artifactDisplay = latestTextPath;
|
|
583293
|
+
try {
|
|
583294
|
+
_fsMkdirSync(treeDir, { recursive: true });
|
|
583295
|
+
const header = [
|
|
583296
|
+
`WORKSPACE TREE SNAPSHOT`,
|
|
583297
|
+
`generated_at=${generatedAt}`,
|
|
583298
|
+
`turn=${turn}`,
|
|
583299
|
+
`session=${this._sessionId ?? ""}`,
|
|
583300
|
+
`root=${root}`,
|
|
583301
|
+
`files=${scan.files.length}${scan.truncated ? "+" : ""}`,
|
|
583302
|
+
`dirs=${scan.dirs.length}`,
|
|
583303
|
+
`bytes=${totalBytes}`,
|
|
583304
|
+
focusSnapshot?.directive?.requiredNextAction ? `supervisor_required_next_action=${focusSnapshot.directive.requiredNextAction}` : `supervisor_required_next_action=none`,
|
|
583305
|
+
recentActionLines.length ? `recent_actions=${recentActions.length}` : `recent_actions=0`,
|
|
583306
|
+
recentActionLines.length ? recentActionLines.join("\n") : "",
|
|
583307
|
+
""
|
|
583308
|
+
].join("\n");
|
|
583309
|
+
const text2 = `${header}${fullTree.text}
|
|
583310
|
+
`;
|
|
583311
|
+
const payload = {
|
|
583312
|
+
generatedAt,
|
|
583313
|
+
turn,
|
|
583314
|
+
sessionId: this._sessionId,
|
|
583315
|
+
root,
|
|
583316
|
+
supervisor: focusSnapshot ? {
|
|
583317
|
+
state: focusSnapshot.state,
|
|
583318
|
+
lastDecision: focusSnapshot.lastDecision,
|
|
583319
|
+
lastReason: focusSnapshot.lastReason,
|
|
583320
|
+
requiredNextAction: focusSnapshot.directive?.requiredNextAction ?? null,
|
|
583321
|
+
directiveReason: focusSnapshot.directive?.reason ?? null
|
|
583322
|
+
} : null,
|
|
583323
|
+
recentActions,
|
|
583324
|
+
stats: {
|
|
583325
|
+
files: scan.files.length,
|
|
583326
|
+
dirs: scan.dirs.length,
|
|
583327
|
+
totalBytes,
|
|
583328
|
+
truncated: scan.truncated || fullTree.truncated,
|
|
583329
|
+
dirsVisited: scan.dirsVisited
|
|
583330
|
+
},
|
|
583331
|
+
files: scan.files.map((file) => ({
|
|
583332
|
+
path: file.rel,
|
|
583333
|
+
bytes: file.bytes,
|
|
583334
|
+
mtimeMs: file.mtimeMs
|
|
583335
|
+
})),
|
|
583336
|
+
dirs: scan.dirs.map((dir) => ({
|
|
583337
|
+
path: dir.rel,
|
|
583338
|
+
mtimeMs: dir.mtimeMs
|
|
583339
|
+
}))
|
|
583340
|
+
};
|
|
583341
|
+
_fsWriteFileSync(latestTextPath, text2, "utf8");
|
|
583342
|
+
_fsWriteFileSync(turnTextPath, text2, "utf8");
|
|
583343
|
+
_fsWriteFileSync(latestJsonPath, JSON.stringify(payload, null, 2), "utf8");
|
|
583344
|
+
_fsWriteFileSync(turnJsonPath, JSON.stringify(payload, null, 2), "utf8");
|
|
583345
|
+
const rel = _pathRelative(root, latestTextPath).replace(/\\/g, "/");
|
|
583346
|
+
if (rel && !rel.startsWith(".."))
|
|
583347
|
+
artifactDisplay = rel;
|
|
583348
|
+
} catch {
|
|
583349
|
+
artifactDisplay = "(workspace tree artifact write failed; inline digest still current)";
|
|
583350
|
+
}
|
|
583351
|
+
return [
|
|
583352
|
+
"[WORKSPACE TREE — fresh per-turn disk crawl]",
|
|
583353
|
+
`generated_at=${generatedAt}`,
|
|
583354
|
+
`root=${root}`,
|
|
583355
|
+
`files=${scan.files.length}${scan.truncated ? "+" : ""} dirs=${scan.dirs.length} total_bytes=${totalBytes}`,
|
|
583356
|
+
`artifact=${artifactDisplay}`,
|
|
583357
|
+
focusSnapshot?.directive?.requiredNextAction ? `supervisor_required_next_action=${focusSnapshot.directive.requiredNextAction}` : `supervisor_required_next_action=none`,
|
|
583358
|
+
recentActionLines.length ? `recent_actions:
|
|
583359
|
+
${recentActionLines.join("\n")}` : "recent_actions=none",
|
|
583360
|
+
"Use this tree for path orientation. It includes empty directories; it does not include file contents.",
|
|
583361
|
+
compactTree.truncated || scan.truncated ? "Inline tree is truncated; read the artifact path above for the fuller capped tree before broad rediscovery." : "Inline tree is complete within the configured scan cap.",
|
|
583362
|
+
compactTree.text
|
|
583363
|
+
].join("\n");
|
|
583364
|
+
} catch (error) {
|
|
583365
|
+
return [
|
|
583366
|
+
"[WORKSPACE TREE — fresh per-turn disk crawl]",
|
|
583367
|
+
`root=${root}`,
|
|
583368
|
+
`scan_failed=${error instanceof Error ? error.message : String(error)}`,
|
|
583369
|
+
"Do not assume the tree is current; use list_directory/find_files if path orientation is required."
|
|
583370
|
+
].join("\n");
|
|
583371
|
+
}
|
|
583372
|
+
}
|
|
583131
583373
|
/**
|
|
583132
583374
|
* REG-2: Render a compact "files known to me" block from `_worldFacts`.
|
|
583133
583375
|
* Goal: tell the model what it has already touched this run so it stops
|
|
@@ -583667,6 +583909,7 @@ ${chunk.content}`, {
|
|
|
583667
583909
|
this._renderRuntimeRootBlock(),
|
|
583668
583910
|
this._taskState.goal ? `Active task: (see user message above — the goal block defers to the user message as the authoritative source)` : null
|
|
583669
583911
|
].filter(Boolean).join("\n\n");
|
|
583912
|
+
const workspaceTreeBlock = this._renderWorkspaceTreeBlock(turn);
|
|
583670
583913
|
const filesystemBlock = this._renderFilesystemStateBlock(turn);
|
|
583671
583914
|
const artifactContractBlock = this._contractRegistry.format(15);
|
|
583672
583915
|
const todoBlock = this._renderTodoStateBlock(turn);
|
|
@@ -583711,6 +583954,13 @@ ${this._lastPprMemoryLines.slice(0, 5).join("\n")}` : null;
|
|
|
583711
583954
|
createdTurn: turn,
|
|
583712
583955
|
ttlTurns: 1
|
|
583713
583956
|
}),
|
|
583957
|
+
signalFromBlock("known_files", "turn.workspace-tree", workspaceTreeBlock, {
|
|
583958
|
+
id: "workspace-tree",
|
|
583959
|
+
dedupeKey: "turn.workspace-tree",
|
|
583960
|
+
priority: 84,
|
|
583961
|
+
createdTurn: turn,
|
|
583962
|
+
ttlTurns: 1
|
|
583963
|
+
}),
|
|
583714
583964
|
signalFromBlock("known_files", "turn.artifact-contracts", artifactContractBlock, {
|
|
583715
583965
|
id: "artifact-contracts",
|
|
583716
583966
|
dedupeKey: "turn.artifact-contracts",
|
|
@@ -583799,7 +584049,7 @@ ${this._lastPprMemoryLines.slice(0, 5).join("\n")}` : null;
|
|
|
583799
584049
|
// Raised from 10k to fit the durable read-evidence content (known_files)
|
|
583800
584050
|
// that replaces the re-read loop; the per-kind budget below caps it.
|
|
583801
584051
|
maxChars: 13e3,
|
|
583802
|
-
kindCharBudget: { known_files:
|
|
584052
|
+
kindCharBudget: { known_files: 8500 },
|
|
583803
584053
|
includeDiagnostics: process.env["OMNIUS_CONTEXT_FABRIC_DIAGNOSTICS"] === "1"
|
|
583804
584054
|
});
|
|
583805
584055
|
this._lastContextFrameDiagnostics = frame.diagnostics;
|
|
@@ -584003,10 +584253,12 @@ ${blob}
|
|
|
584003
584253
|
if (p2 && content.length >= 100) {
|
|
584004
584254
|
try {
|
|
584005
584255
|
this._evidenceLedger.recordRead({
|
|
584006
|
-
path: p2,
|
|
584256
|
+
path: this._normalizeEvidencePath(p2),
|
|
584007
584257
|
content,
|
|
584258
|
+
contentHash: this._extractFileReadSha256(content) ?? void 0,
|
|
584008
584259
|
range: { start: 0, end: Number.POSITIVE_INFINITY },
|
|
584009
584260
|
fileVersion: this._worldFacts.files.get(p2)?.writeCount ?? 0,
|
|
584261
|
+
mtimeMs: this._statMtimeMsForToolPath(p2),
|
|
584010
584262
|
turn: this._taskState?.toolCallCount ?? 0
|
|
584011
584263
|
});
|
|
584012
584264
|
} catch {
|
|
@@ -587905,6 +588157,18 @@ ${memoryLines.join("\n")}`
|
|
|
587905
588157
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
587906
588158
|
});
|
|
587907
588159
|
}
|
|
588160
|
+
for (const tc of msg.toolCalls) {
|
|
588161
|
+
const patched = this._attachFreshExpectedHashesToEditArgs(tc.name, tc.arguments ?? {});
|
|
588162
|
+
if (patched.patchedCount > 0) {
|
|
588163
|
+
tc.arguments = patched.args;
|
|
588164
|
+
this.emit({
|
|
588165
|
+
type: "status",
|
|
588166
|
+
content: `Edit freshness: attached expected_hash to ${patched.patchedCount} ${tc.name} edit target${patched.patchedCount === 1 ? "" : "s"} from fresh file_read evidence`,
|
|
588167
|
+
turn,
|
|
588168
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
588169
|
+
});
|
|
588170
|
+
}
|
|
588171
|
+
}
|
|
587908
588172
|
messages2.push({
|
|
587909
588173
|
role: "assistant",
|
|
587910
588174
|
content: msg.content || null,
|
|
@@ -588644,7 +588908,8 @@ Read the current file if needed, make a different concrete edit, or move to veri
|
|
|
588644
588908
|
const readArgs = tc.arguments;
|
|
588645
588909
|
const readPath2 = String(readArgs?.["path"] ?? readArgs?.["file"] ?? "");
|
|
588646
588910
|
if (readPath2) {
|
|
588647
|
-
const
|
|
588911
|
+
const evidencePath = this._normalizeEvidencePath(readPath2);
|
|
588912
|
+
const wasFresh = evidencePath && this._evidenceLedger.validateFreshness(evidencePath, this._absoluteToolPath(readPath2));
|
|
588648
588913
|
if (!wasFresh) {
|
|
588649
588914
|
recentToolResults.delete(toolFingerprint);
|
|
588650
588915
|
dedupHitCount.delete(toolFingerprint);
|
|
@@ -588774,13 +589039,13 @@ ${cachedResult}`,
|
|
|
588774
589039
|
error: this.unknownToolError(tc.name)
|
|
588775
589040
|
};
|
|
588776
589041
|
} else {
|
|
588777
|
-
let validationError =
|
|
588778
|
-
if (tool.inputSchema) {
|
|
589042
|
+
let validationError = this._validateFreshExpectedHashesForEdit(resolvedTool?.name ?? tc.name, tc.arguments ?? {});
|
|
589043
|
+
if (!validationError && tool.inputSchema) {
|
|
588779
589044
|
const parseResult = tool.inputSchema.safeParse(tc.arguments);
|
|
588780
589045
|
if (!parseResult.success) {
|
|
588781
589046
|
validationError = parseResult.error.issues.map((iss) => `${iss.path.join(".")}: ${iss.message}`).join("; ");
|
|
588782
589047
|
}
|
|
588783
|
-
} else if (tool.parameters && typeof tool.parameters === "object") {
|
|
589048
|
+
} else if (!validationError && tool.parameters && typeof tool.parameters === "object") {
|
|
588784
589049
|
const required = tool.parameters.required;
|
|
588785
589050
|
if (Array.isArray(required)) {
|
|
588786
589051
|
const missing = required.filter((field) => tc.arguments[field] === void 0 || tc.arguments[field] === null);
|
|
@@ -589021,7 +589286,7 @@ Respond with EXACTLY this structure before your next tool call:
|
|
|
589021
589286
|
lastWriteTurn: turn,
|
|
589022
589287
|
writeCount: nextWriteCount
|
|
589023
589288
|
});
|
|
589024
|
-
this._evidenceLedger.markMutated(p2, nextWriteCount, turn);
|
|
589289
|
+
this._evidenceLedger.markMutated(this._normalizeEvidencePath(p2), nextWriteCount, turn);
|
|
589025
589290
|
}
|
|
589026
589291
|
if (paths.length > 0) {
|
|
589027
589292
|
this._writesSinceLastTodoWrite += paths.length;
|
|
@@ -589065,11 +589330,12 @@ Respond with EXACTLY this structure before your next tool call:
|
|
|
589065
589330
|
const start3 = rOffset === void 0 && rLimit === void 0 ? 0 : Math.max(1, rOffset ?? 1);
|
|
589066
589331
|
const end = rOffset === void 0 && rLimit === void 0 ? Number.POSITIVE_INFINITY : rLimit !== void 0 ? Math.max(1, rOffset ?? 1) + Math.max(0, rLimit) - 1 : Number.POSITIVE_INFINITY;
|
|
589067
589332
|
this._evidenceLedger.recordRead({
|
|
589068
|
-
path: p2,
|
|
589333
|
+
path: this._normalizeEvidencePath(p2),
|
|
589069
589334
|
content: result.output,
|
|
589335
|
+
contentHash: typeof result.beforeHash === "string" ? result.beforeHash : void 0,
|
|
589070
589336
|
range: { start: start3, end },
|
|
589071
589337
|
fileVersion: this._worldFacts.files.get(p2)?.writeCount ?? 0,
|
|
589072
|
-
mtimeMs:
|
|
589338
|
+
mtimeMs: this._statMtimeMsForToolPath(p2),
|
|
589073
589339
|
turn
|
|
589074
589340
|
});
|
|
589075
589341
|
}
|
|
@@ -590290,6 +590556,7 @@ Evidence: ${evidencePreview}`.slice(0, 500);
|
|
|
590290
590556
|
focusSupervisor: focusAfterToolResult,
|
|
590291
590557
|
focusDecision: !focusDecision || focusDecision.kind === "pass" ? void 0 : {
|
|
590292
590558
|
kind: focusDecision.kind,
|
|
590559
|
+
success: focusDecision.kind === "block_tool_call" ? focusDecision.success : void 0,
|
|
590293
590560
|
state: focusDecision.directive.state,
|
|
590294
590561
|
reason: focusDecision.directive.reason,
|
|
590295
590562
|
requiredNextAction: focusDecision.directive.requiredNextAction
|
|
@@ -592764,13 +593031,14 @@ ${marker}` : marker);
|
|
|
592764
593031
|
const displayOutput = this.unwrapToolOutputForDisplay(output);
|
|
592765
593032
|
if (toolName === "file_read") {
|
|
592766
593033
|
const path13 = this.extractPrimaryToolPath(args);
|
|
592767
|
-
|
|
593034
|
+
const evidencePath = path13 ? this._normalizeEvidencePath(path13) : "";
|
|
593035
|
+
if (!evidencePath || !this._evidenceLedger.hasFresh(evidencePath))
|
|
592768
593036
|
return output;
|
|
592769
|
-
const entry = this._evidenceLedger.get(
|
|
593037
|
+
const entry = this._evidenceLedger.get(evidencePath);
|
|
592770
593038
|
return this.wrapToolOutputForModel(toolName, [
|
|
592771
593039
|
"[DISCOVERY COMPACTED - file_read evidence captured]",
|
|
592772
593040
|
`path=${path13}`,
|
|
592773
|
-
`captured=${this.countTextLines(displayOutput)} lines, ${displayOutput.length} chars${entry ? `, fidelity=${entry.fidelity}` : ""}`,
|
|
593041
|
+
`captured=${this.countTextLines(displayOutput)} lines, ${displayOutput.length} chars${entry ? `, fidelity=${entry.fidelity}${entry.contentHash ? `, sha256=${entry.contentHash}` : ""}` : ""}`,
|
|
592774
593042
|
'active_context="Evidence already gathered this run"',
|
|
592775
593043
|
"Use the active evidence frame. Re-read only if that frame marks this file STALE or you need a distinct range."
|
|
592776
593044
|
].join("\n"));
|
|
@@ -592916,6 +593184,175 @@ ${marker}` : marker);
|
|
|
592916
593184
|
return trimmed.replace(/\\/g, "/").replace(/^\.\/+/, "");
|
|
592917
593185
|
}
|
|
592918
593186
|
}
|
|
593187
|
+
_absoluteToolPath(path12) {
|
|
593188
|
+
return _pathResolve(this.authoritativeWorkingDirectory(), path12.trim() || ".");
|
|
593189
|
+
}
|
|
593190
|
+
_normalizeEvidencePath(path12) {
|
|
593191
|
+
const trimmed = path12.trim();
|
|
593192
|
+
if (!trimmed)
|
|
593193
|
+
return "";
|
|
593194
|
+
try {
|
|
593195
|
+
const root = this.authoritativeWorkingDirectory();
|
|
593196
|
+
const abs = _pathResolve(root, trimmed);
|
|
593197
|
+
const rel = _pathRelative(root, abs).replace(/\\/g, "/");
|
|
593198
|
+
if (rel && !rel.startsWith("..") && rel !== ".")
|
|
593199
|
+
return rel;
|
|
593200
|
+
if (rel === "")
|
|
593201
|
+
return ".";
|
|
593202
|
+
return abs.replace(/\\/g, "/");
|
|
593203
|
+
} catch {
|
|
593204
|
+
return trimmed.replace(/\\/g, "/").replace(/^\.\/+/, "");
|
|
593205
|
+
}
|
|
593206
|
+
}
|
|
593207
|
+
_statMtimeMsForToolPath(path12) {
|
|
593208
|
+
try {
|
|
593209
|
+
const st = _fsStatSync(this._absoluteToolPath(path12), {
|
|
593210
|
+
throwIfNoEntry: false
|
|
593211
|
+
});
|
|
593212
|
+
return st?.mtimeMs;
|
|
593213
|
+
} catch {
|
|
593214
|
+
return void 0;
|
|
593215
|
+
}
|
|
593216
|
+
}
|
|
593217
|
+
_normalizeExpectedHashValue(value2) {
|
|
593218
|
+
if (typeof value2 !== "string")
|
|
593219
|
+
return null;
|
|
593220
|
+
const raw = value2.trim();
|
|
593221
|
+
if (!raw)
|
|
593222
|
+
return null;
|
|
593223
|
+
const stripped = raw.replace(/^sha256[:=]/i, "").toLowerCase();
|
|
593224
|
+
return /^[a-f0-9]{64}$/.test(stripped) ? stripped : null;
|
|
593225
|
+
}
|
|
593226
|
+
_extractFileReadSha256(text2) {
|
|
593227
|
+
const match = text2.match(/\bsha256=([a-f0-9]{64})\b/i);
|
|
593228
|
+
return match ? match[1].toLowerCase() : null;
|
|
593229
|
+
}
|
|
593230
|
+
_rawExpectedHashValue(rec) {
|
|
593231
|
+
return rec["expected_hash"] ?? rec["expectedHash"] ?? rec["before_hash"] ?? rec["beforeHash"];
|
|
593232
|
+
}
|
|
593233
|
+
_freshReadHashForEditPath(path12) {
|
|
593234
|
+
const key = this._normalizeEvidencePath(path12);
|
|
593235
|
+
if (!key)
|
|
593236
|
+
return null;
|
|
593237
|
+
const entry = this._evidenceLedger.get(key);
|
|
593238
|
+
if (!entry || entry.stale || !entry.contentHash)
|
|
593239
|
+
return null;
|
|
593240
|
+
const statPath = this._absoluteToolPath(path12);
|
|
593241
|
+
if (!this._evidenceLedger.validateFreshness(key, statPath))
|
|
593242
|
+
return null;
|
|
593243
|
+
const fresh = this._evidenceLedger.get(key);
|
|
593244
|
+
if (!fresh || fresh.stale || !fresh.contentHash)
|
|
593245
|
+
return null;
|
|
593246
|
+
return {
|
|
593247
|
+
key,
|
|
593248
|
+
hash: fresh.contentHash,
|
|
593249
|
+
lastReadTurn: fresh.lastReadTurn
|
|
593250
|
+
};
|
|
593251
|
+
}
|
|
593252
|
+
_attachFreshExpectedHashesToEditArgs(toolName, args) {
|
|
593253
|
+
if (process.env["OMNIUS_ALLOW_UNVERIFIED_OLD_STRING_EDIT"] === "1") {
|
|
593254
|
+
return { args, patchedCount: 0 };
|
|
593255
|
+
}
|
|
593256
|
+
if (toolName === "file_edit") {
|
|
593257
|
+
if (this._normalizeExpectedHashValue(this._rawExpectedHashValue(args))) {
|
|
593258
|
+
return { args, patchedCount: 0 };
|
|
593259
|
+
}
|
|
593260
|
+
const path12 = this.extractPrimaryToolPath(args);
|
|
593261
|
+
const fresh = path12 ? this._freshReadHashForEditPath(path12) : null;
|
|
593262
|
+
if (!fresh)
|
|
593263
|
+
return { args, patchedCount: 0 };
|
|
593264
|
+
return { args: { ...args, expected_hash: fresh.hash }, patchedCount: 1 };
|
|
593265
|
+
}
|
|
593266
|
+
if (toolName !== "batch_edit" || !Array.isArray(args["edits"])) {
|
|
593267
|
+
return { args, patchedCount: 0 };
|
|
593268
|
+
}
|
|
593269
|
+
let patchedCount = 0;
|
|
593270
|
+
const edits = args["edits"].map((edit) => {
|
|
593271
|
+
if (!edit || typeof edit !== "object" || Array.isArray(edit))
|
|
593272
|
+
return edit;
|
|
593273
|
+
const rec = edit;
|
|
593274
|
+
if (this._normalizeExpectedHashValue(this._rawExpectedHashValue(rec))) {
|
|
593275
|
+
return rec;
|
|
593276
|
+
}
|
|
593277
|
+
const path12 = typeof rec["path"] === "string" ? rec["path"] : typeof rec["file"] === "string" ? rec["file"] : "";
|
|
593278
|
+
const fresh = path12 ? this._freshReadHashForEditPath(path12) : null;
|
|
593279
|
+
if (!fresh)
|
|
593280
|
+
return rec;
|
|
593281
|
+
patchedCount++;
|
|
593282
|
+
return { ...rec, expected_hash: fresh.hash };
|
|
593283
|
+
});
|
|
593284
|
+
return patchedCount > 0 ? { args: { ...args, edits }, patchedCount } : { args, patchedCount: 0 };
|
|
593285
|
+
}
|
|
593286
|
+
_validateFreshExpectedHashesForEdit(toolName, args) {
|
|
593287
|
+
if (process.env["OMNIUS_ALLOW_UNVERIFIED_OLD_STRING_EDIT"] === "1") {
|
|
593288
|
+
return null;
|
|
593289
|
+
}
|
|
593290
|
+
const targets = [];
|
|
593291
|
+
if (toolName === "file_edit") {
|
|
593292
|
+
const path12 = this.extractPrimaryToolPath(args);
|
|
593293
|
+
if (path12) {
|
|
593294
|
+
targets.push({
|
|
593295
|
+
label: path12,
|
|
593296
|
+
path: path12,
|
|
593297
|
+
expectedHash: this._normalizeExpectedHashValue(this._rawExpectedHashValue(args)),
|
|
593298
|
+
rawExpectedHash: this._rawExpectedHashValue(args)
|
|
593299
|
+
});
|
|
593300
|
+
}
|
|
593301
|
+
} else if (toolName === "batch_edit" && Array.isArray(args["edits"])) {
|
|
593302
|
+
args["edits"].forEach((edit, index) => {
|
|
593303
|
+
if (!edit || typeof edit !== "object" || Array.isArray(edit))
|
|
593304
|
+
return;
|
|
593305
|
+
const rec = edit;
|
|
593306
|
+
const path12 = typeof rec["path"] === "string" ? rec["path"] : typeof rec["file"] === "string" ? rec["file"] : "";
|
|
593307
|
+
if (!path12)
|
|
593308
|
+
return;
|
|
593309
|
+
targets.push({
|
|
593310
|
+
label: `edit #${index + 1} ${path12}`,
|
|
593311
|
+
path: path12,
|
|
593312
|
+
expectedHash: this._normalizeExpectedHashValue(this._rawExpectedHashValue(rec)),
|
|
593313
|
+
rawExpectedHash: this._rawExpectedHashValue(rec)
|
|
593314
|
+
});
|
|
593315
|
+
});
|
|
593316
|
+
} else {
|
|
593317
|
+
return null;
|
|
593318
|
+
}
|
|
593319
|
+
if (targets.length === 0)
|
|
593320
|
+
return null;
|
|
593321
|
+
const problems = [];
|
|
593322
|
+
for (const target of targets) {
|
|
593323
|
+
const fresh = this._freshReadHashForEditPath(target.path);
|
|
593324
|
+
if (target.rawExpectedHash !== void 0 && !target.expectedHash) {
|
|
593325
|
+
problems.push(`${target.label}: expected_hash is present but is not a valid 64-character SHA-256`);
|
|
593326
|
+
continue;
|
|
593327
|
+
}
|
|
593328
|
+
if (!fresh && target.expectedHash) {
|
|
593329
|
+
continue;
|
|
593330
|
+
}
|
|
593331
|
+
if (!fresh) {
|
|
593332
|
+
problems.push(`${target.label}: missing expected_hash and no fresh file_read hash is available for this file in the current run`);
|
|
593333
|
+
continue;
|
|
593334
|
+
}
|
|
593335
|
+
if (!target.expectedHash) {
|
|
593336
|
+
problems.push(`${target.label}: missing expected_hash; use sha256=${fresh.hash} from the fresh file_read evidence`);
|
|
593337
|
+
continue;
|
|
593338
|
+
}
|
|
593339
|
+
if (target.expectedHash !== fresh.hash) {
|
|
593340
|
+
problems.push(`${target.label}: expected_hash=${target.expectedHash} does not match fresh file_read sha256=${fresh.hash}`);
|
|
593341
|
+
}
|
|
593342
|
+
}
|
|
593343
|
+
if (problems.length === 0)
|
|
593344
|
+
return null;
|
|
593345
|
+
return [
|
|
593346
|
+
"[EDIT FRESHNESS CONTRACT]",
|
|
593347
|
+
"Exact replacement edits must be built from verified current file content, not remembered text.",
|
|
593348
|
+
"Before file_edit or batch_edit can run, each target must carry expected_hash from file_read. If the runner has fresh read evidence, it will attach that hash automatically; otherwise the edit tool verifies the provided hash against disk before mutating.",
|
|
593349
|
+
"For multiple edits to the same file, use one batch_edit against the same expected_hash so all replacements validate atomically before the file changes.",
|
|
593350
|
+
"",
|
|
593351
|
+
...problems.map((problem) => `- ${problem}`),
|
|
593352
|
+
"",
|
|
593353
|
+
"Next action: file_read the target file or range, then retry the edit with old_string copied exactly from that read and expected_hash set to the read's sha256."
|
|
593354
|
+
].join("\n");
|
|
593355
|
+
}
|
|
592919
593356
|
staleEditFamilyKey(toolName, pathKey, errorKind, targetHash, latestFileHash) {
|
|
592920
593357
|
return [
|
|
592921
593358
|
toolName,
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "omnius",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.458",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "omnius",
|
|
9
|
-
"version": "1.0.
|
|
9
|
+
"version": "1.0.458",
|
|
10
10
|
"bundleDependencies": [
|
|
11
11
|
"image-to-ascii"
|
|
12
12
|
],
|
|
@@ -4138,9 +4138,9 @@
|
|
|
4138
4138
|
}
|
|
4139
4139
|
},
|
|
4140
4140
|
"node_modules/iconv-lite": {
|
|
4141
|
-
"version": "0.7.
|
|
4142
|
-
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.
|
|
4143
|
-
"integrity": "sha512-
|
|
4141
|
+
"version": "0.7.3",
|
|
4142
|
+
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.3.tgz",
|
|
4143
|
+
"integrity": "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==",
|
|
4144
4144
|
"license": "MIT",
|
|
4145
4145
|
"dependencies": {
|
|
4146
4146
|
"safer-buffer": ">= 2.1.2 < 3.0.0"
|
package/package.json
CHANGED