@topogram/cli 0.3.34

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 (257) hide show
  1. package/ARCHITECTURE.md +67 -0
  2. package/CHANGELOG.md +240 -0
  3. package/README.md +223 -0
  4. package/package.json +51 -0
  5. package/src/adoption/index.js +3 -0
  6. package/src/adoption/plan.js +702 -0
  7. package/src/adoption/reporting.js +464 -0
  8. package/src/adoption/review-groups.js +313 -0
  9. package/src/agent-ops/query-builders.js +5012 -0
  10. package/src/archive/archive.js +141 -0
  11. package/src/archive/compact.js +26 -0
  12. package/src/archive/jsonl.js +70 -0
  13. package/src/archive/resolver-bridge.js +82 -0
  14. package/src/archive/schema.js +87 -0
  15. package/src/archive/unarchive.js +108 -0
  16. package/src/catalog.js +752 -0
  17. package/src/cli/catalog-alias.js +166 -0
  18. package/src/cli.js +9738 -0
  19. package/src/component-behavior.js +173 -0
  20. package/src/example-implementation.js +91 -0
  21. package/src/format.js +19 -0
  22. package/src/generator/adapters.d.ts +4 -0
  23. package/src/generator/adapters.js +325 -0
  24. package/src/generator/api.d.ts +1 -0
  25. package/src/generator/api.js +1196 -0
  26. package/src/generator/check.js +355 -0
  27. package/src/generator/component-conformance.js +767 -0
  28. package/src/generator/components.js +39 -0
  29. package/src/generator/context/bundle.js +291 -0
  30. package/src/generator/context/diff.js +256 -0
  31. package/src/generator/context/digest.js +182 -0
  32. package/src/generator/context/domain-coverage.js +94 -0
  33. package/src/generator/context/domain-page.js +137 -0
  34. package/src/generator/context/index.js +42 -0
  35. package/src/generator/context/report.js +121 -0
  36. package/src/generator/context/shared.js +1397 -0
  37. package/src/generator/context/slice.js +703 -0
  38. package/src/generator/context/task-mode.js +466 -0
  39. package/src/generator/docs.js +327 -0
  40. package/src/generator/index.js +161 -0
  41. package/src/generator/native/parity-bundle.js +311 -0
  42. package/src/generator/output.js +300 -0
  43. package/src/generator/registry.js +482 -0
  44. package/src/generator/runtime/app-bundle.js +456 -0
  45. package/src/generator/runtime/bundle-shared.js +166 -0
  46. package/src/generator/runtime/compile-check.js +163 -0
  47. package/src/generator/runtime/deployment.js +287 -0
  48. package/src/generator/runtime/environment.js +635 -0
  49. package/src/generator/runtime/index.js +32 -0
  50. package/src/generator/runtime/runtime-check.js +554 -0
  51. package/src/generator/runtime/shared.js +515 -0
  52. package/src/generator/runtime/smoke.js +219 -0
  53. package/src/generator/schema.js +204 -0
  54. package/src/generator/sdlc/board.js +66 -0
  55. package/src/generator/sdlc/doc-page.js +53 -0
  56. package/src/generator/sdlc/index.js +23 -0
  57. package/src/generator/sdlc/release-notes.js +62 -0
  58. package/src/generator/sdlc/traceability-matrix.js +65 -0
  59. package/src/generator/shared.js +29 -0
  60. package/src/generator/surfaces/contracts.js +146 -0
  61. package/src/generator/surfaces/databases/contract.js +40 -0
  62. package/src/generator/surfaces/databases/index.js +84 -0
  63. package/src/generator/surfaces/databases/lifecycle-shared.d.ts +1 -0
  64. package/src/generator/surfaces/databases/lifecycle-shared.js +612 -0
  65. package/src/generator/surfaces/databases/migration-plan.js +281 -0
  66. package/src/generator/surfaces/databases/postgres/capabilities.js +14 -0
  67. package/src/generator/surfaces/databases/postgres/drizzle.js +99 -0
  68. package/src/generator/surfaces/databases/postgres/index.js +9 -0
  69. package/src/generator/surfaces/databases/postgres/lifecycle.js +16 -0
  70. package/src/generator/surfaces/databases/postgres/prisma.js +159 -0
  71. package/src/generator/surfaces/databases/postgres/sql-migration.js +102 -0
  72. package/src/generator/surfaces/databases/postgres/sql-schema.js +34 -0
  73. package/src/generator/surfaces/databases/shared.d.ts +1 -0
  74. package/src/generator/surfaces/databases/shared.js +350 -0
  75. package/src/generator/surfaces/databases/snapshot.js +96 -0
  76. package/src/generator/surfaces/databases/sqlite/capabilities.js +14 -0
  77. package/src/generator/surfaces/databases/sqlite/index.js +8 -0
  78. package/src/generator/surfaces/databases/sqlite/lifecycle.js +16 -0
  79. package/src/generator/surfaces/databases/sqlite/prisma.js +143 -0
  80. package/src/generator/surfaces/databases/sqlite/sql-migration.js +65 -0
  81. package/src/generator/surfaces/databases/sqlite/sql-schema.js +27 -0
  82. package/src/generator/surfaces/index.js +25 -0
  83. package/src/generator/surfaces/native/swiftui-app.js +38 -0
  84. package/src/generator/surfaces/native/swiftui-templates/Package.swift.txt +20 -0
  85. package/src/generator/surfaces/native/swiftui-templates/README.generated.md +26 -0
  86. package/src/generator/surfaces/native/swiftui-templates/runtime/DynamicScreens.swift +682 -0
  87. package/src/generator/surfaces/native/swiftui-templates/runtime/TodoAPIClient.swift +156 -0
  88. package/src/generator/surfaces/native/swiftui-templates/runtime/TodoSwiftUIApp.swift +44 -0
  89. package/src/generator/surfaces/native/swiftui-templates/runtime/Visibility.swift +183 -0
  90. package/src/generator/surfaces/services/express.d.ts +1 -0
  91. package/src/generator/surfaces/services/express.js +766 -0
  92. package/src/generator/surfaces/services/hono.d.ts +1 -0
  93. package/src/generator/surfaces/services/hono.js +204 -0
  94. package/src/generator/surfaces/services/index.js +42 -0
  95. package/src/generator/surfaces/services/persistence-wiring.js +240 -0
  96. package/src/generator/surfaces/services/runtime-helpers.js +631 -0
  97. package/src/generator/surfaces/services/server-contract.js +80 -0
  98. package/src/generator/surfaces/services/stateless.d.ts +1 -0
  99. package/src/generator/surfaces/services/stateless.js +97 -0
  100. package/src/generator/surfaces/shared.js +64 -0
  101. package/src/generator/surfaces/web/api-client.js +1 -0
  102. package/src/generator/surfaces/web/forms.js +1 -0
  103. package/src/generator/surfaces/web/index.d.ts +2 -0
  104. package/src/generator/surfaces/web/index.js +53 -0
  105. package/src/generator/surfaces/web/react-components.js +248 -0
  106. package/src/generator/surfaces/web/react.js +538 -0
  107. package/src/generator/surfaces/web/routes.js +1 -0
  108. package/src/generator/surfaces/web/screens.js +1 -0
  109. package/src/generator/surfaces/web/shared.js +369 -0
  110. package/src/generator/surfaces/web/sveltekit-actions.js +28 -0
  111. package/src/generator/surfaces/web/sveltekit-components.js +234 -0
  112. package/src/generator/surfaces/web/sveltekit.js +426 -0
  113. package/src/generator/surfaces/web/ui-web-contract.js +65 -0
  114. package/src/generator/surfaces/web/vanilla.js +239 -0
  115. package/src/generator/verification.js +84 -0
  116. package/src/generator.js +1 -0
  117. package/src/import/core/context.js +52 -0
  118. package/src/import/core/contracts.js +23 -0
  119. package/src/import/core/registry.js +81 -0
  120. package/src/import/core/runner.js +646 -0
  121. package/src/import/core/shared.js +910 -0
  122. package/src/import/enrichers/auth-session.js +18 -0
  123. package/src/import/enrichers/django-rest.js +226 -0
  124. package/src/import/enrichers/doc-linking.js +20 -0
  125. package/src/import/enrichers/rails-controllers.js +246 -0
  126. package/src/import/enrichers/rails-models.js +130 -0
  127. package/src/import/enrichers/workflow-target-state.js +10 -0
  128. package/src/import/extractors/api/aspnet-core.js +304 -0
  129. package/src/import/extractors/api/django-routes.js +318 -0
  130. package/src/import/extractors/api/express.js +154 -0
  131. package/src/import/extractors/api/fastify.js +371 -0
  132. package/src/import/extractors/api/flutter-dio.js +135 -0
  133. package/src/import/extractors/api/generic-route-fallback.js +90 -0
  134. package/src/import/extractors/api/graphql-code-first.js +565 -0
  135. package/src/import/extractors/api/graphql-sdl.js +309 -0
  136. package/src/import/extractors/api/jaxrs.js +303 -0
  137. package/src/import/extractors/api/micronaut.js +213 -0
  138. package/src/import/extractors/api/next-route.js +50 -0
  139. package/src/import/extractors/api/next-server-action.js +51 -0
  140. package/src/import/extractors/api/nextauth.js +52 -0
  141. package/src/import/extractors/api/openapi-code.js +242 -0
  142. package/src/import/extractors/api/openapi.js +232 -0
  143. package/src/import/extractors/api/rails-routes.js +230 -0
  144. package/src/import/extractors/api/react-native-repository.js +128 -0
  145. package/src/import/extractors/api/retrofit.js +103 -0
  146. package/src/import/extractors/api/spring-web.js +372 -0
  147. package/src/import/extractors/api/swift-webapi.js +116 -0
  148. package/src/import/extractors/api/trpc.js +212 -0
  149. package/src/import/extractors/db/django-models.js +232 -0
  150. package/src/import/extractors/db/dotnet-models.js +93 -0
  151. package/src/import/extractors/db/drizzle.js +242 -0
  152. package/src/import/extractors/db/ef-core.js +221 -0
  153. package/src/import/extractors/db/flutter-entities.js +120 -0
  154. package/src/import/extractors/db/jpa.js +120 -0
  155. package/src/import/extractors/db/liquibase.js +180 -0
  156. package/src/import/extractors/db/mybatis-xml.js +145 -0
  157. package/src/import/extractors/db/prisma.js +185 -0
  158. package/src/import/extractors/db/rails-schema.js +175 -0
  159. package/src/import/extractors/db/react-native-entities.js +95 -0
  160. package/src/import/extractors/db/room.js +193 -0
  161. package/src/import/extractors/db/snapshot.js +112 -0
  162. package/src/import/extractors/db/sql.js +180 -0
  163. package/src/import/extractors/db/swiftdata.js +137 -0
  164. package/src/import/extractors/ui/android-compose.js +230 -0
  165. package/src/import/extractors/ui/backend-only.js +70 -0
  166. package/src/import/extractors/ui/blazor.js +227 -0
  167. package/src/import/extractors/ui/flutter-screens.js +152 -0
  168. package/src/import/extractors/ui/maui-xaml.js +135 -0
  169. package/src/import/extractors/ui/next-app-router.js +83 -0
  170. package/src/import/extractors/ui/next-pages-router.js +141 -0
  171. package/src/import/extractors/ui/razor-pages.js +181 -0
  172. package/src/import/extractors/ui/react-native-screens.js +166 -0
  173. package/src/import/extractors/ui/react-router.js +139 -0
  174. package/src/import/extractors/ui/sveltekit.js +123 -0
  175. package/src/import/extractors/ui/swiftui.js +193 -0
  176. package/src/import/extractors/ui/uikit.js +175 -0
  177. package/src/import/extractors/verification/generic.js +290 -0
  178. package/src/import/extractors/workflows/generic.js +137 -0
  179. package/src/import/index.js +7 -0
  180. package/src/import/provenance.js +158 -0
  181. package/src/new-project.js +2107 -0
  182. package/src/parser.js +439 -0
  183. package/src/policy/review-boundaries.js +165 -0
  184. package/src/project-config.js +535 -0
  185. package/src/proofs/backend-parity.js +19 -0
  186. package/src/proofs/contract-audit.js +220 -0
  187. package/src/proofs/ios-parity.js +7 -0
  188. package/src/proofs/issues-parity.js +10 -0
  189. package/src/proofs/web-parity.js +50 -0
  190. package/src/realization/api/build-api-realization.js +5 -0
  191. package/src/realization/api/index.js +1 -0
  192. package/src/realization/backend/build-backend-runtime-realization.js +82 -0
  193. package/src/realization/backend/index.d.ts +1 -0
  194. package/src/realization/backend/index.js +4 -0
  195. package/src/realization/db/build-db-realization.js +17 -0
  196. package/src/realization/db/index.js +3 -0
  197. package/src/realization/db/migration-plan.js +5 -0
  198. package/src/realization/db/snapshot.js +5 -0
  199. package/src/realization/ui/build-ui-shared-realization.js +305 -0
  200. package/src/realization/ui/build-web-realization.js +189 -0
  201. package/src/realization/ui/index.js +2 -0
  202. package/src/reconcile/docs.js +280 -0
  203. package/src/reconcile/index.js +3 -0
  204. package/src/reconcile/journeys.js +441 -0
  205. package/src/resolver/docs.js +1 -0
  206. package/src/resolver/enrich/acceptance-criterion.js +14 -0
  207. package/src/resolver/enrich/bug.js +12 -0
  208. package/src/resolver/enrich/component.js +2 -0
  209. package/src/resolver/enrich/index.js +1 -0
  210. package/src/resolver/enrich/pitch.js +18 -0
  211. package/src/resolver/enrich/requirement.js +20 -0
  212. package/src/resolver/enrich/task.js +16 -0
  213. package/src/resolver/expressions.js +1 -0
  214. package/src/resolver/index.js +2422 -0
  215. package/src/resolver/normalize.js +1 -0
  216. package/src/resolver.js +1 -0
  217. package/src/sdlc/adopt.js +65 -0
  218. package/src/sdlc/check.js +86 -0
  219. package/src/sdlc/dod/acceptance-criterion.js +22 -0
  220. package/src/sdlc/dod/bug.js +26 -0
  221. package/src/sdlc/dod/document.js +23 -0
  222. package/src/sdlc/dod/index.js +25 -0
  223. package/src/sdlc/dod/pitch.js +23 -0
  224. package/src/sdlc/dod/requirement.js +34 -0
  225. package/src/sdlc/dod/task.js +39 -0
  226. package/src/sdlc/explain.js +116 -0
  227. package/src/sdlc/history.js +80 -0
  228. package/src/sdlc/paths.js +11 -0
  229. package/src/sdlc/release.js +106 -0
  230. package/src/sdlc/scaffold.js +89 -0
  231. package/src/sdlc/status-filter.js +54 -0
  232. package/src/sdlc/transition.js +112 -0
  233. package/src/sdlc/transitions/acceptance-criterion.js +28 -0
  234. package/src/sdlc/transitions/bug.js +31 -0
  235. package/src/sdlc/transitions/document.js +29 -0
  236. package/src/sdlc/transitions/index.js +56 -0
  237. package/src/sdlc/transitions/pitch.js +34 -0
  238. package/src/sdlc/transitions/requirement.js +31 -0
  239. package/src/sdlc/transitions/task.js +34 -0
  240. package/src/template-trust.js +597 -0
  241. package/src/validator/expressions.js +1 -0
  242. package/src/validator/index.js +3424 -0
  243. package/src/validator/kinds.js +346 -0
  244. package/src/validator/per-kind/acceptance-criterion.js +91 -0
  245. package/src/validator/per-kind/bug.js +77 -0
  246. package/src/validator/per-kind/component.js +274 -0
  247. package/src/validator/per-kind/domain.js +205 -0
  248. package/src/validator/per-kind/pitch.js +101 -0
  249. package/src/validator/per-kind/requirement.js +75 -0
  250. package/src/validator/per-kind/task.js +96 -0
  251. package/src/validator/registry.js +1 -0
  252. package/src/validator/utils.js +12 -0
  253. package/src/validator.js +1 -0
  254. package/src/workflows.js +7597 -0
  255. package/src/workspace-docs.js +265 -0
  256. package/template-helpers/react.js +5 -0
  257. package/template-helpers/sveltekit.js +5 -0
@@ -0,0 +1,466 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+
4
+ import { buildAgentAdoptionPlan } from "../../adoption/plan.js";
5
+ import { defaultOwnershipBoundary } from "../../policy/review-boundaries.js";
6
+ import {
7
+ buildDefaultWriteScope,
8
+ buildMaintainedWriteScope,
9
+ maintainedProofMetadata,
10
+ recommendedVerificationTargets,
11
+ stableSortedStrings,
12
+ summarizeById,
13
+ workspaceInventory
14
+ } from "./shared.js";
15
+ import { generateContextBundle } from "./bundle.js";
16
+ import { generateContextDiff } from "./diff.js";
17
+ import { generateContextSlice } from "./slice.js";
18
+
19
+ function readAgentAdoptionPlan(graph) {
20
+ const filePath = path.join(graph.root, "candidates", "reconcile", "adoption-plan.agent.json");
21
+ if (!fs.existsSync(filePath)) {
22
+ return null;
23
+ }
24
+ return JSON.parse(fs.readFileSync(filePath, "utf8"));
25
+ }
26
+
27
+ function nextImportAdoptAction(plan) {
28
+ if (!plan) {
29
+ return {
30
+ kind: "missing_plan",
31
+ label: "Run reconcile first",
32
+ reason: "No staged adoption plan exists yet under candidates/reconcile."
33
+ };
34
+ }
35
+ const proposalSurfaces = plan.imported_proposal_surfaces || [];
36
+ const stagedItems = plan.staged_items || [];
37
+ const approvedReviewGroups = plan.approved_review_groups || [];
38
+ const requiresHumanReview = plan.requires_human_review || [];
39
+ const surfaceById = new Map(proposalSurfaces.map((surface) => [surface.id, surface]));
40
+ if ((plan.requires_human_review || []).length > 0) {
41
+ const targetId = requiresHumanReview[0];
42
+ const surface = surfaceById.get(targetId) || null;
43
+ return {
44
+ kind: "review_staged",
45
+ label: "Review staged proposal surfaces",
46
+ reason: `${requiresHumanReview.length} staged proposal(s) still require human review or mapping decisions.`,
47
+ target_id: targetId,
48
+ current_state: surface?.current_state || "stage",
49
+ recommended_state: surface?.recommended_state || null,
50
+ target_review_group: approvedReviewGroups[0] || null
51
+ };
52
+ }
53
+ if (stagedItems.length > 0) {
54
+ const targetId = stagedItems[0];
55
+ const surface = surfaceById.get(targetId) || null;
56
+ return {
57
+ kind: "adopt_staged",
58
+ label: "Adopt staged proposal surfaces",
59
+ reason: `${stagedItems.length} staged proposal(s) are available for explicit adoption.`,
60
+ target_id: targetId,
61
+ current_state: surface?.current_state || "stage",
62
+ recommended_state: surface?.recommended_state || "accept",
63
+ target_review_group: approvedReviewGroups[0] || null
64
+ };
65
+ }
66
+ if (approvedReviewGroups.length > 0) {
67
+ return {
68
+ kind: "inspect_review_group",
69
+ label: "Inspect approved review group",
70
+ reason: `No staged proposal surfaces are waiting, but ${approvedReviewGroups[0]} remains the clearest adoption-review grouping to inspect next.`,
71
+ target_review_group: approvedReviewGroups[0]
72
+ };
73
+ }
74
+ if (proposalSurfaces.length > 0) {
75
+ return {
76
+ kind: "inspect_proposal_surface",
77
+ label: "Inspect proposal surface",
78
+ reason: `No staged adoption action is pending, so inspect ${proposalSurfaces[0].id} before changing canonical Topogram.`,
79
+ target_id: proposalSurfaces[0].id,
80
+ current_state: proposalSurfaces[0].current_state || null,
81
+ recommended_state: proposalSurfaces[0].recommended_state || null
82
+ };
83
+ }
84
+ return {
85
+ kind: "inspect_plan",
86
+ label: "Inspect adoption plan",
87
+ reason: "No staged proposal surfaces are currently waiting, but the plan is still the right source of truth."
88
+ };
89
+ }
90
+
91
+ function nextDiffReviewAction(diff, focus, options = {}) {
92
+ if (!options.fromTopogramPath) {
93
+ return {
94
+ kind: "run_diff",
95
+ label: "Run a semantic diff baseline",
96
+ reason: "Diff-review mode is most useful when comparing the current Topogram against a baseline via --from-topogram."
97
+ };
98
+ }
99
+
100
+ const maintainedOutputs = diff.affected_maintained_surfaces?.outputs || [];
101
+ const maintainedSeams = diff.affected_maintained_surfaces?.affected_seams || [];
102
+ const highestMaintainedSeverity = [...maintainedSeams]
103
+ .sort((a, b) => maintainedSeverityRank(b.status) - maintainedSeverityRank(a.status))[0]?.status || null;
104
+ const affectedOutputIds = stableSortedStrings(maintainedOutputs.map((output) => output.output_id).filter(Boolean));
105
+ const maintainedImpactCount = maintainedSeams.length;
106
+ const reviewBoundaryChangeCount = (diff.review_boundary_changes || []).length;
107
+ const generatedImpactCount =
108
+ (diff.affected_generated_surfaces?.capabilities || []).length +
109
+ (diff.affected_generated_surfaces?.projections || []).length +
110
+ (diff.affected_generated_surfaces?.workflows || []).length +
111
+ (diff.affected_generated_surfaces?.journeys || []).length;
112
+
113
+ if (reviewBoundaryChangeCount > 0) {
114
+ return {
115
+ kind: "review_boundary_changes",
116
+ label: "Review changed automation boundaries first",
117
+ reason: `${reviewBoundaryChangeCount} review-boundary change(s) alter what can be safely automated or must stay human-reviewed.`
118
+ };
119
+ }
120
+
121
+ if (maintainedImpactCount > 0) {
122
+ return {
123
+ kind: "inspect_maintained_impact",
124
+ label: "Inspect maintained-app impact next",
125
+ reason: `${maintainedImpactCount} seam(s) across ${affectedOutputIds.length || maintainedOutputs.length} output(s) are in scope${highestMaintainedSeverity ? `, with highest severity ${highestMaintainedSeverity}` : ""}${affectedOutputIds.length > 0 ? ` (${affectedOutputIds.join(", ")})` : ""}, so human-owned seams should be reviewed before editing or regeneration.`
126
+ };
127
+ }
128
+
129
+ if (generatedImpactCount > 0) {
130
+ return {
131
+ kind: "inspect_generated_impact",
132
+ label: "Inspect generated surface impact next",
133
+ reason: `${generatedImpactCount} generated surface(s) are affected; review those deltas before choosing a write path.`
134
+ };
135
+ }
136
+
137
+ return {
138
+ kind: "inspect_diff",
139
+ label: "Inspect semantic diff",
140
+ reason: focus ? `Review the semantic diff for ${focus.kind} ${focus.id}.` : "Review the semantic diff before taking action."
141
+ };
142
+ }
143
+
144
+ function nextVerificationAction(verificationTargets, focus) {
145
+ const maintainedChecks = verificationTargets?.maintained_app_checks || [];
146
+ const generatedChecks = verificationTargets?.generated_checks || [];
147
+ const outputVerificationTargets = verificationTargets?.output_verification_targets || [];
148
+ const affectedOutputIds = stableSortedStrings(outputVerificationTargets.map((entry) => entry.output_id).filter(Boolean));
149
+ if (maintainedChecks.length > 0) {
150
+ return {
151
+ kind: "run_maintained_checks",
152
+ label: "Run maintained proof checks",
153
+ reason: focus
154
+ ? `${focus.kind} ${focus.id} touches maintained proof surfaces${affectedOutputIds.length === 1 ? ` in ${affectedOutputIds[0]}` : affectedOutputIds.length > 1 ? ` across ${affectedOutputIds.join(", ")}` : ""}, so start with the maintained-app check set.`
155
+ : `This task touches maintained proof surfaces${affectedOutputIds.length === 1 ? ` in ${affectedOutputIds[0]}` : affectedOutputIds.length > 1 ? ` across ${affectedOutputIds.join(", ")}` : ""}, so start with the maintained-app check set.`
156
+ };
157
+ }
158
+ if (generatedChecks.length > 0) {
159
+ return {
160
+ kind: "run_generated_checks",
161
+ label: "Run generated verification checks",
162
+ reason: `${generatedChecks.join(", ")} is the smallest generated proof set currently attached to this surface.`
163
+ };
164
+ }
165
+ return {
166
+ kind: "inspect_verification_targets",
167
+ label: "Inspect verification targets",
168
+ reason: "No concrete verification checks were attached, so inspect the verification target set before acting."
169
+ };
170
+ }
171
+
172
+ function nextModelingAction(slice, diff, focus, options = {}) {
173
+ if (options.fromTopogramPath && diff) {
174
+ const reviewBoundaryChangeCount = (diff.review_boundary_changes || []).length;
175
+ const maintainedSeams = diff.affected_maintained_surfaces?.affected_seams || [];
176
+ const maintainedOutputs = diff.affected_maintained_surfaces?.outputs || [];
177
+ const maintainedImpactCount = maintainedSeams.length;
178
+ const highestMaintainedSeverity = [...maintainedSeams]
179
+ .sort((a, b) => maintainedSeverityRank(b.status) - maintainedSeverityRank(a.status))[0]?.status || null;
180
+ const affectedOutputIds = stableSortedStrings(maintainedOutputs.map((output) => output.output_id).filter(Boolean));
181
+ if (reviewBoundaryChangeCount > 0) {
182
+ return {
183
+ kind: "review_diff_boundaries",
184
+ label: "Review diff boundary changes first",
185
+ reason: `${reviewBoundaryChangeCount} review-boundary change(s) were detected against the baseline Topogram.`
186
+ };
187
+ }
188
+ if (maintainedImpactCount > 0) {
189
+ return {
190
+ kind: "review_diff_impact",
191
+ label: "Review diff impact before editing",
192
+ reason: `${maintainedImpactCount} seam(s) across ${affectedOutputIds.length || maintainedOutputs.length} output(s) would be affected${highestMaintainedSeverity ? `, with highest severity ${highestMaintainedSeverity}` : ""}${affectedOutputIds.length > 0 ? ` (${affectedOutputIds.join(", ")})` : ""}, so inspect the cross-surface impact before changing canonical Topogram.`
193
+ };
194
+ }
195
+ }
196
+
197
+ const automationClass = slice?.review_boundary?.automation_class || null;
198
+ if (automationClass === "manual_decision" || automationClass === "no_go") {
199
+ return {
200
+ kind: "inspect_boundary_before_edit",
201
+ label: "Inspect review boundary before editing",
202
+ reason: focus
203
+ ? `${focus.kind} ${focus.id} is not a routine modeling change; inspect its boundary classification before editing canonical Topogram.`
204
+ : "The selected modeling surface has a non-routine review boundary."
205
+ };
206
+ }
207
+
208
+ if (focus) {
209
+ return {
210
+ kind: "edit_canonical_topogram",
211
+ label: "Edit canonical Topogram next",
212
+ reason: `${focus.kind} ${focus.id} has a scoped context and verification target set, so canonical modeling work can proceed deliberately.`
213
+ };
214
+ }
215
+
216
+ return {
217
+ kind: "inspect_workspace_digest",
218
+ label: "Inspect workspace digest first",
219
+ reason: "No specific surface was selected, so start from the workspace digest before editing canonical Topogram."
220
+ };
221
+ }
222
+
223
+ function maintainedSeverityRank(status) {
224
+ if (status === "no_go") return 3;
225
+ if (status === "manual_decision") return 2;
226
+ if (status === "review_required") return 1;
227
+ return 0;
228
+ }
229
+
230
+ function selectedSurface(options = {}) {
231
+ if (options.capabilityId) return { kind: "capability", id: options.capabilityId };
232
+ if (options.workflowId) return { kind: "workflow", id: options.workflowId };
233
+ if (options.projectionId) return { kind: "projection", id: options.projectionId };
234
+ if (options.entityId) return { kind: "entity", id: options.entityId };
235
+ if (options.journeyId) return { kind: "journey", id: options.journeyId };
236
+ if (options.surfaceId) return { kind: "surface", id: options.surfaceId };
237
+ return null;
238
+ }
239
+
240
+ function preferredSlice(graph, options = {}) {
241
+ const focus = selectedSurface(options);
242
+ if (!focus) {
243
+ return null;
244
+ }
245
+ return generateContextSlice(graph, options);
246
+ }
247
+
248
+ function modelingMode(graph, options = {}) {
249
+ const focus = selectedSurface(options);
250
+ const slice = preferredSlice(graph, options);
251
+ const inventory = workspaceInventory(graph);
252
+ const diff = options.fromTopogramPath ? generateContextDiff(graph, options) : null;
253
+ return {
254
+ type: "context_task_mode",
255
+ version: 1,
256
+ mode: "modeling",
257
+ summary: {
258
+ focus: "Canonical Topogram meaning changes",
259
+ selected_surface: focus,
260
+ preferred_start: focus ? "context-slice" : "context-digest"
261
+ },
262
+ preferred_context_artifacts: [
263
+ focus ? `${focus.id}.context-slice.json` : "workspace.context-digest.json",
264
+ "context-diff.json"
265
+ ],
266
+ review_emphasis: [
267
+ "entities_and_relations",
268
+ "capabilities",
269
+ "workflows_and_journeys",
270
+ "projection_semantics"
271
+ ],
272
+ write_scope: buildDefaultWriteScope(),
273
+ verification_targets: slice?.verification_targets || recommendedVerificationTargets(graph, [
274
+ ...inventory.capabilities,
275
+ ...inventory.projections
276
+ ], {
277
+ rationale: "Modeling mode should verify the smallest semantic closure touched by the intended Topogram change."
278
+ }),
279
+ ownership_boundary: defaultOwnershipBoundary(),
280
+ next_action: nextModelingAction(slice, diff, focus, options)
281
+ };
282
+ }
283
+
284
+ function maintainedAppEditMode(graph, options = {}) {
285
+ const bundle = generateContextBundle(graph, { taskId: "maintained-app" });
286
+ return {
287
+ type: "context_task_mode",
288
+ version: 1,
289
+ mode: "maintained-app-edit",
290
+ summary: {
291
+ focus: "Human-owned maintained code changes constrained by emitted Topogram artifacts",
292
+ preferred_start: "context-bundle maintained-app"
293
+ },
294
+ preferred_context_artifacts: [
295
+ "context-bundle.maintained-app.json",
296
+ "maintained-boundary.json"
297
+ ],
298
+ review_emphasis: [
299
+ "accepted_vs_guarded_vs_no_go",
300
+ "human_owned_seams",
301
+ "maintained_surface_boundaries"
302
+ ],
303
+ write_scope: buildMaintainedWriteScope(graph, bundle.maintained_boundary?.maintained_files_in_scope || []),
304
+ verification_targets: bundle.verification_targets,
305
+ ownership_boundary: bundle.ownership_boundary
306
+ };
307
+ }
308
+
309
+ function importAdoptMode(graph, options = {}) {
310
+ const existingAgentPlan = readAgentAdoptionPlan(graph);
311
+ const agentPlan = existingAgentPlan || buildAgentAdoptionPlan({
312
+ type: "reconcile_adoption_plan",
313
+ workspace: graph.root,
314
+ approved_review_groups: [],
315
+ items: []
316
+ });
317
+ const proposalSurfaces = agentPlan.imported_proposal_surfaces || [];
318
+ return {
319
+ type: "context_task_mode",
320
+ version: 1,
321
+ mode: "import-adopt",
322
+ summary: {
323
+ focus: "Proposal review and adoption planning",
324
+ preferred_start: "adoption-plan.agent.json",
325
+ staged_item_count: (agentPlan.staged_items || []).length,
326
+ requires_human_review_count: (agentPlan.requires_human_review || []).length,
327
+ plan_present: Boolean(existingAgentPlan)
328
+ },
329
+ preferred_context_artifacts: [
330
+ "candidates/reconcile/adoption-plan.agent.json",
331
+ "workspace.context-digest.json"
332
+ ],
333
+ review_emphasis: [
334
+ "accept_map_customize_stage_reject",
335
+ "mapping_suggestions",
336
+ "review_required_imports"
337
+ ],
338
+ write_scope: {
339
+ safe_to_edit: ["candidates/**"],
340
+ generator_owned: ["artifacts/**", "apps/**"],
341
+ human_owned_review_required: ["topogram/**"],
342
+ out_of_bounds: [".git/**", "node_modules/**"]
343
+ },
344
+ verification_targets: {
345
+ verification_ids: [],
346
+ generated_checks: ["reconcile-review"],
347
+ maintained_app_checks: [],
348
+ rationale: "Import/adopt mode should validate proposal state before canonical writes."
349
+ },
350
+ ownership_boundary: defaultOwnershipBoundary(),
351
+ adoption_state_vocabulary: agentPlan.adoption_state_vocabulary,
352
+ next_action: nextImportAdoptAction(existingAgentPlan),
353
+ staged_items: agentPlan.staged_items || [],
354
+ requires_human_review: agentPlan.requires_human_review || [],
355
+ accepted_items: agentPlan.accepted_items || [],
356
+ rejected_items: agentPlan.rejected_items || [],
357
+ approved_review_groups: agentPlan.approved_review_groups || [],
358
+ proposal_surface_count: proposalSurfaces.length,
359
+ proposal_surfaces: proposalSurfaces
360
+ };
361
+ }
362
+
363
+ function diffReviewMode(graph, options = {}) {
364
+ const focus = selectedSurface(options);
365
+ const slice = preferredSlice(graph, options);
366
+ const diff = options.fromTopogramPath ? generateContextDiff(graph, options) : null;
367
+ return {
368
+ type: "context_task_mode",
369
+ version: 1,
370
+ mode: "diff-review",
371
+ summary: {
372
+ focus: "Understand semantic change impact before editing",
373
+ selected_surface: focus,
374
+ preferred_start: options.fromTopogramPath ? "context-diff" : "context-slice"
375
+ },
376
+ preferred_context_artifacts: options.fromTopogramPath
377
+ ? ["context-diff.json", focus ? `${focus.id}.context-slice.json` : "workspace.context-digest.json"]
378
+ : [focus ? `${focus.id}.context-slice.json` : "workspace.context-digest.json"],
379
+ review_emphasis: [
380
+ "affected_generated_surfaces",
381
+ "affected_maintained_surfaces",
382
+ "review_boundary_changes"
383
+ ],
384
+ write_scope: {
385
+ safe_to_edit: [],
386
+ generator_owned: ["artifacts/**", "apps/**"],
387
+ human_owned_review_required: ["topogram/**", "examples/maintained/proof-app/**"],
388
+ out_of_bounds: [".git/**", "node_modules/**"]
389
+ },
390
+ verification_targets: slice?.verification_targets || recommendedVerificationTargets(graph, [], {
391
+ rationale: "Diff review mode should stay read-first until the affected verification surface is clear."
392
+ }),
393
+ ownership_boundary: defaultOwnershipBoundary(),
394
+ next_action: nextDiffReviewAction(diff, focus, options)
395
+ };
396
+ }
397
+
398
+ function verificationMode(graph, options = {}) {
399
+ const focus = selectedSurface(options);
400
+ const slice = preferredSlice(graph, options);
401
+ const maintainedFiles = stableSortedStrings(maintainedProofMetadata(graph).flatMap((item) => item.maintainedFiles || []));
402
+ const maintainedBundle = maintainedFiles.length > 0 ? generateContextBundle(graph, { taskId: "maintained-app" }) : null;
403
+ const fallbackVerificationTargets = recommendedVerificationTargets(graph, [], {
404
+ includeMaintainedApp: maintainedFiles.length > 0,
405
+ rationale: "Verification mode should return the smallest relevant proof set for the selected semantic surface."
406
+ });
407
+ const verificationTargets = slice?.verification_targets || {
408
+ ...(maintainedBundle?.verification_targets || fallbackVerificationTargets),
409
+ output_verification_targets: (maintainedBundle?.maintained_boundary?.outputs || []).map((output) => ({
410
+ output_id: output.output_id,
411
+ verification_targets: output.verification_targets || null
412
+ }))
413
+ };
414
+ return {
415
+ type: "context_task_mode",
416
+ version: 1,
417
+ mode: "verification",
418
+ summary: {
419
+ focus: "Run the smallest correct proof set for a known change",
420
+ selected_surface: focus,
421
+ preferred_start: focus ? "context-slice" : "context-report"
422
+ },
423
+ preferred_context_artifacts: [
424
+ focus ? `${focus.id}.context-slice.json` : "context-report.json"
425
+ ],
426
+ review_emphasis: [
427
+ "smallest_correct_check_set",
428
+ "verification_coverage",
429
+ "maintained_proof_gates"
430
+ ],
431
+ write_scope: {
432
+ safe_to_edit: [],
433
+ generator_owned: ["artifacts/**", "apps/**"],
434
+ human_owned_review_required: maintainedFiles.length > 0 ? ["examples/maintained/proof-app/**"] : [],
435
+ out_of_bounds: [".git/**", "node_modules/**"]
436
+ },
437
+ verification_targets: verificationTargets,
438
+ ownership_boundary: defaultOwnershipBoundary(),
439
+ next_action: nextVerificationAction(verificationTargets, focus)
440
+ };
441
+ }
442
+
443
+ export function generateContextTaskMode(graph, options = {}) {
444
+ const mode = String(options.modeId || "").trim();
445
+ if (!mode) {
446
+ throw new Error("context-task-mode requires --mode <modeling|maintained-app-edit|import-adopt|diff-review|verification>");
447
+ }
448
+
449
+ if (mode === "modeling") {
450
+ return modelingMode(graph, options);
451
+ }
452
+ if (mode === "maintained-app-edit") {
453
+ return maintainedAppEditMode(graph, options);
454
+ }
455
+ if (mode === "import-adopt") {
456
+ return importAdoptMode(graph, options);
457
+ }
458
+ if (mode === "diff-review") {
459
+ return diffReviewMode(graph, options);
460
+ }
461
+ if (mode === "verification") {
462
+ return verificationMode(graph, options);
463
+ }
464
+
465
+ throw new Error(`Unsupported context task mode '${mode}'`);
466
+ }