@topogram/cli 0.3.64 → 0.3.65

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 (245) hide show
  1. package/package.json +1 -1
  2. package/src/adoption/plan/index.js +703 -0
  3. package/src/adoption/plan.js +12 -703
  4. package/src/agent-ops/query-builders/auth.js +375 -0
  5. package/src/agent-ops/query-builders/change-risk/change-plan.js +123 -0
  6. package/src/agent-ops/query-builders/change-risk/import-plan.js +49 -0
  7. package/src/agent-ops/query-builders/change-risk/maintained.js +286 -0
  8. package/src/agent-ops/query-builders/change-risk/review-packets.js +123 -0
  9. package/src/agent-ops/query-builders/change-risk/risk.js +189 -0
  10. package/src/agent-ops/query-builders/change-risk.js +25 -0
  11. package/src/agent-ops/query-builders/common.js +149 -0
  12. package/src/agent-ops/query-builders/maintained-risk.js +539 -0
  13. package/src/agent-ops/query-builders/maintained-shared.js +120 -0
  14. package/src/agent-ops/query-builders/multi-agent.js +547 -0
  15. package/src/agent-ops/query-builders/projection-impacts.js +514 -0
  16. package/src/agent-ops/query-builders/work-packets.js +417 -0
  17. package/src/agent-ops/query-builders/workflow-context-shared.js +300 -0
  18. package/src/agent-ops/query-builders/workflow-context.js +398 -0
  19. package/src/agent-ops/query-builders/workflow-presets-core.js +676 -0
  20. package/src/agent-ops/query-builders/workflow-presets.js +341 -0
  21. package/src/agent-ops/query-builders.d.ts +26 -26
  22. package/src/agent-ops/query-builders.js +42 -5021
  23. package/src/catalog/constants.js +10 -0
  24. package/src/catalog/copy.js +60 -0
  25. package/src/catalog/diagnostics.js +15 -0
  26. package/src/catalog/entries.js +42 -0
  27. package/src/catalog/files.js +67 -0
  28. package/src/catalog/provenance.js +122 -0
  29. package/src/catalog/source.js +150 -0
  30. package/src/catalog/validation.js +252 -0
  31. package/src/catalog.d.ts +2 -0
  32. package/src/catalog.js +18 -746
  33. package/src/cli/commands/catalog/check.js +31 -0
  34. package/src/cli/commands/catalog/copy.js +59 -0
  35. package/src/cli/commands/catalog/doctor.js +248 -0
  36. package/src/cli/commands/catalog/help.js +21 -0
  37. package/src/cli/commands/catalog/list.js +52 -0
  38. package/src/cli/commands/catalog/runner.js +92 -0
  39. package/src/cli/commands/catalog/shared.js +17 -0
  40. package/src/cli/commands/catalog/show.js +134 -0
  41. package/src/cli/commands/catalog.js +30 -615
  42. package/src/cli/commands/generator-policy/package-info.js +162 -0
  43. package/src/cli/commands/generator-policy/payloads.js +372 -0
  44. package/src/cli/commands/generator-policy/printers.js +159 -0
  45. package/src/cli/commands/generator-policy/runner.js +81 -0
  46. package/src/cli/commands/generator-policy/shared.js +39 -0
  47. package/src/cli/commands/generator-policy.js +15 -783
  48. package/src/cli/commands/import/adopt.js +170 -0
  49. package/src/cli/commands/import/check.js +91 -0
  50. package/src/cli/commands/import/diff.js +84 -0
  51. package/src/cli/commands/import/help.js +47 -0
  52. package/src/cli/commands/import/paths.js +277 -0
  53. package/src/cli/commands/import/plan.js +284 -0
  54. package/src/cli/commands/import/refresh.js +470 -0
  55. package/src/cli/commands/import/status-history.js +196 -0
  56. package/src/cli/commands/import/workspace.js +230 -0
  57. package/src/cli/commands/import.js +33 -1732
  58. package/src/cli/commands/package/constants.js +17 -0
  59. package/src/cli/commands/package/doctor.js +240 -0
  60. package/src/cli/commands/package/help.js +27 -0
  61. package/src/cli/commands/package/lockfile.js +135 -0
  62. package/src/cli/commands/package/npm.js +97 -0
  63. package/src/cli/commands/package/reporting.js +35 -0
  64. package/src/cli/commands/package/runner.js +33 -0
  65. package/src/cli/commands/package/shared.js +9 -0
  66. package/src/cli/commands/package/update-cli.js +252 -0
  67. package/src/cli/commands/package/versions.js +35 -0
  68. package/src/cli/commands/package.js +29 -813
  69. package/src/cli/commands/query/change-plan.js +68 -0
  70. package/src/cli/commands/query/definitions.js +202 -0
  71. package/src/cli/commands/query/import-adopt.js +121 -0
  72. package/src/cli/commands/query/runner/artifacts.js +102 -0
  73. package/src/cli/commands/query/runner/boundaries.js +211 -0
  74. package/src/cli/commands/query/runner/change.js +182 -0
  75. package/src/cli/commands/query/runner/import-adopt.js +111 -0
  76. package/src/cli/commands/query/runner/index.js +31 -0
  77. package/src/cli/commands/query/runner/output.js +12 -0
  78. package/src/cli/commands/query/runner/workflow.js +241 -0
  79. package/src/cli/commands/query/runner.js +3 -0
  80. package/src/cli/commands/query/workflow-context.js +5 -0
  81. package/src/cli/commands/query/workspace.js +274 -0
  82. package/src/cli/commands/query.js +9 -1300
  83. package/src/cli/commands/template/baseline.js +100 -0
  84. package/src/cli/commands/template/check.js +466 -0
  85. package/src/cli/commands/template/constants.js +8 -0
  86. package/src/cli/commands/template/diagnostics.js +26 -0
  87. package/src/cli/commands/template/help.js +28 -0
  88. package/src/cli/commands/template/lifecycle.js +404 -0
  89. package/src/cli/commands/template/list-show.js +287 -0
  90. package/src/cli/commands/template/policy.js +422 -0
  91. package/src/cli/commands/template/shared.js +127 -0
  92. package/src/cli/commands/template/updates.js +352 -0
  93. package/src/cli/commands/template.js +41 -2143
  94. package/src/generator/api/contracts.js +497 -0
  95. package/src/generator/api/metadata.js +221 -0
  96. package/src/generator/api/openapi.js +559 -0
  97. package/src/generator/api/schema.js +124 -0
  98. package/src/generator/api/types.d.ts +98 -0
  99. package/src/generator/api.js +3 -1195
  100. package/src/generator/context/shared/domain-sdlc.js +282 -0
  101. package/src/generator/context/shared/maintained-boundary.js +665 -0
  102. package/src/generator/context/shared/metrics.js +85 -0
  103. package/src/generator/context/shared/primitives.js +64 -0
  104. package/src/generator/context/shared/relationships.js +453 -0
  105. package/src/generator/context/shared/summaries.js +263 -0
  106. package/src/generator/context/shared/types.d.ts +207 -0
  107. package/src/generator/context/shared.d.ts +42 -0
  108. package/src/generator/context/shared.js +80 -1390
  109. package/src/generator/context/slice/core.js +397 -0
  110. package/src/generator/context/slice/sdlc.js +417 -0
  111. package/src/generator/context/slice/ui-packets.js +183 -0
  112. package/src/generator/context/slice.js +2 -859
  113. package/src/generator/registry/index.js +507 -0
  114. package/src/generator/registry.js +18 -504
  115. package/src/generator/runtime/environment/index.js +666 -0
  116. package/src/generator/runtime/environment.js +4 -666
  117. package/src/generator/runtime/runtime-check/index.js +554 -0
  118. package/src/generator/runtime/runtime-check.js +4 -554
  119. package/src/generator/runtime/shared/index.js +572 -0
  120. package/src/generator/runtime/shared.js +19 -570
  121. package/src/generator/shared.d.ts +2 -0
  122. package/src/generator/surfaces/shared.d.ts +3 -0
  123. package/src/generator/widget-conformance/behavior-report.js +258 -0
  124. package/src/generator/widget-conformance/checks.js +371 -0
  125. package/src/generator/widget-conformance/projection-context.js +200 -0
  126. package/src/generator/widget-conformance/report.js +166 -0
  127. package/src/generator/widget-conformance/types.d.ts +121 -0
  128. package/src/generator/widget-conformance.js +3 -824
  129. package/src/import/core/context.d.ts +3 -0
  130. package/src/import/core/contracts.d.ts +1 -0
  131. package/src/import/core/registry.d.ts +4 -0
  132. package/src/import/core/runner/candidates.js +217 -0
  133. package/src/import/core/runner/options.js +22 -0
  134. package/src/import/core/runner/reports.js +50 -0
  135. package/src/import/core/runner/run.js +79 -0
  136. package/src/import/core/runner/tracks.js +150 -0
  137. package/src/import/core/runner/ui-drafts.js +337 -0
  138. package/src/import/core/runner.js +3 -698
  139. package/src/import/core/shared/api-routes.js +221 -0
  140. package/src/import/core/shared/candidates.js +97 -0
  141. package/src/import/core/shared/files.js +177 -0
  142. package/src/import/core/shared/next-app.js +389 -0
  143. package/src/import/core/shared/types.d.ts +51 -0
  144. package/src/import/core/shared/ui-routes.js +230 -0
  145. package/src/import/core/shared.js +60 -861
  146. package/src/new-project/constants.js +128 -0
  147. package/src/new-project/create.js +83 -0
  148. package/src/new-project/json.js +28 -0
  149. package/src/new-project/metadata.js +96 -0
  150. package/src/new-project/package-spec.js +161 -0
  151. package/src/new-project/project-files.js +348 -0
  152. package/src/new-project/template-policy.js +269 -0
  153. package/src/new-project/template-resolution.js +368 -0
  154. package/src/new-project/template-snapshots.js +430 -0
  155. package/src/new-project/template-updates.js +512 -0
  156. package/src/new-project/types.d.ts +83 -0
  157. package/src/new-project.js +6 -2277
  158. package/src/parser.d.ts +87 -1
  159. package/src/parser.js +118 -0
  160. package/src/policy/review-boundaries.d.ts +15 -0
  161. package/src/project-config/index.js +564 -0
  162. package/src/project-config.js +19 -561
  163. package/src/resolver/enrich/acceptance-criterion.js +2 -0
  164. package/src/resolver/enrich/bug.js +2 -0
  165. package/src/resolver/enrich/pitch.js +2 -0
  166. package/src/resolver/enrich/requirement.js +2 -0
  167. package/src/resolver/enrich/task.js +2 -0
  168. package/src/resolver/index.js +19 -2089
  169. package/src/resolver/normalize.js +384 -1
  170. package/src/resolver/plans.js +168 -0
  171. package/src/resolver/projections-api.js +494 -0
  172. package/src/resolver/projections-db.js +133 -0
  173. package/src/resolver/projections-ui.js +317 -0
  174. package/src/resolver/shapes.js +251 -0
  175. package/src/resolver/shared.js +278 -0
  176. package/src/resolver/widgets.js +132 -0
  177. package/src/template-trust/constants.js +62 -0
  178. package/src/template-trust/content.js +258 -0
  179. package/src/template-trust/diff.js +92 -0
  180. package/src/template-trust/policy.js +61 -0
  181. package/src/template-trust/record.js +90 -0
  182. package/src/template-trust/status.js +182 -0
  183. package/src/template-trust.js +24 -687
  184. package/src/text-helpers.d.ts +1 -0
  185. package/src/topogram-types.d.ts +69 -0
  186. package/src/validator/common.js +488 -0
  187. package/src/validator/data-model.js +237 -0
  188. package/src/validator/docs.js +167 -0
  189. package/src/validator/expressions.js +146 -1
  190. package/src/validator/index.d.ts +23 -0
  191. package/src/validator/index.js +32 -3585
  192. package/src/validator/kinds.d.ts +41 -0
  193. package/src/validator/kinds.js +2 -0
  194. package/src/validator/model-helpers.js +46 -0
  195. package/src/validator/per-kind/acceptance-criterion.js +5 -0
  196. package/src/validator/per-kind/bug.js +6 -0
  197. package/src/validator/per-kind/domain.js +15 -2
  198. package/src/validator/per-kind/pitch.js +7 -0
  199. package/src/validator/per-kind/requirement.js +5 -0
  200. package/src/validator/per-kind/task.js +7 -0
  201. package/src/validator/per-kind/widget.js +14 -0
  202. package/src/validator/projections/api-http-async.js +410 -0
  203. package/src/validator/projections/api-http-authz.js +88 -0
  204. package/src/validator/projections/api-http-core.js +205 -0
  205. package/src/validator/projections/api-http-policies.js +339 -0
  206. package/src/validator/projections/api-http-responses.js +233 -0
  207. package/src/validator/projections/api-http.js +44 -0
  208. package/src/validator/projections/db.js +353 -0
  209. package/src/validator/projections/generator-defaults.js +45 -0
  210. package/src/validator/projections/helpers.js +87 -0
  211. package/src/validator/projections/ui-helpers.js +214 -0
  212. package/src/validator/projections/ui-navigation.js +344 -0
  213. package/src/validator/projections/ui-structure.js +364 -0
  214. package/src/validator/projections/ui-widgets.js +493 -0
  215. package/src/validator/projections/ui.js +46 -0
  216. package/src/validator/registry.js +48 -1
  217. package/src/validator/utils.d.ts +20 -0
  218. package/src/validator/utils.js +115 -12
  219. package/src/widget-behavior.d.ts +1 -0
  220. package/src/workflows/import-app/api/collect.js +221 -0
  221. package/src/workflows/import-app/api/openapi.js +257 -0
  222. package/src/workflows/import-app/api/routes.js +327 -0
  223. package/src/workflows/import-app/api/sources.js +22 -0
  224. package/src/workflows/import-app/api.js +2 -797
  225. package/src/workflows/reconcile/adoption-plan/build.js +208 -0
  226. package/src/workflows/reconcile/adoption-plan/dependencies.js +75 -0
  227. package/src/workflows/reconcile/adoption-plan/outputs.js +143 -0
  228. package/src/workflows/reconcile/adoption-plan/paths.js +58 -0
  229. package/src/workflows/reconcile/adoption-plan/projection-patches.js +177 -0
  230. package/src/workflows/reconcile/adoption-plan/reasons.js +107 -0
  231. package/src/workflows/reconcile/adoption-plan.js +30 -740
  232. package/src/workflows/reconcile/auth/closures.js +115 -0
  233. package/src/workflows/reconcile/auth/formatters.js +142 -0
  234. package/src/workflows/reconcile/auth/inference.js +330 -0
  235. package/src/workflows/reconcile/auth/roles.js +122 -0
  236. package/src/workflows/reconcile/auth.js +35 -690
  237. package/src/workflows/reconcile/bundle-core/index.js +600 -0
  238. package/src/workflows/reconcile/bundle-core.js +12 -598
  239. package/src/workflows/reconcile/canonical-surface.js +1 -1
  240. package/src/workflows/reconcile/impacts/adoption-plan.js +192 -0
  241. package/src/workflows/reconcile/impacts/indexes.js +101 -0
  242. package/src/workflows/reconcile/impacts/patches.js +252 -0
  243. package/src/workflows/reconcile/impacts/reports.js +80 -0
  244. package/src/workflows/reconcile/impacts.js +14 -623
  245. package/src/workspace-docs.d.ts +29 -0
@@ -1,742 +1,32 @@
1
1
  // @ts-check
2
- import fs from "node:fs";
3
- import path from "node:path";
4
2
 
5
- import { ensureTrailingNewline } from "../../text-helpers.js";
6
- import { adoptionItemKey } from "../../adoption/plan.js";
7
- import {
8
- applyDocLinkPatchToMarkdown as applyDocLinkPatchToMarkdownReconcile,
9
- applyDocMetadataPatchToMarkdown as applyDocMetadataPatchToMarkdownReconcile
10
- } from "../../reconcile/docs.js";
11
- import { confidenceRank } from "../docs.js";
12
- import { dashedTopogramId } from "./ids.js";
13
- import { readJsonIfExists, readTextIfExists } from "../shared.js";
14
- import { buildProjectionReviewGroups, buildUiReviewGroups, buildWorkflowReviewGroups } from "../../adoption/review-groups.js";
15
- import { buildProjectionImpacts, buildUiImpacts, buildWorkflowImpacts } from "./impacts.js";
16
-
17
- /** @param {string} kind @param {string} item @returns {any} */
18
- export function canonicalRelativePathForItem(kind, item) {
19
- switch (kind) {
20
- case "actor":
21
- return `actors/${dashedTopogramId(item)}.tg`;
22
- case "role":
23
- return `roles/${dashedTopogramId(item)}.tg`;
24
- case "enum":
25
- return `enums/enum-${dashedTopogramId(String(item || "").replace(/^enum_/, ""))}.tg`;
26
- case "entity":
27
- return `entities/${dashedTopogramId(item)}.tg`;
28
- case "shape":
29
- return `shapes/${dashedTopogramId(item)}.tg`;
30
- case "capability":
31
- return `capabilities/${dashedTopogramId(item)}.tg`;
32
- case "widget":
33
- return `widgets/${dashedTopogramId(item)}.tg`;
34
- case "verification":
35
- return `verifications/${dashedTopogramId(item)}.tg`;
36
- default:
37
- return null;
38
- }
39
- }
40
-
41
- /** @param {string} kind @param {string} item @returns {any} */
42
- export function canonicalDisplayPathForItem(kind, item) {
43
- const relativePath = canonicalRelativePathForItem(kind, item);
44
- return relativePath ? `topogram/${relativePath}` : null;
45
- }
46
-
47
- /** @param {CandidateBundle} bundle @param {string} kind @param {WorkflowRecord} item @returns {any} */
48
- export function candidateSourcePathForItem(bundle, kind, item) {
49
- const base = `candidates/reconcile/model/bundles/${bundle.slug}`;
50
- switch (kind) {
51
- case "actor":
52
- return `${base}/actors/${item}.tg`;
53
- case "role":
54
- return `${base}/roles/${item}.tg`;
55
- case "enum":
56
- return `${base}/enums/${item}.tg`;
57
- case "entity":
58
- return `${base}/entities/${item}.tg`;
59
- case "shape":
60
- return `${base}/shapes/${item}.tg`;
61
- case "capability":
62
- return `${base}/capabilities/${item}.tg`;
63
- case "widget":
64
- return `${base}/widgets/${item}.tg`;
65
- case "verification":
66
- return `${base}/verifications/${item}.tg`;
67
- default:
68
- return `${base}/README.md`;
69
- }
70
- }
71
-
72
- /** @param {WorkflowRecord} step @returns {any} */
73
- export function reasonForAdoptionItem(step) {
74
- switch (step.action) {
75
- case "promote_actor":
76
- return "Promote this imported actor into canonical Topogram.";
77
- case "promote_role":
78
- return "Promote this imported role into canonical Topogram.";
79
- case "promote_entity":
80
- return "No canonical entity exists for this imported concept.";
81
- case "promote_enum":
82
- return step.target ? `Promote this enum to support merged concept ${step.target}.` : "Promote this imported enum into canonical Topogram.";
83
- case "promote_shape":
84
- return step.target ? `Promote this shape to support concept ${step.target}.` : "Promote this imported shape into canonical Topogram.";
85
- case "promote_capability":
86
- return "Promote this imported capability into canonical Topogram.";
87
- case "promote_widget":
88
- return "Promote this imported reusable UI widget into canonical Topogram.";
89
- case "merge_capability_into_existing_entity":
90
- return `Adopt this capability while preserving the existing canonical entity ${step.target}.`;
91
- case "promote_doc":
92
- return "Promote this imported companion doc into canonical Topogram docs.";
93
- case "promote_workflow_doc":
94
- return "Promote this imported workflow doc into canonical Topogram workflow docs.";
95
- case "promote_workflow_decision":
96
- return "Promote this imported workflow decision into canonical Topogram decisions.";
97
- case "promote_verification":
98
- return "Promote this imported verification into canonical Topogram verifications.";
99
- case "promote_ui_report":
100
- return "Promote this imported UI review report into canonical Topogram docs.";
101
- case "apply_projection_permission_patch":
102
- return `Apply inferred permission-based auth rules to canonical projection ${step.target}.`;
103
- case "apply_projection_auth_patch":
104
- return `Apply inferred claim-based auth rules to canonical projection ${step.target}.`;
105
- case "apply_projection_ownership_patch":
106
- return `Apply inferred ownership-based auth rules to canonical projection ${step.target}.`;
107
- case "apply_doc_link_patch":
108
- return "Apply this suggested actor/role metadata update to an existing canonical doc.";
109
- case "apply_doc_metadata_patch":
110
- return "Apply this suggested safe metadata update to an existing canonical doc.";
111
- case "skip_duplicate_shape":
112
- return step.target ? `Skip this shape because it duplicates canonical shape ${step.target}.` : "Skip this shape because it duplicates existing canonical surface.";
113
- default:
114
- return "Review this adoption suggestion before applying it.";
115
- }
116
- }
117
-
118
- /** @param {WorkflowRecord} step @returns {any} */
119
- export function recommendationForAdoptionItem(step) {
120
- if (step.action === "apply_doc_link_patch") {
121
- return `Update \`${step.target}\` with the suggested related actor/role links.`;
122
- }
123
- if (step.action === "apply_doc_metadata_patch") {
124
- return `Update \`${step.target}\` with the suggested safe metadata changes.`;
125
- }
126
- if (step.action === "apply_projection_permission_patch") {
127
- return `Update \`${step.target}\` with inferred permission auth rules for ${(step.related_capabilities || []).map((/** @type {any} */ item) => `\`${item}\``).join(", ") || "the related capabilities"}.`;
128
- }
129
- if (step.action === "apply_projection_auth_patch") {
130
- return `Update \`${step.target}\` with inferred claim auth rules for ${(step.related_capabilities || []).map((/** @type {any} */ item) => `\`${item}\``).join(", ") || "the related capabilities"}.`;
131
- }
132
- if (step.action === "apply_projection_ownership_patch") {
133
- return `Update \`${step.target}\` with inferred ownership auth rules for ${(step.related_capabilities || []).map((/** @type {any} */ item) => `\`${item}\``).join(", ") || "the related capabilities"}.`;
134
- }
135
- if (step.action === "promote_widget") {
136
- return "Promote this reviewed widget candidate before binding or reusing it from canonical projections.";
137
- }
138
- if (!["promote_actor", "promote_role"].includes(step.action)) {
139
- return null;
140
- }
141
- const kindLabel = step.action === "promote_actor" ? "actor" : "role";
142
- /** @type {any[]} */
143
- const linkHints = [];
144
- if ((step.related_docs || []).length > 0) {
145
- linkHints.push(`link to docs ${step.related_docs.map((/** @type {any} */ item) => `\`${item}\``).join(", ")}`);
146
- }
147
- if ((step.related_capabilities || []).length > 0) {
148
- linkHints.push(`check capabilities ${step.related_capabilities.map((/** @type {any} */ item) => `\`${item}\``).join(", ")}`);
149
- }
150
- return `Promote this ${kindLabel}${step.confidence ? ` (${step.confidence})` : ""}${linkHints.length ? ` and ${linkHints.join("; ")}` : ""}.`;
151
- }
152
-
153
- /** @param {WorkflowRecord} item @returns {any} */
154
- export function formatDocLinkSuggestionInline(item) {
155
- return `doc \`${item.doc_id}\`` +
156
- `${item.add_related_actors?.length ? ` add-actors=${item.add_related_actors.map((/** @type {any} */ entry) => `\`${entry}\``).join(", ")}` : ""}` +
157
- `${item.add_related_roles?.length ? ` add-roles=${item.add_related_roles.map((/** @type {any} */ entry) => `\`${entry}\``).join(", ")}` : ""}` +
158
- `${item.add_related_capabilities?.length ? ` add-capabilities=${item.add_related_capabilities.map((/** @type {any} */ entry) => `\`${entry}\``).join(", ")}` : ""}` +
159
- `${item.add_related_rules?.length ? ` add-rules=${item.add_related_rules.map((/** @type {any} */ entry) => `\`${entry}\``).join(", ")}` : ""}` +
160
- `${item.add_related_workflows?.length ? ` add-workflows=${item.add_related_workflows.map((/** @type {any} */ entry) => `\`${entry}\``).join(", ")}` : ""}` +
161
- `${item.patch_rel_path ? ` draft=\`${item.patch_rel_path}\`` : ""}`;
162
- }
163
-
164
- /** @param {WorkflowRecord} item @returns {any} */
165
- export function formatDocDriftSummaryInline(item) {
166
- return `doc \`${item.doc_id}\` (${item.recommendation_type}) fields=${item.differing_fields.map((/** @type {any} */ entry) => entry.field).join(", ")} confidence=${item.imported_confidence}`;
167
- }
168
-
169
- /** @param {WorkflowRecord} item @returns {any} */
170
- export function formatDocMetadataPatchInline(item) {
171
- return `doc \`${item.doc_id}\`` +
172
- `${item.summary ? " set-summary=yes" : ""}` +
173
- `${item.success_outcome ? " set-success_outcome=yes" : ""}` +
174
- `${item.actors?.length ? ` add-actors=${item.actors.map((/** @type {any} */ entry) => `\`${entry}\``).join(", ")}` : ""}` +
175
- `${item.patch_rel_path ? ` draft=\`${item.patch_rel_path}\`` : ""}`;
176
- }
177
-
178
- /** @param {WorkflowRecord} step @param {any[]} projectionImpacts @param {any[]} uiImpacts @param {any[]} workflowImpacts @returns {any} */
179
- export function adoptionStatusForStep(step, projectionImpacts = [], uiImpacts = [], workflowImpacts = []) {
180
- if (step.action === "skip_duplicate_shape") {
181
- return "skipped";
182
- }
183
- if (step.action === "apply_projection_permission_patch") {
184
- return "needs_projection_review";
185
- }
186
- if (step.action === "apply_projection_auth_patch") {
187
- return "needs_projection_review";
188
- }
189
- if (step.action === "apply_projection_ownership_patch") {
190
- return "needs_projection_review";
191
- }
192
- if (step.action.includes("capability") && projectionImpacts.length > 0) {
193
- return "needs_projection_review";
194
- }
195
- if (step.action.includes("ui_") && uiImpacts.length > 0) {
196
- return "needs_ui_review";
197
- }
198
- if (step.action.includes("workflow") && workflowImpacts.length > 0) {
199
- return "needs_workflow_review";
200
- }
201
- return "pending";
202
- }
203
-
204
- /** @param {CandidateBundle} bundle @param {WorkflowRecord} step @returns {any} */
205
- export function projectionImpactsForAdoptionItem(bundle, step) {
206
- if (!step.action.includes("capability")) {
207
- return [];
208
- }
209
- return (bundle.projectionImpacts || [])
210
- .filter((/** @type {any} */ impact) => (impact.missing_capabilities || []).includes(step.item))
211
- .map((/** @type {any} */ impact) => ({
212
- projection_id: impact.projection_id,
213
- kind: impact.kind,
214
- projection_type: impact.projection_type,
215
- reason: impact.reason
216
- }));
217
- }
218
-
219
- /** @param {any[]} projectionImpacts @returns {any} */
220
- export function blockingDependenciesForProjectionImpacts(projectionImpacts) {
221
- return projectionImpacts.map((/** @type {any} */ impact) => ({
222
- type: "projection_review",
223
- id: `projection_review:${impact.projection_id}`,
224
- projection_id: impact.projection_id,
225
- kind: impact.kind,
226
- projection_type: impact.projection_type,
227
- reason: impact.reason
228
- }));
229
- }
230
-
231
- /** @param {any[]} uiImpacts @returns {any} */
232
- export function blockingDependenciesForUiImpacts(uiImpacts) {
233
- return uiImpacts.map((/** @type {any} */ impact) => ({
234
- type: "ui_review",
235
- id: `ui_review:${impact.projection_id}`,
236
- projection_id: impact.projection_id,
237
- kind: impact.kind,
238
- projection_type: impact.projection_type,
239
- reason: impact.reason
240
- }));
241
- }
242
-
243
- /** @param {any[]} workflowImpacts @returns {any} */
244
- export function blockingDependenciesForWorkflowImpacts(workflowImpacts) {
245
- return workflowImpacts.map((/** @type {any} */ impact) => ({
246
- type: "workflow_review",
247
- id: impact.review_group_id,
248
- reason: impact.reason
249
- }));
250
- }
251
-
252
- /** @param {CandidateBundle[]} bundles @returns {any} */
253
- export function buildAdoptionPlan(bundles) {
254
- /** @type {any[]} */
255
- const items = [];
256
- for (const bundle of bundles) {
257
- for (const step of bundle.adoptionPlan || []) {
258
- const itemKind =
259
- step.action === "merge_bundle_into_existing_entity" ? "bundle" :
260
- step.action === "apply_projection_permission_patch" ? "projection_permission_patch" :
261
- step.action === "apply_projection_auth_patch" ? "projection_auth_patch" :
262
- step.action === "apply_projection_ownership_patch" ? "projection_ownership_patch" :
263
- step.action.includes("doc") ? "doc" :
264
- step.action.includes("decision") ? "decision" :
265
- step.action.includes("verification") ? "verification" :
266
- step.action.includes("widget") ? "widget" :
267
- step.action.includes("ui_") ? "ui" :
268
- step.action.includes("actor") ? "actor" :
269
- step.action.includes("role") ? "role" :
270
- step.action.includes("enum") ? "enum" :
271
- step.action.includes("shape") ? "shape" :
272
- step.action.includes("capability") ? "capability" :
273
- step.action.includes("entity") ? "entity" :
274
- "bundle";
275
- if (itemKind === "bundle") {
276
- continue;
277
- }
278
- const projectionImpacts = projectionImpactsForAdoptionItem(bundle, step);
279
- const directProjectionBlockingDependencies =
280
- (step.action === "apply_projection_permission_patch" || step.action === "apply_projection_auth_patch" || step.action === "apply_projection_ownership_patch") && step.target
281
- ? blockingDependenciesForProjectionImpacts([
282
- {
283
- projection_id: step.target,
284
- kind: step.projection_kind || "api",
285
- projection_type: null,
286
- reason: `Projection ${step.target} auth rules need explicit review before promotion.`
287
- }
288
- ])
289
- : [];
290
- const uiImpacts = step.action.includes("ui_") ? bundle.uiImpacts || [] : [];
291
- const workflowImpacts = step.action.includes("workflow") ? bundle.workflowImpacts || [] : [];
292
- const blockingDependencies = [
293
- ...blockingDependenciesForProjectionImpacts(projectionImpacts),
294
- ...directProjectionBlockingDependencies,
295
- ...blockingDependenciesForUiImpacts(uiImpacts),
296
- ...blockingDependenciesForWorkflowImpacts(workflowImpacts)
297
- ];
298
- items.push({
299
- bundle: bundle.slug,
300
- item: step.item,
301
- kind: itemKind,
302
- track:
303
- step.action.includes("workflow") ? "workflows" :
304
- step.action.includes("verification") ? "verification" :
305
- step.action.includes("ui_") ? "ui" :
306
- step.action === "apply_projection_permission_patch" ? "projection" :
307
- step.action === "apply_projection_auth_patch" ? "projection" :
308
- step.action === "apply_projection_ownership_patch" ? "projection" :
309
- step.action.includes("doc") ? "docs" :
310
- itemKind,
311
- suggested_action: step.action,
312
- target: step.target || null,
313
- confidence: step.confidence || null,
314
- inference_summary: step.inference_summary || null,
315
- related_docs: step.related_docs || [],
316
- related_capabilities: step.related_capabilities || [],
317
- permission: step.permission || null,
318
- claim: step.claim || null,
319
- claim_value: Object.prototype.hasOwnProperty.call(step, "claim_value") ? step.claim_value : null,
320
- ownership: step.ownership || null,
321
- ownership_field: step.ownership_field || null,
322
- projection_surface: step.projection_surface || null,
323
- status: adoptionStatusForStep(step, projectionImpacts, uiImpacts, workflowImpacts),
324
- source_path: step.source_path || candidateSourcePathForItem(bundle, itemKind, step.item),
325
- canonical_path:
326
- step.action === "skip_duplicate_shape"
327
- ? (step.target ? canonicalDisplayPathForItem("shape", step.target) : null)
328
- : (step.canonical_rel_path ? `topogram/${step.canonical_rel_path}` : canonicalDisplayPathForItem(itemKind, step.item)),
329
- canonical_rel_path: step.canonical_rel_path || canonicalRelativePathForItem(itemKind, step.item),
330
- reason: reasonForAdoptionItem(step),
331
- recommendation: recommendationForAdoptionItem(step),
332
- projection_impacts: projectionImpacts,
333
- ui_impacts: uiImpacts,
334
- workflow_impacts: workflowImpacts,
335
- blocking_dependencies: blockingDependencies
336
- });
337
- }
338
- for (const patch of bundle.projectionPatches || []) {
339
- items.push({
340
- bundle: bundle.slug,
341
- item: `projection_patch:${patch.projection_id}`,
342
- kind: "projection_patch",
343
- track: "projection",
344
- suggested_action: "review_projection_patch",
345
- target: patch.projection_id,
346
- status: "needs_projection_review",
347
- source_path: `candidates/reconcile/model/bundles/${bundle.slug}/${patch.patch_rel_path}`,
348
- canonical_path: null,
349
- canonical_rel_path: null,
350
- reason: patch.reason || `Projection ${patch.projection_id} needs additive review.`,
351
- projection_impacts: [
352
- {
353
- projection_id: patch.projection_id,
354
- kind: patch.kind,
355
- projection_type: patch.projection_type,
356
- missing_capabilities: patch.missing_realizes || []
357
- }
358
- ],
359
- ui_impacts: (patch.missing_screens || []).length > 0 ? [
360
- {
361
- projection_id: patch.projection_id,
362
- kind: patch.kind,
363
- projection_type: patch.projection_type,
364
- missing_screens: patch.missing_screens || []
365
- }
366
- ] : [],
367
- workflow_impacts: [],
368
- blocking_dependencies: blockingDependenciesForProjectionImpacts([
369
- {
370
- projection_id: patch.projection_id,
371
- kind: patch.kind,
372
- projection_type: patch.projection_type,
373
- reason: patch.reason || `Projection ${patch.projection_id} needs additive review.`
374
- }
375
- ])
376
- });
377
- }
378
- for (const patch of bundle.docLinkSuggestions || []) {
379
- items.push({
380
- bundle: bundle.slug,
381
- item: `doc_link_patch:${patch.doc_id}`,
382
- kind: "doc_link_patch",
383
- track: "docs",
384
- suggested_action: "apply_doc_link_patch",
385
- target: patch.doc_id,
386
- status: "pending",
387
- source_path: `candidates/reconcile/model/bundles/${bundle.slug}/${patch.patch_rel_path}`,
388
- canonical_path: patch.canonical_rel_path ? `topogram/${patch.canonical_rel_path}` : null,
389
- canonical_rel_path: patch.canonical_rel_path || null,
390
- reason: `Apply suggested related actor/role links to \`${patch.doc_id}\`.`,
391
- recommendation: recommendationForAdoptionItem({ action: "apply_doc_link_patch", target: patch.doc_id }),
392
- related_docs: [patch.doc_id],
393
- related_actors: patch.add_related_actors || [],
394
- related_roles: patch.add_related_roles || [],
395
- related_capabilities: patch.add_related_capabilities || [],
396
- related_rules: patch.add_related_rules || [],
397
- related_workflows: patch.add_related_workflows || [],
398
- projection_impacts: [],
399
- ui_impacts: [],
400
- workflow_impacts: [],
401
- blocking_dependencies: []
402
- });
403
- }
404
- for (const patch of bundle.docMetadataPatches || []) {
405
- items.push({
406
- bundle: bundle.slug,
407
- item: `doc_metadata_patch:${patch.doc_id}`,
408
- kind: "doc_metadata_patch",
409
- track: "docs",
410
- suggested_action: "apply_doc_metadata_patch",
411
- target: patch.doc_id,
412
- status: "pending",
413
- confidence: patch.imported_confidence || "low",
414
- source_path: `candidates/reconcile/model/bundles/${bundle.slug}/${patch.patch_rel_path}`,
415
- canonical_path: patch.canonical_rel_path ? `topogram/${patch.canonical_rel_path}` : null,
416
- canonical_rel_path: patch.canonical_rel_path || null,
417
- reason: `Apply suggested safe metadata updates to \`${patch.doc_id}\`.`,
418
- recommendation: recommendationForAdoptionItem({ action: "apply_doc_metadata_patch", target: patch.doc_id }),
419
- related_docs: [patch.doc_id],
420
- summary: patch.summary || null,
421
- success_outcome: patch.success_outcome || null,
422
- actors: patch.actors || [],
423
- projection_impacts: [],
424
- ui_impacts: [],
425
- workflow_impacts: [],
426
- blocking_dependencies: []
427
- });
428
- }
429
- }
430
- return items.sort((/** @type {any} */ a, /** @type {any} */ b) =>
431
- a.bundle.localeCompare(b.bundle) ||
432
- confidenceRank(b.confidence || "low") - confidenceRank(a.confidence || "low") ||
433
- a.kind.localeCompare(b.kind) ||
434
- a.item.localeCompare(b.item)
435
- );
436
- }
437
-
438
- const ADOPT_SELECTORS = new Set(["from-plan", "actors", "roles", "enums", "shapes", "entities", "capabilities", "widgets", "docs", "journeys", "workflows", "verification", "ui"]);
439
-
440
- /** @param {WorkspacePaths} paths @returns {any} */
441
- export function readAdoptionPlan(paths) {
442
- return readJsonIfExists(path.join(paths.topogramRoot, "candidates", "reconcile", "adoption-plan.json"));
443
- }
444
-
445
- /** @param {WorkspacePaths} paths @param {any[]} candidateFiles @param {any[]} planItems @param {any[]} selectedItems @param {WorkflowOptions} options @returns {any} */
446
- export function buildCanonicalAdoptionOutputs(paths, candidateFiles, planItems, selectedItems, options = {}) {
447
- const refreshAdopted = Boolean(options.refreshAdopted);
448
- /** @type {WorkflowFiles} */
449
- /** @type {WorkflowFiles} */
450
- const files = {};
451
- /** @type {any[]} */
452
- const refreshedFiles = [];
453
- const selectedSet = new Set(selectedItems);
454
- const itemMap = new Map(planItems.map((/** @type {any} */ item) => [adoptionItemKey(item), item]));
455
- const capabilityBundleSet = new Set(
456
- [...selectedSet]
457
- .map((/** @type {any} */ key) => itemMap.get(key))
458
- .filter((/** @type {any} */ item) => item?.kind === "capability")
459
- .map((/** @type {any} */ item) => item.bundle)
460
- );
461
- for (const item of planItems) {
462
- if (item.kind === "shape" && item.status !== "skipped" && capabilityBundleSet.has(item.bundle)) {
463
- selectedSet.add(adoptionItemKey(item));
464
- }
465
- }
466
- for (const item of planItems) {
467
- if (!selectedSet.has(adoptionItemKey(item))) {
468
- continue;
469
- }
470
- if (item.suggested_action === "skip_duplicate_shape") {
471
- continue;
472
- }
473
- const relativeCanonicalPath = item.canonical_rel_path || canonicalRelativePathForItem(item.kind, item.item);
474
- if (!relativeCanonicalPath) {
475
- continue;
476
- }
477
- const canonicalPath = path.join(paths.topogramRoot, relativeCanonicalPath);
478
- if (item.suggested_action === "apply_doc_link_patch") {
479
- const baseContents = files[relativeCanonicalPath] || (fs.existsSync(canonicalPath) ? fs.readFileSync(canonicalPath, "utf8") : null);
480
- if (!baseContents) {
481
- continue;
482
- }
483
- const updatedContents = applyDocLinkPatchToMarkdownReconcile(baseContents, item);
484
- if (!updatedContents || updatedContents === baseContents) {
485
- continue;
486
- }
487
- files[relativeCanonicalPath] = updatedContents;
488
- refreshedFiles.push(relativeCanonicalPath.replaceAll(path.sep, "/"));
489
- continue;
490
- }
491
- if (item.suggested_action === "apply_doc_metadata_patch") {
492
- const baseContents = files[relativeCanonicalPath] || (fs.existsSync(canonicalPath) ? fs.readFileSync(canonicalPath, "utf8") : null);
493
- if (!baseContents) {
494
- continue;
495
- }
496
- const updatedContents = applyDocMetadataPatchToMarkdownReconcile(baseContents, item);
497
- if (!updatedContents || updatedContents === baseContents) {
498
- continue;
499
- }
500
- files[relativeCanonicalPath] = updatedContents;
501
- refreshedFiles.push(relativeCanonicalPath.replaceAll(path.sep, "/"));
502
- continue;
503
- }
504
- if (item.suggested_action === "apply_projection_permission_patch" || item.suggested_action === "apply_projection_auth_patch" || item.suggested_action === "apply_projection_ownership_patch") {
505
- const baseContents = files[relativeCanonicalPath] || (fs.existsSync(canonicalPath) ? fs.readFileSync(canonicalPath, "utf8") : null);
506
- if (!baseContents) {
507
- continue;
508
- }
509
- const updatedContents = applyProjectionAuthPatchToTopogram(baseContents, item);
510
- if (!updatedContents || updatedContents === baseContents) {
511
- continue;
512
- }
513
- files[relativeCanonicalPath] = updatedContents;
514
- refreshedFiles.push(relativeCanonicalPath.replaceAll(path.sep, "/"));
515
- continue;
516
- }
517
- if (fs.existsSync(canonicalPath)) {
518
- if (!refreshAdopted) {
519
- continue;
520
- }
521
- const existingContents = fs.readFileSync(canonicalPath, "utf8");
522
- const machineManagedImported =
523
- existingContents.startsWith("# imported ") ||
524
- /\bsource_of_truth:\s*imported\b/.test(existingContents);
525
- if (!machineManagedImported) {
526
- continue;
527
- }
528
- }
529
- const candidateContents =
530
- candidateFiles[item.source_path] ||
531
- (item.source_path ? readTextIfExists(path.join(paths.topogramRoot, item.source_path)) : null);
532
- if (!candidateContents) {
533
- continue;
534
- }
535
- files[relativeCanonicalPath] = candidateContents;
536
- if (fs.existsSync(canonicalPath)) {
537
- refreshedFiles.push(relativeCanonicalPath.replaceAll(path.sep, "/"));
538
- }
539
- }
540
- return { files, refreshedFiles: [...new Set(refreshedFiles)].sort() };
541
- }
542
-
543
- /** @param {any[]} planItems @param {any[]} selectedItems @param {any[]} writtenCanonicalFiles @param {string} selector @returns {any} */
544
- export function buildPromotedCanonicalItems(planItems, selectedItems, writtenCanonicalFiles, selector) {
545
- const itemMap = new Map((planItems || []).map((/** @type {any} */ item) => [adoptionItemKey(item), item]));
546
- const writtenSet = new Set((writtenCanonicalFiles || []).map((/** @type {any} */ item) => String(item).replaceAll(path.sep, "/")));
547
- return [...new Set(selectedItems || [])]
548
- .map((/** @type {any} */ key) => itemMap.get(key))
549
- .filter(Boolean)
550
- .filter((/** @type {any} */ item) => item.canonical_rel_path && writtenSet.has(String(item.canonical_rel_path).replaceAll(path.sep, "/")))
551
- .map((/** @type {any} */ item) => ({
552
- selector: selector || null,
553
- bundle: item.bundle,
554
- item: item.item,
555
- kind: item.kind,
556
- track: item.track || null,
557
- source_path: item.source_path || null,
558
- canonical_rel_path: String(item.canonical_rel_path).replaceAll(path.sep, "/"),
559
- canonical_path: item.canonical_path || `topogram/${String(item.canonical_rel_path).replaceAll(path.sep, "/")}`,
560
- suggested_action: item.suggested_action || null
561
- }))
562
- .sort((/** @type {any} */ a, /** @type {any} */ b) =>
563
- (a.bundle || "").localeCompare(b.bundle || "") ||
564
- (a.track || "").localeCompare(b.track || "") ||
565
- (a.kind || "").localeCompare(b.kind || "") ||
566
- (a.item || "").localeCompare(b.item || "")
567
- );
568
- }
569
-
570
- /** @param {any[]} lines @param {string} blockName @returns {any} */
571
- export function ensureProjectionBlock(lines, blockName) {
572
- const startIndex = lines.findIndex((/** @type {any} */ line) => new RegExp(`^\\s*${blockName}\\s*\\{\\s*$`).test(line));
573
- if (startIndex !== -1) {
574
- let endIndex = -1;
575
- for (let index = startIndex + 1; index < lines.length; index += 1) {
576
- if (/^\s*\}\s*$/.test(lines[index])) {
577
- endIndex = index;
578
- break;
579
- }
580
- }
581
- if (endIndex !== -1) {
582
- return { lines, startIndex, endIndex };
583
- }
584
- }
585
- const insertBeforeStatus = lines.findIndex((/** @type {any} */ line) => /^\s*status\s+\w+/.test(line));
586
- const insertIndex = insertBeforeStatus === -1 ? lines.length : insertBeforeStatus;
587
- const blockLines = ["", ` ${blockName} {`, " }"];
588
- lines.splice(insertIndex, 0, ...blockLines);
589
- return {
590
- lines,
591
- startIndex: insertIndex + 1,
592
- endIndex: insertIndex + 2
593
- };
594
- }
595
-
596
- /** @param {any[]} lines @param {any[]} capabilityIds @returns {any} */
597
- export function ensureProjectionRealizes(lines, capabilityIds) {
598
- const startIndex = lines.findIndex((/** @type {any} */ line) => /^\s*realizes\s*\[/.test(line));
599
- if (startIndex === -1) {
600
- return { changed: false, lines };
601
- }
602
- let endIndex = startIndex;
603
- while (endIndex < lines.length && !/\]/.test(lines[endIndex])) {
604
- endIndex += 1;
605
- }
606
- if (endIndex >= lines.length) {
607
- return { changed: false, lines };
608
- }
609
- /** @type {any[]} */
610
- const existingItems = [];
611
- for (let index = startIndex; index <= endIndex; index += 1) {
612
- const text = lines[index]
613
- .replace(/^\s*realizes\s*\[/, "")
614
- .replace(/\]\s*$/, "")
615
- .trim();
616
- if (!text) {
617
- continue;
618
- }
619
- for (const item of text.split(",").map((/** @type {any} */ entry) => entry.trim()).filter(Boolean)) {
620
- existingItems.push(item);
621
- }
622
- }
623
- const merged = [...new Set([...existingItems, ...(capabilityIds || [])])];
624
- if (merged.length === existingItems.length) {
625
- return { changed: false, lines };
626
- }
627
- const replacement = [" realizes [", ...merged.map((/** @type {any} */ item, /** @type {any} */ index) => ` ${item}${index === merged.length - 1 ? "" : ","}`), " ]"];
628
- lines.splice(startIndex, endIndex - startIndex + 1, ...replacement);
629
- return { changed: true, lines };
630
- }
631
-
632
- /** @param {string} baseContents @param {WorkflowRecord} item @returns {any} */
633
- export function applyProjectionAuthPatchToTopogram(baseContents, item) {
634
- const lines = String(baseContents || "").replace(/\r\n/g, "\n").split("\n");
635
- const capabilities = [...new Set(item.related_capabilities || [])];
636
- let changed = false;
637
-
638
- const realizesResult = ensureProjectionRealizes(lines, capabilities);
639
- changed = changed || realizesResult.changed;
640
-
641
- if (item.projection_surface === "authorization") {
642
- const block = ensureProjectionBlock(lines, "authorization");
643
- for (const capabilityId of capabilities) {
644
- const lineIndex = lines.findIndex((/** @type {any} */ line, /** @type {any} */ index) =>
645
- index > block.startIndex &&
646
- index < block.endIndex &&
647
- new RegExp(`^\\s*${capabilityId}(\\s|$)`).test(line)
648
- );
649
- if (item.suggested_action === "apply_projection_ownership_patch") {
650
- const ownershipFragment = `ownership ${item.ownership}${item.ownership_field ? ` ownership_field ${item.ownership_field}` : ""}`;
651
- if (lineIndex !== -1) {
652
- if (!/\bownership\s+/.test(lines[lineIndex])) {
653
- lines[lineIndex] = `${lines[lineIndex].trimEnd()} ${ownershipFragment}`;
654
- changed = true;
655
- }
656
- continue;
657
- }
658
- lines.splice(block.endIndex, 0, ` ${capabilityId} ${ownershipFragment}`);
659
- block.endIndex += 1;
660
- changed = true;
661
- continue;
662
- }
663
-
664
- if (item.suggested_action === "apply_projection_permission_patch") {
665
- const permissionFragment = `permission ${item.permission}`;
666
- if (lineIndex !== -1) {
667
- if (!/\bpermission\s+/.test(lines[lineIndex])) {
668
- lines[lineIndex] = `${lines[lineIndex].trimEnd()} ${permissionFragment}`;
669
- changed = true;
670
- }
671
- continue;
672
- }
673
- lines.splice(block.endIndex, 0, ` ${capabilityId} ${permissionFragment}`);
674
- block.endIndex += 1;
675
- changed = true;
676
- continue;
677
- }
678
-
679
- const claimFragment = `claim ${item.claim}${item.claim_value != null ? ` claim_value ${item.claim_value}` : ""}`;
680
- if (lineIndex !== -1) {
681
- if (!/\bclaim\s+/.test(lines[lineIndex])) {
682
- lines[lineIndex] = `${lines[lineIndex].trimEnd()} ${claimFragment}`;
683
- changed = true;
684
- }
685
- continue;
686
- }
687
- lines.splice(block.endIndex, 0, ` ${capabilityId} ${claimFragment}`);
688
- block.endIndex += 1;
689
- changed = true;
690
- }
691
- }
692
-
693
- if (item.projection_surface === "visibility_rules") {
694
- const block = ensureProjectionBlock(lines, "visibility_rules");
695
- for (const capabilityId of capabilities) {
696
- if (item.suggested_action === "apply_projection_permission_patch") {
697
- const hasExistingPermissionRule = lines.some((/** @type {any} */ line, /** @type {any} */ index) =>
698
- index > block.startIndex &&
699
- index < block.endIndex &&
700
- new RegExp(`^\\s*action\\s+${capabilityId}\\s+visible_if\\s+permission\\s+${item.permission}(\\s|$)`).test(line)
701
- );
702
- if (hasExistingPermissionRule) {
703
- continue;
704
- }
705
- const hasAnyVisibilityRule = lines.some((/** @type {any} */ line, /** @type {any} */ index) =>
706
- index > block.startIndex &&
707
- index < block.endIndex &&
708
- new RegExp(`^\\s*action\\s+${capabilityId}\\s+visible_if\\s+`).test(line)
709
- );
710
- if (hasAnyVisibilityRule) {
711
- continue;
712
- }
713
- lines.splice(block.endIndex, 0, ` action ${capabilityId} visible_if permission ${item.permission}`);
714
- block.endIndex += 1;
715
- changed = true;
716
- continue;
717
- }
718
-
719
- const hasExistingClaimRule = lines.some((/** @type {any} */ line, /** @type {any} */ index) =>
720
- index > block.startIndex &&
721
- index < block.endIndex &&
722
- new RegExp(`^\\s*action\\s+${capabilityId}\\s+visible_if\\s+claim\\s+${item.claim}(\\s|$)`).test(line)
723
- );
724
- if (hasExistingClaimRule) {
725
- continue;
726
- }
727
- const hasAnyVisibilityRule = lines.some((/** @type {any} */ line, /** @type {any} */ index) =>
728
- index > block.startIndex &&
729
- index < block.endIndex &&
730
- new RegExp(`^\\s*action\\s+${capabilityId}\\s+visible_if\\s+`).test(line)
731
- );
732
- if (hasAnyVisibilityRule) {
733
- continue;
734
- }
735
- lines.splice(block.endIndex, 0, ` action ${capabilityId} visible_if claim ${item.claim}${item.claim_value != null ? ` claim_value ${item.claim_value}` : ""}`);
736
- block.endIndex += 1;
737
- changed = true;
738
- }
739
- }
740
-
741
- return changed ? ensureTrailingNewline(lines.join("\n")) : baseContents;
742
- }
3
+ export { ADOPT_SELECTORS, buildAdoptionPlan } from "./adoption-plan/build.js";
4
+ export {
5
+ adoptionStatusForStep,
6
+ blockingDependenciesForProjectionImpacts,
7
+ blockingDependenciesForUiImpacts,
8
+ blockingDependenciesForWorkflowImpacts,
9
+ projectionImpactsForAdoptionItem
10
+ } from "./adoption-plan/dependencies.js";
11
+ export {
12
+ buildCanonicalAdoptionOutputs,
13
+ buildPromotedCanonicalItems,
14
+ readAdoptionPlan
15
+ } from "./adoption-plan/outputs.js";
16
+ export {
17
+ canonicalDisplayPathForItem,
18
+ canonicalRelativePathForItem,
19
+ candidateSourcePathForItem
20
+ } from "./adoption-plan/paths.js";
21
+ export {
22
+ applyProjectionAuthPatchToTopogram,
23
+ ensureProjectionBlock,
24
+ ensureProjectionRealizes
25
+ } from "./adoption-plan/projection-patches.js";
26
+ export {
27
+ formatDocDriftSummaryInline,
28
+ formatDocLinkSuggestionInline,
29
+ formatDocMetadataPatchInline,
30
+ reasonForAdoptionItem,
31
+ recommendationForAdoptionItem
32
+ } from "./adoption-plan/reasons.js";