@moda-ai/cli 1.55.55 → 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.
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  buildDoctorReport
3
- } from "./cli-eqj302as.js";
3
+ } from "./cli-7epk27vq.js";
4
4
  import"./cli-94r5x9bg.js";
5
- import"./cli-jnwba1f3.js";
5
+ import"./cli-jrf8annc.js";
6
6
  import"./cli-mm48br00.js";
7
7
  import {
8
8
  readHarnessSyncState
@@ -95,7 +95,7 @@ async function buildAgentContext(context) {
95
95
  const graph = readHarnessGraphIfPresent(context.cwd);
96
96
  const reportState = readHarnessReportState(context.cwd);
97
97
  const syncState = readHarnessSyncState(context.cwd);
98
- const harness = graph ? await import("./harness-j0n400bv.js") : undefined;
98
+ const harness = graph ? await import("./harness-2vkcwm85.js") : undefined;
99
99
  const topFindings = doctor.checks.filter((check) => check.status === "fail" || check.status === "warning").slice(0, 12).map(checkToFinding);
100
100
  const evidenceRefs = [
101
101
  ...doctor.checks.map(checkToEvidenceRef),
@@ -4,7 +4,7 @@ import {
4
4
  } from "./cli-94r5x9bg.js";
5
5
  import {
6
6
  inspectPromptManifest
7
- } from "./cli-jnwba1f3.js";
7
+ } from "./cli-jrf8annc.js";
8
8
  import {
9
9
  readHarnessSyncState,
10
10
  renderDoctorHuman,
@@ -395,7 +395,7 @@ async function harnessCurrentCheck(cwd, manifestPath, manifestExists, tenantId)
395
395
  };
396
396
  }
397
397
  try {
398
- const { scanHarness } = await import("./harness-j0n400bv.js");
398
+ const { scanHarness } = await import("./harness-2vkcwm85.js");
399
399
  const current = scanHarness({
400
400
  rootDir: cwd,
401
401
  scannerVersion: "doctor",
@@ -5768,7 +5768,7 @@ async function runPromptSyncExclusive(flags, profileOptions, options) {
5768
5768
  const analyzedDefinitions = new Map;
5769
5769
  if (flags["no-analyze"] !== "true") {
5770
5770
  options.onProgress?.("Analyzing prompt sources before sync.");
5771
- const { analyzeHarnessPrompts } = await import("./harness-j0n400bv.js");
5771
+ const { analyzeHarnessPrompts } = await import("./harness-2vkcwm85.js");
5772
5772
  const result = await analyzeHarnessPrompts({
5773
5773
  rootDir: process.cwd(),
5774
5774
  existing: established.flatMap((prompt) => prompt.sourceDefinition ? [prompt.sourceDefinition.source] : []),
@@ -5796,7 +5796,7 @@ async function runPromptSyncExclusive(flags, profileOptions, options) {
5796
5796
  const mergedSources = mergePromptSources(manifest.sources, extraSources);
5797
5797
  const manifestUpdate = stableJson(mergedSources) === stableJson(mergePromptSources(manifest.sources, [])) ? undefined : $stringify({ version: 2, prompt_paths: manifest.promptPaths, sources: mergedSources });
5798
5798
  const prompts = await discoverPrompts(extraSources);
5799
- const { checkPromptAttribution } = await import("./prompt-attribution-x84cgdct.js");
5799
+ const { checkPromptAttribution } = await import("./prompt-attribution-2h9vertk.js");
5800
5800
  const attribution = checkPromptAttribution(process.cwd(), prompts.map((prompt) => prompt.key));
5801
5801
  const brokenAttribution = attribution.references.filter((reference) => reference.status === "missing");
5802
5802
  if (brokenAttribution.length) {
@@ -6102,7 +6102,7 @@ async function migratePromptManifest(options = {}) {
6102
6102
  let addedSources = [];
6103
6103
  let pendingSources = [];
6104
6104
  if (options.discover) {
6105
- const { analyzeHarnessPrompts } = await import("./harness-j0n400bv.js");
6105
+ const { analyzeHarnessPrompts } = await import("./harness-2vkcwm85.js");
6106
6106
  const result = await analyzeHarnessPrompts({
6107
6107
  rootDir: root,
6108
6108
  existing: manifest.sources,
@@ -12128,7 +12128,7 @@ var LINE_PATTERNS = [
12128
12128
  kind: "prompt_literal",
12129
12129
  signal: "code.prompt_configuration_field",
12130
12130
  confidence: "high",
12131
- pattern: /(?:^|[{,])\s*(?:instructions|systemPrompt|system_prompt)\s*:/,
12131
+ pattern: /(?:^|[{,])\s*["']?(?:instructions?|systemPrompt|system_prompt|systemMessage|system_message|systemInstruction|system_instruction|backstory)["']?\s*:/,
12132
12132
  extensions: JS
12133
12133
  },
12134
12134
  {
@@ -13562,6 +13562,319 @@ function applyPromptDiscovery(graph, discovery) {
13562
13562
  // src/harness-candidate-promotion.ts
13563
13563
  import { readFileSync as readFileSync11 } from "node:fs";
13564
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
13565
13878
  var PROMOTED_CONFIDENCE = {
13566
13879
  high: 0.85,
13567
13880
  medium: 0.6
@@ -13584,13 +13897,21 @@ function candidateEvidence(candidate) {
13584
13897
  function pathStem(path) {
13585
13898
  return path.replace(/\.[^.]+$/, "");
13586
13899
  }
13900
+ var jsSources = new Map;
13587
13901
  function readFileLines(rootDir, path, cache) {
13588
13902
  const cached = cache.get(path);
13589
13903
  if (cached !== undefined)
13590
13904
  return cached;
13591
13905
  let lines;
13592
13906
  try {
13593
- lines = readFileSync11(resolve9(rootDir, path), "utf8").split(/\r?\n/);
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
+ }
13594
13915
  } catch {
13595
13916
  lines = null;
13596
13917
  }
@@ -13665,6 +13986,12 @@ function buildsPrompts(path, lines) {
13665
13986
  return false;
13666
13987
  return exportedNames(path, lines).some((name) => !UTILITY_EXPORT.test(name) && (BUILDER_VERB.test(name) || PROMPT_NOUN_LAST.test(name)));
13667
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
+ }
13668
13995
  function promotePromptFileCandidate(candidate, confidence2) {
13669
13996
  return {
13670
13997
  id: stableId("prompt", candidate.path),
@@ -13696,6 +14023,7 @@ var MODEL_INPUT_KEYS = [
13696
14023
  "text"
13697
14024
  ];
13698
14025
  var DIRECT_PROMPT_KEYS = new Set([
14026
+ "instruction",
13699
14027
  "system",
13700
14028
  "systemPrompt",
13701
14029
  "system_prompt",
@@ -13727,6 +14055,7 @@ var CONFIG_EXTENSIONS = new Set([".json", ".yaml", ".yml"]);
13727
14055
  var PROMPT_NAMED_IDENTIFIER = /prompt|system|instruction/i;
13728
14056
  var SECOND_PERSON_OPENING = /^\s*(?:\[[A-Z]+:\s*|<\w+>\s*)*(?:you|your)\b/i;
13729
14057
  var MIN_UNNAMED_REFERENCED_PROMPT_CHARS = 200;
14058
+ var UNUSED_PROMPT_CONFIDENCE = 0.6;
13730
14059
  var REFERENCED_PROMPT_CONFIDENCE = 0.7;
13731
14060
  var MIN_RESOLVED_PROMPT_CHARS = 20;
13732
14061
  var MIN_CONFIG_PROMPT_CHARS = 40;
@@ -13753,128 +14082,15 @@ function readStringLiteral(text, start) {
13753
14082
  i += 2;
13754
14083
  continue;
13755
14084
  }
13756
- if (opener.length === 1 && opener !== "`" && char === `
14085
+ if (opener.length === 1 && char === `
13757
14086
  `)
13758
14087
  return;
13759
- if (opener === "`" && char === "$" && text[i + 1] === "{") {
13760
- let depth = 1;
13761
- i += 2;
13762
- while (i < text.length && depth > 0) {
13763
- if (text[i] === "`" || text[i] === '"' || text[i] === "'") {
13764
- const nested = readStringLiteral(text, i);
13765
- if (nested) {
13766
- i = nested.end;
13767
- continue;
13768
- }
13769
- if (text[i] === "`")
13770
- return;
13771
- i += 1;
13772
- continue;
13773
- }
13774
- const regexEnd = text[i] === "/" ? regexLiteralEnd(text, i) : undefined;
13775
- if (regexEnd !== undefined) {
13776
- i = regexEnd;
13777
- continue;
13778
- }
13779
- if (text.startsWith("//", i)) {
13780
- const newline = text.indexOf(`
13781
- `, i);
13782
- i = newline < 0 ? text.length : newline;
13783
- continue;
13784
- }
13785
- if (text.startsWith("/*", i)) {
13786
- const close = text.indexOf("*/", i + 2);
13787
- if (close < 0)
13788
- return;
13789
- i = close + 2;
13790
- continue;
13791
- }
13792
- if (text[i] === "{")
13793
- depth += 1;
13794
- else if (text[i] === "}")
13795
- depth -= 1;
13796
- i += 1;
13797
- }
13798
- continue;
13799
- }
13800
14088
  if (text.startsWith(opener, i))
13801
14089
  return { value: text.slice(start + opener.length, i), end: i + opener.length };
13802
14090
  i += 1;
13803
14091
  }
13804
14092
  return;
13805
14093
  }
13806
- var EXPRESSION_KEYWORDS = new Set([
13807
- "return",
13808
- "typeof",
13809
- "instanceof",
13810
- "in",
13811
- "of",
13812
- "new",
13813
- "delete",
13814
- "void",
13815
- "throw",
13816
- "case",
13817
- "do",
13818
- "else",
13819
- "yield",
13820
- "await"
13821
- ]);
13822
- function endsWithOperand(text, end) {
13823
- let i = end;
13824
- while (i > 0 && /\s/.test(text[i - 1]))
13825
- i -= 1;
13826
- if (i === 0)
13827
- return false;
13828
- const char = text[i - 1];
13829
- if (char === ")" || char === "]" || char === '"' || char === "'" || char === "`")
13830
- return true;
13831
- if (/[\w$]/.test(char)) {
13832
- let wordStart = i;
13833
- while (wordStart > 0 && /[\w$]/.test(text[wordStart - 1]))
13834
- wordStart -= 1;
13835
- const word = text.slice(wordStart, i);
13836
- if (/^\d/.test(word))
13837
- return true;
13838
- let before = wordStart;
13839
- while (before > 0 && /\s/.test(text[before - 1]))
13840
- before -= 1;
13841
- const isProperty = text[before - 1] === "." && text[before - 2] !== ".";
13842
- return isProperty || !EXPRESSION_KEYWORDS.has(word);
13843
- }
13844
- if ((char === "+" || char === "-") && text[i - 2] === char)
13845
- return endsWithOperand(text, i - 2);
13846
- if (char === "!" && i >= 2 && /[\w$)\]]/.test(text[i - 2]))
13847
- return endsWithOperand(text, i - 1);
13848
- return false;
13849
- }
13850
- function regexLiteralEnd(text, start) {
13851
- if (text[start + 1] === "/" || text[start + 1] === "*")
13852
- return;
13853
- if (endsWithOperand(text, start))
13854
- return;
13855
- let inClass = false;
13856
- for (let i = start + 1;i < text.length; i += 1) {
13857
- const char = text[i];
13858
- if (char === `
13859
- `)
13860
- return;
13861
- if (char === "\\") {
13862
- i += 1;
13863
- continue;
13864
- }
13865
- if (char === "[")
13866
- inClass = true;
13867
- else if (char === "]")
13868
- inClass = false;
13869
- else if (char === "/" && !inClass) {
13870
- let end = i + 1;
13871
- while (/[a-z]/i.test(text[end] ?? ""))
13872
- end += 1;
13873
- return end;
13874
- }
13875
- }
13876
- return;
13877
- }
13878
14094
  function readStringValue(text, offset) {
13879
14095
  let i = offset;
13880
14096
  const parts = [];
@@ -13931,7 +14147,9 @@ function stringStart(rest) {
13931
14147
  }
13932
14148
  return STRING_OPENER.test(remaining) ? consumed : -1;
13933
14149
  }
13934
- function resolvePromptLiteralDefinition(lines, startLine) {
14150
+ function resolvePromptLiteralDefinition(lines, startLine, jsSource, excerpt2) {
14151
+ if (jsSource)
14152
+ return jsLiteralDefinitionAt(jsSource, startLine, excerpt2);
13935
14153
  const text = lines.join(`
13936
14154
  `);
13937
14155
  for (const index of [startLine - 1, startLine - 2]) {
@@ -14009,16 +14227,8 @@ function resolvePromptLiteralDefinition(lines, startLine) {
14009
14227
  }
14010
14228
  function endsInComment(prefix) {
14011
14229
  let quote;
14012
- let inBlock = false;
14013
14230
  for (let i = 0;i < prefix.length; i += 1) {
14014
14231
  const char = prefix[i];
14015
- if (inBlock) {
14016
- if (prefix.startsWith("*/", i)) {
14017
- inBlock = false;
14018
- i += 1;
14019
- }
14020
- continue;
14021
- }
14022
14232
  if (quote) {
14023
14233
  if (char === "\\")
14024
14234
  i += 1;
@@ -14026,23 +14236,14 @@ function endsInComment(prefix) {
14026
14236
  quote = undefined;
14027
14237
  continue;
14028
14238
  }
14029
- if (char === '"' || char === "'" || char === "`") {
14239
+ if (char === '"' || char === "'") {
14030
14240
  quote = char;
14031
14241
  continue;
14032
14242
  }
14033
- const regexEnd = char === "/" ? regexLiteralEnd(prefix, i) : undefined;
14034
- if (regexEnd !== undefined) {
14035
- i = regexEnd - 1;
14036
- continue;
14037
- }
14038
- if (prefix.startsWith("//", i))
14243
+ if (char === "#")
14039
14244
  return true;
14040
- else if (prefix.startsWith("/*", i)) {
14041
- inBlock = true;
14042
- i += 1;
14043
- }
14044
14245
  }
14045
- return inBlock;
14246
+ return false;
14046
14247
  }
14047
14248
  function readYamlBlockScalar(lines, index, rest) {
14048
14249
  const indicator = /^([|>])([-+]?)\s*(?:#.*)?$/.exec(rest.trim());
@@ -14206,7 +14407,7 @@ function importStatementLines(lines) {
14206
14407
  }
14207
14408
  return covered;
14208
14409
  }
14209
- 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;
14210
14411
  function calleeImportedFromModelFile(callee, path, lines, modelFiles) {
14211
14412
  const base = callee.split(".")[0];
14212
14413
  const text = lines.join(`
@@ -14251,7 +14452,10 @@ function localHelperCallsModel(callee, lines) {
14251
14452
  const start = lines.findIndex((line) => head.test(line));
14252
14453
  if (start < 0)
14253
14454
  return false;
14254
- return lines.slice(start + 1, start + 1 + MAX_HELPER_BODY_LINES).some((line) => MODEL_CALL_IN_BODY.test(line));
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));
14255
14459
  }
14256
14460
  function callCarriesChatMessages(lines, index) {
14257
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) {
@@ -14398,6 +14602,31 @@ function readsAsInstructions(identifier, text) {
14398
14602
  return score >= 2 || secondPerson;
14399
14603
  return secondPerson && score >= 2 && text.length >= MIN_UNNAMED_REFERENCED_PROMPT_CHARS;
14400
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
+ }
14401
14630
  function hasNearbyRole(lines, line) {
14402
14631
  for (let i = Math.max(0, line - 4);i < Math.min(lines.length, line + 3); i += 1) {
14403
14632
  if (/\brole\b\s*["']?\s*[:=]/.test(lines[i]))
@@ -14412,21 +14641,100 @@ function isDirectModelInput(key, value, path, lines, line, modelFiles) {
14412
14641
  if (modelFiles.has(path)) {
14413
14642
  return DIRECT_PROMPT_KEYS.has(key) || key === "content" && hasNearbyRole(lines, line);
14414
14643
  }
14644
+ if (PROMPT_CONFIG_KEYS.has(key))
14645
+ return true;
14415
14646
  return DIRECT_PROMPT_KEYS.has(key) && instructionScore(value) >= 2;
14416
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
+ ]);
14417
14709
  function promotePromptLiteralCandidate(candidate, rootDir, confidence2, fileCache, files) {
14418
14710
  const lines = readFileLines(rootDir, candidate.path, fileCache);
14419
14711
  if (!lines)
14420
14712
  return;
14421
- const definition = resolvePromptLiteralDefinition(lines, candidate.startLine);
14713
+ const definition = resolvePromptLiteralDefinition(lines, candidate.startLine, jsSources.get(`${rootDir}::${candidate.path}`), candidate.excerpt);
14422
14714
  if (!definition)
14423
14715
  return;
14424
14716
  const value = definition.text.trim();
14425
14717
  const literalText = value.replace(/\$\{[^}]*\}|\{[A-Za-z_][\w.]*\}/g, "").trim();
14426
- if (literalText.length < MIN_RESOLVED_PROMPT_CHARS || isCodeLikeContent(value))
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))
14427
14722
  return;
14428
14723
  const key = definition.key ?? (definition.identifier && DIRECT_PROMPT_KEYS.has(definition.identifier) ? definition.identifier : undefined);
14429
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
+ }
14430
14738
  if (key && isDirectModelInput(key, value, candidate.path, lines, definition.line, files.model)) {
14431
14739
  use = { path: candidate.path, line: definition.line, key };
14432
14740
  }
@@ -14435,9 +14743,15 @@ function promotePromptLiteralCandidate(candidate, rootDir, confidence2, fileCach
14435
14743
  allowReference: readsAsInstructions(definition.identifier, value)
14436
14744
  });
14437
14745
  }
14438
- if (!use)
14439
- return;
14440
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
+ }
14441
14755
  const evidence = [{ path: candidate.path, line: definition.line, reason: `deterministic detector ${candidate.signal}` }];
14442
14756
  const sameSite = use.path === candidate.path && use.line === definition.line;
14443
14757
  if (!sameSite) {
@@ -14448,13 +14762,13 @@ function promotePromptLiteralCandidate(candidate, rootDir, confidence2, fileCach
14448
14762
  });
14449
14763
  }
14450
14764
  return {
14451
- id: stableId("prompt", `${pathStem(candidate.path)}:L${definition.line}`),
14765
+ id: stableId("prompt", `${pathStem(candidate.path)}:L${definition.line}${definition.column ? `C${definition.column}` : ""}`),
14452
14766
  type: "prompt",
14453
14767
  name: name ? titleFromId(name) : `Inline Prompt (${candidate.path}:${definition.line})`,
14454
14768
  scope: "shared",
14455
14769
  usedByAgentIds: [],
14456
- confidence: use.referenceOnly ? Math.min(confidence2, REFERENCED_PROMPT_CONFIDENCE) : confidence2,
14457
- 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}.`,
14458
14772
  evidence,
14459
14773
  body: definition.text
14460
14774
  };
@@ -14486,6 +14800,14 @@ function mergePromotedDuplicate(existing, next) {
14486
14800
  existing.body = next.body;
14487
14801
  }
14488
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) {
14489
14811
  const fileCache = new Map;
14490
14812
  const byId = new Map;
14491
14813
  const files = {
@@ -14502,7 +14824,9 @@ function promoteHarnessCandidates(report, rootDir) {
14502
14824
  artifact = promoteToolCandidate(candidate, rootDir, confidence2, fileCache);
14503
14825
  break;
14504
14826
  case "prompt_file":
14505
- if (candidate.signal === "prompt_module.name_hint" && (TEST_PATH2.test(candidate.path) || !buildsPrompts(candidate.path, readFileLines(rootDir, candidate.path, fileCache))))
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))
14506
14830
  break;
14507
14831
  artifact = promotePromptFileCandidate(candidate, confidence2);
14508
14832
  break;
@@ -14861,7 +15185,7 @@ async function runHarnessCommand(context) {
14861
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.");
14862
15186
  }
14863
15187
  if (context.flags["github-actions"] === "true") {
14864
- const { runGithubActionsAnalyze } = await import("./harness-github-actions-6bex338w.js");
15188
+ const { runGithubActionsAnalyze } = await import("./harness-github-actions-yev2yrkr.js");
14865
15189
  const result = await runGithubActionsAnalyze(rootDir, {
14866
15190
  writeReport: (report2) => {
14867
15191
  const normalized = normalizeHarnessReport(report2);
@@ -16707,6 +17031,7 @@ function renderExternalHarnessAnalystPrompt(options) {
16707
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.",
16708
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.',
16709
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.",
16710
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."',
16711
17036
  "Each graph item with evidence must use evidence: [{ path, reason }], not citationIds/citations.",
16712
17037
  ...spec ? spec.contractLines : [
@@ -16845,7 +17170,7 @@ function renderAnalystCandidateLines(report, concern) {
16845
17170
  const lines = [
16846
17171
  "",
16847
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):`,
16848
- 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.'
16849
17174
  ];
16850
17175
  if (concern === "evals") {
16851
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.");
package/dist/cli.js CHANGED
@@ -2968,25 +2968,25 @@ function leafManifestFields(leaf, commands) {
2968
2968
  import { fileURLToPath } from "url";
2969
2969
  import { realpathSync } from "fs";
2970
2970
  async function runPromptsCommand(...args) {
2971
- return (await import("./prompts-r0mv69yx.js")).runPromptsCommand(...args);
2971
+ return (await import("./prompts-y35emwj0.js")).runPromptsCommand(...args);
2972
2972
  }
2973
2973
  async function runSkillsCommand(...args) {
2974
2974
  return (await import("./skills-etzcqhp8.js")).runSkillsCommand(...args);
2975
2975
  }
2976
2976
  async function runHarnessCommand(...args) {
2977
- return (await import("./harness-j0n400bv.js")).runHarnessCommand(...args);
2977
+ return (await import("./harness-2vkcwm85.js")).runHarnessCommand(...args);
2978
2978
  }
2979
2979
  async function runSyncCommand(...args) {
2980
- return (await import("./sync-p4dz7qmn.js")).runSyncCommand(...args);
2980
+ return (await import("./sync-ydfxfjs5.js")).runSyncCommand(...args);
2981
2981
  }
2982
2982
  async function runRegistryCommand(...args) {
2983
2983
  return (await import("./registry-wv1zzyce.js")).runRegistryCommand(...args);
2984
2984
  }
2985
2985
  async function runDoctorCommand(...args) {
2986
- return (await import("./doctor-r16n0me8.js")).runDoctorCommand(...args);
2986
+ return (await import("./doctor-q8khayre.js")).runDoctorCommand(...args);
2987
2987
  }
2988
2988
  async function runStatusCommand(...args) {
2989
- return (await import("./doctor-r16n0me8.js")).runStatusCommand(...args);
2989
+ return (await import("./doctor-q8khayre.js")).runStatusCommand(...args);
2990
2990
  }
2991
2991
  async function runAuthCommand(...args) {
2992
2992
  return (await import("./profile-commands-yvpe4d8y.js")).runAuthCommand(...args);
@@ -2998,7 +2998,7 @@ async function runProfilesCommand(...args) {
2998
2998
  return (await import("./profile-commands-yvpe4d8y.js")).runProfilesCommand(...args);
2999
2999
  }
3000
3000
  async function runAgentCommand(...args) {
3001
- return (await import("./agent-dc9zkdsm.js")).runAgentCommand(...args);
3001
+ return (await import("./agent-j0syymez.js")).runAgentCommand(...args);
3002
3002
  }
3003
3003
  async function runProductionCommand(...args) {
3004
3004
  return (await import("./production-intelligence-fqvhzq6s.js")).runProductionCommand(...args);
@@ -6762,7 +6762,7 @@ var commandRegistry = createCommandRegistry([
6762
6762
  resetApiRequestCountBeforeRun: true,
6763
6763
  telemetry: "result-and-error",
6764
6764
  handler: async (context) => {
6765
- const { runInit } = await import("./index-ecy3ntzc.js");
6765
+ const { runInit } = await import("./index-k6xec97f.js");
6766
6766
  if (context.outputMode === "agent-stream") {
6767
6767
  context.output.writeEvent({
6768
6768
  event: "started",
@@ -3,9 +3,9 @@ import {
3
3
  promptsDiscoveredCheck,
4
4
  runDoctorCommand,
5
5
  runStatusCommand
6
- } from "./cli-eqj302as.js";
6
+ } from "./cli-7epk27vq.js";
7
7
  import"./cli-94r5x9bg.js";
8
- import"./cli-jnwba1f3.js";
8
+ import"./cli-jrf8annc.js";
9
9
  import"./cli-mm48br00.js";
10
10
  import"./cli-xq45etg1.js";
11
11
  import"./cli-v2h21cgf.js";
@@ -43,7 +43,7 @@ import {
43
43
  writeHarnessAnalyzeResult,
44
44
  writeHarnessArtifacts,
45
45
  writeHumanProgress
46
- } from "./cli-px4dmcy0.js";
46
+ } from "./cli-p7856v3b.js";
47
47
  import"./cli-97fnztpy.js";
48
48
  import"./cli-xq45etg1.js";
49
49
  import"./cli-v2h21cgf.js";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  buildSourceSnapshot
3
- } from "./cli-px4dmcy0.js";
3
+ } from "./cli-p7856v3b.js";
4
4
  import"./cli-97fnztpy.js";
5
5
  import"./cli-xq45etg1.js";
6
6
  import"./cli-v2h21cgf.js";
@@ -21,7 +21,7 @@ import {
21
21
  } from "./cli-hcwdz9sd.js";
22
22
  import {
23
23
  buildDoctorReport
24
- } from "./cli-eqj302as.js";
24
+ } from "./cli-7epk27vq.js";
25
25
  import {
26
26
  ConnectCodeError,
27
27
  connectWithCode,
@@ -32,7 +32,7 @@ import {
32
32
  import {
33
33
  initPrompts,
34
34
  runPromptSync
35
- } from "./cli-jnwba1f3.js";
35
+ } from "./cli-jrf8annc.js";
36
36
  import"./cli-mm48br00.js";
37
37
  import {
38
38
  codingAgentDisplayName,
@@ -46,7 +46,7 @@ import {
46
46
  runCodingAgent,
47
47
  runHarnessCommand,
48
48
  startRemoteAnalyze
49
- } from "./cli-px4dmcy0.js";
49
+ } from "./cli-p7856v3b.js";
50
50
  import {
51
51
  stripAnsi
52
52
  } from "./cli-97fnztpy.js";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  inventoryFiles,
3
3
  safePromptEvidencePath
4
- } from "./cli-px4dmcy0.js";
4
+ } from "./cli-p7856v3b.js";
5
5
  import"./cli-97fnztpy.js";
6
6
  import"./cli-xq45etg1.js";
7
7
  import"./cli-v2h21cgf.js";
@@ -3,7 +3,7 @@ import {
3
3
  checkPromptMapping,
4
4
  discoverHarnessPromptSources,
5
5
  safePromptEvidencePath
6
- } from "./cli-px4dmcy0.js";
6
+ } from "./cli-p7856v3b.js";
7
7
  import"./cli-97fnztpy.js";
8
8
  import"./cli-xq45etg1.js";
9
9
  import"./cli-v2h21cgf.js";
@@ -9,7 +9,7 @@ import {
9
9
  runPromptSync,
10
10
  runPromptsCommand,
11
11
  writePromptSyncProgress
12
- } from "./cli-jnwba1f3.js";
12
+ } from "./cli-jrf8annc.js";
13
13
  import {
14
14
  promptSourceHashPayload
15
15
  } from "./cli-mm48br00.js";
@@ -6,11 +6,11 @@ import"./cli-rjav0vj1.js";
6
6
  import"./cli-hcwdz9sd.js";
7
7
  import {
8
8
  runPromptsCommand
9
- } from "./cli-jnwba1f3.js";
9
+ } from "./cli-jrf8annc.js";
10
10
  import"./cli-mm48br00.js";
11
11
  import {
12
12
  runHarnessCommand
13
- } from "./cli-px4dmcy0.js";
13
+ } from "./cli-p7856v3b.js";
14
14
  import"./cli-97fnztpy.js";
15
15
  import"./cli-xq45etg1.js";
16
16
  import"./cli-v2h21cgf.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moda-ai/cli",
3
- "version": "1.55.55",
3
+ "version": "1.55.56",
4
4
  "description": "CLI for Moda: production monitoring and evals for AI agents.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schema_version": "moda.skill_index.v1",
3
- "bundled_at": "2026-10-21T02:38:15.319Z",
4
- "cli_version": "1.55.55",
3
+ "bundled_at": "2026-10-21T02:54:32.332Z",
4
+ "cli_version": "1.55.56",
5
5
  "skills": [
6
6
  {
7
7
  "id": "integration-cloudflare-think",