@event4u/agent-config 9.28.0 → 9.30.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 (209) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/AGENTS.md +6 -6
  3. package/CHANGELOG.md +172 -5
  4. package/README.md +2 -1
  5. package/agents/templates/.ai-council.yml.example +55 -24
  6. package/dist/agent-src/commands/analyze/inbox.md +22 -1
  7. package/dist/agent-src/commands/cost/report.md +2 -2
  8. package/dist/agent-src/commands/explain-run.md +31 -1
  9. package/dist/agent-src/commands/team/adversarial.md +8 -7
  10. package/dist/agent-src/commands/team/delegate.md +14 -12
  11. package/dist/agent-src/commands/team/review.md +9 -8
  12. package/dist/agent-src/commands/team/status.md +9 -8
  13. package/dist/agent-src/commands/team.md +29 -19
  14. package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +88 -2
  15. package/dist/agent-src/contexts/execution/auto-orchestration-activation.md +29 -21
  16. package/dist/agent-src/contexts/execution/host-capability-manifest.md +26 -15
  17. package/dist/agent-src/contexts/execution/orchestration-telemetry.md +22 -1
  18. package/dist/agent-src/contexts/execution/roadmap-process-loop.md +17 -0
  19. package/dist/agent-src/contexts/execution/subagent-response-contract.md +65 -1
  20. package/dist/agent-src/contexts/execution/subagent-routing.md +13 -11
  21. package/dist/agent-src/contexts/execution/subagent-spawn-contract.md +25 -0
  22. package/dist/agent-src/contexts/execution/subagent-steering.md +6 -3
  23. package/dist/agent-src/rules/delegation-policy.md +11 -7
  24. package/dist/agent-src/rules/preservation-guard.md +9 -0
  25. package/dist/agent-src/rules/settings-ask-protocol.md +8 -7
  26. package/dist/agent-src/rules/token-budget-discipline.md +1 -1
  27. package/dist/agent-src/scripts/roadmap_gates.ts +312 -0
  28. package/dist/agent-src/scripts/update_roadmap_progress.ts +72 -4
  29. package/dist/agent-src/skills/forensics-report/SKILL.md +114 -0
  30. package/dist/agent-src/skills/forensics-report/evals/triggers.json +17 -0
  31. package/dist/agent-src/skills/premortem/SKILL.md +30 -1
  32. package/dist/agent-src/skills/reasoning-orchestrator/SKILL.md +2 -1
  33. package/dist/agent-src/skills/subagent-orchestration/SKILL.md +17 -5
  34. package/dist/agent-src/skills/subagent-orchestration/schemas/subagent-status.json +61 -3
  35. package/dist/agent-src/skills/test-case-discovery/SKILL.md +1 -1
  36. package/dist/agent-src/templates/AGENTS.md +4 -4
  37. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  38. package/dist/agent-src/templates/roadmaps.md +23 -0
  39. package/dist/cli/registry.js +2 -0
  40. package/dist/cli/registry.js.map +1 -1
  41. package/dist/cli-delegate/{chunk-22GCIJ2O.js → chunk-66OVWGB5.js} +1 -1
  42. package/dist/cli-delegate/{chunk-7OMQCH4V.js → chunk-BTJNRUX3.js} +22 -35
  43. package/dist/cli-delegate/{chunk-DVRS2KVR.js → chunk-DDUNNFYX.js} +24 -17
  44. package/dist/cli-delegate/{chunk-PQSAQKHW.js → chunk-EQY4FLJB.js} +3 -3
  45. package/dist/cli-delegate/{chunk-2BE5I2MN.js → chunk-IYTGIG2Y.js} +155 -91
  46. package/dist/cli-delegate/{chunk-GB2FSUEE.js → chunk-LCFJIQ4J.js} +32 -0
  47. package/dist/cli-delegate/{chunk-VSYT7OHO.js → chunk-LVRYBKTI.js} +31 -2
  48. package/dist/cli-delegate/chunk-MMJL4TIX.js +18 -0
  49. package/dist/cli-delegate/{chunk-JXARCGVN.js → chunk-MP3JT3IU.js} +1 -1
  50. package/dist/cli-delegate/chunk-O3CO5BFB.js +161 -0
  51. package/dist/cli-delegate/{chunk-REKCMYOU.js → chunk-PFBV6XRT.js} +36 -20
  52. package/dist/cli-delegate/chunk-RVGBH4XK.js +142 -0
  53. package/dist/cli-delegate/cmd_analyze_session.js +1 -1
  54. package/dist/cli-delegate/cmd_brand_status.js +1 -1
  55. package/dist/cli-delegate/cmd_conformance.js +2803 -137
  56. package/dist/cli-delegate/cmd_doctor.js +10 -5
  57. package/dist/cli-delegate/cmd_explain.js +2 -2
  58. package/dist/cli-delegate/cmd_export.js +4 -4
  59. package/dist/cli-delegate/cmd_handoff.js +88 -8
  60. package/dist/cli-delegate/cmd_mcp_available.js +1 -1
  61. package/dist/cli-delegate/cmd_migrate.js +2 -2
  62. package/dist/cli-delegate/cmd_packs_active.js +2 -2
  63. package/dist/cli-delegate/cmd_prune.js +4 -4
  64. package/dist/cli-delegate/cmd_route_audit.js +3 -2
  65. package/dist/cli-delegate/cmd_route_explain.js +1 -1
  66. package/dist/cli-delegate/cmd_session_recycle.js +177 -0
  67. package/dist/cli-delegate/cmd_settings_get.js +2 -8
  68. package/dist/cli-delegate/cmd_settings_migrate.js +4 -4
  69. package/dist/cli-delegate/cmd_settings_set.js +2 -2
  70. package/dist/cli-delegate/cmd_sync.js +4 -4
  71. package/dist/cli-delegate/cmd_uninstall.js +4 -4
  72. package/dist/cli-delegate/cmd_update.js +1 -1
  73. package/dist/cli-delegate/cmd_upgrade.js +1 -1
  74. package/dist/cli-delegate/cmd_validate.js +4 -4
  75. package/dist/cli-delegate/cmd_versions.js +1 -1
  76. package/dist/discovery/deprecation-report.md +1 -1
  77. package/dist/discovery/discovery-manifest.json +72 -23
  78. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  79. package/dist/discovery/discovery-manifest.summary.md +3 -2
  80. package/dist/discovery/orphan-report.md +1 -1
  81. package/dist/discovery/packs.json +39 -2
  82. package/dist/discovery/trust-report.md +2 -2
  83. package/dist/discovery/workspaces.json +12 -4
  84. package/dist/hooks/dispatch.js +2278 -611
  85. package/dist/install/install.mjs +56 -17
  86. package/dist/mcp/registry-manifest.json +3 -3
  87. package/dist/mcp/server.json +2 -2
  88. package/dist/mcp/server.mjs +4122 -699
  89. package/dist/router.json +1 -1
  90. package/dist/scripts/_lib/agent_settings.js +54 -0
  91. package/dist/scripts/_lib/agent_settings.js.map +1 -1
  92. package/dist/scripts/condense.js +147 -2
  93. package/dist/scripts/condense.js.map +1 -1
  94. package/dist/server/schemas/settings.js +12 -7
  95. package/dist/server/schemas/settings.js.map +1 -1
  96. package/dist/shared/settingsCarveOut.js +0 -9
  97. package/dist/shared/settingsCarveOut.js.map +1 -1
  98. package/dist/shared/settingsClasses.js +11 -9
  99. package/dist/shared/settingsClasses.js.map +1 -1
  100. package/dist/ui/assets/index-B5qGYOJo.js +26 -0
  101. package/dist/ui/assets/index-B5qGYOJo.js.map +1 -0
  102. package/dist/ui/index.html +1 -1
  103. package/docs/contracts/settings-classes.md +58 -12
  104. package/package.json +1 -1
  105. package/src/agent-src/scripts/roadmap_gates.ts +312 -0
  106. package/src/agent-src/scripts/update_roadmap_progress.ts +72 -4
  107. package/src/agent-src/templates/AGENTS.md +4 -4
  108. package/src/config/agent-settings.template.yml +88 -66
  109. package/src/config/discovery/packs.yml +11 -0
  110. package/src/config/discovery/workspaces.yml +1 -1
  111. package/src/config/dispatch-economy-metrics.json +61 -0
  112. package/src/config/evaluator-budgets.json +4 -4
  113. package/src/config/gate-violation-baselines.json +3 -3
  114. package/src/config/hook-token-budget.json +91 -0
  115. package/src/config/recycle-threshold-budget.json +12 -0
  116. package/src/config/rule-enforcement-baseline.json +86 -0
  117. package/src/scripts/_cli/cmd_conformance.ts +31 -44
  118. package/src/scripts/_cli/cmd_doctor.ts +65 -48
  119. package/src/scripts/_cli/cmd_session_recycle.ts +226 -0
  120. package/src/scripts/_dispatch.bash +23 -0
  121. package/src/scripts/_lib/agent_settings.ts +58 -0
  122. package/src/scripts/_lib/auto_dispatch.corpus.test.ts +1 -1
  123. package/src/scripts/_lib/auto_dispatch.ts +23 -18
  124. package/src/scripts/_lib/capsule_trigger.ts +124 -0
  125. package/src/scripts/_lib/host_capability.ts +63 -6
  126. package/src/scripts/_lib/judgment_ladder.ts +634 -0
  127. package/src/scripts/_lib/orchestration_gate.ts +8 -0
  128. package/src/scripts/_lib/orchestration_record.ts +78 -10
  129. package/src/scripts/_lib/orchestration_savings.ts +1 -1
  130. package/src/scripts/_lib/recycle_envelope_paths.ts +35 -0
  131. package/src/scripts/_lib/self_repair.ts +354 -13
  132. package/src/scripts/_lib/self_repair_store.ts +28 -0
  133. package/src/scripts/_lib/session_eol.ts +230 -0
  134. package/src/scripts/_lib/session_role.ts +42 -0
  135. package/src/scripts/_lib/subagent_capsule.ts +341 -0
  136. package/src/scripts/_lib/subagent_response.ts +94 -0
  137. package/src/scripts/_lib/subagent_spawn.ts +13 -0
  138. package/src/scripts/_lib/subagent_steering.ts +9 -4
  139. package/src/scripts/_lib/tier_budget_routing.ts +6 -1
  140. package/src/scripts/_lib/worker_budget.ts +37 -2
  141. package/src/scripts/ai_council/clients.ts +126 -55
  142. package/src/scripts/ai_council/config.ts +94 -6
  143. package/src/scripts/ai_council/handoff.ts +113 -0
  144. package/src/scripts/ai_council/modes.ts +19 -4
  145. package/src/scripts/ai_council/orchestrator.ts +105 -0
  146. package/src/scripts/ai_council/quorum.ts +84 -0
  147. package/src/scripts/ai_council/session.ts +44 -0
  148. package/src/scripts/ai_council/transport_resolver.ts +127 -1
  149. package/src/scripts/ai_team/availability.ts +110 -0
  150. package/src/scripts/ai_team/config.ts +34 -14
  151. package/src/scripts/ai_team/team_dispatch.ts +71 -29
  152. package/src/scripts/ask_transport.ts +221 -0
  153. package/src/scripts/bench_critic_protocol.ts +396 -0
  154. package/src/scripts/bench_hook_injection.ts +234 -0
  155. package/src/scripts/check_adr_frontmatter.ts +84 -40
  156. package/src/scripts/check_branch_freshness.ts +1 -0
  157. package/src/scripts/check_corpus_staleness.ts +18 -4
  158. package/src/scripts/check_detector_corpus.ts +219 -0
  159. package/src/scripts/check_gitignore_freshness.ts +42 -8
  160. package/src/scripts/check_hook_bundle_freshness.ts +24 -1
  161. package/src/scripts/check_kernel_prefix_stability.ts +1 -0
  162. package/src/scripts/check_standing_rule_delivery.ts +73 -32
  163. package/src/scripts/check_static_layer_stability.ts +154 -0
  164. package/src/scripts/check_suppression_hygiene.ts +48 -0
  165. package/src/scripts/condense.ts +162 -2
  166. package/src/scripts/council_cli.ts +401 -25
  167. package/src/scripts/dispatch_economy_report.ts +448 -0
  168. package/src/scripts/dispatch_r2_reviewer.ts +15 -2
  169. package/src/scripts/explain_run.ts +206 -4
  170. package/src/scripts/forensics_report.ts +333 -0
  171. package/src/scripts/generate_settings_reference.ts +1 -0
  172. package/src/scripts/handoff_context_hook.ts +112 -4
  173. package/src/scripts/hook_manifest.yaml +117 -10
  174. package/src/scripts/hooks/concern_registry.ts +8 -0
  175. package/src/scripts/hooks/delegation_nudge_hook.ts +106 -35
  176. package/src/scripts/hooks/dispatch_hook.ts +39 -2
  177. package/src/scripts/hooks/edit_shape_hook.ts +303 -0
  178. package/src/scripts/hooks/orchestration_record_hook.ts +19 -1
  179. package/src/scripts/hooks/reread_guard_hook.ts +314 -0
  180. package/src/scripts/hooks/rtk_wrap_hook.ts +133 -14
  181. package/src/scripts/hooks/session_eol_hook.ts +268 -0
  182. package/src/scripts/hooks/turn_end_gate_hook.ts +507 -0
  183. package/src/scripts/install-hooks.sh +1 -1
  184. package/src/scripts/language_mirror_hook.ts +89 -0
  185. package/src/scripts/lint_decision_impact.ts +14 -1
  186. package/src/scripts/lint_discovery_vocabulary.ts +2 -0
  187. package/src/scripts/lint_hook_manifest.ts +82 -0
  188. package/src/scripts/lint_never_silent.ts +276 -0
  189. package/src/scripts/lint_no_activation_gates.ts +271 -0
  190. package/src/scripts/lint_readme_serial_comma.ts +1 -0
  191. package/src/scripts/lint_rule_enforcement_declaration.ts +347 -0
  192. package/src/scripts/measure_turn_end_gate.ts +194 -0
  193. package/src/scripts/orchestration_record.ts +12 -1
  194. package/src/scripts/rebuild_hook_bundle.ts +178 -0
  195. package/src/scripts/release.ts +74 -2
  196. package/src/scripts/report_conformance_funnel.ts +284 -0
  197. package/src/scripts/report_imperative_density.ts +1 -0
  198. package/src/scripts/routing_doctor.ts +118 -36
  199. package/src/scripts/score_skill_selection.ts +19 -5
  200. package/src/scripts/self_repair_cli.ts +337 -59
  201. package/src/scripts/session_eol_report.ts +261 -0
  202. package/src/scripts/team_events_spike.ts +271 -0
  203. package/src/scripts/team_review_gate_hook.ts +31 -9
  204. package/src/server/schemas/settings.ts +24 -17
  205. package/src/shared/settingsCarveOut.ts +0 -10
  206. package/src/shared/settingsClasses.ts +11 -9
  207. package/src/templates/compact-instructions.md +40 -0
  208. package/dist/ui/assets/index-DmR0mbk4.js +0 -26
  209. package/dist/ui/assets/index-DmR0mbk4.js.map +0 -1
@@ -1174,11 +1174,27 @@ export function generate_rule_symlinks(): number {
1174
1174
  const skip = new Set(rules.filter((r) => !emit_here.has(r)));
1175
1175
  skipped_per_tool[tool_dir] = skip;
1176
1176
  _mkdirp(target_dir);
1177
- // Clean stale symlinks — a rule that became de-duplicable this run is
1177
+ // Clean stale entries — a rule that became de-duplicable this run is
1178
1178
  // stale at project scope too, so it has to go with the rest.
1179
+ //
1180
+ // Symlink-only was correct while every tool dir was a symlink tree. Two
1181
+ // paths now write REAL files (`thin` mode, and the Claude emitter
1182
+ // below), and a stale real file is invisible to an `_isSymlink` test —
1183
+ // so a renamed or newly de-duplicable rule would leave its body behind,
1184
+ // loaded unconditionally, forever.
1185
+ //
1186
+ // Ownership test for a real file: its basename is an agent-config rule
1187
+ // in the projection source. A consumer's own hand-written rule is only
1188
+ // touched if it collides with one of ours by name, in which case it was
1189
+ // already being overwritten.
1179
1190
  for (const item of _iterdirSorted(target_dir)) {
1180
1191
  const name = path.basename(item);
1181
- if (_isSymlink(item) && (!rules.includes(name) || skip.has(name)) && name !== 'README.md') {
1192
+ if (name === 'README.md') {
1193
+ continue;
1194
+ }
1195
+ const is_ours =
1196
+ _isSymlink(item) || _isFile(path.join(MODULE_STATE.RULES_SOURCE, name));
1197
+ if (is_ours && (!rules.includes(name) || skip.has(name))) {
1182
1198
  fs.unlinkSync(item);
1183
1199
  }
1184
1200
  }
@@ -1192,6 +1208,11 @@ export function generate_rule_symlinks(): number {
1192
1208
  }
1193
1209
  if (thin_files !== null) {
1194
1210
  _writeText(link, thin_files[rule] as string);
1211
+ } else if (tool_dir === '.claude/rules') {
1212
+ // Host-native activation (P3.1): emit the rule with the host's
1213
+ // own `paths:` key instead of symlinking agent-config
1214
+ // frontmatter this host does not read.
1215
+ _emit_claude_rule(path.join(MODULE_STATE.RULES_SOURCE, rule), link);
1195
1216
  } else {
1196
1217
  fs.symlinkSync(path.join(rel_prefix, rule), link);
1197
1218
  }
@@ -1355,6 +1376,145 @@ export function _emit_windsurf_rule(source: string, target: string): void {
1355
1376
  _writeText(target, lines.join('\n'));
1356
1377
  }
1357
1378
 
1379
+ /**
1380
+ * A brace group the host expands, versus an agent-config placeholder that only
1381
+ * LOOKS like one.
1382
+ *
1383
+ * `path_prefix: "{module_root}/"` in `roadmap-ci-steps-policy` is resolved by
1384
+ * this suite from `modules.root_paths`. Emitted verbatim into a host `paths:`
1385
+ * list it is a brace group with no comma, which the host expands to the literal
1386
+ * string `{module_root}` — a pattern that matches no file. The rule would then
1387
+ * reach the model **never** instead of on-demand, and nothing would say so: the
1388
+ * probed contract records this exact degradation as silent
1389
+ * (`claude-code-rules-dir-contract.md` § constraints).
1390
+ *
1391
+ * Dropping the pattern is fail-safe in the one direction that matters. A rule
1392
+ * left with no pattern at all carries no `paths:` key and loads
1393
+ * unconditionally — the status quo, not a regression. A rule carrying a
1394
+ * no-op pattern is invisible.
1395
+ *
1396
+ * The discriminator is the comma, not a placeholder allowlist: `{ts,tsx}` is a
1397
+ * real alternation, `{module_root}` cannot be one.
1398
+ */
1399
+ export function _is_unresolved_placeholder(pattern: string): boolean {
1400
+ for (const m of pattern.matchAll(/\{([^}]*)\}/g)) {
1401
+ if (!(m[1] as string).includes(',')) {
1402
+ return true;
1403
+ }
1404
+ }
1405
+ return false;
1406
+ }
1407
+
1408
+ /**
1409
+ * `[` opens a bracket expression for the host. An unparseable one makes that
1410
+ * pattern match nothing while the rule's other patterns keep working — so a
1411
+ * literal `[` in a trigger is escaped rather than trusted.
1412
+ */
1413
+ export function _escape_claude_bracket(pattern: string): string {
1414
+ return pattern.replace(/\[/g, '\\[');
1415
+ }
1416
+
1417
+ /**
1418
+ * Expanded-pattern cost of one glob: the product of its brace alternations.
1419
+ * The host budgets a rule's whole `paths:` list at 1,000 expanded patterns and
1420
+ * 4 MiB, and a list over budget is used UNEXPANDED — braces then match
1421
+ * literally, i.e. nothing. Counting keeps the emitter under the cliff instead
1422
+ * of discovering it as a silent no-op.
1423
+ */
1424
+ export function _expanded_pattern_count(pattern: string): number {
1425
+ let n = 1;
1426
+ for (const m of pattern.matchAll(/\{([^}]*)\}/g)) {
1427
+ n *= (m[1] as string).split(',').length;
1428
+ }
1429
+ return n;
1430
+ }
1431
+
1432
+ /** Host-documented budget for one rule's whole `paths:` list. */
1433
+ export const CLAUDE_PATHS_PATTERN_BUDGET = 1000;
1434
+
1435
+ export interface ClaudePathsPlan {
1436
+ /** Patterns to emit under `paths:`, in declaration order. */
1437
+ globs: string[];
1438
+ /** Patterns deliberately not emitted, with the reason a reader can act on. */
1439
+ dropped: { pattern: string; reason: 'unresolved-placeholder' | 'over-budget' }[];
1440
+ }
1441
+
1442
+ /**
1443
+ * Derive the host's `paths:` list for one rule, with every drop recorded.
1444
+ *
1445
+ * Kernel / always-apply rules get an EMPTY list on purpose: absent `paths:` is
1446
+ * how this host says "load unconditionally", which is exactly what an Iron-Law
1447
+ * rule needs. Scoping one would be a correctness regression dressed as a byte
1448
+ * saving — and the same contract notes path-scoped rules are not re-injected
1449
+ * after `/compact`, so an obligation that must survive compaction cannot be
1450
+ * path-scoped at all.
1451
+ */
1452
+ export function _claude_paths_plan(meta: Record<string, unknown>): ClaudePathsPlan {
1453
+ const always_apply = Boolean(meta['alwaysApply'] || meta['type'] === 'always');
1454
+ if (always_apply) {
1455
+ return { globs: [], dropped: [] };
1456
+ }
1457
+ const globs: string[] = [];
1458
+ const dropped: ClaudePathsPlan['dropped'] = [];
1459
+ let spent = 0;
1460
+ for (const raw of derive_trigger_globs(meta)) {
1461
+ if (_is_unresolved_placeholder(raw)) {
1462
+ dropped.push({ pattern: raw, reason: 'unresolved-placeholder' });
1463
+ continue;
1464
+ }
1465
+ const cost = _expanded_pattern_count(raw);
1466
+ if (spent + cost > CLAUDE_PATHS_PATTERN_BUDGET) {
1467
+ dropped.push({ pattern: raw, reason: 'over-budget' });
1468
+ continue;
1469
+ }
1470
+ spent += cost;
1471
+ globs.push(_escape_claude_bracket(raw));
1472
+ }
1473
+ return { globs, dropped };
1474
+ }
1475
+
1476
+ /**
1477
+ * Emit a Claude Code rule carrying the host's OWN activation key.
1478
+ *
1479
+ * Sibling of {@link _emit_cursor_mdc} and {@link _emit_windsurf_rule}, and the
1480
+ * third member of a set that had two. `.claude/rules` was a symlink projection
1481
+ * of `dist/agent-src/rules`, which carried agent-config's own frontmatter
1482
+ * vocabulary (`type`, `tier`, `triggers`, `alwaysApply`, …) into a host that
1483
+ * reads **none** of it — so every rule loaded unconditionally and the corpus
1484
+ * arrived in full every session.
1485
+ *
1486
+ * Emitted frontmatter is therefore `paths:` and nothing else: the one key the
1487
+ * probed contract records as read by this host. A rule with no path-shaped
1488
+ * trigger gets no frontmatter at all rather than a block the host ignores —
1489
+ * keys that do nothing are bytes in every session's standing context.
1490
+ *
1491
+ * The body is copied byte-for-byte from the projection source (ADR-201's
1492
+ * copy-plus-rewrite discipline); only the frontmatter is host-shaped.
1493
+ */
1494
+ export function _emit_claude_rule(source: string, target: string): void {
1495
+ const [meta, body] = _parse_frontmatter(_readText(source));
1496
+ const plan = _claude_paths_plan(meta);
1497
+ for (const d of plan.dropped) {
1498
+ _print(
1499
+ ` ⚠️ ${path.basename(target)}: dropped \`paths:\` pattern ${JSON.stringify(d.pattern)} (${d.reason}) — ` +
1500
+ (plan.globs.length > 0
1501
+ ? 'the rule keeps its other patterns'
1502
+ : 'the rule now loads unconditionally'),
1503
+ );
1504
+ }
1505
+ const lines: string[] = [];
1506
+ if (plan.globs.length > 0) {
1507
+ lines.push('---', 'paths:');
1508
+ for (const g of plan.globs) {
1509
+ lines.push(` - ${_yaml_scalar(g)}`);
1510
+ }
1511
+ lines.push('---', '');
1512
+ }
1513
+ lines.push(_pyRstrip(body) + '\n');
1514
+ _mkdirp(path.dirname(target));
1515
+ _writeText(target, lines.join('\n'));
1516
+ }
1517
+
1358
1518
  /** Python str.rstrip() with no args. */
1359
1519
  function _pyRstrip(s: string): string {
1360
1520
  return s.replace(/\s+$/u, '');