@sema-agent/core 5.43.0 → 5.45.0
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/CHANGELOG.md +108 -6
- package/dist/agents/subagent.d.ts +3 -1
- package/dist/brain/reasoning.d.ts +50 -4
- package/dist/brain/reasoning.js +28 -7
- package/dist/brain/request-params.d.ts +0 -12
- package/dist/brain/request-params.js +1 -1
- package/dist/core/governance-codes.js +3 -0
- package/dist/core/memory-engine/content-origin.d.ts +6 -3
- package/dist/core/memory-engine/delegation-provenance.d.ts +12 -7
- package/dist/core/memory-engine/engine.d.ts +94 -2
- package/dist/core/memory-engine/engine.js +46 -4
- package/dist/core/memory-engine/layout.d.ts +11 -4
- package/dist/core/memory-engine/layout.js +3 -3
- package/dist/core/memory-engine/tools.d.ts +12 -0
- package/dist/core/memory-engine/tools.js +30 -11
- package/dist/core/runner/assemble-result.d.ts +5 -0
- package/dist/core/runner/assemble-result.js +1 -1
- package/dist/core/runner/prepare-config-doors.d.ts +6 -0
- package/dist/core/runner/prepare-config-doors.js +17 -0
- package/dist/core/runner/prepare-memory.js +24 -3
- package/dist/core/runner/prepare-task.d.ts +3 -1
- package/dist/core/runner/prepare-task.js +25 -3
- package/dist/core/runner/runtask.js +20 -17
- package/dist/core/trace.d.ts +17 -2
- package/dist/core/types.d.ts +100 -1
- package/dist/tools/fs/fs-search-tools.d.ts +4 -3
- package/dist/tools/fs/search.d.ts +43 -7
- package/dist/tools/fs/search.js +75 -31
- package/package.json +3 -2
package/dist/tools/fs/search.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { delimitUntrusted } from "../../core/untrusted-text.js";
|
|
2
2
|
import { MAX_EXEC_OUTPUT_BYTES } from "../../core/exec-output-tail.js";
|
|
3
|
-
import { hasBinaryExtension, isAbsolutePathForm } from "./safety.js";
|
|
3
|
+
import { hasBinaryExtension, isAbsolutePathForm, isWinFormPath } from "./safety.js";
|
|
4
4
|
const WALK_MAX_FILES = 5000;
|
|
5
5
|
const WALK_MAX_DEPTH = 32;
|
|
6
6
|
const GREP_DEFAULT_CAP = 250;
|
|
@@ -35,6 +35,25 @@ const TYPE_GLOBS = {
|
|
|
35
35
|
css: "*.{css,scss,less}",
|
|
36
36
|
};
|
|
37
37
|
const basename = (p) => p.slice(Math.max(p.lastIndexOf("/"), p.lastIndexOf("\\")) + 1);
|
|
38
|
+
function collapseDotSegments(p) {
|
|
39
|
+
const win = isWinFormPath(p);
|
|
40
|
+
const lead = (win ? /^[\\/]*/ : /^\/*/).exec(p)?.[0] ?? "";
|
|
41
|
+
const sep = win ? "\\" : "/";
|
|
42
|
+
const parts = p.slice(lead.length).split(win ? /[\\/]+/ : /\/+/);
|
|
43
|
+
const floor = !win ? 0 : lead.length >= 2 ? 2 : /^[A-Za-z]:$/.test(parts[0] ?? "") ? 1 : 0;
|
|
44
|
+
const kept = [];
|
|
45
|
+
for (const part of parts) {
|
|
46
|
+
if (part === "" || part === ".")
|
|
47
|
+
continue;
|
|
48
|
+
if (part === "..") {
|
|
49
|
+
if (kept.length > floor)
|
|
50
|
+
kept.pop();
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
kept.push(part);
|
|
54
|
+
}
|
|
55
|
+
return kept.length === 0 ? "" : lead + kept.join(sep);
|
|
56
|
+
}
|
|
38
57
|
const NO_MATCHES = "No matches.";
|
|
39
58
|
const GREP_LINE_CLIP = 500;
|
|
40
59
|
function clipLine(line) {
|
|
@@ -759,10 +778,10 @@ function multilineSpans(content, p, captureText = false, deadline = Infinity) {
|
|
|
759
778
|
}
|
|
760
779
|
return spans;
|
|
761
780
|
}
|
|
762
|
-
export async function
|
|
781
|
+
export async function jsGrepDetailed(env, root, p, signal, guards, deny, denyOut) {
|
|
763
782
|
const analysis = analyzeRedos(p.pattern, p.ignore_case === true);
|
|
764
783
|
if (analysis.risk)
|
|
765
|
-
return redosRejection(analysis.risk);
|
|
784
|
+
return { text: redosRejection(analysis.risk) };
|
|
766
785
|
const budgetMs = guards?.budgetMs ?? GREP_FILE_BUDGET_MS;
|
|
767
786
|
const longLineLimit = guards?.longLineLimit ?? GREP_GRAY_LINE_MAX;
|
|
768
787
|
const grayPattern = analysis.quantifiedGroup || analysis.unboundedCount >= 2;
|
|
@@ -776,7 +795,7 @@ export async function jsGrep(env, root, p, signal, guards, deny, denyOut) {
|
|
|
776
795
|
test = compilePattern(p);
|
|
777
796
|
}
|
|
778
797
|
catch (e) {
|
|
779
|
-
return `Error (grep): invalid regex: ${e instanceof Error ? e.message : String(e)}
|
|
798
|
+
return { text: `Error (grep): invalid regex: ${e instanceof Error ? e.message : String(e)}` };
|
|
780
799
|
}
|
|
781
800
|
const ignore = await buildIgnore(env, root, signal);
|
|
782
801
|
const rootPrefix = root.replace(/[\\/]+$/, "") + (root.includes("\\") ? "\\" : "/");
|
|
@@ -816,9 +835,20 @@ export async function jsGrep(env, root, p, signal, guards, deny, denyOut) {
|
|
|
816
835
|
const cap = p.head_limit === 0 ? Infinity : Math.max(1, Math.floor(p.head_limit ?? GREP_DEFAULT_CAP));
|
|
817
836
|
const mode = p.output_mode ?? "files_with_matches";
|
|
818
837
|
const rel = (abs) => (abs.startsWith(rootPrefix) ? abs.slice(rootPrefix.length) : abs);
|
|
838
|
+
const startWin = isWinFormPath(start);
|
|
839
|
+
const startNorm = collapseDotSegments(start);
|
|
840
|
+
const targetSpell = p.path ? p.path.replace(startWin ? /[\\/]+$/ : /\/+$/, "") : "";
|
|
841
|
+
const isBoundary = (c) => c === "/" || (startWin && c === "\\");
|
|
819
842
|
const relOut = (abs) => {
|
|
820
|
-
|
|
821
|
-
|
|
843
|
+
if (!p.path) {
|
|
844
|
+
const r = rel(abs);
|
|
845
|
+
return r === abs ? r : `./${r}`;
|
|
846
|
+
}
|
|
847
|
+
if (abs === startNorm || abs === start)
|
|
848
|
+
return targetSpell;
|
|
849
|
+
if (abs.startsWith(startNorm) && isBoundary(abs[startNorm.length]))
|
|
850
|
+
return targetSpell + abs.slice(startNorm.length);
|
|
851
|
+
return rel(abs);
|
|
822
852
|
};
|
|
823
853
|
if (p.glob) {
|
|
824
854
|
const globRes = splitGlobParam(p.glob).map((g) => globTokenToRegExp(normalizeGlobToken(g), globIsAnchored(g), true));
|
|
@@ -846,7 +876,7 @@ export async function jsGrep(env, root, p, signal, guards, deny, denyOut) {
|
|
|
846
876
|
let outBytes = 0;
|
|
847
877
|
let outputTruncated = false;
|
|
848
878
|
let rowsBeforeWindow = 0;
|
|
849
|
-
const pushRow = (row) => {
|
|
879
|
+
const pushRow = (row, path) => {
|
|
850
880
|
if (outputTruncated)
|
|
851
881
|
return;
|
|
852
882
|
if (rowsBeforeWindow < off) {
|
|
@@ -861,7 +891,7 @@ export async function jsGrep(env, root, p, signal, guards, deny, denyOut) {
|
|
|
861
891
|
return;
|
|
862
892
|
}
|
|
863
893
|
outBytes += size;
|
|
864
|
-
out.push(row);
|
|
894
|
+
out.push({ path, text: row });
|
|
865
895
|
};
|
|
866
896
|
const fileMatches = [];
|
|
867
897
|
const counts = [];
|
|
@@ -889,6 +919,7 @@ export async function jsGrep(env, root, p, signal, guards, deny, denyOut) {
|
|
|
889
919
|
const lines = read.value.split("\n");
|
|
890
920
|
if (lines.length > 1 && lines.at(-1) === "")
|
|
891
921
|
lines.pop();
|
|
922
|
+
const shownPath = relOut(f);
|
|
892
923
|
let fileCount = 0;
|
|
893
924
|
const fileMatchStart = monotonicNow();
|
|
894
925
|
if (p.multiline) {
|
|
@@ -902,8 +933,8 @@ export async function jsGrep(env, root, p, signal, guards, deny, denyOut) {
|
|
|
902
933
|
}
|
|
903
934
|
catch (e) {
|
|
904
935
|
if (e instanceof GrepBudgetExceeded)
|
|
905
|
-
return budgetError(
|
|
906
|
-
return `Error (grep): invalid regex: ${e instanceof Error ? e.message : String(e)}
|
|
936
|
+
return { text: budgetError(shownPath, monotonicNow() - fileMatchStart) };
|
|
937
|
+
return { text: `Error (grep): invalid regex: ${e instanceof Error ? e.message : String(e)}` };
|
|
907
938
|
}
|
|
908
939
|
fileCount = spans.length;
|
|
909
940
|
if (mode === "content") {
|
|
@@ -911,12 +942,12 @@ export async function jsGrep(env, root, p, signal, guards, deny, denyOut) {
|
|
|
911
942
|
if (p.only_matching && text !== undefined) {
|
|
912
943
|
const parts = text.split("\n");
|
|
913
944
|
for (let k = 0; k < parts.length; k++) {
|
|
914
|
-
pushRow(`${
|
|
945
|
+
pushRow(`${shownPath}:${s + k}:${clipLine(parts[k])}`, shownPath);
|
|
915
946
|
}
|
|
916
947
|
continue;
|
|
917
948
|
}
|
|
918
949
|
for (let j = Math.max(0, s - 1 - ctxB); j <= Math.min(lines.length - 1, eL - 1 + ctxA); j++) {
|
|
919
|
-
pushRow(`${
|
|
950
|
+
pushRow(`${shownPath}:${j + 1}:${clipLine(lines[j])}`, shownPath);
|
|
920
951
|
}
|
|
921
952
|
}
|
|
922
953
|
}
|
|
@@ -926,7 +957,7 @@ export async function jsGrep(env, root, p, signal, guards, deny, denyOut) {
|
|
|
926
957
|
if (grayPattern || (i > 0 && i % GREP_LINE_CHECK_EVERY === 0)) {
|
|
927
958
|
const elapsed = monotonicNow() - fileMatchStart;
|
|
928
959
|
if (elapsed >= budgetMs)
|
|
929
|
-
return budgetError(
|
|
960
|
+
return { text: budgetError(shownPath, elapsed) };
|
|
930
961
|
}
|
|
931
962
|
if (i > 0 && i % GREP_LINE_CHECK_EVERY === 0) {
|
|
932
963
|
await yieldEventLoop();
|
|
@@ -945,16 +976,16 @@ export async function jsGrep(env, root, p, signal, guards, deny, denyOut) {
|
|
|
945
976
|
if (mode === "content") {
|
|
946
977
|
if (p.only_matching) {
|
|
947
978
|
for (const part of matchedParts(lines[i], p)) {
|
|
948
|
-
pushRow(`${
|
|
979
|
+
pushRow(`${shownPath}:${i + 1}:${clipLine(part)}`, shownPath);
|
|
949
980
|
}
|
|
950
981
|
}
|
|
951
982
|
else if (ctx > 0) {
|
|
952
983
|
for (let j = Math.max(0, i - ctxB); j <= Math.min(lines.length - 1, i + ctxA); j++) {
|
|
953
|
-
pushRow(`${
|
|
984
|
+
pushRow(`${shownPath}:${j + 1}:${clipLine(lines[j])}`, shownPath);
|
|
954
985
|
}
|
|
955
986
|
}
|
|
956
987
|
else {
|
|
957
|
-
pushRow(`${
|
|
988
|
+
pushRow(`${shownPath}:${i + 1}:${clipLine(lines[i])}`, shownPath);
|
|
958
989
|
}
|
|
959
990
|
}
|
|
960
991
|
}
|
|
@@ -968,7 +999,7 @@ export async function jsGrep(env, root, p, signal, guards, deny, denyOut) {
|
|
|
968
999
|
if (mode === "files_with_matches")
|
|
969
1000
|
fileMatches.push(f);
|
|
970
1001
|
else if (mode === "count" && counts.length < collectCap)
|
|
971
|
-
counts.push(`${
|
|
1002
|
+
counts.push({ path: shownPath, text: `${shownPath}:${fileCount}` });
|
|
972
1003
|
}
|
|
973
1004
|
}
|
|
974
1005
|
if (scanAborted || skippedUnreadableFiles > 0 || skippedLongLines > 0 || multilineSkippedFiles > 0) {
|
|
@@ -988,7 +1019,7 @@ export async function jsGrep(env, root, p, signal, guards, deny, denyOut) {
|
|
|
988
1019
|
}
|
|
989
1020
|
}
|
|
990
1021
|
const caveat = honestyCaveat + denyNote;
|
|
991
|
-
const paged = (arr) => (off > 0 ? arr.slice(off, off + cap) : arr);
|
|
1022
|
+
const paged = (arr) => (off > 0 ? arr.slice(off, off + cap) : [...arr]);
|
|
992
1023
|
const offNote = off > 0 ? `\n[offset ${off}]` : "";
|
|
993
1024
|
if (mode === "files_with_matches") {
|
|
994
1025
|
const haveMtimes = fileMatches.length > 0 && fileMatches.every((f) => walked.mtimes.has(f));
|
|
@@ -999,26 +1030,37 @@ export async function jsGrep(env, root, p, signal, guards, deny, denyOut) {
|
|
|
999
1030
|
.map((x) => x.r)
|
|
1000
1031
|
: fileMatches.map(relOut).sort();
|
|
1001
1032
|
const body = sortedFileMatches.slice(off, off + cap);
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
: body.
|
|
1033
|
+
const rows = body.map((r) => ({ path: r, text: r }));
|
|
1034
|
+
return {
|
|
1035
|
+
text: body.length === 0
|
|
1036
|
+
? NO_MATCHES + offNote + typeNote + caveat
|
|
1037
|
+
: body.join("\n") + (totalFiles > off + cap ? `\n…[capped at ${cap} of ${totalFiles}]` : "") + offNote + typeNote + caveat,
|
|
1038
|
+
rows,
|
|
1039
|
+
};
|
|
1005
1040
|
}
|
|
1006
1041
|
if (mode === "count") {
|
|
1007
1042
|
const body = paged(counts);
|
|
1008
|
-
return
|
|
1009
|
-
|
|
1010
|
-
|
|
1043
|
+
return {
|
|
1044
|
+
text: body.length === 0
|
|
1045
|
+
? NO_MATCHES + offNote + typeNote + caveat
|
|
1046
|
+
: body.map((r) => r.text).join("\n") + (totalFiles > off + cap ? `\n…[capped at ${cap} of ${totalFiles}]` : "") + offNote + typeNote + caveat,
|
|
1047
|
+
rows: body,
|
|
1048
|
+
};
|
|
1011
1049
|
}
|
|
1012
1050
|
const body = out;
|
|
1013
1051
|
const byteNote = outputTruncated ? `\n…[output truncated at ${outputMaxBytes} bytes — narrow the pattern or set a smaller head_limit]` : "";
|
|
1014
1052
|
if (body.length === 0)
|
|
1015
|
-
return NO_MATCHES + byteNote + offNote + typeNote + caveat;
|
|
1053
|
+
return { text: NO_MATCHES + byteNote + offNote + typeNote + caveat, rows: [] };
|
|
1054
|
+
const bodyText = body.map((r) => r.text).join("\n");
|
|
1016
1055
|
if (out.length < cap)
|
|
1017
|
-
return
|
|
1056
|
+
return { text: bodyText + byteNote + offNote + typeNote + caveat, rows: body };
|
|
1018
1057
|
const marker = ctx > 0 || p.multiline || p.only_matching
|
|
1019
1058
|
? `\n…[capped at ${cap}; ${totalContent}+ match(es) found, more output omitted]`
|
|
1020
1059
|
: `\n…[capped at ${cap} of ${totalContent}]`;
|
|
1021
|
-
return
|
|
1060
|
+
return { text: bodyText + marker + byteNote + offNote + typeNote + caveat, rows: body };
|
|
1061
|
+
}
|
|
1062
|
+
export async function jsGrep(env, root, p, signal, guards, deny, denyOut) {
|
|
1063
|
+
return (await jsGrepDetailed(env, root, p, signal, guards, deny, denyOut)).text;
|
|
1022
1064
|
}
|
|
1023
1065
|
const rgCache = new WeakMap();
|
|
1024
1066
|
export function detectRipgrep(env) {
|
|
@@ -1124,23 +1166,25 @@ export function rgOutputDenyTripwire(stdout, mode, judge, opts = {}) {
|
|
|
1124
1166
|
}
|
|
1125
1167
|
async function jsGrepDenyTripFallback(env, root, p, signal, trip, deny) {
|
|
1126
1168
|
const denyOut = {};
|
|
1127
|
-
const text = await
|
|
1169
|
+
const { text, rows } = await jsGrepDetailed(env, root, p, signal, undefined, deny, denyOut);
|
|
1128
1170
|
const why = trip.reason === "deny-hit" ? "its output involved sensitive-path deny-listed entries the exclusion globs cannot express" : "its output contained a record the line format cannot account for";
|
|
1129
1171
|
return {
|
|
1130
1172
|
text: text.startsWith("Error (grep)")
|
|
1131
1173
|
? text
|
|
1132
1174
|
: `${text}\n[note: the ripgrep pass was abandoned (${why}); results are from the fallback scanner, which prunes with the authoritative deny judge]`,
|
|
1175
|
+
...(rows !== undefined ? { rows } : {}),
|
|
1133
1176
|
degraded: { fallback: "js-scan", reason: `ripgrep output tripped the deny tripwire (${trip.reason})` },
|
|
1134
1177
|
...(denyOut.withheld !== undefined ? { withheld: denyOut.withheld } : {}),
|
|
1135
1178
|
};
|
|
1136
1179
|
}
|
|
1137
1180
|
async function jsGrepFallback(env, root, p, signal, reason, deny) {
|
|
1138
1181
|
const denyOut = {};
|
|
1139
|
-
const text = await
|
|
1182
|
+
const { text, rows } = await jsGrepDetailed(env, root, p, signal, undefined, deny, denyOut);
|
|
1140
1183
|
return {
|
|
1141
1184
|
text: text.startsWith("Error (grep)")
|
|
1142
1185
|
? text
|
|
1143
1186
|
: `${text}\n[note: ripgrep failed (${reason}); results are from a fallback scanner]`,
|
|
1187
|
+
...(rows !== undefined ? { rows } : {}),
|
|
1144
1188
|
degraded: { fallback: "js-scan", reason: `ripgrep failed (${reason})` },
|
|
1145
1189
|
...(denyOut.withheld !== undefined ? { withheld: denyOut.withheld } : {}),
|
|
1146
1190
|
};
|
|
@@ -1288,8 +1332,8 @@ export async function runGrepDetailed(env, root, p, signal, deny) {
|
|
|
1288
1332
|
if (await detectRipgrep(env))
|
|
1289
1333
|
return rgGrepDetailed(env, root, p, signal, deny);
|
|
1290
1334
|
const denyOut = {};
|
|
1291
|
-
const text = await
|
|
1292
|
-
return { text, ...(denyOut.withheld !== undefined ? { withheld: denyOut.withheld } : {}) };
|
|
1335
|
+
const { text, rows } = await jsGrepDetailed(env, root, p, signal, undefined, deny, denyOut);
|
|
1336
|
+
return { text, ...(rows !== undefined ? { rows } : {}), ...(denyOut.withheld !== undefined ? { withheld: denyOut.withheld } : {}) };
|
|
1293
1337
|
}
|
|
1294
1338
|
export async function runGrep(env, root, p, signal) {
|
|
1295
1339
|
return (await runGrepDetailed(env, root, p, signal)).text;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sema-agent/core",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.45.0",
|
|
4
4
|
"description": "Stateless, task-oriented AI agent core",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "BUSL-1.1",
|
|
@@ -65,7 +65,8 @@
|
|
|
65
65
|
"gate:single-mint": "node scripts/verify-single-mint.mjs",
|
|
66
66
|
"gate:nuia": "node scripts/verify-nuia-baseline.mjs",
|
|
67
67
|
"gate:field-liveness": "node scripts/verify-field-liveness.mjs",
|
|
68
|
-
"gate:error-surface": "node scripts/verify-error-surface.mjs"
|
|
68
|
+
"gate:error-surface": "node scripts/verify-error-surface.mjs",
|
|
69
|
+
"gate:criteria": "node scripts/criteria-lint.mjs"
|
|
69
70
|
},
|
|
70
71
|
"dependencies": {
|
|
71
72
|
"@modelcontextprotocol/sdk": "1.30.0",
|