@moda-ai/cli 1.55.54 → 1.55.56
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/{agent-rmmtap23.js → agent-j0syymez.js} +10 -10
- package/dist/{cli-3dj84cbk.js → cli-2jwxdhh5.js} +1 -1
- package/dist/{cli-1ehmy9rh.js → cli-31ybq5f2.js} +2 -2
- package/dist/{cli-4vc2cksg.js → cli-7epk27vq.js} +5 -5
- package/dist/{cli-rdh9jjr2.js → cli-94r5x9bg.js} +1 -1
- package/dist/{cli-c1k20j6e.js → cli-9a4b1wxz.js} +1 -1
- package/dist/{cli-4pzbgxcn.js → cli-9g8kp42c.js} +2 -2
- package/dist/{cli-mf37dxpc.js → cli-b918vs2m.js} +4 -4
- package/dist/{cli-wry78bg8.js → cli-hawwf30b.js} +1 -1
- package/dist/{cli-c1vmgdjb.js → cli-jrf8annc.js} +8 -8
- package/dist/{cli-dxxc7tzq.js → cli-m25c0rke.js} +3 -3
- package/dist/{cli-7ye5004e.js → cli-p7856v3b.js} +541 -449
- package/dist/{cli-40fqk078.js → cli-pnarsb96.js} +1 -1
- package/dist/{cli-6hdqp65a.js → cli-rtkjjf0a.js} +1255 -66
- package/dist/{cli-gtke9wrw.js → cli-v2h21cgf.js} +1 -1
- package/dist/{cli-vswckv9g.js → cli-y5d33a1y.js} +1 -1
- package/dist/cli.js +20 -20
- package/dist/{doctor-b34em2fm.js → doctor-q8khayre.js} +8 -8
- package/dist/{harness-jcqwf5h6.js → harness-2vkcwm85.js} +8 -8
- package/dist/{harness-github-actions-rayyxh1w.js → harness-github-actions-yev2yrkr.js} +8 -8
- package/dist/{harness-report-rjcjbh93.js → harness-report-gz5d3y48.js} +1 -1
- package/dist/{index-cqnp8pfv.js → index-k6xec97f.js} +14 -14
- package/dist/{production-intelligence-zek0rkzj.js → production-intelligence-fqvhzq6s.js} +4 -4
- package/dist/{profile-commands-nbaec4y9.js → profile-commands-yvpe4d8y.js} +5 -5
- package/dist/{prompt-attribution-gyx0g661.js → prompt-attribution-2h9vertk.js} +8 -8
- package/dist/prompt-source-mcp.js +8 -8
- package/dist/{prompt-sources-qw2p4t5h.js → prompt-sources-1hycgx6r.js} +2 -2
- package/dist/{prompts-s4y90zs7.js → prompts-y35emwj0.js} +6 -6
- package/dist/{provision-tch8rc3y.js → provision-aqhfbnez.js} +6 -6
- package/dist/{registry-tv8fktxc.js → registry-wv1zzyce.js} +4 -4
- package/dist/{skills-mwftqzyk.js → skills-etzcqhp8.js} +6 -6
- package/dist/{sync-qxf3gkhy.js → sync-ydfxfjs5.js} +10 -10
- package/package.json +1 -1
- package/skills/integration/index.json +2 -2
|
@@ -13,16 +13,16 @@ import {
|
|
|
13
13
|
import {
|
|
14
14
|
createCommandContext,
|
|
15
15
|
stringOption
|
|
16
|
-
} from "./cli-
|
|
16
|
+
} from "./cli-v2h21cgf.js";
|
|
17
17
|
import {
|
|
18
18
|
assertFlags,
|
|
19
19
|
assertPositionals,
|
|
20
20
|
requireTenant
|
|
21
|
-
} from "./cli-
|
|
21
|
+
} from "./cli-31ybq5f2.js";
|
|
22
22
|
import {
|
|
23
23
|
ApiError,
|
|
24
24
|
callControlAPI
|
|
25
|
-
} from "./cli-
|
|
25
|
+
} from "./cli-hawwf30b.js";
|
|
26
26
|
import {
|
|
27
27
|
embeddedTenantIdFromApiKey,
|
|
28
28
|
getActiveProfile,
|
|
@@ -32,7 +32,7 @@ import {
|
|
|
32
32
|
resolveModaBaseUrl,
|
|
33
33
|
resolveTenantId,
|
|
34
34
|
shellArg
|
|
35
|
-
} from "./cli-
|
|
35
|
+
} from "./cli-pnarsb96.js";
|
|
36
36
|
import {
|
|
37
37
|
PYTHON_AGENT_MODULES,
|
|
38
38
|
TYPESCRIPT_AGENT_MODULES,
|
|
@@ -44,7 +44,7 @@ import {
|
|
|
44
44
|
require_typescript,
|
|
45
45
|
resolvePromptSource,
|
|
46
46
|
validatePromptSource
|
|
47
|
-
} from "./cli-
|
|
47
|
+
} from "./cli-y5d33a1y.js";
|
|
48
48
|
import {
|
|
49
49
|
$isMap,
|
|
50
50
|
$isNode,
|
|
@@ -70,7 +70,7 @@ import {
|
|
|
70
70
|
packSnapshot,
|
|
71
71
|
redactDeep,
|
|
72
72
|
shouldInventoryFile
|
|
73
|
-
} from "./cli-
|
|
73
|
+
} from "./cli-9a4b1wxz.js";
|
|
74
74
|
import {
|
|
75
75
|
HARNESS_ANALYZE_CONCERNS,
|
|
76
76
|
HARNESS_REPORT_PATH,
|
|
@@ -83,14 +83,16 @@ import {
|
|
|
83
83
|
hashHarnessReport,
|
|
84
84
|
hashStableJson,
|
|
85
85
|
loadHarnessReportForSync,
|
|
86
|
+
mergeBoundRuntimeClasses,
|
|
86
87
|
normalizeHarnessReport,
|
|
87
88
|
readHarnessReport,
|
|
88
89
|
requiresArtifactBody,
|
|
89
90
|
resolveHarnessReportPath,
|
|
90
91
|
stampRemoteSnapshotTruncation,
|
|
92
|
+
tagComponentStatus,
|
|
91
93
|
validateHarnessReport,
|
|
92
94
|
writeHarnessReportArtifacts
|
|
93
|
-
} from "./cli-
|
|
95
|
+
} from "./cli-rtkjjf0a.js";
|
|
94
96
|
import {
|
|
95
97
|
CliInputError,
|
|
96
98
|
CliInputRequiredError
|
|
@@ -107,15 +109,15 @@ import { homedir, tmpdir as tmpdir2 } from "node:os";
|
|
|
107
109
|
import { fileURLToPath } from "node:url";
|
|
108
110
|
import {
|
|
109
111
|
existsSync as existsSync8,
|
|
110
|
-
lstatSync as
|
|
112
|
+
lstatSync as lstatSync7,
|
|
111
113
|
mkdtempSync as mkdtempSync2,
|
|
112
114
|
mkdirSync as mkdirSync5,
|
|
113
|
-
readFileSync as
|
|
114
|
-
readdirSync as
|
|
115
|
+
readFileSync as readFileSync12,
|
|
116
|
+
readdirSync as readdirSync4,
|
|
115
117
|
writeFileSync as writeFileSync5,
|
|
116
118
|
rmSync as rmSync4
|
|
117
119
|
} from "node:fs";
|
|
118
|
-
import { basename as basename6, delimiter, dirname as dirname7, join as
|
|
120
|
+
import { basename as basename6, delimiter, dirname as dirname7, join as join9, relative as relative6, resolve as resolve10, sep as sep5 } from "node:path";
|
|
119
121
|
import { confirm, select } from "@inquirer/prompts";
|
|
120
122
|
|
|
121
123
|
// src/analyst-tui.ts
|
|
@@ -12126,7 +12128,7 @@ var LINE_PATTERNS = [
|
|
|
12126
12128
|
kind: "prompt_literal",
|
|
12127
12129
|
signal: "code.prompt_configuration_field",
|
|
12128
12130
|
confidence: "high",
|
|
12129
|
-
pattern: /(?:^|[{,])\s*(?:instructions
|
|
12131
|
+
pattern: /(?:^|[{,])\s*["']?(?:instructions?|systemPrompt|system_prompt|systemMessage|system_message|systemInstruction|system_instruction|backstory)["']?\s*:/,
|
|
12130
12132
|
extensions: JS
|
|
12131
12133
|
},
|
|
12132
12134
|
{
|
|
@@ -13560,6 +13562,319 @@ function applyPromptDiscovery(graph, discovery) {
|
|
|
13560
13562
|
// src/harness-candidate-promotion.ts
|
|
13561
13563
|
import { readFileSync as readFileSync11 } from "node:fs";
|
|
13562
13564
|
import { extname as extname7, posix, resolve as resolve9 } from "node:path";
|
|
13565
|
+
|
|
13566
|
+
// src/harness-js-source.ts
|
|
13567
|
+
var import_typescript2 = __toESM(require_typescript(), 1);
|
|
13568
|
+
var JS_EXTENSION = /\.(?:[cm]?[jt]sx?)$/i;
|
|
13569
|
+
function isJsSourcePath(path) {
|
|
13570
|
+
return JS_EXTENSION.test(path);
|
|
13571
|
+
}
|
|
13572
|
+
function scriptKindFor(path) {
|
|
13573
|
+
const lower = path.toLowerCase();
|
|
13574
|
+
if (lower.endsWith(".tsx"))
|
|
13575
|
+
return import_typescript2.default.ScriptKind.TSX;
|
|
13576
|
+
if (lower.endsWith(".ts") || lower.endsWith(".mts") || lower.endsWith(".cts"))
|
|
13577
|
+
return import_typescript2.default.ScriptKind.TS;
|
|
13578
|
+
if (lower.endsWith(".jsx"))
|
|
13579
|
+
return import_typescript2.default.ScriptKind.JSX;
|
|
13580
|
+
return import_typescript2.default.ScriptKind.JS;
|
|
13581
|
+
}
|
|
13582
|
+
function parseJsSource(path, text) {
|
|
13583
|
+
return import_typescript2.default.createSourceFile(path, text, import_typescript2.default.ScriptTarget.Latest, true, scriptKindFor(path));
|
|
13584
|
+
}
|
|
13585
|
+
function codeOnlyLines(source) {
|
|
13586
|
+
const text = source.text;
|
|
13587
|
+
const chars = text.split("");
|
|
13588
|
+
const seen = new Set;
|
|
13589
|
+
const jsxText = [];
|
|
13590
|
+
const collectJsxText = (node) => {
|
|
13591
|
+
if (node.kind === import_typescript2.default.SyntaxKind.JsxText)
|
|
13592
|
+
jsxText.push([node.getFullStart(), node.getEnd()]);
|
|
13593
|
+
import_typescript2.default.forEachChild(node, collectJsxText);
|
|
13594
|
+
};
|
|
13595
|
+
collectJsxText(source);
|
|
13596
|
+
const blank = (range) => {
|
|
13597
|
+
if (seen.has(range.pos))
|
|
13598
|
+
return;
|
|
13599
|
+
if (jsxText.some(([start, end]) => range.pos >= start && range.pos < end))
|
|
13600
|
+
return;
|
|
13601
|
+
seen.add(range.pos);
|
|
13602
|
+
for (let i = range.pos;i < range.end; i += 1) {
|
|
13603
|
+
if (chars[i] !== `
|
|
13604
|
+
` && chars[i] !== "\r")
|
|
13605
|
+
chars[i] = " ";
|
|
13606
|
+
}
|
|
13607
|
+
};
|
|
13608
|
+
const visit = (node) => {
|
|
13609
|
+
if (node.kind === import_typescript2.default.SyntaxKind.JsxText)
|
|
13610
|
+
return;
|
|
13611
|
+
const children = node.getChildren(source);
|
|
13612
|
+
if (children.length === 0) {
|
|
13613
|
+
for (const range of import_typescript2.default.getLeadingCommentRanges(text, node.getFullStart()) ?? [])
|
|
13614
|
+
blank(range);
|
|
13615
|
+
for (const range of import_typescript2.default.getTrailingCommentRanges(text, node.getEnd()) ?? [])
|
|
13616
|
+
blank(range);
|
|
13617
|
+
return;
|
|
13618
|
+
}
|
|
13619
|
+
for (const child of children)
|
|
13620
|
+
visit(child);
|
|
13621
|
+
};
|
|
13622
|
+
visit(source);
|
|
13623
|
+
for (const range of import_typescript2.default.getLeadingCommentRanges(text, source.endOfFileToken.getFullStart()) ?? [])
|
|
13624
|
+
blank(range);
|
|
13625
|
+
return chars.join("").split(/\r?\n/);
|
|
13626
|
+
}
|
|
13627
|
+
var TRIM_METHODS = new Set(["trim", "trimStart", "trimEnd"]);
|
|
13628
|
+
var TEXT_TAGS = new Map([
|
|
13629
|
+
["dedent", stripIndent],
|
|
13630
|
+
["outdent", stripIndent],
|
|
13631
|
+
["stripIndent", stripIndent],
|
|
13632
|
+
["stripIndents", (text) => text.replace(/^[ \t]+/gm, "").trim()],
|
|
13633
|
+
["oneLine", (text) => text.replace(/(?:\n(?:\s*))+/g, " ").trim()],
|
|
13634
|
+
["oneLineTrim", (text) => text.replace(/(?:\n(?:\s*))+/g, "").trim()]
|
|
13635
|
+
]);
|
|
13636
|
+
function stripIndent(text) {
|
|
13637
|
+
const indents = text.split(`
|
|
13638
|
+
`).filter((line) => line.trim() !== "").map((line) => /^[ \t]*/.exec(line)[0].length);
|
|
13639
|
+
const common = indents.length > 0 ? Math.min(...indents) : 0;
|
|
13640
|
+
return (common > 0 ? text.replace(new RegExp(`^[ \\t]{${common}}`, "gm"), "") : text).trim();
|
|
13641
|
+
}
|
|
13642
|
+
function stringValueOf(node, source) {
|
|
13643
|
+
if (import_typescript2.default.isStringLiteral(node) || import_typescript2.default.isNoSubstitutionTemplateLiteral(node))
|
|
13644
|
+
return node.text;
|
|
13645
|
+
if (import_typescript2.default.isTemplateExpression(node)) {
|
|
13646
|
+
let out = node.head.text;
|
|
13647
|
+
for (const span of node.templateSpans)
|
|
13648
|
+
out += `\${${span.expression.getText(source)}}${span.literal.text}`;
|
|
13649
|
+
return out;
|
|
13650
|
+
}
|
|
13651
|
+
if (import_typescript2.default.isParenthesizedExpression(node) || import_typescript2.default.isAsExpression(node) || import_typescript2.default.isSatisfiesExpression(node) || import_typescript2.default.isTypeAssertionExpression(node)) {
|
|
13652
|
+
return stringValueOf(node.expression, source);
|
|
13653
|
+
}
|
|
13654
|
+
if (import_typescript2.default.isTaggedTemplateExpression(node)) {
|
|
13655
|
+
const transform = import_typescript2.default.isIdentifier(node.tag) ? TEXT_TAGS.get(node.tag.text) : undefined;
|
|
13656
|
+
const inner = transform && stringValueOf(node.template, source);
|
|
13657
|
+
return inner === undefined || !transform ? undefined : transform(inner);
|
|
13658
|
+
}
|
|
13659
|
+
if (import_typescript2.default.isBinaryExpression(node) && node.operatorToken.kind === import_typescript2.default.SyntaxKind.PlusToken) {
|
|
13660
|
+
const parts = composedParts([node.left, node.right], source);
|
|
13661
|
+
return parts?.join("");
|
|
13662
|
+
}
|
|
13663
|
+
if (import_typescript2.default.isArrayLiteralExpression(node)) {
|
|
13664
|
+
return composedParts(node.elements, source)?.join(`
|
|
13665
|
+
`);
|
|
13666
|
+
}
|
|
13667
|
+
if (import_typescript2.default.isCallExpression(node)) {
|
|
13668
|
+
const callee = node.expression;
|
|
13669
|
+
const array = import_typescript2.default.isPropertyAccessExpression(callee) && callee.name.text === "join" ? unfiltered(callee.expression) : undefined;
|
|
13670
|
+
if (array && import_typescript2.default.isArrayLiteralExpression(array)) {
|
|
13671
|
+
const separatorArg = node.arguments[0];
|
|
13672
|
+
const separator = separatorArg === undefined ? "," : import_typescript2.default.isStringLiteral(separatorArg) || import_typescript2.default.isNoSubstitutionTemplateLiteral(separatorArg) ? separatorArg.text : undefined;
|
|
13673
|
+
if (separator === undefined)
|
|
13674
|
+
return;
|
|
13675
|
+
return composedParts(array.elements, source)?.join(separator);
|
|
13676
|
+
}
|
|
13677
|
+
if (import_typescript2.default.isPropertyAccessExpression(callee) && TRIM_METHODS.has(callee.name.text) && node.arguments.length === 0) {
|
|
13678
|
+
const inner = stringValueOf(callee.expression, source);
|
|
13679
|
+
return inner === undefined ? undefined : callee.name.text === "trimStart" ? inner.trimStart() : callee.name.text === "trimEnd" ? inner.trimEnd() : inner.trim();
|
|
13680
|
+
}
|
|
13681
|
+
const transform = import_typescript2.default.isIdentifier(callee) && node.arguments.length === 1 ? TEXT_TAGS.get(callee.text) : undefined;
|
|
13682
|
+
if (transform) {
|
|
13683
|
+
const inner = stringValueOf(node.arguments[0], source);
|
|
13684
|
+
return inner === undefined ? undefined : transform(inner);
|
|
13685
|
+
}
|
|
13686
|
+
return;
|
|
13687
|
+
}
|
|
13688
|
+
return;
|
|
13689
|
+
}
|
|
13690
|
+
function composedParts(elements, source) {
|
|
13691
|
+
let literal = false;
|
|
13692
|
+
const parts = [];
|
|
13693
|
+
for (const element of elements) {
|
|
13694
|
+
if (import_typescript2.default.isOmittedExpression(element))
|
|
13695
|
+
return;
|
|
13696
|
+
const value = import_typescript2.default.isSpreadElement(element) ? undefined : stringValueOf(element, source);
|
|
13697
|
+
if (value !== undefined)
|
|
13698
|
+
literal = true;
|
|
13699
|
+
parts.push(value ?? `\${${element.getText(source)}}`);
|
|
13700
|
+
}
|
|
13701
|
+
return literal && parts.length > 0 ? parts : undefined;
|
|
13702
|
+
}
|
|
13703
|
+
function unfiltered(node) {
|
|
13704
|
+
let current = node;
|
|
13705
|
+
while (import_typescript2.default.isCallExpression(current) && import_typescript2.default.isPropertyAccessExpression(current.expression) && current.expression.name.text === "filter") {
|
|
13706
|
+
const [predicate] = current.arguments;
|
|
13707
|
+
if (current.arguments.length !== 1 || !import_typescript2.default.isIdentifier(predicate) || predicate.text !== "Boolean")
|
|
13708
|
+
return;
|
|
13709
|
+
current = current.expression.expression;
|
|
13710
|
+
}
|
|
13711
|
+
return current;
|
|
13712
|
+
}
|
|
13713
|
+
var PROMPT_NAME = /prompt|instruction|system|template|rubric|persona|backstory|content/i;
|
|
13714
|
+
function comparable(text) {
|
|
13715
|
+
return text.replace(/\\/g, "").replace(/\s+/g, " ").trim();
|
|
13716
|
+
}
|
|
13717
|
+
function lineOf(source, position) {
|
|
13718
|
+
return source.getLineAndCharacterOfPosition(position).line + 1;
|
|
13719
|
+
}
|
|
13720
|
+
function propertyNameText(name) {
|
|
13721
|
+
if (import_typescript2.default.isIdentifier(name) || import_typescript2.default.isStringLiteral(name) || import_typescript2.default.isPrivateIdentifier(name))
|
|
13722
|
+
return name.text;
|
|
13723
|
+
return;
|
|
13724
|
+
}
|
|
13725
|
+
function enclosingFunctionName(node) {
|
|
13726
|
+
for (let current = node.parent;current; current = current.parent) {
|
|
13727
|
+
if (import_typescript2.default.isFunctionDeclaration(current) || import_typescript2.default.isMethodDeclaration(current)) {
|
|
13728
|
+
return current.name && (import_typescript2.default.isIdentifier(current.name) || import_typescript2.default.isStringLiteral(current.name)) ? current.name.text : undefined;
|
|
13729
|
+
}
|
|
13730
|
+
if (import_typescript2.default.isArrowFunction(current) || import_typescript2.default.isFunctionExpression(current)) {
|
|
13731
|
+
const holder = current.parent;
|
|
13732
|
+
if (holder && import_typescript2.default.isVariableDeclaration(holder) && import_typescript2.default.isIdentifier(holder.name))
|
|
13733
|
+
return holder.name.text;
|
|
13734
|
+
if (holder && import_typescript2.default.isPropertyAssignment(holder))
|
|
13735
|
+
return propertyNameText(holder.name);
|
|
13736
|
+
return;
|
|
13737
|
+
}
|
|
13738
|
+
}
|
|
13739
|
+
return;
|
|
13740
|
+
}
|
|
13741
|
+
function jsLiteralDefinitionAt(source, startLine, excerpt2) {
|
|
13742
|
+
const literal = excerpt2 ? comparable(excerpt2).slice(0, 120) : "";
|
|
13743
|
+
const all = [];
|
|
13744
|
+
const consider = (node, value, def, depth) => {
|
|
13745
|
+
const defLine = lineOf(source, node.getStart(source));
|
|
13746
|
+
const valueLine = lineOf(source, value.getStart(source));
|
|
13747
|
+
const valueEndLine = lineOf(source, value.getEnd());
|
|
13748
|
+
const distance = valueLine === startLine || defLine === startLine ? 0 : defLine === startLine - 1 && valueEndLine >= startLine ? 1 : -1;
|
|
13749
|
+
if (distance < 0)
|
|
13750
|
+
return;
|
|
13751
|
+
const text = stringValueOf(value, source);
|
|
13752
|
+
if (text === undefined)
|
|
13753
|
+
return;
|
|
13754
|
+
all.push({
|
|
13755
|
+
def: { ...def, text, line: defLine },
|
|
13756
|
+
start: node.getStart(source),
|
|
13757
|
+
depth,
|
|
13758
|
+
distance,
|
|
13759
|
+
matches: literal.length > 0 && comparable(value.getText(source)).includes(literal),
|
|
13760
|
+
named: PROMPT_NAME.test(def.key ?? def.identifier ?? "")
|
|
13761
|
+
});
|
|
13762
|
+
};
|
|
13763
|
+
const visit = (node, depth) => {
|
|
13764
|
+
const nodeStart = lineOf(source, node.getStart(source));
|
|
13765
|
+
const nodeEnd = lineOf(source, node.getEnd());
|
|
13766
|
+
if (nodeEnd < startLine - 1 || nodeStart > startLine)
|
|
13767
|
+
return;
|
|
13768
|
+
if (import_typescript2.default.isVariableDeclaration(node) && import_typescript2.default.isIdentifier(node.name) && node.initializer) {
|
|
13769
|
+
consider(node, node.initializer, { identifier: node.name.text }, depth);
|
|
13770
|
+
} else if (import_typescript2.default.isPropertyAssignment(node)) {
|
|
13771
|
+
const key = propertyNameText(node.name);
|
|
13772
|
+
if (key)
|
|
13773
|
+
consider(node, node.initializer, { key }, depth);
|
|
13774
|
+
} else if (import_typescript2.default.isPropertyDeclaration(node) && node.initializer) {
|
|
13775
|
+
const name = propertyNameText(node.name);
|
|
13776
|
+
if (name)
|
|
13777
|
+
consider(node, node.initializer, { identifier: name }, depth);
|
|
13778
|
+
} else if (import_typescript2.default.isBinaryExpression(node) && node.operatorToken.kind === import_typescript2.default.SyntaxKind.EqualsToken) {
|
|
13779
|
+
const target = node.left;
|
|
13780
|
+
const name = import_typescript2.default.isIdentifier(target) ? target.text : import_typescript2.default.isPropertyAccessExpression(target) ? target.name.text : undefined;
|
|
13781
|
+
if (name)
|
|
13782
|
+
consider(node, node.right, { identifier: name }, depth);
|
|
13783
|
+
} else if (import_typescript2.default.isReturnStatement(node) && node.expression) {
|
|
13784
|
+
const name = enclosingFunctionName(node);
|
|
13785
|
+
if (name)
|
|
13786
|
+
consider(node, node.expression, { identifier: name }, depth);
|
|
13787
|
+
}
|
|
13788
|
+
import_typescript2.default.forEachChild(node, (child) => visit(child, depth + 1));
|
|
13789
|
+
};
|
|
13790
|
+
visit(source, 0);
|
|
13791
|
+
const rank = (a, b) => a.distance - b.distance || Number(b.matches) - Number(a.matches) || Number(b.named) - Number(a.named) || b.def.text.length - a.def.text.length || b.depth - a.depth;
|
|
13792
|
+
const best = all.sort(rank)[0];
|
|
13793
|
+
if (!best)
|
|
13794
|
+
return;
|
|
13795
|
+
const earlier = all.some((other) => other.def.line === best.def.line && other.start < best.start);
|
|
13796
|
+
return earlier ? { ...best.def, column: source.getLineAndCharacterOfPosition(best.start).character + 1 } : best.def;
|
|
13797
|
+
}
|
|
13798
|
+
function calleeText(call, source) {
|
|
13799
|
+
return call.expression.getText(source).replace(/\s+/g, "");
|
|
13800
|
+
}
|
|
13801
|
+
function outermostContainer(node) {
|
|
13802
|
+
let current = node;
|
|
13803
|
+
while (current.parent && (import_typescript2.default.isPropertyAssignment(current.parent) || import_typescript2.default.isObjectLiteralExpression(current.parent) || import_typescript2.default.isArrayLiteralExpression(current.parent) || import_typescript2.default.isParenthesizedExpression(current.parent) || import_typescript2.default.isAsExpression(current.parent) || import_typescript2.default.isSatisfiesExpression(current.parent) || import_typescript2.default.isSpreadElement(current.parent) || import_typescript2.default.isShorthandPropertyAssignment(current.parent) || import_typescript2.default.isAwaitExpression(current.parent) || import_typescript2.default.isNonNullExpression(current.parent)))
|
|
13804
|
+
current = current.parent;
|
|
13805
|
+
return current;
|
|
13806
|
+
}
|
|
13807
|
+
function isExportedDeclaration(declaration) {
|
|
13808
|
+
const statement = declaration.parent?.parent;
|
|
13809
|
+
return Boolean(statement && import_typescript2.default.isVariableStatement(statement) && statement.modifiers?.some((modifier) => modifier.kind === import_typescript2.default.SyntaxKind.ExportKeyword));
|
|
13810
|
+
}
|
|
13811
|
+
function followValue(start, source, callees, targets, seen, out) {
|
|
13812
|
+
let current = start;
|
|
13813
|
+
for (;; ) {
|
|
13814
|
+
let parent = current.parent;
|
|
13815
|
+
while (parent && ((import_typescript2.default.isPropertyAccessExpression(parent) || import_typescript2.default.isElementAccessExpression(parent)) && parent.expression === current)) {
|
|
13816
|
+
current = parent;
|
|
13817
|
+
parent = current.parent;
|
|
13818
|
+
}
|
|
13819
|
+
const container = outermostContainer(current);
|
|
13820
|
+
const holder = container.parent;
|
|
13821
|
+
if (holder && (import_typescript2.default.isCallExpression(holder) || import_typescript2.default.isNewExpression(holder)) && (holder.arguments?.includes(container) || import_typescript2.default.isCallExpression(holder) && holder.expression === container)) {
|
|
13822
|
+
callees.push(calleeText(holder, source));
|
|
13823
|
+
targets.push(holder.arguments?.[0]?.getText(source) ?? "");
|
|
13824
|
+
current = holder;
|
|
13825
|
+
continue;
|
|
13826
|
+
}
|
|
13827
|
+
if (holder && import_typescript2.default.isVariableDeclaration(holder) && import_typescript2.default.isIdentifier(holder.name) && holder.initializer === container) {
|
|
13828
|
+
if (seen.has(holder))
|
|
13829
|
+
return;
|
|
13830
|
+
seen.add(holder);
|
|
13831
|
+
const name = holder.name.text;
|
|
13832
|
+
const declaration = holder.name;
|
|
13833
|
+
const before = out.length;
|
|
13834
|
+
if (isExportedDeclaration(holder))
|
|
13835
|
+
out.push({ callees: [...callees], targets: [...targets], display: false, escape: "export" });
|
|
13836
|
+
const visit = (node) => {
|
|
13837
|
+
if (import_typescript2.default.isIdentifier(node) && node.text === name && node !== declaration && !(node.parent && import_typescript2.default.isPropertyAccessExpression(node.parent) && node.parent.name === node)) {
|
|
13838
|
+
followValue(node, source, [...callees], [...targets], seen, out);
|
|
13839
|
+
}
|
|
13840
|
+
import_typescript2.default.forEachChild(node, visit);
|
|
13841
|
+
};
|
|
13842
|
+
visit(source);
|
|
13843
|
+
if (out.length === before)
|
|
13844
|
+
out.push({ callees: [...callees], targets: [...targets], display: false, escape: "unknown" });
|
|
13845
|
+
return;
|
|
13846
|
+
}
|
|
13847
|
+
const display = Boolean(holder && (import_typescript2.default.isJsxExpression(holder) || import_typescript2.default.isJsxSpreadAttribute(holder)));
|
|
13848
|
+
const statement = Boolean(holder && import_typescript2.default.isExpressionStatement(holder));
|
|
13849
|
+
const exported = Boolean(holder && (import_typescript2.default.isExportSpecifier(holder) || import_typescript2.default.isExportAssignment(holder)));
|
|
13850
|
+
out.push({ callees, targets, display, escape: display || statement ? undefined : exported ? "export" : "unknown" });
|
|
13851
|
+
return;
|
|
13852
|
+
}
|
|
13853
|
+
}
|
|
13854
|
+
function keyedValueConsumer(source, line, key, column) {
|
|
13855
|
+
let property;
|
|
13856
|
+
const find = (node) => {
|
|
13857
|
+
if (property)
|
|
13858
|
+
return;
|
|
13859
|
+
if (import_typescript2.default.isPropertyAssignment(node) && lineOf(source, node.getStart(source)) === line && (column === undefined || source.getLineAndCharacterOfPosition(node.getStart(source)).character + 1 === column) && (import_typescript2.default.isIdentifier(node.name) || import_typescript2.default.isStringLiteral(node.name)) && node.name.text === key) {
|
|
13860
|
+
property = node;
|
|
13861
|
+
return;
|
|
13862
|
+
}
|
|
13863
|
+
import_typescript2.default.forEachChild(node, find);
|
|
13864
|
+
};
|
|
13865
|
+
find(source);
|
|
13866
|
+
if (!property)
|
|
13867
|
+
return { kind: "uses", uses: [{ callees: [], targets: [], display: false, escape: "unknown" }] };
|
|
13868
|
+
const owner = property.parent;
|
|
13869
|
+
if (import_typescript2.default.isObjectLiteralExpression(owner) && owner.properties.some((other) => import_typescript2.default.isPropertyAssignment(other) && import_typescript2.default.isIdentifier(other.name) && other.name.text === "role" && (import_typescript2.default.isStringLiteral(other.initializer) || import_typescript2.default.isNoSubstitutionTemplateLiteral(other.initializer)) && /^(?:system|user|assistant|developer|human)$/.test(other.initializer.text))) {
|
|
13870
|
+
return { kind: "chat_message" };
|
|
13871
|
+
}
|
|
13872
|
+
const uses = [];
|
|
13873
|
+
followValue(property, source, [], [], new Set, uses);
|
|
13874
|
+
return { kind: "uses", uses };
|
|
13875
|
+
}
|
|
13876
|
+
|
|
13877
|
+
// src/harness-candidate-promotion.ts
|
|
13563
13878
|
var PROMOTED_CONFIDENCE = {
|
|
13564
13879
|
high: 0.85,
|
|
13565
13880
|
medium: 0.6
|
|
@@ -13582,13 +13897,21 @@ function candidateEvidence(candidate) {
|
|
|
13582
13897
|
function pathStem(path) {
|
|
13583
13898
|
return path.replace(/\.[^.]+$/, "");
|
|
13584
13899
|
}
|
|
13900
|
+
var jsSources = new Map;
|
|
13585
13901
|
function readFileLines(rootDir, path, cache) {
|
|
13586
13902
|
const cached = cache.get(path);
|
|
13587
13903
|
if (cached !== undefined)
|
|
13588
13904
|
return cached;
|
|
13589
13905
|
let lines;
|
|
13590
13906
|
try {
|
|
13591
|
-
|
|
13907
|
+
const text = readFileSync11(resolve9(rootDir, path), "utf8");
|
|
13908
|
+
if (isJsSourcePath(path)) {
|
|
13909
|
+
const source = parseJsSource(path, text);
|
|
13910
|
+
jsSources.set(`${rootDir}::${path}`, source);
|
|
13911
|
+
lines = codeOnlyLines(source);
|
|
13912
|
+
} else {
|
|
13913
|
+
lines = text.split(/\r?\n/);
|
|
13914
|
+
}
|
|
13592
13915
|
} catch {
|
|
13593
13916
|
lines = null;
|
|
13594
13917
|
}
|
|
@@ -13663,6 +13986,12 @@ function buildsPrompts(path, lines) {
|
|
|
13663
13986
|
return false;
|
|
13664
13987
|
return exportedNames(path, lines).some((name) => !UTILITY_EXPORT.test(name) && (BUILDER_VERB.test(name) || PROMPT_NOUN_LAST.test(name)));
|
|
13665
13988
|
}
|
|
13989
|
+
var TEST_FILE2 = /(?:^|\/)(?:test_[^/]*\.py|[^/]*_test\.py|conftest\.py|[^/]*\.(?:test|spec)\.[^/]+)$/i;
|
|
13990
|
+
var FIXTURE_DIR2 = /(?:^|\/)(?:fixtures?|test-fixtures|__fixtures__|__mocks__)(?:\/|$)/i;
|
|
13991
|
+
var EVAL_HARNESS_PATH = /(?:^|[\/_.-])(?:evals?|evaluations?|judges?|grader|grading|pairwise|quality|rubrics?|benchmarks?)(?:[\/_.-]|$)/i;
|
|
13992
|
+
function isTestInput(path) {
|
|
13993
|
+
return (TEST_FILE2.test(path) || FIXTURE_DIR2.test(path)) && !EVAL_HARNESS_PATH.test(path);
|
|
13994
|
+
}
|
|
13666
13995
|
function promotePromptFileCandidate(candidate, confidence2) {
|
|
13667
13996
|
return {
|
|
13668
13997
|
id: stableId("prompt", candidate.path),
|
|
@@ -13694,6 +14023,7 @@ var MODEL_INPUT_KEYS = [
|
|
|
13694
14023
|
"text"
|
|
13695
14024
|
];
|
|
13696
14025
|
var DIRECT_PROMPT_KEYS = new Set([
|
|
14026
|
+
"instruction",
|
|
13697
14027
|
"system",
|
|
13698
14028
|
"systemPrompt",
|
|
13699
14029
|
"system_prompt",
|
|
@@ -13725,6 +14055,7 @@ var CONFIG_EXTENSIONS = new Set([".json", ".yaml", ".yml"]);
|
|
|
13725
14055
|
var PROMPT_NAMED_IDENTIFIER = /prompt|system|instruction/i;
|
|
13726
14056
|
var SECOND_PERSON_OPENING = /^\s*(?:\[[A-Z]+:\s*|<\w+>\s*)*(?:you|your)\b/i;
|
|
13727
14057
|
var MIN_UNNAMED_REFERENCED_PROMPT_CHARS = 200;
|
|
14058
|
+
var UNUSED_PROMPT_CONFIDENCE = 0.6;
|
|
13728
14059
|
var REFERENCED_PROMPT_CONFIDENCE = 0.7;
|
|
13729
14060
|
var MIN_RESOLVED_PROMPT_CHARS = 20;
|
|
13730
14061
|
var MIN_CONFIG_PROMPT_CHARS = 40;
|
|
@@ -13751,128 +14082,15 @@ function readStringLiteral(text, start) {
|
|
|
13751
14082
|
i += 2;
|
|
13752
14083
|
continue;
|
|
13753
14084
|
}
|
|
13754
|
-
if (opener.length === 1 &&
|
|
14085
|
+
if (opener.length === 1 && char === `
|
|
13755
14086
|
`)
|
|
13756
14087
|
return;
|
|
13757
|
-
if (opener === "`" && char === "$" && text[i + 1] === "{") {
|
|
13758
|
-
let depth = 1;
|
|
13759
|
-
i += 2;
|
|
13760
|
-
while (i < text.length && depth > 0) {
|
|
13761
|
-
if (text[i] === "`" || text[i] === '"' || text[i] === "'") {
|
|
13762
|
-
const nested = readStringLiteral(text, i);
|
|
13763
|
-
if (nested) {
|
|
13764
|
-
i = nested.end;
|
|
13765
|
-
continue;
|
|
13766
|
-
}
|
|
13767
|
-
if (text[i] === "`")
|
|
13768
|
-
return;
|
|
13769
|
-
i += 1;
|
|
13770
|
-
continue;
|
|
13771
|
-
}
|
|
13772
|
-
const regexEnd = text[i] === "/" ? regexLiteralEnd(text, i) : undefined;
|
|
13773
|
-
if (regexEnd !== undefined) {
|
|
13774
|
-
i = regexEnd;
|
|
13775
|
-
continue;
|
|
13776
|
-
}
|
|
13777
|
-
if (text.startsWith("//", i)) {
|
|
13778
|
-
const newline = text.indexOf(`
|
|
13779
|
-
`, i);
|
|
13780
|
-
i = newline < 0 ? text.length : newline;
|
|
13781
|
-
continue;
|
|
13782
|
-
}
|
|
13783
|
-
if (text.startsWith("/*", i)) {
|
|
13784
|
-
const close = text.indexOf("*/", i + 2);
|
|
13785
|
-
if (close < 0)
|
|
13786
|
-
return;
|
|
13787
|
-
i = close + 2;
|
|
13788
|
-
continue;
|
|
13789
|
-
}
|
|
13790
|
-
if (text[i] === "{")
|
|
13791
|
-
depth += 1;
|
|
13792
|
-
else if (text[i] === "}")
|
|
13793
|
-
depth -= 1;
|
|
13794
|
-
i += 1;
|
|
13795
|
-
}
|
|
13796
|
-
continue;
|
|
13797
|
-
}
|
|
13798
14088
|
if (text.startsWith(opener, i))
|
|
13799
14089
|
return { value: text.slice(start + opener.length, i), end: i + opener.length };
|
|
13800
14090
|
i += 1;
|
|
13801
14091
|
}
|
|
13802
14092
|
return;
|
|
13803
14093
|
}
|
|
13804
|
-
var EXPRESSION_KEYWORDS = new Set([
|
|
13805
|
-
"return",
|
|
13806
|
-
"typeof",
|
|
13807
|
-
"instanceof",
|
|
13808
|
-
"in",
|
|
13809
|
-
"of",
|
|
13810
|
-
"new",
|
|
13811
|
-
"delete",
|
|
13812
|
-
"void",
|
|
13813
|
-
"throw",
|
|
13814
|
-
"case",
|
|
13815
|
-
"do",
|
|
13816
|
-
"else",
|
|
13817
|
-
"yield",
|
|
13818
|
-
"await"
|
|
13819
|
-
]);
|
|
13820
|
-
function endsWithOperand(text, end) {
|
|
13821
|
-
let i = end;
|
|
13822
|
-
while (i > 0 && /\s/.test(text[i - 1]))
|
|
13823
|
-
i -= 1;
|
|
13824
|
-
if (i === 0)
|
|
13825
|
-
return false;
|
|
13826
|
-
const char = text[i - 1];
|
|
13827
|
-
if (char === ")" || char === "]" || char === '"' || char === "'" || char === "`")
|
|
13828
|
-
return true;
|
|
13829
|
-
if (/[\w$]/.test(char)) {
|
|
13830
|
-
let wordStart = i;
|
|
13831
|
-
while (wordStart > 0 && /[\w$]/.test(text[wordStart - 1]))
|
|
13832
|
-
wordStart -= 1;
|
|
13833
|
-
const word = text.slice(wordStart, i);
|
|
13834
|
-
if (/^\d/.test(word))
|
|
13835
|
-
return true;
|
|
13836
|
-
let before = wordStart;
|
|
13837
|
-
while (before > 0 && /\s/.test(text[before - 1]))
|
|
13838
|
-
before -= 1;
|
|
13839
|
-
const isProperty = text[before - 1] === "." && text[before - 2] !== ".";
|
|
13840
|
-
return isProperty || !EXPRESSION_KEYWORDS.has(word);
|
|
13841
|
-
}
|
|
13842
|
-
if ((char === "+" || char === "-") && text[i - 2] === char)
|
|
13843
|
-
return endsWithOperand(text, i - 2);
|
|
13844
|
-
if (char === "!" && i >= 2 && /[\w$)\]]/.test(text[i - 2]))
|
|
13845
|
-
return endsWithOperand(text, i - 1);
|
|
13846
|
-
return false;
|
|
13847
|
-
}
|
|
13848
|
-
function regexLiteralEnd(text, start) {
|
|
13849
|
-
if (text[start + 1] === "/" || text[start + 1] === "*")
|
|
13850
|
-
return;
|
|
13851
|
-
if (endsWithOperand(text, start))
|
|
13852
|
-
return;
|
|
13853
|
-
let inClass = false;
|
|
13854
|
-
for (let i = start + 1;i < text.length; i += 1) {
|
|
13855
|
-
const char = text[i];
|
|
13856
|
-
if (char === `
|
|
13857
|
-
`)
|
|
13858
|
-
return;
|
|
13859
|
-
if (char === "\\") {
|
|
13860
|
-
i += 1;
|
|
13861
|
-
continue;
|
|
13862
|
-
}
|
|
13863
|
-
if (char === "[")
|
|
13864
|
-
inClass = true;
|
|
13865
|
-
else if (char === "]")
|
|
13866
|
-
inClass = false;
|
|
13867
|
-
else if (char === "/" && !inClass) {
|
|
13868
|
-
let end = i + 1;
|
|
13869
|
-
while (/[a-z]/i.test(text[end] ?? ""))
|
|
13870
|
-
end += 1;
|
|
13871
|
-
return end;
|
|
13872
|
-
}
|
|
13873
|
-
}
|
|
13874
|
-
return;
|
|
13875
|
-
}
|
|
13876
14094
|
function readStringValue(text, offset) {
|
|
13877
14095
|
let i = offset;
|
|
13878
14096
|
const parts = [];
|
|
@@ -13929,7 +14147,9 @@ function stringStart(rest) {
|
|
|
13929
14147
|
}
|
|
13930
14148
|
return STRING_OPENER.test(remaining) ? consumed : -1;
|
|
13931
14149
|
}
|
|
13932
|
-
function resolvePromptLiteralDefinition(lines, startLine) {
|
|
14150
|
+
function resolvePromptLiteralDefinition(lines, startLine, jsSource, excerpt2) {
|
|
14151
|
+
if (jsSource)
|
|
14152
|
+
return jsLiteralDefinitionAt(jsSource, startLine, excerpt2);
|
|
13933
14153
|
const text = lines.join(`
|
|
13934
14154
|
`);
|
|
13935
14155
|
for (const index of [startLine - 1, startLine - 2]) {
|
|
@@ -14007,16 +14227,8 @@ function resolvePromptLiteralDefinition(lines, startLine) {
|
|
|
14007
14227
|
}
|
|
14008
14228
|
function endsInComment(prefix) {
|
|
14009
14229
|
let quote;
|
|
14010
|
-
let inBlock = false;
|
|
14011
14230
|
for (let i = 0;i < prefix.length; i += 1) {
|
|
14012
14231
|
const char = prefix[i];
|
|
14013
|
-
if (inBlock) {
|
|
14014
|
-
if (prefix.startsWith("*/", i)) {
|
|
14015
|
-
inBlock = false;
|
|
14016
|
-
i += 1;
|
|
14017
|
-
}
|
|
14018
|
-
continue;
|
|
14019
|
-
}
|
|
14020
14232
|
if (quote) {
|
|
14021
14233
|
if (char === "\\")
|
|
14022
14234
|
i += 1;
|
|
@@ -14024,23 +14236,14 @@ function endsInComment(prefix) {
|
|
|
14024
14236
|
quote = undefined;
|
|
14025
14237
|
continue;
|
|
14026
14238
|
}
|
|
14027
|
-
if (char === '"' || char === "'"
|
|
14239
|
+
if (char === '"' || char === "'") {
|
|
14028
14240
|
quote = char;
|
|
14029
14241
|
continue;
|
|
14030
14242
|
}
|
|
14031
|
-
|
|
14032
|
-
if (regexEnd !== undefined) {
|
|
14033
|
-
i = regexEnd - 1;
|
|
14034
|
-
continue;
|
|
14035
|
-
}
|
|
14036
|
-
if (prefix.startsWith("//", i))
|
|
14243
|
+
if (char === "#")
|
|
14037
14244
|
return true;
|
|
14038
|
-
else if (prefix.startsWith("/*", i)) {
|
|
14039
|
-
inBlock = true;
|
|
14040
|
-
i += 1;
|
|
14041
|
-
}
|
|
14042
14245
|
}
|
|
14043
|
-
return
|
|
14246
|
+
return false;
|
|
14044
14247
|
}
|
|
14045
14248
|
function readYamlBlockScalar(lines, index, rest) {
|
|
14046
14249
|
const indicator = /^([|>])([-+]?)\s*(?:#.*)?$/.exec(rest.trim());
|
|
@@ -14204,7 +14407,7 @@ function importStatementLines(lines) {
|
|
|
14204
14407
|
}
|
|
14205
14408
|
return covered;
|
|
14206
14409
|
}
|
|
14207
|
-
var MODEL_CALLEE = /model|llm|complet|generat|chat|invoke|infer|prompt|agent|judge|claude|gpt|openai|anthropic|gemini|\.create$/i;
|
|
14410
|
+
var MODEL_CALLEE = /model|llm|complet|generat|chat|invoke|infer|prompt|agent|judge|jev|claude|gpt|openai|anthropic|gemini|\.create$/i;
|
|
14208
14411
|
function calleeImportedFromModelFile(callee, path, lines, modelFiles) {
|
|
14209
14412
|
const base = callee.split(".")[0];
|
|
14210
14413
|
const text = lines.join(`
|
|
@@ -14249,7 +14452,10 @@ function localHelperCallsModel(callee, lines) {
|
|
|
14249
14452
|
const start = lines.findIndex((line) => head.test(line));
|
|
14250
14453
|
if (start < 0)
|
|
14251
14454
|
return false;
|
|
14252
|
-
|
|
14455
|
+
const match = head.exec(lines[start]);
|
|
14456
|
+
const declared = /^\s*(?:export\s+)?(?:async\s+)?(?:function|def|const|let|var)\b/.test(lines[start]);
|
|
14457
|
+
const sameLine = declared && match ? lines[start].slice(match.index + match[0].length) : "";
|
|
14458
|
+
return [sameLine, ...lines.slice(start + 1, start + 1 + MAX_HELPER_BODY_LINES)].some((line) => MODEL_CALL_IN_BODY.test(line));
|
|
14253
14459
|
}
|
|
14254
14460
|
function callCarriesChatMessages(lines, index) {
|
|
14255
14461
|
for (let i = Math.max(0, index - CALL_ROLE_WINDOW_LINES);i < Math.min(lines.length, index + CALL_ROLE_WINDOW_LINES + 1); i += 1) {
|
|
@@ -14396,6 +14602,31 @@ function readsAsInstructions(identifier, text) {
|
|
|
14396
14602
|
return score >= 2 || secondPerson;
|
|
14397
14603
|
return secondPerson && score >= 2 && text.length >= MIN_UNNAMED_REFERENCED_PROMPT_CHARS;
|
|
14398
14604
|
}
|
|
14605
|
+
function readsAsUnusedPrompt(name, text) {
|
|
14606
|
+
if (UI_COPY_NAME.test(name))
|
|
14607
|
+
return false;
|
|
14608
|
+
if (DIRECT_PROMPT_KEYS.has(name) && instructionScore(text) >= 2)
|
|
14609
|
+
return true;
|
|
14610
|
+
return readsAsInstructions(name, text);
|
|
14611
|
+
}
|
|
14612
|
+
var UI_COPY_NAME = /placeholder|label|tooltip|hint|title|caption|toast|button|error|empty_?state|copy/i;
|
|
14613
|
+
function isOnlyDisplayed(lines, identifier, definitionLine) {
|
|
14614
|
+
const ident = escapeRegExp(identifier);
|
|
14615
|
+
const reference = new RegExp(`(?<![\\w$.])${ident}(?![\\w$])`);
|
|
14616
|
+
const display = new RegExp(`\\{\\s*${ident}\\s*\\}(?!\\s*from)|[\\w-]+=\\{\\s*${ident}\\s*\\}|\\b(?:console|logger|log)\\.\\w+\\([^)]*\\b${ident}\\b|\\b(?:toast|alert|notify)\\w*\\([^)]*\\b${ident}\\b`);
|
|
14617
|
+
let references = 0;
|
|
14618
|
+
for (let index = 0;index < lines.length; index += 1) {
|
|
14619
|
+
const line = lines[index];
|
|
14620
|
+
if (index === definitionLine - 1 || !reference.test(line))
|
|
14621
|
+
continue;
|
|
14622
|
+
if (/^\s*(?:\/\/|#|\*|export\s*(?:default\s+)?\{|export\s+default\s+[\w$]+\s*;?\s*$)/.test(line))
|
|
14623
|
+
continue;
|
|
14624
|
+
references += 1;
|
|
14625
|
+
if (!display.test(line))
|
|
14626
|
+
return false;
|
|
14627
|
+
}
|
|
14628
|
+
return references > 0;
|
|
14629
|
+
}
|
|
14399
14630
|
function hasNearbyRole(lines, line) {
|
|
14400
14631
|
for (let i = Math.max(0, line - 4);i < Math.min(lines.length, line + 3); i += 1) {
|
|
14401
14632
|
if (/\brole\b\s*["']?\s*[:=]/.test(lines[i]))
|
|
@@ -14410,21 +14641,100 @@ function isDirectModelInput(key, value, path, lines, line, modelFiles) {
|
|
|
14410
14641
|
if (modelFiles.has(path)) {
|
|
14411
14642
|
return DIRECT_PROMPT_KEYS.has(key) || key === "content" && hasNearbyRole(lines, line);
|
|
14412
14643
|
}
|
|
14644
|
+
if (PROMPT_CONFIG_KEYS.has(key))
|
|
14645
|
+
return true;
|
|
14413
14646
|
return DIRECT_PROMPT_KEYS.has(key) && instructionScore(value) >= 2;
|
|
14414
14647
|
}
|
|
14648
|
+
function isModelCallee(callee, path, lines, modelFiles) {
|
|
14649
|
+
return MODEL_CALLEE.test(callee) || calleeImportedFromModelFile(callee, path, lines, modelFiles) || localHelperCallsModel(callee, lines);
|
|
14650
|
+
}
|
|
14651
|
+
function importSpecifiers(lines) {
|
|
14652
|
+
return lines.flatMap((line) => [...line.matchAll(/\bfrom\s+["']?([.\w/@$-]+)["']?|\bimport\s*\(\s*["']([^"']+)["']|\brequire\(\s*["']([^"']+)["']/g)].map((match) => match[1] ?? match[2] ?? match[3]));
|
|
14653
|
+
}
|
|
14654
|
+
var MODEL_ENDPOINT = /api\.anthropic\.com|api\.openai\.com|openrouter\.ai|generativelanguage\.googleapis\.com|api\.mistral\.ai|api\.groq\.com|api\.together\.(?:xyz|ai)|api\.deepseek\.com|\/chat\/completions\b|\/v1\/messages\b|\/v1\/responses\b/;
|
|
14655
|
+
var HTTP_CALLEE = /^(?:fetch|axios(?:\.post|\.request)?|got(?:\.post)?|ky(?:\.post)?|request|ofetch|\$fetch)$/;
|
|
14656
|
+
function targetsModelEndpoint(target, lines) {
|
|
14657
|
+
if (MODEL_ENDPOINT.test(target))
|
|
14658
|
+
return true;
|
|
14659
|
+
const name = /^(?:[A-Za-z_$][\w$]*\.)*([A-Za-z_$][\w$]*)$/.exec(target.trim())?.[1];
|
|
14660
|
+
if (!name)
|
|
14661
|
+
return false;
|
|
14662
|
+
const binding = new RegExp(`\\b${escapeRegExp(name)}\\s*[:=](?!=)`);
|
|
14663
|
+
return lines.some((line, index) => {
|
|
14664
|
+
const match = binding.exec(line);
|
|
14665
|
+
if (!match)
|
|
14666
|
+
return false;
|
|
14667
|
+
const initializer = [line.slice(match.index), ...lines.slice(index + 1, index + 4)].join(`
|
|
14668
|
+
`);
|
|
14669
|
+
const end = initializer.search(/;|,\s*$/m);
|
|
14670
|
+
return MODEL_ENDPOINT.test(end < 0 ? initializer : initializer.slice(0, end));
|
|
14671
|
+
});
|
|
14672
|
+
}
|
|
14673
|
+
function fileReachesModel(path, lines, modelFiles) {
|
|
14674
|
+
if (modelFiles.has(path))
|
|
14675
|
+
return true;
|
|
14676
|
+
if (lines.some((line) => MODEL_ENDPOINT.test(line)))
|
|
14677
|
+
return true;
|
|
14678
|
+
const python = extname7(path) === ".py";
|
|
14679
|
+
return importSpecifiers(lines).some((spec) => [...modelFiles].some((modelFile) => specifierResolvesTo(spec, path, modelFile, python)));
|
|
14680
|
+
}
|
|
14681
|
+
function modelFileImports(path, rootDir, modelFiles, fileCache) {
|
|
14682
|
+
return [...modelFiles].some((modelFile) => {
|
|
14683
|
+
if (modelFile === path)
|
|
14684
|
+
return false;
|
|
14685
|
+
const lines = readFileLines(rootDir, modelFile, fileCache);
|
|
14686
|
+
return Boolean(lines && importSpecifiers(lines).some((spec) => specifierResolvesTo(spec, modelFile, path, extname7(modelFile) === ".py")));
|
|
14687
|
+
});
|
|
14688
|
+
}
|
|
14689
|
+
var PASS_THROUGH_CALLEE = /^(?:Object\.(?:freeze|seal|assign)|structuredClone|Promise\.resolve|JSON\.stringify|(?:_\.|lodash\.)?(?:cloneDeep|clone|merge)|deepFreeze|defu)$/;
|
|
14690
|
+
function escapesAsItself(use, kind) {
|
|
14691
|
+
return use.escape !== undefined && (kind === undefined || use.escape === kind) && use.callees.every((callee) => PASS_THROUGH_CALLEE.test(callee));
|
|
14692
|
+
}
|
|
14693
|
+
function keyedObjectReachesModel(consumer, path, lines, modelFiles) {
|
|
14694
|
+
if (consumer.kind === "chat_message")
|
|
14695
|
+
return true;
|
|
14696
|
+
return consumer.uses.some((use) => escapesAsItself(use) || use.callees.some((callee, index) => isModelCallee(callee, path, lines, modelFiles) || HTTP_CALLEE.test(callee) && targetsModelEndpoint(use.targets[index] ?? "", lines)));
|
|
14697
|
+
}
|
|
14698
|
+
var PROMPT_CONFIG_KEYS = new Set([
|
|
14699
|
+
"instructions",
|
|
14700
|
+
"instruction",
|
|
14701
|
+
"systemPrompt",
|
|
14702
|
+
"system_prompt",
|
|
14703
|
+
"systemMessage",
|
|
14704
|
+
"system_message",
|
|
14705
|
+
"systemInstruction",
|
|
14706
|
+
"system_instruction",
|
|
14707
|
+
"backstory"
|
|
14708
|
+
]);
|
|
14415
14709
|
function promotePromptLiteralCandidate(candidate, rootDir, confidence2, fileCache, files) {
|
|
14416
14710
|
const lines = readFileLines(rootDir, candidate.path, fileCache);
|
|
14417
14711
|
if (!lines)
|
|
14418
14712
|
return;
|
|
14419
|
-
const definition = resolvePromptLiteralDefinition(lines, candidate.startLine);
|
|
14713
|
+
const definition = resolvePromptLiteralDefinition(lines, candidate.startLine, jsSources.get(`${rootDir}::${candidate.path}`), candidate.excerpt);
|
|
14420
14714
|
if (!definition)
|
|
14421
14715
|
return;
|
|
14422
14716
|
const value = definition.text.trim();
|
|
14423
14717
|
const literalText = value.replace(/\$\{[^}]*\}|\{[A-Za-z_][\w.]*\}/g, "").trim();
|
|
14424
|
-
|
|
14718
|
+
const minChars = definition.key && PROMPT_CONFIG_KEYS.has(definition.key) ? 1 : MIN_RESOLVED_PROMPT_CHARS;
|
|
14719
|
+
if (literalText.length < minChars || isCodeLikeContent(value))
|
|
14720
|
+
return;
|
|
14721
|
+
if (isTestInput(candidate.path))
|
|
14425
14722
|
return;
|
|
14426
14723
|
const key = definition.key ?? (definition.identifier && DIRECT_PROMPT_KEYS.has(definition.identifier) ? definition.identifier : undefined);
|
|
14427
14724
|
let use;
|
|
14725
|
+
const jsSource = jsSources.get(`${rootDir}::${candidate.path}`);
|
|
14726
|
+
if (definition.key && !PROMPT_CONFIG_KEYS.has(definition.key) && !CONFIG_EXTENSIONS.has(extname7(candidate.path).toLowerCase())) {
|
|
14727
|
+
const exportUsed = () => modelFileImports(candidate.path, rootDir, files.model, fileCache);
|
|
14728
|
+
if (jsSource) {
|
|
14729
|
+
const consumer = keyedValueConsumer(jsSource, definition.line, definition.key, definition.column);
|
|
14730
|
+
if (!fileReachesModel(candidate.path, lines, files.model) && !(consumer.kind === "uses" && consumer.uses.some((use2) => escapesAsItself(use2, "export")) && exportUsed()))
|
|
14731
|
+
return;
|
|
14732
|
+
if (!keyedObjectReachesModel(consumer, candidate.path, lines, files.model))
|
|
14733
|
+
return;
|
|
14734
|
+
} else if (!fileReachesModel(candidate.path, lines, files.model) && !exportUsed()) {
|
|
14735
|
+
return;
|
|
14736
|
+
}
|
|
14737
|
+
}
|
|
14428
14738
|
if (key && isDirectModelInput(key, value, candidate.path, lines, definition.line, files.model)) {
|
|
14429
14739
|
use = { path: candidate.path, line: definition.line, key };
|
|
14430
14740
|
}
|
|
@@ -14433,9 +14743,15 @@ function promotePromptLiteralCandidate(candidate, rootDir, confidence2, fileCach
|
|
|
14433
14743
|
allowReference: readsAsInstructions(definition.identifier, value)
|
|
14434
14744
|
});
|
|
14435
14745
|
}
|
|
14436
|
-
if (!use)
|
|
14437
|
-
return;
|
|
14438
14746
|
const name = definition.identifier ?? definition.key;
|
|
14747
|
+
const unused = !use;
|
|
14748
|
+
if (!use) {
|
|
14749
|
+
if (!name || !readsAsUnusedPrompt(name, value))
|
|
14750
|
+
return;
|
|
14751
|
+
if (definition.identifier && isOnlyDisplayed(lines, definition.identifier, definition.line))
|
|
14752
|
+
return;
|
|
14753
|
+
use = { path: candidate.path, line: definition.line, key: "unused" };
|
|
14754
|
+
}
|
|
14439
14755
|
const evidence = [{ path: candidate.path, line: definition.line, reason: `deterministic detector ${candidate.signal}` }];
|
|
14440
14756
|
const sameSite = use.path === candidate.path && use.line === definition.line;
|
|
14441
14757
|
if (!sameSite) {
|
|
@@ -14446,13 +14762,13 @@ function promotePromptLiteralCandidate(candidate, rootDir, confidence2, fileCach
|
|
|
14446
14762
|
});
|
|
14447
14763
|
}
|
|
14448
14764
|
return {
|
|
14449
|
-
id: stableId("prompt", `${pathStem(candidate.path)}:L${definition.line}`),
|
|
14765
|
+
id: stableId("prompt", `${pathStem(candidate.path)}:L${definition.line}${definition.column ? `C${definition.column}` : ""}`),
|
|
14450
14766
|
type: "prompt",
|
|
14451
14767
|
name: name ? titleFromId(name) : `Inline Prompt (${candidate.path}:${definition.line})`,
|
|
14452
14768
|
scope: "shared",
|
|
14453
14769
|
usedByAgentIds: [],
|
|
14454
|
-
confidence: use.referenceOnly ? Math.min(confidence2, REFERENCED_PROMPT_CONFIDENCE) : confidence2,
|
|
14455
|
-
confidenceReason: use.referenceOnly ? `Deterministic: instruction-like literal ${name} is referenced at ${use.path}:${use.line} through ${use.via}, but no prompt key (system, instructions, content) was found at the call.` : sameSite ? `Deterministic: string literal written under the ${use.key} key at ${candidate.path}:${definition.line}.` : `Deterministic: string literal ${name} passed to a model call as ${use.key} at ${use.path}:${use.line}.`,
|
|
14770
|
+
confidence: unused ? Math.min(confidence2, UNUSED_PROMPT_CONFIDENCE) : use.referenceOnly ? Math.min(confidence2, REFERENCED_PROMPT_CONFIDENCE) : confidence2,
|
|
14771
|
+
confidenceReason: unused ? `Deterministic: instruction-like literal ${name} at ${candidate.path}:${definition.line}; no model call using it was found, so it may be unused.` : use.referenceOnly ? `Deterministic: instruction-like literal ${name} is referenced at ${use.path}:${use.line} through ${use.via}, but no prompt key (system, instructions, content) was found at the call.` : sameSite ? `Deterministic: string literal written under the ${use.key} key at ${candidate.path}:${definition.line}.` : `Deterministic: string literal ${name} passed to a model call as ${use.key} at ${use.path}:${use.line}.`,
|
|
14456
14772
|
evidence,
|
|
14457
14773
|
body: definition.text
|
|
14458
14774
|
};
|
|
@@ -14484,6 +14800,14 @@ function mergePromotedDuplicate(existing, next) {
|
|
|
14484
14800
|
existing.body = next.body;
|
|
14485
14801
|
}
|
|
14486
14802
|
function promoteHarnessCandidates(report, rootDir) {
|
|
14803
|
+
jsSources.clear();
|
|
14804
|
+
try {
|
|
14805
|
+
return promoteAll(report, rootDir);
|
|
14806
|
+
} finally {
|
|
14807
|
+
jsSources.clear();
|
|
14808
|
+
}
|
|
14809
|
+
}
|
|
14810
|
+
function promoteAll(report, rootDir) {
|
|
14487
14811
|
const fileCache = new Map;
|
|
14488
14812
|
const byId = new Map;
|
|
14489
14813
|
const files = {
|
|
@@ -14500,7 +14824,9 @@ function promoteHarnessCandidates(report, rootDir) {
|
|
|
14500
14824
|
artifact = promoteToolCandidate(candidate, rootDir, confidence2, fileCache);
|
|
14501
14825
|
break;
|
|
14502
14826
|
case "prompt_file":
|
|
14503
|
-
if (candidate.signal === "prompt_module.name_hint" && (
|
|
14827
|
+
if (candidate.signal === "prompt_module.name_hint" && (isTestInput(candidate.path) || !buildsPrompts(candidate.path, readFileLines(rootDir, candidate.path, fileCache))))
|
|
14828
|
+
break;
|
|
14829
|
+
if (isTestInput(candidate.path))
|
|
14504
14830
|
break;
|
|
14505
14831
|
artifact = promotePromptFileCandidate(candidate, confidence2);
|
|
14506
14832
|
break;
|
|
@@ -14528,245 +14854,6 @@ function promoteHarnessCandidates(report, rootDir) {
|
|
|
14528
14854
|
return [...byId.values()];
|
|
14529
14855
|
}
|
|
14530
14856
|
|
|
14531
|
-
// src/harness-wrangler-bindings.ts
|
|
14532
|
-
import { lstatSync as lstatSync7, readdirSync as readdirSync4, readFileSync as readFileSync12 } from "node:fs";
|
|
14533
|
-
import { join as join9, relative as relative6 } from "node:path";
|
|
14534
|
-
var WRANGLER_FILE = /^wrangler\.jsonc?$/;
|
|
14535
|
-
var SKIPPED_DIRS2 = new Set(["node_modules", ".git", ".wrangler", "dist", "build", ".next", ".turbo", "vendor"]);
|
|
14536
|
-
var MAX_DEPTH = 4;
|
|
14537
|
-
var AGENT_CLASS = /Agent(?:V\d+)?$/;
|
|
14538
|
-
function stripJsonc2(text) {
|
|
14539
|
-
let out = "";
|
|
14540
|
-
let inString = false;
|
|
14541
|
-
for (let i = 0;i < text.length; i += 1) {
|
|
14542
|
-
const ch = text[i];
|
|
14543
|
-
if (inString) {
|
|
14544
|
-
out += ch;
|
|
14545
|
-
if (ch === "\\") {
|
|
14546
|
-
out += text[i + 1] ?? "";
|
|
14547
|
-
i += 1;
|
|
14548
|
-
} else if (ch === '"') {
|
|
14549
|
-
inString = false;
|
|
14550
|
-
}
|
|
14551
|
-
continue;
|
|
14552
|
-
}
|
|
14553
|
-
if (ch === '"') {
|
|
14554
|
-
inString = true;
|
|
14555
|
-
out += ch;
|
|
14556
|
-
} else if (ch === "/" && text[i + 1] === "/") {
|
|
14557
|
-
while (i < text.length && text[i] !== `
|
|
14558
|
-
`)
|
|
14559
|
-
i += 1;
|
|
14560
|
-
out += `
|
|
14561
|
-
`;
|
|
14562
|
-
} else if (ch === "/" && text[i + 1] === "*") {
|
|
14563
|
-
i += 2;
|
|
14564
|
-
while (i < text.length && !(text[i] === "*" && text[i + 1] === "/")) {
|
|
14565
|
-
if (text[i] === `
|
|
14566
|
-
`)
|
|
14567
|
-
out += `
|
|
14568
|
-
`;
|
|
14569
|
-
i += 1;
|
|
14570
|
-
}
|
|
14571
|
-
i += 1;
|
|
14572
|
-
} else {
|
|
14573
|
-
out += ch;
|
|
14574
|
-
}
|
|
14575
|
-
}
|
|
14576
|
-
return out.replace(/,(\s*[}\]])/g, "$1");
|
|
14577
|
-
}
|
|
14578
|
-
function findWranglerFiles(rootDir) {
|
|
14579
|
-
const found = [];
|
|
14580
|
-
const walk = (dir, depth) => {
|
|
14581
|
-
let entries;
|
|
14582
|
-
try {
|
|
14583
|
-
entries = readdirSync4(dir);
|
|
14584
|
-
} catch {
|
|
14585
|
-
return;
|
|
14586
|
-
}
|
|
14587
|
-
for (const name of entries) {
|
|
14588
|
-
const abs = join9(dir, name);
|
|
14589
|
-
let stat;
|
|
14590
|
-
try {
|
|
14591
|
-
stat = lstatSync7(abs);
|
|
14592
|
-
} catch {
|
|
14593
|
-
continue;
|
|
14594
|
-
}
|
|
14595
|
-
if (stat.isDirectory()) {
|
|
14596
|
-
if (depth < MAX_DEPTH && !SKIPPED_DIRS2.has(name) && !name.startsWith("."))
|
|
14597
|
-
walk(abs, depth + 1);
|
|
14598
|
-
} else if (stat.isFile() && WRANGLER_FILE.test(name)) {
|
|
14599
|
-
found.push(abs);
|
|
14600
|
-
}
|
|
14601
|
-
}
|
|
14602
|
-
};
|
|
14603
|
-
walk(rootDir, 0);
|
|
14604
|
-
return found.sort();
|
|
14605
|
-
}
|
|
14606
|
-
function lineOf(text, className) {
|
|
14607
|
-
const index = text.search(new RegExp(`"class_name"\\s*:\\s*"${className.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}"`));
|
|
14608
|
-
return index < 0 ? undefined : text.slice(0, index).split(`
|
|
14609
|
-
`).length;
|
|
14610
|
-
}
|
|
14611
|
-
function workerDir(path) {
|
|
14612
|
-
const slash = path.lastIndexOf("/");
|
|
14613
|
-
return slash < 0 ? "" : path.slice(0, slash);
|
|
14614
|
-
}
|
|
14615
|
-
function detectBoundRuntimeClasses(rootDir) {
|
|
14616
|
-
const byClass = new Map;
|
|
14617
|
-
for (const abs of findWranglerFiles(rootDir)) {
|
|
14618
|
-
let text;
|
|
14619
|
-
let config2;
|
|
14620
|
-
try {
|
|
14621
|
-
text = readFileSync12(abs, "utf8");
|
|
14622
|
-
config2 = JSON.parse(stripJsonc2(text));
|
|
14623
|
-
} catch {
|
|
14624
|
-
continue;
|
|
14625
|
-
}
|
|
14626
|
-
if (!config2 || typeof config2 !== "object")
|
|
14627
|
-
continue;
|
|
14628
|
-
const path = relative6(rootDir, abs).split("\\").join("/");
|
|
14629
|
-
const root = config2;
|
|
14630
|
-
const sections2 = [root, ...Object.values(root.env ?? {})];
|
|
14631
|
-
for (const section of sections2) {
|
|
14632
|
-
if (!section || typeof section !== "object")
|
|
14633
|
-
continue;
|
|
14634
|
-
const s = section;
|
|
14635
|
-
const durable = s.durable_objects?.bindings;
|
|
14636
|
-
const entries = [
|
|
14637
|
-
...Array.isArray(durable) ? durable.map((b) => ["durable_object", b]) : [],
|
|
14638
|
-
...Array.isArray(s.workflows) ? s.workflows.map((w) => ["workflow", w]) : []
|
|
14639
|
-
];
|
|
14640
|
-
for (const [kind, raw] of entries) {
|
|
14641
|
-
if (!raw || typeof raw !== "object")
|
|
14642
|
-
continue;
|
|
14643
|
-
const entry = raw;
|
|
14644
|
-
const className = typeof entry.class_name === "string" ? entry.class_name : "";
|
|
14645
|
-
const scriptName = typeof entry.script_name === "string" && entry.script_name ? entry.script_name : undefined;
|
|
14646
|
-
const key = `${className}|${scriptName ? "external" : `config:${path}`}`;
|
|
14647
|
-
if (!className || byClass.has(key))
|
|
14648
|
-
continue;
|
|
14649
|
-
const binding = typeof (kind === "workflow" ? entry.binding : entry.name) === "string" ? String(kind === "workflow" ? entry.binding : entry.name) : className;
|
|
14650
|
-
byClass.set(key, {
|
|
14651
|
-
className,
|
|
14652
|
-
kind,
|
|
14653
|
-
binding,
|
|
14654
|
-
...scriptName ? { scriptName } : {},
|
|
14655
|
-
path,
|
|
14656
|
-
line: lineOf(text, className)
|
|
14657
|
-
});
|
|
14658
|
-
}
|
|
14659
|
-
}
|
|
14660
|
-
}
|
|
14661
|
-
return [...byClass.values()];
|
|
14662
|
-
}
|
|
14663
|
-
function norm(value) {
|
|
14664
|
-
return typeof value === "string" ? value.toLowerCase().replace(/[^a-z0-9]/g, "") : "";
|
|
14665
|
-
}
|
|
14666
|
-
function itemPaths(item) {
|
|
14667
|
-
const paths = [];
|
|
14668
|
-
for (const value of [item.root, item.sourcePath]) {
|
|
14669
|
-
if (typeof value === "string" && value && value !== ".")
|
|
14670
|
-
paths.push(value.replace(/^\.\//, ""));
|
|
14671
|
-
}
|
|
14672
|
-
for (const entry of Array.isArray(item.evidence) ? item.evidence : []) {
|
|
14673
|
-
const path = entry && typeof entry === "object" ? entry.path : undefined;
|
|
14674
|
-
if (typeof path === "string" && path)
|
|
14675
|
-
paths.push(path.replace(/^\.\//, ""));
|
|
14676
|
-
}
|
|
14677
|
-
return paths;
|
|
14678
|
-
}
|
|
14679
|
-
function withinWorker(path, dir, otherDirs) {
|
|
14680
|
-
const inside = (d) => d === "" || path === d || path.startsWith(`${d}/`);
|
|
14681
|
-
return inside(dir) && !otherDirs.some((other) => other.length > dir.length && inside(other));
|
|
14682
|
-
}
|
|
14683
|
-
function graphNamesClass(graph, bound, all) {
|
|
14684
|
-
const target = norm(bound.className);
|
|
14685
|
-
const named = (name) => {
|
|
14686
|
-
if (typeof name !== "string")
|
|
14687
|
-
return false;
|
|
14688
|
-
const bare = name.replace(/\s*\([^)]*\)\s*$/, "");
|
|
14689
|
-
return norm(bare) === target || bare.split(/[^A-Za-z0-9_]+/).some((word) => norm(word) === target);
|
|
14690
|
-
};
|
|
14691
|
-
const sameName = bound.scriptName ? [bound] : all.filter((other) => other.className === bound.className && !other.scriptName);
|
|
14692
|
-
const dir = workerDir(bound.path);
|
|
14693
|
-
const otherDirs = sameName.map((other) => workerDir(other.path)).filter((other) => other !== dir);
|
|
14694
|
-
const covers = (item) => {
|
|
14695
|
-
if (!named(item.name))
|
|
14696
|
-
return false;
|
|
14697
|
-
if (sameName.length < 2)
|
|
14698
|
-
return true;
|
|
14699
|
-
return itemPaths(item).some((path) => withinWorker(path, dir, otherDirs));
|
|
14700
|
-
};
|
|
14701
|
-
return graph.runtimeAgents.some(covers) || graph.artifacts.some(covers);
|
|
14702
|
-
}
|
|
14703
|
-
function bindingReason(bound) {
|
|
14704
|
-
const what = bound.kind === "workflow" ? "Workflow" : "Durable Object";
|
|
14705
|
-
const where = bound.scriptName ? ` served by the external Worker "${bound.scriptName}"` : "";
|
|
14706
|
-
return `${what} binding ${bound.binding} -> class ${bound.className}${where}`;
|
|
14707
|
-
}
|
|
14708
|
-
function uniqueId(base, taken) {
|
|
14709
|
-
let id = base;
|
|
14710
|
-
for (let n = 2;taken.has(id); n += 1)
|
|
14711
|
-
id = `${base}-${n}`;
|
|
14712
|
-
taken.add(id);
|
|
14713
|
-
return id;
|
|
14714
|
-
}
|
|
14715
|
-
function mergeBoundRuntimeClasses(graph, rootDir) {
|
|
14716
|
-
if (process.env.MODA_HARNESS_DETERMINISTIC_MERGE === "0")
|
|
14717
|
-
return { added: 0 };
|
|
14718
|
-
let bound;
|
|
14719
|
-
try {
|
|
14720
|
-
bound = detectBoundRuntimeClasses(rootDir);
|
|
14721
|
-
} catch {
|
|
14722
|
-
return { added: 0 };
|
|
14723
|
-
}
|
|
14724
|
-
const taken = new Set([
|
|
14725
|
-
...graph.runtimeAgents.map((agent) => agent.id),
|
|
14726
|
-
...graph.artifacts.map((artifact) => artifact.id)
|
|
14727
|
-
]);
|
|
14728
|
-
let added = 0;
|
|
14729
|
-
for (const entry of bound) {
|
|
14730
|
-
if (graphNamesClass(graph, entry, bound))
|
|
14731
|
-
continue;
|
|
14732
|
-
const evidence = [{ path: entry.path, ...entry.line ? { line: entry.line } : {}, reason: bindingReason(entry) }];
|
|
14733
|
-
const slug = entry.className.replace(/[^A-Za-z0-9]+/g, "-").toLowerCase();
|
|
14734
|
-
if (entry.kind === "durable_object" && AGENT_CLASS.test(entry.className) && !entry.scriptName) {
|
|
14735
|
-
const agent = {
|
|
14736
|
-
id: uniqueId(`agent.bound.${slug}`, taken),
|
|
14737
|
-
name: entry.className,
|
|
14738
|
-
kind: "runtime_agent",
|
|
14739
|
-
purpose: "Agent class bound as a Durable Object.",
|
|
14740
|
-
root: ".",
|
|
14741
|
-
entrypointIds: [],
|
|
14742
|
-
channelAdapterIds: [],
|
|
14743
|
-
artifactIds: [],
|
|
14744
|
-
identityNamespaceIds: [],
|
|
14745
|
-
deploymentIds: [],
|
|
14746
|
-
frameworkIds: [],
|
|
14747
|
-
modelProviderIds: [],
|
|
14748
|
-
confidence: 0.6,
|
|
14749
|
-
evidence
|
|
14750
|
-
};
|
|
14751
|
-
graph.runtimeAgents.push(agent);
|
|
14752
|
-
} else {
|
|
14753
|
-
const artifact = {
|
|
14754
|
-
id: uniqueId(`entrypoint.bound.${slug}`, taken),
|
|
14755
|
-
type: "entrypoint",
|
|
14756
|
-
name: entry.className,
|
|
14757
|
-
scope: "shared",
|
|
14758
|
-
sourcePath: entry.path,
|
|
14759
|
-
usedByAgentIds: [],
|
|
14760
|
-
confidence: 0.6,
|
|
14761
|
-
evidence
|
|
14762
|
-
};
|
|
14763
|
-
graph.artifacts.push(artifact);
|
|
14764
|
-
}
|
|
14765
|
-
added += 1;
|
|
14766
|
-
}
|
|
14767
|
-
return { added };
|
|
14768
|
-
}
|
|
14769
|
-
|
|
14770
14857
|
// src/harness-sync-limits.ts
|
|
14771
14858
|
var MAX_HARNESS_SYNC_GRAPH_BYTES = 2000000;
|
|
14772
14859
|
function assertHarnessGraphSyncSize(graph) {
|
|
@@ -14785,8 +14872,8 @@ function assertHarnessGraphSyncSize(graph) {
|
|
|
14785
14872
|
}
|
|
14786
14873
|
// src/harness.ts
|
|
14787
14874
|
var MODA_DIR = ".moda";
|
|
14788
|
-
var HARNESS_PATH =
|
|
14789
|
-
var HARNESS_SUMMARY_PATH =
|
|
14875
|
+
var HARNESS_PATH = join9(MODA_DIR, "harness.json");
|
|
14876
|
+
var HARNESS_SUMMARY_PATH = join9(MODA_DIR, "HARNESS.md");
|
|
14790
14877
|
var SCHEMA_VERSION = "harness.v0.1";
|
|
14791
14878
|
var REPORT_JSON_BEGIN = "MODA_HARNESS_REPORT_JSON_BEGIN";
|
|
14792
14879
|
var REPORT_JSON_END = "MODA_HARNESS_REPORT_JSON_END";
|
|
@@ -14952,7 +15039,7 @@ async function runHarnessCommand(context) {
|
|
|
14952
15039
|
report: {
|
|
14953
15040
|
reportId: report.reportId,
|
|
14954
15041
|
reportHash,
|
|
14955
|
-
path: normalizePath2(
|
|
15042
|
+
path: normalizePath2(relative6(rootDir, reportPath)) || ".moda/harness-report.json"
|
|
14956
15043
|
},
|
|
14957
15044
|
validation,
|
|
14958
15045
|
approval: {
|
|
@@ -15098,7 +15185,7 @@ async function runHarnessCommand(context) {
|
|
|
15098
15185
|
throw new CliInputError("Focused remote prompt analysis is not supported yet.", "Use local --analyst=claude|codex|cursor|local-scan, or drop --concern for a full remote report.");
|
|
15099
15186
|
}
|
|
15100
15187
|
if (context.flags["github-actions"] === "true") {
|
|
15101
|
-
const { runGithubActionsAnalyze } = await import("./harness-github-actions-
|
|
15188
|
+
const { runGithubActionsAnalyze } = await import("./harness-github-actions-yev2yrkr.js");
|
|
15102
15189
|
const result = await runGithubActionsAnalyze(rootDir, {
|
|
15103
15190
|
writeReport: (report2) => {
|
|
15104
15191
|
const normalized = normalizeHarnessReport(report2);
|
|
@@ -15220,7 +15307,7 @@ async function runHarnessCommand(context) {
|
|
|
15220
15307
|
report: {
|
|
15221
15308
|
reportId: approval.report.reportId,
|
|
15222
15309
|
reportHash: hashHarnessReport(approval.report),
|
|
15223
|
-
path: normalizePath2(
|
|
15310
|
+
path: normalizePath2(relative6(rootDir, reportPath)) || ".moda/harness-report.json"
|
|
15224
15311
|
},
|
|
15225
15312
|
validation: approval.validation,
|
|
15226
15313
|
approval: approval.approval
|
|
@@ -15243,6 +15330,7 @@ async function runHarnessCommand(context) {
|
|
|
15243
15330
|
throw new CliInputError("Missing output path for --out.", "Usage: moda harness candidates --promote=<concern|all> --out=<file>");
|
|
15244
15331
|
}
|
|
15245
15332
|
const artifacts = deterministicArtifacts(rootDir, promote === "all" ? undefined : promote);
|
|
15333
|
+
tagComponentStatus({ runtimeAgents: [], artifacts }, rootDir);
|
|
15246
15334
|
const promoted = { concern: promote, artifacts };
|
|
15247
15335
|
const promoteWritten = [];
|
|
15248
15336
|
if (promoteOut && !context.dryRun) {
|
|
@@ -15310,7 +15398,7 @@ async function runHarnessCommand(context) {
|
|
|
15310
15398
|
return { exitCode: 0 };
|
|
15311
15399
|
}
|
|
15312
15400
|
case "status": {
|
|
15313
|
-
const manifestPath =
|
|
15401
|
+
const manifestPath = join9(rootDir, HARNESS_PATH);
|
|
15314
15402
|
const graph = existsSync8(manifestPath) ? readHarnessGraph(manifestPath) : scanHarness({
|
|
15315
15403
|
rootDir,
|
|
15316
15404
|
tenantId: tenant?.tenantId,
|
|
@@ -15451,10 +15539,10 @@ function emitWrittenArtifacts(context, written, description) {
|
|
|
15451
15539
|
}
|
|
15452
15540
|
}
|
|
15453
15541
|
async function runPromptConcernAnalysis(context, rootDir, scanPlan, tenant) {
|
|
15454
|
-
const manifest =
|
|
15542
|
+
const manifest = join9(rootDir, ".moda/prompts.yml");
|
|
15455
15543
|
let existing = [];
|
|
15456
15544
|
if (existsSync8(manifest)) {
|
|
15457
|
-
const document = $parseDocument(
|
|
15545
|
+
const document = $parseDocument(readFileSync12(manifest, "utf8"));
|
|
15458
15546
|
if (document.errors.length)
|
|
15459
15547
|
throw new CliInputError("Invalid prompt manifest.", document.errors[0].message);
|
|
15460
15548
|
existing = document.toJS({ maxAliasCount: 20 })?.sources ?? [];
|
|
@@ -15708,7 +15796,7 @@ function readExternalAnalystReport(rootDir, result, adapter, concern) {
|
|
|
15708
15796
|
result.stderr
|
|
15709
15797
|
].join(`
|
|
15710
15798
|
`));
|
|
15711
|
-
debugHint = `Raw analyst output saved to ${
|
|
15799
|
+
debugHint = `Raw analyst output saved to ${join9(MODA_DIR, "analyst-debug.log")} for debugging.`;
|
|
15712
15800
|
} catch {}
|
|
15713
15801
|
throw new CliInputError(`Harness analyst ${adapter} did not return a harness report.`, [
|
|
15714
15802
|
`Expected ${HARNESS_REPORT_PATH} or final JSON between ${REPORT_JSON_BEGIN} and ${REPORT_JSON_END}.`,
|
|
@@ -15819,6 +15907,7 @@ function repairExternalAnalystReport(report, rootDir, options = {}) {
|
|
|
15819
15907
|
mergeDeterministicArtifacts(normalized.graph, rootDir, { concern: options.concern });
|
|
15820
15908
|
if (!options.concern || options.concern === "topology")
|
|
15821
15909
|
mergeBoundRuntimeClasses(normalized.graph, rootDir);
|
|
15910
|
+
tagComponentStatus(normalized.graph, rootDir);
|
|
15822
15911
|
hydratePromptAndToolBodies(normalized.graph, rootDir);
|
|
15823
15912
|
const unverified = new Set;
|
|
15824
15913
|
for (const artifact of normalized.graph.artifacts) {
|
|
@@ -16115,7 +16204,7 @@ function repairCitationLines(report, rootDir) {
|
|
|
16115
16204
|
continue;
|
|
16116
16205
|
let text;
|
|
16117
16206
|
try {
|
|
16118
|
-
text =
|
|
16207
|
+
text = readFileSync12(candidatePath, "utf8");
|
|
16119
16208
|
} catch {
|
|
16120
16209
|
continue;
|
|
16121
16210
|
}
|
|
@@ -16721,14 +16810,14 @@ function createPromptAnalystIsolation(adapter, rootDir) {
|
|
|
16721
16810
|
const serverPath = bundledServer ? bundled : source;
|
|
16722
16811
|
const command = bundledServer ? process.execPath : resolveBunRuntime();
|
|
16723
16812
|
const serverArgs = [serverPath, "--root", rootDir];
|
|
16724
|
-
const tempPath = mkdtempSync2(
|
|
16813
|
+
const tempPath = mkdtempSync2(join9(tmpdir2(), "moda-prompt-analyst-"));
|
|
16725
16814
|
const cleanup = () => {
|
|
16726
16815
|
try {
|
|
16727
16816
|
rmSync4(tempPath, { recursive: true, force: true });
|
|
16728
16817
|
} catch {}
|
|
16729
16818
|
};
|
|
16730
16819
|
if (adapter === "claude") {
|
|
16731
|
-
const configPath =
|
|
16820
|
+
const configPath = join9(tempPath, "claude-mcp.json");
|
|
16732
16821
|
writeFileSync5(configPath, JSON.stringify({ mcpServers: { "moda-prompt-source": { command, args: serverArgs } } }));
|
|
16733
16822
|
return { configPath, cleanup };
|
|
16734
16823
|
}
|
|
@@ -16939,8 +17028,10 @@ function renderExternalHarnessAnalystPrompt(options) {
|
|
|
16939
17028
|
"",
|
|
16940
17029
|
'Use exact field names and numeric confidence values from 0 to 1. Do not write string confidence values like "high". Do not use confidence >= 0.90 unless the claim is direct evidence from the cited line(s).',
|
|
16941
17030
|
`Name each runtime agent after the class or exported symbol that defines it, adding the role in parentheses when helpful, e.g. "AutonomousPlanWorkflow (weekly planner)"; a Cloudflare Workflow or Durable Object class keeps its class name. Never emit an agent whose class is not defined or exported in this source tree: a binding to another worker's class (e.g. a wrangler script_name binding) is a deployment detail, not an agent of this repo.`,
|
|
17031
|
+
"Include every real harness component in your scope whether or not anything uses it: a tool defined but never registered, a prompt file or prompt literal nothing references, an agent, Workflow, or Durable Object class defined or exported but never bound, an eval or fixture that tests the agent, a model config declared but unused. Never drop a component for being unused, dead, or legacy; Moda tags its deployment status separately. A class defined here that nothing binds or instantiates is an `entrypoint` artifact, not a runtime agent.",
|
|
16942
17032
|
'A `tool` artifact is one tool definition. Never emit a group of tools ("MCP server tools", "composio_*", "worker tools") as a tool; record a dynamic tool source (MCP servers, Composio, webhooks) as a graph unknown that cites where the tools are loaded.',
|
|
16943
17033
|
"Ignore any checked-in .moda/ directory: it is the output of an earlier Moda run and is often stale. Never cite it or reuse its entities.",
|
|
17034
|
+
"The harness includes every real harness component, used or not: a prompt, tool, or model config that is defined but never called is still part of the harness (lower its confidence and say so in confidenceReason). A false positive is only something that is not a harness component: SQL, React or UI props and display copy, URL or path templates, test fixtures, and general utilities. Refute only those; never refute a real component because it is unused.",
|
|
16944
17035
|
'Every graph item with confidence below 0.85 must also carry confidenceReason: one sentence naming what held confidence down, e.g. "Inferred from AGENTS.md:231-232 only; no source file defines this agent." or "Entrypoint read, but the tool registry was outside the snapshot."',
|
|
16945
17036
|
"Each graph item with evidence must use evidence: [{ path, reason }], not citationIds/citations.",
|
|
16946
17037
|
...spec ? spec.contractLines : [
|
|
@@ -17079,7 +17170,7 @@ function renderAnalystCandidateLines(report, concern) {
|
|
|
17079
17170
|
const lines = [
|
|
17080
17171
|
"",
|
|
17081
17172
|
concern ? `Deterministic candidate inventory for the ${concern} concern (${candidates.length} candidates, scanned in ${report.stats.durationMs}ms):` : `Deterministic candidate inventory (${candidates.length} candidates across ${report.stats.filesWithCandidates} files, scanned in ${report.stats.durationMs}ms):`,
|
|
17082
|
-
concern ? 'Each entry is path:line [detector] excerpt. Candidates are pattern matches — verify each against the real file, drop false positives (list refuted ones in unknowns: an unknown whose id starts with "refuted_", with one evidence entry {path, line, reason} per refuted candidate, using the path:line shown for that candidate and starting the reason with its [detector]), and hunt for in-concern items the patterns cannot see. Do not cite this list as evidence; cite the files.' : 'Each entry is path:line [detector] excerpt. Candidates are pattern matches — verify each against the real file and drop false positives. Verified deterministic candidates are also auto-merged into the graph after your run, so prioritize (1) agents, topology, and relationships, (2) verifying or refuting these candidates (list refuted ones in unknowns: an unknown whose id starts with "refuted_", with one evidence entry {path, line, reason} per refuted candidate, using the path:line shown for that candidate and starting the reason with its [detector]; refuted candidates are never auto-merged), and (3) artifacts the patterns cannot see (runtime agents, prompts assembled at runtime, cross-file wiring) — rather than re-listing every candidate as an artifact. Do not cite this list as evidence; cite the files.'
|
|
17173
|
+
concern ? 'Each entry is path:line [detector] excerpt. Candidates are pattern matches — verify each against the real file, drop false positives — things that are not harness components (SQL, UI props or display copy, URL templates, test fixtures, utilities), never a real component merely because it is unused (list refuted ones in unknowns: an unknown whose id starts with "refuted_", with one evidence entry {path, line, reason} per refuted candidate, using the path:line shown for that candidate and starting the reason with its [detector]), and hunt for in-concern items the patterns cannot see. Do not cite this list as evidence; cite the files.' : 'Each entry is path:line [detector] excerpt. Candidates are pattern matches — verify each against the real file and drop false positives — things that are not harness components (SQL, UI props or display copy, URL templates, test fixtures, utilities), never a real component merely because it is unused. Verified deterministic candidates are also auto-merged into the graph after your run, so prioritize (1) agents, topology, and relationships, (2) verifying or refuting these candidates (list refuted ones in unknowns: an unknown whose id starts with "refuted_", with one evidence entry {path, line, reason} per refuted candidate, using the path:line shown for that candidate and starting the reason with its [detector]; refuted candidates are never auto-merged), and (3) artifacts the patterns cannot see (runtime agents, prompts assembled at runtime, cross-file wiring) — rather than re-listing every candidate as an artifact. Do not cite this list as evidence; cite the files.'
|
|
17083
17174
|
];
|
|
17084
17175
|
if (concern === "evals") {
|
|
17085
17176
|
lines.push("Note: evals, guardrails, and memory/retrieval stores have no deterministic detector — only model_config candidates are seeded. Discover the rest by investigation.");
|
|
@@ -17144,10 +17235,10 @@ function readDirectoryPreflightPaths(rootDir) {
|
|
|
17144
17235
|
const stack = ["."];
|
|
17145
17236
|
while (stack.length > 0 && paths.length < 2000) {
|
|
17146
17237
|
const current = stack.pop() ?? ".";
|
|
17147
|
-
const absolute = current === "." ? rootDir :
|
|
17238
|
+
const absolute = current === "." ? rootDir : join9(rootDir, current);
|
|
17148
17239
|
let entries;
|
|
17149
17240
|
try {
|
|
17150
|
-
entries =
|
|
17241
|
+
entries = readdirSync4(absolute);
|
|
17151
17242
|
} catch {
|
|
17152
17243
|
continue;
|
|
17153
17244
|
}
|
|
@@ -17155,10 +17246,10 @@ function readDirectoryPreflightPaths(rootDir) {
|
|
|
17155
17246
|
const child = current === "." ? entry : `${current}/${entry}`;
|
|
17156
17247
|
if (shouldSkipPreflightPath(child))
|
|
17157
17248
|
continue;
|
|
17158
|
-
const childAbsolute =
|
|
17249
|
+
const childAbsolute = join9(rootDir, child);
|
|
17159
17250
|
let stat;
|
|
17160
17251
|
try {
|
|
17161
|
-
stat =
|
|
17252
|
+
stat = lstatSync7(childAbsolute);
|
|
17162
17253
|
} catch {
|
|
17163
17254
|
continue;
|
|
17164
17255
|
}
|
|
@@ -17220,7 +17311,7 @@ function findOnPath(command) {
|
|
|
17220
17311
|
if (command.includes("/") && existsSync8(command))
|
|
17221
17312
|
return command;
|
|
17222
17313
|
for (const dir of (process.env.PATH ?? "").split(delimiter).filter(Boolean)) {
|
|
17223
|
-
const candidate =
|
|
17314
|
+
const candidate = join9(dir, command);
|
|
17224
17315
|
if (existsSync8(candidate))
|
|
17225
17316
|
return candidate;
|
|
17226
17317
|
}
|
|
@@ -17274,6 +17365,7 @@ function scanHarness(options = {}) {
|
|
|
17274
17365
|
linkFrameworksAndProviders(graph);
|
|
17275
17366
|
finalizeGraph(graph);
|
|
17276
17367
|
hydratePromptAndToolBodies(graph, rootDir);
|
|
17368
|
+
tagComponentStatus(graph, rootDir);
|
|
17277
17369
|
enrichScanCaptureMetadata(graph);
|
|
17278
17370
|
return graph;
|
|
17279
17371
|
}
|
|
@@ -17298,10 +17390,10 @@ function collectSnapshotInputs(rootDir, maxFiles, maxTextBytes) {
|
|
|
17298
17390
|
let inventoryFileCount = 0;
|
|
17299
17391
|
let inventoryTextBytes = 0;
|
|
17300
17392
|
function walk(current) {
|
|
17301
|
-
const path = normalizePath2(
|
|
17393
|
+
const path = normalizePath2(relative6(rootDir, current)) || ".";
|
|
17302
17394
|
let stat;
|
|
17303
17395
|
try {
|
|
17304
|
-
stat =
|
|
17396
|
+
stat = lstatSync7(current);
|
|
17305
17397
|
} catch {
|
|
17306
17398
|
return;
|
|
17307
17399
|
}
|
|
@@ -17312,8 +17404,8 @@ function collectSnapshotInputs(rootDir, maxFiles, maxTextBytes) {
|
|
|
17312
17404
|
if (stat.isDirectory()) {
|
|
17313
17405
|
if (path !== "." && (isSkippedDir(path) || isSkippedPathPrefix(path)))
|
|
17314
17406
|
return;
|
|
17315
|
-
for (const entry of
|
|
17316
|
-
walk(
|
|
17407
|
+
for (const entry of readdirSync4(current).sort())
|
|
17408
|
+
walk(join9(current, entry));
|
|
17317
17409
|
return;
|
|
17318
17410
|
}
|
|
17319
17411
|
if (!stat.isFile())
|
|
@@ -17336,7 +17428,7 @@ function collectSnapshotInputs(rootDir, maxFiles, maxTextBytes) {
|
|
|
17336
17428
|
let text = "";
|
|
17337
17429
|
if (isTextFile(path)) {
|
|
17338
17430
|
try {
|
|
17339
|
-
text =
|
|
17431
|
+
text = readFileSync12(current, "utf8");
|
|
17340
17432
|
inventoryTextBytes += Buffer.byteLength(text, "utf8");
|
|
17341
17433
|
} catch {
|
|
17342
17434
|
return;
|
|
@@ -17355,7 +17447,7 @@ function buildSourceSnapshot(rootDir) {
|
|
|
17355
17447
|
const inputs = collectSnapshotInputs(root, maxFiles, maxTextBytes);
|
|
17356
17448
|
const repo = detectRepo(root, inputs.map((input) => ({
|
|
17357
17449
|
path: input.path,
|
|
17358
|
-
absPath:
|
|
17450
|
+
absPath: join9(root, input.path),
|
|
17359
17451
|
rootDir: root,
|
|
17360
17452
|
text: input.text
|
|
17361
17453
|
})));
|
|
@@ -17369,7 +17461,7 @@ function buildSourceSnapshot(rootDir) {
|
|
|
17369
17461
|
}
|
|
17370
17462
|
function buildCommandScanPlan(context, rootDir) {
|
|
17371
17463
|
const explicitPath = context.flags.path !== undefined;
|
|
17372
|
-
const rel2 = normalizePath2(
|
|
17464
|
+
const rel2 = normalizePath2(relative6(context.cwd, rootDir)) || ".";
|
|
17373
17465
|
const scope = explicitPath && rel2 !== "." ? "narrow" : "broad";
|
|
17374
17466
|
const machineReadable = context.outputMode !== "human";
|
|
17375
17467
|
const approvalRequired = context.positional === "analyze" && scope === "broad" && !context.yes;
|
|
@@ -17454,7 +17546,7 @@ function writeHumanBlock(context, message) {
|
|
|
17454
17546
|
function buildHarnessReadPlan(rootDir, pathWasExplicit) {
|
|
17455
17547
|
return {
|
|
17456
17548
|
scope: pathWasExplicit ? "narrow" : "broad",
|
|
17457
|
-
rootPaths: [normalizePath2(
|
|
17549
|
+
rootPaths: [normalizePath2(relative6(rootDir, rootDir)) || "."],
|
|
17458
17550
|
willRead: [
|
|
17459
17551
|
"package manifests",
|
|
17460
17552
|
"source files under the selected path",
|
|
@@ -17572,7 +17664,7 @@ async function syncHarnessWithRemote(context, body) {
|
|
|
17572
17664
|
}, profileOptions);
|
|
17573
17665
|
}
|
|
17574
17666
|
function writeHarnessSyncState(rootDir, state) {
|
|
17575
|
-
const path =
|
|
17667
|
+
const path = join9(rootDir, SYNC_STATE_PATH);
|
|
17576
17668
|
mkdirSync5(dirname7(path), { recursive: true });
|
|
17577
17669
|
writeFileSync5(path, `${JSON.stringify(state, null, 2)}
|
|
17578
17670
|
`);
|
|
@@ -17586,7 +17678,7 @@ function selectedRuntimeAgentId(flags) {
|
|
|
17586
17678
|
return;
|
|
17587
17679
|
}
|
|
17588
17680
|
function loadOrScanHarness(rootDir, tenant, context) {
|
|
17589
|
-
const manifestPath =
|
|
17681
|
+
const manifestPath = join9(rootDir, HARNESS_PATH);
|
|
17590
17682
|
if (existsSync8(manifestPath))
|
|
17591
17683
|
return readHarnessGraph(manifestPath);
|
|
17592
17684
|
if (context) {
|
|
@@ -17643,7 +17735,7 @@ var FRESHER_REPORT_MAX_DIRS = 4000;
|
|
|
17643
17735
|
function findFresherHarnessReports(rootDir) {
|
|
17644
17736
|
let rootMtimeMs = 0;
|
|
17645
17737
|
try {
|
|
17646
|
-
rootMtimeMs =
|
|
17738
|
+
rootMtimeMs = lstatSync7(join9(rootDir, HARNESS_REPORT_PATH)).mtimeMs;
|
|
17647
17739
|
} catch {
|
|
17648
17740
|
rootMtimeMs = 0;
|
|
17649
17741
|
}
|
|
@@ -17655,19 +17747,19 @@ function findFresherHarnessReports(rootDir) {
|
|
|
17655
17747
|
visited += 1;
|
|
17656
17748
|
let entries;
|
|
17657
17749
|
try {
|
|
17658
|
-
entries =
|
|
17750
|
+
entries = readdirSync4(dir, { withFileTypes: true });
|
|
17659
17751
|
} catch {
|
|
17660
17752
|
return;
|
|
17661
17753
|
}
|
|
17662
17754
|
for (const entry of entries) {
|
|
17663
17755
|
if (!entry.isDirectory() || entry.name.startsWith(".") || SKIPPED_DIRS.has(entry.name))
|
|
17664
17756
|
continue;
|
|
17665
|
-
const child =
|
|
17757
|
+
const child = join9(dir, entry.name);
|
|
17666
17758
|
try {
|
|
17667
|
-
const candidate =
|
|
17759
|
+
const candidate = lstatSync7(join9(child, HARNESS_REPORT_PATH));
|
|
17668
17760
|
if (candidate.isFile() && candidate.mtimeMs > rootMtimeMs) {
|
|
17669
17761
|
fresher.push({
|
|
17670
|
-
path: normalizePath2(
|
|
17762
|
+
path: normalizePath2(relative6(rootDir, join9(child, HARNESS_REPORT_PATH))),
|
|
17671
17763
|
mtimeMs: candidate.mtimeMs
|
|
17672
17764
|
});
|
|
17673
17765
|
}
|
|
@@ -17679,7 +17771,7 @@ function findFresherHarnessReports(rootDir) {
|
|
|
17679
17771
|
return fresher.sort((a, b) => b.mtimeMs - a.mtimeMs);
|
|
17680
17772
|
}
|
|
17681
17773
|
function warnFresherSubdirHarnessReports(context, rootDir, explicitReport) {
|
|
17682
|
-
const explicitReportPath = explicitReport && explicitReport !== "true" ? normalizePath2(
|
|
17774
|
+
const explicitReportPath = explicitReport && explicitReport !== "true" ? normalizePath2(relative6(rootDir, resolve10(rootDir, explicitReport))) : undefined;
|
|
17683
17775
|
if (explicitReportPath && explicitReportPath !== normalizePath2(HARNESS_REPORT_PATH))
|
|
17684
17776
|
return;
|
|
17685
17777
|
let fresher;
|
|
@@ -17692,16 +17784,16 @@ function warnFresherSubdirHarnessReports(context, rootDir, explicitReport) {
|
|
|
17692
17784
|
return;
|
|
17693
17785
|
const newest = fresher[0];
|
|
17694
17786
|
const subdir = normalizePath2(dirname7(dirname7(newest.path)));
|
|
17695
|
-
const rootState = existsSync8(
|
|
17787
|
+
const rootState = existsSync8(join9(rootDir, HARNESS_REPORT_PATH)) ? `older ${HARNESS_REPORT_PATH}` : `no ${HARNESS_REPORT_PATH}`;
|
|
17696
17788
|
writeHarnessNotice(context, `A fresher harness report exists at ${newest.path} (this directory has ${rootState}). If you meant that report, re-run with --path=${subdir}.`);
|
|
17697
17789
|
}
|
|
17698
17790
|
function readHarnessGraph(manifestPath) {
|
|
17699
|
-
return JSON.parse(
|
|
17791
|
+
return JSON.parse(readFileSync12(manifestPath, "utf8"));
|
|
17700
17792
|
}
|
|
17701
17793
|
function writeHarnessArtifacts(graph, rootDir, options = {}) {
|
|
17702
|
-
const modaDir =
|
|
17794
|
+
const modaDir = join9(rootDir, MODA_DIR);
|
|
17703
17795
|
mkdirSync5(modaDir, { recursive: true });
|
|
17704
|
-
const manifestPath =
|
|
17796
|
+
const manifestPath = join9(rootDir, HARNESS_PATH);
|
|
17705
17797
|
writeFileSync5(manifestPath, `${JSON.stringify(graph, null, 2)}
|
|
17706
17798
|
`);
|
|
17707
17799
|
const written = [HARNESS_PATH];
|
|
@@ -17711,7 +17803,7 @@ function writeHarnessArtifacts(graph, rootDir, options = {}) {
|
|
|
17711
17803
|
return written;
|
|
17712
17804
|
}
|
|
17713
17805
|
function writeHarnessSummary(graph, rootDir) {
|
|
17714
|
-
const summaryPath =
|
|
17806
|
+
const summaryPath = join9(rootDir, HARNESS_SUMMARY_PATH);
|
|
17715
17807
|
mkdirSync5(dirname7(summaryPath), { recursive: true });
|
|
17716
17808
|
writeFileSync5(summaryPath, renderHarnessMarkdown(graph));
|
|
17717
17809
|
return HARNESS_SUMMARY_PATH;
|
|
@@ -17886,10 +17978,10 @@ function inventoryFiles(rootDir, skipped, options = {}) {
|
|
|
17886
17978
|
const maxTextBytes = numericEnv("MODA_HARNESS_MAX_TEXT_BYTES", DEFAULT_MAX_INVENTORY_TEXT_BYTES);
|
|
17887
17979
|
let textBytes = 0;
|
|
17888
17980
|
function walk(current) {
|
|
17889
|
-
const rel2 = normalizePath2(
|
|
17981
|
+
const rel2 = normalizePath2(relative6(rootReal, current)) || ".";
|
|
17890
17982
|
let stat;
|
|
17891
17983
|
try {
|
|
17892
|
-
stat =
|
|
17984
|
+
stat = lstatSync7(current);
|
|
17893
17985
|
} catch {
|
|
17894
17986
|
recordSkipped(skipped, { path: rel2, reason: "stat failed" });
|
|
17895
17987
|
return;
|
|
@@ -17903,8 +17995,8 @@ function inventoryFiles(rootDir, skipped, options = {}) {
|
|
|
17903
17995
|
recordSkipped(skipped, { path: rel2, reason: "ignored directory" });
|
|
17904
17996
|
return;
|
|
17905
17997
|
}
|
|
17906
|
-
for (const entry of
|
|
17907
|
-
walk(
|
|
17998
|
+
for (const entry of readdirSync4(current).sort()) {
|
|
17999
|
+
walk(join9(current, entry));
|
|
17908
18000
|
}
|
|
17909
18001
|
return;
|
|
17910
18002
|
}
|
|
@@ -17935,7 +18027,7 @@ function inventoryFiles(rootDir, skipped, options = {}) {
|
|
|
17935
18027
|
recordSkipped(skipped, { path: rel2, reason: "scan text budget exceeded" });
|
|
17936
18028
|
} else {
|
|
17937
18029
|
try {
|
|
17938
|
-
item.text =
|
|
18030
|
+
item.text = readFileSync12(current, "utf8");
|
|
17939
18031
|
textBytes += Buffer.byteLength(item.text, "utf8");
|
|
17940
18032
|
} catch {
|
|
17941
18033
|
recordSkipped(skipped, { path: rel2, reason: "text read failed" });
|
|
@@ -18242,7 +18334,7 @@ function maybeAddPromptArtifact(graph, file) {
|
|
|
18242
18334
|
if (!isPrompt)
|
|
18243
18335
|
return;
|
|
18244
18336
|
const id = stableId("prompt", file.path);
|
|
18245
|
-
const text = file.text ??
|
|
18337
|
+
const text = file.text ?? readFileSync12(file.absPath, "utf8");
|
|
18246
18338
|
upsertArtifact(graph, {
|
|
18247
18339
|
id,
|
|
18248
18340
|
type: "prompt",
|
|
@@ -18820,10 +18912,10 @@ function computeDeterministicFloor(rootDir) {
|
|
|
18820
18912
|
}
|
|
18821
18913
|
function detectProviderPackagesInManifests(rootDir) {
|
|
18822
18914
|
const present = new Set;
|
|
18823
|
-
const packageJsonPath =
|
|
18915
|
+
const packageJsonPath = join9(rootDir, "package.json");
|
|
18824
18916
|
if (existsSync8(packageJsonPath)) {
|
|
18825
18917
|
try {
|
|
18826
|
-
const deps = packageDependencyNames(
|
|
18918
|
+
const deps = packageDependencyNames(readFileSync12(packageJsonPath, "utf8"));
|
|
18827
18919
|
for (const provider of PROVIDER_CATALOG) {
|
|
18828
18920
|
for (const name of provider.packageNames) {
|
|
18829
18921
|
if (deps.has(name))
|
|
@@ -18832,10 +18924,10 @@ function detectProviderPackagesInManifests(rootDir) {
|
|
|
18832
18924
|
}
|
|
18833
18925
|
} catch {}
|
|
18834
18926
|
}
|
|
18835
|
-
const pyprojectPath =
|
|
18927
|
+
const pyprojectPath = join9(rootDir, "pyproject.toml");
|
|
18836
18928
|
if (existsSync8(pyprojectPath)) {
|
|
18837
18929
|
try {
|
|
18838
|
-
const deps = pyprojectDependencyNames(
|
|
18930
|
+
const deps = pyprojectDependencyNames(readFileSync12(pyprojectPath, "utf8"));
|
|
18839
18931
|
for (const provider of PROVIDER_CATALOG) {
|
|
18840
18932
|
for (const name of provider.packageNames) {
|
|
18841
18933
|
if (deps.has(name.toLowerCase()))
|
|
@@ -19237,12 +19329,12 @@ function contentHashForAnnotatedSource(sourcePath, annotation) {
|
|
|
19237
19329
|
function readSmallTextFileForHash(absPath, rootDir) {
|
|
19238
19330
|
if (!existsSync8(absPath))
|
|
19239
19331
|
return;
|
|
19240
|
-
const rel2 = normalizePath2(
|
|
19332
|
+
const rel2 = normalizePath2(relative6(rootDir, absPath));
|
|
19241
19333
|
if (isSecretishPath(rel2))
|
|
19242
19334
|
return;
|
|
19243
19335
|
let stat;
|
|
19244
19336
|
try {
|
|
19245
|
-
stat =
|
|
19337
|
+
stat = lstatSync7(absPath);
|
|
19246
19338
|
} catch {
|
|
19247
19339
|
return;
|
|
19248
19340
|
}
|
|
@@ -19252,7 +19344,7 @@ function readSmallTextFileForHash(absPath, rootDir) {
|
|
|
19252
19344
|
if (!isTextFile(rel2))
|
|
19253
19345
|
return;
|
|
19254
19346
|
try {
|
|
19255
|
-
return
|
|
19347
|
+
return readFileSync12(absPath, "utf8");
|
|
19256
19348
|
} catch {
|
|
19257
19349
|
return;
|
|
19258
19350
|
}
|