@event4u/agent-config 14.6.0 → 14.8.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 (258) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/CHANGELOG.md +255 -145
  3. package/README.md +1 -1
  4. package/dist/agent-src/commands/analyze/inbox.md +264 -10
  5. package/dist/agent-src/commands/analyze.md +1 -1
  6. package/dist/agent-src/commands/evals/git-pr-merge.json +13 -0
  7. package/dist/agent-src/commands/evals/roadmap.json +17 -1
  8. package/dist/agent-src/commands/pr/create.md +14 -2
  9. package/dist/agent-src/commands/pr/merge.md +379 -0
  10. package/dist/agent-src/commands/roadmap/process-full.md +272 -32
  11. package/dist/agent-src/commands/roadmap.md +1 -1
  12. package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +46 -36
  13. package/dist/agent-src/contexts/execution/autonomy-mechanics.md +37 -2
  14. package/dist/agent-src/contexts/execution/roadmap-execution-contract.md +95 -2
  15. package/dist/agent-src/contexts/execution/roadmap-process-loop.md +289 -106
  16. package/dist/agent-src/rules/artifact-drafting-protocol.md +5 -1
  17. package/dist/agent-src/rules/context-hygiene.md +2 -0
  18. package/dist/agent-src/rules/decision-revisit-gate.md +67 -32
  19. package/dist/agent-src/rules/fix-what-you-see.md +108 -0
  20. package/dist/agent-src/rules/no-roadmap-references.md +0 -5
  21. package/dist/agent-src/rules/recurring-criticism.md +110 -0
  22. package/dist/agent-src/rules/roadmap-progress-sync.md +20 -1
  23. package/dist/agent-src/rules/rule-type-governance.md +0 -2
  24. package/dist/agent-src/rules/self-repair-loop.md +17 -0
  25. package/dist/agent-src/rules/skill-quality.md +0 -2
  26. package/dist/agent-src/rules/source-confidentiality.md +37 -7
  27. package/dist/agent-src/scripts/archival_sweep.ts +117 -0
  28. package/dist/agent-src/scripts/archive_completed_roadmaps.ts +26 -7
  29. package/dist/agent-src/scripts/dashboard_mode.ts +212 -0
  30. package/dist/agent-src/scripts/gate_budget.ts +282 -0
  31. package/dist/agent-src/scripts/gate_execute.ts +72 -31
  32. package/dist/agent-src/scripts/roadmap_gates.ts +74 -3
  33. package/dist/agent-src/scripts/update_roadmap_progress.ts +296 -53
  34. package/dist/agent-src/skills/adr-create/SKILL.md +124 -5
  35. package/dist/agent-src/skills/ai-council/SKILL.md +48 -807
  36. package/dist/agent-src/skills/ai-council/references/advanced-modes.md +320 -0
  37. package/dist/agent-src/skills/ai-council/references/cost-and-redaction.md +99 -0
  38. package/dist/agent-src/skills/ai-council/references/execution-modes.md +162 -0
  39. package/dist/agent-src/skills/ai-council/references/output-and-synthesis.md +125 -0
  40. package/dist/agent-src/skills/ai-council/references/procedure.md +143 -0
  41. package/dist/agent-src/skills/decision-record/SKILL.md +61 -3
  42. package/dist/agent-src/skills/decision-review/SKILL.md +65 -0
  43. package/dist/agent-src/skills/merge-conflicts/SKILL.md +26 -0
  44. package/dist/agent-src/skills/quality-tools/SKILL.md +34 -326
  45. package/dist/agent-src/skills/quality-tools/references/js-ts-tools.md +113 -0
  46. package/dist/agent-src/skills/quality-tools/references/php-tools.md +222 -0
  47. package/dist/agent-src/skills/roadmap-management/SKILL.md +15 -409
  48. package/dist/agent-src/skills/roadmap-management/references/archival.md +226 -0
  49. package/dist/agent-src/skills/roadmap-management/references/authoring.md +107 -0
  50. package/dist/agent-src/skills/roadmap-management/references/dashboard.md +47 -0
  51. package/dist/agent-src/skills/roadmap-management/references/lifecycle.md +58 -0
  52. package/dist/agent-src/skills/security/SKILL.md +8 -0
  53. package/dist/agent-src/skills/security-audit/SKILL.md +12 -1
  54. package/dist/agent-src/skills/skill-writing/SKILL.md +34 -570
  55. package/dist/agent-src/skills/skill-writing/references/procedure.md +275 -0
  56. package/dist/agent-src/skills/skill-writing/references/read-only-scripts.md +18 -0
  57. package/dist/agent-src/skills/skill-writing/references/section-patterns.md +298 -0
  58. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  59. package/dist/agent-src/templates/roadmaps.md +65 -4
  60. package/dist/agent-src/templates/scripts/telemetry/flush_sender.mjs +163 -0
  61. package/dist/agent-src/templates/scripts/telemetry/remote.ts +160 -7
  62. package/dist/agent-src/templates/scripts/telemetry/transport.ts +169 -0
  63. package/dist/cli/registry.js +2 -1
  64. package/dist/cli/registry.js.map +1 -1
  65. package/dist/cli-delegate/chunk-2GNWGMAL.js +172 -0
  66. package/dist/cli-delegate/{chunk-P6LQDIWK.js → chunk-7PRE6ZV2.js} +338 -0
  67. package/dist/cli-delegate/{chunk-BKO2AZ7Z.js → chunk-B2ERU2VA.js} +1 -1
  68. package/dist/cli-delegate/chunk-E4XIZDIB.js +402 -0
  69. package/dist/cli-delegate/{chunk-3UCJWMMP.js → chunk-EEJUMCDZ.js} +16 -16
  70. package/dist/cli-delegate/{chunk-NXFWFAYV.js → chunk-G23AT6GD.js} +1 -0
  71. package/dist/cli-delegate/{chunk-XURJ4AQC.js → chunk-H4VIVD4C.js} +385 -284
  72. package/dist/cli-delegate/chunk-I3EIN2YG.js +36 -0
  73. package/dist/cli-delegate/{chunk-RLN73PR5.js → chunk-LPPWO5CE.js} +12 -8
  74. package/dist/cli-delegate/chunk-MWRD5YOH.js +100 -0
  75. package/dist/cli-delegate/{chunk-UEZ7D35A.js → chunk-N7CDDGI3.js} +4 -23
  76. package/dist/cli-delegate/{chunk-63WSP6YZ.js → chunk-PMEKGDED.js} +74 -167
  77. package/dist/cli-delegate/{chunk-GRRPEPRN.js → chunk-T7L2QK3K.js} +24 -5
  78. package/dist/cli-delegate/{chunk-EVTY7ISR.js → chunk-YM4GZDJG.js} +9 -1
  79. package/dist/cli-delegate/cmd_adr_effective.js +1162 -0
  80. package/dist/cli-delegate/cmd_conformance.js +466 -716
  81. package/dist/cli-delegate/cmd_converge.js +3 -3
  82. package/dist/cli-delegate/cmd_doctor.js +10 -10
  83. package/dist/cli-delegate/cmd_explain.js +1 -1
  84. package/dist/cli-delegate/cmd_export.js +10 -9
  85. package/dist/cli-delegate/cmd_handoff.js +10 -9
  86. package/dist/cli-delegate/cmd_memory_get.js +2 -1
  87. package/dist/cli-delegate/cmd_migrate.js +2 -2
  88. package/dist/cli-delegate/cmd_packs_active.js +1 -1
  89. package/dist/cli-delegate/cmd_preflight.js +5 -5
  90. package/dist/cli-delegate/cmd_prune.js +11 -10
  91. package/dist/cli-delegate/cmd_route_audit.js +6 -5
  92. package/dist/cli-delegate/cmd_route_explain.js +3 -3
  93. package/dist/cli-delegate/cmd_session_recycle.js +840 -30
  94. package/dist/cli-delegate/cmd_settings_get.js +3 -3
  95. package/dist/cli-delegate/cmd_settings_migrate.js +10 -9
  96. package/dist/cli-delegate/cmd_settings_set.js +1 -1
  97. package/dist/cli-delegate/cmd_sync.js +11 -10
  98. package/dist/cli-delegate/cmd_uninstall.js +13 -11
  99. package/dist/cli-delegate/cmd_update.js +4 -4
  100. package/dist/cli-delegate/cmd_upgrade.js +4 -4
  101. package/dist/cli-delegate/cmd_validate.js +11 -10
  102. package/dist/cli-delegate/cmd_versions.js +3 -3
  103. package/dist/discovery/deprecation-report.md +1 -1
  104. package/dist/discovery/discovery-manifest.json +111 -37
  105. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  106. package/dist/discovery/discovery-manifest.summary.md +5 -5
  107. package/dist/discovery/dormancy-report.md +1 -1
  108. package/dist/discovery/orphan-report.md +1 -1
  109. package/dist/discovery/packs.json +15 -12
  110. package/dist/discovery/trust-report.md +3 -3
  111. package/dist/discovery/workspaces.json +11 -8
  112. package/dist/hooks/dispatch.js +3165 -2192
  113. package/dist/install/claudePathsPlan.js +187 -0
  114. package/dist/install/claudePathsPlan.js.map +1 -0
  115. package/dist/install/globalRuleLayers.js +169 -0
  116. package/dist/install/globalRuleLayers.js.map +1 -0
  117. package/dist/install/hostLayerFingerprint.js +136 -0
  118. package/dist/install/hostLayerFingerprint.js.map +1 -0
  119. package/dist/install/install.mjs +553 -425
  120. package/dist/install/partitionEligibility.js +432 -0
  121. package/dist/install/partitionEligibility.js.map +1 -0
  122. package/dist/install/ruleLayerPartition.js +157 -0
  123. package/dist/install/ruleLayerPartition.js.map +1 -0
  124. package/dist/mcp/registry-manifest.json +3 -3
  125. package/dist/mcp/server.json +2 -2
  126. package/dist/mcp/server.mjs +1863 -1234
  127. package/dist/router.json +1 -1
  128. package/dist/scripts/_lib/agent_src.js +41 -0
  129. package/dist/scripts/_lib/agent_src.js.map +1 -1
  130. package/dist/scripts/_lib/install_layout.js +83 -0
  131. package/dist/scripts/_lib/install_layout.js.map +1 -0
  132. package/dist/scripts/_lib/installed_lock.js +444 -0
  133. package/dist/scripts/_lib/installed_lock.js.map +1 -0
  134. package/dist/scripts/_lib/prune_empty_dirs.js +85 -0
  135. package/dist/scripts/_lib/prune_empty_dirs.js.map +1 -0
  136. package/dist/scripts/condense.js +63 -251
  137. package/dist/scripts/condense.js.map +1 -1
  138. package/dist/server/schemas/settings.js +4 -0
  139. package/dist/server/schemas/settings.js.map +1 -1
  140. package/docs/contracts/settings-classes.md +12 -6
  141. package/docs/guidelines/agent-infra/agent-interaction-and-decision-quality.md +8 -3
  142. package/docs/guidelines/agent-infra/artifact-drafting-protocol-mechanics.md +45 -1
  143. package/docs/guidelines/agent-infra/context-hygiene-mechanics.md +26 -0
  144. package/docs/guidelines/agent-infra/false-green.md +47 -1
  145. package/docs/guidelines/agent-infra/memory-access.md +17 -0
  146. package/docs/guidelines/agent-infra/recurring-criticism-mechanics.md +96 -0
  147. package/package.json +1 -1
  148. package/src/agent-src/scripts/archival_sweep.ts +117 -0
  149. package/src/agent-src/scripts/archive_completed_roadmaps.ts +26 -7
  150. package/src/agent-src/scripts/dashboard_mode.ts +212 -0
  151. package/src/agent-src/scripts/gate_budget.ts +282 -0
  152. package/src/agent-src/scripts/gate_execute.ts +72 -31
  153. package/src/agent-src/scripts/roadmap_gates.ts +74 -3
  154. package/src/agent-src/scripts/update_roadmap_progress.ts +296 -53
  155. package/src/agent-src/templates/scripts/telemetry/flush_sender.mjs +163 -0
  156. package/src/agent-src/templates/scripts/telemetry/remote.ts +160 -7
  157. package/src/agent-src/templates/scripts/telemetry/transport.ts +169 -0
  158. package/src/config/agent-settings.template.yml +27 -2
  159. package/src/config/ci-local-parity.yml +39 -0
  160. package/src/config/estate-count-budget.json +612 -3
  161. package/src/config/evaluator-budgets.json +3 -3
  162. package/src/config/gate-coverage.yml +220 -12
  163. package/src/config/gate-violation-baselines.json +73 -63
  164. package/src/config/gitignore-block.txt +15 -2
  165. package/src/config/hook-latency-budget.json +5 -0
  166. package/src/config/rule-activation-census.json +14 -6
  167. package/src/config/rule-stub-ceilings.json +34 -7
  168. package/src/install/claudePathsPlan.ts +196 -0
  169. package/src/install/globalRuleLayers.ts +197 -0
  170. package/src/install/hostLayerFingerprint.ts +145 -0
  171. package/src/install/partitionEligibility.ts +502 -0
  172. package/src/install/ruleLayerPartition.ts +212 -0
  173. package/src/scripts/_cli/cmd_adr_effective.ts +484 -0
  174. package/src/scripts/_cli/cmd_session_recycle.ts +9 -1
  175. package/src/scripts/_dispatch.bash +17 -1
  176. package/src/scripts/_lib/ac_heading.ts +30 -0
  177. package/src/scripts/_lib/adr_frontmatter.test.ts +365 -0
  178. package/src/scripts/_lib/adr_frontmatter.ts +459 -0
  179. package/src/scripts/_lib/agent_src.ts +42 -0
  180. package/src/scripts/_lib/bench_ab_pinned_repo.ts +162 -0
  181. package/src/scripts/_lib/bench_ab_workspace.ts +10 -1
  182. package/src/scripts/_lib/envelope_grounding.ts +49 -9
  183. package/src/scripts/_lib/installed_lock.ts +50 -5
  184. package/src/scripts/_lib/layer_overlap_notice.ts +11 -2
  185. package/src/scripts/_lib/md_section.ts +129 -0
  186. package/src/scripts/_lib/prune_empty_dirs.ts +80 -0
  187. package/src/scripts/_lib/scope_guard.sh +26 -3
  188. package/src/scripts/_lib/self_repair.ts +19 -0
  189. package/src/scripts/_lib/self_repair_class_b.ts +171 -0
  190. package/src/scripts/adr/evidence_census.ts +899 -0
  191. package/src/scripts/adr/regenerate_index.ts +12 -32
  192. package/src/scripts/adr_cite_check.ts +540 -39
  193. package/src/scripts/ai_council/cli_help.ts +55 -0
  194. package/src/scripts/audit_adr_coverage.ts +103 -17
  195. package/src/scripts/before_complete_hook.ts +153 -28
  196. package/src/scripts/bench_ab_v2_complexity.ts +27 -7
  197. package/src/scripts/bench_hook_latency.ts +204 -0
  198. package/src/scripts/build_archive_index.ts +34 -0
  199. package/src/scripts/check_adr_frontmatter.ts +574 -39
  200. package/src/scripts/check_hook_bundle_content.ts +219 -0
  201. package/src/scripts/check_new_adr_evidence.ts +529 -0
  202. package/src/scripts/check_references.ts +78 -0
  203. package/src/scripts/check_release_published.ts +32 -11
  204. package/src/scripts/check_rule_layer_partition.ts +531 -0
  205. package/src/scripts/check_single_delivery.ts +194 -17
  206. package/src/scripts/check_standing_rule_delivery.ts +8 -2
  207. package/src/scripts/ci_settle.ts +170 -0
  208. package/src/scripts/condense.ts +79 -259
  209. package/src/scripts/council_cli.ts +3 -3
  210. package/src/scripts/dispatch_r2_reviewer.ts +6 -14
  211. package/src/scripts/external_sources_denylist.json +4 -1
  212. package/src/scripts/hook_manifest.json +1 -1
  213. package/src/scripts/hook_manifest.yaml +77 -14
  214. package/src/scripts/hooks/block_no_verify.ts +61 -10
  215. package/src/scripts/hooks/block_unauthorized_git.ts +21 -1
  216. package/src/scripts/hooks/concern_registry.ts +4 -0
  217. package/src/scripts/hooks/dispatch_hook.ts +154 -187
  218. package/src/scripts/hooks/dispatch_issues.ts +38 -19
  219. package/src/scripts/hooks/fallback_yaml.ts +66 -0
  220. package/src/scripts/hooks/host_semantics.ts +21 -0
  221. package/src/scripts/hooks/injection_budget.ts +13 -3
  222. package/src/scripts/hooks/py_json_dumps.ts +103 -0
  223. package/src/scripts/hooks/rtk_wrap_hook.ts +8 -3
  224. package/src/scripts/hooks/run_continuation_hook.ts +8 -5
  225. package/src/scripts/hooks/ship_diff_volume_hook.ts +81 -15
  226. package/src/scripts/hooks/source_first_gate_hook.ts +464 -0
  227. package/src/scripts/hooks/state_io.ts +870 -21
  228. package/src/scripts/hooks/stdin_failure_policy.ts +96 -0
  229. package/src/scripts/hooks/subagent_ledger_hook.ts +44 -15
  230. package/src/scripts/hooks/telemetry_flush_hook.ts +139 -0
  231. package/src/scripts/hooks/telemetry_self_repair.ts +128 -0
  232. package/src/scripts/hooks/telemetry_usage_hook.ts +22 -4
  233. package/src/scripts/hooks/turn_end_gate_hook.ts +81 -15
  234. package/src/scripts/injection_scan_hook.ts +137 -5
  235. package/src/scripts/install.ts +16 -11
  236. package/src/scripts/language_mirror_hook.ts +561 -25
  237. package/src/scripts/lint_framework_leakage_allowlist.json +2 -2
  238. package/src/scripts/lint_hook_manifest.ts +49 -0
  239. package/src/scripts/lint_plan_risk_register.ts +4 -3
  240. package/src/scripts/lint_provenance_vocabulary.ts +472 -4
  241. package/src/scripts/lint_skill_router_head.ts +4 -4
  242. package/src/scripts/mcp_server/tools.ts +2 -2
  243. package/src/scripts/new_roadmap.ts +136 -0
  244. package/src/scripts/pack_mcp_content.ts +20 -5
  245. package/src/scripts/release.ts +37 -38
  246. package/src/scripts/report_layer_overlap.ts +6 -0
  247. package/src/scripts/routing_doctor.ts +5 -1
  248. package/src/scripts/self_repair_hook.ts +37 -5
  249. package/src/scripts/session_register_hook.ts +11 -0
  250. package/src/scripts/skill_usage_collect.ts +11 -1
  251. package/src/scripts/skill_usage_report.ts +278 -8
  252. package/src/scripts/sync_pr_branch.ts +170 -20
  253. package/src/server/schemas/settings.ts +8 -0
  254. package/dist/cli-delegate/chunk-EJITJBJX.js +0 -172
  255. package/dist/cli-delegate/chunk-PZWRPRWP.js +0 -38
  256. package/dist/cli-delegate/{chunk-PPQO4NGR.js → chunk-6RJA2F5A.js} +3 -3
  257. package/dist/cli-delegate/{chunk-RYNADUFG.js → chunk-LWTYTX6F.js} +0 -0
  258. package/dist/cli-delegate/{chunk-FBKL6JWT.js → chunk-MMSGVZKV.js} +3 -3
@@ -0,0 +1,444 @@
1
+ /**
2
+ * Global-install lockfile at `~/.event4u/agent-config/installed.lock`.
3
+ *
4
+ * Ported from the retired Python `src/scripts/_lib/installed_lock.py` (ADR-200 — Python→TS
5
+ * migration, Phase 2 / Wave 2a). Public API mirrors the Python module exactly
6
+ * (snake_case kept deliberately — fidelity over TS idiom), including the
7
+ * byte-exact lockfile wire format and the tempfile + rename atomic write.
8
+ *
9
+ * Phase 1.6 of road-to-global-first-install (ADR-007 D5). Records the package
10
+ * version that performed the most recent user-scope install plus the tools
11
+ * that were scaffolded. `init --global` reads this file: on version mismatch
12
+ * the install refuses unless `--force` is passed; the `update` subcommand
13
+ * refreshes the entry in lockstep with the pin flip in `.agent-settings.yml`.
14
+ *
15
+ * The schema is intentionally minimal YAML so the module can read and write
16
+ * without depending on a YAML library. Atomic writes go through tempfile +
17
+ * rename per ADR-007 risk-mitigation row.
18
+ *
19
+ * Path resolution is delegated to `user_global_paths` (Phase 1 of
20
+ * road-to-event4u-namespace-and-claude-desktop.md): writes land at
21
+ * `~/.event4u/agent-config/installed.lock`; reads fall back to the legacy
22
+ * `~/.config/agent-config/installed.lock` if the new path is missing, so
23
+ * pre-2.4 installs keep working during the transition.
24
+ */
25
+ import { randomBytes } from "node:crypto";
26
+ import * as fs from "node:fs";
27
+ import * as os from "node:os";
28
+ import * as path from "node:path";
29
+ import { fileURLToPath } from "node:url";
30
+ import * as user_global_paths from "./user_global_paths.js";
31
+ import { INSTALL_LAYOUT_VERSION, coerce_layout_version, needs_migration, } from "./install_layout.js";
32
+ export const LOCKFILE_ENV = "AGENT_CONFIG_INSTALLED_LOCK";
33
+ export const SCHEMA_VERSION = 1;
34
+ /** Canonical write target for the lockfile (new namespace). */
35
+ function _default_lockfile() {
36
+ return user_global_paths.write_target("installed.lock");
37
+ }
38
+ /**
39
+ * Module-level constant retained for back-compat with importers that read
40
+ * `DEFAULT_LOCKFILE` directly. Derived from the helper so the path tracks any
41
+ * future override of `event4u_root()`.
42
+ */
43
+ export const DEFAULT_LOCKFILE = _default_lockfile();
44
+ const _VERSION_RE = /^\s*agent_config_version\s*:\s*"?([^"\s]+)"?\s*$/;
45
+ const _SCHEMA_RE = /^\s*schema_version\s*:\s*(\d+)\s*$/;
46
+ const _LAYOUT_RE = /^\s*install_layout_version\s*:\s*(\d+)\s*$/;
47
+ const _INSTALLED_AT_RE = /^\s*installed_at\s*:\s*"?([^"\s]+)"?\s*$/;
48
+ const _FINGERPRINT_RE = /^\s*host_layer_fingerprint\s*:\s*"?([0-9a-f]{64})"?\s*$/;
49
+ const _TOOL_RE = /^\s*-\s*([A-Za-z0-9_\-.]+)\s*$/;
50
+ /** Expand a leading `~` like Python's `Path.expanduser()`. */
51
+ function expanduser(p) {
52
+ if (p === "~") {
53
+ return os.homedir();
54
+ }
55
+ if (p.startsWith("~/") || (process.platform === "win32" && p.startsWith("~\\"))) {
56
+ return path.join(os.homedir(), p.slice(2));
57
+ }
58
+ return p;
59
+ }
60
+ /**
61
+ * Return the active lockfile path for **reads**, honoring overrides.
62
+ *
63
+ * Resolution order:
64
+ * 1. `$AGENT_CONFIG_INSTALLED_LOCK` — explicit full-path override.
65
+ * 2. `~/.event4u/agent-config/installed.lock` if it exists on disk.
66
+ * 3. `~/.config/agent-config/installed.lock` (legacy fallback, read-only).
67
+ * 4. Canonical write target under the new namespace (Step 2 fallthrough).
68
+ */
69
+ export function lockfile_path(env) {
70
+ const env_map = env ?? process.env;
71
+ const override = env_map[LOCKFILE_ENV];
72
+ if (override) {
73
+ return expanduser(override);
74
+ }
75
+ const resolved = user_global_paths.resolve_with_fallback("installed.lock", { env: env ?? null });
76
+ if (resolved !== null) {
77
+ return resolved;
78
+ }
79
+ return user_global_paths.write_target("installed.lock", { env: env ?? null });
80
+ }
81
+ /**
82
+ * Return the canonical write target for the lockfile.
83
+ *
84
+ * Unlike {@link lockfile_path}, this never falls back to the legacy
85
+ * `~/.config/agent-config/` location. Honors the `$AGENT_CONFIG_INSTALLED_LOCK`
86
+ * override for tests, otherwise pins to `~/.event4u/agent-config/installed.lock`.
87
+ */
88
+ export function lockfile_write_path(env) {
89
+ const env_map = env ?? process.env;
90
+ const override = env_map[LOCKFILE_ENV];
91
+ if (override) {
92
+ return expanduser(override);
93
+ }
94
+ return user_global_paths.write_target("installed.lock", { env: env ?? null });
95
+ }
96
+ /**
97
+ * Parse `path` (or the default) into a dict; return `null` if absent.
98
+ *
99
+ * Tolerates partial / malformed files: missing keys yield missing dict entries
100
+ * rather than throwing, so a hand-edited corrupt file does not brick `init`.
101
+ */
102
+ export function read_lockfile(path) {
103
+ const target = path ?? lockfile_path();
104
+ let text;
105
+ try {
106
+ text = fs.readFileSync(target, { encoding: "utf-8" });
107
+ }
108
+ catch {
109
+ return null;
110
+ }
111
+ const data = { tools: [] };
112
+ let in_tools = false;
113
+ for (const raw_line of splitlines(text)) {
114
+ const schema_m = _SCHEMA_RE.exec(raw_line);
115
+ if (schema_m) {
116
+ data.schema_version = Number.parseInt(schema_m[1], 10);
117
+ in_tools = false;
118
+ continue;
119
+ }
120
+ const layout_m = _LAYOUT_RE.exec(raw_line);
121
+ if (layout_m) {
122
+ data.install_layout_version = Number.parseInt(layout_m[1], 10);
123
+ in_tools = false;
124
+ continue;
125
+ }
126
+ const version_m = _VERSION_RE.exec(raw_line);
127
+ if (version_m) {
128
+ data.agent_config_version = version_m[1];
129
+ in_tools = false;
130
+ continue;
131
+ }
132
+ const installed_m = _INSTALLED_AT_RE.exec(raw_line);
133
+ if (installed_m) {
134
+ data.installed_at = installed_m[1];
135
+ in_tools = false;
136
+ continue;
137
+ }
138
+ const fp_m = _FINGERPRINT_RE.exec(raw_line);
139
+ if (fp_m) {
140
+ data.host_layer_fingerprint = fp_m[1];
141
+ in_tools = false;
142
+ continue;
143
+ }
144
+ if (raw_line.trim().startsWith("tools:")) {
145
+ in_tools = true;
146
+ continue;
147
+ }
148
+ if (in_tools) {
149
+ const m = _TOOL_RE.exec(raw_line);
150
+ if (m) {
151
+ data.tools.push(m[1]);
152
+ }
153
+ else if (raw_line.trim() &&
154
+ !(raw_line.startsWith(" ") || raw_line.startsWith("\t") || raw_line.startsWith("-"))) {
155
+ in_tools = false;
156
+ }
157
+ }
158
+ }
159
+ return data;
160
+ }
161
+ /** `str.splitlines()` — split on `\n`, dropping a trailing empty segment. */
162
+ function splitlines(text) {
163
+ const parts = text.split("\n");
164
+ if (parts.length > 0 && parts[parts.length - 1] === "") {
165
+ parts.pop();
166
+ }
167
+ return parts;
168
+ }
169
+ function _render(version, tools, installed_at, fingerprint) {
170
+ const lines = [
171
+ `schema_version: ${SCHEMA_VERSION}`,
172
+ `install_layout_version: ${INSTALL_LAYOUT_VERSION}`,
173
+ `agent_config_version: "${version}"`,
174
+ `installed_at: "${installed_at}"`,
175
+ ];
176
+ // Written BEFORE `tools:` so the sequence block stays last and the parser's
177
+ // in_tools state machine needs no extra exit condition.
178
+ if (fingerprint) {
179
+ lines.push(`host_layer_fingerprint: "${fingerprint}"`);
180
+ }
181
+ lines.push("tools:");
182
+ for (const tool of tools) {
183
+ lines.push(` - ${tool}`);
184
+ }
185
+ return lines.join("\n") + "\n";
186
+ }
187
+ /** Atomically write the lockfile; return the path written. */
188
+ export function write_lockfile(version, tools, options = {}) {
189
+ const target = options.path ?? lockfile_path();
190
+ fs.mkdirSync(path.dirname(target), { recursive: true });
191
+ const stamp = strftime_iso_z(options.now ?? new Date());
192
+ const rendered = _render(version, sorted_unique(tools), stamp, options.host_layer_fingerprint ?? null);
193
+ // Atomic write: tempfile in the same dir + rename. The same-dir constraint
194
+ // keeps the rename atomic across all POSIX filesystems and Windows when the
195
+ // file already exists.
196
+ const parent = path.dirname(target);
197
+ const { fd, tmp_name } = mkstemp(parent, ".installed.lock.");
198
+ try {
199
+ fs.writeFileSync(fd, rendered, { encoding: "utf-8" });
200
+ fs.closeSync(fd);
201
+ fs.renameSync(tmp_name, target);
202
+ }
203
+ catch (err) {
204
+ try {
205
+ fs.closeSync(fd);
206
+ }
207
+ catch {
208
+ // fd may already be closed.
209
+ }
210
+ try {
211
+ fs.unlinkSync(tmp_name);
212
+ }
213
+ catch {
214
+ // Best-effort cleanup.
215
+ }
216
+ throw err;
217
+ }
218
+ return target;
219
+ }
220
+ /**
221
+ * Parse the lockfile's `installed_at` stamp back into a UTC Date.
222
+ *
223
+ * Returns `null` when absent or malformed, so a migration falls back to the
224
+ * current time rather than raising on a hand-edited file. Mirrors Python's
225
+ * `datetime.strptime(stamp, "%Y-%m-%dT%H:%M:%SZ")` — strict, UTC, no other
226
+ * formats accepted.
227
+ */
228
+ function _parse_installed_at(stamp) {
229
+ if (!stamp) {
230
+ return null;
231
+ }
232
+ const m = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})Z$/.exec(stamp);
233
+ if (!m) {
234
+ return null;
235
+ }
236
+ const [, y, mo, d, h, mi, s] = m;
237
+ const ms = Date.UTC(Number.parseInt(y, 10), Number.parseInt(mo, 10) - 1, Number.parseInt(d, 10), Number.parseInt(h, 10), Number.parseInt(mi, 10), Number.parseInt(s, 10));
238
+ // strptime rejects out-of-range fields (e.g. month 13) rather than rolling
239
+ // over the way Date.UTC does; reject any value that round-trips differently.
240
+ const parsed = new Date(ms);
241
+ if (parsed.getUTCFullYear() !== Number.parseInt(y, 10) ||
242
+ parsed.getUTCMonth() !== Number.parseInt(mo, 10) - 1 ||
243
+ parsed.getUTCDate() !== Number.parseInt(d, 10) ||
244
+ parsed.getUTCHours() !== Number.parseInt(h, 10) ||
245
+ parsed.getUTCMinutes() !== Number.parseInt(mi, 10) ||
246
+ parsed.getUTCSeconds() !== Number.parseInt(s, 10)) {
247
+ return null;
248
+ }
249
+ return parsed;
250
+ }
251
+ /**
252
+ * Migrate an installed-tree lockfile to the current install-layout ABI.
253
+ *
254
+ * Idempotent. Detects `install_layout_version < INSTALL_LAYOUT_VERSION`
255
+ * (absent = pre-freeze v0) and migrates the on-disk shape in place,
256
+ * preserving the recorded tools, package version, and `installed_at` stamp
257
+ * and re-stamping the layout version.
258
+ *
259
+ * At the freeze baseline (v0 → v1) the only material change is stamping the
260
+ * version — the on-disk shape is unchanged. Future layout versions extend
261
+ * this function with the concrete shape transforms; surgical-uninstall
262
+ * pointers must always be preserved.
263
+ *
264
+ * Returns:
265
+ * - `null` — no lockfile exists (nothing installed).
266
+ * - `{from: v, to: v, changed: []}` — already current (no-op).
267
+ * - `{from: old, to: current, changed: [...]}` — migrated.
268
+ */
269
+ export function migrate_layout(options = {}) {
270
+ const target = options.path ?? lockfile_write_path();
271
+ const existing = read_lockfile(target);
272
+ if (existing === null) {
273
+ return null;
274
+ }
275
+ const from_v = coerce_layout_version(existing.install_layout_version);
276
+ if (!needs_migration(existing.install_layout_version)) {
277
+ return { from: from_v, to: from_v, changed: [] };
278
+ }
279
+ const version = existing.agent_config_version || current_package_version();
280
+ const tools = [...(existing.tools ?? [])];
281
+ const when = options.now ?? _parse_installed_at(existing.installed_at);
282
+ // Carry the fingerprint across the migration. Dropping it would silently
283
+ // demote a verified host layer to "not verified" and turn the partition off
284
+ // on the next build — a layout migration must not change delivery.
285
+ write_lockfile(version, tools, {
286
+ path: target,
287
+ now: when,
288
+ host_layer_fingerprint: existing.host_layer_fingerprint ?? null,
289
+ });
290
+ return {
291
+ from: from_v,
292
+ to: INSTALL_LAYOUT_VERSION,
293
+ changed: [`install_layout_version ${from_v} → ${INSTALL_LAYOUT_VERSION}`],
294
+ };
295
+ }
296
+ /** `sorted(set(tools))` — de-duplicate then sort ascending (codepoint). */
297
+ function sorted_unique(tools) {
298
+ return [...new Set(tools)].sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
299
+ }
300
+ /** Format a Date as `%Y-%m-%dT%H:%M:%SZ` in UTC. */
301
+ function strftime_iso_z(now) {
302
+ // ISO string is `YYYY-MM-DDTHH:MM:SS.sssZ`; drop milliseconds → `...SSZ`.
303
+ return now.toISOString().replace(/\.\d{3}Z$/, "Z");
304
+ }
305
+ /** `tempfile.mkstemp` equivalent: exclusive-create a unique sibling, mode 0600. */
306
+ function mkstemp(dir, prefix) {
307
+ for (let attempt = 0; attempt < 32; attempt += 1) {
308
+ const tmp_name = path.join(dir, `${prefix}${randomBytes(6).toString("hex")}`);
309
+ try {
310
+ const fd = fs.openSync(tmp_name, "wx", 0o600);
311
+ return { fd, tmp_name };
312
+ }
313
+ catch (err) {
314
+ if (err.code === "EEXIST") {
315
+ continue;
316
+ }
317
+ throw err;
318
+ }
319
+ }
320
+ throw new Error("mkstemp: could not create a unique temp file");
321
+ }
322
+ /**
323
+ * Compare `installed_version` against the lockfile's recorded version.
324
+ *
325
+ * Returns `[ok, recorded_version_or_null]`:
326
+ * - `[true, null]` — no lockfile yet; `init` may proceed.
327
+ * - `[true, vX]` — matches; `init` may proceed.
328
+ * - `[false, vY]` — mismatch; caller must refuse without `--force`.
329
+ */
330
+ export function check_version(installed_version, options = {}) {
331
+ const existing = read_lockfile(options.path ?? null);
332
+ if (existing === null) {
333
+ return [true, null];
334
+ }
335
+ const recorded = existing.agent_config_version;
336
+ if (!recorded) {
337
+ return [true, null];
338
+ }
339
+ return [recorded === installed_version, recorded];
340
+ }
341
+ const _SEMVER_RE = /^\s*v?(\d+)\.(\d+)\.(\d+)/;
342
+ /**
343
+ * Parse `X.Y.Z[-suffix]` into a `[major, minor, patch]` tuple.
344
+ *
345
+ * Returns `null` when the leading three numeric segments cannot be extracted.
346
+ * Suffixes (`-rc1`, `+build.5`) are ignored.
347
+ */
348
+ function _parse_semver(version) {
349
+ const match = _SEMVER_RE.exec(version);
350
+ if (!match) {
351
+ return null;
352
+ }
353
+ return [Number.parseInt(match[1], 10), Number.parseInt(match[2], 10), Number.parseInt(match[3], 10)];
354
+ }
355
+ /**
356
+ * Classify the relationship between recorded and installed versions.
357
+ *
358
+ * Returns one of: `"none"`, `"match"`, `"upgrade"`, `"downgrade"`,
359
+ * `"unparseable"`.
360
+ */
361
+ export function classify_mismatch(installed_version, recorded) {
362
+ if (recorded === null) {
363
+ return "none";
364
+ }
365
+ if (recorded === installed_version) {
366
+ return "match";
367
+ }
368
+ const rec = _parse_semver(recorded);
369
+ const inst = _parse_semver(installed_version);
370
+ if (rec === null || inst === null) {
371
+ return "unparseable";
372
+ }
373
+ if (tuple_lt(rec, inst)) {
374
+ return "upgrade";
375
+ }
376
+ return "downgrade";
377
+ }
378
+ /** Lexicographic tuple `<` comparison, mirroring Python's tuple ordering. */
379
+ function tuple_lt(a, b) {
380
+ for (let i = 0; i < a.length; i += 1) {
381
+ const av = a[i];
382
+ const bv = b[i];
383
+ if (av < bv)
384
+ return true;
385
+ if (av > bv)
386
+ return false;
387
+ }
388
+ return false;
389
+ }
390
+ /** Read a string `version` from `<dir>/package.json`, or null if absent/malformed. */
391
+ function _read_package_version(dir) {
392
+ try {
393
+ const data = JSON.parse(fs.readFileSync(path.join(dir, "package.json"), { encoding: "utf-8" }));
394
+ const version = data.version;
395
+ if (typeof version === "string" && version.trim()) {
396
+ return version.trim();
397
+ }
398
+ }
399
+ catch {
400
+ // Missing / unreadable / malformed package.json → null.
401
+ }
402
+ return null;
403
+ }
404
+ /**
405
+ * Walk upward from `start_dir` to the nearest `package.json` carrying a string
406
+ * `version`. Layout-independent: works in the source tree
407
+ * (`src/scripts/_lib/`), a per-file `dist/`, AND the esbuild single-file bundle
408
+ * (`dist/cli/agent-config.js`) where this module's runtime location differs
409
+ * from its source path. Returns null at the filesystem root.
410
+ */
411
+ export function _find_package_version_upward(start_dir) {
412
+ let dir = start_dir;
413
+ for (;;) {
414
+ const found = _read_package_version(dir);
415
+ if (found !== null) {
416
+ return found;
417
+ }
418
+ const parent = path.dirname(dir);
419
+ if (parent === dir) {
420
+ return null; // reached the filesystem root
421
+ }
422
+ dir = parent;
423
+ }
424
+ }
425
+ /**
426
+ * Read `version` from the package's own `package.json`.
427
+ *
428
+ * With no `repo_root`, the version is resolved by walking **upward** from this
429
+ * module's runtime directory to the nearest `package.json`. A previous fixed
430
+ * `parents[3]` hop assumed the source layout (`src/scripts/_lib/`); in the
431
+ * shipped esbuild bundle the module runs from `dist/cli/`, so three hops
432
+ * overshot the package root → `package.json` not found → `"0.0.0"` → a
433
+ * spurious "downgrade" refusal on `agent-config global` (lockfile recorded a
434
+ * real version, current package read as `0.0.0`). The upward walk is correct
435
+ * in both layouts.
436
+ */
437
+ export function current_package_version(repo_root) {
438
+ if (repo_root != null) {
439
+ return _read_package_version(repo_root) ?? "0.0.0";
440
+ }
441
+ const here = path.dirname(fileURLToPath(import.meta.url));
442
+ return _find_package_version_upward(here) ?? "0.0.0";
443
+ }
444
+ //# sourceMappingURL=installed_lock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"installed_lock.js","sourceRoot":"","sources":["../../../src/scripts/_lib/installed_lock.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,KAAK,iBAAiB,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EACL,sBAAsB,EACtB,qBAAqB,EACrB,eAAe,GAChB,MAAM,qBAAqB,CAAC;AAoB7B,MAAM,CAAC,MAAM,YAAY,GAAG,6BAA6B,CAAC;AAC1D,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC;AAEhC,+DAA+D;AAC/D,SAAS,iBAAiB;IACxB,OAAO,iBAAiB,CAAC,YAAY,CAAC,gBAAgB,CAAC,CAAC;AAC1D,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,iBAAiB,EAAE,CAAC;AAEpD,MAAM,WAAW,GAAG,kDAAkD,CAAC;AACvE,MAAM,UAAU,GAAG,oCAAoC,CAAC;AACxD,MAAM,UAAU,GAAG,4CAA4C,CAAC;AAChE,MAAM,gBAAgB,GAAG,0CAA0C,CAAC;AACpE,MAAM,eAAe,GAAG,yDAAyD,CAAC;AAClF,MAAM,QAAQ,GAAG,gCAAgC,CAAC;AAElD,8DAA8D;AAC9D,SAAS,UAAU,CAAC,CAAS;IAC3B,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;QACd,OAAO,EAAE,CAAC,OAAO,EAAE,CAAC;IACtB,CAAC;IACD,IAAI,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,KAAK,OAAO,IAAI,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;QAChF,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7C,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,aAAa,CAAC,GAAmB;IAC/C,MAAM,OAAO,GAAG,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC;IACnC,MAAM,QAAQ,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IACvC,IAAI,QAAQ,EAAE,CAAC;QACb,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC;IAC9B,CAAC;IACD,MAAM,QAAQ,GAAG,iBAAiB,CAAC,qBAAqB,CAAC,gBAAgB,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI,IAAI,EAAE,CAAC,CAAC;IACjG,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;QACtB,OAAO,QAAQ,CAAC;IAClB,CAAC;IACD,OAAO,iBAAiB,CAAC,YAAY,CAAC,gBAAgB,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI,IAAI,EAAE,CAAC,CAAC;AAChF,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB,CAAC,GAAmB;IACrD,MAAM,OAAO,GAAG,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC;IACnC,MAAM,QAAQ,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IACvC,IAAI,QAAQ,EAAE,CAAC;QACb,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC;IAC9B,CAAC;IACD,OAAO,iBAAiB,CAAC,YAAY,CAAC,gBAAgB,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI,IAAI,EAAE,CAAC,CAAC;AAChF,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,IAAoB;IAChD,MAAM,MAAM,GAAG,IAAI,IAAI,aAAa,EAAE,CAAC;IACvC,IAAI,IAAY,CAAC;IACjB,IAAI,CAAC;QACH,IAAI,GAAG,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;IACxD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,IAAI,GAAiB,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;IACzC,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,KAAK,MAAM,QAAQ,IAAI,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACxC,MAAM,QAAQ,GAAG,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC3C,IAAI,QAAQ,EAAE,CAAC;YACb,IAAI,CAAC,cAAc,GAAG,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAE,EAAE,EAAE,CAAC,CAAC;YACxD,QAAQ,GAAG,KAAK,CAAC;YACjB,SAAS;QACX,CAAC;QACD,MAAM,QAAQ,GAAG,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC3C,IAAI,QAAQ,EAAE,CAAC;YACb,IAAI,CAAC,sBAAsB,GAAG,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAE,EAAE,EAAE,CAAC,CAAC;YAChE,QAAQ,GAAG,KAAK,CAAC;YACjB,SAAS;QACX,CAAC;QACD,MAAM,SAAS,GAAG,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC7C,IAAI,SAAS,EAAE,CAAC;YACd,IAAI,CAAC,oBAAoB,GAAG,SAAS,CAAC,CAAC,CAAE,CAAC;YAC1C,QAAQ,GAAG,KAAK,CAAC;YACjB,SAAS;QACX,CAAC;QACD,MAAM,WAAW,GAAG,gBAAgB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACpD,IAAI,WAAW,EAAE,CAAC;YAChB,IAAI,CAAC,YAAY,GAAG,WAAW,CAAC,CAAC,CAAE,CAAC;YACpC,QAAQ,GAAG,KAAK,CAAC;YACjB,SAAS;QACX,CAAC;QACD,MAAM,IAAI,GAAG,eAAe,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC5C,IAAI,IAAI,EAAE,CAAC;YACT,IAAI,CAAC,sBAAsB,GAAG,IAAI,CAAC,CAAC,CAAE,CAAC;YACvC,QAAQ,GAAG,KAAK,CAAC;YACjB,SAAS;QACX,CAAC;QACD,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YACzC,QAAQ,GAAG,IAAI,CAAC;YAChB,SAAS;QACX,CAAC;QACD,IAAI,QAAQ,EAAE,CAAC;YACb,MAAM,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAClC,IAAI,CAAC,EAAE,CAAC;gBACN,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAE,CAAC,CAAC;YACzB,CAAC;iBAAM,IACL,QAAQ,CAAC,IAAI,EAAE;gBACf,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,EACpF,CAAC;gBACD,QAAQ,GAAG,KAAK,CAAC;YACnB,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,6EAA6E;AAC7E,SAAS,UAAU,CAAC,IAAY;IAC9B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC/B,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC;QACvD,KAAK,CAAC,GAAG,EAAE,CAAC;IACd,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,OAAO,CACd,OAAe,EACf,KAAe,EACf,YAAoB,EACpB,WAA2B;IAE3B,MAAM,KAAK,GAAG;QACZ,mBAAmB,cAAc,EAAE;QACnC,2BAA2B,sBAAsB,EAAE;QACnD,0BAA0B,OAAO,GAAG;QACpC,kBAAkB,YAAY,GAAG;KAClC,CAAC;IACF,4EAA4E;IAC5E,wDAAwD;IACxD,IAAI,WAAW,EAAE,CAAC;QAChB,KAAK,CAAC,IAAI,CAAC,4BAA4B,WAAW,GAAG,CAAC,CAAC;IACzD,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACrB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,KAAK,CAAC,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC;IAC5B,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AACjC,CAAC;AAED,8DAA8D;AAC9D,MAAM,UAAU,cAAc,CAC5B,OAAe,EACf,KAAe,EACf,UASI,EAAE;IAEN,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,IAAI,aAAa,EAAE,CAAC;IAC/C,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACxD,MAAM,KAAK,GAAG,cAAc,CAAC,OAAO,CAAC,GAAG,IAAI,IAAI,IAAI,EAAE,CAAC,CAAC;IACxD,MAAM,QAAQ,GAAG,OAAO,CACtB,OAAO,EACP,aAAa,CAAC,KAAK,CAAC,EACpB,KAAK,EACL,OAAO,CAAC,sBAAsB,IAAI,IAAI,CACvC,CAAC;IACF,2EAA2E;IAC3E,4EAA4E;IAC5E,uBAAuB;IACvB,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACpC,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAC7D,IAAI,CAAC;QACH,EAAE,CAAC,aAAa,CAAC,EAAE,EAAE,QAAQ,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;QACtD,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;QACjB,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAClC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,CAAC;YACH,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;QACnB,CAAC;QAAC,MAAM,CAAC;YACP,4BAA4B;QAC9B,CAAC;QACD,IAAI,CAAC;YACH,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;QAC1B,CAAC;QAAC,MAAM,CAAC;YACP,uBAAuB;QACzB,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AASD;;;;;;;GAOG;AACH,SAAS,mBAAmB,CAAC,KAAqB;IAChD,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,CAAC,GAAG,oDAAoD,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC3E,IAAI,CAAC,CAAC,EAAE,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC;IACjC,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CACjB,MAAM,CAAC,QAAQ,CAAC,CAAE,EAAE,EAAE,CAAC,EACvB,MAAM,CAAC,QAAQ,CAAC,EAAG,EAAE,EAAE,CAAC,GAAG,CAAC,EAC5B,MAAM,CAAC,QAAQ,CAAC,CAAE,EAAE,EAAE,CAAC,EACvB,MAAM,CAAC,QAAQ,CAAC,CAAE,EAAE,EAAE,CAAC,EACvB,MAAM,CAAC,QAAQ,CAAC,EAAG,EAAE,EAAE,CAAC,EACxB,MAAM,CAAC,QAAQ,CAAC,CAAE,EAAE,EAAE,CAAC,CACxB,CAAC;IACF,2EAA2E;IAC3E,6EAA6E;IAC7E,MAAM,MAAM,GAAG,IAAI,IAAI,CAAC,EAAE,CAAC,CAAC;IAC5B,IACE,MAAM,CAAC,cAAc,EAAE,KAAK,MAAM,CAAC,QAAQ,CAAC,CAAE,EAAE,EAAE,CAAC;QACnD,MAAM,CAAC,WAAW,EAAE,KAAK,MAAM,CAAC,QAAQ,CAAC,EAAG,EAAE,EAAE,CAAC,GAAG,CAAC;QACrD,MAAM,CAAC,UAAU,EAAE,KAAK,MAAM,CAAC,QAAQ,CAAC,CAAE,EAAE,EAAE,CAAC;QAC/C,MAAM,CAAC,WAAW,EAAE,KAAK,MAAM,CAAC,QAAQ,CAAC,CAAE,EAAE,EAAE,CAAC;QAChD,MAAM,CAAC,aAAa,EAAE,KAAK,MAAM,CAAC,QAAQ,CAAC,EAAG,EAAE,EAAE,CAAC;QACnD,MAAM,CAAC,aAAa,EAAE,KAAK,MAAM,CAAC,QAAQ,CAAC,CAAE,EAAE,EAAE,CAAC,EAClD,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,cAAc,CAC5B,UAAuD,EAAE;IAEzD,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,IAAI,mBAAmB,EAAE,CAAC;IACrD,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;IACvC,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;QACtB,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,MAAM,GAAG,qBAAqB,CAAC,QAAQ,CAAC,sBAAsB,CAAC,CAAC;IACtE,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,sBAAsB,CAAC,EAAE,CAAC;QACtD,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;IACnD,CAAC;IACD,MAAM,OAAO,GAAG,QAAQ,CAAC,oBAAoB,IAAI,uBAAuB,EAAE,CAAC;IAC3E,MAAM,KAAK,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC;IAC1C,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,IAAI,mBAAmB,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;IACvE,yEAAyE;IACzE,4EAA4E;IAC5E,mEAAmE;IACnE,cAAc,CAAC,OAAO,EAAE,KAAK,EAAE;QAC7B,IAAI,EAAE,MAAM;QACZ,GAAG,EAAE,IAAI;QACT,sBAAsB,EAAE,QAAQ,CAAC,sBAAsB,IAAI,IAAI;KAChE,CAAC,CAAC;IACH,OAAO;QACL,IAAI,EAAE,MAAM;QACZ,EAAE,EAAE,sBAAsB;QAC1B,OAAO,EAAE,CAAC,0BAA0B,MAAM,MAAM,sBAAsB,EAAE,CAAC;KAC1E,CAAC;AACJ,CAAC;AAED,2EAA2E;AAC3E,SAAS,aAAa,CAAC,KAAe;IACpC,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1E,CAAC;AAED,oDAAoD;AACpD,SAAS,cAAc,CAAC,GAAS;IAC/B,0EAA0E;IAC1E,OAAO,GAAG,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;AACrD,CAAC;AAED,mFAAmF;AACnF,SAAS,OAAO,CAAC,GAAW,EAAE,MAAc;IAC1C,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,EAAE,EAAE,OAAO,IAAI,CAAC,EAAE,CAAC;QACjD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAC9E,IAAI,CAAC;YACH,MAAM,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;YAC9C,OAAO,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC;QAC1B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACrD,SAAS;YACX,CAAC;YACD,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;AAClE,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,aAAa,CAC3B,iBAAyB,EACzB,UAAoC,EAAE;IAEtC,MAAM,QAAQ,GAAG,aAAa,CAAC,OAAO,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC;IACrD,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;QACtB,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACtB,CAAC;IACD,MAAM,QAAQ,GAAG,QAAQ,CAAC,oBAAoB,CAAC;IAC/C,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACtB,CAAC;IACD,OAAO,CAAC,QAAQ,KAAK,iBAAiB,EAAE,QAAQ,CAAC,CAAC;AACpD,CAAC;AAED,MAAM,UAAU,GAAG,2BAA2B,CAAC;AAE/C;;;;;GAKG;AACH,SAAS,aAAa,CAAC,OAAe;IACpC,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACvC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAE,EAAE,EAAE,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAE,EAAE,EAAE,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAE,EAAE,EAAE,CAAC,CAAC,CAAC;AAC1G,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAC/B,iBAAyB,EACzB,QAAuB;IAEvB,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;QACtB,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,IAAI,QAAQ,KAAK,iBAAiB,EAAE,CAAC;QACnC,OAAO,OAAO,CAAC;IACjB,CAAC;IACD,MAAM,GAAG,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;IACpC,MAAM,IAAI,GAAG,aAAa,CAAC,iBAAiB,CAAC,CAAC;IAC9C,IAAI,GAAG,KAAK,IAAI,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;QAClC,OAAO,aAAa,CAAC;IACvB,CAAC;IACD,IAAI,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,CAAC;QACxB,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,OAAO,WAAW,CAAC;AACrB,CAAC;AAED,6EAA6E;AAC7E,SAAS,QAAQ,CAAC,CAA2B,EAAE,CAA2B;IACxE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QACrC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC;QACjB,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC;QACjB,IAAI,EAAE,GAAG,EAAE;YAAE,OAAO,IAAI,CAAC;QACzB,IAAI,EAAE,GAAG,EAAE;YAAE,OAAO,KAAK,CAAC;IAC5B,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,sFAAsF;AACtF,SAAS,qBAAqB,CAAC,GAAW;IACxC,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;QAChG,MAAM,OAAO,GAAI,IAA8B,CAAC,OAAO,CAAC;QACxD,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC;YAClD,OAAO,OAAO,CAAC,IAAI,EAAE,CAAC;QACxB,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,wDAAwD;IAC1D,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,4BAA4B,CAAC,SAAiB;IAC5D,IAAI,GAAG,GAAG,SAAS,CAAC;IACpB,SAAS,CAAC;QACR,MAAM,KAAK,GAAG,qBAAqB,CAAC,GAAG,CAAC,CAAC;QACzC,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YACnB,OAAO,KAAK,CAAC;QACf,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACjC,IAAI,MAAM,KAAK,GAAG,EAAE,CAAC;YACnB,OAAO,IAAI,CAAC,CAAC,8BAA8B;QAC7C,CAAC;QACD,GAAG,GAAG,MAAM,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,uBAAuB,CAAC,SAAyB;IAC/D,IAAI,SAAS,IAAI,IAAI,EAAE,CAAC;QACtB,OAAO,qBAAqB,CAAC,SAAS,CAAC,IAAI,OAAO,CAAC;IACrD,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1D,OAAO,4BAA4B,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC;AACvD,CAAC"}
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Remove empty directories under a root, deepest first.
3
+ *
4
+ * ## Why this exists as a shared helper
5
+ *
6
+ * A generator that stops writing into a tree leaves the tree's DIRECTORIES
7
+ * behind. Measured 2026-08-21 while extending the ADR-236 partition to the
8
+ * colon-form commands: after the generator was gated, `.claude/commands/`
9
+ * held **0 `.md` files and 40 empty cluster directories** — and
10
+ * `check_single_delivery` counts directory NAMES, so it still reported 40
11
+ * overlapping commands against a layer that delivered none. A partition that
12
+ * stops the writes and leaves the shape is invisible to the gate that is
13
+ * supposed to confirm it.
14
+ *
15
+ * `condense.ts` already carried this loop inline for the skills tree. It is
16
+ * lifted here rather than copied because the second caller is what turns an
17
+ * inline block into a shape two producers must agree on — and because
18
+ * `condense.ts` sits above `check_source_size_budget`'s ceiling, where a
19
+ * shrink-only ratchet refuses even a small addition.
20
+ *
21
+ * Best-effort by construction: a race or a permission error on one directory is
22
+ * swallowed, matching the inline original. Pruning is cleanup, never a gate.
23
+ *
24
+ * ## Symlinks: MEASURED, because a neutral review split on it
25
+ *
26
+ * One seat called an unguarded recursion a merge blocker (a directory symlink
27
+ * pointing at an ancestor would loop forever); the other called the finding
28
+ * false, on the grounds that `Dirent.isDirectory()` does not follow the target.
29
+ * A vote cannot settle that, so it was probed — `readdirSync(dir, {withFileTypes:
30
+ * true})` over a real symlink-to-directory on darwin, Node 26:
31
+ *
32
+ * link isDirectory=false isSymbolicLink=true
33
+ * real isDirectory=true isSymbolicLink=false
34
+ *
35
+ * `Dirent` carries `lstat` semantics, so the walk below cannot descend into a
36
+ * symlink at all and no loop is reachable — and no inode set is needed. The
37
+ * second seat was right. Recorded rather than fixed, so the next reader does not
38
+ * re-raise it: a defensive `!e.isSymbolicLink()` here would be dead code
39
+ * asserting something the type already guarantees.
40
+ *
41
+ * The same property is why this is safe on a tree of symlinks: `.claude/commands`
42
+ * holds symlinks into `src/domains/**`, and pruning must not follow one out of
43
+ * the tree it was pointed at.
44
+ */
45
+ import * as fs from 'node:fs';
46
+ import * as path from 'node:path';
47
+ /** @returns the number of directories removed. */
48
+ export function pruneEmptyDirs(root) {
49
+ let removed = 0;
50
+ const walk = (dir) => {
51
+ let entries;
52
+ try {
53
+ entries = fs.readdirSync(dir, { withFileTypes: true });
54
+ }
55
+ catch {
56
+ return;
57
+ }
58
+ for (const e of entries) {
59
+ if (e.isDirectory())
60
+ walk(path.join(dir, e.name));
61
+ }
62
+ try {
63
+ if (fs.readdirSync(dir).length === 0) {
64
+ fs.rmdirSync(dir);
65
+ removed += 1;
66
+ }
67
+ }
68
+ catch {
69
+ /* race or permission — cleanup is best-effort, mirrors the inline original */
70
+ }
71
+ };
72
+ let top;
73
+ try {
74
+ top = fs.readdirSync(root, { withFileTypes: true });
75
+ }
76
+ catch {
77
+ return 0;
78
+ }
79
+ for (const e of top) {
80
+ if (e.isDirectory())
81
+ walk(path.join(root, e.name));
82
+ }
83
+ return removed;
84
+ }
85
+ //# sourceMappingURL=prune_empty_dirs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prune_empty_dirs.js","sourceRoot":"","sources":["../../../src/scripts/_lib/prune_empty_dirs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AACH,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,kDAAkD;AAClD,MAAM,UAAU,cAAc,CAAC,IAAY;IACvC,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,MAAM,IAAI,GAAG,CAAC,GAAW,EAAQ,EAAE;QAC/B,IAAI,OAAoB,CAAC;QACzB,IAAI,CAAC;YACD,OAAO,GAAG,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3D,CAAC;QAAC,MAAM,CAAC;YACL,OAAO;QACX,CAAC;QACD,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;YACtB,IAAI,CAAC,CAAC,WAAW,EAAE;gBAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QACtD,CAAC;QACD,IAAI,CAAC;YACD,IAAI,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACnC,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;gBAClB,OAAO,IAAI,CAAC,CAAC;YACjB,CAAC;QACL,CAAC;QAAC,MAAM,CAAC;YACL,8EAA8E;QAClF,CAAC;IACL,CAAC,CAAC;IACF,IAAI,GAAgB,CAAC;IACrB,IAAI,CAAC;QACD,GAAG,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IACxD,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,CAAC,CAAC;IACb,CAAC;IACD,KAAK,MAAM,CAAC,IAAI,GAAG,EAAE,CAAC;QAClB,IAAI,CAAC,CAAC,WAAW,EAAE;YAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IACvD,CAAC;IACD,OAAO,OAAO,CAAC;AACnB,CAAC"}