mandrel 2.63.0 → 2.65.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 (70) hide show
  1. package/.agents/agents/acceptance-critic.md +3 -2
  2. package/.agents/agents/auditor.md +3 -2
  3. package/.agents/agents/plan-critic.md +3 -2
  4. package/.agents/agents/story-worker.md +2 -2
  5. package/.agents/audit-checklists/quality.md +3 -0
  6. package/.agents/docs/agentrc-reference.json +1 -9
  7. package/.agents/docs/configuration.md +8 -7
  8. package/.agents/schemas/agentrc.schema.json +6 -13
  9. package/.agents/schemas/audit-rules.schema.json +1 -1
  10. package/.agents/schemas/story-deliver-terminal.schema.json +5 -0
  11. package/.agents/scripts/bootstrap.js +8 -2
  12. package/.agents/scripts/check-context-budget.js +1 -1
  13. package/.agents/scripts/lib/ITicketingProvider.js +1 -3
  14. package/.agents/scripts/lib/audit-suite/findings.js +1 -17
  15. package/.agents/scripts/lib/audit-suite/frontmatter.js +0 -28
  16. package/.agents/scripts/lib/audit-suite/index.js +0 -6
  17. package/.agents/scripts/lib/audit-suite/selector.js +0 -31
  18. package/.agents/scripts/lib/bootstrap/agents-md-fold.js +156 -0
  19. package/.agents/scripts/lib/bootstrap/commit-push.js +1 -1
  20. package/.agents/scripts/lib/bootstrap/manifest.js +2 -2
  21. package/.agents/scripts/lib/bootstrap/project-bootstrap.js +13 -29
  22. package/.agents/scripts/lib/config/review-chain-default.js +13 -0
  23. package/.agents/scripts/lib/config-settings-schema-delivery.js +2 -2
  24. package/.agents/scripts/lib/config-settings-schema-quality.js +11 -13
  25. package/.agents/scripts/lib/doc-tiers.js +25 -6
  26. package/.agents/scripts/lib/generated/agentrc-validator.js +1 -1
  27. package/.agents/scripts/lib/observability/metrics-ledger.js +0 -72
  28. package/.agents/scripts/lib/orchestration/ci-red-handling.js +73 -0
  29. package/.agents/scripts/lib/orchestration/code-review.js +11 -6
  30. package/.agents/scripts/lib/orchestration/deliver-recover.js +56 -11
  31. package/.agents/scripts/lib/orchestration/epic-rollup.js +29 -12
  32. package/.agents/scripts/lib/orchestration/merge-block-class.js +20 -4
  33. package/.agents/scripts/lib/orchestration/merge-poll.js +41 -22
  34. package/.agents/scripts/lib/orchestration/required-checks.js +147 -0
  35. package/.agents/scripts/lib/orchestration/review-providers/code-review.js +203 -0
  36. package/.agents/scripts/lib/orchestration/review-providers/review-provider-factory.js +6 -4
  37. package/.agents/scripts/lib/orchestration/review-providers/security-review.js +3 -2
  38. package/.agents/scripts/lib/orchestration/single-story-close/failed-terminal.js +1 -0
  39. package/.agents/scripts/lib/orchestration/single-story-close/phases/code-review.js +0 -12
  40. package/.agents/scripts/lib/orchestration/single-story-close/phases/confirm-merge.js +135 -20
  41. package/.agents/scripts/lib/orchestration/single-story-close/phases/post-land.js +112 -82
  42. package/.agents/scripts/lib/orchestration/single-story-close/runner.js +72 -5
  43. package/.agents/scripts/lib/orchestration/story-close/phases/review-core.js +12 -87
  44. package/.agents/scripts/lib/orchestration/story-deliver-terminal.js +3 -0
  45. package/.agents/scripts/lib/templates/decomposer-prompts.js +5 -24
  46. package/.agents/scripts/pr-watch-with-update.js +13 -19
  47. package/.agents/scripts/providers/github/issues.js +14 -23
  48. package/.agents/scripts/sync-claude-agents.js +1 -1
  49. package/.agents/workflows/audit-quality.md +42 -7
  50. package/.agents/workflows/helpers/acceptance-self-eval.md +1 -1
  51. package/.agents/workflows/helpers/code-review.md +15 -38
  52. package/.agents/workflows/helpers/deliver-reference.md +4 -2
  53. package/.agents/workflows/helpers/deliver-story.md +3 -0
  54. package/.agents/workflows/helpers/plan-reference.md +9 -8
  55. package/.agents/workflows/mandrel-deliver.md +2 -1
  56. package/.agents/workflows/mandrel-plan.md +10 -7
  57. package/.agents/workflows/mandrel-update.md +5 -3
  58. package/docs/CHANGELOG.md +38 -0
  59. package/lib/cli/claude-code-version.js +73 -0
  60. package/lib/cli/doctor.js +2 -2
  61. package/lib/cli/registry.js +9 -0
  62. package/lib/cli/uninstall.js +37 -9
  63. package/lib/migrations/index.js +2 -0
  64. package/lib/migrations/steps/2.65.0-fold-claude-md-into-agents-md.js +38 -0
  65. package/package.json +2 -1
  66. package/.agents/scripts/lib/audit-suite/lens-diff-floor.js +0 -99
  67. package/.agents/scripts/lib/audit-suite/runner.js +0 -205
  68. package/.agents/scripts/lib/audit-suite/substitutions.js +0 -96
  69. package/.agents/scripts/lib/audit-suite/workflow-loader.js +0 -37
  70. package/.agents/scripts/lib/orchestration/story-close/phases/local-lens-review.js +0 -234
@@ -11,6 +11,12 @@ import path from 'node:path';
11
11
  import { pathToFileURL } from 'node:url';
12
12
  import { isCommandExcluded } from '../command-header.js';
13
13
  import { detectPackageManager as detectPm } from '../detect-package-manager.js';
14
+ import {
15
+ SYSTEM_PROMPT_BLOCK,
16
+ SYSTEM_PROMPT_ENTRY_DOC,
17
+ SYSTEM_PROMPT_IMPORT,
18
+ wireEntryDoc,
19
+ } from './agents-md-fold.js';
14
20
  import { LEDGER_RELATIVE_PATH } from './install-ledger.js';
15
21
  import { ensureIssueForms } from './issue-forms-template.js';
16
22
  import { PHASE_GROUPS } from './manifest.js';
@@ -23,17 +29,10 @@ export const SYNC_AGENTS_COMMAND = 'node .agents/scripts/sync-claude-agents.js';
23
29
 
24
30
  export const BOOTSTRAP_COMMAND = 'node .agents/scripts/bootstrap.js';
25
31
 
26
- /** `CLAUDE.md` wiring keys idempotence off this exact import path. */
27
- export const SYSTEM_PROMPT_IMPORT = '@.agents/instructions.md';
32
+ export { SYSTEM_PROMPT_BLOCK, SYSTEM_PROMPT_IMPORT };
28
33
 
29
- export const SYSTEM_PROMPT_BLOCK = `## System Prompt
30
-
31
- ${SYSTEM_PROMPT_IMPORT}
32
- `;
33
-
34
- export const SYSTEM_PROMPT_CLAUDE_MD = `# Agent Protocols
35
-
36
- ${SYSTEM_PROMPT_BLOCK}`;
34
+ /** Install template for a fresh AGENTS.md (also the legacy CLAUDE.md one). */
35
+ export const SYSTEM_PROMPT_AGENTS_MD = SYSTEM_PROMPT_ENTRY_DOC;
37
36
 
38
37
  export const GITIGNORE_BLOCKS = Object.freeze({
39
38
  commands: {
@@ -420,30 +419,15 @@ export function checkParity(ctx) {
420
419
  }
421
420
 
422
421
  /**
423
- * Ensure `CLAUDE.md` imports the system prompt — without it the framework
424
- * never loads on cold start. Creates, appends, or no-ops.
422
+ * Ensure `AGENTS.md` imports the system prompt — without it the framework
423
+ * never loads on cold start. A pre-existing `CLAUDE.md` is folded in first
424
+ * (the host would otherwise read it instead). Creates, appends, or no-ops.
425
425
  *
426
426
  * @param {object} ctx
427
427
  * @param {typeof fs} [ctx.fsImpl]
428
428
  */
429
429
  export function ensureSystemPromptWiring(ctx) {
430
- const { fsImpl = fs } = ctx;
431
- const target = path.join(ctx.projectRoot, 'CLAUDE.md');
432
- if (!fsImpl.existsSync(target)) {
433
- fsImpl.writeFileSync(target, SYSTEM_PROMPT_CLAUDE_MD, 'utf8');
434
- return { action: 'created', path: target };
435
- }
436
- const existing = fsImpl.readFileSync(target, 'utf8');
437
- if (existing.includes(SYSTEM_PROMPT_IMPORT)) {
438
- return { action: 'already-present', path: target };
439
- }
440
- const separator = existing.length > 0 && !existing.endsWith('\n') ? '\n' : '';
441
- fsImpl.writeFileSync(
442
- target,
443
- `${existing}${separator}\n${SYSTEM_PROMPT_BLOCK}`,
444
- 'utf8',
445
- );
446
- return { action: 'appended', path: target };
430
+ return wireEntryDoc(ctx.projectRoot, ctx.fsImpl);
447
431
  }
448
432
 
449
433
  /**
@@ -0,0 +1,13 @@
1
+ /**
2
+ * The one default review chain: the factory's unset/empty fallback and the
3
+ * runtime schema's declared default. `code-review` is `optional` so hosts
4
+ * without the `claude` CLI close on `native` alone.
5
+ */
6
+ export const DEFAULT_REVIEW_PROVIDERS = Object.freeze([
7
+ Object.freeze({ name: 'native' }),
8
+ Object.freeze({
9
+ name: 'code-review',
10
+ scopes: Object.freeze(['story']),
11
+ optional: true,
12
+ }),
13
+ ]);
@@ -140,7 +140,7 @@ const WORKTREE_ISOLATION_SCHEMA = {
140
140
  const MERGE_WATCH_SCHEMA = {
141
141
  type: 'object',
142
142
  description:
143
- "Knobs consumed by the close-and-land merge wait (Story #4543). `mode` (Story #4698) selects the close-time merge posture. `maxWaitSeconds` bounds ONE invocation of the merge wait and its expiry returns a resumable `pending` terminal with no label mutation; `maxBudgetSeconds` bounds the CUMULATIVE wait across resumes (anchored at the PR's createdAt, so a resume does not restart the clock) and exhausting it is the genuine give-up that classifies and blocks. The 30s poll cadence and the cap of 3 behind-the-base updates are fixed.",
143
+ "Knobs consumed by the close-and-land merge wait (Story #4543). `mode` (Story #4698) selects the close-time merge posture. `maxWaitSeconds` bounds ONE invocation of the merge wait and its expiry returns a resumable `pending` terminal with no label mutation; `maxBudgetSeconds` bounds the CUMULATIVE wait across resumes (anchored at the PR's createdAt, so a resume does not restart the clock) and exhausting it is the genuine give-up that classifies and blocks. The poll cadence is internal (at most 30s while checks run, at most 10s once they are green and the PR is unmerged); it and the cap of 3 behind-the-base updates are not configurable.",
144
144
  properties: {
145
145
  mode: {
146
146
  type: 'string',
@@ -173,7 +173,7 @@ const ROUTING_SCHEMA = {
173
173
  roleScopedAgents: {
174
174
  type: 'boolean',
175
175
  description:
176
- 'Epic #4478 (M7-B). Kill-switch for the role-scoped boot contexts. When true (default), a converted delivery spawn (`story-worker`, `acceptance-critic`) boots on its own `.claude/agents/<role>.md` system prompt instead of re-paying the full CLAUDE.md @-import closure. When false, every converted spawn falls back to `subagent_type: general-purpose` — the instant, code-rollback-free per-consumer revert, and the universal escape for hosts that ignore `.claude/agents/`. The fallback is the full-closure agent that ran before M7-B, so flipping it off never drops a gate.',
176
+ 'Epic #4478 (M7-B). Kill-switch for the role-scoped boot contexts. When true (default), a converted delivery spawn (`story-worker`, `acceptance-critic`) boots on its own `.claude/agents/<role>.md` system prompt instead of re-paying the full entry-doc (AGENTS.md or CLAUDE.md) @-import closure. When false, every converted spawn falls back to `subagent_type: general-purpose` — the instant, code-rollback-free per-consumer revert, and the universal escape for hosts that ignore `.claude/agents/`. The fallback is the full-closure agent that ran before M7-B, so flipping it off never drops a gate.',
177
177
  default: DELIVERY_ROUTING_DEFAULTS.roleScopedAgents,
178
178
  },
179
179
  ceremonyProfile: {
@@ -4,6 +4,7 @@
4
4
  // live in `config/gates/`.
5
5
 
6
6
  import { GATES_SCHEMA } from './config/gates/index.js';
7
+ import { DEFAULT_REVIEW_PROVIDERS } from './config/review-chain-default.js';
7
8
  import { DEFAULT_CODE_REVIEW } from './config/runners.js';
8
9
 
9
10
  const AUTO_REFRESH_SCHEMA = {
@@ -80,9 +81,15 @@ export const CODE_REVIEW_SCHEMA = {
80
81
  properties: {
81
82
  name: {
82
83
  type: 'string',
83
- enum: ['native', 'codex', 'security-review', 'ultrareview'],
84
+ enum: [
85
+ 'native',
86
+ 'code-review',
87
+ 'codex',
88
+ 'security-review',
89
+ 'ultrareview',
90
+ ],
84
91
  description:
85
- 'Registered provider key. Inline: native, codex, security-review. Manual-prompt: ultrareview.',
92
+ 'Registered provider key. Inline: native, code-review, codex, security-review. Manual-prompt: ultrareview.',
86
93
  },
87
94
  scopes: {
88
95
  type: 'array',
@@ -125,17 +132,8 @@ export const CODE_REVIEW_SCHEMA = {
125
132
  additionalProperties: false,
126
133
  },
127
134
  description:
128
- 'Review-provider chain (Story #2871). When unset or empty, defaults to [{ name: "native" }]. The orchestrator iterates inline entries in declaration order and merges their Finding[] before posting one structured comment; manual-prompt entries (e.g. ultrareview) contribute a trailing \'Manual review suggestions\' section. Selecting an adapter whose probe fails hard-fails at factory construction unless declared `optional: true` in the chain.',
129
- default: [
130
- { name: 'native' },
131
- { name: 'security-review', scopes: ['story'], optional: true },
132
- {
133
- name: 'ultrareview',
134
- scopes: ['story'],
135
- manualPrompt: true,
136
- when: { label: 'risk::high' },
137
- },
138
- ],
135
+ "Review-provider chain (Story #2871). When unset or empty, falls back to this default: `native` (scoped lint + MI) then an optional story-scoped `code-review` — a low-effort `claude --print` bug review whose every finding is critical and halts close before auto-merge; hosts without the `claude` CLI skip it. `security-review` and `ultrareview` are opt-in. The orchestrator iterates inline entries in declaration order and merges their Finding[] before posting one structured comment; manual-prompt entries (e.g. ultrareview) contribute a trailing 'Manual review suggestions' section. Selecting an adapter whose probe fails hard-fails at factory construction unless declared `optional: true` in the chain.",
136
+ default: DEFAULT_REVIEW_PROVIDERS,
139
137
  },
140
138
  autoFixSeverity: {
141
139
  type: 'string',
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Doc-tier resolver: partition the repo's docs into read-tiers with byte
3
- * sizes for the context-budget ratchet (`alwaysLoaded` = CLAUDE.md's
4
- * `@`-import closure; `agentBoot` and `workflowOnDemand` are recorded, not
3
+ * sizes for the context-budget ratchet (`alwaysLoaded` = the host entry
4
+ * doc's `@`-import closure; `agentBoot` and `workflowOnDemand` are recorded, not
5
5
  * gated). A path lives only in its highest tier. Emits paths and byte
6
6
  * counts, never file contents.
7
7
  */
@@ -11,9 +11,27 @@ import path from 'node:path';
11
11
  import { resolveWorkflowClosures } from './workflow-closure.js';
12
12
 
13
13
  /**
14
- * @type {string}
14
+ * Claude Code's project-root entry precedence: it reads `CLAUDE.md` when
15
+ * present and falls back to `AGENTS.md` only when `CLAUDE.md` is absent.
16
+ *
17
+ * @type {string[]}
18
+ */
19
+ const ENTRY_DOC_PRECEDENCE = ['CLAUDE.md', 'AGENTS.md'];
20
+
21
+ /**
22
+ * The root entry doc the host loads, or null when neither exists.
23
+ *
24
+ * @param {string} root
25
+ * @param {{ fs?: FsLike }} [opts]
26
+ * @returns {string | null}
15
27
  */
16
- const ENTRY_DOC = 'CLAUDE.md';
28
+ function resolveEntryDoc(root, { fs = nodeFs } = {}) {
29
+ return (
30
+ ENTRY_DOC_PRECEDENCE.find((name) =>
31
+ fs.existsSync(path.resolve(root, name)),
32
+ ) ?? null
33
+ );
34
+ }
17
35
 
18
36
  /**
19
37
  * @type {string[]}
@@ -89,8 +107,9 @@ function fileEntry(root, rel, fs) {
89
107
  * @returns {Array<{ path: string, bytes: number }>}
90
108
  */
91
109
  export function resolveAlwaysLoadedClosure(root, { fs = nodeFs } = {}) {
92
- const entryAbs = path.resolve(root, ENTRY_DOC);
93
- if (!fs.existsSync(entryAbs)) return [];
110
+ const entry = resolveEntryDoc(root, { fs });
111
+ if (entry === null) return [];
112
+ const entryAbs = path.resolve(root, entry);
94
113
 
95
114
  const visited = new Set();
96
115
  const entries = new Map();