@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
@@ -347,7 +347,7 @@ export function buildPromotedCanonicalItems(planItems, selectedItems, writtenCan
347
347
  track: item.track || null,
348
348
  source_path: item.source_path || null,
349
349
  canonical_rel_path: normalizeReportPath(item.canonical_rel_path),
350
- canonical_path: item.canonical_path || `topogram/${normalizeReportPath(item.canonical_rel_path)}`,
350
+ canonical_path: item.canonical_path || `topo/${normalizeReportPath(item.canonical_rel_path)}`,
351
351
  suggested_action: item.suggested_action || null,
352
352
  change_type: updatedSet.has(normalizeReportPath(item.canonical_rel_path)) ? "update" : "create"
353
353
  }))
@@ -20,6 +20,7 @@ import {
20
20
  getTemplateTrustStatus,
21
21
  TEMPLATE_TRUST_FILE
22
22
  } from "./template-trust.js";
23
+ import { DEFAULT_TOPO_FOLDER_NAME, resolveTopoRoot, resolveWorkspaceContext } from "./workspace-paths.js";
23
24
 
24
25
  /**
25
26
  * @typedef {{ path: string, reason: string, required: boolean, exists: boolean }} AgentBriefReadItem
@@ -36,12 +37,7 @@ import {
36
37
  * @returns {string}
37
38
  */
38
39
  export function normalizeAgentTopogramPath(inputPath) {
39
- const resolved = path.resolve(inputPath || "./topogram");
40
- if (path.basename(resolved) === "topogram") {
41
- return resolved;
42
- }
43
- const nested = path.join(resolved, "topogram");
44
- return fs.existsSync(nested) && fs.statSync(nested).isDirectory() ? nested : resolved;
40
+ return resolveTopoRoot(inputPath || ".");
45
41
  }
46
42
 
47
43
  /**
@@ -49,17 +45,7 @@ export function normalizeAgentTopogramPath(inputPath) {
49
45
  * @returns {string}
50
46
  */
51
47
  function normalizeProjectRoot(inputPath) {
52
- const resolved = path.resolve(inputPath || ".");
53
- if (path.basename(resolved) === "topogram") {
54
- return path.dirname(resolved);
55
- }
56
- if (fs.existsSync(path.join(resolved, "topogram.project.json"))) {
57
- return resolved;
58
- }
59
- if (fs.existsSync(path.join(resolved, "topogram"))) {
60
- return resolved;
61
- }
62
- return path.dirname(normalizeAgentTopogramPath(inputPath));
48
+ return resolveWorkspaceContext(inputPath || ".").projectRoot;
63
49
  }
64
50
 
65
51
  /**
@@ -325,7 +311,7 @@ export function buildAgentBrief(inputPath, workspaceAst) {
325
311
  const generatorDiagnostics = generatorPolicyDiagnosticsForBindings(generatorPolicyInfo, generatorBindings, "agent-brief");
326
312
  const importSummary = readImportSummary(configDir);
327
313
 
328
- const topogramReadPath = path.resolve(topogramRoot) === path.resolve(projectRoot) ? "." : "topogram/";
314
+ const topogramReadPath = path.resolve(topogramRoot) === path.resolve(projectRoot) ? "." : `${DEFAULT_TOPO_FOLDER_NAME}/`;
329
315
  const readOrder = [
330
316
  readItem(projectRoot, "AGENTS.md", "Human-readable first-run guidance generated with this project.", false),
331
317
  readItem(projectRoot, "README.md", "Project workflow and template provenance summary.", true),
@@ -394,7 +380,7 @@ export function buildAgentBrief(inputPath, workspaceAst) {
394
380
  first_commands: firstCommands,
395
381
  edit_boundaries: {
396
382
  safe_paths: [
397
- "topogram/**",
383
+ `${DEFAULT_TOPO_FOLDER_NAME}/**`,
398
384
  "topogram.project.json",
399
385
  "topogram.template-policy.json",
400
386
  GENERATOR_POLICY_FILE,
@@ -405,8 +391,8 @@ export function buildAgentBrief(inputPath, workspaceAst) {
405
391
  },
406
392
  workflows: buildWorkflows(config, Boolean(importSummary)),
407
393
  file_organization: {
408
- small: ["topogram/actors", "topogram/entities", "topogram/shapes", "topogram/capabilities", "topogram/widgets", "topogram/projections", "topogram/verifications"],
409
- large: ["topogram/domains/<domain>", "topogram/shared", "topogram/domains/<domain>/widgets", "topogram/domains/<domain>/projections"],
394
+ small: [`${DEFAULT_TOPO_FOLDER_NAME}/actors`, `${DEFAULT_TOPO_FOLDER_NAME}/entities`, `${DEFAULT_TOPO_FOLDER_NAME}/shapes`, `${DEFAULT_TOPO_FOLDER_NAME}/capabilities`, `${DEFAULT_TOPO_FOLDER_NAME}/widgets`, `${DEFAULT_TOPO_FOLDER_NAME}/projections`, `${DEFAULT_TOPO_FOLDER_NAME}/verifications`],
395
+ large: [`${DEFAULT_TOPO_FOLDER_NAME}/domains/<domain>`, `${DEFAULT_TOPO_FOLDER_NAME}/shared`, `${DEFAULT_TOPO_FOLDER_NAME}/domains/<domain>/widgets`, `${DEFAULT_TOPO_FOLDER_NAME}/domains/<domain>/projections`],
410
396
  parserRule: "Folder layout is for humans and agents; Topogram flattens statements into one graph."
411
397
  },
412
398
  topology: {
@@ -0,0 +1,375 @@
1
+ export function formatAuthClaimValueInline(value) {
2
+ return value == null ? "_dynamic_" : `${value}`;
3
+ }
4
+
5
+ export function normalizeReviewGroupSelector(id) {
6
+ const normalized = String(id || "");
7
+ if (normalized.startsWith("projection_review:")) {
8
+ return `projection-review:${normalized.slice("projection_review:".length)}`;
9
+ }
10
+ if (normalized.startsWith("ui_review:")) {
11
+ return `ui-review:${normalized.slice("ui_review:".length)}`;
12
+ }
13
+ if (normalized.startsWith("workflow_review:")) {
14
+ return `workflow-review:${normalized.slice("workflow_review:".length)}`;
15
+ }
16
+ return null;
17
+ }
18
+
19
+ export function buildHintLabel(hintType, hint) {
20
+ if (hintType === "permission") {
21
+ return `permission ${hint.permission}`;
22
+ }
23
+ if (hintType === "claim") {
24
+ return `claim ${hint.claim} = ${formatAuthClaimValueInline(hint.claim_value)}`;
25
+ }
26
+ return `ownership ${hint.ownership} ownership_field ${hint.ownership_field}`;
27
+ }
28
+
29
+ export function flattenHints(candidateModelBundles = []) {
30
+ const hintGroups = [
31
+ {
32
+ collection: "auth_permission_hints",
33
+ hintType: "permission",
34
+ action: "apply_projection_permission_patch"
35
+ },
36
+ {
37
+ collection: "auth_claim_hints",
38
+ hintType: "claim",
39
+ action: "apply_projection_auth_patch"
40
+ },
41
+ {
42
+ collection: "auth_ownership_hints",
43
+ hintType: "ownership",
44
+ action: "apply_projection_ownership_patch"
45
+ }
46
+ ];
47
+ return candidateModelBundles.flatMap((bundle) =>
48
+ hintGroups.flatMap(({ collection, hintType, action }) =>
49
+ (bundle[collection] || []).map((hint) => ({
50
+ bundle: bundle.slug,
51
+ hint_type: hintType,
52
+ hint_label: buildHintLabel(hintType, hint),
53
+ confidence: hint.confidence || null,
54
+ related_capabilities: hint.related_capabilities || [],
55
+ closure_state: hint.closure_state || "unresolved",
56
+ closure_reason: hint.closure_reason || null,
57
+ why_inferred: hint.why_inferred || hint.explanation || null,
58
+ review_guidance: hint.review_guidance || null,
59
+ projection_patch_action: action
60
+ }))
61
+ )
62
+ );
63
+ }
64
+
65
+ export function flattenAuthRoleFollowup(candidateModelBundles = []) {
66
+ return candidateModelBundles.flatMap((bundle) =>
67
+ (bundle.auth_role_guidance || []).map((entry) => ({
68
+ bundle: bundle.slug,
69
+ role_id: entry.role_id,
70
+ confidence: entry.confidence || null,
71
+ followup_action: entry.followup_action || null,
72
+ followup_label: entry.followup_label || null,
73
+ followup_reason: entry.followup_reason || null,
74
+ review_guidance: entry.review_guidance || null,
75
+ related_capabilities: entry.related_capabilities || [],
76
+ related_docs: entry.related_docs || []
77
+ }))
78
+ );
79
+ }
80
+
81
+ export function buildHighRiskBundles(bundlePriorities = []) {
82
+ return (bundlePriorities || [])
83
+ .filter((bundle) => bundle.auth_closure_summary?.status === "high_risk")
84
+ .map((bundle) => ({
85
+ bundle: bundle.bundle,
86
+ auth_closure: bundle.auth_closure_summary || null,
87
+ auth_aging: bundle.auth_aging_summary || null,
88
+ next_review_group: bundle.next_review_groups?.[0]
89
+ ? {
90
+ id: bundle.next_review_groups[0].id,
91
+ type: bundle.next_review_groups[0].type || null,
92
+ reason: bundle.next_review_groups[0].reason || null,
93
+ selector: normalizeReviewGroupSelector(bundle.next_review_groups[0].id)
94
+ }
95
+ : null,
96
+ bundle_review_selector: bundle.recommend_bundle_review_selector || null,
97
+ from_plan_ready: Boolean(bundle.recommend_from_plan)
98
+ }));
99
+ }
100
+
101
+ export function buildBundleReviewSummary(bundle) {
102
+ if (!bundle) {
103
+ return null;
104
+ }
105
+ return {
106
+ bundle: bundle.bundle,
107
+ auth_closure: bundle.auth_closure_summary || null,
108
+ auth_aging: bundle.auth_aging_summary || null,
109
+ next_review_group: bundle.next_review_groups?.[0]
110
+ ? {
111
+ id: bundle.next_review_groups[0].id,
112
+ type: bundle.next_review_groups[0].type || null,
113
+ reason: bundle.next_review_groups[0].reason || null,
114
+ selector: normalizeReviewGroupSelector(bundle.next_review_groups[0].id)
115
+ }
116
+ : null,
117
+ bundle_review_selector: bundle.recommend_bundle_review_selector || null,
118
+ from_plan_ready: Boolean(bundle.recommend_from_plan)
119
+ };
120
+ }
121
+
122
+ export function buildRecommendedSteps({ highRiskBundles, authRoleFollowup, nextBundle }) {
123
+ const priorityBundles = [];
124
+ if (nextBundle?.bundle) {
125
+ priorityBundles.push(nextBundle.bundle);
126
+ }
127
+ for (const bundle of highRiskBundles || []) {
128
+ if (!priorityBundles.includes(bundle.bundle)) {
129
+ priorityBundles.push(bundle.bundle);
130
+ }
131
+ }
132
+
133
+ const highRiskMap = new Map((highRiskBundles || []).map((bundle) => [bundle.bundle, bundle]));
134
+ const roleMap = new Map();
135
+ for (const entry of authRoleFollowup || []) {
136
+ if (!roleMap.has(entry.bundle)) {
137
+ roleMap.set(entry.bundle, []);
138
+ }
139
+ roleMap.get(entry.bundle).push(entry);
140
+ }
141
+
142
+ const steps = [];
143
+ for (const bundleId of priorityBundles) {
144
+ const bundle = highRiskMap.get(bundleId);
145
+ if (!bundle) {
146
+ continue;
147
+ }
148
+ const nextReviewSelector = bundle.next_review_group?.selector || null;
149
+ if (nextReviewSelector?.startsWith("projection-review:")) {
150
+ steps.push({
151
+ bundle: bundle.bundle,
152
+ action: "review_projection_group",
153
+ selector: nextReviewSelector,
154
+ reason: bundle.next_review_group.reason || "Projection review is still required before auth hints can be adopted safely."
155
+ });
156
+ } else if (bundle.bundle_review_selector) {
157
+ steps.push({
158
+ bundle: bundle.bundle,
159
+ action: "review_bundle",
160
+ selector: bundle.bundle_review_selector,
161
+ reason: bundle.next_review_group?.reason || "Bundle review is the safest next step before promoting auth-sensitive changes."
162
+ });
163
+ }
164
+
165
+ for (const entry of roleMap.get(bundle.bundle) || []) {
166
+ if (entry.followup_action === "promote_role") {
167
+ steps.push({
168
+ bundle: bundle.bundle,
169
+ action: "promote_role_first",
170
+ selector: null,
171
+ reason: entry.followup_reason || `Promote role ${entry.role_id} before promoting related auth-sensitive changes.`
172
+ });
173
+ } else if (entry.followup_action === "link_role_to_docs") {
174
+ steps.push({
175
+ bundle: bundle.bundle,
176
+ action: "patch_docs_first",
177
+ selector: null,
178
+ reason: entry.followup_reason || `Patch docs for role ${entry.role_id} before promoting related auth-sensitive changes.`
179
+ });
180
+ }
181
+ }
182
+
183
+ if (bundle.from_plan_ready) {
184
+ steps.push({
185
+ bundle: bundle.bundle,
186
+ action: "run_from_plan_write",
187
+ selector: "from-plan",
188
+ reason: "Reviewed auth-sensitive items are ready to promote through from-plan adoption."
189
+ });
190
+ }
191
+ }
192
+ return steps;
193
+ }
194
+
195
+ export function buildAuthHintsQueryPayload(report, adoptionStatus) {
196
+ const candidateModelBundles = report?.candidate_model_bundles || [];
197
+ const bundlePriorities = adoptionStatus?.bundle_priorities || report?.bundle_priorities || [];
198
+ const allHints = flattenHints(candidateModelBundles);
199
+ const authRoleFollowup = flattenAuthRoleFollowup(candidateModelBundles);
200
+ const highRiskBundles = buildHighRiskBundles(bundlePriorities);
201
+ const staleHighRiskBundles = highRiskBundles.filter((bundle) => bundle.auth_aging?.escalationLevel === "stale_high_risk");
202
+ const bundlesWithHints = candidateModelBundles.filter((bundle) =>
203
+ (bundle.auth_permission_hints || []).length > 0 ||
204
+ (bundle.auth_claim_hints || []).length > 0 ||
205
+ (bundle.auth_ownership_hints || []).length > 0
206
+ );
207
+
208
+ const hintClosureCounts = allHints.reduce(
209
+ (acc, hint) => {
210
+ if (hint.closure_state === "adopted") {
211
+ acc.adopted += 1;
212
+ } else if (hint.closure_state === "deferred") {
213
+ acc.deferred += 1;
214
+ } else {
215
+ acc.unresolved += 1;
216
+ }
217
+ return acc;
218
+ },
219
+ { adopted: 0, deferred: 0, unresolved: 0 }
220
+ );
221
+
222
+ const bundleClosureCounts = candidateModelBundles.reduce(
223
+ (acc, bundle) => {
224
+ const status = bundle.operator_summary?.authClosureSummary?.status || "no_auth_hints";
225
+ acc[status] = (acc[status] || 0) + 1;
226
+ return acc;
227
+ },
228
+ { no_auth_hints: 0, mostly_closed: 0, partially_closed: 0, high_risk: 0 }
229
+ );
230
+
231
+ return {
232
+ type: "auth_hints_query",
233
+ workspace: report?.workspace || adoptionStatus?.workspace || null,
234
+ summary: {
235
+ total_bundles_with_auth_hints: bundlesWithHints.length,
236
+ hint_closure_counts: hintClosureCounts,
237
+ bundle_auth_closure_counts: bundleClosureCounts,
238
+ stale_high_risk_bundle_count: staleHighRiskBundles.length
239
+ },
240
+ high_risk_bundles: highRiskBundles,
241
+ stale_high_risk_bundles: staleHighRiskBundles,
242
+ unresolved_hints: allHints.filter((hint) => hint.closure_state === "unresolved"),
243
+ deferred_hints: allHints.filter((hint) => hint.closure_state === "deferred"),
244
+ adopted_hints: allHints.filter((hint) => hint.closure_state === "adopted"),
245
+ auth_role_followup: authRoleFollowup,
246
+ recommended_steps: buildRecommendedSteps({
247
+ highRiskBundles,
248
+ authRoleFollowup,
249
+ nextBundle: adoptionStatus?.next_bundle || null
250
+ })
251
+ };
252
+ }
253
+
254
+ export function buildProjectionPatchActionsForBundle(hints = []) {
255
+ const actions = new Map();
256
+ for (const hint of hints) {
257
+ const actionId = hint.projection_patch_action;
258
+ if (!actionId) {
259
+ continue;
260
+ }
261
+ if (!actions.has(actionId)) {
262
+ actions.set(actionId, {
263
+ action: actionId,
264
+ hint_types: [],
265
+ hint_labels: []
266
+ });
267
+ }
268
+ const entry = actions.get(actionId);
269
+ if (hint.hint_type && !entry.hint_types.includes(hint.hint_type)) {
270
+ entry.hint_types.push(hint.hint_type);
271
+ }
272
+ if (hint.hint_label && !entry.hint_labels.includes(hint.hint_label)) {
273
+ entry.hint_labels.push(hint.hint_label);
274
+ }
275
+ }
276
+ return [...actions.values()];
277
+ }
278
+
279
+ export function buildBundleRecommendedSteps({ bundle, authRoleFollowup = [] }) {
280
+ if (!bundle) {
281
+ return [];
282
+ }
283
+
284
+ const steps = [];
285
+ const nextReviewSelector = bundle.next_review_group?.selector || null;
286
+ if (nextReviewSelector?.startsWith("projection-review:")) {
287
+ steps.push({
288
+ bundle: bundle.bundle,
289
+ action: "review_projection_group",
290
+ selector: nextReviewSelector,
291
+ reason: bundle.next_review_group.reason || "Projection review is still required before auth hints can be adopted safely."
292
+ });
293
+ } else if (bundle.bundle_review_selector) {
294
+ steps.push({
295
+ bundle: bundle.bundle,
296
+ action: "review_bundle",
297
+ selector: bundle.bundle_review_selector,
298
+ reason: bundle.next_review_group?.reason || "Bundle review is the safest next step before promoting auth-sensitive changes."
299
+ });
300
+ }
301
+
302
+ for (const entry of authRoleFollowup || []) {
303
+ if (entry.followup_action === "promote_role") {
304
+ steps.push({
305
+ bundle: bundle.bundle,
306
+ action: "promote_role_first",
307
+ selector: null,
308
+ reason: entry.followup_reason || `Promote role ${entry.role_id} before promoting related auth-sensitive changes.`
309
+ });
310
+ } else if (entry.followup_action === "link_role_to_docs") {
311
+ steps.push({
312
+ bundle: bundle.bundle,
313
+ action: "patch_docs_first",
314
+ selector: null,
315
+ reason: entry.followup_reason || `Patch docs for role ${entry.role_id} before promoting related auth-sensitive changes.`
316
+ });
317
+ }
318
+ }
319
+
320
+ if (bundle.from_plan_ready) {
321
+ steps.push({
322
+ bundle: bundle.bundle,
323
+ action: "run_from_plan_write",
324
+ selector: "from-plan",
325
+ reason: "Reviewed auth-sensitive items are ready to promote through from-plan adoption."
326
+ });
327
+ }
328
+
329
+ return steps;
330
+ }
331
+
332
+ export function buildAuthReviewPacketPayload(report, adoptionStatus, bundleSlug) {
333
+ const candidateModelBundles = report?.candidate_model_bundles || [];
334
+ const bundlePriorities = adoptionStatus?.bundle_priorities || report?.bundle_priorities || [];
335
+ const targetBundle = candidateModelBundles.find((bundle) => bundle.slug === bundleSlug) || null;
336
+ if (!targetBundle) {
337
+ return null;
338
+ }
339
+
340
+ const bundlePriority = bundlePriorities.find((bundle) => bundle.bundle === bundleSlug) || null;
341
+ const allBundleHints = flattenHints([targetBundle]);
342
+ const unresolvedHints = allBundleHints.filter((hint) => hint.closure_state === "unresolved");
343
+ const deferredHints = allBundleHints.filter((hint) => hint.closure_state === "deferred");
344
+ const adoptedHints = allBundleHints.filter((hint) => hint.closure_state === "adopted");
345
+ const authRoleFollowup = flattenAuthRoleFollowup([targetBundle]);
346
+ const projectionPatchActions = buildProjectionPatchActionsForBundle([...unresolvedHints, ...deferredHints, ...adoptedHints]);
347
+ const highRiskBundle = buildBundleReviewSummary(bundlePriority) || {
348
+ bundle: bundleSlug,
349
+ auth_closure: targetBundle.operator_summary?.authClosureSummary || null,
350
+ auth_aging: targetBundle.operator_summary?.authAging || null,
351
+ next_review_group: null,
352
+ bundle_review_selector: null,
353
+ from_plan_ready: false
354
+ };
355
+
356
+ return {
357
+ type: "auth_review_packet_query",
358
+ workspace: report?.workspace || adoptionStatus?.workspace || null,
359
+ bundle: bundleSlug,
360
+ auth_closure: highRiskBundle.auth_closure,
361
+ auth_aging: highRiskBundle.auth_aging,
362
+ next_review_selector: highRiskBundle.next_review_group?.selector || null,
363
+ bundle_review_selector: highRiskBundle.bundle_review_selector || null,
364
+ from_plan_ready: Boolean(highRiskBundle.from_plan_ready),
365
+ unresolved_hints: unresolvedHints,
366
+ deferred_hints: deferredHints,
367
+ adopted_hints: adoptedHints,
368
+ auth_role_followup: authRoleFollowup,
369
+ projection_patch_actions: projectionPatchActions,
370
+ recommended_steps: buildBundleRecommendedSteps({
371
+ bundle: highRiskBundle,
372
+ authRoleFollowup
373
+ })
374
+ };
375
+ }
@@ -0,0 +1,123 @@
1
+ import {
2
+ stableSortedStrings,
3
+ summarizeDiffArtifact
4
+ } from "../common.js";
5
+ import {
6
+ buildGeneratorTargets,
7
+ buildProjectionImpacts
8
+ } from "../projection-impacts.js";
9
+ import {
10
+ buildMaintainedImpacts
11
+ } from "../maintained-risk.js";
12
+
13
+ export function classifyChangePlan(changePlan, diffArtifact, projectionImpacts, generatorTargets, maintainedImpacts) {
14
+ const focusKind = changePlan.focus?.kind || null;
15
+ const semanticSections = diffArtifact
16
+ ? ["entities", "capabilities", "components", "rules", "workflows", "journeys", "shapes", "projections"]
17
+ .filter((section) => (diffArtifact[section] || []).length > 0)
18
+ : [];
19
+ let classification = "context_review";
20
+ if (diffArtifact) {
21
+ classification = semanticSections.length > 0 ? "semantic_diff" : "diff_without_semantic_change";
22
+ } else if (focusKind === "projection") {
23
+ classification = "projection_focused_change";
24
+ } else if (focusKind === "capability" || focusKind === "entity") {
25
+ classification = "surface_closure_review";
26
+ }
27
+ if (maintainedImpacts.maintained_code_likely_impacted) {
28
+ classification = `${classification}_with_maintained_followup`;
29
+ }
30
+
31
+ return {
32
+ classification,
33
+ selected_mode: changePlan.mode,
34
+ focus: changePlan.focus,
35
+ has_diff_baseline: Boolean(diffArtifact),
36
+ semantic_sections_changed: semanticSections,
37
+ affected_projection_count: projectionImpacts.length,
38
+ affected_output_count: maintainedImpacts.affected_outputs.length,
39
+ affected_seam_count: maintainedImpacts.affected_seams.length,
40
+ recommended_generator_count: generatorTargets.length,
41
+ maintained_code_likely_impacted: maintainedImpacts.maintained_code_likely_impacted
42
+ };
43
+ }
44
+
45
+ export function buildAlignmentRecommendations(changePlan, projectionImpacts, generatorTargets, maintainedImpacts) {
46
+ const recommendations = [
47
+ {
48
+ action: "inspect_semantic_scope",
49
+ order: 1,
50
+ reason: changePlan.diff_summary
51
+ ? "Review the semantic diff and affected projection closure before regenerating downstream surfaces."
52
+ : "Review the selected surface and its projection closure before regenerating downstream surfaces."
53
+ }
54
+ ];
55
+
56
+ if (projectionImpacts.length > 0) {
57
+ recommendations.push({
58
+ action: "regenerate_projection_targets",
59
+ order: 2,
60
+ reason: `Regenerate the recommended targets for ${projectionImpacts.length} affected projection(s).`,
61
+ targets: stableSortedStrings(generatorTargets.map((entry) => entry.target))
62
+ });
63
+ }
64
+
65
+ if (maintainedImpacts.maintained_code_likely_impacted) {
66
+ recommendations.push({
67
+ action: "review_maintained_followup",
68
+ order: 3,
69
+ reason: "Maintained code is likely impacted, so human-owned seams should be reviewed after regeneration.",
70
+ maintained_files_in_scope: maintainedImpacts.maintained_files_in_scope,
71
+ affected_outputs: stableSortedStrings(maintainedImpacts.affected_outputs.map((output) => output.output_id)),
72
+ affected_seams: stableSortedStrings(maintainedImpacts.affected_seams.map((seam) => seam.seam_id || seam.label))
73
+ });
74
+ }
75
+
76
+ recommendations.push({
77
+ action: "run_verification_targets",
78
+ order: maintainedImpacts.maintained_code_likely_impacted ? 4 : 3,
79
+ reason: "Run the smallest recommended proof set once generated and maintained surfaces are aligned.",
80
+ verification_targets: changePlan.verification_targets || null,
81
+ output_verification_targets: maintainedImpacts.affected_outputs.map((output) => ({
82
+ output_id: output.output_id,
83
+ verification_targets: output.verification_targets || null
84
+ }))
85
+ });
86
+
87
+ return recommendations;
88
+ }
89
+
90
+ export function buildChangePlanPayload({ graph, taskModeArtifact, sliceArtifact, diffArtifact, maintainedBoundaryArtifact }) {
91
+ const basePayload = {
92
+ type: "change_plan_query",
93
+ mode: taskModeArtifact.mode,
94
+ focus: sliceArtifact?.focus || taskModeArtifact.summary?.selected_surface || null,
95
+ summary: taskModeArtifact.summary || null,
96
+ preferred_context_artifacts: taskModeArtifact.preferred_context_artifacts || [],
97
+ next_action: taskModeArtifact.next_action || null,
98
+ review_boundary: sliceArtifact?.review_boundary || null,
99
+ ownership_boundary: sliceArtifact?.ownership_boundary || taskModeArtifact.ownership_boundary || null,
100
+ write_scope: taskModeArtifact.write_scope || sliceArtifact?.write_scope || null,
101
+ verification_targets: taskModeArtifact.verification_targets || sliceArtifact?.verification_targets || null,
102
+ maintained_boundary: maintainedBoundaryArtifact || null,
103
+ diff_summary: summarizeDiffArtifact(diffArtifact)
104
+ };
105
+
106
+ const projectionImpacts = graph ? buildProjectionImpacts(graph, { sliceArtifact, diffArtifact }) : [];
107
+ const generatorTargets = graph ? buildGeneratorTargets(graph, projectionImpacts, diffArtifact) : [];
108
+ const maintainedImpacts = buildMaintainedImpacts({
109
+ diffArtifact,
110
+ maintainedBoundaryArtifact,
111
+ sliceArtifact,
112
+ verificationTargets: basePayload.verification_targets
113
+ });
114
+
115
+ return {
116
+ ...basePayload,
117
+ change_summary: classifyChangePlan(basePayload, diffArtifact, projectionImpacts, generatorTargets, maintainedImpacts),
118
+ projection_impacts: projectionImpacts,
119
+ generator_targets: generatorTargets,
120
+ maintained_impacts: maintainedImpacts,
121
+ alignment_recommendations: buildAlignmentRecommendations(basePayload, projectionImpacts, generatorTargets, maintainedImpacts)
122
+ };
123
+ }
@@ -0,0 +1,49 @@
1
+ import { buildImportMaintainedRisk } from "../maintained-risk.js";
2
+ import { buildImportPlanNextAction } from "../workflow-presets-core.js";
3
+ import { buildPresetGuidanceSummary } from "./risk.js";
4
+
5
+ export function buildImportPlanPayload(adoptionPlan, taskModeArtifact, maintainedBoundaryArtifact = null, workflowPresetState = null) {
6
+ const importMaintained = buildImportMaintainedRisk(adoptionPlan.imported_proposal_surfaces || [], maintainedBoundaryArtifact);
7
+ const importNextAction = buildImportPlanNextAction(taskModeArtifact.next_action || null, workflowPresetState);
8
+ const presetGuidanceSummary = buildPresetGuidanceSummary(workflowPresetState, null);
9
+ return {
10
+ type: "import_plan_query",
11
+ summary: taskModeArtifact.summary || null,
12
+ adoption_state_vocabulary: adoptionPlan.adoption_state_vocabulary || [],
13
+ next_action: importNextAction,
14
+ write_scope: taskModeArtifact.write_scope || null,
15
+ verification_targets: taskModeArtifact.verification_targets || null,
16
+ review_groups: adoptionPlan.approved_review_groups || [],
17
+ staged_items: adoptionPlan.staged_items || [],
18
+ accepted_items: adoptionPlan.accepted_items || [],
19
+ rejected_items: adoptionPlan.rejected_items || [],
20
+ requires_human_review: adoptionPlan.requires_human_review || [],
21
+ proposal_surfaces: importMaintained.proposal_surfaces,
22
+ maintained_risk: importMaintained.maintained_risk,
23
+ maintained_seam_review_summary: importMaintained.maintained_seam_review_summary,
24
+ preset_guidance_summary: presetGuidanceSummary,
25
+ active_preset_ids: presetGuidanceSummary.active_preset_ids,
26
+ preset_blockers: presetGuidanceSummary.preset_blockers,
27
+ recommended_preset_action: presetGuidanceSummary.recommended_preset_action,
28
+ workflow_presets: workflowPresetState || {
29
+ provider: [],
30
+ team: [],
31
+ active_provider_count: 0,
32
+ active_team_count: 0,
33
+ workflow_preset_surfaces: [],
34
+ workflow_preset_refresh_summary: {
35
+ type: "workflow_preset_diff_query",
36
+ diffs: [],
37
+ summary: {
38
+ diff_count: 0,
39
+ new_count: 0,
40
+ unchanged_count: 0,
41
+ changed_count: 0,
42
+ locally_customized_count: 0,
43
+ orphaned_customization_count: 0,
44
+ requires_fresh_review_count: 0
45
+ }
46
+ }
47
+ }
48
+ };
49
+ }