@moda-ai/cli 1.55.51 → 1.55.53

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-3pn6w6m3.js";
3
+ } from "./cli-thhggczw.js";
4
4
  import"./cli-rdh9jjr2.js";
5
- import"./cli-s3bcce69.js";
5
+ import"./cli-r4k0yfkt.js";
6
6
  import"./cli-mm48br00.js";
7
7
  import {
8
8
  readHarnessSyncState
@@ -26,7 +26,7 @@ import {
26
26
  hashStableJson,
27
27
  readHarnessReport,
28
28
  validateHarnessReport
29
- } from "./cli-wqyrcnm1.js";
29
+ } from "./cli-6hdqp65a.js";
30
30
  import {
31
31
  CliInputError
32
32
  } from "./cli-k4tqwah4.js";
@@ -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-0pzqswvr.js") : undefined;
98
+ const harness = graph ? await import("./harness-3bcakwrv.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),
@@ -882,6 +882,28 @@ function hasEvidenceLine(evidence) {
882
882
  line: typeof entry.line === "number" ? entry.line : undefined
883
883
  }) !== undefined);
884
884
  }
885
+ var RUNTIME_AGENT_LINK_FIELDS = [
886
+ "entrypointIds",
887
+ "channelAdapterIds",
888
+ "artifactIds",
889
+ "identityNamespaceIds",
890
+ "deploymentIds",
891
+ "frameworkIds",
892
+ "modelProviderIds",
893
+ "evidence"
894
+ ];
895
+ var HARNESS_ARTIFACT_TYPES = new Set([
896
+ "entrypoint",
897
+ "prompt",
898
+ "tool",
899
+ "skill",
900
+ "eval",
901
+ "retrieval_index",
902
+ "memory",
903
+ "guardrail",
904
+ "model_config",
905
+ "unknown"
906
+ ]);
885
907
  function normalizeGraphItemFieldAliases(collection, item) {
886
908
  if (!isRecord(item))
887
909
  return;
@@ -890,6 +912,32 @@ function normalizeGraphItemFieldAliases(collection, item) {
890
912
  if (typeof item.sourcePath !== "string")
891
913
  item.sourcePath = firstEvidencePath(item) ?? ".";
892
914
  }
915
+ if (collection === "runtimeAgents") {
916
+ if (typeof item.kind !== "string")
917
+ item.kind = "runtime_agent";
918
+ if (typeof item.root !== "string" || item.root.length === 0)
919
+ item.root = ".";
920
+ for (const key of RUNTIME_AGENT_LINK_FIELDS) {
921
+ if (!Array.isArray(item[key]))
922
+ item[key] = [];
923
+ }
924
+ }
925
+ if (collection === "artifacts") {
926
+ if (typeof item.type !== "string" || item.type.length === 0) {
927
+ item.type = typeof item.kind === "string" && HARNESS_ARTIFACT_TYPES.has(item.kind) ? item.kind : "unknown";
928
+ }
929
+ if (typeof item.sourcePath !== "string" && typeof item.path === "string" && item.path.length > 0) {
930
+ item.sourcePath = item.path;
931
+ }
932
+ if (typeof item.name !== "string" || item.name.length === 0) {
933
+ item.name = firstEvidencePath(item) ?? (typeof item.id === "string" ? item.id : "unnamed");
934
+ }
935
+ if (typeof item.scope !== "string" || item.scope.length === 0) {
936
+ item.scope = typeof item.ownedByAgentId === "string" ? "agent" : "shared";
937
+ }
938
+ if (!Array.isArray(item.usedByAgentIds))
939
+ item.usedByAgentIds = [];
940
+ }
893
941
  if (collection === "channelAdapters" && typeof item.kind !== "string")
894
942
  item.kind = "unknown";
895
943
  if (collection === "identityNamespaces" && typeof item.kind !== "string")
@@ -90,7 +90,7 @@ import {
90
90
  stampRemoteSnapshotTruncation,
91
91
  validateHarnessReport,
92
92
  writeHarnessReportArtifacts
93
- } from "./cli-wqyrcnm1.js";
93
+ } from "./cli-6hdqp65a.js";
94
94
  import {
95
95
  CliInputError,
96
96
  CliInputRequiredError
@@ -107,15 +107,15 @@ import { homedir, tmpdir as tmpdir2 } from "node:os";
107
107
  import { fileURLToPath } from "node:url";
108
108
  import {
109
109
  existsSync as existsSync8,
110
- lstatSync as lstatSync7,
110
+ lstatSync as lstatSync8,
111
111
  mkdtempSync as mkdtempSync2,
112
112
  mkdirSync as mkdirSync5,
113
- readFileSync as readFileSync12,
114
- readdirSync as readdirSync4,
113
+ readFileSync as readFileSync13,
114
+ readdirSync as readdirSync5,
115
115
  writeFileSync as writeFileSync5,
116
116
  rmSync as rmSync4
117
117
  } from "node:fs";
118
- import { basename as basename6, delimiter, dirname as dirname7, join as join9, relative as relative6, resolve as resolve10, sep as sep5 } from "node:path";
118
+ import { basename as basename6, delimiter, dirname as dirname7, join as join10, relative as relative7, resolve as resolve10, sep as sep5 } from "node:path";
119
119
  import { confirm, select } from "@inquirer/prompts";
120
120
 
121
121
  // src/analyst-tui.ts
@@ -12333,6 +12333,7 @@ var NON_PROMPT_DOC_BASENAMES = new Set([
12333
12333
  "requirements.txt"
12334
12334
  ]);
12335
12335
  var PROMPT_NAME_HINT = /(prompt|system[-_]?message|instruction|persona|sop)/i;
12336
+ var PROMPTS_DIR = /(^|\/)(?:system[-_]?)?prompts?(\/|$)/i;
12336
12337
  var AGENTIC_DIR_HINT = /(^|\/)(agents?|prompts?|llm|ai|assistants?|chains?|crew|graph)s?(\/|$)/i;
12337
12338
  var INSTRUCTION_MARKERS = [
12338
12339
  /\byou are\b/i,
@@ -12532,6 +12533,9 @@ function detectPromptFile(file, out) {
12532
12533
  if (nameHint) {
12533
12534
  confidence2 = "high";
12534
12535
  signal = "prompt_file.name_hint";
12536
+ } else if (PROMPTS_DIR.test(dir)) {
12537
+ confidence2 = "high";
12538
+ signal = "prompt_file.prompts_dir";
12535
12539
  } else if (dirHint && score >= 3) {
12536
12540
  confidence2 = "medium";
12537
12541
  signal = "prompt_file.agent_dir_instruction_text";
@@ -14465,6 +14469,8 @@ function promoteHarnessCandidates(report, rootDir) {
14465
14469
  artifact = promoteToolCandidate(candidate, rootDir, confidence2, fileCache);
14466
14470
  break;
14467
14471
  case "prompt_file":
14472
+ if (candidate.signal === "prompt_module.name_hint")
14473
+ break;
14468
14474
  artifact = promotePromptFileCandidate(candidate, confidence2);
14469
14475
  break;
14470
14476
  case "prompt_literal":
@@ -14491,6 +14497,245 @@ function promoteHarnessCandidates(report, rootDir) {
14491
14497
  return [...byId.values()];
14492
14498
  }
14493
14499
 
14500
+ // src/harness-wrangler-bindings.ts
14501
+ import { lstatSync as lstatSync7, readdirSync as readdirSync4, readFileSync as readFileSync12 } from "node:fs";
14502
+ import { join as join9, relative as relative6 } from "node:path";
14503
+ var WRANGLER_FILE = /^wrangler\.jsonc?$/;
14504
+ var SKIPPED_DIRS2 = new Set(["node_modules", ".git", ".wrangler", "dist", "build", ".next", ".turbo", "vendor"]);
14505
+ var MAX_DEPTH = 4;
14506
+ var AGENT_CLASS = /Agent(?:V\d+)?$/;
14507
+ function stripJsonc2(text) {
14508
+ let out = "";
14509
+ let inString = false;
14510
+ for (let i = 0;i < text.length; i += 1) {
14511
+ const ch = text[i];
14512
+ if (inString) {
14513
+ out += ch;
14514
+ if (ch === "\\") {
14515
+ out += text[i + 1] ?? "";
14516
+ i += 1;
14517
+ } else if (ch === '"') {
14518
+ inString = false;
14519
+ }
14520
+ continue;
14521
+ }
14522
+ if (ch === '"') {
14523
+ inString = true;
14524
+ out += ch;
14525
+ } else if (ch === "/" && text[i + 1] === "/") {
14526
+ while (i < text.length && text[i] !== `
14527
+ `)
14528
+ i += 1;
14529
+ out += `
14530
+ `;
14531
+ } else if (ch === "/" && text[i + 1] === "*") {
14532
+ i += 2;
14533
+ while (i < text.length && !(text[i] === "*" && text[i + 1] === "/")) {
14534
+ if (text[i] === `
14535
+ `)
14536
+ out += `
14537
+ `;
14538
+ i += 1;
14539
+ }
14540
+ i += 1;
14541
+ } else {
14542
+ out += ch;
14543
+ }
14544
+ }
14545
+ return out.replace(/,(\s*[}\]])/g, "$1");
14546
+ }
14547
+ function findWranglerFiles(rootDir) {
14548
+ const found = [];
14549
+ const walk = (dir, depth) => {
14550
+ let entries;
14551
+ try {
14552
+ entries = readdirSync4(dir);
14553
+ } catch {
14554
+ return;
14555
+ }
14556
+ for (const name of entries) {
14557
+ const abs = join9(dir, name);
14558
+ let stat;
14559
+ try {
14560
+ stat = lstatSync7(abs);
14561
+ } catch {
14562
+ continue;
14563
+ }
14564
+ if (stat.isDirectory()) {
14565
+ if (depth < MAX_DEPTH && !SKIPPED_DIRS2.has(name) && !name.startsWith("."))
14566
+ walk(abs, depth + 1);
14567
+ } else if (stat.isFile() && WRANGLER_FILE.test(name)) {
14568
+ found.push(abs);
14569
+ }
14570
+ }
14571
+ };
14572
+ walk(rootDir, 0);
14573
+ return found.sort();
14574
+ }
14575
+ function lineOf(text, className) {
14576
+ const index = text.search(new RegExp(`"class_name"\\s*:\\s*"${className.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}"`));
14577
+ return index < 0 ? undefined : text.slice(0, index).split(`
14578
+ `).length;
14579
+ }
14580
+ function workerDir(path) {
14581
+ const slash = path.lastIndexOf("/");
14582
+ return slash < 0 ? "" : path.slice(0, slash);
14583
+ }
14584
+ function detectBoundRuntimeClasses(rootDir) {
14585
+ const byClass = new Map;
14586
+ for (const abs of findWranglerFiles(rootDir)) {
14587
+ let text;
14588
+ let config2;
14589
+ try {
14590
+ text = readFileSync12(abs, "utf8");
14591
+ config2 = JSON.parse(stripJsonc2(text));
14592
+ } catch {
14593
+ continue;
14594
+ }
14595
+ if (!config2 || typeof config2 !== "object")
14596
+ continue;
14597
+ const path = relative6(rootDir, abs).split("\\").join("/");
14598
+ const root = config2;
14599
+ const sections2 = [root, ...Object.values(root.env ?? {})];
14600
+ for (const section of sections2) {
14601
+ if (!section || typeof section !== "object")
14602
+ continue;
14603
+ const s = section;
14604
+ const durable = s.durable_objects?.bindings;
14605
+ const entries = [
14606
+ ...Array.isArray(durable) ? durable.map((b) => ["durable_object", b]) : [],
14607
+ ...Array.isArray(s.workflows) ? s.workflows.map((w) => ["workflow", w]) : []
14608
+ ];
14609
+ for (const [kind, raw] of entries) {
14610
+ if (!raw || typeof raw !== "object")
14611
+ continue;
14612
+ const entry = raw;
14613
+ const className = typeof entry.class_name === "string" ? entry.class_name : "";
14614
+ const scriptName = typeof entry.script_name === "string" && entry.script_name ? entry.script_name : undefined;
14615
+ const key = `${className}|${scriptName ? "external" : `config:${path}`}`;
14616
+ if (!className || byClass.has(key))
14617
+ continue;
14618
+ const binding = typeof (kind === "workflow" ? entry.binding : entry.name) === "string" ? String(kind === "workflow" ? entry.binding : entry.name) : className;
14619
+ byClass.set(key, {
14620
+ className,
14621
+ kind,
14622
+ binding,
14623
+ ...scriptName ? { scriptName } : {},
14624
+ path,
14625
+ line: lineOf(text, className)
14626
+ });
14627
+ }
14628
+ }
14629
+ }
14630
+ return [...byClass.values()];
14631
+ }
14632
+ function norm(value) {
14633
+ return typeof value === "string" ? value.toLowerCase().replace(/[^a-z0-9]/g, "") : "";
14634
+ }
14635
+ function itemPaths(item) {
14636
+ const paths = [];
14637
+ for (const value of [item.root, item.sourcePath]) {
14638
+ if (typeof value === "string" && value && value !== ".")
14639
+ paths.push(value.replace(/^\.\//, ""));
14640
+ }
14641
+ for (const entry of Array.isArray(item.evidence) ? item.evidence : []) {
14642
+ const path = entry && typeof entry === "object" ? entry.path : undefined;
14643
+ if (typeof path === "string" && path)
14644
+ paths.push(path.replace(/^\.\//, ""));
14645
+ }
14646
+ return paths;
14647
+ }
14648
+ function withinWorker(path, dir, otherDirs) {
14649
+ const inside = (d) => d === "" || path === d || path.startsWith(`${d}/`);
14650
+ return inside(dir) && !otherDirs.some((other) => other.length > dir.length && inside(other));
14651
+ }
14652
+ function graphNamesClass(graph, bound, all) {
14653
+ const target = norm(bound.className);
14654
+ const named = (name) => {
14655
+ if (typeof name !== "string")
14656
+ return false;
14657
+ const bare = name.replace(/\s*\([^)]*\)\s*$/, "");
14658
+ return norm(bare) === target || bare.split(/[^A-Za-z0-9_]+/).some((word) => norm(word) === target);
14659
+ };
14660
+ const sameName = bound.scriptName ? [bound] : all.filter((other) => other.className === bound.className && !other.scriptName);
14661
+ const dir = workerDir(bound.path);
14662
+ const otherDirs = sameName.map((other) => workerDir(other.path)).filter((other) => other !== dir);
14663
+ const covers = (item) => {
14664
+ if (!named(item.name))
14665
+ return false;
14666
+ if (sameName.length < 2)
14667
+ return true;
14668
+ return itemPaths(item).some((path) => withinWorker(path, dir, otherDirs));
14669
+ };
14670
+ return graph.runtimeAgents.some(covers) || graph.artifacts.some(covers);
14671
+ }
14672
+ function bindingReason(bound) {
14673
+ const what = bound.kind === "workflow" ? "Workflow" : "Durable Object";
14674
+ const where = bound.scriptName ? ` served by the external Worker "${bound.scriptName}"` : "";
14675
+ return `${what} binding ${bound.binding} -> class ${bound.className}${where}`;
14676
+ }
14677
+ function uniqueId(base, taken) {
14678
+ let id = base;
14679
+ for (let n = 2;taken.has(id); n += 1)
14680
+ id = `${base}-${n}`;
14681
+ taken.add(id);
14682
+ return id;
14683
+ }
14684
+ function mergeBoundRuntimeClasses(graph, rootDir) {
14685
+ if (process.env.MODA_HARNESS_DETERMINISTIC_MERGE === "0")
14686
+ return { added: 0 };
14687
+ let bound;
14688
+ try {
14689
+ bound = detectBoundRuntimeClasses(rootDir);
14690
+ } catch {
14691
+ return { added: 0 };
14692
+ }
14693
+ const taken = new Set([
14694
+ ...graph.runtimeAgents.map((agent) => agent.id),
14695
+ ...graph.artifacts.map((artifact) => artifact.id)
14696
+ ]);
14697
+ let added = 0;
14698
+ for (const entry of bound) {
14699
+ if (graphNamesClass(graph, entry, bound))
14700
+ continue;
14701
+ const evidence = [{ path: entry.path, ...entry.line ? { line: entry.line } : {}, reason: bindingReason(entry) }];
14702
+ const slug = entry.className.replace(/[^A-Za-z0-9]+/g, "-").toLowerCase();
14703
+ if (entry.kind === "durable_object" && AGENT_CLASS.test(entry.className) && !entry.scriptName) {
14704
+ const agent = {
14705
+ id: uniqueId(`agent.bound.${slug}`, taken),
14706
+ name: entry.className,
14707
+ kind: "runtime_agent",
14708
+ purpose: "Agent class bound as a Durable Object.",
14709
+ root: ".",
14710
+ entrypointIds: [],
14711
+ channelAdapterIds: [],
14712
+ artifactIds: [],
14713
+ identityNamespaceIds: [],
14714
+ deploymentIds: [],
14715
+ frameworkIds: [],
14716
+ modelProviderIds: [],
14717
+ confidence: 0.6,
14718
+ evidence
14719
+ };
14720
+ graph.runtimeAgents.push(agent);
14721
+ } else {
14722
+ const artifact = {
14723
+ id: uniqueId(`entrypoint.bound.${slug}`, taken),
14724
+ type: "entrypoint",
14725
+ name: entry.className,
14726
+ scope: "shared",
14727
+ sourcePath: entry.path,
14728
+ usedByAgentIds: [],
14729
+ confidence: 0.6,
14730
+ evidence
14731
+ };
14732
+ graph.artifacts.push(artifact);
14733
+ }
14734
+ added += 1;
14735
+ }
14736
+ return { added };
14737
+ }
14738
+
14494
14739
  // src/harness-sync-limits.ts
14495
14740
  var MAX_HARNESS_SYNC_GRAPH_BYTES = 2000000;
14496
14741
  function assertHarnessGraphSyncSize(graph) {
@@ -14509,8 +14754,8 @@ function assertHarnessGraphSyncSize(graph) {
14509
14754
  }
14510
14755
  // src/harness.ts
14511
14756
  var MODA_DIR = ".moda";
14512
- var HARNESS_PATH = join9(MODA_DIR, "harness.json");
14513
- var HARNESS_SUMMARY_PATH = join9(MODA_DIR, "HARNESS.md");
14757
+ var HARNESS_PATH = join10(MODA_DIR, "harness.json");
14758
+ var HARNESS_SUMMARY_PATH = join10(MODA_DIR, "HARNESS.md");
14514
14759
  var SCHEMA_VERSION = "harness.v0.1";
14515
14760
  var REPORT_JSON_BEGIN = "MODA_HARNESS_REPORT_JSON_BEGIN";
14516
14761
  var REPORT_JSON_END = "MODA_HARNESS_REPORT_JSON_END";
@@ -14535,6 +14780,7 @@ var HARNESS_FAMILY_FLAGS = [
14535
14780
  "offset",
14536
14781
  "out",
14537
14782
  "path",
14783
+ "promote",
14538
14784
  "remote",
14539
14785
  "report",
14540
14786
  "run",
@@ -14675,7 +14921,7 @@ async function runHarnessCommand(context) {
14675
14921
  report: {
14676
14922
  reportId: report.reportId,
14677
14923
  reportHash,
14678
- path: normalizePath2(relative6(rootDir, reportPath)) || ".moda/harness-report.json"
14924
+ path: normalizePath2(relative7(rootDir, reportPath)) || ".moda/harness-report.json"
14679
14925
  },
14680
14926
  validation,
14681
14927
  approval: {
@@ -14821,7 +15067,7 @@ async function runHarnessCommand(context) {
14821
15067
  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.");
14822
15068
  }
14823
15069
  if (context.flags["github-actions"] === "true") {
14824
- const { runGithubActionsAnalyze } = await import("./harness-github-actions-nzcpftjn.js");
15070
+ const { runGithubActionsAnalyze } = await import("./harness-github-actions-1031t1kt.js");
14825
15071
  const result = await runGithubActionsAnalyze(rootDir, {
14826
15072
  writeReport: (report2) => {
14827
15073
  const normalized = normalizeHarnessReport(report2);
@@ -14943,7 +15189,7 @@ async function runHarnessCommand(context) {
14943
15189
  report: {
14944
15190
  reportId: approval.report.reportId,
14945
15191
  reportHash: hashHarnessReport(approval.report),
14946
- path: normalizePath2(relative6(rootDir, reportPath)) || ".moda/harness-report.json"
15192
+ path: normalizePath2(relative7(rootDir, reportPath)) || ".moda/harness-report.json"
14947
15193
  },
14948
15194
  validation: approval.validation,
14949
15195
  approval: approval.approval
@@ -14956,6 +15202,28 @@ async function runHarnessCommand(context) {
14956
15202
  message: "Scan this project for static harness candidates?"
14957
15203
  });
14958
15204
  writeHumanProgress(context, "Harness candidates: static pre-pass (no LLM, no network)...");
15205
+ if (context.flags.promote !== undefined) {
15206
+ const promote = context.flags.promote === "true" ? "all" : context.flags.promote.trim().toLowerCase();
15207
+ if (promote !== "all" && !HARNESS_ANALYZE_CONCERNS.includes(promote)) {
15208
+ throw new CliInputError(`Unknown --promote value "${context.flags.promote}".`, `Use --promote=all or one of: ${HARNESS_ANALYZE_CONCERNS.join(", ")}.`);
15209
+ }
15210
+ const promoteOut = context.flags.out;
15211
+ if (promoteOut === "true") {
15212
+ throw new CliInputError("Missing output path for --out.", "Usage: moda harness candidates --promote=<concern|all> --out=<file>");
15213
+ }
15214
+ const artifacts = deterministicArtifacts(rootDir, promote === "all" ? undefined : promote);
15215
+ const promoted = { concern: promote, artifacts };
15216
+ const promoteWritten = [];
15217
+ if (promoteOut && !context.dryRun) {
15218
+ const target = resolve10(context.cwd, promoteOut);
15219
+ mkdirSync5(dirname7(target), { recursive: true });
15220
+ writeFileSync5(target, `${JSON.stringify(promoted, null, 2)}
15221
+ `, "utf8");
15222
+ promoteWritten.push(target);
15223
+ }
15224
+ context.output.writeData({ scanPlan, ...promoted, written: promoteWritten, dryRun: context.dryRun });
15225
+ return { exitCode: 0 };
15226
+ }
14959
15227
  const report = detectHarnessCandidates(rootDir);
14960
15228
  const written = [];
14961
15229
  const outFlag = context.flags.out;
@@ -15011,7 +15279,7 @@ async function runHarnessCommand(context) {
15011
15279
  return { exitCode: 0 };
15012
15280
  }
15013
15281
  case "status": {
15014
- const manifestPath = join9(rootDir, HARNESS_PATH);
15282
+ const manifestPath = join10(rootDir, HARNESS_PATH);
15015
15283
  const graph = existsSync8(manifestPath) ? readHarnessGraph(manifestPath) : scanHarness({
15016
15284
  rootDir,
15017
15285
  tenantId: tenant?.tenantId,
@@ -15152,10 +15420,10 @@ function emitWrittenArtifacts(context, written, description) {
15152
15420
  }
15153
15421
  }
15154
15422
  async function runPromptConcernAnalysis(context, rootDir, scanPlan, tenant) {
15155
- const manifest = join9(rootDir, ".moda/prompts.yml");
15423
+ const manifest = join10(rootDir, ".moda/prompts.yml");
15156
15424
  let existing = [];
15157
15425
  if (existsSync8(manifest)) {
15158
- const document = $parseDocument(readFileSync12(manifest, "utf8"));
15426
+ const document = $parseDocument(readFileSync13(manifest, "utf8"));
15159
15427
  if (document.errors.length)
15160
15428
  throw new CliInputError("Invalid prompt manifest.", document.errors[0].message);
15161
15429
  existing = document.toJS({ maxAliasCount: 20 })?.sources ?? [];
@@ -15409,7 +15677,7 @@ function readExternalAnalystReport(rootDir, result, adapter, concern) {
15409
15677
  result.stderr
15410
15678
  ].join(`
15411
15679
  `));
15412
- debugHint = `Raw analyst output saved to ${join9(MODA_DIR, "analyst-debug.log")} for debugging.`;
15680
+ debugHint = `Raw analyst output saved to ${join10(MODA_DIR, "analyst-debug.log")} for debugging.`;
15413
15681
  } catch {}
15414
15682
  throw new CliInputError(`Harness analyst ${adapter} did not return a harness report.`, [
15415
15683
  `Expected ${HARNESS_REPORT_PATH} or final JSON between ${REPORT_JSON_BEGIN} and ${REPORT_JSON_END}.`,
@@ -15474,6 +15742,17 @@ function applyResolvedPromptSource(artifact, source) {
15474
15742
  artifact.sourcePath = source.sourcePath;
15475
15743
  artifact.contentHash = source.sourceDefinition.sourceHash;
15476
15744
  }
15745
+ function isToolGroupPlaceholder(name) {
15746
+ const trimmed = (name ?? "").trim();
15747
+ if (!trimmed)
15748
+ return false;
15749
+ if (trimmed.includes("*"))
15750
+ return true;
15751
+ return /\s(?:tools|toolkits?|toolsets?)$/i.test(trimmed);
15752
+ }
15753
+ function isDetectedToolDefinitionReason(reason) {
15754
+ return typeof reason === "string" && (reason.startsWith("deterministic detector ") || reason.startsWith("Tool definition detected"));
15755
+ }
15477
15756
  function removeArtifacts(report, ids) {
15478
15757
  const graph = report.graph;
15479
15758
  const keep = (id) => typeof id !== "string" || !ids.has(id);
@@ -15507,6 +15786,8 @@ function repairExternalAnalystReport(report, rootDir, options = {}) {
15507
15786
  const normalized = normalizeHarnessReport(report);
15508
15787
  repairCitationLines(normalized, rootDir);
15509
15788
  mergeDeterministicArtifacts(normalized.graph, rootDir, { concern: options.concern });
15789
+ if (!options.concern || options.concern === "topology")
15790
+ mergeBoundRuntimeClasses(normalized.graph, rootDir);
15510
15791
  hydratePromptAndToolBodies(normalized.graph, rootDir);
15511
15792
  const unverified = new Set;
15512
15793
  for (const artifact of normalized.graph.artifacts) {
@@ -15523,6 +15804,33 @@ function repairExternalAnalystReport(report, rootDir, options = {}) {
15523
15804
  normalized.graph.unknowns.push({ id: `unresolved_${artifact.id}`, question: error instanceof Error ? error.message : String(error), candidateIds: [artifact.id], evidence: artifact.evidence });
15524
15805
  }
15525
15806
  }
15807
+ for (const artifact of normalized.graph.artifacts) {
15808
+ if (artifact.type !== "tool" || unverified.has(artifact.id) || !isToolGroupPlaceholder(artifact.name))
15809
+ continue;
15810
+ if (artifact.evidence.some((entry) => isDetectedToolDefinitionReason(entry.reason)))
15811
+ continue;
15812
+ unverified.add(artifact.id);
15813
+ normalized.graph.unknowns.push({
15814
+ id: `unresolved_${artifact.id}`,
15815
+ question: `"${artifact.name}" is a dynamic tool source (a group of tools resolved at runtime), not a single tool definition, so its tools are not enumerated in the harness.`,
15816
+ candidateIds: [artifact.id],
15817
+ evidence: artifact.evidence
15818
+ });
15819
+ }
15820
+ for (const artifact of normalized.graph.artifacts) {
15821
+ if (artifact.type !== "model_config" || unverified.has(artifact.id))
15822
+ continue;
15823
+ const paths = artifact.evidence.map((entry) => entry.path).filter((path) => typeof path === "string" && path.length > 0);
15824
+ if (paths.length === 0 || !paths.every((path) => TEST_PATH2.test(path)))
15825
+ continue;
15826
+ unverified.add(artifact.id);
15827
+ normalized.graph.unknowns.push({
15828
+ id: `unresolved_${artifact.id}`,
15829
+ question: `Model ${artifact.name ?? artifact.id} is cited only from test or fixture files, so it is a test input rather than the harness's model configuration.`,
15830
+ candidateIds: [artifact.id],
15831
+ evidence: artifact.evidence
15832
+ });
15833
+ }
15526
15834
  for (const artifact of normalized.graph.artifacts) {
15527
15835
  if (unverified.has(artifact.id) || !requiresArtifactBody(artifact.type))
15528
15836
  continue;
@@ -15606,6 +15914,12 @@ var CONCERN_PROMOTED_ARTIFACT_TYPES = {
15606
15914
  prompts: new Set(["prompt"]),
15607
15915
  evals: new Set(["model_config"])
15608
15916
  };
15917
+ function deterministicArtifacts(rootDir, concern) {
15918
+ const graph = { artifacts: [], unknowns: [] };
15919
+ mergeDeterministicArtifacts(graph, rootDir, { concern });
15920
+ hydratePromptAndToolBodies(graph, rootDir);
15921
+ return graph.artifacts;
15922
+ }
15609
15923
  function mergeDeterministicArtifacts(graph, rootDir, options = {}) {
15610
15924
  if (process.env.MODA_HARNESS_DETERMINISTIC_MERGE === "0")
15611
15925
  return { added: 0 };
@@ -15767,7 +16081,7 @@ function repairCitationLines(report, rootDir) {
15767
16081
  continue;
15768
16082
  let text;
15769
16083
  try {
15770
- text = readFileSync12(candidatePath, "utf8");
16084
+ text = readFileSync13(candidatePath, "utf8");
15771
16085
  } catch {
15772
16086
  continue;
15773
16087
  }
@@ -16373,14 +16687,14 @@ function createPromptAnalystIsolation(adapter, rootDir) {
16373
16687
  const serverPath = bundledServer ? bundled : source;
16374
16688
  const command = bundledServer ? process.execPath : resolveBunRuntime();
16375
16689
  const serverArgs = [serverPath, "--root", rootDir];
16376
- const tempPath = mkdtempSync2(join9(tmpdir2(), "moda-prompt-analyst-"));
16690
+ const tempPath = mkdtempSync2(join10(tmpdir2(), "moda-prompt-analyst-"));
16377
16691
  const cleanup = () => {
16378
16692
  try {
16379
16693
  rmSync4(tempPath, { recursive: true, force: true });
16380
16694
  } catch {}
16381
16695
  };
16382
16696
  if (adapter === "claude") {
16383
- const configPath = join9(tempPath, "claude-mcp.json");
16697
+ const configPath = join10(tempPath, "claude-mcp.json");
16384
16698
  writeFileSync5(configPath, JSON.stringify({ mcpServers: { "moda-prompt-source": { command, args: serverArgs } } }));
16385
16699
  return { configPath, cleanup };
16386
16700
  }
@@ -16590,6 +16904,9 @@ function renderExternalHarnessAnalystPrompt(options) {
16590
16904
  "- unknowns: report-level open questions with id, question, and citationIds",
16591
16905
  "",
16592
16906
  '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).',
16907
+ `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.`,
16908
+ '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.',
16909
+ "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.",
16593
16910
  '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."',
16594
16911
  "Each graph item with evidence must use evidence: [{ path, reason }], not citationIds/citations.",
16595
16912
  ...spec ? spec.contractLines : [
@@ -16793,10 +17110,10 @@ function readDirectoryPreflightPaths(rootDir) {
16793
17110
  const stack = ["."];
16794
17111
  while (stack.length > 0 && paths.length < 2000) {
16795
17112
  const current = stack.pop() ?? ".";
16796
- const absolute = current === "." ? rootDir : join9(rootDir, current);
17113
+ const absolute = current === "." ? rootDir : join10(rootDir, current);
16797
17114
  let entries;
16798
17115
  try {
16799
- entries = readdirSync4(absolute);
17116
+ entries = readdirSync5(absolute);
16800
17117
  } catch {
16801
17118
  continue;
16802
17119
  }
@@ -16804,10 +17121,10 @@ function readDirectoryPreflightPaths(rootDir) {
16804
17121
  const child = current === "." ? entry : `${current}/${entry}`;
16805
17122
  if (shouldSkipPreflightPath(child))
16806
17123
  continue;
16807
- const childAbsolute = join9(rootDir, child);
17124
+ const childAbsolute = join10(rootDir, child);
16808
17125
  let stat;
16809
17126
  try {
16810
- stat = lstatSync7(childAbsolute);
17127
+ stat = lstatSync8(childAbsolute);
16811
17128
  } catch {
16812
17129
  continue;
16813
17130
  }
@@ -16869,7 +17186,7 @@ function findOnPath(command) {
16869
17186
  if (command.includes("/") && existsSync8(command))
16870
17187
  return command;
16871
17188
  for (const dir of (process.env.PATH ?? "").split(delimiter).filter(Boolean)) {
16872
- const candidate = join9(dir, command);
17189
+ const candidate = join10(dir, command);
16873
17190
  if (existsSync8(candidate))
16874
17191
  return candidate;
16875
17192
  }
@@ -16947,10 +17264,10 @@ function collectSnapshotInputs(rootDir, maxFiles, maxTextBytes) {
16947
17264
  let inventoryFileCount = 0;
16948
17265
  let inventoryTextBytes = 0;
16949
17266
  function walk(current) {
16950
- const path = normalizePath2(relative6(rootDir, current)) || ".";
17267
+ const path = normalizePath2(relative7(rootDir, current)) || ".";
16951
17268
  let stat;
16952
17269
  try {
16953
- stat = lstatSync7(current);
17270
+ stat = lstatSync8(current);
16954
17271
  } catch {
16955
17272
  return;
16956
17273
  }
@@ -16961,8 +17278,8 @@ function collectSnapshotInputs(rootDir, maxFiles, maxTextBytes) {
16961
17278
  if (stat.isDirectory()) {
16962
17279
  if (path !== "." && (isSkippedDir(path) || isSkippedPathPrefix(path)))
16963
17280
  return;
16964
- for (const entry of readdirSync4(current).sort())
16965
- walk(join9(current, entry));
17281
+ for (const entry of readdirSync5(current).sort())
17282
+ walk(join10(current, entry));
16966
17283
  return;
16967
17284
  }
16968
17285
  if (!stat.isFile())
@@ -16985,7 +17302,7 @@ function collectSnapshotInputs(rootDir, maxFiles, maxTextBytes) {
16985
17302
  let text = "";
16986
17303
  if (isTextFile(path)) {
16987
17304
  try {
16988
- text = readFileSync12(current, "utf8");
17305
+ text = readFileSync13(current, "utf8");
16989
17306
  inventoryTextBytes += Buffer.byteLength(text, "utf8");
16990
17307
  } catch {
16991
17308
  return;
@@ -17004,7 +17321,7 @@ function buildSourceSnapshot(rootDir) {
17004
17321
  const inputs = collectSnapshotInputs(root, maxFiles, maxTextBytes);
17005
17322
  const repo = detectRepo(root, inputs.map((input) => ({
17006
17323
  path: input.path,
17007
- absPath: join9(root, input.path),
17324
+ absPath: join10(root, input.path),
17008
17325
  rootDir: root,
17009
17326
  text: input.text
17010
17327
  })));
@@ -17018,7 +17335,7 @@ function buildSourceSnapshot(rootDir) {
17018
17335
  }
17019
17336
  function buildCommandScanPlan(context, rootDir) {
17020
17337
  const explicitPath = context.flags.path !== undefined;
17021
- const rel2 = normalizePath2(relative6(context.cwd, rootDir)) || ".";
17338
+ const rel2 = normalizePath2(relative7(context.cwd, rootDir)) || ".";
17022
17339
  const scope = explicitPath && rel2 !== "." ? "narrow" : "broad";
17023
17340
  const machineReadable = context.outputMode !== "human";
17024
17341
  const approvalRequired = context.positional === "analyze" && scope === "broad" && !context.yes;
@@ -17103,7 +17420,7 @@ function writeHumanBlock(context, message) {
17103
17420
  function buildHarnessReadPlan(rootDir, pathWasExplicit) {
17104
17421
  return {
17105
17422
  scope: pathWasExplicit ? "narrow" : "broad",
17106
- rootPaths: [normalizePath2(relative6(rootDir, rootDir)) || "."],
17423
+ rootPaths: [normalizePath2(relative7(rootDir, rootDir)) || "."],
17107
17424
  willRead: [
17108
17425
  "package manifests",
17109
17426
  "source files under the selected path",
@@ -17221,7 +17538,7 @@ async function syncHarnessWithRemote(context, body) {
17221
17538
  }, profileOptions);
17222
17539
  }
17223
17540
  function writeHarnessSyncState(rootDir, state) {
17224
- const path = join9(rootDir, SYNC_STATE_PATH);
17541
+ const path = join10(rootDir, SYNC_STATE_PATH);
17225
17542
  mkdirSync5(dirname7(path), { recursive: true });
17226
17543
  writeFileSync5(path, `${JSON.stringify(state, null, 2)}
17227
17544
  `);
@@ -17235,7 +17552,7 @@ function selectedRuntimeAgentId(flags) {
17235
17552
  return;
17236
17553
  }
17237
17554
  function loadOrScanHarness(rootDir, tenant, context) {
17238
- const manifestPath = join9(rootDir, HARNESS_PATH);
17555
+ const manifestPath = join10(rootDir, HARNESS_PATH);
17239
17556
  if (existsSync8(manifestPath))
17240
17557
  return readHarnessGraph(manifestPath);
17241
17558
  if (context) {
@@ -17292,7 +17609,7 @@ var FRESHER_REPORT_MAX_DIRS = 4000;
17292
17609
  function findFresherHarnessReports(rootDir) {
17293
17610
  let rootMtimeMs = 0;
17294
17611
  try {
17295
- rootMtimeMs = lstatSync7(join9(rootDir, HARNESS_REPORT_PATH)).mtimeMs;
17612
+ rootMtimeMs = lstatSync8(join10(rootDir, HARNESS_REPORT_PATH)).mtimeMs;
17296
17613
  } catch {
17297
17614
  rootMtimeMs = 0;
17298
17615
  }
@@ -17304,19 +17621,19 @@ function findFresherHarnessReports(rootDir) {
17304
17621
  visited += 1;
17305
17622
  let entries;
17306
17623
  try {
17307
- entries = readdirSync4(dir, { withFileTypes: true });
17624
+ entries = readdirSync5(dir, { withFileTypes: true });
17308
17625
  } catch {
17309
17626
  return;
17310
17627
  }
17311
17628
  for (const entry of entries) {
17312
17629
  if (!entry.isDirectory() || entry.name.startsWith(".") || SKIPPED_DIRS.has(entry.name))
17313
17630
  continue;
17314
- const child = join9(dir, entry.name);
17631
+ const child = join10(dir, entry.name);
17315
17632
  try {
17316
- const candidate = lstatSync7(join9(child, HARNESS_REPORT_PATH));
17633
+ const candidate = lstatSync8(join10(child, HARNESS_REPORT_PATH));
17317
17634
  if (candidate.isFile() && candidate.mtimeMs > rootMtimeMs) {
17318
17635
  fresher.push({
17319
- path: normalizePath2(relative6(rootDir, join9(child, HARNESS_REPORT_PATH))),
17636
+ path: normalizePath2(relative7(rootDir, join10(child, HARNESS_REPORT_PATH))),
17320
17637
  mtimeMs: candidate.mtimeMs
17321
17638
  });
17322
17639
  }
@@ -17328,7 +17645,7 @@ function findFresherHarnessReports(rootDir) {
17328
17645
  return fresher.sort((a, b) => b.mtimeMs - a.mtimeMs);
17329
17646
  }
17330
17647
  function warnFresherSubdirHarnessReports(context, rootDir, explicitReport) {
17331
- const explicitReportPath = explicitReport && explicitReport !== "true" ? normalizePath2(relative6(rootDir, resolve10(rootDir, explicitReport))) : undefined;
17648
+ const explicitReportPath = explicitReport && explicitReport !== "true" ? normalizePath2(relative7(rootDir, resolve10(rootDir, explicitReport))) : undefined;
17332
17649
  if (explicitReportPath && explicitReportPath !== normalizePath2(HARNESS_REPORT_PATH))
17333
17650
  return;
17334
17651
  let fresher;
@@ -17341,16 +17658,16 @@ function warnFresherSubdirHarnessReports(context, rootDir, explicitReport) {
17341
17658
  return;
17342
17659
  const newest = fresher[0];
17343
17660
  const subdir = normalizePath2(dirname7(dirname7(newest.path)));
17344
- const rootState = existsSync8(join9(rootDir, HARNESS_REPORT_PATH)) ? `older ${HARNESS_REPORT_PATH}` : `no ${HARNESS_REPORT_PATH}`;
17661
+ const rootState = existsSync8(join10(rootDir, HARNESS_REPORT_PATH)) ? `older ${HARNESS_REPORT_PATH}` : `no ${HARNESS_REPORT_PATH}`;
17345
17662
  writeHarnessNotice(context, `A fresher harness report exists at ${newest.path} (this directory has ${rootState}). If you meant that report, re-run with --path=${subdir}.`);
17346
17663
  }
17347
17664
  function readHarnessGraph(manifestPath) {
17348
- return JSON.parse(readFileSync12(manifestPath, "utf8"));
17665
+ return JSON.parse(readFileSync13(manifestPath, "utf8"));
17349
17666
  }
17350
17667
  function writeHarnessArtifacts(graph, rootDir, options = {}) {
17351
- const modaDir = join9(rootDir, MODA_DIR);
17668
+ const modaDir = join10(rootDir, MODA_DIR);
17352
17669
  mkdirSync5(modaDir, { recursive: true });
17353
- const manifestPath = join9(rootDir, HARNESS_PATH);
17670
+ const manifestPath = join10(rootDir, HARNESS_PATH);
17354
17671
  writeFileSync5(manifestPath, `${JSON.stringify(graph, null, 2)}
17355
17672
  `);
17356
17673
  const written = [HARNESS_PATH];
@@ -17360,7 +17677,7 @@ function writeHarnessArtifacts(graph, rootDir, options = {}) {
17360
17677
  return written;
17361
17678
  }
17362
17679
  function writeHarnessSummary(graph, rootDir) {
17363
- const summaryPath = join9(rootDir, HARNESS_SUMMARY_PATH);
17680
+ const summaryPath = join10(rootDir, HARNESS_SUMMARY_PATH);
17364
17681
  mkdirSync5(dirname7(summaryPath), { recursive: true });
17365
17682
  writeFileSync5(summaryPath, renderHarnessMarkdown(graph));
17366
17683
  return HARNESS_SUMMARY_PATH;
@@ -17535,10 +17852,10 @@ function inventoryFiles(rootDir, skipped, options = {}) {
17535
17852
  const maxTextBytes = numericEnv("MODA_HARNESS_MAX_TEXT_BYTES", DEFAULT_MAX_INVENTORY_TEXT_BYTES);
17536
17853
  let textBytes = 0;
17537
17854
  function walk(current) {
17538
- const rel2 = normalizePath2(relative6(rootReal, current)) || ".";
17855
+ const rel2 = normalizePath2(relative7(rootReal, current)) || ".";
17539
17856
  let stat;
17540
17857
  try {
17541
- stat = lstatSync7(current);
17858
+ stat = lstatSync8(current);
17542
17859
  } catch {
17543
17860
  recordSkipped(skipped, { path: rel2, reason: "stat failed" });
17544
17861
  return;
@@ -17552,8 +17869,8 @@ function inventoryFiles(rootDir, skipped, options = {}) {
17552
17869
  recordSkipped(skipped, { path: rel2, reason: "ignored directory" });
17553
17870
  return;
17554
17871
  }
17555
- for (const entry of readdirSync4(current).sort()) {
17556
- walk(join9(current, entry));
17872
+ for (const entry of readdirSync5(current).sort()) {
17873
+ walk(join10(current, entry));
17557
17874
  }
17558
17875
  return;
17559
17876
  }
@@ -17584,7 +17901,7 @@ function inventoryFiles(rootDir, skipped, options = {}) {
17584
17901
  recordSkipped(skipped, { path: rel2, reason: "scan text budget exceeded" });
17585
17902
  } else {
17586
17903
  try {
17587
- item.text = readFileSync12(current, "utf8");
17904
+ item.text = readFileSync13(current, "utf8");
17588
17905
  textBytes += Buffer.byteLength(item.text, "utf8");
17589
17906
  } catch {
17590
17907
  recordSkipped(skipped, { path: rel2, reason: "text read failed" });
@@ -17891,7 +18208,7 @@ function maybeAddPromptArtifact(graph, file) {
17891
18208
  if (!isPrompt)
17892
18209
  return;
17893
18210
  const id = stableId("prompt", file.path);
17894
- const text = file.text ?? readFileSync12(file.absPath, "utf8");
18211
+ const text = file.text ?? readFileSync13(file.absPath, "utf8");
17895
18212
  upsertArtifact(graph, {
17896
18213
  id,
17897
18214
  type: "prompt",
@@ -18469,10 +18786,10 @@ function computeDeterministicFloor(rootDir) {
18469
18786
  }
18470
18787
  function detectProviderPackagesInManifests(rootDir) {
18471
18788
  const present = new Set;
18472
- const packageJsonPath = join9(rootDir, "package.json");
18789
+ const packageJsonPath = join10(rootDir, "package.json");
18473
18790
  if (existsSync8(packageJsonPath)) {
18474
18791
  try {
18475
- const deps = packageDependencyNames(readFileSync12(packageJsonPath, "utf8"));
18792
+ const deps = packageDependencyNames(readFileSync13(packageJsonPath, "utf8"));
18476
18793
  for (const provider of PROVIDER_CATALOG) {
18477
18794
  for (const name of provider.packageNames) {
18478
18795
  if (deps.has(name))
@@ -18481,10 +18798,10 @@ function detectProviderPackagesInManifests(rootDir) {
18481
18798
  }
18482
18799
  } catch {}
18483
18800
  }
18484
- const pyprojectPath = join9(rootDir, "pyproject.toml");
18801
+ const pyprojectPath = join10(rootDir, "pyproject.toml");
18485
18802
  if (existsSync8(pyprojectPath)) {
18486
18803
  try {
18487
- const deps = pyprojectDependencyNames(readFileSync12(pyprojectPath, "utf8"));
18804
+ const deps = pyprojectDependencyNames(readFileSync13(pyprojectPath, "utf8"));
18488
18805
  for (const provider of PROVIDER_CATALOG) {
18489
18806
  for (const name of provider.packageNames) {
18490
18807
  if (deps.has(name.toLowerCase()))
@@ -18886,12 +19203,12 @@ function contentHashForAnnotatedSource(sourcePath, annotation) {
18886
19203
  function readSmallTextFileForHash(absPath, rootDir) {
18887
19204
  if (!existsSync8(absPath))
18888
19205
  return;
18889
- const rel2 = normalizePath2(relative6(rootDir, absPath));
19206
+ const rel2 = normalizePath2(relative7(rootDir, absPath));
18890
19207
  if (isSecretishPath(rel2))
18891
19208
  return;
18892
19209
  let stat;
18893
19210
  try {
18894
- stat = lstatSync7(absPath);
19211
+ stat = lstatSync8(absPath);
18895
19212
  } catch {
18896
19213
  return;
18897
19214
  }
@@ -18901,7 +19218,7 @@ function readSmallTextFileForHash(absPath, rootDir) {
18901
19218
  if (!isTextFile(rel2))
18902
19219
  return;
18903
19220
  try {
18904
- return readFileSync12(absPath, "utf8");
19221
+ return readFileSync13(absPath, "utf8");
18905
19222
  } catch {
18906
19223
  return;
18907
19224
  }
@@ -18994,4 +19311,4 @@ function hashText(text) {
18994
19311
  return createHash5("sha256").update(text).digest("hex");
18995
19312
  }
18996
19313
 
18997
- export { startRemoteAnalyze, pollRemoteAnalyzeUntilDone, isRecoverableRemoteRun, checkPromptMapping, safePromptEvidencePath, discoverHarnessPromptSources, runHarnessCommand, writeHarnessAnalyzeResult, emitWrittenArtifacts, analyzeHarnessPrompts, repairExternalAnalystReport, deriveRelationshipsFromGraph, mergeDeterministicArtifacts, analystRefutations, describeCodingAgentEvent, analystEventProgress, isRetryableExternalAnalystFailure, sleep, summarizeInvalidAnalystReport, isDeterministicLocalAnalyst, resolveHarnessAnalyzeConcern, detectAvailableCodingAgents, codingAgentDisplayName, runCodingAgent, resolveAnalystModel, renderExternalHarnessAnalystPrompt, CONCERN_CANDIDATE_KINDS, SEED_CANDIDATE_KIND_LABELS, renderAnalystCandidateLines, renderAnalystSeedLines, truncateText, scanHarness, summarizeHarness, buildSourceSnapshot, writeHumanProgress, describeSyncIdentity, describeSyncTenantLabel, findFresherHarnessReports, writeHarnessArtifacts, assertHarnessGraphSyncQuality, graphForSync, inventoryFiles, numericEnv, numericEnvAllowZero, computeDeterministicFloor, stableId, titleFromId, promptNameFromPath };
19314
+ export { startRemoteAnalyze, pollRemoteAnalyzeUntilDone, isRecoverableRemoteRun, checkPromptMapping, safePromptEvidencePath, discoverHarnessPromptSources, runHarnessCommand, writeHarnessAnalyzeResult, emitWrittenArtifacts, analyzeHarnessPrompts, isToolGroupPlaceholder, repairExternalAnalystReport, deriveRelationshipsFromGraph, deterministicArtifacts, mergeDeterministicArtifacts, analystRefutations, describeCodingAgentEvent, analystEventProgress, isRetryableExternalAnalystFailure, sleep, summarizeInvalidAnalystReport, isDeterministicLocalAnalyst, resolveHarnessAnalyzeConcern, detectAvailableCodingAgents, codingAgentDisplayName, runCodingAgent, resolveAnalystModel, renderExternalHarnessAnalystPrompt, CONCERN_CANDIDATE_KINDS, SEED_CANDIDATE_KIND_LABELS, renderAnalystCandidateLines, renderAnalystSeedLines, truncateText, scanHarness, summarizeHarness, buildSourceSnapshot, writeHumanProgress, describeSyncIdentity, describeSyncTenantLabel, findFresherHarnessReports, writeHarnessArtifacts, assertHarnessGraphSyncQuality, graphForSync, inventoryFiles, numericEnv, numericEnvAllowZero, computeDeterministicFloor, stableId, titleFromId, promptNameFromPath };
@@ -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-0pzqswvr.js");
5771
+ const { analyzeHarnessPrompts } = await import("./harness-3bcakwrv.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-dfj7etks.js");
5799
+ const { checkPromptAttribution } = await import("./prompt-attribution-2687ns4k.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-0pzqswvr.js");
6105
+ const { analyzeHarnessPrompts } = await import("./harness-3bcakwrv.js");
6106
6106
  const result = await analyzeHarnessPrompts({
6107
6107
  rootDir: root,
6108
6108
  existing: manifest.sources,
@@ -6303,7 +6303,7 @@ async function readHarnessSources(reportPath) {
6303
6303
  if (!graph) {
6304
6304
  throw new CliInputError(`${selected} is not a harness report with a graph (schema: ${schemaLabel}). Regenerate it with \`${HARNESS_REANALYZE_COMMAND}\`.`);
6305
6305
  }
6306
- const { normalizeHarnessReport } = await import("./harness-report-d64517j4.js");
6306
+ const { normalizeHarnessReport } = await import("./harness-report-rjcjbh93.js");
6307
6307
  const { backfillPromptSource, resolvePromptSource } = await loadPromptSources();
6308
6308
  const report = normalizeHarnessReport(raw);
6309
6309
  const artifacts = (report.graph.artifacts ?? []).filter((artifact) => artifact.type === "prompt");
@@ -4,7 +4,7 @@ import {
4
4
  } from "./cli-rdh9jjr2.js";
5
5
  import {
6
6
  inspectPromptManifest
7
- } from "./cli-s3bcce69.js";
7
+ } from "./cli-r4k0yfkt.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-0pzqswvr.js");
398
+ const { scanHarness } = await import("./harness-3bcakwrv.js");
399
399
  const current = scanHarness({
400
400
  rootDir: cwd,
401
401
  scannerVersion: "doctor",
package/dist/cli.js CHANGED
@@ -2145,9 +2145,10 @@ var HARNESS_SUBCOMMAND_HELP = [
2145
2145
  {
2146
2146
  name: "candidates",
2147
2147
  description: "Static pre-pass listing likely agents, prompts, and tools (local; no LLM, no network)",
2148
- usage: "moda harness candidates [--path=<dir>] [--out=<file>] [--dry-run] [--yes]",
2148
+ usage: "moda harness candidates [--path=<dir>] [--out=<file>] [--promote=<concern|all>] [--dry-run] [--yes]",
2149
2149
  flags: [
2150
2150
  HARNESS_PATH_FLAG,
2151
+ { name: "--promote=<concern|all>", description: "Print the deterministic artifacts (tools, prompts, model configs) for one concern (topology, tools, prompts, evals) or all, with bodies, instead of the raw candidates." },
2151
2152
  { name: "--out=<file>", description: "Also write the candidates report to a file." },
2152
2153
  { name: "--dry-run", description: "Do not write --out." },
2153
2154
  { name: "--yes", description: "Approve a broad scan without the prompt." }
@@ -2967,25 +2968,25 @@ function leafManifestFields(leaf, commands) {
2967
2968
  import { fileURLToPath } from "url";
2968
2969
  import { realpathSync } from "fs";
2969
2970
  async function runPromptsCommand(...args) {
2970
- return (await import("./prompts-r7kzdnca.js")).runPromptsCommand(...args);
2971
+ return (await import("./prompts-887e9w1v.js")).runPromptsCommand(...args);
2971
2972
  }
2972
2973
  async function runSkillsCommand(...args) {
2973
2974
  return (await import("./skills-mwftqzyk.js")).runSkillsCommand(...args);
2974
2975
  }
2975
2976
  async function runHarnessCommand(...args) {
2976
- return (await import("./harness-0pzqswvr.js")).runHarnessCommand(...args);
2977
+ return (await import("./harness-3bcakwrv.js")).runHarnessCommand(...args);
2977
2978
  }
2978
2979
  async function runSyncCommand(...args) {
2979
- return (await import("./sync-xcjye7em.js")).runSyncCommand(...args);
2980
+ return (await import("./sync-dxnw1mwa.js")).runSyncCommand(...args);
2980
2981
  }
2981
2982
  async function runRegistryCommand(...args) {
2982
2983
  return (await import("./registry-tv8fktxc.js")).runRegistryCommand(...args);
2983
2984
  }
2984
2985
  async function runDoctorCommand(...args) {
2985
- return (await import("./doctor-0z5k6z9a.js")).runDoctorCommand(...args);
2986
+ return (await import("./doctor-wstqcfm4.js")).runDoctorCommand(...args);
2986
2987
  }
2987
2988
  async function runStatusCommand(...args) {
2988
- return (await import("./doctor-0z5k6z9a.js")).runStatusCommand(...args);
2989
+ return (await import("./doctor-wstqcfm4.js")).runStatusCommand(...args);
2989
2990
  }
2990
2991
  async function runAuthCommand(...args) {
2991
2992
  return (await import("./profile-commands-nbaec4y9.js")).runAuthCommand(...args);
@@ -2997,7 +2998,7 @@ async function runProfilesCommand(...args) {
2997
2998
  return (await import("./profile-commands-nbaec4y9.js")).runProfilesCommand(...args);
2998
2999
  }
2999
3000
  async function runAgentCommand(...args) {
3000
- return (await import("./agent-jyst7r0g.js")).runAgentCommand(...args);
3001
+ return (await import("./agent-0wpfk7ed.js")).runAgentCommand(...args);
3001
3002
  }
3002
3003
  async function runProductionCommand(...args) {
3003
3004
  return (await import("./production-intelligence-zek0rkzj.js")).runProductionCommand(...args);
@@ -6761,7 +6762,7 @@ var commandRegistry = createCommandRegistry([
6761
6762
  resetApiRequestCountBeforeRun: true,
6762
6763
  telemetry: "result-and-error",
6763
6764
  handler: async (context) => {
6764
- const { runInit } = await import("./index-2p6x0xg2.js");
6765
+ const { runInit } = await import("./index-msk4gfn5.js");
6765
6766
  if (context.outputMode === "agent-stream") {
6766
6767
  context.output.writeEvent({
6767
6768
  event: "started",
@@ -3,9 +3,9 @@ import {
3
3
  promptsDiscoveredCheck,
4
4
  runDoctorCommand,
5
5
  runStatusCommand
6
- } from "./cli-3pn6w6m3.js";
6
+ } from "./cli-thhggczw.js";
7
7
  import"./cli-rdh9jjr2.js";
8
- import"./cli-s3bcce69.js";
8
+ import"./cli-r4k0yfkt.js";
9
9
  import"./cli-mm48br00.js";
10
10
  import"./cli-xq45etg1.js";
11
11
  import"./cli-gtke9wrw.js";
@@ -13,12 +13,14 @@ import {
13
13
  describeSyncIdentity,
14
14
  describeSyncTenantLabel,
15
15
  detectAvailableCodingAgents,
16
+ deterministicArtifacts,
16
17
  emitWrittenArtifacts,
17
18
  findFresherHarnessReports,
18
19
  graphForSync,
19
20
  inventoryFiles,
20
21
  isDeterministicLocalAnalyst,
21
22
  isRetryableExternalAnalystFailure,
23
+ isToolGroupPlaceholder,
22
24
  mergeDeterministicArtifacts,
23
25
  numericEnv,
24
26
  numericEnvAllowZero,
@@ -41,7 +43,7 @@ import {
41
43
  writeHarnessAnalyzeResult,
42
44
  writeHarnessArtifacts,
43
45
  writeHumanProgress
44
- } from "./cli-k6kydtkv.js";
46
+ } from "./cli-7nghchj8.js";
45
47
  import"./cli-97fnztpy.js";
46
48
  import"./cli-xq45etg1.js";
47
49
  import"./cli-gtke9wrw.js";
@@ -54,7 +56,7 @@ import"./cli-9kfxkxmk.js";
54
56
  import"./cli-c1k20j6e.js";
55
57
  import {
56
58
  HARNESS_ANALYZE_CONCERNS
57
- } from "./cli-wqyrcnm1.js";
59
+ } from "./cli-6hdqp65a.js";
58
60
  import"./cli-k4tqwah4.js";
59
61
  import"./cli-0v6na3yp.js";
60
62
  export {
@@ -80,12 +82,14 @@ export {
80
82
  numericEnvAllowZero,
81
83
  numericEnv,
82
84
  mergeDeterministicArtifacts,
85
+ isToolGroupPlaceholder,
83
86
  isRetryableExternalAnalystFailure,
84
87
  isDeterministicLocalAnalyst,
85
88
  inventoryFiles,
86
89
  graphForSync,
87
90
  findFresherHarnessReports,
88
91
  emitWrittenArtifacts,
92
+ deterministicArtifacts,
89
93
  detectAvailableCodingAgents,
90
94
  describeSyncTenantLabel,
91
95
  describeSyncIdentity,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  buildSourceSnapshot
3
- } from "./cli-k6kydtkv.js";
3
+ } from "./cli-7nghchj8.js";
4
4
  import"./cli-97fnztpy.js";
5
5
  import"./cli-xq45etg1.js";
6
6
  import"./cli-gtke9wrw.js";
@@ -13,7 +13,7 @@ import {
13
13
  import"./cli-vswckv9g.js";
14
14
  import"./cli-9kfxkxmk.js";
15
15
  import"./cli-c1k20j6e.js";
16
- import"./cli-wqyrcnm1.js";
16
+ import"./cli-6hdqp65a.js";
17
17
  import"./cli-k4tqwah4.js";
18
18
  import"./cli-0v6na3yp.js";
19
19
 
@@ -24,7 +24,7 @@ import {
24
24
  stampRemoteSnapshotTruncation,
25
25
  validateHarnessReport,
26
26
  writeHarnessReportArtifacts
27
- } from "./cli-wqyrcnm1.js";
27
+ } from "./cli-6hdqp65a.js";
28
28
  import"./cli-k4tqwah4.js";
29
29
  import"./cli-0v6na3yp.js";
30
30
  export {
@@ -21,7 +21,7 @@ import {
21
21
  } from "./cli-hcwdz9sd.js";
22
22
  import {
23
23
  buildDoctorReport
24
- } from "./cli-3pn6w6m3.js";
24
+ } from "./cli-thhggczw.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-s3bcce69.js";
35
+ } from "./cli-r4k0yfkt.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-k6kydtkv.js";
49
+ } from "./cli-7nghchj8.js";
50
50
  import {
51
51
  stripAnsi
52
52
  } from "./cli-97fnztpy.js";
@@ -74,7 +74,7 @@ import {
74
74
  import"./cli-vswckv9g.js";
75
75
  import"./cli-9kfxkxmk.js";
76
76
  import"./cli-c1k20j6e.js";
77
- import"./cli-wqyrcnm1.js";
77
+ import"./cli-6hdqp65a.js";
78
78
  import {
79
79
  CliAuthError,
80
80
  CliInputError
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  inventoryFiles,
3
3
  safePromptEvidencePath
4
- } from "./cli-k6kydtkv.js";
4
+ } from "./cli-7nghchj8.js";
5
5
  import"./cli-97fnztpy.js";
6
6
  import"./cli-xq45etg1.js";
7
7
  import"./cli-gtke9wrw.js";
@@ -14,7 +14,7 @@ import {
14
14
  } from "./cli-vswckv9g.js";
15
15
  import"./cli-9kfxkxmk.js";
16
16
  import"./cli-c1k20j6e.js";
17
- import"./cli-wqyrcnm1.js";
17
+ import"./cli-6hdqp65a.js";
18
18
  import"./cli-k4tqwah4.js";
19
19
  import {
20
20
  __toESM
@@ -3,7 +3,7 @@ import {
3
3
  checkPromptMapping,
4
4
  discoverHarnessPromptSources,
5
5
  safePromptEvidencePath
6
- } from "./cli-k6kydtkv.js";
6
+ } from "./cli-7nghchj8.js";
7
7
  import"./cli-97fnztpy.js";
8
8
  import"./cli-xq45etg1.js";
9
9
  import"./cli-gtke9wrw.js";
@@ -17,7 +17,7 @@ import {
17
17
  } from "./cli-vswckv9g.js";
18
18
  import"./cli-9kfxkxmk.js";
19
19
  import"./cli-c1k20j6e.js";
20
- import"./cli-wqyrcnm1.js";
20
+ import"./cli-6hdqp65a.js";
21
21
  import"./cli-k4tqwah4.js";
22
22
  import {
23
23
  __commonJS,
@@ -9,7 +9,7 @@ import {
9
9
  runPromptSync,
10
10
  runPromptsCommand,
11
11
  writePromptSyncProgress
12
- } from "./cli-s3bcce69.js";
12
+ } from "./cli-r4k0yfkt.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-s3bcce69.js";
9
+ } from "./cli-r4k0yfkt.js";
10
10
  import"./cli-mm48br00.js";
11
11
  import {
12
12
  runHarnessCommand
13
- } from "./cli-k6kydtkv.js";
13
+ } from "./cli-7nghchj8.js";
14
14
  import"./cli-97fnztpy.js";
15
15
  import"./cli-xq45etg1.js";
16
16
  import"./cli-gtke9wrw.js";
@@ -21,7 +21,7 @@ import"./cli-40fqk078.js";
21
21
  import"./cli-vswckv9g.js";
22
22
  import"./cli-9kfxkxmk.js";
23
23
  import"./cli-c1k20j6e.js";
24
- import"./cli-wqyrcnm1.js";
24
+ import"./cli-6hdqp65a.js";
25
25
  import {
26
26
  CliInputError
27
27
  } from "./cli-k4tqwah4.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moda-ai/cli",
3
- "version": "1.55.51",
3
+ "version": "1.55.53",
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-20T22:22:44.875Z",
4
- "cli_version": "1.55.51",
3
+ "bundled_at": "2026-10-21T00:50:29.487Z",
4
+ "cli_version": "1.55.53",
5
5
  "skills": [
6
6
  {
7
7
  "id": "integration-cloudflare-think",