@topogram/cli 0.3.51 → 0.3.52
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.
- package/ARCHITECTURE.md +4 -4
- package/CHANGELOG.md +11 -11
- package/package.json +1 -1
- package/src/adoption/plan.js +2 -2
- package/src/agent-ops/query-builders.js +42 -33
- package/src/cli.js +174 -129
- package/src/generator/adapters.d.ts +1 -0
- package/src/generator/adapters.js +64 -39
- package/src/generator/check.js +19 -12
- package/src/generator/context/diff.js +9 -9
- package/src/generator/context/domain-coverage.js +11 -10
- package/src/generator/context/domain-page.js +6 -6
- package/src/generator/context/shared.js +37 -21
- package/src/generator/context/slice.js +70 -65
- package/src/generator/index.js +12 -12
- package/src/generator/output.js +21 -20
- package/src/generator/registry.js +61 -49
- package/src/generator/runtime/app-bundle.js +15 -15
- package/src/generator/runtime/compile-check.js +7 -7
- package/src/generator/runtime/deployment.js +9 -9
- package/src/generator/runtime/environment.js +39 -39
- package/src/generator/runtime/runtime-check.js +5 -5
- package/src/generator/runtime/shared.js +40 -38
- package/src/generator/runtime/smoke.js +5 -5
- package/src/generator/surfaces/databases/contract.js +1 -1
- package/src/generator/surfaces/databases/lifecycle-shared.js +6 -5
- package/src/generator/surfaces/databases/postgres/drizzle.js +3 -2
- package/src/generator/surfaces/databases/postgres/prisma.js +3 -2
- package/src/generator/surfaces/databases/shared.js +3 -2
- package/src/generator/surfaces/databases/snapshot.js +1 -1
- package/src/generator/surfaces/databases/sqlite/prisma.js +3 -2
- package/src/generator/surfaces/native/swiftui-app.js +3 -3
- package/src/generator/surfaces/native/swiftui-templates/Package.swift.txt +1 -1
- package/src/generator/surfaces/native/swiftui-templates/README.generated.md +3 -3
- package/src/generator/surfaces/native/swiftui-templates/runtime/DynamicScreens.swift +3 -3
- package/src/generator/surfaces/services/persistence-wiring.js +3 -2
- package/src/generator/surfaces/services/server-contract.js +4 -4
- package/src/generator/surfaces/shared.js +2 -2
- package/src/generator/surfaces/web/design-intent.js +1 -1
- package/src/generator/surfaces/web/index.js +7 -7
- package/src/generator/surfaces/web/{react-components.js → react-widgets.js} +53 -53
- package/src/generator/surfaces/web/react.js +36 -36
- package/src/generator/surfaces/web/{sveltekit-components.js → sveltekit-widgets.js} +53 -53
- package/src/generator/surfaces/web/sveltekit.js +34 -34
- package/src/generator/surfaces/web/{ui-web-contract.js → ui-surface-contract.js} +8 -8
- package/src/generator/surfaces/web/vanilla.js +6 -6
- package/src/generator/{component-conformance.js → widget-conformance.js} +129 -128
- package/src/generator/widgets.js +40 -0
- package/src/generator-policy.js +10 -12
- package/src/import/core/runner.js +34 -34
- package/src/import/core/shared.js +1 -1
- package/src/import/extractors/ui/android-compose.js +1 -1
- package/src/import/extractors/ui/blazor.js +1 -1
- package/src/import/extractors/ui/razor-pages.js +1 -1
- package/src/import/extractors/ui/react-router.js +4 -4
- package/src/import/extractors/ui/sveltekit.js +4 -4
- package/src/import/extractors/ui/swiftui.js +1 -1
- package/src/import/extractors/ui/uikit.js +1 -1
- package/src/new-project.js +19 -18
- package/src/project-config.js +92 -42
- package/src/proofs/contract-audit.js +1 -1
- package/src/proofs/ios-parity.js +1 -1
- package/src/proofs/issues-parity.js +1 -1
- package/src/realization/backend/build-backend-runtime-realization.js +2 -2
- package/src/realization/ui/build-ui-shared-realization.js +33 -33
- package/src/realization/ui/build-web-realization.js +23 -20
- package/src/reconcile/journeys.js +1 -1
- package/src/resolver/index.js +148 -65
- package/src/validator/index.js +473 -423
- package/src/validator/kinds.js +36 -36
- package/src/validator/per-kind/{component.js → widget.js} +47 -47
- package/src/{component-behavior.js → widget-behavior.js} +3 -3
- package/src/workflows.js +39 -38
- package/template-helpers/react.js +4 -4
- package/template-helpers/sveltekit.js +4 -4
- package/src/generator/components.js +0 -39
- /package/src/resolver/enrich/{component.js → widget.js} +0 -0
package/ARCHITECTURE.md
CHANGED
|
@@ -33,7 +33,7 @@ Topogram turns a `.tg` workspace into generated artifacts and apps through five
|
|
|
33
33
|
Generator adapters
|
|
34
34
|
- Own stack-specific realization such as React, SvelteKit, Hono, Express,
|
|
35
35
|
Postgres, SQLite, Prisma, Drizzle, SwiftUI, or future Android files.
|
|
36
|
-
- Consume normalized contracts, topology
|
|
36
|
+
- Consume normalized contracts, topology runtime metadata, widget contracts, and optional
|
|
37
37
|
implementation hooks.
|
|
38
38
|
- Return generated files and diagnostics through the shared generator interface.
|
|
39
39
|
|
|
@@ -42,9 +42,9 @@ Workspace `implementation/`
|
|
|
42
42
|
- Can include seed data, custom page renderers, repository implementations, and runtime-check specifics.
|
|
43
43
|
- Must not be treated as engine contracts.
|
|
44
44
|
|
|
45
|
-
`
|
|
46
|
-
shapes, and projections. They produce `
|
|
47
|
-
and can be emitted through the `ui-
|
|
45
|
+
`widget` statements live in the semantic graph beside entities, capabilities,
|
|
46
|
+
shapes, and projections. They produce `widgetContract` resolver enrichment
|
|
47
|
+
and can be emitted through the `ui-widget-contract` generator target without
|
|
48
48
|
requiring an implementation provider.
|
|
49
49
|
|
|
50
50
|
## Stable Internal Contracts
|
package/CHANGELOG.md
CHANGED
|
@@ -36,17 +36,17 @@
|
|
|
36
36
|
|
|
37
37
|
## 0.3.13 - 2026-05-01
|
|
38
38
|
|
|
39
|
-
- Add `topogram
|
|
39
|
+
- Add `topogram widget check` as a user-facing alias for component
|
|
40
40
|
conformance reports. The command prints a human summary by default, supports
|
|
41
|
-
`--projection`, `--
|
|
41
|
+
`--projection`, `--widget`, and `--json`, and exits non-zero when
|
|
42
42
|
conformance errors are present.
|
|
43
43
|
|
|
44
44
|
## 0.3.12 - 2026-05-01
|
|
45
45
|
|
|
46
|
-
- Add `
|
|
47
|
-
`projection.
|
|
46
|
+
- Add `widget-conformance-report` generator target. The report compares
|
|
47
|
+
`projection.widget_bindings` usage against component contracts, includes
|
|
48
48
|
inherited shared-UI usages for concrete web projections, supports
|
|
49
|
-
`--projection` and `--
|
|
49
|
+
`--projection` and `--widget` filters, and reports repair-oriented checks
|
|
50
50
|
for missing required props, event action context, component status, approvals,
|
|
51
51
|
write scope, and projection/component impact.
|
|
52
52
|
|
|
@@ -159,7 +159,7 @@
|
|
|
159
159
|
generators (board/release-notes/traceability), state-machine
|
|
160
160
|
transitions, DoD rules, archive load/save, transition round-trips
|
|
161
161
|
(rewrite + history sidecar), and release dry-run output.
|
|
162
|
-
- Add `projection.
|
|
162
|
+
- Add `projection.widget_bindings` so projections explicitly own component
|
|
163
163
|
placement and wiring. Component usage validates screen, region, component,
|
|
164
164
|
prop, event, data-source, and event-target references.
|
|
165
165
|
- Remove `component.consumers` from the component grammar before external
|
|
@@ -168,7 +168,7 @@
|
|
|
168
168
|
- Add structured component `behaviors { ... }` alongside the shorthand
|
|
169
169
|
`behavior [...]`, with validation for supported stack-agnostic behavior
|
|
170
170
|
kinds and behavior references to component props/events.
|
|
171
|
-
- Emit `approvals` and normalized `behaviors` in `ui-
|
|
171
|
+
- Emit `approvals` and normalized `behaviors` in `ui-widget-contract`
|
|
172
172
|
artifacts.
|
|
173
173
|
- Include component usage metadata in generated UI contracts. Concrete web
|
|
174
174
|
projections that realize a shared UI projection now inherit the shared
|
|
@@ -180,18 +180,18 @@
|
|
|
180
180
|
|
|
181
181
|
- Add `component` statement kind for reusable UI/service component contracts
|
|
182
182
|
(props, events, slots, patterns, regions, dependencies, consumers).
|
|
183
|
-
- Add `ui-
|
|
184
|
-
component or for the whole workspace; selectable via `--
|
|
183
|
+
- Add `ui-widget-contract` generator target that emits stable JSON per
|
|
184
|
+
component or for the whole workspace; selectable via `--widget <id>`.
|
|
185
185
|
- `context-diff` now emits a `components` section, and changed components
|
|
186
186
|
fan out into `affected_generated_surfaces.projections` so consumer
|
|
187
187
|
projections show up in diff payloads.
|
|
188
|
-
- `context-slice --
|
|
188
|
+
- `context-slice --widget <id>` returns a first-class component slice with
|
|
189
189
|
`focus.kind === "component"`, dependent shapes/projections/verifications,
|
|
190
190
|
and a `component_surface` review boundary; the same selector flows through
|
|
191
191
|
`verification-targets`, `change-plan`, `risk-summary`, `review-packet`,
|
|
192
192
|
`proceed-decision`, `next-action`, `single-agent-plan`, and
|
|
193
193
|
`resolved-workflow-context`.
|
|
194
|
-
- `topogram generate ... --generate ui-
|
|
194
|
+
- `topogram generate ... --generate ui-widget-contract --widget <id>`
|
|
195
195
|
now errors loudly when the id does not match any component (previously it
|
|
196
196
|
wrote a `null` artifact).
|
|
197
197
|
- Component prop defaults preserve real values: `default true`, `default false`,
|
package/package.json
CHANGED
package/src/adoption/plan.js
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
reviewBoundaryForImportProposal
|
|
7
7
|
} from "../policy/review-boundaries.js";
|
|
8
8
|
|
|
9
|
-
const ADOPT_SELECTORS = new Set(["from-plan", "actors", "roles", "enums", "shapes", "entities", "capabilities", "
|
|
9
|
+
const ADOPT_SELECTORS = new Set(["from-plan", "actors", "roles", "enums", "shapes", "entities", "capabilities", "widgets", "docs", "journeys", "workflows", "verification", "ui"]);
|
|
10
10
|
|
|
11
11
|
function stableSortedStrings(values) {
|
|
12
12
|
return [...new Set((values || []).filter(Boolean))].sort();
|
|
@@ -355,7 +355,7 @@ export function selectorMatchesItem(selector, item) {
|
|
|
355
355
|
if (selector === "shapes") return item.kind === "shape";
|
|
356
356
|
if (selector === "entities") return item.kind === "entity";
|
|
357
357
|
if (selector === "capabilities") return item.kind === "capability";
|
|
358
|
-
if (selector === "
|
|
358
|
+
if (selector === "widgets") return item.kind === "widget";
|
|
359
359
|
if (selector === "docs") return item.track === "docs";
|
|
360
360
|
if (selector === "journeys") return item.track === "docs" && String(item.canonical_rel_path || "").startsWith("docs/journeys/");
|
|
361
361
|
if (selector === "workflows") return item.track === "workflows" || item.kind === "decision";
|
|
@@ -138,24 +138,29 @@ function stableOrderedUnion(values = []) {
|
|
|
138
138
|
return result;
|
|
139
139
|
}
|
|
140
140
|
|
|
141
|
+
function targetWidgetId(target = {}) {
|
|
142
|
+
return target.widget_id || target.component_id || null;
|
|
143
|
+
}
|
|
144
|
+
|
|
141
145
|
function componentBehaviorArtifactPath(target = {}) {
|
|
142
|
-
if (target.target !== "
|
|
146
|
+
if (target.target !== "widget-behavior-report") {
|
|
143
147
|
return null;
|
|
144
148
|
}
|
|
145
|
-
const suffix = [target.projection_id, target
|
|
146
|
-
return suffix ? `${suffix}.
|
|
149
|
+
const suffix = [target.projection_id, targetWidgetId(target)].filter(Boolean).join(".");
|
|
150
|
+
return suffix ? `${suffix}.widget-behavior-report.json` : "widget-behavior-report.json";
|
|
147
151
|
}
|
|
148
152
|
|
|
149
153
|
function componentBehaviorQueryCommand(target = {}) {
|
|
150
|
-
if (target.target !== "
|
|
154
|
+
if (target.target !== "widget-behavior-report") {
|
|
151
155
|
return null;
|
|
152
156
|
}
|
|
153
|
-
const parts = ["topogram", "query", "
|
|
157
|
+
const parts = ["topogram", "query", "widget-behavior", "./topogram"];
|
|
154
158
|
if (target.projection_id) {
|
|
155
159
|
parts.push("--projection", target.projection_id);
|
|
156
160
|
}
|
|
157
|
-
|
|
158
|
-
|
|
161
|
+
const widgetId = targetWidgetId(target);
|
|
162
|
+
if (widgetId) {
|
|
163
|
+
parts.push("--widget", widgetId);
|
|
159
164
|
}
|
|
160
165
|
parts.push("--json");
|
|
161
166
|
return parts.join(" ");
|
|
@@ -169,10 +174,10 @@ function recommendedArtifactQueriesFromGeneratorTargets(generatorTargets = []) {
|
|
|
169
174
|
if (!command || seen.has(command)) continue;
|
|
170
175
|
seen.add(command);
|
|
171
176
|
queries.push({
|
|
172
|
-
query: "
|
|
177
|
+
query: "widget-behavior",
|
|
173
178
|
target: target.target,
|
|
174
179
|
projection_id: target.projection_id || null,
|
|
175
|
-
|
|
180
|
+
widget_id: targetWidgetId(target),
|
|
176
181
|
command
|
|
177
182
|
});
|
|
178
183
|
}
|
|
@@ -1340,9 +1345,9 @@ function projectionKindForImpact(projection) {
|
|
|
1340
1345
|
(projection.uiWeb || []).length > 0 ||
|
|
1341
1346
|
(projection.uiIos || []).length > 0 ||
|
|
1342
1347
|
(projection.uiScreens || []).length > 0 ||
|
|
1343
|
-
projection.platform === "
|
|
1344
|
-
projection.platform === "
|
|
1345
|
-
projection.platform === "
|
|
1348
|
+
projection.platform === "web_surface" ||
|
|
1349
|
+
projection.platform === "ios_surface" ||
|
|
1350
|
+
projection.platform === "ui_contract"
|
|
1346
1351
|
) {
|
|
1347
1352
|
return "ui";
|
|
1348
1353
|
}
|
|
@@ -1634,7 +1639,7 @@ function buildProjectionImpacts(graph, { sliceArtifact, diffArtifact }) {
|
|
|
1634
1639
|
"selected_entity",
|
|
1635
1640
|
(projection) => `Projection ${projection.id} is in scope because selected entity ${id} participates in that projection.`
|
|
1636
1641
|
)) addImpact(impactMap, impact);
|
|
1637
|
-
} else if (kind === "
|
|
1642
|
+
} else if (kind === "widget") {
|
|
1638
1643
|
for (const impact of projectionImpactsFromComponent(graph, id)) addImpact(impactMap, impact);
|
|
1639
1644
|
} else if (kind === "workflow") {
|
|
1640
1645
|
for (const impact of projectionImpactsFromWorkflow(graph, id, true)) addImpact(impactMap, impact);
|
|
@@ -1656,11 +1661,15 @@ function buildGeneratorTargets(graph, projectionImpacts = [], diffArtifact = nul
|
|
|
1656
1661
|
const targets = [];
|
|
1657
1662
|
const addTarget = (target) => {
|
|
1658
1663
|
if (!target?.target) return;
|
|
1659
|
-
if (
|
|
1664
|
+
if (target.component_id && !target.widget_id) {
|
|
1665
|
+
target.widget_id = target.component_id;
|
|
1666
|
+
delete target.component_id;
|
|
1667
|
+
}
|
|
1668
|
+
if (!target.projection_id && !target.widget_id) return;
|
|
1660
1669
|
if (!targets.some((entry) =>
|
|
1661
1670
|
entry.target === target.target &&
|
|
1662
1671
|
entry.projection_id === target.projection_id &&
|
|
1663
|
-
entry
|
|
1672
|
+
targetWidgetId(entry) === targetWidgetId(target)
|
|
1664
1673
|
)) {
|
|
1665
1674
|
targets.push(target);
|
|
1666
1675
|
}
|
|
@@ -1668,16 +1677,16 @@ function buildGeneratorTargets(graph, projectionImpacts = [], diffArtifact = nul
|
|
|
1668
1677
|
|
|
1669
1678
|
for (const entry of diffArtifact?.components || []) {
|
|
1670
1679
|
addTarget({
|
|
1671
|
-
target: "ui-
|
|
1672
|
-
|
|
1680
|
+
target: "ui-widget-contract",
|
|
1681
|
+
widget_id: entry.id,
|
|
1673
1682
|
required: true,
|
|
1674
|
-
reason: `
|
|
1683
|
+
reason: `Widget ${entry.id} changed directly, so its widget contract should be refreshed.`
|
|
1675
1684
|
});
|
|
1676
1685
|
addTarget({
|
|
1677
|
-
target: "
|
|
1678
|
-
|
|
1686
|
+
target: "widget-behavior-report",
|
|
1687
|
+
widget_id: entry.id,
|
|
1679
1688
|
required: true,
|
|
1680
|
-
reason: `
|
|
1689
|
+
reason: `Widget ${entry.id} changed directly, so behavior realizations should be reviewed across affected projections.`
|
|
1681
1690
|
});
|
|
1682
1691
|
}
|
|
1683
1692
|
|
|
@@ -1708,7 +1717,7 @@ function buildGeneratorTargets(graph, projectionImpacts = [], diffArtifact = nul
|
|
|
1708
1717
|
});
|
|
1709
1718
|
}
|
|
1710
1719
|
|
|
1711
|
-
if (projection.platform === "
|
|
1720
|
+
if (projection.platform === "ui_contract") {
|
|
1712
1721
|
addTarget({
|
|
1713
1722
|
target: "ui-contract-graph",
|
|
1714
1723
|
projection_id: impact.projection_id,
|
|
@@ -1730,30 +1739,30 @@ function buildGeneratorTargets(graph, projectionImpacts = [], diffArtifact = nul
|
|
|
1730
1739
|
|
|
1731
1740
|
for (const componentId of componentIds) {
|
|
1732
1741
|
addTarget({
|
|
1733
|
-
target: "ui-
|
|
1734
|
-
|
|
1742
|
+
target: "ui-widget-contract",
|
|
1743
|
+
widget_id: componentId,
|
|
1735
1744
|
projection_id: impact.projection_id,
|
|
1736
1745
|
required: true,
|
|
1737
|
-
reason: `Projection ${impact.projection_id} is affected by
|
|
1746
|
+
reason: `Projection ${impact.projection_id} is affected by widget ${componentId}, so the widget contract should be refreshed.`
|
|
1738
1747
|
});
|
|
1739
1748
|
addTarget({
|
|
1740
|
-
target: "
|
|
1741
|
-
|
|
1749
|
+
target: "widget-behavior-report",
|
|
1750
|
+
widget_id: componentId,
|
|
1742
1751
|
projection_id: impact.projection_id,
|
|
1743
1752
|
required: true,
|
|
1744
|
-
reason: `Projection ${impact.projection_id} is affected by
|
|
1753
|
+
reason: `Projection ${impact.projection_id} is affected by widget ${componentId}, so behavior data/event/action wiring should be reviewed.`
|
|
1745
1754
|
});
|
|
1746
1755
|
}
|
|
1747
1756
|
|
|
1748
|
-
if (projection.platform === "
|
|
1757
|
+
if (projection.platform === "web_surface") {
|
|
1749
1758
|
addTarget({
|
|
1750
|
-
target: "ui-
|
|
1759
|
+
target: "ui-surface-contract",
|
|
1751
1760
|
projection_id: impact.projection_id,
|
|
1752
1761
|
required: true,
|
|
1753
1762
|
reason: `Projection ${impact.projection_id} is a web UI surface, so the web UI contract should be refreshed.`
|
|
1754
1763
|
});
|
|
1755
1764
|
addTarget({
|
|
1756
|
-
target: "ui-
|
|
1765
|
+
target: "ui-surface-debug",
|
|
1757
1766
|
projection_id: impact.projection_id,
|
|
1758
1767
|
required: false,
|
|
1759
1768
|
reason: `Projection ${impact.projection_id} may benefit from UI web debug output during review.`
|
|
@@ -1768,7 +1777,7 @@ function buildGeneratorTargets(graph, projectionImpacts = [], diffArtifact = nul
|
|
|
1768
1777
|
}
|
|
1769
1778
|
}
|
|
1770
1779
|
|
|
1771
|
-
if (projection.platform === "
|
|
1780
|
+
if (projection.platform === "ios_surface") {
|
|
1772
1781
|
addTarget({
|
|
1773
1782
|
target: "swiftui-app",
|
|
1774
1783
|
projection_id: impact.projection_id,
|
|
@@ -1819,7 +1828,7 @@ function buildGeneratorTargets(graph, projectionImpacts = [], diffArtifact = nul
|
|
|
1819
1828
|
return targets.sort((a, b) => {
|
|
1820
1829
|
const projectionCompare = String(a.projection_id || "").localeCompare(String(b.projection_id || ""));
|
|
1821
1830
|
if (projectionCompare !== 0) return projectionCompare;
|
|
1822
|
-
const componentCompare = String(a
|
|
1831
|
+
const componentCompare = String(targetWidgetId(a) || "").localeCompare(String(targetWidgetId(b) || ""));
|
|
1823
1832
|
if (componentCompare !== 0) return componentCompare;
|
|
1824
1833
|
return projectionCompare !== 0 ? projectionCompare : a.target.localeCompare(b.target);
|
|
1825
1834
|
});
|