@event4u/agent-config 14.19.0 → 14.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. package/.augment-plugin/marketplace.json +3 -3
  2. package/.augment-plugin/plugin.json +1 -1
  3. package/.claude-plugin/marketplace.json +1 -1
  4. package/CHANGELOG.md +108 -156
  5. package/dist/agent-src/commands/agent-handoff.md +42 -41
  6. package/dist/agent-src/contexts/execution/host-capability-manifest.md +7 -1
  7. package/dist/agent-src/rules/untrusted-input-defense.md +0 -2
  8. package/dist/agent-src/skills/evaluate-llm-feature/SKILL.md +1 -1
  9. package/dist/agent-src/skills/markitdown/SKILL.md +1 -1
  10. package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +28 -6
  11. package/dist/agent-src/skills/test-driven-development/SKILL.md +1 -3
  12. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  13. package/dist/agent-src/templates/roadmaps.md +14 -1
  14. package/dist/agent-src/templates/scripts/telemetry/mcp_lite.ts +213 -0
  15. package/dist/agent-src/templates/scripts/telemetry/report_renderer.ts +16 -0
  16. package/dist/agent-src/templates/scripts/telemetry_report.ts +22 -2
  17. package/dist/cli/mcp/dispatch.js +10 -0
  18. package/dist/cli/mcp/stdio.js +33 -2
  19. package/dist/cli/mcp/telemetry.js +227 -0
  20. package/dist/cli-delegate/{chunk-GZTMRYCN.js → chunk-C6IPZRDA.js} +79 -12
  21. package/dist/cli-delegate/{chunk-CYH5SP6M.js → chunk-I6RHFQEG.js} +151 -16
  22. package/dist/cli-delegate/{chunk-IDHUQIXP.js → chunk-NUMQHLS5.js} +21 -4
  23. package/dist/cli-delegate/{chunk-PMEKGDED.js → chunk-PI2GU3DP.js} +163 -1
  24. package/dist/cli-delegate/{chunk-7PRE6ZV2.js → chunk-YS6XTLEK.js} +199 -4
  25. package/dist/cli-delegate/chunk-ZVBOHSVF.js +1109 -0
  26. package/dist/cli-delegate/cmd_conformance.js +73 -109
  27. package/dist/cli-delegate/cmd_doctor.js +2 -2
  28. package/dist/cli-delegate/cmd_export.js +2 -2
  29. package/dist/cli-delegate/cmd_handoff.js +41 -11
  30. package/dist/cli-delegate/cmd_memory_get.js +1 -1
  31. package/dist/cli-delegate/cmd_prune.js +2 -2
  32. package/dist/cli-delegate/cmd_route_audit.js +1 -1
  33. package/dist/cli-delegate/cmd_session_recycle.js +59 -902
  34. package/dist/cli-delegate/cmd_settings_migrate.js +2 -2
  35. package/dist/cli-delegate/cmd_sync.js +2 -2
  36. package/dist/cli-delegate/cmd_uninstall.js +2 -2
  37. package/dist/cli-delegate/cmd_validate.js +2 -2
  38. package/dist/discovery/deprecation-report.md +1 -1
  39. package/dist/discovery/discovery-manifest.json +9 -9
  40. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  41. package/dist/discovery/discovery-manifest.summary.md +1 -1
  42. package/dist/discovery/dormancy-report.md +1 -1
  43. package/dist/discovery/orphan-report.md +1 -1
  44. package/dist/discovery/packs.json +2 -2
  45. package/dist/discovery/trust-report.md +1 -1
  46. package/dist/discovery/workspaces.json +2 -2
  47. package/dist/hooks/dispatch.js +7257 -6497
  48. package/dist/install/install.mjs +393 -168
  49. package/dist/mcp/registry-manifest.json +2 -2
  50. package/dist/mcp/server.json +2 -2
  51. package/dist/mcp/server.mjs +497 -118
  52. package/dist/scripts/mcp_server/telemetry.js +148 -0
  53. package/docs/guidelines/agent-infra/naming.md +1 -1
  54. package/docs/guidelines/agent-infra/security-lint-containment.md +46 -6
  55. package/docs/guidelines/agent-infra/self-improvement-pipeline.md +4 -4
  56. package/docs/guidelines/agent-infra/untrusted-input-spotlighting.md +1 -1
  57. package/docs/guidelines/redundancy-taxonomy.md +28 -0
  58. package/package.json +1 -1
  59. package/src/agent-src/templates/scripts/telemetry/mcp_lite.ts +213 -0
  60. package/src/agent-src/templates/scripts/telemetry/report_renderer.ts +16 -0
  61. package/src/agent-src/templates/scripts/telemetry_report.ts +22 -2
  62. package/src/config/assurance-capability-registry.json +9 -0
  63. package/src/config/gate-coverage.yml +55 -0
  64. package/src/config/gate-violation-baselines.json +15 -3
  65. package/src/scripts/_cli/cmd_session_recycle.ts +51 -3
  66. package/src/scripts/_lib/audit_field_provenance.ts +44 -3
  67. package/src/scripts/_lib/host_capability.ts +38 -0
  68. package/src/scripts/_lib/install_reach_checks.ts +33 -1
  69. package/src/scripts/_lib/mcp_bridge.ts +222 -10
  70. package/src/scripts/_lib/mcp_consent_residual.ts +173 -0
  71. package/src/scripts/_lib/orchestration_record.ts +23 -1
  72. package/src/scripts/_lib/recycle_envelope_paths.ts +190 -0
  73. package/src/scripts/_lib/release_position.ts +96 -0
  74. package/src/scripts/_lib/review_skipped_record.ts +17 -1
  75. package/src/scripts/_lib/security_lint.ts +179 -7
  76. package/src/scripts/_lib/self_repair.ts +141 -6
  77. package/src/scripts/_lib/self_repair_store.ts +273 -7
  78. package/src/scripts/_lib/subagent_capsule.ts +155 -3
  79. package/src/scripts/build_rule_trigger_matrix.ts +5 -0
  80. package/src/scripts/check_mcp_doc_drift.ts +217 -0
  81. package/src/scripts/check_pack_size.ts +321 -3
  82. package/src/scripts/handoff_context_hook.ts +54 -7
  83. package/src/scripts/hooks/session_eol_hook.ts +18 -7
  84. package/src/scripts/install.ts +4 -4
  85. package/src/scripts/lint_agent_security.ts +316 -25
  86. package/src/scripts/lint_confusables.ts +42 -6
  87. package/src/scripts/lint_handoffs.ts +0 -132
  88. package/src/scripts/lint_hidden_unicode.ts +49 -7
  89. package/src/scripts/lint_instruction_smuggling.ts +42 -6
  90. package/src/scripts/lint_mcp_config_security.ts +42 -6
  91. package/src/scripts/lint_roadmap_later_disposition.ts +217 -27
  92. package/src/scripts/lint_skill_frontmatter_safety.ts +43 -7
  93. package/src/scripts/mcp_server/resources.ts +41 -0
  94. package/src/scripts/mcp_server/telemetry.ts +19 -4
  95. package/src/scripts/orchestration_record.ts +12 -1
  96. package/src/scripts/release.ts +24 -24
  97. package/src/scripts/release_publication.ts +6 -2
  98. package/src/scripts/self_repair_cli.ts +31 -1
  99. package/src/scripts/skill_scout.ts +69 -0
  100. package/dist/cli-delegate/chunk-2GNWGMAL.js +0 -172
  101. package/dist/cli-delegate/chunk-LPPWO5CE.js +0 -161
@@ -1502,6 +1502,7 @@ __export(resources_exports, {
1502
1502
  MIME_MARKDOWN: () => MIME_MARKDOWN,
1503
1503
  ResourceCache: () => ResourceCache,
1504
1504
  load_all_resources: () => load_all_resources,
1505
+ resourcePriority: () => resourcePriority,
1505
1506
  scan_contexts: () => scan_contexts,
1506
1507
  scan_guidelines: () => scan_guidelines,
1507
1508
  scan_rules: () => scan_rules,
@@ -1600,9 +1601,18 @@ function _load(p, options) {
1600
1601
  body: _rstrip2(text) + "\n",
1601
1602
  source: meta.source ?? "package",
1602
1603
  mime_type: MIME_MARKDOWN,
1603
- kind
1604
+ kind,
1605
+ ...meta.type === void 0 ? {} : { rule_type: meta.type.trim() },
1606
+ ..._mtimeIso(p) === null ? {} : { last_modified: _mtimeIso(p) }
1604
1607
  };
1605
1608
  }
1609
+ function _mtimeIso(p) {
1610
+ try {
1611
+ return fs5.statSync(p).mtime.toISOString();
1612
+ } catch {
1613
+ return null;
1614
+ }
1615
+ }
1606
1616
  function scan_rules(root) {
1607
1617
  const base = root ?? _project_root();
1608
1618
  const rules_root = path5.join(base, "dist/agent-src", "rules");
@@ -1684,12 +1694,23 @@ function _strCmp2(a, b) {
1684
1694
  }
1685
1695
  return 0;
1686
1696
  }
1697
+ function resourcePriority(resource) {
1698
+ if (resource.rule_type === "always") return 1;
1699
+ if (resource.rule_type === "auto") return 0.7;
1700
+ if (resource.rule_type === "manual") return 0.3;
1701
+ return resource.kind === "rule" ? 0.7 : resource.kind === "context" ? 0.5 : 0.3;
1702
+ }
1687
1703
  function to_mcp_resource_meta(resource) {
1688
1704
  return {
1689
1705
  uri: resource.uri,
1690
1706
  name: resource.name,
1691
1707
  description: resource.description,
1692
1708
  mimeType: resource.mime_type,
1709
+ // `audience` is the model, not the end user: these are governance
1710
+ // assets a host injects, never something a person reads in a client.
1711
+ audience: ["assistant"],
1712
+ priority: resourcePriority(resource),
1713
+ ...resource.last_modified === void 0 ? {} : { lastModified: resource.last_modified },
1693
1714
  _meta: { source: resource.source, kind: resource.kind }
1694
1715
  };
1695
1716
  }
@@ -9092,6 +9113,7 @@ var require_dist = __commonJS({
9092
9113
  });
9093
9114
 
9094
9115
  // src/scripts/_lib/security_lint.ts
9116
+ import { createHash as createHash2 } from "node:crypto";
9095
9117
  import * as fs6 from "node:fs";
9096
9118
  import * as path6 from "node:path";
9097
9119
  import { fileURLToPath as fileURLToPath3 } from "node:url";
@@ -9101,6 +9123,9 @@ function is_example_path(rel_path) {
9101
9123
  function path_weight(rel_path) {
9102
9124
  return is_example_path(rel_path) ? 0.25 : 1;
9103
9125
  }
9126
+ function source_identity(rel) {
9127
+ return rel.startsWith(PROJECTION_PREFIX) ? `src/${rel.slice(PROJECTION_PREFIX.length)}` : rel;
9128
+ }
9104
9129
  function _splitlines(text) {
9105
9130
  const out = [];
9106
9131
  let buf = "";
@@ -9176,11 +9201,18 @@ function scan_file(filePath) {
9176
9201
  }
9177
9202
  }
9178
9203
  const pragmas = {};
9204
+ const pragmaHashes = {};
9179
9205
  for (const text of lines) {
9180
9206
  _PRAGMA.lastIndex = 0;
9181
9207
  let m;
9182
9208
  while ((m = _PRAGMA.exec(text)) !== null) {
9183
- pragmas[m[1]] = m[2];
9209
+ const check = m[1];
9210
+ pragmas[check] = m[2];
9211
+ const hashes = (m[3] ?? "").match(/sha256:([0-9a-f]{64})/g) ?? [];
9212
+ pragmaHashes[check] = [
9213
+ ...pragmaHashes[check] ?? [],
9214
+ ...hashes.map((h) => h.slice("sha256:".length))
9215
+ ];
9184
9216
  if (m.index === _PRAGMA.lastIndex) {
9185
9217
  _PRAGMA.lastIndex += 1;
9186
9218
  }
@@ -9193,7 +9225,29 @@ function scan_file(filePath) {
9193
9225
  in_example,
9194
9226
  in_any,
9195
9227
  pragmas,
9196
- path_weight(rel)
9228
+ path_weight(rel),
9229
+ pragmaHashes
9230
+ );
9231
+ }
9232
+ function scan_path(filePath, base) {
9233
+ const sf = scan_file(filePath);
9234
+ let rel;
9235
+ const baseResolved = path6.resolve(base);
9236
+ const fileResolved = path6.resolve(filePath);
9237
+ if (fileResolved === baseResolved || fileResolved.startsWith(baseResolved + path6.sep)) {
9238
+ rel = path6.relative(baseResolved, fileResolved).split(path6.sep).join("/");
9239
+ } else {
9240
+ rel = path6.basename(filePath);
9241
+ }
9242
+ return new ScannedFile(
9243
+ sf.path,
9244
+ rel,
9245
+ sf.lines,
9246
+ sf.in_example_fence,
9247
+ sf.in_any_fence,
9248
+ sf.pragmas,
9249
+ path_weight(rel),
9250
+ sf.pragma_hashes
9197
9251
  );
9198
9252
  }
9199
9253
  function _rglobSorted(base) {
@@ -9229,9 +9283,9 @@ function _pathCmp(a, b) {
9229
9283
  if (pa.length > pb.length) return 1;
9230
9284
  return 0;
9231
9285
  }
9232
- function* iter_corpus(roots = DEFAULT_SCAN_ROOTS, exts = [".md"]) {
9286
+ function* iter_corpus(roots = DEFAULT_SCAN_ROOTS, exts = [".md"], scanBase = ROOT) {
9233
9287
  for (const root of roots) {
9234
- const base = path6.join(ROOT, root);
9288
+ const base = path6.join(scanBase, root);
9235
9289
  if (!fs6.existsSync(base)) {
9236
9290
  continue;
9237
9291
  }
@@ -9243,11 +9297,25 @@ function* iter_corpus(roots = DEFAULT_SCAN_ROOTS, exts = [".md"]) {
9243
9297
  continue;
9244
9298
  }
9245
9299
  if (st.isFile() && exts.includes(path6.extname(p))) {
9246
- yield scan_file(p);
9300
+ yield scan_path(p, scanBase);
9247
9301
  }
9248
9302
  }
9249
9303
  }
9250
9304
  }
9305
+ function legacy_pragma_finding(sf, check) {
9306
+ return new Finding(
9307
+ sf.rel,
9308
+ 0,
9309
+ LEGACY_PRAGMA_CHECK,
9310
+ "LOW",
9311
+ `unbound \`security-lint: allow ${check}\` pragma suppresses this whole file \u2014 it accepts whatever the matched text is later changed to say. Bind it with \`sha256:<hex>\` per accepted match.`,
9312
+ sf.weight
9313
+ );
9314
+ }
9315
+ function report_child_scanned(count) {
9316
+ process.stderr.write(`${CHILD_SCANNED_PREFIX}${String(count)}
9317
+ `);
9318
+ }
9251
9319
  function report(findings, opts) {
9252
9320
  const check_label = opts.check_label;
9253
9321
  if (findings.length === 0) {
@@ -9431,7 +9499,7 @@ function _pyJsonScalarAscii(value) {
9431
9499
  if (typeof value === "string") return _pyJsonStrAscii(value);
9432
9500
  return _pyJsonScalar(value);
9433
9501
  }
9434
- var _HERE, ROOT, EXAMPLE_FENCE_LANG, GUIDELINE, GUIDELINE_EPILOG, DEFAULT_SCAN_ROOTS, _EXAMPLE_PATH, _PRAGMA, _FENCE, SEVERITY_RANK, Finding, ScannedFile, PyFloat;
9502
+ var _HERE, ROOT, EXAMPLE_FENCE_LANG, GUIDELINE, GUIDELINE_EPILOG, DEFAULT_SCAN_ROOTS, _EXAMPLE_PATH, _PRAGMA, _FENCE, SEVERITY_RANK, Finding, PROJECTION_PREFIX, ScannedFile, LEGACY_PRAGMA_CHECK, CHILD_SCANNED_PREFIX, PyFloat;
9435
9503
  var init_security_lint = __esm({
9436
9504
  "src/scripts/_lib/security_lint.ts"() {
9437
9505
  "use strict";
@@ -9448,7 +9516,7 @@ var init_security_lint = __esm({
9448
9516
  "dist/agent-src"
9449
9517
  ];
9450
9518
  _EXAMPLE_PATH = /(^|\/)(docs|evals|tests?|fixtures?)(\/|$)|example|template|sample|\/_template/i;
9451
- _PRAGMA = /<!--\s*security-lint:\s*allow\s+([A-Za-z0-9_-]+)\s+"([^"]+)"\s*-->/g;
9519
+ _PRAGMA = /<!--\s*security-lint:\s*allow\s+([A-Za-z0-9_-]+)\s+"([^"]+)"((?:\s+sha256:[0-9a-f]{64})*)\s*-->/g;
9452
9520
  _FENCE = /^(\s*)(`{3,}|~{3,})\s*([A-Za-z0-9_-]*)\s*$/;
9453
9521
  SEVERITY_RANK = { LOW: 1, MED: 2, HIGH: 3 };
9454
9522
  Finding = class {
@@ -9488,6 +9556,7 @@ var init_security_lint = __esm({
9488
9556
  };
9489
9557
  }
9490
9558
  };
9559
+ PROJECTION_PREFIX = "dist/agent-src/";
9491
9560
  ScannedFile = class {
9492
9561
  path;
9493
9562
  // absolute or as-given path
@@ -9498,8 +9567,10 @@ var init_security_lint = __esm({
9498
9567
  in_any_fence;
9499
9568
  pragmas;
9500
9569
  // check id → reason
9570
+ /** check id → the sha256 fingerprints that pragma accepts. Empty = unbound. */
9571
+ pragma_hashes;
9501
9572
  weight;
9502
- constructor(pathArg, rel, lines, in_example_fence, in_any_fence, pragmas, weight) {
9573
+ constructor(pathArg, rel, lines, in_example_fence, in_any_fence, pragmas, weight, pragma_hashes = {}) {
9503
9574
  this.path = pathArg;
9504
9575
  this.rel = rel;
9505
9576
  this.lines = lines;
@@ -9507,10 +9578,74 @@ var init_security_lint = __esm({
9507
9578
  this.in_any_fence = in_any_fence;
9508
9579
  this.pragmas = pragmas;
9509
9580
  this.weight = weight;
9581
+ this.pragma_hashes = pragma_hashes;
9510
9582
  }
9511
9583
  pragma_allows(check) {
9512
9584
  return Object.prototype.hasOwnProperty.call(this.pragmas, check);
9513
9585
  }
9586
+ /**
9587
+ * Which form of pragma this file carries for `check`.
9588
+ *
9589
+ * `absent` — no pragma; scan normally.
9590
+ * `legacy` — a pragma with no fingerprint. Suppresses the whole file, as it
9591
+ * always did, and says so: a key lookup accepts whatever the
9592
+ * line is later changed to say, which is the defect being paid
9593
+ * down, not a mode anybody should choose.
9594
+ * `bound` — a pragma listing fingerprints. Suppresses exactly the matches
9595
+ * whose evidence hashes to one of them; anything else survives.
9596
+ */
9597
+ pragma_form(check) {
9598
+ if (!this.pragma_allows(check)) return "absent";
9599
+ return (this.pragma_hashes[check] ?? []).length > 0 ? "bound" : "legacy";
9600
+ }
9601
+ /**
9602
+ * The fingerprint one finding's evidence hashes to.
9603
+ *
9604
+ * WHAT IS HASHED, and each part earns its place:
9605
+ * check id — the same line may legitimately be accepted for one check
9606
+ * and not another.
9607
+ * rel path — the location IDENTITY. Not the line NUMBER: an unrelated
9608
+ * insert above would otherwise break every pragma in the
9609
+ * file, and a suppression that breaks on unrelated edits
9610
+ * gets deleted rather than re-derived. A `dist/agent-src/`
9611
+ * path folds to its `src/` original first, because the
9612
+ * projection is byte-exact by contract (ADR-201) and
9613
+ * carries the pragma verbatim — without the fold, every
9614
+ * migrated pragma would suppress the source and leave its
9615
+ * own copy flagged, which is a gate that reds on a file
9616
+ * nobody may edit.
9617
+ * matched line, — the evidence. ASCII whitespace runs collapse so a reflow
9618
+ * normalized does not invalidate the binding, `sha256:<hex>` tokens are
9619
+ * removed, and NOTHING else is stripped: the zero-width
9620
+ * characters this suite hunts are exactly what a wider
9621
+ * normalizer would erase.
9622
+ *
9623
+ * WHY THE HASH TOKENS COME OUT. A pragma's own reason string can be the
9624
+ * matched evidence — two in this tree are, because they quote the very
9625
+ * phrases their check detects in order to explain themselves. Without this
9626
+ * the fingerprint would have to be computed over a line that already
9627
+ * contains it, which has no fixed point: writing the hash changes the line,
9628
+ * which changes the hash. Stripping the tokens makes the fingerprint stable
9629
+ * under the act of recording it, and costs nothing elsewhere — a `sha256:`
9630
+ * token in ordinary prose is not evidence of anything a linter here checks.
9631
+ *
9632
+ * Deliberately NOT the whole file: incidental content elsewhere would make
9633
+ * every unrelated edit re-fire the pragma, which is the noise that produces
9634
+ * blanket suppressions.
9635
+ */
9636
+ evidence_fingerprint(finding) {
9637
+ const text = finding.line > 0 ? this.lines[finding.line - 1] ?? "" : "";
9638
+ const normalized = text.replace(/\s*sha256:[0-9a-f]{64}/g, "").replace(/[ \t]+/g, " ").trim();
9639
+ return createHash2("sha256").update(`${finding.check}
9640
+ ${source_identity(this.rel)}
9641
+ ${normalized}`, "utf-8").digest("hex");
9642
+ }
9643
+ /** Drop the findings this file's BOUND pragma for `check` accepts. */
9644
+ filter_bound_pragma(check, findings) {
9645
+ const accepted = new Set(this.pragma_hashes[check] ?? []);
9646
+ if (accepted.size === 0) return [...findings];
9647
+ return findings.filter((f) => !accepted.has(this.evidence_fingerprint(f)));
9648
+ }
9514
9649
  /** Yield [lineno, text] honouring the fence masks (mirrors iter_lines). */
9515
9650
  *iter_lines(opts = {}) {
9516
9651
  const skip_example_fence = opts.skip_example_fence ?? true;
@@ -9526,6 +9661,8 @@ var init_security_lint = __esm({
9526
9661
  }
9527
9662
  }
9528
9663
  };
9664
+ LEGACY_PRAGMA_CHECK = "legacy-pragma";
9665
+ CHILD_SCANNED_PREFIX = "scanned: ";
9529
9666
  PyFloat = class {
9530
9667
  constructor(value) {
9531
9668
  this.value = value;
@@ -9604,9 +9741,11 @@ function _cpName(cp) {
9604
9741
  return n !== void 0 ? n : "<unnamed>";
9605
9742
  }
9606
9743
  function _scan(sf) {
9607
- if (sf.pragma_allows(CHECK)) {
9608
- return [];
9744
+ const pragmaForm = sf.pragma_form(CHECK);
9745
+ if (pragmaForm === "legacy") {
9746
+ return [legacy_pragma_finding(sf, CHECK)];
9609
9747
  }
9748
+ const finish = (hits) => pragmaForm === "bound" ? sf.filter_bound_pragma(CHECK, hits) : hits;
9610
9749
  const out = [];
9611
9750
  for (const [lineno, text] of sf.iter_lines({ skip_example_fence: true })) {
9612
9751
  let vs_run = 0;
@@ -9644,7 +9783,7 @@ function _scan(sf) {
9644
9783
  );
9645
9784
  }
9646
9785
  }
9647
- return out;
9786
+ return finish(out);
9648
9787
  }
9649
9788
  function _isGenerated(rel) {
9650
9789
  return _GENERATED_PREFIXES.some((p) => rel.startsWith(p));
@@ -9728,7 +9867,7 @@ function _sanitize(filePath) {
9728
9867
  return out;
9729
9868
  }
9730
9869
  function _argError(msg) {
9731
- process.stderr.write("usage: lint_hidden_unicode [-h] [--json] [--fix]\n");
9870
+ process.stderr.write("usage: lint_hidden_unicode [-h] [--json] [--fix] [--root DIR]\n");
9732
9871
  process.stderr.write(`lint_hidden_unicode: error: ${msg}
9733
9872
  `);
9734
9873
  process.exit(2);
@@ -9736,14 +9875,27 @@ function _argError(msg) {
9736
9875
  function parse_args(argv) {
9737
9876
  const out = { json: false, fix: false };
9738
9877
  const extra = [];
9878
+ let rootPending = false;
9739
9879
  for (const a of argv) {
9880
+ if (rootPending) {
9881
+ out.root = a;
9882
+ rootPending = false;
9883
+ continue;
9884
+ }
9740
9885
  if (a === "-h" || a === "--help") {
9741
- process.stdout.write("usage: lint_hidden_unicode [-h] [--json] [--fix]\n");
9886
+ process.stdout.write("usage: lint_hidden_unicode [-h] [--json] [--fix] [--root DIR]\n");
9742
9887
  process.exit(0);
9743
9888
  } else if (a === "--json") {
9744
9889
  out.json = true;
9745
9890
  } else if (a === "--fix") {
9746
9891
  out.fix = true;
9892
+ } else if (a === "--root" || a.startsWith("--root=")) {
9893
+ const eq = a.indexOf("=");
9894
+ if (eq !== -1) {
9895
+ out.root = a.slice(eq + 1);
9896
+ } else {
9897
+ rootPending = true;
9898
+ }
9747
9899
  } else {
9748
9900
  extra.push(a);
9749
9901
  }
@@ -9755,10 +9907,11 @@ function parse_args(argv) {
9755
9907
  }
9756
9908
  function main(argv = null) {
9757
9909
  const args = parse_args(argv ?? process.argv.slice(2));
9910
+ const scanBase = args.root === void 0 ? ROOT : path7.resolve(args.root);
9758
9911
  const findings = [];
9759
9912
  const flagged = /* @__PURE__ */ new Set();
9760
9913
  let corpusFiles = 0;
9761
- for (const sf of iter_corpus()) {
9914
+ for (const sf of iter_corpus(DEFAULT_SCAN_ROOTS, [".md"], scanBase)) {
9762
9915
  corpusFiles += 1;
9763
9916
  const hits = _scan(sf);
9764
9917
  for (const h of hits) {
@@ -9783,7 +9936,7 @@ function main(argv = null) {
9783
9936
  }
9784
9937
  throw exc;
9785
9938
  }
9786
- const sourceFiles = _eligibleSourceFiles();
9939
+ const sourceFiles = args.root === void 0 ? _eligibleSourceFiles() : [];
9787
9940
  for (const h of _scanSourceControlBytes(sourceFiles)) {
9788
9941
  findings.push(h);
9789
9942
  }
@@ -9802,6 +9955,9 @@ function main(argv = null) {
9802
9955
  `);
9803
9956
  }
9804
9957
  }
9958
+ if (args.json) {
9959
+ report_child_scanned(corpusFiles + (sourceFiles === null ? 0 : sourceFiles.length));
9960
+ }
9805
9961
  if (args.json) {
9806
9962
  const payload = py_json_dumps_indent2(findings.map((f) => f.toDict()));
9807
9963
  process.stdout.write(payload + "\n");
@@ -11467,7 +11623,7 @@ var init_memory_fts_index = __esm({
11467
11623
  });
11468
11624
 
11469
11625
  // src/scripts/learning_sidecar.ts
11470
- import { createHash as createHash2 } from "node:crypto";
11626
+ import { createHash as createHash3 } from "node:crypto";
11471
11627
  import * as fs11 from "node:fs";
11472
11628
  import * as path11 from "node:path";
11473
11629
  import process5 from "node:process";
@@ -11477,7 +11633,7 @@ function _parseTsMs(ts) {
11477
11633
  return Number.isNaN(t) ? null : t;
11478
11634
  }
11479
11635
  function _bodyHash(body) {
11480
- return createHash2("sha256").update(body.trim().toLowerCase()).digest("hex").slice(0, 12);
11636
+ return createHash3("sha256").update(body.trim().toLowerCase()).digest("hex").slice(0, 12);
11481
11637
  }
11482
11638
  function _globSignalFiles(dir) {
11483
11639
  let names;
@@ -27740,6 +27896,168 @@ var init_runtime_wiring_checks = __esm({
27740
27896
  }
27741
27897
  });
27742
27898
 
27899
+ // src/scripts/_lib/host_capability.ts
27900
+ import process17 from "node:process";
27901
+ function asBool(value) {
27902
+ return value === true;
27903
+ }
27904
+ function normalizeHostManifest(input) {
27905
+ if (input === null || typeof input !== "object") {
27906
+ return { ...SAFE_DEFAULT };
27907
+ }
27908
+ const src = input;
27909
+ return {
27910
+ schema_version: 1,
27911
+ subagent_spawn: asBool(src.subagent_spawn),
27912
+ parallel_spawn: asBool(src.parallel_spawn),
27913
+ status_polling: asBool(src.status_polling),
27914
+ separate_quota_pool: asBool(src.separate_quota_pool),
27915
+ agent_teams: asBool(src.agent_teams),
27916
+ worker_respawn: asBool(src.worker_respawn),
27917
+ reads_project_mcp_config: asBool(src.reads_project_mcp_config),
27918
+ // Inverted coercion, matching the inverted default: only an explicit
27919
+ // `false` clears the residual, so an absent or malformed value keeps
27920
+ // the manual step visible instead of silently dropping it.
27921
+ mcp_needs_manual_activation: src.mcp_needs_manual_activation !== false
27922
+ };
27923
+ }
27924
+ function resolveHostCapabilities(hostId, override) {
27925
+ if (override !== void 0 && override !== null && typeof override === "object" && !Array.isArray(override)) {
27926
+ return normalizeHostManifest(override);
27927
+ }
27928
+ const row = hostId !== null && hostId !== void 0 ? HOST_CAPABILITY_REGISTRY[hostId] : void 0;
27929
+ if (row === void 0) {
27930
+ return { ...SAFE_DEFAULT };
27931
+ }
27932
+ return { ...SAFE_DEFAULT, ...row, schema_version: 1 };
27933
+ }
27934
+ function probeHostCapabilities(hostId) {
27935
+ const base = resolveHostCapabilities(hostId);
27936
+ const flag = process17.env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS;
27937
+ const probedAgentTeams = typeof flag === "string" && flag !== "";
27938
+ return { ...base, agent_teams: base.agent_teams || probedAgentTeams };
27939
+ }
27940
+ function describeHostCapabilities(hostId) {
27941
+ const manifest = probeHostCapabilities(hostId);
27942
+ const row = hostId !== null && hostId !== void 0 ? HOST_CAPABILITY_REGISTRY[hostId] : void 0;
27943
+ const flag = process17.env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS;
27944
+ const probedAgentTeams = typeof flag === "string" && flag !== "";
27945
+ const sources = {};
27946
+ for (const field of CAPABILITY_FIELDS) {
27947
+ if (row !== void 0 && typeof row[field] === "boolean") {
27948
+ sources[field] = "registry";
27949
+ } else if (field === "agent_teams" && probedAgentTeams) {
27950
+ sources[field] = "live-probe";
27951
+ } else {
27952
+ sources[field] = "default";
27953
+ }
27954
+ }
27955
+ return { manifest, sources };
27956
+ }
27957
+ var SAFE_DEFAULT, HOST_CAPABILITY_REGISTRY, CAPABILITY_FIELDS;
27958
+ var init_host_capability = __esm({
27959
+ "src/scripts/_lib/host_capability.ts"() {
27960
+ "use strict";
27961
+ SAFE_DEFAULT = {
27962
+ schema_version: 1,
27963
+ subagent_spawn: false,
27964
+ parallel_spawn: false,
27965
+ status_polling: false,
27966
+ separate_quota_pool: false,
27967
+ agent_teams: false,
27968
+ worker_respawn: false,
27969
+ reads_project_mcp_config: false,
27970
+ // `true` because the safe answer here is "there is still a step", not
27971
+ // "there is nothing to do" — see the field's own note.
27972
+ mcp_needs_manual_activation: true
27973
+ };
27974
+ HOST_CAPABILITY_REGISTRY = {
27975
+ claude: { subagent_spawn: true, parallel_spawn: true }
27976
+ };
27977
+ CAPABILITY_FIELDS = [
27978
+ "subagent_spawn",
27979
+ "parallel_spawn",
27980
+ "status_polling",
27981
+ "separate_quota_pool",
27982
+ "agent_teams",
27983
+ "worker_respawn",
27984
+ "reads_project_mcp_config",
27985
+ "mcp_needs_manual_activation"
27986
+ ];
27987
+ }
27988
+ });
27989
+
27990
+ // src/scripts/_lib/mcp_consent_residual.ts
27991
+ function residualFor(hostId) {
27992
+ const { manifest, sources } = describeHostCapabilities(hostId);
27993
+ if (sources.mcp_needs_manual_activation === "registry" && !manifest.mcp_needs_manual_activation) {
27994
+ return null;
27995
+ }
27996
+ return SEEDED[hostId] ?? null;
27997
+ }
27998
+ function isRecorded(hostId) {
27999
+ const { sources } = describeHostCapabilities(hostId);
28000
+ return hostId in SEEDED || sources.mcp_needs_manual_activation === "registry";
28001
+ }
28002
+ function residualLine(hostId) {
28003
+ const r = residualFor(hostId);
28004
+ if (r !== null) {
28005
+ return {
28006
+ hostId,
28007
+ state: "residual",
28008
+ text: `${hostId}: ${r.residual} (source: ${r.source} \u2014 not observed here)`
28009
+ };
28010
+ }
28011
+ if (isRecorded(hostId)) {
28012
+ return {
28013
+ hostId,
28014
+ state: "cleared",
28015
+ text: `${hostId}: nothing left to do (source: observed)`
28016
+ };
28017
+ }
28018
+ return {
28019
+ hostId,
28020
+ state: "unrecorded",
28021
+ text: `${hostId}: no residual recorded \u2014 nobody checked this host, which is not the same as nothing to do`
28022
+ };
28023
+ }
28024
+ function residualReport(toolIds) {
28025
+ const seen = /* @__PURE__ */ new Set();
28026
+ const out = [];
28027
+ for (const toolId of toolIds) {
28028
+ const hostId = TOOL_TO_HOST[toolId];
28029
+ if (hostId === void 0 || seen.has(hostId)) continue;
28030
+ seen.add(hostId);
28031
+ const line = residualLine(hostId);
28032
+ if (line.state !== "cleared") out.push(line);
28033
+ }
28034
+ return out;
28035
+ }
28036
+ var SEEDED, TOOL_TO_HOST;
28037
+ var init_mcp_consent_residual = __esm({
28038
+ "src/scripts/_lib/mcp_consent_residual.ts"() {
28039
+ "use strict";
28040
+ init_host_capability();
28041
+ SEEDED = {
28042
+ claude: {
28043
+ hostId: "claude",
28044
+ residual: "Approve the project-scoped `agent-config` server the first time the host prompts \u2014 the installer writes `.mcp.json` but does not pre-approve it.",
28045
+ source: "vendor-doc",
28046
+ cite: "Host documentation: a project-scope MCP server requires explicit approval, suppressible only through the user-global `enabledMcpjsonServers` key, which this package deliberately does not write (blocker `mcp-user-scope-approval-consent`)."
28047
+ }
28048
+ };
28049
+ TOOL_TO_HOST = {
28050
+ "claude-code": "claude",
28051
+ cursor: "cursor",
28052
+ "gemini-cli": "gemini",
28053
+ windsurf: "windsurf",
28054
+ cline: "cline",
28055
+ copilot: "copilot",
28056
+ augment: "augment"
28057
+ };
28058
+ }
28059
+ });
28060
+
27743
28061
  // src/scripts/_lib/install_reach_checks.ts
27744
28062
  import * as fs52 from "node:fs";
27745
28063
  import * as path53 from "node:path";
@@ -27928,17 +28246,33 @@ function checkOverrideSet(projectRoot) {
27928
28246
  remedy: "route it through the upstream-contribution path, never by changing a shipped default on one install"
27929
28247
  };
27930
28248
  }
28249
+ function checkMcpConsentResidual() {
28250
+ const id = "mcp-consent-residual";
28251
+ const lines = residualReport(Object.keys(TOOL_TO_HOST));
28252
+ if (lines.length === 0) {
28253
+ return { id, status: "ok", message: "no MCP consent residual recorded for any known host", remedy: "" };
28254
+ }
28255
+ const actionable = lines.filter((l) => l.state === "residual");
28256
+ return {
28257
+ id,
28258
+ status: "warn",
28259
+ message: lines.map((l) => l.text).join(" \xB7 "),
28260
+ remedy: actionable.length > 0 ? "complete the step named above on each host you use" : "record an observation for the unchecked hosts, or ignore if you do not use them"
28261
+ };
28262
+ }
27931
28263
  function reachRunners(opts) {
27932
28264
  return {
27933
28265
  "instruction-path-reach": () => checkInstructionPaths(opts.projectRoot),
27934
28266
  "version-axis": () => checkVersionAxis(opts.projectRoot, opts.resolvableVersion),
27935
- "override-set": () => checkOverrideSet(opts.projectRoot)
28267
+ "override-set": () => checkOverrideSet(opts.projectRoot),
28268
+ "mcp-consent-residual": () => checkMcpConsentResidual()
27936
28269
  };
27937
28270
  }
27938
28271
  var ROOT_INSTRUCTION_FILES, UNRESOLVABLE_REASONS, BACKTICKED, LINK_TARGET, EXTENSION, SETTINGS_PIN_FILES, PIN_RE, LOCK_VERSION_RE, OVERRIDE_LAYERS, KIND_DIRS, REACH_CHECK_IDS;
27939
28272
  var init_install_reach_checks = __esm({
27940
28273
  "src/scripts/_lib/install_reach_checks.ts"() {
27941
28274
  "use strict";
28275
+ init_mcp_consent_residual();
27942
28276
  ROOT_INSTRUCTION_FILES = [
27943
28277
  "AGENTS.md",
27944
28278
  "CLAUDE.md",
@@ -27981,7 +28315,7 @@ var init_install_reach_checks = __esm({
27981
28315
  { dir: "skills", kind: "skill" },
27982
28316
  { dir: "commands", kind: "command" }
27983
28317
  ];
27984
- REACH_CHECK_IDS = ["instruction-path-reach", "version-axis", "override-set"];
28318
+ REACH_CHECK_IDS = ["instruction-path-reach", "version-axis", "override-set", "mcp-consent-residual"];
27985
28319
  }
27986
28320
  });
27987
28321
 
@@ -33220,7 +33554,7 @@ var init_detection_report = __esm({
33220
33554
  });
33221
33555
 
33222
33556
  // src/scripts/hooks/state_io.ts
33223
- import { createHash as createHash6 } from "node:crypto";
33557
+ import { createHash as createHash7 } from "node:crypto";
33224
33558
  import fs59 from "node:fs";
33225
33559
  import path61 from "node:path";
33226
33560
  function is_replay_mode() {
@@ -33418,7 +33752,7 @@ function has_stable_session_id(session_id) {
33418
33752
  return typeof session_id === "string" && session_id.trim() !== "";
33419
33753
  }
33420
33754
  function session_state_file(dir, session_id) {
33421
- const digest = createHash6("sha256").update(session_id, "utf8").digest("hex").slice(0, 32);
33755
+ const digest = createHash7("sha256").update(session_id, "utf8").digest("hex").slice(0, 32);
33422
33756
  return path61.join(dir, `${digest}.json`);
33423
33757
  }
33424
33758
  function restore_claimed_state(tomb, live, link = fs59.linkSync) {
@@ -34093,7 +34427,7 @@ import * as crypto6 from "node:crypto";
34093
34427
  import * as fs64 from "node:fs";
34094
34428
  import * as os14 from "node:os";
34095
34429
  import * as path65 from "node:path";
34096
- import process17 from "node:process";
34430
+ import process18 from "node:process";
34097
34431
  import { fileURLToPath as fileURLToPath31, pathToFileURL as pathToFileURL21 } from "node:url";
34098
34432
  function expanduser5(p) {
34099
34433
  if (p === "~") return os14.homedir();
@@ -34230,10 +34564,10 @@ function yamlSafeLoad2(text) {
34230
34564
  }
34231
34565
  }
34232
34566
  function print2(line = "") {
34233
- process17.stdout.write(line + "\n");
34567
+ process18.stdout.write(line + "\n");
34234
34568
  }
34235
34569
  function eprint2(line = "") {
34236
- process17.stderr.write(line + "\n");
34570
+ process18.stderr.write(line + "\n");
34237
34571
  }
34238
34572
  function _resolve_project_root(arg) {
34239
34573
  return resolve_project_root(arg);
@@ -34284,7 +34618,7 @@ function _detect_wrapper(project_root) {
34284
34618
  };
34285
34619
  }
34286
34620
  function _emit_trace_text(root, anchor, trace, origin) {
34287
- print2(` \u{1F4CD} start: ${process17.cwd()}`);
34621
+ print2(` \u{1F4CD} start: ${process18.cwd()}`);
34288
34622
  print2(` \u{1F4CD} origin: ${origin}`);
34289
34623
  if (trace.length > 0) {
34290
34624
  print2(" trace:");
@@ -34304,7 +34638,7 @@ function _emit_trace_text(root, anchor, trace, origin) {
34304
34638
  }
34305
34639
  function _emit_trace_json(root, anchor, trace, origin) {
34306
34640
  const payload = {
34307
- start: process17.cwd(),
34641
+ start: process18.cwd(),
34308
34642
  origin,
34309
34643
  resolved_root: root !== null ? String(root) : null,
34310
34644
  anchor,
@@ -34744,10 +35078,10 @@ function shutilWhich(name) {
34744
35078
  if (path65.dirname(name) !== "." && (name.includes("/") || name.includes("\\"))) {
34745
35079
  return isExecutableFile(name) ? name : null;
34746
35080
  }
34747
- const pathEnv = process17.env["PATH"] || "";
34748
- const sep16 = process17.platform === "win32" ? ";" : ":";
35081
+ const pathEnv = process18.env["PATH"] || "";
35082
+ const sep16 = process18.platform === "win32" ? ";" : ":";
34749
35083
  const dirs = pathEnv.split(sep16);
34750
- const exts = process17.platform === "win32" ? (process17.env["PATHEXT"] || ".COM;.EXE;.BAT;.CMD").split(";") : [""];
35084
+ const exts = process18.platform === "win32" ? (process18.env["PATHEXT"] || ".COM;.EXE;.BAT;.CMD").split(";") : [""];
34751
35085
  const seenDirs = /* @__PURE__ */ new Set();
34752
35086
  for (const dir of dirs) {
34753
35087
  const d = dir === "" ? "." : dir;
@@ -34770,7 +35104,7 @@ function isExecutableFile(p) {
34770
35104
  try {
34771
35105
  const st = fs64.statSync(p);
34772
35106
  if (!st.isFile()) return false;
34773
- if (process17.platform === "win32") return true;
35107
+ if (process18.platform === "win32") return true;
34774
35108
  fs64.accessSync(p, fs64.constants.X_OK);
34775
35109
  return true;
34776
35110
  } catch {
@@ -36236,8 +36570,8 @@ function _emit_detection_text(project_root, checks) {
36236
36570
  print2("");
36237
36571
  }
36238
36572
  function _argError9(msg) {
36239
- process17.stderr.write(USAGE2);
36240
- process17.stderr.write(`${PROG4}: error: ${msg}
36573
+ process18.stderr.write(USAGE2);
36574
+ process18.stderr.write(`${PROG4}: error: ${msg}
36241
36575
  `);
36242
36576
  throw new ArgparseExit4(2);
36243
36577
  }
@@ -36258,7 +36592,7 @@ function _parse3(argv) {
36258
36592
  while (i < argv.length) {
36259
36593
  const a = argv[i];
36260
36594
  if (a === "-h" || a === "--help") {
36261
- process17.stdout.write(USAGE2);
36595
+ process18.stdout.write(USAGE2);
36262
36596
  throw new ArgparseExit4(0);
36263
36597
  }
36264
36598
  const eq = a.startsWith("--") ? a.indexOf("=") : -1;
@@ -36316,14 +36650,14 @@ function argMetaName(flag) {
36316
36650
  return flag;
36317
36651
  }
36318
36652
  function _run_trace_root(opts) {
36319
- const start = process17.cwd();
36653
+ const start = process18.cwd();
36320
36654
  const [root, anchor, trace] = find_project_root_with_trace(start);
36321
36655
  let origin;
36322
- if (process17.env[ROOT_OVERRIDE_ENV] === "1" && process17.env[PROJECT_ROOT_ENV]) {
36656
+ if (process18.env[ROOT_OVERRIDE_ENV] === "1" && process18.env[PROJECT_ROOT_ENV]) {
36323
36657
  origin = "root-flag";
36324
36658
  } else if (opts.project) {
36325
36659
  origin = "explicit";
36326
- } else if (process17.env[PROJECT_ROOT_ENV]) {
36660
+ } else if (process18.env[PROJECT_ROOT_ENV]) {
36327
36661
  origin = "env";
36328
36662
  } else if (root !== null) {
36329
36663
  origin = anchor || "unknown";
@@ -36355,8 +36689,8 @@ function _run_context(opts) {
36355
36689
  origin,
36356
36690
  install_mode: mode,
36357
36691
  install_mode_source: mode_source,
36358
- env_pin: process17.env[PROJECT_ROOT_ENV] || null,
36359
- root_override: process17.env[ROOT_OVERRIDE_ENV] === "1",
36692
+ env_pin: process18.env[PROJECT_ROOT_ENV] || null,
36693
+ root_override: process18.env[ROOT_OVERRIDE_ENV] === "1",
36360
36694
  settings_layers: _settings_layer_chain(project_root),
36361
36695
  wrapper: _detect_wrapper(project_root)
36362
36696
  };
@@ -36376,7 +36710,7 @@ function _run_anatomy(opts) {
36376
36710
  try {
36377
36711
  economyReport = economy.buildReport({
36378
36712
  root: economy.DEFAULT_PROJECTS_ROOT,
36379
- auditDir: path65.join(process17.cwd(), economy.DEFAULT_AUDIT_DIR),
36713
+ auditDir: path65.join(process18.cwd(), economy.DEFAULT_AUDIT_DIR),
36380
36714
  maxAgeDays: 14
36381
36715
  });
36382
36716
  } catch (err) {
@@ -36442,7 +36776,7 @@ function _run_repair(opts) {
36442
36776
  return 2;
36443
36777
  }
36444
36778
  function main21(argv = null) {
36445
- const opts = _parse3(argv !== null ? Array.from(argv) : process17.argv.slice(2));
36779
+ const opts = _parse3(argv !== null ? Array.from(argv) : process18.argv.slice(2));
36446
36780
  validateStrictLevelOr(opts.strict_level, _argError9);
36447
36781
  if (opts.ci) {
36448
36782
  opts.json = true;
@@ -36518,21 +36852,21 @@ function _isCliEntry17() {
36518
36852
  if (bundled && !cliDelegate) {
36519
36853
  return false;
36520
36854
  }
36521
- if (process17.argv[1] === void 0) {
36855
+ if (process18.argv[1] === void 0) {
36522
36856
  return false;
36523
36857
  }
36524
36858
  if (cliDelegate) {
36525
- if (path65.basename(process17.argv[1], ".js") === "cmd_doctor") {
36859
+ if (path65.basename(process18.argv[1], ".js") === "cmd_doctor") {
36526
36860
  return true;
36527
36861
  }
36528
36862
  }
36529
- const argvUrl = pathToFileURL21(path65.resolve(process17.argv[1])).href;
36863
+ const argvUrl = pathToFileURL21(path65.resolve(process18.argv[1])).href;
36530
36864
  if (import.meta.url === argvUrl) {
36531
36865
  return true;
36532
36866
  }
36533
36867
  try {
36534
36868
  const here = fs64.realpathSync(fileURLToPath31(import.meta.url));
36535
- const argv = fs64.realpathSync(path65.resolve(process17.argv[1]));
36869
+ const argv = fs64.realpathSync(path65.resolve(process18.argv[1]));
36536
36870
  return here === argv;
36537
36871
  } catch {
36538
36872
  return false;
@@ -36693,12 +37027,12 @@ var init_cmd_doctor = __esm({
36693
37027
  "--check": "check",
36694
37028
  "--repair": "repair"
36695
37029
  };
36696
- if (_isCliEntry17() || process17.argv[1] === _HERE18) {
37030
+ if (_isCliEntry17() || process18.argv[1] === _HERE18) {
36697
37031
  try {
36698
- process17.exitCode = main21(process17.argv.slice(2));
37032
+ process18.exitCode = main21(process18.argv.slice(2));
36699
37033
  } catch (e) {
36700
37034
  if (e instanceof ArgparseExit4) {
36701
- process17.exitCode = e.code;
37035
+ process18.exitCode = e.code;
36702
37036
  } else {
36703
37037
  throw e;
36704
37038
  }
@@ -38963,6 +39297,25 @@ var init_before_complete_hook = __esm({
38963
39297
  }
38964
39298
  });
38965
39299
 
39300
+ // src/scripts/_lib/audit_field_provenance.ts
39301
+ function appliedIds(values) {
39302
+ const out = [];
39303
+ for (const raw of values ?? []) {
39304
+ const v = String(raw).trim();
39305
+ if (v === "" || out.includes(v)) continue;
39306
+ out.push(v);
39307
+ if (out.length >= MAX_APPLIED_IDS) break;
39308
+ }
39309
+ return out;
39310
+ }
39311
+ var MAX_APPLIED_IDS;
39312
+ var init_audit_field_provenance = __esm({
39313
+ "src/scripts/_lib/audit_field_provenance.ts"() {
39314
+ "use strict";
39315
+ MAX_APPLIED_IDS = 32;
39316
+ }
39317
+ });
39318
+
38966
39319
  // src/scripts/_lib/review_skipped_record.ts
38967
39320
  function isNonNegInt(n) {
38968
39321
  return typeof n === "number" && Number.isFinite(n) && Number.isInteger(n) && n >= 0;
@@ -38989,7 +39342,8 @@ function buildReviewSkippedLine(input) {
38989
39342
  risk_class: input.diff_lines >= HIGH_RISK_DIFF_LINES ? "high" : "medium",
38990
39343
  memory: { asks: 0, hits: 0 },
38991
39344
  verify: { claims: 0, first_try_passes: 0 },
38992
- rules_applied: ["delegation-policy"],
39345
+ // COMPUTED, never a producer constant.
39346
+ rules_applied: appliedIds(input.rules_applied),
38993
39347
  // MANDATORY on every audit line, same as the orchestration producer.
38994
39348
  privacy_class: PRODUCER_PRIVACY_CLASS,
38995
39349
  // `skills_applied` is OMITTED here, deliberately and not by oversight.
@@ -39010,6 +39364,7 @@ var PRODUCER_PRIVACY_CLASS, HIGH_RISK_DIFF_LINES;
39010
39364
  var init_review_skipped_record = __esm({
39011
39365
  "src/scripts/_lib/review_skipped_record.ts"() {
39012
39366
  "use strict";
39367
+ init_audit_field_provenance();
39013
39368
  PRODUCER_PRIVACY_CLASS = "ids-only";
39014
39369
  HIGH_RISK_DIFF_LINES = 200;
39015
39370
  }
@@ -40674,61 +41029,6 @@ var init_evidence_independence = __esm({
40674
41029
  }
40675
41030
  });
40676
41031
 
40677
- // src/scripts/_lib/host_capability.ts
40678
- import process18 from "node:process";
40679
- function asBool(value) {
40680
- return value === true;
40681
- }
40682
- function normalizeHostManifest(input) {
40683
- if (input === null || typeof input !== "object") {
40684
- return { ...SAFE_DEFAULT };
40685
- }
40686
- const src = input;
40687
- return {
40688
- schema_version: 1,
40689
- subagent_spawn: asBool(src.subagent_spawn),
40690
- parallel_spawn: asBool(src.parallel_spawn),
40691
- status_polling: asBool(src.status_polling),
40692
- separate_quota_pool: asBool(src.separate_quota_pool),
40693
- agent_teams: asBool(src.agent_teams),
40694
- worker_respawn: asBool(src.worker_respawn)
40695
- };
40696
- }
40697
- function resolveHostCapabilities(hostId, override) {
40698
- if (override !== void 0 && override !== null && typeof override === "object" && !Array.isArray(override)) {
40699
- return normalizeHostManifest(override);
40700
- }
40701
- const row = hostId !== null && hostId !== void 0 ? HOST_CAPABILITY_REGISTRY[hostId] : void 0;
40702
- if (row === void 0) {
40703
- return { ...SAFE_DEFAULT };
40704
- }
40705
- return { ...SAFE_DEFAULT, ...row, schema_version: 1 };
40706
- }
40707
- function probeHostCapabilities(hostId) {
40708
- const base = resolveHostCapabilities(hostId);
40709
- const flag = process18.env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS;
40710
- const probedAgentTeams = typeof flag === "string" && flag !== "";
40711
- return { ...base, agent_teams: base.agent_teams || probedAgentTeams };
40712
- }
40713
- var SAFE_DEFAULT, HOST_CAPABILITY_REGISTRY;
40714
- var init_host_capability = __esm({
40715
- "src/scripts/_lib/host_capability.ts"() {
40716
- "use strict";
40717
- SAFE_DEFAULT = {
40718
- schema_version: 1,
40719
- subagent_spawn: false,
40720
- parallel_spawn: false,
40721
- status_polling: false,
40722
- separate_quota_pool: false,
40723
- agent_teams: false,
40724
- worker_respawn: false
40725
- };
40726
- HOST_CAPABILITY_REGISTRY = {
40727
- claude: { subagent_spawn: true, parallel_spawn: true }
40728
- };
40729
- }
40730
- });
40731
-
40732
41032
  // src/scripts/_lib/auto_dispatch.ts
40733
41033
  function inSession(reason) {
40734
41034
  return { delegable: false, action: "in-session", mode: null, reason };
@@ -41265,7 +41565,7 @@ var init_delegation_nudge_hook = __esm({
41265
41565
  });
41266
41566
 
41267
41567
  // src/scripts/conformance_scan.ts
41268
- import { createHash as createHash12 } from "node:crypto";
41568
+ import { createHash as createHash13 } from "node:crypto";
41269
41569
  import fs73 from "node:fs";
41270
41570
  import os16 from "node:os";
41271
41571
  import path75 from "node:path";
@@ -41636,7 +41936,7 @@ function measureDelivered(projectRulesDir, globalRulesDir) {
41636
41936
  };
41637
41937
  }
41638
41938
  function storeKey(store) {
41639
- return createHash12("sha256").update(path75.resolve(store)).digest("hex").slice(0, 12);
41939
+ return createHash13("sha256").update(path75.resolve(store)).digest("hex").slice(0, 12);
41640
41940
  }
41641
41941
  function scanStore(store, limit) {
41642
41942
  const files = fs73.readdirSync(store).filter((f) => f.endsWith(".jsonl")).map((f) => ({ f, m: fs73.statSync(path75.join(store, f)).mtimeMs })).sort((a, b) => b.m - a.m).slice(0, limit).map((x) => x.f);
@@ -44565,6 +44865,75 @@ var init_aggregator = __esm({
44565
44865
  }
44566
44866
  });
44567
44867
 
44868
+ // src/agent-src/templates/scripts/telemetry/mcp_lite.ts
44869
+ function _sorted(m) {
44870
+ return [...m.entries()].sort((a, b) => b[1] - a[1] || (a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0));
44871
+ }
44872
+ function render_mcp_lite_markdown(agg) {
44873
+ const lines = [];
44874
+ lines.push("## MCP lite surface");
44875
+ lines.push("");
44876
+ lines.push(`- calls recorded: **${agg.calls}**`);
44877
+ if (agg.earliest_ts && agg.latest_ts) {
44878
+ lines.push(`- ts range: \`${agg.earliest_ts}\` \u2192 \`${agg.latest_ts}\``);
44879
+ }
44880
+ lines.push("");
44881
+ if (agg.calls === 0) {
44882
+ lines.push(ZERO_NOTE);
44883
+ lines.push("");
44884
+ return `${lines.join("\n")}`;
44885
+ }
44886
+ lines.push("| tool | calls |");
44887
+ lines.push("|---|---:|");
44888
+ for (const [tool, n] of _sorted(agg.by_tool)) {
44889
+ check_id_redaction("mcp_lite.by_tool.id", tool);
44890
+ lines.push(`| ${tool} | ${n} |`);
44891
+ }
44892
+ lines.push("");
44893
+ lines.push("| host | calls |");
44894
+ lines.push("|---|---:|");
44895
+ for (const [host, n] of _sorted(agg.by_host)) {
44896
+ check_id_redaction("mcp_lite.by_host.id", host);
44897
+ lines.push(`| ${host} | ${n} |`);
44898
+ }
44899
+ lines.push("");
44900
+ return `${lines.join("\n")}`;
44901
+ }
44902
+ function mcp_lite_json(agg) {
44903
+ const by_tool = {};
44904
+ for (const [tool, n] of _sorted(agg.by_tool)) {
44905
+ check_id_redaction("mcp_lite.by_tool.id", tool);
44906
+ by_tool[tool] = n;
44907
+ }
44908
+ const by_host = {};
44909
+ for (const [host, n] of _sorted(agg.by_host)) {
44910
+ check_id_redaction("mcp_lite.by_host.id", host);
44911
+ by_host[host] = n;
44912
+ }
44913
+ const by_outcome = {};
44914
+ for (const [outcome, n] of _sorted(agg.by_outcome)) {
44915
+ by_outcome[outcome] = n;
44916
+ }
44917
+ return {
44918
+ log_path: agg.log_path,
44919
+ calls: agg.calls,
44920
+ skipped_lines: agg.skipped_lines,
44921
+ by_tool,
44922
+ by_host,
44923
+ by_outcome,
44924
+ earliest_ts: agg.earliest_ts,
44925
+ latest_ts: agg.latest_ts
44926
+ };
44927
+ }
44928
+ var ZERO_NOTE;
44929
+ var init_mcp_lite = __esm({
44930
+ "src/agent-src/templates/scripts/telemetry/mcp_lite.ts"() {
44931
+ "use strict";
44932
+ init_engagement();
44933
+ ZERO_NOTE = "_No calls recorded. The lite-surface emitter is default-off (`telemetry.artifact_engagement.enabled`), so a zero here says the instrument was off or unused on this machine \u2014 it is not a measurement of what consumers do._";
44934
+ }
44935
+ });
44936
+
44568
44937
  // src/agent-src/templates/scripts/telemetry/report_renderer.ts
44569
44938
  var report_renderer_exports = {};
44570
44939
  __export(report_renderer_exports, {
@@ -44674,6 +45043,9 @@ function render_markdown(aggregate3, opts = {}) {
44674
45043
  }
44675
45044
  lines.push("");
44676
45045
  }
45046
+ if (opts.mcp_lite) {
45047
+ lines.push(render_mcp_lite_markdown(opts.mcp_lite));
45048
+ }
44677
45049
  return `${_pyRStrip(lines.join("\n"))}
44678
45050
  `;
44679
45051
  }
@@ -44717,7 +45089,8 @@ function render_json2(aggregate3, opts = {}) {
44717
45089
  since_label
44718
45090
  },
44719
45091
  outcomes: outcomes_payload,
44720
- buckets: grouped
45092
+ buckets: grouped,
45093
+ ...opts.mcp_lite ? { mcp_lite: mcp_lite_json(opts.mcp_lite) } : {}
44721
45094
  };
44722
45095
  return `${_py_json_dumps_indent2_sorted(payload)}
44723
45096
  `;
@@ -44912,6 +45285,7 @@ var init_report_renderer = __esm({
44912
45285
  "use strict";
44913
45286
  init_aggregator();
44914
45287
  init_engagement();
45288
+ init_mcp_lite();
44915
45289
  QUARTILE_TOP_RATIO = 0.2;
44916
45290
  QUARTILE_BOTTOM_RATIO = 0.2;
44917
45291
  BUCKET_TOP = "essential";
@@ -45516,9 +45890,9 @@ var init_consensus = __esm({
45516
45890
  });
45517
45891
 
45518
45892
  // src/scripts/ai_council/blind_review.ts
45519
- import { createHash as createHash13 } from "node:crypto";
45893
+ import { createHash as createHash14 } from "node:crypto";
45520
45894
  function _sha256_hex(s) {
45521
- return createHash13("sha256").update(s, "utf-8").digest("hex");
45895
+ return createHash14("sha256").update(s, "utf-8").digest("hex");
45522
45896
  }
45523
45897
  function deterministic_shuffle_indices(seed, n) {
45524
45898
  const keyed = Array.from({ length: n }, (_, i) => ({ i, key: _sha256_hex(`${seed}\0${i}`) }));
@@ -51531,7 +51905,7 @@ __export(shadow_dispatch_exports, {
51531
51905
  slo_status: () => slo_status
51532
51906
  });
51533
51907
  import * as fs90 from "node:fs";
51534
- import { createHash as createHash14 } from "node:crypto";
51908
+ import { createHash as createHash15 } from "node:crypto";
51535
51909
  function should_shadow(sampleRate, opts = {}) {
51536
51910
  const rate = Math.max(0, Math.min(1, sampleRate));
51537
51911
  const rng = opts.rng ?? null;
@@ -51540,7 +51914,7 @@ function should_shadow(sampleRate, opts = {}) {
51540
51914
  }
51541
51915
  function _hashQuery(query) {
51542
51916
  const redacted = redact(query);
51543
- return createHash14("sha256").update(Buffer.from(redacted, "utf-8")).digest("hex").slice(0, 16);
51917
+ return createHash15("sha256").update(Buffer.from(redacted, "utf-8")).digest("hex").slice(0, 16);
51544
51918
  }
51545
51919
  function _privacyDropped(redacted) {
51546
51920
  const stripped = _strip8(redacted);
@@ -56568,7 +56942,7 @@ import { fileURLToPath as fileURLToPath48 } from "node:url";
56568
56942
  init_memory_lookup();
56569
56943
  init_agent_settings();
56570
56944
  init_hook_stdin();
56571
- import { createHash as createHash3 } from "node:crypto";
56945
+ import { createHash as createHash4 } from "node:crypto";
56572
56946
  import * as fs14 from "node:fs";
56573
56947
  import * as path13 from "node:path";
56574
56948
  import { fileURLToPath as fileURLToPath9, pathToFileURL as pathToFileURL5 } from "node:url";
@@ -56788,7 +57162,7 @@ function _now() {
56788
57162
  }
56789
57163
  function fingerprint(value) {
56790
57164
  const normalized = _strip2((value || "").replace(_WS_RE, " "));
56791
- return createHash3("sha256").update(normalized, "utf-8").digest("hex");
57165
+ return createHash4("sha256").update(normalized, "utf-8").digest("hex");
56792
57166
  }
56793
57167
  function derive_session_tag(session_id) {
56794
57168
  if (!session_id) {
@@ -57021,7 +57395,7 @@ function _atomic_write_text(target, text) {
57021
57395
  return;
57022
57396
  }
57023
57397
  const suffix = path13.extname(target);
57024
- const uniq = `${process.pid}.${createHash3("sha256").update(`${process.pid}:${Date.now()}:${Math.random()}`).digest("hex").slice(0, 8)}`;
57398
+ const uniq = `${process.pid}.${createHash4("sha256").update(`${process.pid}:${Date.now()}:${Math.random()}`).digest("hex").slice(0, 8)}`;
57025
57399
  const tmp = target.slice(0, target.length - suffix.length) + `${suffix}.${uniq}.tmp`;
57026
57400
  try {
57027
57401
  fs14.writeFileSync(tmp, text, { encoding: "utf-8" });
@@ -58748,22 +59122,27 @@ function _now_iso() {
58748
59122
  return (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d{3}Z$/, "Z");
58749
59123
  }
58750
59124
  function build_record(options) {
58751
- const { tool_name, outcome, transport, client_id_hash_value, ts } = options;
58752
- return {
59125
+ const { tool_name, outcome, transport, client_id_hash_value, ts, host } = options;
59126
+ const record = {
58753
59127
  tool_name,
58754
59128
  client_id_hash: client_id_hash_value || hash_client_id(),
58755
59129
  ts: ts || _now_iso(),
58756
59130
  transport,
58757
59131
  outcome
58758
59132
  };
59133
+ if (typeof host === "string" && host !== "") {
59134
+ record.host = host;
59135
+ }
59136
+ return record;
58759
59137
  }
58760
59138
  function record_call(options) {
58761
- const { tool_name, outcome, transport, consumer_root, client_id_hash_value } = options;
59139
+ const { tool_name, outcome, transport, consumer_root, client_id_hash_value, host } = options;
58762
59140
  const record = build_record({
58763
59141
  tool_name,
58764
59142
  outcome,
58765
59143
  transport,
58766
- client_id_hash_value
59144
+ client_id_hash_value,
59145
+ host
58767
59146
  });
58768
59147
  const target = _resolve_log_path(consumer_root ?? void 0);
58769
59148
  try {