omnius 1.0.174 → 1.0.175
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
CHANGED
|
@@ -5738,6 +5738,108 @@ var init_change_log = __esm({
|
|
|
5738
5738
|
}
|
|
5739
5739
|
});
|
|
5740
5740
|
|
|
5741
|
+
// packages/execution/dist/tools/text-encoding.js
|
|
5742
|
+
import { TextDecoder as TextDecoder2 } from "node:util";
|
|
5743
|
+
function decodeTextArgument(args, options2) {
|
|
5744
|
+
const direct = firstString(args, options2.textKeys);
|
|
5745
|
+
const b64 = firstString(args, options2.base64Keys);
|
|
5746
|
+
const encodingRaw = firstString(args, options2.encodingKeys ?? ["content_encoding", "encoding"]);
|
|
5747
|
+
const encoding = encodingRaw?.value.trim().toLowerCase().replace(/_/g, "-");
|
|
5748
|
+
if (b64) {
|
|
5749
|
+
return decodeBase64Text(b64.value, b64.key);
|
|
5750
|
+
}
|
|
5751
|
+
if (encoding === "base64") {
|
|
5752
|
+
if (!direct) {
|
|
5753
|
+
return {
|
|
5754
|
+
ok: false,
|
|
5755
|
+
reason: "missing",
|
|
5756
|
+
error: `${options2.fieldLabel} is required when content_encoding="base64". ` + options2.example
|
|
5757
|
+
};
|
|
5758
|
+
}
|
|
5759
|
+
return decodeBase64Text(direct.value, direct.key);
|
|
5760
|
+
}
|
|
5761
|
+
if (encoding && encoding !== "utf-8" && encoding !== "utf8" && encoding !== "text") {
|
|
5762
|
+
return {
|
|
5763
|
+
ok: false,
|
|
5764
|
+
reason: "invalid",
|
|
5765
|
+
error: `Unsupported ${options2.fieldLabel} encoding "${encodingRaw?.value}". Use plain UTF-8 text or base64-encoded UTF-8 text.`
|
|
5766
|
+
};
|
|
5767
|
+
}
|
|
5768
|
+
if (direct) {
|
|
5769
|
+
return { ok: true, value: direct.value, source: direct.key, encoded: false };
|
|
5770
|
+
}
|
|
5771
|
+
return {
|
|
5772
|
+
ok: false,
|
|
5773
|
+
reason: "missing",
|
|
5774
|
+
error: `${options2.fieldLabel} is required. ${options2.example}`
|
|
5775
|
+
};
|
|
5776
|
+
}
|
|
5777
|
+
function firstString(args, keys) {
|
|
5778
|
+
for (const key of keys) {
|
|
5779
|
+
if (typeof args[key] === "string") {
|
|
5780
|
+
return { key, value: args[key] };
|
|
5781
|
+
}
|
|
5782
|
+
}
|
|
5783
|
+
return null;
|
|
5784
|
+
}
|
|
5785
|
+
function decodeBase64Text(raw, source) {
|
|
5786
|
+
const compact3 = raw.replace(/\s+/g, "").replace(/-/g, "+").replace(/_/g, "/");
|
|
5787
|
+
if (compact3.length > 0 && /[^A-Za-z0-9+/=]/.test(compact3)) {
|
|
5788
|
+
return {
|
|
5789
|
+
ok: false,
|
|
5790
|
+
reason: "invalid",
|
|
5791
|
+
error: `${source} is not valid base64: contains characters outside the base64 alphabet.`
|
|
5792
|
+
};
|
|
5793
|
+
}
|
|
5794
|
+
if (compact3.length % 4 === 1) {
|
|
5795
|
+
return {
|
|
5796
|
+
ok: false,
|
|
5797
|
+
reason: "invalid",
|
|
5798
|
+
error: `${source} is not valid base64: invalid length.`
|
|
5799
|
+
};
|
|
5800
|
+
}
|
|
5801
|
+
const padded = compact3.padEnd(Math.ceil(compact3.length / 4) * 4, "=");
|
|
5802
|
+
let bytes;
|
|
5803
|
+
try {
|
|
5804
|
+
bytes = Buffer.from(padded, "base64");
|
|
5805
|
+
} catch (err) {
|
|
5806
|
+
return {
|
|
5807
|
+
ok: false,
|
|
5808
|
+
reason: "invalid",
|
|
5809
|
+
error: `${source} could not be decoded as base64: ${err instanceof Error ? err.message : String(err)}`
|
|
5810
|
+
};
|
|
5811
|
+
}
|
|
5812
|
+
const canonical = bytes.toString("base64").replace(/=+$/g, "");
|
|
5813
|
+
if (compact3.replace(/=+$/g, "") !== canonical) {
|
|
5814
|
+
return {
|
|
5815
|
+
ok: false,
|
|
5816
|
+
reason: "invalid",
|
|
5817
|
+
error: `${source} is not canonical base64 for the bytes it decodes to.`
|
|
5818
|
+
};
|
|
5819
|
+
}
|
|
5820
|
+
try {
|
|
5821
|
+
return {
|
|
5822
|
+
ok: true,
|
|
5823
|
+
value: UTF8_DECODER.decode(bytes),
|
|
5824
|
+
source,
|
|
5825
|
+
encoded: true
|
|
5826
|
+
};
|
|
5827
|
+
} catch {
|
|
5828
|
+
return {
|
|
5829
|
+
ok: false,
|
|
5830
|
+
reason: "invalid",
|
|
5831
|
+
error: `${source} decoded successfully but is not valid UTF-8 text. file_write/file_edit/file_patch are text tools.`
|
|
5832
|
+
};
|
|
5833
|
+
}
|
|
5834
|
+
}
|
|
5835
|
+
var UTF8_DECODER;
|
|
5836
|
+
var init_text_encoding = __esm({
|
|
5837
|
+
"packages/execution/dist/tools/text-encoding.js"() {
|
|
5838
|
+
"use strict";
|
|
5839
|
+
UTF8_DECODER = new TextDecoder2("utf-8", { fatal: true });
|
|
5840
|
+
}
|
|
5841
|
+
});
|
|
5842
|
+
|
|
5741
5843
|
// packages/execution/dist/tools/file-write.js
|
|
5742
5844
|
import { writeFile, mkdir, readFile as readFile2 } from "node:fs/promises";
|
|
5743
5845
|
import { existsSync as existsSync9 } from "node:fs";
|
|
@@ -5756,14 +5858,27 @@ var init_file_write = __esm({
|
|
|
5756
5858
|
"use strict";
|
|
5757
5859
|
init_change_log();
|
|
5758
5860
|
init_edit_metadata();
|
|
5861
|
+
init_text_encoding();
|
|
5759
5862
|
FileWriteTool = class {
|
|
5760
5863
|
name = "file_write";
|
|
5761
|
-
description = "Write
|
|
5864
|
+
description = "Write UTF-8 text to a file, creating directories as needed. For content with heavy quoting, raw JSON, control characters, or large full-file payloads, pass content_base64 instead of shell heredocs/cat/tee.";
|
|
5762
5865
|
parameters = {
|
|
5763
5866
|
type: "object",
|
|
5764
5867
|
properties: {
|
|
5765
5868
|
path: { type: "string", description: "Absolute or relative file path" },
|
|
5766
|
-
content: {
|
|
5869
|
+
content: {
|
|
5870
|
+
type: "string",
|
|
5871
|
+
description: "UTF-8 text content to write. Use content_base64 when JSON escaping is fragile."
|
|
5872
|
+
},
|
|
5873
|
+
content_base64: {
|
|
5874
|
+
type: "string",
|
|
5875
|
+
description: "Base64-encoded UTF-8 text content. Preferred for full-file writes with quotes, backticks, raw JSON, or control characters."
|
|
5876
|
+
},
|
|
5877
|
+
content_encoding: {
|
|
5878
|
+
type: "string",
|
|
5879
|
+
enum: ["utf-8", "base64"],
|
|
5880
|
+
description: "Set to base64 when passing base64 text in the content field. Not needed when using content_base64."
|
|
5881
|
+
},
|
|
5767
5882
|
overwrite: {
|
|
5768
5883
|
type: "boolean",
|
|
5769
5884
|
description: "Required when overwriting an existing file with different content."
|
|
@@ -5773,7 +5888,11 @@ var init_file_write = __esm({
|
|
|
5773
5888
|
description: "SHA-256 hash from the most recent file_read. Required with overwrite=true for existing files."
|
|
5774
5889
|
}
|
|
5775
5890
|
},
|
|
5776
|
-
required: ["path",
|
|
5891
|
+
required: ["path"],
|
|
5892
|
+
anyOf: [
|
|
5893
|
+
{ required: ["content"] },
|
|
5894
|
+
{ required: ["content_base64"] }
|
|
5895
|
+
]
|
|
5777
5896
|
};
|
|
5778
5897
|
workingDir;
|
|
5779
5898
|
constructor(workingDir) {
|
|
@@ -5781,7 +5900,13 @@ var init_file_write = __esm({
|
|
|
5781
5900
|
}
|
|
5782
5901
|
async execute(args) {
|
|
5783
5902
|
const filePath = extractWritePath(args);
|
|
5784
|
-
const
|
|
5903
|
+
const decodedContent = decodeTextArgument(args, {
|
|
5904
|
+
fieldLabel: "file_write content",
|
|
5905
|
+
textKeys: ["content", "text", "data"],
|
|
5906
|
+
base64Keys: ["content_base64", "contentBase64", "base64_content", "base64Content"],
|
|
5907
|
+
encodingKeys: ["content_encoding", "contentEncoding", "encoding"],
|
|
5908
|
+
example: `Call: file_write({"path": "${filePath ?? "src/file.ts"}", "content": "..."}) or file_write({"path": "${filePath ?? "src/file.ts"}", "content_base64": "<base64 utf-8>"})`
|
|
5909
|
+
});
|
|
5785
5910
|
const overwrite = args["overwrite"] === true || args["overwriteExisting"] === true;
|
|
5786
5911
|
const expectedHash = extractExpectedHash(args);
|
|
5787
5912
|
const start2 = performance.now();
|
|
@@ -5793,14 +5918,15 @@ var init_file_write = __esm({
|
|
|
5793
5918
|
durationMs: performance.now() - start2
|
|
5794
5919
|
};
|
|
5795
5920
|
}
|
|
5796
|
-
if (
|
|
5921
|
+
if (!decodedContent.ok) {
|
|
5797
5922
|
return {
|
|
5798
5923
|
success: false,
|
|
5799
5924
|
output: "",
|
|
5800
|
-
error:
|
|
5925
|
+
error: `${decodedContent.error} Do not fall back to shell cat/tee/heredoc for project file writes; retry file_write with content_base64 when quoting or JSON encoding is the problem.`,
|
|
5801
5926
|
durationMs: performance.now() - start2
|
|
5802
5927
|
};
|
|
5803
5928
|
}
|
|
5929
|
+
const content = decodedContent.value;
|
|
5804
5930
|
try {
|
|
5805
5931
|
const fullPath = resolve3(this.workingDir, filePath);
|
|
5806
5932
|
const isNew = !existsSync9(fullPath);
|
|
@@ -8539,6 +8665,7 @@ var init_file_edit = __esm({
|
|
|
8539
8665
|
init_change_log();
|
|
8540
8666
|
init_edit_snippet_finder();
|
|
8541
8667
|
init_edit_metadata();
|
|
8668
|
+
init_text_encoding();
|
|
8542
8669
|
FileEditTool = class {
|
|
8543
8670
|
name = "file_edit";
|
|
8544
8671
|
description = "Make a precise edit to a file by replacing an exact string match. The old_string must be unique in the file unless replace_all is true. Use replace_all to rename variables or change repeated patterns throughout the file.";
|
|
@@ -8548,11 +8675,24 @@ var init_file_edit = __esm({
|
|
|
8548
8675
|
path: { type: "string", description: "Absolute or relative file path" },
|
|
8549
8676
|
old_string: {
|
|
8550
8677
|
type: "string",
|
|
8551
|
-
description: "The exact string to search for and replace. Must be unique in the file (or use replace_all)."
|
|
8678
|
+
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."
|
|
8679
|
+
},
|
|
8680
|
+
old_string_base64: {
|
|
8681
|
+
type: "string",
|
|
8682
|
+
description: "Base64-encoded UTF-8 old_string. Use when exact current text contains quotes, raw JSON, or control characters."
|
|
8552
8683
|
},
|
|
8553
8684
|
new_string: {
|
|
8554
8685
|
type: "string",
|
|
8555
|
-
description: "The replacement string"
|
|
8686
|
+
description: "The replacement string. Use new_string_base64 when JSON escaping is fragile."
|
|
8687
|
+
},
|
|
8688
|
+
new_string_base64: {
|
|
8689
|
+
type: "string",
|
|
8690
|
+
description: "Base64-encoded UTF-8 replacement string."
|
|
8691
|
+
},
|
|
8692
|
+
string_encoding: {
|
|
8693
|
+
type: "string",
|
|
8694
|
+
enum: ["utf-8", "base64"],
|
|
8695
|
+
description: "Set to base64 only when both old_string and new_string are base64. Prefer old_string_base64/new_string_base64 for mixed cases."
|
|
8556
8696
|
},
|
|
8557
8697
|
replace_all: {
|
|
8558
8698
|
type: "boolean",
|
|
@@ -8563,7 +8703,11 @@ var init_file_edit = __esm({
|
|
|
8563
8703
|
description: "Optional SHA-256 from the most recent file_read. If provided, edit is refused when the file changed."
|
|
8564
8704
|
}
|
|
8565
8705
|
},
|
|
8566
|
-
required: ["path",
|
|
8706
|
+
required: ["path"],
|
|
8707
|
+
allOf: [
|
|
8708
|
+
{ anyOf: [{ required: ["old_string"] }, { required: ["old_string_base64"] }] },
|
|
8709
|
+
{ anyOf: [{ required: ["new_string"] }, { required: ["new_string_base64"] }] }
|
|
8710
|
+
]
|
|
8567
8711
|
};
|
|
8568
8712
|
workingDir;
|
|
8569
8713
|
constructor(workingDir) {
|
|
@@ -8571,8 +8715,20 @@ var init_file_edit = __esm({
|
|
|
8571
8715
|
}
|
|
8572
8716
|
async execute(args) {
|
|
8573
8717
|
const filePath = extractEditPath(args);
|
|
8574
|
-
const
|
|
8575
|
-
|
|
8718
|
+
const oldDecoded = decodeTextArgument(args, {
|
|
8719
|
+
fieldLabel: "file_edit old_string",
|
|
8720
|
+
textKeys: ["old_string", "oldString", "search", "find"],
|
|
8721
|
+
base64Keys: ["old_string_base64", "oldStringBase64", "search_base64", "searchBase64"],
|
|
8722
|
+
encodingKeys: ["old_string_encoding", "oldStringEncoding", "string_encoding", "stringEncoding"],
|
|
8723
|
+
example: `Call: file_edit({"path": "${filePath ?? "src/file.ts"}", "old_string": "...", "new_string": "..."}) or pass old_string_base64 for exact UTF-8 text that is hard to JSON-escape.`
|
|
8724
|
+
});
|
|
8725
|
+
const newDecoded = decodeTextArgument(args, {
|
|
8726
|
+
fieldLabel: "file_edit new_string",
|
|
8727
|
+
textKeys: ["new_string", "newString", "replace", "replacement"],
|
|
8728
|
+
base64Keys: ["new_string_base64", "newStringBase64", "replacement_base64", "replacementBase64"],
|
|
8729
|
+
encodingKeys: ["new_string_encoding", "newStringEncoding", "string_encoding", "stringEncoding"],
|
|
8730
|
+
example: `Call: file_edit({"path": "${filePath ?? "src/file.ts"}", "old_string": "...", "new_string": "..."}) or pass new_string_base64 for replacement text that is hard to JSON-escape.`
|
|
8731
|
+
});
|
|
8576
8732
|
const replaceAll = args["replace_all"] === true || args["replaceAll"] === true;
|
|
8577
8733
|
const expectedHash = extractExpectedHash(args);
|
|
8578
8734
|
const start2 = performance.now();
|
|
@@ -8584,22 +8740,24 @@ var init_file_edit = __esm({
|
|
|
8584
8740
|
durationMs: performance.now() - start2
|
|
8585
8741
|
};
|
|
8586
8742
|
}
|
|
8587
|
-
if (!
|
|
8743
|
+
if (!oldDecoded.ok || oldDecoded.value.length === 0) {
|
|
8588
8744
|
return {
|
|
8589
8745
|
success: false,
|
|
8590
8746
|
output: "",
|
|
8591
|
-
error:
|
|
8747
|
+
error: `${oldDecoded.ok ? "file_edit old_string must be non-empty." : oldDecoded.error} Do not switch to shell sed/perl/python file rewrites for this; retry file_edit with old_string_base64 if exact text encoding is the problem.`,
|
|
8592
8748
|
durationMs: performance.now() - start2
|
|
8593
8749
|
};
|
|
8594
8750
|
}
|
|
8595
|
-
if (
|
|
8751
|
+
if (!newDecoded.ok) {
|
|
8596
8752
|
return {
|
|
8597
8753
|
success: false,
|
|
8598
8754
|
output: "",
|
|
8599
|
-
error:
|
|
8755
|
+
error: `${newDecoded.error} Do not switch to shell sed/perl/python file rewrites for this; retry file_edit with new_string_base64 if exact text encoding is the problem.`,
|
|
8600
8756
|
durationMs: performance.now() - start2
|
|
8601
8757
|
};
|
|
8602
8758
|
}
|
|
8759
|
+
const oldString = oldDecoded.value;
|
|
8760
|
+
const newString = newDecoded.value;
|
|
8603
8761
|
try {
|
|
8604
8762
|
const fullPath = resolve7(this.workingDir, filePath);
|
|
8605
8763
|
const content = await readFile3(fullPath, "utf-8");
|
|
@@ -10757,6 +10915,7 @@ var init_file_patch = __esm({
|
|
|
10757
10915
|
"use strict";
|
|
10758
10916
|
init_change_log();
|
|
10759
10917
|
init_edit_metadata();
|
|
10918
|
+
init_text_encoding();
|
|
10760
10919
|
FilePatchTool = class {
|
|
10761
10920
|
name = "file_patch";
|
|
10762
10921
|
description = "Edit specific line ranges in a file. More precise than string matching for large files. Modes: 'replace' replaces lines start_line..end_line with new_content, 'insert_before' inserts before start_line, 'insert_after' inserts after start_line, 'delete' removes lines start_line..end_line. Use dry_run to preview changes.";
|
|
@@ -10777,7 +10936,16 @@ var init_file_patch = __esm({
|
|
|
10777
10936
|
},
|
|
10778
10937
|
new_content: {
|
|
10779
10938
|
type: "string",
|
|
10780
|
-
description: "Replacement content (for replace mode) or content to insert (for insert modes). Required for replace and insert modes. Not needed for delete mode."
|
|
10939
|
+
description: "Replacement content (for replace mode) or content to insert (for insert modes). Required for replace and insert modes. Not needed for delete mode. Use new_content_base64 when JSON escaping is fragile."
|
|
10940
|
+
},
|
|
10941
|
+
new_content_base64: {
|
|
10942
|
+
type: "string",
|
|
10943
|
+
description: "Base64-encoded UTF-8 replacement/insert content. Use for content with quotes, raw JSON, or control characters."
|
|
10944
|
+
},
|
|
10945
|
+
new_content_encoding: {
|
|
10946
|
+
type: "string",
|
|
10947
|
+
enum: ["utf-8", "base64"],
|
|
10948
|
+
description: "Set to base64 when passing base64 text in new_content. Not needed when using new_content_base64."
|
|
10781
10949
|
},
|
|
10782
10950
|
expected_hash: {
|
|
10783
10951
|
type: "string",
|
|
@@ -10813,13 +10981,28 @@ var init_file_patch = __esm({
|
|
|
10813
10981
|
const endLine = args["end_line"] ?? startLine;
|
|
10814
10982
|
const mode = args["mode"] ?? "replace";
|
|
10815
10983
|
const dryRun = args["dry_run"] === true;
|
|
10816
|
-
const
|
|
10817
|
-
|
|
10984
|
+
const decodedNewContent = decodeTextArgument(args, {
|
|
10985
|
+
fieldLabel: "file_patch new_content",
|
|
10986
|
+
textKeys: ["new_content", "newContent"],
|
|
10987
|
+
base64Keys: ["new_content_base64", "newContentBase64"],
|
|
10988
|
+
encodingKeys: ["new_content_encoding", "newContentEncoding", "content_encoding", "contentEncoding", "encoding"],
|
|
10989
|
+
example: `Call: file_patch({"path": "${filePath ?? "src/file.ts"}", "start_line": 1, "end_line": 1, "new_content": "..."}) or pass "new_content_base64": "<base64 utf-8>".`
|
|
10990
|
+
});
|
|
10991
|
+
const hasNewContent = decodedNewContent.ok;
|
|
10992
|
+
const newContent = decodedNewContent.ok ? decodedNewContent.value : "";
|
|
10818
10993
|
const expectedHash = extractExpectedHash(args);
|
|
10819
10994
|
const expectedOldContent = typeof args["expected_old_content"] === "string" ? args["expected_old_content"] : void 0;
|
|
10820
10995
|
const allowEmptyContent = args["allow_empty_content"] === true;
|
|
10821
10996
|
const start2 = performance.now();
|
|
10822
10997
|
try {
|
|
10998
|
+
if (!decodedNewContent.ok && decodedNewContent.reason === "invalid") {
|
|
10999
|
+
return {
|
|
11000
|
+
success: false,
|
|
11001
|
+
output: "",
|
|
11002
|
+
error: `${decodedNewContent.error} Do not use shell heredocs to patch project files; retry file_patch with new_content_base64 or use expected_old_content with exact text.`,
|
|
11003
|
+
durationMs: performance.now() - start2
|
|
11004
|
+
};
|
|
11005
|
+
}
|
|
10823
11006
|
if (!Number.isInteger(startLine) || startLine < 1) {
|
|
10824
11007
|
return {
|
|
10825
11008
|
success: false,
|
|
@@ -548287,6 +548470,39 @@ function repairJson(raw) {
|
|
|
548287
548470
|
}
|
|
548288
548471
|
return found ? result : null;
|
|
548289
548472
|
}
|
|
548473
|
+
function malformedToolArgsMessage(toolName, raw) {
|
|
548474
|
+
const rawStr = String(raw).slice(0, 240);
|
|
548475
|
+
const base3 = `Your ${toolName} tool call had malformed JSON arguments and did not reach the tool implementation. Raw argument preview: "${rawStr}".`;
|
|
548476
|
+
if (toolName === "file_write") {
|
|
548477
|
+
return [
|
|
548478
|
+
base3,
|
|
548479
|
+
`This is usually tool-call JSON encoding, not a filesystem write failure: raw newlines, unescaped quotes, backticks, or control characters broke the arguments before file_write could run.`,
|
|
548480
|
+
`Retry file_write with valid JSON. For full-file content that is hard to escape, pass base64-encoded UTF-8 text as content_base64 instead of content.`,
|
|
548481
|
+
`Do NOT pivot to shell cat/tee/heredoc/python just to write project files; that bypasses file_write overwrite/hash checks, mutation tracking, and diagnostics.`,
|
|
548482
|
+
`Example shape: file_write({"path":"src/file.ts","content_base64":"<base64 utf-8>","overwrite":true,"expected_hash":"<sha256 from file_read if overwriting>"})`
|
|
548483
|
+
].join(" ");
|
|
548484
|
+
}
|
|
548485
|
+
if (toolName === "file_edit") {
|
|
548486
|
+
return [
|
|
548487
|
+
base3,
|
|
548488
|
+
`This is usually JSON encoding of old_string/new_string, not an edit failure on disk.`,
|
|
548489
|
+
`Retry file_edit with old_string_base64 and/or new_string_base64 for exact UTF-8 text that is hard to JSON-escape.`,
|
|
548490
|
+
`Do NOT pivot to shell sed/perl/python rewrites just to edit project files; keep edits tracked through file_edit/file_patch/file_write.`
|
|
548491
|
+
].join(" ");
|
|
548492
|
+
}
|
|
548493
|
+
if (toolName === "file_patch") {
|
|
548494
|
+
return [
|
|
548495
|
+
base3,
|
|
548496
|
+
`This is usually JSON encoding of new_content, not a patch failure on disk.`,
|
|
548497
|
+
`Retry file_patch with new_content_base64 for replacement/insert text that is hard to JSON-escape, or use expected_old_content copied exactly from file_read.`,
|
|
548498
|
+
`Do NOT pivot to shell heredocs just to patch project files; keep edits tracked through file_patch/file_edit/file_write.`
|
|
548499
|
+
].join(" ");
|
|
548500
|
+
}
|
|
548501
|
+
return `${base3} Please call ${toolName} again with valid JSON arguments: double-quoted keys and string values, escaped newlines/quotes, no trailing commas, and no comments.`;
|
|
548502
|
+
}
|
|
548503
|
+
function looksLikeShellFileWrite(command) {
|
|
548504
|
+
return /\bcat\s+[^|;&\n]*>\s*[^&|;\n]+/.test(command) || /\b(?:tee|dd)\b[\s\S]*(?:\bof=|>\s*[^&|;\n]+)/.test(command) || /\b(?:echo|printf)\b[\s\S]*>\s*[^&|;\n]+/.test(command) || /\bpython(?:3)?\b[\s\S]*(?:write_text|open\([^)]*["']w["'])/.test(command) || /<<\s*['"]?\w+['"]?[\s\S]*>\s*[^&|;\n]+/.test(command);
|
|
548505
|
+
}
|
|
548290
548506
|
function normalizeProviderToolMessage(msg, model) {
|
|
548291
548507
|
const rawContent2 = typeof msg.content === "string" ? msg.content : "";
|
|
548292
548508
|
const profile = resolveModelProfile(model);
|
|
@@ -553344,7 +553560,7 @@ If this matches your current shape, try it before continuing.`
|
|
|
553344
553560
|
``,
|
|
553345
553561
|
`Pick ONE of these for your next response:`,
|
|
553346
553562
|
``,
|
|
553347
|
-
` (a) PRODUCE: emit a file_write / file_edit / file_patch
|
|
553563
|
+
` (a) PRODUCE: emit a file_write / file_edit / file_patch that creates or changes project content. Even a partial draft of the next planned file is progress. Use shell only for commands/tests/system operations, not as a workaround for failed edit-tool encoding.`,
|
|
553348
553564
|
``,
|
|
553349
553565
|
` (b) ERROR-INFORMED LOCAL TRIAGE: anchor on the freshest local failure, identify the implicated file/path/symbol/command, then make one targeted local move instead of broad exploration.`,
|
|
553350
553566
|
``,
|
|
@@ -555050,11 +555266,10 @@ ${header}${truncatedCache}`
|
|
|
555050
555266
|
const tool = resolvedTool?.tool;
|
|
555051
555267
|
let result;
|
|
555052
555268
|
if (tc.arguments && "_raw" in tc.arguments) {
|
|
555053
|
-
const rawStr = String(tc.arguments._raw).slice(0, 200);
|
|
555054
555269
|
result = {
|
|
555055
555270
|
success: false,
|
|
555056
555271
|
output: "",
|
|
555057
|
-
error:
|
|
555272
|
+
error: malformedToolArgsMessage(tc.name, tc.arguments._raw)
|
|
555058
555273
|
};
|
|
555059
555274
|
} else if (!tool) {
|
|
555060
555275
|
result = {
|
|
@@ -556795,6 +557010,18 @@ Your most recent tool calls SUCCEEDED. If the task is complete, call task_comple
|
|
|
556795
557010
|
if (codeBlockMatch && codeBlockMatch[1]?.trim()) {
|
|
556796
557011
|
const shellCommands = codeBlockMatch[1].trim().split("\n").filter((l2) => l2.trim() && !l2.trim().startsWith("#")).join(" && ");
|
|
556797
557012
|
if (shellCommands.length > 0 && shellCommands.length < 2e3) {
|
|
557013
|
+
if (looksLikeShellFileWrite(shellCommands)) {
|
|
557014
|
+
messages2.push({
|
|
557015
|
+
role: "user",
|
|
557016
|
+
content: `You wrote a shell code block that appears to create or overwrite files. I did NOT auto-execute it because shell redirection bypasses file_write/file_edit/file_patch tracking and version checks. Use file_write/content_base64 for full-file writes, file_edit for exact replacements, or file_patch/new_content_base64 for line-range patches.`
|
|
557017
|
+
});
|
|
557018
|
+
this.emit({
|
|
557019
|
+
type: "status",
|
|
557020
|
+
content: `Blocked auto-execution of file-writing shell code block; steering back to edit tools`,
|
|
557021
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
557022
|
+
});
|
|
557023
|
+
continue;
|
|
557024
|
+
}
|
|
556798
557025
|
const shellTool = this.tools.get("shell");
|
|
556799
557026
|
if (shellTool) {
|
|
556800
557027
|
this.emit({
|
|
@@ -594668,16 +594895,16 @@ var require_source = __commonJS({
|
|
|
594668
594895
|
};
|
|
594669
594896
|
var template;
|
|
594670
594897
|
var chalkTag = (chalk2, ...strings) => {
|
|
594671
|
-
const [
|
|
594672
|
-
if (!isArray(
|
|
594898
|
+
const [firstString2] = strings;
|
|
594899
|
+
if (!isArray(firstString2) || !isArray(firstString2.raw)) {
|
|
594673
594900
|
return strings.join(" ");
|
|
594674
594901
|
}
|
|
594675
594902
|
const arguments_ = strings.slice(1);
|
|
594676
|
-
const parts = [
|
|
594677
|
-
for (let i2 = 1; i2 <
|
|
594903
|
+
const parts = [firstString2.raw[0]];
|
|
594904
|
+
for (let i2 = 1; i2 < firstString2.length; i2++) {
|
|
594678
594905
|
parts.push(
|
|
594679
594906
|
String(arguments_[i2 - 1]).replace(/[{}\\]/g, "\\$&"),
|
|
594680
|
-
String(
|
|
594907
|
+
String(firstString2.raw[i2])
|
|
594681
594908
|
);
|
|
594682
594909
|
}
|
|
594683
594910
|
if (template === void 0) {
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "omnius",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.175",
|
|
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.175",
|
|
10
10
|
"bundleDependencies": [
|
|
11
11
|
"image-to-ascii"
|
|
12
12
|
],
|
package/package.json
CHANGED
|
@@ -41,9 +41,9 @@ If you anticipate a large result before calling a tool, prefer narrow flags firs
|
|
|
41
41
|
## Available Tools
|
|
42
42
|
|
|
43
43
|
- file_read: Read file contents (always read before editing). Supports path, offset, limit.
|
|
44
|
-
- file_write: Create or overwrite a file with complete content
|
|
45
|
-
- file_edit: Make a precise string replacement in a file (preferred over rewriting). Uses old_string/new_string. old_string must be unique unless replace_all=true. Use
|
|
46
|
-
- file_patch: Edit specific line ranges in large files. Modes: replace (swap lines), insert_before, insert_after, delete. Use dry_run to preview. Best for large files (500+ lines) where string matching is fragile.
|
|
44
|
+
- file_write: Create or overwrite a file with complete UTF-8 text. If full-file content is hard to JSON-escape, use content_base64 instead of shell cat/tee/heredoc.
|
|
45
|
+
- file_edit: Make a precise string replacement in a file (preferred over rewriting). Uses old_string/new_string. old_string must be unique unless replace_all=true. Use old_string_base64/new_string_base64 if exact text is hard to JSON-escape.
|
|
46
|
+
- file_patch: Edit specific line ranges in large files. Modes: replace (swap lines), insert_before, insert_after, delete. Use dry_run to preview. Use new_content_base64 if replacement text is hard to JSON-escape. Best for large files (500+ lines) where string matching is fragile.
|
|
47
47
|
- find_files: Find files by name pattern (glob). Searches recursively, excludes node_modules/.git.
|
|
48
48
|
- grep_search: Search file contents with regex. Returns matching lines with paths and line numbers.
|
|
49
49
|
- shell: Execute any shell command (tests, builds, git, npm, etc.). Supports stdin parameter for input. Commands run with CI=true for non-interactive mode.
|
|
@@ -73,6 +73,12 @@ Order: web_search (find) → web_fetch (read) → web_crawl (if JS/multi-page)
|
|
|
73
73
|
- debate: Multi-agent debate on a hard sub-decision. Spawns N parallel reasoners that propose, critique each other, and converge on a consensus. Use AFTER you've tried 3-4 different approaches and they have all failed.
|
|
74
74
|
- replay_with_intervention: DoVer-style replay of a turn-boundary checkpoint with a corrective directive. When you suspect a specific past turn is where you went wrong, replay it under an alternative directive and compare. Run op="list_checkpoints" first to see what's available.
|
|
75
75
|
|
|
76
|
+
## File Editing Discipline
|
|
77
|
+
|
|
78
|
+
- Shell is for commands, builds, tests, and system operations. Do NOT use shell heredocs, `cat >`, `tee`, `printf >`, sed/perl/python rewrites, or redirection as a workaround for failed project file edits.
|
|
79
|
+
- If file_write/file_edit/file_patch reports malformed JSON or encoding trouble, the tool call did not reach the filesystem. Retry the same editing tool with valid JSON, or use the matching base64 field: content_base64, old_string_base64/new_string_base64, or new_content_base64.
|
|
80
|
+
- For existing files, read first and preserve version checks: file_edit/file_patch for targeted changes; file_write with overwrite=true and expected_hash only for intentional full rewrites.
|
|
81
|
+
|
|
76
82
|
## Parallel Execution & Sub-Agents
|
|
77
83
|
|
|
78
84
|
- background_run: Run a shell command in the background. Returns a task ID immediately.
|
|
@@ -28,9 +28,9 @@ Tool results over ~100KB are NOT truncated. The orchestrator saves the full payl
|
|
|
28
28
|
## Tools
|
|
29
29
|
|
|
30
30
|
- file_read: Read file contents (always read before editing)
|
|
31
|
-
- file_write: Create or overwrite a file
|
|
32
|
-
- file_edit: Precise string replacement (preferred over rewriting). old_string must be unique.
|
|
33
|
-
- file_patch: Edit specific line ranges in large files
|
|
31
|
+
- file_write: Create or overwrite a file with complete UTF-8 text. Use content_base64 when full-file content is hard to JSON-escape.
|
|
32
|
+
- file_edit: Precise string replacement (preferred over rewriting). old_string must be unique. Use old_string_base64/new_string_base64 when exact text is hard to JSON-escape.
|
|
33
|
+
- file_patch: Edit specific line ranges in large files. Use new_content_base64 when replacement text is hard to JSON-escape.
|
|
34
34
|
- find_files: Find files by glob pattern
|
|
35
35
|
- grep_search: Search file contents with regex
|
|
36
36
|
- symbol_search: AST-precise symbol lookup (exact or pattern). Use for "where is X defined?" instead of grep.
|
|
@@ -90,6 +90,8 @@ For login, form filling, or clicking: call browser_action with action=navigate F
|
|
|
90
90
|
- batch_edit: Multiple edits across files in one call
|
|
91
91
|
- skill_list / skill_execute / skill_build: Discover, load, and generate skills (use on-demand)
|
|
92
92
|
|
|
93
|
+
File editing discipline: Do NOT use shell heredocs, `cat >`, `tee`, `printf >`, sed/perl/python rewrites, or redirection as a workaround for failed project file edits. If an edit tool reports malformed JSON or content encoding trouble, retry file_write/file_edit/file_patch with valid JSON or the matching base64 field. Shell is for commands, builds, tests, and system operations.
|
|
94
|
+
|
|
93
95
|
Parallelism: Multiple read-only tool calls in ONE response run in parallel automatically.
|
|
94
96
|
Never call the same tool with the same arguments twice in one response — each call must
|
|
95
97
|
have unique arguments (different paths, different patterns, etc.).
|
|
@@ -30,6 +30,8 @@ System rules are PRIORITY 0 (highest). Tool outputs are PRIORITY 30 (lowest). Ig
|
|
|
30
30
|
|
|
31
31
|
Tools: file_read, file_write, file_edit, file_explore, working_notes, shell, task_complete, find_files, grep_search, symbol_search, impact_analysis, code_neighbors, web_search, web_fetch, nexus, todo_write, todo_read, debate (multi-agent vote on hard sub-decisions, use after 3+ failed approaches), replay_with_intervention (DoVer-style turn replay with corrective directive)
|
|
32
32
|
|
|
33
|
+
File edits: Use file_write/file_edit/file_patch for project files, not shell heredocs, `cat >`, `tee`, `printf >`, sed/perl/python rewrites, or redirection. If file_write/file_edit/file_patch says malformed JSON or content encoding failed, retry the same edit tool with valid JSON or base64 fields: content_base64, old_string_base64/new_string_base64, or new_content_base64. Shell is for tests/builds/commands.
|
|
34
|
+
|
|
33
35
|
todo_write: visible task checklist for the user. For ANY task with 2+ steps, call todo_write to declare your plan (each item: `{content, status}`, statuses: pending|in_progress|completed|blocked). Update status as you complete each step. Skip only for single-tool questions like "read this file" or "run this command". Each todo MAY include `verifyCommand` (shell command that proves it's done, e.g. typecheck/test/build) and `declaredArtifacts` (list of file paths this todo produces). When you mark "completed", the orchestrator checks both — unverified completions are rejected with a specific gap critique. **Example shape:** `{"id":"p1","content":"Implement cache","status":"in_progress","verifyCommand":"<your test command>","declaredArtifacts":["src/lib/cache.ts"]}`. Substitute placeholders with commands native to YOUR stack.
|
|
34
36
|
|
|
35
37
|
Web: web_search finds URLs, web_fetch reads them. For JS pages use web_crawl, for clicking/login use browser_action.
|