@topogram/cli 0.3.64 → 0.3.66

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 (278) hide show
  1. package/package.json +1 -1
  2. package/src/adoption/plan/index.js +716 -0
  3. package/src/adoption/plan.js +12 -703
  4. package/src/adoption/reporting.js +1 -1
  5. package/src/agent-brief.js +7 -21
  6. package/src/agent-ops/query-builders/auth.js +375 -0
  7. package/src/agent-ops/query-builders/change-risk/change-plan.js +123 -0
  8. package/src/agent-ops/query-builders/change-risk/import-plan.js +49 -0
  9. package/src/agent-ops/query-builders/change-risk/maintained.js +286 -0
  10. package/src/agent-ops/query-builders/change-risk/review-packets.js +123 -0
  11. package/src/agent-ops/query-builders/change-risk/risk.js +189 -0
  12. package/src/agent-ops/query-builders/change-risk.js +25 -0
  13. package/src/agent-ops/query-builders/common.js +149 -0
  14. package/src/agent-ops/query-builders/maintained-risk.js +539 -0
  15. package/src/agent-ops/query-builders/maintained-shared.js +120 -0
  16. package/src/agent-ops/query-builders/multi-agent.js +547 -0
  17. package/src/agent-ops/query-builders/projection-impacts.js +514 -0
  18. package/src/agent-ops/query-builders/work-packets.js +417 -0
  19. package/src/agent-ops/query-builders/workflow-context-shared.js +300 -0
  20. package/src/agent-ops/query-builders/workflow-context.js +398 -0
  21. package/src/agent-ops/query-builders/workflow-presets-core.js +677 -0
  22. package/src/agent-ops/query-builders/workflow-presets.js +341 -0
  23. package/src/agent-ops/query-builders.d.ts +26 -26
  24. package/src/agent-ops/query-builders.js +42 -5021
  25. package/src/archive/jsonl.js +2 -2
  26. package/src/archive/resolver-bridge.js +1 -1
  27. package/src/archive/unarchive.js +2 -1
  28. package/src/catalog/constants.js +10 -0
  29. package/src/catalog/copy.js +65 -0
  30. package/src/catalog/diagnostics.js +15 -0
  31. package/src/catalog/entries.js +42 -0
  32. package/src/catalog/files.js +67 -0
  33. package/src/catalog/provenance.js +123 -0
  34. package/src/catalog/source.js +150 -0
  35. package/src/catalog/validation.js +252 -0
  36. package/src/catalog.d.ts +2 -0
  37. package/src/catalog.js +18 -746
  38. package/src/cli/command-parsers/project.js +3 -0
  39. package/src/cli/command-parsers/shared.js +1 -1
  40. package/src/cli/commands/agent.js +2 -2
  41. package/src/cli/commands/catalog/check.js +31 -0
  42. package/src/cli/commands/catalog/copy.js +59 -0
  43. package/src/cli/commands/catalog/doctor.js +248 -0
  44. package/src/cli/commands/catalog/help.js +21 -0
  45. package/src/cli/commands/catalog/list.js +52 -0
  46. package/src/cli/commands/catalog/runner.js +92 -0
  47. package/src/cli/commands/catalog/shared.js +17 -0
  48. package/src/cli/commands/catalog/show.js +134 -0
  49. package/src/cli/commands/catalog.js +30 -615
  50. package/src/cli/commands/check.js +3 -3
  51. package/src/cli/commands/doctor.js +2 -9
  52. package/src/cli/commands/generator-policy/package-info.js +162 -0
  53. package/src/cli/commands/generator-policy/payloads.js +372 -0
  54. package/src/cli/commands/generator-policy/printers.js +159 -0
  55. package/src/cli/commands/generator-policy/runner.js +81 -0
  56. package/src/cli/commands/generator-policy/shared.js +39 -0
  57. package/src/cli/commands/generator-policy.js +15 -783
  58. package/src/cli/commands/import/adopt.js +170 -0
  59. package/src/cli/commands/import/check.js +91 -0
  60. package/src/cli/commands/import/diff.js +84 -0
  61. package/src/cli/commands/import/help.js +47 -0
  62. package/src/cli/commands/import/paths.js +269 -0
  63. package/src/cli/commands/import/plan.js +292 -0
  64. package/src/cli/commands/import/refresh.js +471 -0
  65. package/src/cli/commands/import/status-history.js +196 -0
  66. package/src/cli/commands/import/workspace.js +233 -0
  67. package/src/cli/commands/import.js +33 -1732
  68. package/src/cli/commands/migrate.js +153 -0
  69. package/src/cli/commands/package/constants.js +17 -0
  70. package/src/cli/commands/package/doctor.js +240 -0
  71. package/src/cli/commands/package/help.js +27 -0
  72. package/src/cli/commands/package/lockfile.js +135 -0
  73. package/src/cli/commands/package/npm.js +97 -0
  74. package/src/cli/commands/package/reporting.js +35 -0
  75. package/src/cli/commands/package/runner.js +33 -0
  76. package/src/cli/commands/package/shared.js +9 -0
  77. package/src/cli/commands/package/update-cli.js +252 -0
  78. package/src/cli/commands/package/versions.js +35 -0
  79. package/src/cli/commands/package.js +29 -813
  80. package/src/cli/commands/query/change-plan.js +68 -0
  81. package/src/cli/commands/query/definitions.js +202 -0
  82. package/src/cli/commands/query/import-adopt.js +121 -0
  83. package/src/cli/commands/query/runner/artifacts.js +102 -0
  84. package/src/cli/commands/query/runner/boundaries.js +211 -0
  85. package/src/cli/commands/query/runner/change.js +182 -0
  86. package/src/cli/commands/query/runner/import-adopt.js +111 -0
  87. package/src/cli/commands/query/runner/index.js +31 -0
  88. package/src/cli/commands/query/runner/output.js +12 -0
  89. package/src/cli/commands/query/runner/workflow.js +241 -0
  90. package/src/cli/commands/query/runner.js +3 -0
  91. package/src/cli/commands/query/workflow-context.js +5 -0
  92. package/src/cli/commands/query/workspace.js +270 -0
  93. package/src/cli/commands/query.js +9 -1300
  94. package/src/cli/commands/source.js +3 -12
  95. package/src/cli/commands/template/baseline.js +100 -0
  96. package/src/cli/commands/template/check.js +467 -0
  97. package/src/cli/commands/template/constants.js +8 -0
  98. package/src/cli/commands/template/diagnostics.js +26 -0
  99. package/src/cli/commands/template/help.js +28 -0
  100. package/src/cli/commands/template/lifecycle.js +404 -0
  101. package/src/cli/commands/template/list-show.js +287 -0
  102. package/src/cli/commands/template/policy.js +422 -0
  103. package/src/cli/commands/template/shared.js +127 -0
  104. package/src/cli/commands/template/updates.js +352 -0
  105. package/src/cli/commands/template-runner.js +6 -6
  106. package/src/cli/commands/template.js +41 -2143
  107. package/src/cli/commands/trust.js +1 -1
  108. package/src/cli/commands/workflow.js +6 -1
  109. package/src/cli/dispatcher.js +6 -1
  110. package/src/cli/help.js +15 -14
  111. package/src/cli/migration-guidance.js +1 -1
  112. package/src/cli/output-safety.js +2 -1
  113. package/src/cli/path-normalization.js +3 -13
  114. package/src/generator/api/contracts.js +497 -0
  115. package/src/generator/api/metadata.js +221 -0
  116. package/src/generator/api/openapi.js +559 -0
  117. package/src/generator/api/schema.js +124 -0
  118. package/src/generator/api/types.d.ts +98 -0
  119. package/src/generator/api.js +3 -1195
  120. package/src/generator/context/domain-page.js +1 -1
  121. package/src/generator/context/shared/domain-sdlc.js +282 -0
  122. package/src/generator/context/shared/maintained-boundary.js +665 -0
  123. package/src/generator/context/shared/metrics.js +85 -0
  124. package/src/generator/context/shared/primitives.js +64 -0
  125. package/src/generator/context/shared/relationships.js +453 -0
  126. package/src/generator/context/shared/summaries.js +263 -0
  127. package/src/generator/context/shared/types.d.ts +207 -0
  128. package/src/generator/context/shared.d.ts +42 -0
  129. package/src/generator/context/shared.js +80 -1390
  130. package/src/generator/context/slice/core.js +397 -0
  131. package/src/generator/context/slice/sdlc.js +417 -0
  132. package/src/generator/context/slice/ui-packets.js +183 -0
  133. package/src/generator/context/slice.js +2 -859
  134. package/src/generator/context/task-mode.js +2 -2
  135. package/src/generator/registry/index.js +507 -0
  136. package/src/generator/registry.js +18 -504
  137. package/src/generator/runtime/environment/index.js +666 -0
  138. package/src/generator/runtime/environment.js +4 -666
  139. package/src/generator/runtime/runtime-check/index.js +554 -0
  140. package/src/generator/runtime/runtime-check.js +4 -554
  141. package/src/generator/runtime/shared/index.js +572 -0
  142. package/src/generator/runtime/shared.js +19 -570
  143. package/src/generator/sdlc/doc-page.js +1 -1
  144. package/src/generator/shared.d.ts +2 -0
  145. package/src/generator/surfaces/databases/lifecycle-shared.js +1 -1
  146. package/src/generator/surfaces/native/swiftui-templates/README.generated.md +1 -1
  147. package/src/generator/surfaces/shared.d.ts +3 -0
  148. package/src/generator/widget-conformance/behavior-report.js +258 -0
  149. package/src/generator/widget-conformance/checks.js +371 -0
  150. package/src/generator/widget-conformance/projection-context.js +200 -0
  151. package/src/generator/widget-conformance/report.js +166 -0
  152. package/src/generator/widget-conformance/types.d.ts +121 -0
  153. package/src/generator/widget-conformance.js +3 -824
  154. package/src/import/core/context.d.ts +3 -0
  155. package/src/import/core/context.js +5 -7
  156. package/src/import/core/contracts.d.ts +1 -0
  157. package/src/import/core/registry.d.ts +4 -0
  158. package/src/import/core/runner/candidates.js +337 -0
  159. package/src/import/core/runner/options.js +22 -0
  160. package/src/import/core/runner/reports.js +51 -0
  161. package/src/import/core/runner/run.js +79 -0
  162. package/src/import/core/runner/tracks.js +150 -0
  163. package/src/import/core/runner/ui-drafts.js +393 -0
  164. package/src/import/core/runner.js +3 -698
  165. package/src/import/core/shared/api-routes.js +221 -0
  166. package/src/import/core/shared/candidates.js +97 -0
  167. package/src/import/core/shared/files.js +177 -0
  168. package/src/import/core/shared/next-app.js +389 -0
  169. package/src/import/core/shared/types.d.ts +51 -0
  170. package/src/import/core/shared/ui-routes.js +230 -0
  171. package/src/import/core/shared.js +60 -861
  172. package/src/new-project/constants.js +128 -0
  173. package/src/new-project/create.js +90 -0
  174. package/src/new-project/json.js +28 -0
  175. package/src/new-project/metadata.js +96 -0
  176. package/src/new-project/package-spec.js +161 -0
  177. package/src/new-project/project-files.js +351 -0
  178. package/src/new-project/template-policy.js +269 -0
  179. package/src/new-project/template-resolution.js +370 -0
  180. package/src/new-project/template-snapshots.js +442 -0
  181. package/src/new-project/template-updates.js +512 -0
  182. package/src/new-project/types.d.ts +83 -0
  183. package/src/new-project.js +6 -2277
  184. package/src/parser.d.ts +87 -1
  185. package/src/parser.js +118 -0
  186. package/src/policy/review-boundaries.d.ts +15 -0
  187. package/src/project-config/index.js +591 -0
  188. package/src/project-config.js +19 -561
  189. package/src/resolver/enrich/acceptance-criterion.js +2 -0
  190. package/src/resolver/enrich/bug.js +2 -0
  191. package/src/resolver/enrich/pitch.js +2 -0
  192. package/src/resolver/enrich/requirement.js +2 -0
  193. package/src/resolver/enrich/task.js +2 -0
  194. package/src/resolver/index.js +19 -2089
  195. package/src/resolver/normalize.js +384 -1
  196. package/src/resolver/plans.js +168 -0
  197. package/src/resolver/projections-api.js +494 -0
  198. package/src/resolver/projections-db.js +133 -0
  199. package/src/resolver/projections-ui.js +317 -0
  200. package/src/resolver/shapes.js +251 -0
  201. package/src/resolver/shared.js +278 -0
  202. package/src/resolver/widgets.js +132 -0
  203. package/src/sdlc/adopt.js +6 -5
  204. package/src/sdlc/paths.js +3 -5
  205. package/src/sdlc/scaffold.js +2 -1
  206. package/src/template-trust/constants.js +62 -0
  207. package/src/template-trust/content.js +258 -0
  208. package/src/template-trust/diff.js +92 -0
  209. package/src/template-trust/policy.js +61 -0
  210. package/src/template-trust/record.js +90 -0
  211. package/src/template-trust/status.js +182 -0
  212. package/src/template-trust.js +24 -687
  213. package/src/text-helpers.d.ts +1 -0
  214. package/src/topogram-types.d.ts +69 -0
  215. package/src/validator/common.js +488 -0
  216. package/src/validator/data-model.js +237 -0
  217. package/src/validator/docs.js +167 -0
  218. package/src/validator/expressions.js +146 -1
  219. package/src/validator/index.d.ts +23 -0
  220. package/src/validator/index.js +32 -3585
  221. package/src/validator/kinds.d.ts +41 -0
  222. package/src/validator/kinds.js +2 -0
  223. package/src/validator/model-helpers.js +46 -0
  224. package/src/validator/per-kind/acceptance-criterion.js +5 -0
  225. package/src/validator/per-kind/bug.js +6 -0
  226. package/src/validator/per-kind/domain.js +15 -2
  227. package/src/validator/per-kind/pitch.js +7 -0
  228. package/src/validator/per-kind/requirement.js +5 -0
  229. package/src/validator/per-kind/task.js +7 -0
  230. package/src/validator/per-kind/widget.js +14 -0
  231. package/src/validator/projections/api-http-async.js +410 -0
  232. package/src/validator/projections/api-http-authz.js +88 -0
  233. package/src/validator/projections/api-http-core.js +205 -0
  234. package/src/validator/projections/api-http-policies.js +339 -0
  235. package/src/validator/projections/api-http-responses.js +233 -0
  236. package/src/validator/projections/api-http.js +44 -0
  237. package/src/validator/projections/db.js +353 -0
  238. package/src/validator/projections/generator-defaults.js +45 -0
  239. package/src/validator/projections/helpers.js +87 -0
  240. package/src/validator/projections/ui-helpers.js +214 -0
  241. package/src/validator/projections/ui-navigation.js +344 -0
  242. package/src/validator/projections/ui-structure.js +364 -0
  243. package/src/validator/projections/ui-widgets.js +493 -0
  244. package/src/validator/projections/ui.js +46 -0
  245. package/src/validator/registry.js +48 -1
  246. package/src/validator/utils.d.ts +20 -0
  247. package/src/validator/utils.js +115 -12
  248. package/src/widget-behavior.d.ts +1 -0
  249. package/src/workflows/import-app/api/collect.js +221 -0
  250. package/src/workflows/import-app/api/openapi.js +257 -0
  251. package/src/workflows/import-app/api/routes.js +327 -0
  252. package/src/workflows/import-app/api/sources.js +22 -0
  253. package/src/workflows/import-app/api.js +2 -797
  254. package/src/workflows/reconcile/adoption-plan/build.js +212 -0
  255. package/src/workflows/reconcile/adoption-plan/dependencies.js +75 -0
  256. package/src/workflows/reconcile/adoption-plan/outputs.js +153 -0
  257. package/src/workflows/reconcile/adoption-plan/paths.js +58 -0
  258. package/src/workflows/reconcile/adoption-plan/projection-patches.js +177 -0
  259. package/src/workflows/reconcile/adoption-plan/reasons.js +107 -0
  260. package/src/workflows/reconcile/adoption-plan.js +30 -740
  261. package/src/workflows/reconcile/auth/closures.js +115 -0
  262. package/src/workflows/reconcile/auth/formatters.js +142 -0
  263. package/src/workflows/reconcile/auth/inference.js +330 -0
  264. package/src/workflows/reconcile/auth/roles.js +122 -0
  265. package/src/workflows/reconcile/auth.js +35 -690
  266. package/src/workflows/reconcile/bundle-core/index.js +600 -0
  267. package/src/workflows/reconcile/bundle-core.js +12 -598
  268. package/src/workflows/reconcile/candidate-model.js +18 -2
  269. package/src/workflows/reconcile/canonical-surface.js +1 -1
  270. package/src/workflows/reconcile/impacts/adoption-plan.js +196 -0
  271. package/src/workflows/reconcile/impacts/indexes.js +105 -0
  272. package/src/workflows/reconcile/impacts/patches.js +252 -0
  273. package/src/workflows/reconcile/impacts/reports.js +80 -0
  274. package/src/workflows/reconcile/impacts.js +14 -623
  275. package/src/workflows/reconcile/renderers.js +41 -6
  276. package/src/workflows/shared.js +5 -11
  277. package/src/workspace-docs.d.ts +29 -0
  278. package/src/workspace-paths.js +328 -0
@@ -0,0 +1,417 @@
1
+ // @ts-check
2
+
3
+ import {
4
+ acceptanceCriterionById,
5
+ bugById,
6
+ buildDefaultWriteScope,
7
+ documentById,
8
+ domainById,
9
+ getJourneyDoc,
10
+ pitchById,
11
+ recommendedVerificationTargets,
12
+ relatedEntitiesForDomain,
13
+ relatedProjectionsForDomain,
14
+ relatedRulesForDomain,
15
+ relatedVerificationsForDomain,
16
+ requirementById,
17
+ summarizeAcceptanceCriterion,
18
+ summarizeBug,
19
+ summarizeById,
20
+ summarizeDocsByIds,
21
+ summarizeDocument,
22
+ summarizeDomain,
23
+ summarizePitch,
24
+ summarizeRequirement,
25
+ summarizeStatementsByIds,
26
+ summarizeTask,
27
+ taskById,
28
+ verificationIdsForTarget
29
+ } from "../shared.js";
30
+ import {
31
+ defaultOwnershipBoundary,
32
+ reviewBoundaryForAcceptanceCriterion,
33
+ reviewBoundaryForBug,
34
+ reviewBoundaryForDocument,
35
+ reviewBoundaryForDomain,
36
+ reviewBoundaryForJourneyDoc,
37
+ reviewBoundaryForPitch,
38
+ reviewBoundaryForRequirement,
39
+ reviewBoundaryForTask
40
+ } from "../../../policy/review-boundaries.js";
41
+
42
+ /**
43
+ * @param {import("../shared/types.d.ts").ContextGraph} graph
44
+ * @param {string} journeyId
45
+ * @returns {any}
46
+ */
47
+ export function journeySlice(graph, journeyId) {
48
+ const journey = getJourneyDoc(graph, journeyId);
49
+ const capabilities = [...(journey.relatedCapabilities || [])].sort();
50
+ const workflows = [...(journey.relatedWorkflows || [])].sort();
51
+ const projections = [...(journey.relatedProjections || [])].sort();
52
+ const verifications = verificationIdsForTarget(graph, [...capabilities, ...workflows, ...projections, journeyId]);
53
+
54
+ return {
55
+ type: "context_slice",
56
+ version: 1,
57
+ focus: {
58
+ kind: "journey",
59
+ id: journeyId
60
+ },
61
+ summary: summarizeById(graph, journeyId),
62
+ depends_on: {
63
+ capabilities,
64
+ workflows,
65
+ projections,
66
+ verifications
67
+ },
68
+ related: {
69
+ capabilities: summarizeStatementsByIds(graph, capabilities),
70
+ workflows: summarizeDocsByIds(graph, workflows),
71
+ projections: summarizeStatementsByIds(graph, projections)
72
+ },
73
+ verification: summarizeStatementsByIds(graph, verifications),
74
+ verification_targets: recommendedVerificationTargets(graph, [...capabilities, ...workflows, ...projections, journeyId], {
75
+ rationale: "Journey slices should target workflow-facing verification rather than a full workspace rerun."
76
+ }),
77
+ write_scope: buildDefaultWriteScope(),
78
+ review_boundary: reviewBoundaryForJourneyDoc(journey),
79
+ ownership_boundary: defaultOwnershipBoundary()
80
+ };
81
+ }
82
+
83
+ /**
84
+ * @param {import("../shared/types.d.ts").ContextGraph} graph
85
+ * @param {string} domainId
86
+ * @returns {any}
87
+ */
88
+ export function domainSlice(graph, domainId) {
89
+ const domain = domainById(graph, domainId);
90
+ if (!domain) {
91
+ throw new Error(`No domain found with id '${domainId}'`);
92
+ }
93
+ const capabilities = [...(domain.members?.capabilities || [])].sort();
94
+ const entities = relatedEntitiesForDomain(graph, domainId);
95
+ const rules = relatedRulesForDomain(graph, domainId);
96
+ const verifications = relatedVerificationsForDomain(graph, domainId);
97
+ const orchestrations = [...(domain.members?.orchestrations || [])].sort();
98
+ const operations = [...(domain.members?.operations || [])].sort();
99
+ const decisions = [...(domain.members?.decisions || [])].sort();
100
+ const projections = relatedProjectionsForDomain(graph, domainId);
101
+
102
+ // Verification targets cover the union of capability/entity/projection IDs in
103
+ // the domain so a domain-scoped change re-runs the right verification set
104
+ // without pulling in the whole workspace.
105
+ const verificationTargets = recommendedVerificationTargets(
106
+ graph,
107
+ [domainId, ...capabilities, ...entities, ...projections],
108
+ {
109
+ rationale:
110
+ "Domain slices should re-run verification covering the domain's capabilities, entities, and projection types."
111
+ }
112
+ );
113
+
114
+ return {
115
+ type: "context_slice",
116
+ version: 1,
117
+ focus: {
118
+ kind: "domain",
119
+ id: domainId
120
+ },
121
+ summary: summarizeDomain(domain),
122
+ depends_on: {
123
+ capabilities,
124
+ entities,
125
+ rules,
126
+ verifications,
127
+ orchestrations,
128
+ operations,
129
+ decisions,
130
+ projections
131
+ },
132
+ related: {
133
+ capabilities: summarizeStatementsByIds(graph, capabilities),
134
+ entities: summarizeStatementsByIds(graph, entities),
135
+ rules: summarizeStatementsByIds(graph, rules),
136
+ orchestrations: summarizeStatementsByIds(graph, orchestrations),
137
+ operations: summarizeStatementsByIds(graph, operations),
138
+ decisions: summarizeStatementsByIds(graph, decisions),
139
+ projections: summarizeStatementsByIds(graph, projections)
140
+ },
141
+ verification: summarizeStatementsByIds(graph, verifications),
142
+ verification_targets: verificationTargets,
143
+ write_scope: buildDefaultWriteScope(),
144
+ review_boundary: reviewBoundaryForDomain(),
145
+ ownership_boundary: defaultOwnershipBoundary()
146
+ };
147
+ }
148
+
149
+ // Phase 2 — SDLC slices.
150
+ //
151
+ // SDLC slices follow the same shape as feature slices: focus + summary +
152
+ // depends_on + related + verification + write_scope + review_boundary. They
153
+ // give an agent a single payload covering an artifact's chain (pitch →
154
+ // requirement → AC → task → bug → verification → document) without
155
+ // re-walking the graph.
156
+
157
+ /**
158
+ * @param {import("../shared/types.d.ts").ContextGraph} graph
159
+ * @param {string} pitchId
160
+ * @returns {any}
161
+ */
162
+ export function pitchSlice(graph, pitchId) {
163
+ const pitch = pitchById(graph, pitchId);
164
+ if (!pitch) throw new Error(`No pitch found with id '${pitchId}'`);
165
+
166
+ const requirements = (pitch.requirements || []).slice().sort();
167
+ const decisions = [
168
+ ...(pitch.decisions || []).map(/** @param {any} d */ (d) => (typeof d === "string" ? d : d?.id)).filter(Boolean),
169
+ ...(pitch.decisionsFromPitch || [])
170
+ ];
171
+ const decisionIds = [...new Set(decisions)].sort();
172
+ const affects = (pitch.affects || []).map(/** @param {any} a */ (a) => (typeof a === "string" ? a : a?.id)).filter(Boolean).sort();
173
+ const verifications = verificationIdsForTarget(graph, [pitchId, ...affects]);
174
+
175
+ return {
176
+ type: "context_slice",
177
+ version: 1,
178
+ focus: { kind: "pitch", id: pitchId },
179
+ summary: summarizePitch(pitch),
180
+ depends_on: {
181
+ requirements,
182
+ decisions: decisionIds,
183
+ affects,
184
+ verifications
185
+ },
186
+ related: {
187
+ requirements: summarizeStatementsByIds(graph, requirements),
188
+ decisions: summarizeStatementsByIds(graph, decisionIds),
189
+ affects: summarizeStatementsByIds(graph, affects)
190
+ },
191
+ verification: summarizeStatementsByIds(graph, verifications),
192
+ verification_targets: recommendedVerificationTargets(graph, [pitchId, ...affects], {
193
+ rationale: "Pitch slice covers verification touching any of its affected surfaces."
194
+ }),
195
+ write_scope: buildDefaultWriteScope(),
196
+ review_boundary: reviewBoundaryForPitch(),
197
+ ownership_boundary: defaultOwnershipBoundary()
198
+ };
199
+ }
200
+
201
+ /**
202
+ * @param {import("../shared/types.d.ts").ContextGraph} graph
203
+ * @param {string} requirementId
204
+ * @returns {any}
205
+ */
206
+ export function requirementSlice(graph, requirementId) {
207
+ const req = requirementById(graph, requirementId);
208
+ if (!req) throw new Error(`No requirement found with id '${requirementId}'`);
209
+
210
+ const acceptance = (req.acceptanceCriteria || []).slice().sort();
211
+ const tasks = (req.tasks || []).slice().sort();
212
+ const documents = (req.documents || []).slice().sort();
213
+ const rules = (req.rules || []).slice().sort();
214
+ const introducesRules = (req.introducesRules || []).map(/** @param {any} r */ (r) => (typeof r === "string" ? r : r?.id)).filter(Boolean).sort();
215
+ const respectsRules = (req.respectsRules || []).map(/** @param {any} r */ (r) => (typeof r === "string" ? r : r?.id)).filter(Boolean).sort();
216
+ const affects = (req.affects || []).map(/** @param {any} a */ (a) => (typeof a === "string" ? a : a?.id)).filter(Boolean).sort();
217
+ const verifications = verificationIdsForTarget(graph, [requirementId, ...affects, ...acceptance]);
218
+
219
+ return {
220
+ type: "context_slice",
221
+ version: 1,
222
+ focus: { kind: "requirement", id: requirementId },
223
+ summary: summarizeRequirement(req),
224
+ depends_on: {
225
+ pitch: req.pitch?.id || null,
226
+ acceptance_criteria: acceptance,
227
+ tasks,
228
+ documents,
229
+ rules,
230
+ introduces_rules: introducesRules,
231
+ respects_rules: respectsRules,
232
+ affects,
233
+ verifications
234
+ },
235
+ related: {
236
+ acceptance_criteria: summarizeStatementsByIds(graph, acceptance),
237
+ tasks: summarizeStatementsByIds(graph, tasks),
238
+ rules: summarizeStatementsByIds(graph, [...rules, ...introducesRules, ...respectsRules]),
239
+ affects: summarizeStatementsByIds(graph, affects),
240
+ documents: summarizeDocsByIds(graph, documents)
241
+ },
242
+ verification: summarizeStatementsByIds(graph, verifications),
243
+ verification_targets: recommendedVerificationTargets(graph, [requirementId, ...affects, ...acceptance], {
244
+ rationale: "Requirement slice covers verification tied to its acceptance criteria and affected surfaces."
245
+ }),
246
+ write_scope: buildDefaultWriteScope(),
247
+ review_boundary: reviewBoundaryForRequirement(),
248
+ ownership_boundary: defaultOwnershipBoundary()
249
+ };
250
+ }
251
+
252
+ /**
253
+ * @param {import("../shared/types.d.ts").ContextGraph} graph
254
+ * @param {string} acId
255
+ * @returns {any}
256
+ */
257
+ export function acceptanceCriterionSlice(graph, acId) {
258
+ const ac = acceptanceCriterionById(graph, acId);
259
+ if (!ac) throw new Error(`No acceptance_criterion found with id '${acId}'`);
260
+
261
+ const tasks = (ac.tasks || []).slice().sort();
262
+ const verifications = (ac.verifications || []).slice().sort();
263
+ const requirementId = ac.requirement?.id || null;
264
+
265
+ return {
266
+ type: "context_slice",
267
+ version: 1,
268
+ focus: { kind: "acceptance_criterion", id: acId },
269
+ summary: summarizeAcceptanceCriterion(ac),
270
+ depends_on: {
271
+ requirement: requirementId,
272
+ tasks,
273
+ verifications
274
+ },
275
+ related: {
276
+ tasks: summarizeStatementsByIds(graph, tasks),
277
+ requirement: requirementId ? summarizeStatementsByIds(graph, [requirementId]) : []
278
+ },
279
+ verification: summarizeStatementsByIds(graph, verifications),
280
+ verification_targets: recommendedVerificationTargets(graph, [acId, ...(requirementId ? [requirementId] : [])], {
281
+ rationale: "AC slice points at verification proving this acceptance criterion."
282
+ }),
283
+ write_scope: buildDefaultWriteScope(),
284
+ review_boundary: reviewBoundaryForAcceptanceCriterion(),
285
+ ownership_boundary: defaultOwnershipBoundary()
286
+ };
287
+ }
288
+
289
+ /**
290
+ * @param {import("../shared/types.d.ts").ContextGraph} graph
291
+ * @param {string} taskId
292
+ * @returns {any}
293
+ */
294
+ export function taskSlice(graph, taskId) {
295
+ const task = taskById(graph, taskId);
296
+ if (!task) throw new Error(`No task found with id '${taskId}'`);
297
+
298
+ const satisfies = (task.satisfies || []).map(/** @param {any} r */ (r) => (typeof r === "string" ? r : r?.id)).filter(Boolean).sort();
299
+ const acRefs = (task.acceptanceRefs || []).map(/** @param {any} r */ (r) => (typeof r === "string" ? r : r?.id)).filter(Boolean).sort();
300
+ const blockedBy = (task.blockedBy || []).map(/** @param {any} r */ (r) => (typeof r === "string" ? r : r?.id)).filter(Boolean).sort();
301
+ const blocks = (task.blocks || []).map(/** @param {any} r */ (r) => (typeof r === "string" ? r : r?.id)).filter(Boolean).sort();
302
+ const affects = (task.affects || []).map(/** @param {any} a */ (a) => (typeof a === "string" ? a : a?.id)).filter(Boolean).sort();
303
+ const verifications = verificationIdsForTarget(graph, [taskId, ...affects, ...acRefs]);
304
+
305
+ return {
306
+ type: "context_slice",
307
+ version: 1,
308
+ focus: { kind: "task", id: taskId },
309
+ summary: summarizeTask(task),
310
+ depends_on: {
311
+ satisfies,
312
+ acceptance_refs: acRefs,
313
+ blocked_by: blockedBy,
314
+ blocks,
315
+ affects,
316
+ verifications
317
+ },
318
+ related: {
319
+ satisfies: summarizeStatementsByIds(graph, satisfies),
320
+ acceptance_refs: summarizeStatementsByIds(graph, acRefs),
321
+ blocked_by: summarizeStatementsByIds(graph, blockedBy),
322
+ affects: summarizeStatementsByIds(graph, affects)
323
+ },
324
+ verification: summarizeStatementsByIds(graph, verifications),
325
+ verification_targets: recommendedVerificationTargets(graph, [taskId, ...affects, ...acRefs], {
326
+ rationale: "Task slice points at verification covering the surfaces this task touches."
327
+ }),
328
+ write_scope: buildDefaultWriteScope(),
329
+ review_boundary: reviewBoundaryForTask(),
330
+ ownership_boundary: defaultOwnershipBoundary()
331
+ };
332
+ }
333
+
334
+ /**
335
+ * @param {import("../shared/types.d.ts").ContextGraph} graph
336
+ * @param {string} bugId
337
+ * @returns {any}
338
+ */
339
+ export function bugSlice(graph, bugId) {
340
+ const bug = bugById(graph, bugId);
341
+ if (!bug) throw new Error(`No bug found with id '${bugId}'`);
342
+
343
+ const violates = (bug.violates || []).map(/** @param {any} r */ (r) => (typeof r === "string" ? r : r?.id)).filter(Boolean).sort();
344
+ const surfacesRule = (bug.surfacesRule || []).map(/** @param {any} r */ (r) => (typeof r === "string" ? r : r?.id)).filter(Boolean).sort();
345
+ const fixedIn = (bug.fixedIn || []).map(/** @param {any} r */ (r) => (typeof r === "string" ? r : r?.id)).filter(Boolean).sort();
346
+ const fixedInVerification = (bug.fixedInVerification || []).map(/** @param {any} r */ (r) => (typeof r === "string" ? r : r?.id)).filter(Boolean).sort();
347
+ const verifiedBy = (bug.verifiedBy || []).slice().sort();
348
+ const affects = (bug.affects || []).map(/** @param {any} a */ (a) => (typeof a === "string" ? a : a?.id)).filter(Boolean).sort();
349
+ const verifications = [...new Set([...fixedInVerification, ...verifiedBy, ...verificationIdsForTarget(graph, [bugId, ...affects])])].sort();
350
+
351
+ return {
352
+ type: "context_slice",
353
+ version: 1,
354
+ focus: { kind: "bug", id: bugId },
355
+ summary: summarizeBug(bug),
356
+ depends_on: {
357
+ violates,
358
+ surfaces_rule: surfacesRule,
359
+ fixed_in: fixedIn,
360
+ fixed_in_verification: fixedInVerification,
361
+ affects,
362
+ verifications
363
+ },
364
+ related: {
365
+ violates: summarizeStatementsByIds(graph, violates),
366
+ affects: summarizeStatementsByIds(graph, affects),
367
+ fixed_in: summarizeStatementsByIds(graph, fixedIn)
368
+ },
369
+ verification: summarizeStatementsByIds(graph, verifications),
370
+ verification_targets: recommendedVerificationTargets(graph, [bugId, ...affects, ...violates], {
371
+ rationale: "Bug slice points at verification proving the regression is closed."
372
+ }),
373
+ write_scope: buildDefaultWriteScope(),
374
+ review_boundary: reviewBoundaryForBug(),
375
+ ownership_boundary: defaultOwnershipBoundary()
376
+ };
377
+ }
378
+
379
+ /**
380
+ * @param {import("../shared/types.d.ts").ContextGraph} graph
381
+ * @param {string} documentId
382
+ * @returns {any}
383
+ */
384
+ export function documentSlice(graph, documentId) {
385
+ const doc = documentById(graph, documentId);
386
+ if (!doc) throw new Error(`No document found with id '${documentId}'`);
387
+
388
+ const relatedEntities = (doc.relatedEntities || []).slice().sort();
389
+ const relatedCapabilities = (doc.relatedCapabilities || []).slice().sort();
390
+ const relatedProjections = (doc.relatedProjections || []).slice().sort();
391
+ const relatedRules = (doc.relatedRules || []).slice().sort();
392
+
393
+ return {
394
+ type: "context_slice",
395
+ version: 1,
396
+ focus: { kind: "document", id: documentId },
397
+ summary: summarizeDocument(doc),
398
+ depends_on: {
399
+ related_entities: relatedEntities,
400
+ related_capabilities: relatedCapabilities,
401
+ related_projections: relatedProjections,
402
+ related_rules: relatedRules
403
+ },
404
+ related: {
405
+ entities: summarizeStatementsByIds(graph, relatedEntities),
406
+ capabilities: summarizeStatementsByIds(graph, relatedCapabilities),
407
+ projections: summarizeStatementsByIds(graph, relatedProjections),
408
+ rules: summarizeStatementsByIds(graph, relatedRules)
409
+ },
410
+ verification: [],
411
+ verification_targets: [],
412
+ write_scope: buildDefaultWriteScope(),
413
+ review_boundary: reviewBoundaryForDocument(doc),
414
+ ownership_boundary: defaultOwnershipBoundary()
415
+ };
416
+ }
417
+
@@ -0,0 +1,183 @@
1
+ // @ts-check
2
+
3
+ /**
4
+ * @param {import("../shared/types.d.ts").ContextGraph} graph
5
+ * @param {import("../shared/types.d.ts").ContextProjection} projection
6
+ * @returns {any}
7
+ */
8
+ export function uiAgentPacketForProjection(graph, projection) {
9
+ const projectionType = projection.type || projection.type || null;
10
+ if (projectionType !== "ui_contract" && !String(projectionType || "").endsWith("_surface")) {
11
+ return null;
12
+ }
13
+ const sharedProjection = projectionType === "ui_contract"
14
+ ? projection
15
+ : sharedUiProjectionFor(graph, projection);
16
+ const ownerProjection = sharedProjection || projection;
17
+ return {
18
+ type: "ui_agent_packet",
19
+ version: 1,
20
+ ownership: {
21
+ widgetPlacement: "ui_contract",
22
+ designIntent: "ui_contract",
23
+ concreteSurfaceOwns: ["routes", "surface_hints"]
24
+ },
25
+ sharedProjection: sharedProjection
26
+ ? {
27
+ id: sharedProjection.id,
28
+ name: sharedProjection.name || sharedProjection.id
29
+ }
30
+ : null,
31
+ screens: (ownerProjection.uiScreens || []).map(/** @param {any} screen */ (screen) => ({
32
+ id: screen.id,
33
+ kind: screen.kind,
34
+ title: screen.title || screen.id
35
+ })),
36
+ routes: (projection.uiRoutes || []).map(/** @param {any} route */ (route) => ({
37
+ screenId: route.screenId,
38
+ path: route.path
39
+ })),
40
+ widgets: (ownerProjection.widgetBindings || []).map(/** @param {import("../shared/types.d.ts").ContextWidgetUsage} usage */ (usage) => widgetUsagePacket(usage, ownerProjection)),
41
+ designTokens: designIntentPacket(ownerProjection),
42
+ requiredGates: uiRequiredGates(projection.id)
43
+ };
44
+ }
45
+
46
+ /**
47
+ * @param {import("../shared/types.d.ts").ContextGraph} graph
48
+ * @param {import("../shared/types.d.ts").ContextWidget} widget
49
+ * @param {Iterable<string>} projectionIds
50
+ * @returns {any}
51
+ */
52
+ export function uiAgentPacketForWidget(graph, widget, projectionIds) {
53
+ const projectionSet = new Set(projectionIds);
54
+ const sourceUsages = /** @type {any[]} */ ([]);
55
+ for (const projection of graph.byKind.projection || []) {
56
+ for (const usage of projection.widgetBindings || []) {
57
+ if (usage.widget?.id !== widget.id) continue;
58
+ const projectionType = projection.type || projection.type || null;
59
+ sourceUsages.push({
60
+ projection: {
61
+ id: projection.id,
62
+ type: projectionType,
63
+ ownership: projectionType === "ui_contract" ? "owner" : "concrete"
64
+ },
65
+ usage: widgetUsagePacket(usage, projection),
66
+ designTokens: designIntentPacket(projection)
67
+ });
68
+ projectionSet.add(projection.id);
69
+ }
70
+ }
71
+
72
+ return {
73
+ type: "ui_agent_packet",
74
+ version: 1,
75
+ ownership: {
76
+ widgetContract: "widget",
77
+ widgetPlacement: "ui_contract",
78
+ concreteSurfacesInherit: true
79
+ },
80
+ widget: {
81
+ id: widget.id,
82
+ name: widget.name || widget.id,
83
+ category: widget.category || null,
84
+ patterns: widget.widgetContract?.patterns || [],
85
+ regions: widget.widgetContract?.regions || [],
86
+ behaviors: widget.widgetContract?.behaviors || []
87
+ },
88
+ sourceUsages,
89
+ inheritedBy: [...projectionSet]
90
+ .filter((projectionId) => !sourceUsages.some(/** @param {any} entry */ (entry) => entry.projection.id === projectionId))
91
+ .sort(),
92
+ requiredGates: uiRequiredGates(null, widget.id)
93
+ };
94
+ }
95
+
96
+ /**
97
+ * @param {import("../shared/types.d.ts").ContextGraph} graph
98
+ * @param {import("../shared/types.d.ts").ContextProjection} projection
99
+ * @returns {any}
100
+ */
101
+ function sharedUiProjectionFor(graph, projection) {
102
+ for (const reference of projection.realizes || []) {
103
+ const candidate = (graph.byKind.projection || []).find(/** @param {any} entry */ (entry) => entry.id === reference.id);
104
+ if ((candidate?.type || candidate?.type) === "ui_contract") {
105
+ return candidate;
106
+ }
107
+ }
108
+ return null;
109
+ }
110
+
111
+ /**
112
+ * @param {import("../shared/types.d.ts").ContextWidgetUsage} usage
113
+ * @param {import("../shared/types.d.ts").ContextProjection | null} projection
114
+ * @returns {any}
115
+ */
116
+ function widgetUsagePacket(usage, projection = null) {
117
+ const screen = (projection?.uiScreens || []).find(/** @param {any} entry */ (entry) => entry.id === usage.screenId) || null;
118
+ const region = (projection?.uiScreenRegions || []).find(/** @param {any} entry */ (entry) =>
119
+ entry.screenId === usage.screenId && entry.region === usage.region
120
+ ) || null;
121
+ return {
122
+ screenId: usage.screenId || null,
123
+ screen: screen
124
+ ? {
125
+ id: screen.id,
126
+ kind: screen.kind || null,
127
+ title: screen.title || screen.id
128
+ }
129
+ : null,
130
+ region: usage.region || null,
131
+ regionContract: region
132
+ ? {
133
+ name: region.region || null,
134
+ pattern: region.pattern || null,
135
+ placement: region.placement || null,
136
+ title: region.title || null,
137
+ state: region.state || null,
138
+ variant: region.variant || null
139
+ }
140
+ : null,
141
+ widgetId: usage.widget?.id || null,
142
+ dataBindings: (usage.dataBindings || []).map(/** @param {any} binding */ (binding) => ({
143
+ prop: binding.prop || null,
144
+ source: binding.source?.id || binding.source || null
145
+ })),
146
+ eventBindings: (usage.eventBindings || []).map(/** @param {any} binding */ (binding) => ({
147
+ event: binding.event || null,
148
+ action: binding.action || null,
149
+ target: binding.target?.id || binding.target || null
150
+ }))
151
+ };
152
+ }
153
+
154
+ /**
155
+ * @param {import("../shared/types.d.ts").ContextProjection} projection
156
+ * @returns {any}
157
+ */
158
+ function designIntentPacket(projection) {
159
+ return (projection.uiDesign || []).map(/** @param {any} entry */ (entry) => ({
160
+ key: entry.key,
161
+ role: entry.role,
162
+ value: entry.value
163
+ }));
164
+ }
165
+
166
+ /**
167
+ * @param {string | null} projectionId
168
+ * @param {string | null} widgetId
169
+ * @returns {any}
170
+ */
171
+ function uiRequiredGates(projectionId = null, widgetId = null) {
172
+ return [
173
+ { command: "topogram check", reason: "Validate shared UI ownership, taxonomy, references, and topology." },
174
+ {
175
+ command: `topogram widget check${projectionId ? ` --projection ${projectionId}` : ""}${widgetId ? ` --widget ${widgetId}` : ""}`,
176
+ reason: "Validate widget placement, props, events, regions, and patterns."
177
+ },
178
+ {
179
+ command: `topogram widget behavior${projectionId ? ` --projection ${projectionId}` : ""}${widgetId ? ` --widget ${widgetId}` : ""}`,
180
+ reason: "Inspect behavior realizations and partial bindings before code changes."
181
+ }
182
+ ];
183
+ }