create-byan-agent 2.23.0 → 2.26.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 (172) hide show
  1. package/CHANGELOG.md +230 -0
  2. package/README.md +9 -12
  3. package/install/bin/create-byan-agent-v2.js +29 -169
  4. package/install/lib/agent-generator.js +5 -5
  5. package/install/lib/byan-web-integration.js +1 -1
  6. package/install/lib/claude-native-setup.js +1 -1
  7. package/install/lib/phase2-chat.js +3 -10
  8. package/install/lib/platforms/claude-code.js +2 -2
  9. package/install/lib/platforms/index.js +0 -2
  10. package/install/lib/project-agents-generator.js +3 -3
  11. package/install/lib/staging-consent.js +3 -3
  12. package/install/lib/subagent-generator.js +3 -3
  13. package/install/lib/yanstaller/agent-launcher.js +1 -27
  14. package/install/lib/yanstaller/detector.js +4 -4
  15. package/install/lib/yanstaller/installer.js +0 -2
  16. package/install/lib/yanstaller/interviewer.js +1 -1
  17. package/install/lib/yanstaller/platform-selector.js +1 -13
  18. package/install/package.json +1 -1
  19. package/install/src/byan-v2/context/session-state.js +2 -2
  20. package/install/src/byan-v2/index.js +2 -6
  21. package/install/src/byan-v2/orchestrator/generation-state.js +4 -4
  22. package/install/src/webui/api.js +0 -2
  23. package/install/src/webui/chat/bridge.js +1 -13
  24. package/install/src/webui/chat/cli-detector.js +0 -23
  25. package/install/src/webui/public/app.js +1 -3
  26. package/install/src/webui/public/chat.html +0 -2
  27. package/install/src/webui/public/chat.js +0 -1
  28. package/install/src/webui/public/index.html +2 -2
  29. package/install/templates/.claude/CLAUDE.md +13 -2
  30. package/install/templates/.claude/agents/bmad-byan.md +1 -1
  31. package/install/templates/.claude/hooks/autobench-stop-guard.js +286 -0
  32. package/install/templates/.claude/hooks/drain-advisory.js +85 -0
  33. package/install/templates/.claude/hooks/fact-check-absolutes.js +1 -61
  34. package/install/templates/.claude/hooks/fact-check-claims.js +69 -0
  35. package/install/templates/.claude/hooks/fd-response-check.js +37 -46
  36. package/install/templates/.claude/hooks/inject-soul.js +64 -25
  37. package/install/templates/.claude/hooks/leantime-fd-sync.js +216 -0
  38. package/install/templates/.claude/hooks/lib/autobench-config.json +81 -0
  39. package/install/templates/.claude/hooks/lib/autobench-fc-enrich.js +251 -0
  40. package/install/templates/.claude/hooks/lib/autobench-ledger-report.js +253 -0
  41. package/install/templates/.claude/hooks/lib/autobench-runtime.js +199 -0
  42. package/install/templates/.claude/hooks/lib/fact-check-core.js +69 -0
  43. package/install/templates/.claude/hooks/lib/failure-detector.js +18 -4
  44. package/install/templates/.claude/hooks/lib/transcript-read.js +137 -0
  45. package/install/templates/.claude/hooks/soul-memory-check.js +49 -25
  46. package/install/templates/.claude/hooks/soul-memory-triggers.js +27 -8
  47. package/install/templates/.claude/hooks/stage-to-byan.js +25 -7
  48. package/install/templates/.claude/hooks/strict-stop-guard.js +4 -16
  49. package/install/templates/.claude/rules/benchmark.md +251 -0
  50. package/install/templates/.claude/rules/byan-agents.md +0 -1
  51. package/install/templates/.claude/rules/byan-api.md +64 -0
  52. package/install/templates/.claude/rules/fact-check.md +1 -1
  53. package/install/templates/.claude/rules/strict-mode.md +10 -9
  54. package/install/templates/.claude/settings.json +16 -0
  55. package/install/templates/.claude/skills/byan-benchmark/SKILL.md +159 -0
  56. package/install/templates/.claude/skills/byan-byan/SKILL.md +73 -12
  57. package/install/templates/.claude/skills/byan-fact-check/SKILL.md +1 -1
  58. package/install/templates/.claude/skills/byan-hermes-dispatch/SKILL.md +5 -6
  59. package/install/templates/.claude/skills/byan-insight/SKILL.md +56 -0
  60. package/install/templates/.claude/skills/byan-orchestrate/SKILL.md +11 -3
  61. package/install/templates/.claude/skills/byan-strict/SKILL.md +4 -1
  62. package/install/templates/.claude/workflows/INDEX.md +2 -1
  63. package/install/templates/.claude/workflows/byan-benchmark.js +328 -0
  64. package/install/templates/.claude/workflows/check-implementation-readiness.js +1 -1
  65. package/install/templates/_byan/_config/agent-manifest.csv +1 -1
  66. package/install/templates/_byan/_config/autobench.yaml +510 -0
  67. package/install/templates/_byan/_config/strict-mode.yaml +9 -3
  68. package/install/templates/_byan/_config/workflow-manifest.csv +1 -0
  69. package/install/templates/_byan/agent/byan/byan.md +1 -3
  70. package/install/templates/_byan/agent/byan-flat/byan.md +1 -3
  71. package/install/templates/_byan/agent/byan-test/byan-test.md +2 -2
  72. package/install/templates/_byan/agent/byan-test-flat/byan-test.md +2 -2
  73. package/install/templates/_byan/agent/byan.optimized/byan.optimized.md +2 -2
  74. package/install/templates/_byan/agent/byan.optimized-v2/byan.optimized-v2.md +2 -2
  75. package/install/templates/_byan/agent/claude/claude.md +0 -2
  76. package/install/templates/_byan/agent/codex/codex.md +0 -2
  77. package/install/templates/_byan/agent/rachid/rachid.md +2 -10
  78. package/install/templates/_byan/agent/rachid-flat/rachid.md +2 -11
  79. package/install/templates/_byan/agent/turbo-whisper/turbo-whisper.md +2 -5
  80. package/install/templates/_byan/agent/turbo-whisper-integration/turbo-whisper-integration.md +5 -13
  81. package/install/templates/_byan/agent/yanstaller/yanstaller.md +2 -24
  82. package/install/templates/_byan/config.yaml +0 -1
  83. package/install/templates/_byan/core/activation/soul-activation.md +3 -3
  84. package/install/templates/_byan/mcp/byan-mcp-server/bin/byan-insight-digest.js +31 -0
  85. package/install/templates/_byan/mcp/byan-mcp-server/bin/byan-sync-rules.js +20 -4
  86. package/install/templates/_byan/mcp/byan-mcp-server/lib/advisory-autofeed.js +96 -0
  87. package/install/templates/_byan/mcp/byan-mcp-server/lib/index-generator.js +1 -1
  88. package/install/templates/_byan/mcp/byan-mcp-server/lib/insight-harvest.js +220 -0
  89. package/install/templates/_byan/mcp/byan-mcp-server/lib/kanban.js +6 -3
  90. package/install/templates/_byan/mcp/byan-mcp-server/lib/leantime-fd-core.js +205 -0
  91. package/install/templates/_byan/mcp/byan-mcp-server/lib/leantime-sync.js +415 -0
  92. package/install/templates/_byan/mcp/byan-mcp-server/lib/outcome-buffer.js +64 -0
  93. package/install/templates/_byan/mcp/byan-mcp-server/lib/precommit-gate.js +1 -1
  94. package/install/templates/_byan/mcp/byan-mcp-server/lib/strict-activation.js +1 -1
  95. package/install/templates/_byan/mcp/byan-mcp-server/lib/strict-mode.js +8 -0
  96. package/install/templates/_byan/mcp/byan-mcp-server/lib/sync-rules.js +172 -23
  97. package/install/templates/_byan/mcp/byan-mcp-server/lib/workflows-generator.js +1 -0
  98. package/install/templates/_byan/mcp/byan-mcp-server/server.js +262 -81
  99. package/install/templates/_byan/worker/launchers/README.md +4 -24
  100. package/install/templates/_byan/worker/workers.md +8 -9
  101. package/install/templates/_byan/workflow/simple/bmb/byan-benchmark/workflow.md +86 -0
  102. package/install/templates/_byan/workflow/simple/byan/feature-workflow.md +2 -2
  103. package/install/templates/docs/leantime-integration.md +160 -0
  104. package/package.json +3 -7
  105. package/src/byan-v2/context/session-state.js +2 -2
  106. package/src/byan-v2/generation/mantra-validator.js +3 -3
  107. package/src/byan-v2/index.js +1 -5
  108. package/src/byan-v2/integration/voice-integration.js +1 -1
  109. package/src/byan-v2/orchestrator/generation-state.js +4 -4
  110. package/src/loadbalancer/loadbalancer.js +1 -1
  111. package/src/staging/staging.js +20 -6
  112. package/install/bin/build-copilot-stubs.js +0 -138
  113. package/install/lib/platforms/copilot-cli.js +0 -123
  114. package/install/lib/platforms/vscode.js +0 -51
  115. package/install/src/byan-v2/context/copilot-context.js +0 -79
  116. package/install/src/webui/chat/copilot-adapter.js +0 -68
  117. package/install/templates/.claude/agents/bmad-marc.md +0 -25
  118. package/install/templates/.claude/skills/byan-marc/SKILL.md +0 -20
  119. package/install/templates/.github/agents/bmad-agent-bmad-master.md +0 -16
  120. package/install/templates/.github/agents/bmad-agent-bmb-agent-builder.md +0 -16
  121. package/install/templates/.github/agents/bmad-agent-bmb-module-builder.md +0 -16
  122. package/install/templates/.github/agents/bmad-agent-bmb-workflow-builder.md +0 -16
  123. package/install/templates/.github/agents/bmad-agent-bmm-analyst.md +0 -16
  124. package/install/templates/.github/agents/bmad-agent-bmm-architect.md +0 -16
  125. package/install/templates/.github/agents/bmad-agent-bmm-dev.md +0 -16
  126. package/install/templates/.github/agents/bmad-agent-bmm-pm.md +0 -16
  127. package/install/templates/.github/agents/bmad-agent-bmm-quick-flow-solo-dev.md +0 -16
  128. package/install/templates/.github/agents/bmad-agent-bmm-quinn.md +0 -16
  129. package/install/templates/.github/agents/bmad-agent-bmm-sm.md +0 -16
  130. package/install/templates/.github/agents/bmad-agent-bmm-tech-writer.md +0 -16
  131. package/install/templates/.github/agents/bmad-agent-bmm-ux-designer.md +0 -16
  132. package/install/templates/.github/agents/bmad-agent-byan-test.md +0 -33
  133. package/install/templates/.github/agents/bmad-agent-byan-v2.md +0 -44
  134. package/install/templates/.github/agents/bmad-agent-byan.md +0 -1062
  135. package/install/templates/.github/agents/bmad-agent-carmack.md +0 -14
  136. package/install/templates/.github/agents/bmad-agent-cis-brainstorming-coach.md +0 -16
  137. package/install/templates/.github/agents/bmad-agent-cis-creative-problem-solver.md +0 -16
  138. package/install/templates/.github/agents/bmad-agent-cis-design-thinking-coach.md +0 -16
  139. package/install/templates/.github/agents/bmad-agent-cis-innovation-strategist.md +0 -16
  140. package/install/templates/.github/agents/bmad-agent-cis-presentation-master.md +0 -16
  141. package/install/templates/.github/agents/bmad-agent-cis-storyteller.md +0 -16
  142. package/install/templates/.github/agents/bmad-agent-claude.md +0 -49
  143. package/install/templates/.github/agents/bmad-agent-codex.md +0 -49
  144. package/install/templates/.github/agents/bmad-agent-drawio.md +0 -45
  145. package/install/templates/.github/agents/bmad-agent-fact-checker.md +0 -16
  146. package/install/templates/.github/agents/bmad-agent-forgeron.md +0 -15
  147. package/install/templates/.github/agents/bmad-agent-jimmy.md +0 -15
  148. package/install/templates/.github/agents/bmad-agent-marc.md +0 -49
  149. package/install/templates/.github/agents/bmad-agent-mike.md +0 -15
  150. package/install/templates/.github/agents/bmad-agent-patnote.md +0 -49
  151. package/install/templates/.github/agents/bmad-agent-rachid.md +0 -48
  152. package/install/templates/.github/agents/bmad-agent-skeptic.md +0 -16
  153. package/install/templates/.github/agents/bmad-agent-tao.md +0 -14
  154. package/install/templates/.github/agents/bmad-agent-tea-tea.md +0 -16
  155. package/install/templates/.github/agents/bmad-agent-test-dynamic.md +0 -22
  156. package/install/templates/.github/agents/bmad-agent-yanstaller-interview.md +0 -50
  157. package/install/templates/.github/agents/bmad-agent-yanstaller-phase2.md +0 -189
  158. package/install/templates/.github/agents/bmad-agent-yanstaller.md +0 -350
  159. package/install/templates/.github/agents/expert-merise-agile.md +0 -178
  160. package/install/templates/.github/agents/franck.md +0 -379
  161. package/install/templates/.github/agents/hermes.md +0 -575
  162. package/install/templates/.github/extensions/byan-staging/extension.mjs +0 -169
  163. package/install/templates/.github/extensions/byan-staging/package.json +0 -8
  164. package/install/templates/_byan/agent/marc/marc-soul.md +0 -47
  165. package/install/templates/_byan/agent/marc/marc-tao.md +0 -77
  166. package/install/templates/_byan/agent/marc/marc.md +0 -324
  167. package/install/templates/_byan/agent/marc-flat/marc.md +0 -387
  168. package/install/templates/_byan/mcp/byan-mcp-server/lib/copilot.js +0 -148
  169. package/install/templates/_byan/worker/launchers/launch-yanstaller-copilot.md +0 -173
  170. package/install/templates/workers/cost-optimizer.js +0 -169
  171. package/src/byan-v2/context/copilot-context.js +0 -79
  172. package/src/core/dispatcher/execution-router.js +0 -66
@@ -9,7 +9,6 @@ import yaml from 'js-yaml';
9
9
  // - .claude/skills/byan-strict/SKILL.md (owned, full-file)
10
10
  // - .claude/hooks/lib/strict-config.json (owned, full-file)
11
11
  // - AGENTS.md (upsert block, Codex)
12
- // - .github/copilot-instructions.md (upsert block, Copilot)
13
12
  //
14
13
  // Owned files are rewritten wholesale (they carry a generated-by header).
15
14
  // Shared files get a block upserted between BYAN-STRICT markers, leaving the
@@ -19,6 +18,10 @@ const BEGIN = 'BYAN-STRICT:BEGIN';
19
18
  const END = 'BYAN-STRICT:END';
20
19
  const DEFAULT_CONFIG_REL = path.join('_byan', '_config', 'strict-mode.yaml');
21
20
 
21
+ const AUTOBENCH_BEGIN = 'BYAN-AUTOBENCH:BEGIN';
22
+ const AUTOBENCH_END = 'BYAN-AUTOBENCH:END';
23
+ const AUTOBENCH_CONFIG_REL = path.join('_byan', '_config', 'autobench.yaml');
24
+
22
25
  export function resolveRoot(projectRoot) {
23
26
  return projectRoot || process.env.CLAUDE_PROJECT_DIR || process.cwd();
24
27
  }
@@ -39,6 +42,31 @@ export function loadConfig({ projectRoot, configPath } = {}) {
39
42
  return cfg;
40
43
  }
41
44
 
45
+ // Loads and validates the auto-benchmark source of truth. Mirrors loadConfig:
46
+ // throws on a missing file, a non-object parse, an empty mantras list, or a
47
+ // missing doctrine brick — so a malformed YAML fails the generator loudly
48
+ // rather than emitting a half-rendered pointer block.
49
+ export function loadAutobenchConfig({ projectRoot, configPath } = {}) {
50
+ const root = resolveRoot(projectRoot);
51
+ const file = configPath || path.join(root, AUTOBENCH_CONFIG_REL);
52
+ if (!fs.existsSync(file)) {
53
+ throw new Error(`autobench config not found at ${file}`);
54
+ }
55
+ const cfg = yaml.load(fs.readFileSync(file, 'utf8'));
56
+ if (!cfg || typeof cfg !== 'object') {
57
+ throw new Error(`autobench config at ${file} did not parse to an object`);
58
+ }
59
+ if (!Array.isArray(cfg.mantras) || cfg.mantras.length === 0) {
60
+ throw new Error('autobench config must define a non-empty mantras list');
61
+ }
62
+ for (const brick of ['trigger', 'scaler', 'format']) {
63
+ if (!cfg[brick] || typeof cfg[brick] !== 'object') {
64
+ throw new Error(`autobench config must define the '${brick}' brick`);
65
+ }
66
+ }
67
+ return cfg;
68
+ }
69
+
42
70
  // ---------------------------------------------------------------------------
43
71
  // Renderers — pure functions config -> string.
44
72
  // ---------------------------------------------------------------------------
@@ -46,6 +74,9 @@ export function loadConfig({ projectRoot, configPath } = {}) {
46
74
  const GENERATED_NOTE =
47
75
  'Generated by byan-sync-rules from _byan/_config/strict-mode.yaml. Do not hand-edit.';
48
76
 
77
+ const AUTOBENCH_GENERATED_NOTE =
78
+ 'Generated by byan-sync-rules from _byan/_config/autobench.yaml. Do not hand-edit.';
79
+
49
80
  export function renderStrictConfig(cfg) {
50
81
  return {
51
82
  _generated_by: 'byan-sync-rules',
@@ -125,7 +156,10 @@ complete. Downgrading the scope is the failure this mode exists to prevent.
125
156
 
126
157
  1. **Lock the scope** with \`byan_strict_lock_scope\` before building. Provide a
127
158
  verbatim restatement of the request and testable \`acceptanceCriteria\`. The
128
- locked scope is the contract.
159
+ locked scope is the contract. When one technical domain clearly dominates the
160
+ task, also pass \`domain\` (e.g. security, performance, javascript) — a
161
+ successful completion then feeds one VALIDATED tick to the ELO loop. Explicit
162
+ only; omit when no single domain is clear.
129
163
  2. **Build the full scope.** Do not substitute an MVP, a stub, or a simplified
130
164
  version. If a part cannot be done, surface it as a gap — do not cut silently.
131
165
  3. **Self-verify at least ${cfg.self_verify.min_passes} times** with
@@ -160,19 +194,84 @@ Hard mantras:
160
194
  ${mantraLines(cfg)}`;
161
195
  }
162
196
 
163
- export function renderCopilotBlock(cfg) {
164
- // Copilot has no blocking mechanism; this is injection-only guidance.
165
- return `## BYAN Strict Mode
166
-
167
- ${cfg.injection.context_banner.trim()}
168
-
169
- Use the \`byan\` MCP strict tools to lock scope, self-verify (>= ${cfg.self_verify.min_passes} passes),
170
- and complete. The pre-commit gate is the final net: a commit without a fresh,
171
- matching audit token is rejected.
197
+ // Maps the enriched cfg.hooks section to the EXACT runtime shape read by
198
+ // autobench-stop-guard.js. Every key and every {source, flags} pair structure
199
+ // must stay in sync with what compileRegex / hasChoiceLanguage / hasMarker /
200
+ // hasNeverListed / readMarkerFields / escapeHatchActive / ledgerPath consume.
201
+ //
202
+ // This is the function that closes the single-source-of-truth gap: before it
203
+ // existed, autobench-config.json was hand-authored and the YAML toggle
204
+ // (escape_hatch.disabled) was never propagated to the runtime file.
205
+ export function renderAutobenchConfig(cfg) {
206
+ const h = cfg.hooks;
207
+ const mp = h.marker_patterns;
208
+ const mf = h.marker_fields;
209
+ const eh = h.escape_hatch;
172
210
 
173
- Hard mantras:
211
+ return {
212
+ _generated_by: 'byan-sync-rules',
213
+ _note:
214
+ 'Runtime subset read by autobench-stop-guard.js. Edit _byan/_config/autobench.yaml and regenerate; do not hand-edit. Regexes are {source, flags} pairs reconstructed into RegExp at load time.',
215
+ version: cfg.version,
216
+ marker_patterns: {
217
+ any: { source: mp.any.source, flags: mp.any.flags },
218
+ done: { source: mp.done.source, flags: mp.done.flags },
219
+ skip: { source: mp.skip.source, flags: mp.skip.flags },
220
+ },
221
+ marker_fields: {
222
+ g1: { source: mf.g1.source, flags: mf.g1.flags },
223
+ g2: { source: mf.g2.source, flags: mf.g2.flags },
224
+ scope: { source: mf.scope.source, flags: mf.scope.flags },
225
+ },
226
+ never_list: h.never_list.map((entry) => ({ source: entry.source, flags: entry.flags })),
227
+ choice_language: h.choice_language.map((entry) => {
228
+ const out = { source: entry.source, flags: entry.flags };
229
+ // Preserve optional threshold fields only when present; omitting them
230
+ // keeps the config lean and matches the runtime's typeof checks.
231
+ if (typeof entry.min_matches === 'number') out.min_matches = entry.min_matches;
232
+ if (typeof entry.requires_candidates === 'number') out.requires_candidates = entry.requires_candidates;
233
+ return out;
234
+ }),
235
+ candidate_token: { source: h.candidate_token.source, flags: h.candidate_token.flags },
236
+ escape_hatch: {
237
+ // session_flag is read by autobench-runtime.js but not stored in
238
+ // config.json (the runtime hardcodes the path). Carry only the two
239
+ // fields the runtime actually reads from config.json.
240
+ session_flag: eh.session_flag,
241
+ disabled: eh.disabled,
242
+ },
243
+ enforcement: {
244
+ // Disarmed-by-default (approach C): the Stop hook observes and ledgers but
245
+ // does not block until armed. Arming is config-only (armed: true in the
246
+ // YAML); there is no loose flag file, so a stray file cannot silently arm a
247
+ // machine. Defaulting armed to false keeps an older source inert by default.
248
+ armed: Boolean(h.enforcement && h.enforcement.armed === true),
249
+ },
250
+ ledger: {
251
+ path: h.ledger_path,
252
+ },
253
+ banners: {
254
+ stop_block: h.stop_block,
255
+ },
256
+ };
257
+ }
174
258
 
175
- ${mantraLines(cfg)}`;
259
+ // The lean auto-benchmark pointer block. One shared block for both
260
+ // platform files (CLAUDE.md / AGENTS.md): names the
261
+ // feature, states the marker one-liner the agent must emit, and points to the
262
+ // full doctrine. Kept short on purpose — CLAUDE.md stays lean via pointers, and
263
+ // the full rule lives in .claude/rules/benchmark.md (owned, authored elsewhere).
264
+ export function renderAutobenchPointerBlock(cfg) {
265
+ const name = (cfg.name || 'BYAN Auto-Benchmark').trim();
266
+ return `## ${name}
267
+
268
+ Before asking the user to choose between options, benchmark the fork: render
269
+ ONE compact table (Option | <= 4 criteria | Niv + a best-first reco line) when
270
+ both gates hold (>= 2 non-substitutable options diverging on >= 1 weighted
271
+ criterion). Emit the marker verbatim before the table:
272
+ \`<!-- BYAN-BENCH:done g1=<#options> g2=<#divergent-criteria> scope=<internal|external> conf=<assertive|lean> -->\`.
273
+ A confirm, a destructive prompt, or an obvious default is not a fork — emit
274
+ \`<!-- BYAN-BENCH:skip reason=.. -->\` instead. Full doctrine: see @.claude/rules/benchmark.md`;
176
275
  }
177
276
 
178
277
  // ---------------------------------------------------------------------------
@@ -191,11 +290,29 @@ function writeIfChanged(filePath, content) {
191
290
  return existing === null ? 'created' : 'updated';
192
291
  }
193
292
 
293
+ // Escapes a marker string for safe embedding in a RegExp source. Markers are
294
+ // authored as plain identifiers today, but a literal-safe regex keeps the
295
+ // generalized signature robust if a future marker carries a regex metacharacter.
296
+ function escapeRegex(s) {
297
+ return String(s).replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
298
+ }
299
+
194
300
  // Insert or replace a block delimited by HTML-comment markers. Preserves
195
301
  // everything outside the markers. If the file does not exist, creates it with
196
302
  // just the block.
197
- export function upsertBlock({ filePath, block }) {
198
- const wrapped = `<!-- ${BEGIN} (${GENERATED_NOTE}) -->\n${block}\n<!-- ${END} -->`;
303
+ //
304
+ // markers defaults to the module-level STRICT pair so every existing strict
305
+ // callsite keeps working unchanged. Passing a distinct pair (e.g. the
306
+ // AUTOBENCH markers) scopes the replace-regex to that pair only, so a STRICT
307
+ // block and an AUTOBENCH block coexist in one file without clobbering each
308
+ // other.
309
+ export function upsertBlock({
310
+ filePath,
311
+ block,
312
+ markers = { begin: BEGIN, end: END },
313
+ note = GENERATED_NOTE,
314
+ }) {
315
+ const wrapped = `<!-- ${markers.begin} (${note}) -->\n${block}\n<!-- ${markers.end} -->`;
199
316
  const existing = fs.existsSync(filePath) ? fs.readFileSync(filePath, 'utf8') : null;
200
317
 
201
318
  if (existing === null) {
@@ -205,7 +322,7 @@ export function upsertBlock({ filePath, block }) {
205
322
  }
206
323
 
207
324
  const re = new RegExp(
208
- `<!-- ${BEGIN}[\\s\\S]*?${END} -->`,
325
+ `<!-- ${escapeRegex(markers.begin)}[\\s\\S]*?${escapeRegex(markers.end)} -->`,
209
326
  'm'
210
327
  );
211
328
  let next;
@@ -216,7 +333,7 @@ export function upsertBlock({ filePath, block }) {
216
333
  }
217
334
  if (next === existing) return 'unchanged';
218
335
  fs.writeFileSync(filePath, next);
219
- return existing.includes(BEGIN) ? 'updated' : 'appended';
336
+ return existing.includes(markers.begin) ? 'updated' : 'appended';
220
337
  }
221
338
 
222
339
  // ---------------------------------------------------------------------------
@@ -241,12 +358,6 @@ export function syncRules({ projectRoot, configPath } = {}) {
241
358
  const agentsPath = path.join(root, 'AGENTS.md');
242
359
  report['AGENTS.md'] = upsertBlock({ filePath: agentsPath, block: renderAgentsBlock(cfg) });
243
360
 
244
- const copilotPath = path.join(root, '.github', 'copilot-instructions.md');
245
- report['.github/copilot-instructions.md'] = upsertBlock({
246
- filePath: copilotPath,
247
- block: renderCopilotBlock(cfg),
248
- });
249
-
250
361
  const mantrasPath = path.join(root, 'src', 'byan-v2', 'data', 'strict-mantras.json');
251
362
  if (fs.existsSync(path.dirname(mantrasPath))) {
252
363
  report['src/byan-v2/data/strict-mantras.json'] = writeIfChanged(
@@ -258,4 +369,42 @@ export function syncRules({ projectRoot, configPath } = {}) {
258
369
  return report;
259
370
  }
260
371
 
372
+ // Auto-benchmark orchestrator. Kept SEPARATE from syncRules so the strict
373
+ // generator stays untouched and independently testable. Upserts the lean
374
+ // pointer block into the three platform files and writes the runtime config
375
+ // that the Stop hook reads. The config write closes the single-source-of-truth
376
+ // gap: escape_hatch.disabled toggled in the YAML now reaches the runtime file.
377
+ // Returns a {file: action} report like syncRules.
378
+ export function syncAutobench({ projectRoot, configPath } = {}) {
379
+ const root = resolveRoot(projectRoot);
380
+ const cfg = loadAutobenchConfig({ projectRoot: root, configPath });
381
+
382
+ const report = {};
383
+ const block = renderAutobenchPointerBlock(cfg);
384
+ const markers = { begin: AUTOBENCH_BEGIN, end: AUTOBENCH_END };
385
+
386
+ // CLAUDE.md uses the lean pointer convention (.claude/CLAUDE.md holds the
387
+ // other rule pointers: strict, fact-check, ELO). AGENTS.md (Codex) is the
388
+ // other cross-platform mechanism target.
389
+ const targets = {
390
+ '.claude/CLAUDE.md': path.join(root, '.claude', 'CLAUDE.md'),
391
+ 'AGENTS.md': path.join(root, 'AGENTS.md'),
392
+ };
393
+
394
+ for (const [rel, filePath] of Object.entries(targets)) {
395
+ report[rel] = upsertBlock({ filePath, block, markers, note: AUTOBENCH_GENERATED_NOTE });
396
+ }
397
+
398
+ // Write the runtime config that autobench-stop-guard.js reads. Mirrors the
399
+ // strict pattern (syncRules writes strict-config.json from strict-mode.yaml).
400
+ const autobenchCfgPath = path.join(root, '.claude', 'hooks', 'lib', 'autobench-config.json');
401
+ report['.claude/hooks/lib/autobench-config.json'] = writeIfChanged(
402
+ autobenchCfgPath,
403
+ JSON.stringify(renderAutobenchConfig(cfg), null, 2) + '\n'
404
+ );
405
+
406
+ return report;
407
+ }
408
+
261
409
  export const MARKERS = { BEGIN, END };
410
+ export const AUTOBENCH_MARKERS = { BEGIN: AUTOBENCH_BEGIN, END: AUTOBENCH_END };
@@ -47,6 +47,7 @@ export const PORTABLE = {
47
47
  'create-excalidraw-dataflow',
48
48
  'create-excalidraw-flowchart',
49
49
  'create-excalidraw-wireframe',
50
+ 'byan-benchmark',
50
51
  ],
51
52
  };
52
53