mandrel 2.15.0 → 2.17.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 (69) hide show
  1. package/.agents/docs/configuration.md +1 -0
  2. package/.agents/docs/quality-gates.md +137 -0
  3. package/.agents/docs/workflows.md +2 -1
  4. package/.agents/schemas/agentrc.schema.json +6 -0
  5. package/.agents/schemas/baselines/baseline-envelope.schema.json +4 -0
  6. package/.agents/schemas/baselines/crap.schema.json +4 -0
  7. package/.agents/scripts/acceptance-eval.js +52 -12
  8. package/.agents/scripts/audit-to-stories.js +92 -25
  9. package/.agents/scripts/boot-sweep.js +28 -6
  10. package/.agents/scripts/check-baseline-drift.js +138 -0
  11. package/.agents/scripts/coverage-capture.js +74 -25
  12. package/.agents/scripts/deliver-light.js +31 -3
  13. package/.agents/scripts/deliver-recover.js +45 -18
  14. package/.agents/scripts/drain-pending-cleanup.js +67 -23
  15. package/.agents/scripts/generate-lens-checklists.js +81 -30
  16. package/.agents/scripts/lib/audit-to-stories/parse-audit-md.js +88 -17
  17. package/.agents/scripts/lib/baselines/drift-detector.js +351 -0
  18. package/.agents/scripts/lib/baselines/envelope.js +7 -0
  19. package/.agents/scripts/lib/baselines/kernel.js +31 -0
  20. package/.agents/scripts/lib/baselines/kinds/crap.js +76 -0
  21. package/.agents/scripts/lib/baselines/reader.js +12 -1
  22. package/.agents/scripts/lib/baselines/refresh-service.js +7 -1
  23. package/.agents/scripts/lib/baselines/writer.js +10 -0
  24. package/.agents/scripts/lib/checks/story-init-not-backgrounded.js +23 -8
  25. package/.agents/scripts/lib/cli-utils.js +48 -13
  26. package/.agents/scripts/lib/close-validation/process.js +61 -15
  27. package/.agents/scripts/lib/close-validation/projections/advisories.js +184 -0
  28. package/.agents/scripts/lib/close-validation/projections/crap.js +303 -0
  29. package/.agents/scripts/lib/close-validation/runner.js +68 -0
  30. package/.agents/scripts/lib/config/gates/crap.schema.js +7 -0
  31. package/.agents/scripts/lib/config/quality.js +40 -0
  32. package/.agents/scripts/lib/coverage-utils.js +92 -9
  33. package/.agents/scripts/lib/crap-engine.js +113 -23
  34. package/.agents/scripts/lib/crap-utils.js +159 -93
  35. package/.agents/scripts/lib/dynamic-workflow/audit-orchestrator.js +97 -10
  36. package/.agents/scripts/lib/dynamic-workflow/degraded-coverage.js +81 -0
  37. package/.agents/scripts/lib/git-branch-lifecycle.js +15 -8
  38. package/.agents/scripts/lib/orchestration/check-baselines/phases/compare.js +35 -0
  39. package/.agents/scripts/lib/orchestration/check-baselines/phases/evaluate.js +13 -0
  40. package/.agents/scripts/lib/orchestration/complexity-gate.js +307 -89
  41. package/.agents/scripts/lib/orchestration/git-cleanup/phases/git-probes-ff.js +16 -1
  42. package/.agents/scripts/lib/orchestration/light-suitability.js +31 -9
  43. package/.agents/scripts/lib/orchestration/plan-context.js +190 -10
  44. package/.agents/scripts/lib/orchestration/single-story-close/failed-terminal.js +122 -0
  45. package/.agents/scripts/lib/orchestration/single-story-close/gate-log.js +87 -13
  46. package/.agents/scripts/lib/orchestration/single-story-close/phases/close-validation.js +38 -15
  47. package/.agents/scripts/lib/orchestration/story-deliver-terminal-schema.js +166 -0
  48. package/.agents/scripts/lib/orchestration/story-deliver-terminal.js +21 -50
  49. package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +26 -12
  50. package/.agents/scripts/lib/stdio-flush.js +71 -0
  51. package/.agents/scripts/lib/transpile.js +133 -6
  52. package/.agents/scripts/lib/workers/combined-mi-crap-worker.js +47 -101
  53. package/.agents/scripts/lib/workers/crap-worker.js +49 -76
  54. package/.agents/scripts/lib/worktree/lifecycle/reap.js +81 -8
  55. package/.agents/scripts/nav-registry-diff.js +30 -8
  56. package/.agents/scripts/plan-context.js +4 -1
  57. package/.agents/scripts/plan-run-epilogue.js +27 -11
  58. package/.agents/scripts/resolve-doc-tiers.js +18 -8
  59. package/.agents/scripts/single-story-close.js +9 -92
  60. package/.agents/scripts/update-crap-baseline.js +13 -0
  61. package/.agents/workflows/helpers/deliver-light.md +34 -8
  62. package/.agents/workflows/helpers/plan-reference.md +27 -6
  63. package/.agents/workflows/plan.md +4 -2
  64. package/.agents/workflows/prototype.md +104 -0
  65. package/README.md +14 -6
  66. package/docs/CHANGELOG.md +41 -0
  67. package/lib/cli/version-helpers.js +7 -0
  68. package/lib/migrations/steps/2.2.0-retire-epic-ac-tags.js +15 -8
  69. package/package.json +5 -1
@@ -16,6 +16,13 @@
16
16
  * Builtins only — this module is imported from both the CLI surface
17
17
  * (`lib/cli/`) and the doctor registry which runs before third-party
18
18
  * packages are guaranteed to be present.
19
+ *
20
+ * The two filesystem-touching helpers below take the module's injectable
21
+ * seam as their optional final `fsImpl` parameter, defaulting to the real
22
+ * `node:fs` (`.agents/rules/test-seams.md` rules 1-2);
23
+ * `resolveConsumerPinVersion` forwards that seam to
24
+ * `resolveConsumerPinSpec` rather than re-acquiring `fs` itself (rule 4).
25
+ * Every other export here is pure, so it needs no seam of its own.
19
26
  */
20
27
 
21
28
  import nodeFs from 'node:fs';
@@ -40,10 +40,11 @@ const TAG_LINE_RE = /^(\s*)(@\S+(?:\s+@\S+)*)\s*$/;
40
40
  * Recursively collect `.feature` file paths under `root`.
41
41
  *
42
42
  * @param {string} root
43
- * @param {typeof nodeFs} fsImpl
43
+ * @param {typeof nodeFs} [fsImpl] Filesystem seam; defaults to the real
44
+ * `node:fs` per `.agents/rules/test-seams.md` rule 1.
44
45
  * @returns {string[]}
45
46
  */
46
- function collectFeatureFiles(root, fsImpl) {
47
+ function collectFeatureFiles(root, fsImpl = nodeFs) {
47
48
  /** @type {string[]} */
48
49
  const found = [];
49
50
  /** @type {string[]} */
@@ -71,11 +72,13 @@ function collectFeatureFiles(root, fsImpl) {
71
72
 
72
73
  /**
73
74
  * @param {unknown} ctx
74
- * @param {typeof nodeFs} fsImpl
75
+ * @param {typeof nodeFs} [fsImpl] Filesystem seam; forwarded to
76
+ * {@link collectFeatureFiles} rather than re-acquired there
77
+ * (`.agents/rules/test-seams.md` rule 4).
75
78
  * @returns {string[]} Absolute paths of every `.feature` file under the
76
79
  * canonical feature roots that exist in the consumer tree.
77
80
  */
78
- function resolveFeatureFiles(ctx, fsImpl) {
81
+ function resolveFeatureFiles(ctx, fsImpl = nodeFs) {
79
82
  const projectRoot = ctx?.projectRoot ?? process.cwd();
80
83
  return CANONICAL_FEATURE_ROOTS.flatMap((root) =>
81
84
  collectFeatureFiles(path.join(projectRoot, root), fsImpl),
@@ -119,10 +122,12 @@ export const retireEpicAcTags = {
119
122
  '(their reconciler consumer was deleted in the v2 Epic removal)',
120
123
  /**
121
124
  * @param {{ projectRoot?: string, fs?: typeof nodeFs }} [ctx]
125
+ * @param {typeof nodeFs} [fsImpl] Optional final filesystem seam; defaults
126
+ * to `ctx.fs` when the migration runner threads one, else the real
127
+ * `node:fs` (`.agents/rules/test-seams.md` rule 1).
122
128
  * @returns {boolean}
123
129
  */
124
- detect(ctx) {
125
- const fsImpl = ctx?.fs ?? nodeFs;
130
+ detect(ctx, fsImpl = ctx?.fs ?? nodeFs) {
126
131
  return resolveFeatureFiles(ctx, fsImpl).some((file) => {
127
132
  try {
128
133
  return EPIC_AC_TAG_RE.test(fsImpl.readFileSync(file, 'utf8'));
@@ -133,10 +138,12 @@ export const retireEpicAcTags = {
133
138
  },
134
139
  /**
135
140
  * @param {{ projectRoot?: string, fs?: typeof nodeFs }} [ctx]
141
+ * @param {typeof nodeFs} [fsImpl] Optional final filesystem seam; defaults
142
+ * to `ctx.fs` when the migration runner threads one, else the real
143
+ * `node:fs` (`.agents/rules/test-seams.md` rule 1).
136
144
  * @returns {void}
137
145
  */
138
- apply(ctx) {
139
- const fsImpl = ctx?.fs ?? nodeFs;
146
+ apply(ctx, fsImpl = ctx?.fs ?? nodeFs) {
140
147
  for (const file of resolveFeatureFiles(ctx, fsImpl)) {
141
148
  /** @type {string} */
142
149
  let content;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mandrel",
3
- "version": "2.15.0",
3
+ "version": "2.17.0",
4
4
  "description": "Claude Code-first opinionated workflow framework: instructions, skills, rules, and SDLC workflows that govern AI coding assistants.",
5
5
  "files": [
6
6
  ".agents/",
@@ -110,6 +110,10 @@
110
110
  "optional": true
111
111
  }
112
112
  },
113
+ "//": {
114
+ "overrides.js-yaml": "COUPLED to devDependencies.markdownlint-cli2 — do not bump either alone, and do NOT drop this override. It is load-bearing: markdownlint-cli2 0.22.x pulls js-yaml 4.1.1, which carries GHSA-52cp-r559-cp3m (high) and GHSA-h67p-54hq-rp68 (moderate); removing the override was measured to reintroduce both (1 high + 1 moderate), while with it in place `npm audit` is clean. An npm override also wins over a transitive package's own pin, so this tree-wide ^4.2.0 is imposed on every js-yaml consumer regardless of what they declare — and markdownlint-cli2 0.23.x declares an exact js-yaml 5.2.1. A dry-run bump confirmed the trap: markdownlint-cli2 0.23.1 resolves against js-yaml 4.3.0, two majors off what it declares, silently. The only safe move is to raise this override and bump markdownlint-cli2 in ONE reviewed commit (first confirming cosmiconfig, under @commitlint/cli, tolerates the same major). renovate.json excludes markdownlint-cli2 from devDependency auto-merge so that pair cannot drift apart unattended.",
115
+ "dependencies.js-yaml": "States the SAME range as overrides.js-yaml above. The two are deliberate duplicates — npm has no way to reference the direct range from the overrides block — so they MUST move in lockstep; changing one without the other silently splits the direct and transitive resolutions."
116
+ },
113
117
  "overrides": {
114
118
  "js-yaml": "^4.2.0",
115
119
  "markdown-it": "^14.2.0"