@topogram/cli 0.3.44 → 0.3.46
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/package.json
CHANGED
|
@@ -172,6 +172,7 @@ export function buildBundleAdoptionPriorities(report, confidenceRank) {
|
|
|
172
172
|
enums: bundle.enums.length,
|
|
173
173
|
capabilities: bundle.capabilities.length,
|
|
174
174
|
shapes: bundle.shapes.length,
|
|
175
|
+
components: bundle.components?.length || 0,
|
|
175
176
|
screens: bundle.screens.length,
|
|
176
177
|
workflows: bundle.workflows.length,
|
|
177
178
|
docs: bundle.docs.length
|
package/src/cli.js
CHANGED
|
@@ -595,9 +595,9 @@ function printGeneratorHelp() {
|
|
|
595
595
|
console.log("Inspects generator manifests and checks generator pack conformance.");
|
|
596
596
|
console.log("");
|
|
597
597
|
console.log("Notes:");
|
|
598
|
-
console.log(" - list shows bundled generators plus installed package-backed generators declared in package.json.");
|
|
599
|
-
console.log(" - show accepts an installed package name or a bundled fallback generator id.");
|
|
600
|
-
console.log(" - check validates a local generator package path or an already installed package.");
|
|
598
|
+
console.log(" - list shows bundled generators plus installed package-backed generators declared in package.json; it reads manifests only.");
|
|
599
|
+
console.log(" - show accepts an installed package name or a bundled fallback generator id; it does not load adapter code.");
|
|
600
|
+
console.log(" - check validates a local generator package path or an already installed package by loading the adapter and running smoke generation.");
|
|
601
601
|
console.log(" - Topogram does not install generator packages during show or check.");
|
|
602
602
|
console.log(` - package-backed project generators are governed by ${GENERATOR_POLICY_FILE}; bundled topogram/* generators are allowed.`);
|
|
603
603
|
console.log("");
|
|
@@ -1250,6 +1250,7 @@ function printGeneratorCheck(payload) {
|
|
|
1250
1250
|
console.log(`Projection platforms: ${payload.manifest.projectionPlatforms.join(", ")}`);
|
|
1251
1251
|
console.log(`Source mode: ${payload.manifest.source}`);
|
|
1252
1252
|
}
|
|
1253
|
+
console.log("Executes package code: yes (loads adapter and runs smoke generate)");
|
|
1253
1254
|
console.log("");
|
|
1254
1255
|
console.log("Checks:");
|
|
1255
1256
|
for (const check of payload.checks || []) {
|
|
@@ -1285,6 +1286,8 @@ function generatorManifestSummary(manifest, metadata = {}) {
|
|
|
1285
1286
|
stack: manifest.stack || {},
|
|
1286
1287
|
capabilities: manifest.capabilities || {},
|
|
1287
1288
|
source: manifest.source,
|
|
1289
|
+
loadsAdapter: false,
|
|
1290
|
+
executesPackageCode: false,
|
|
1288
1291
|
...(manifest.profile ? { profile: manifest.profile } : {}),
|
|
1289
1292
|
...(manifest.package ? { package: manifest.package } : {}),
|
|
1290
1293
|
...(installCommand ? { installCommand } : {}),
|
|
@@ -1496,6 +1499,8 @@ function printGeneratorList(payload) {
|
|
|
1496
1499
|
const stack = Object.values(generator.stack || {}).join(" + ") || "not declared";
|
|
1497
1500
|
console.log(`- ${id}${generator.version ? `@${generator.version}` : ""} (${generator.surface || "unknown"}, ${status})`);
|
|
1498
1501
|
console.log(` Source: ${generator.source}`);
|
|
1502
|
+
console.log(" Adapter loaded: no");
|
|
1503
|
+
console.log(" Executes package code: no");
|
|
1499
1504
|
if (generator.source === "package") {
|
|
1500
1505
|
console.log(` Installed: ${generator.installed ? "yes" : "no"}`);
|
|
1501
1506
|
}
|
|
@@ -1529,6 +1534,8 @@ function printGeneratorShow(payload) {
|
|
|
1529
1534
|
console.log(`Generator: ${generator.id}@${generator.version}`);
|
|
1530
1535
|
console.log(`Surface: ${generator.surface}`);
|
|
1531
1536
|
console.log(`Source: ${generator.source}${generator.planned ? " (planned)" : ""}`);
|
|
1537
|
+
console.log("Adapter loaded: no");
|
|
1538
|
+
console.log("Executes package code: no");
|
|
1532
1539
|
if (generator.source === "package") {
|
|
1533
1540
|
console.log(`Installed: ${generator.installed ? "yes" : "no"}`);
|
|
1534
1541
|
}
|
|
@@ -5558,6 +5565,32 @@ function importAdoptCommand(projectRoot, selector, write = false) {
|
|
|
5558
5565
|
return `topogram import adopt ${selector} ${importProjectCommandPath(projectRoot)} ${write ? "--write" : "--dry-run"}`;
|
|
5559
5566
|
}
|
|
5560
5567
|
|
|
5568
|
+
const BROWNFIELD_BROAD_ADOPT_SELECTORS = [
|
|
5569
|
+
{
|
|
5570
|
+
selector: "from-plan",
|
|
5571
|
+
kind: "plan",
|
|
5572
|
+
label: "approved or pending plan items",
|
|
5573
|
+
matches: (item) => item.current_state === "stage" || item.current_state === "accept"
|
|
5574
|
+
},
|
|
5575
|
+
{ selector: "actors", kind: "kind", label: "actors", matches: (item) => item.kind === "actor" },
|
|
5576
|
+
{ selector: "roles", kind: "kind", label: "roles", matches: (item) => item.kind === "role" },
|
|
5577
|
+
{ selector: "enums", kind: "kind", label: "enums", matches: (item) => item.kind === "enum" },
|
|
5578
|
+
{ selector: "shapes", kind: "kind", label: "shapes", matches: (item) => item.kind === "shape" },
|
|
5579
|
+
{ selector: "entities", kind: "kind", label: "entities", matches: (item) => item.kind === "entity" },
|
|
5580
|
+
{ selector: "capabilities", kind: "kind", label: "capabilities", matches: (item) => item.kind === "capability" },
|
|
5581
|
+
{ selector: "components", kind: "kind", label: "components", matches: (item) => item.kind === "component" },
|
|
5582
|
+
{ selector: "docs", kind: "track", label: "docs", matches: (item) => item.track === "docs" },
|
|
5583
|
+
{
|
|
5584
|
+
selector: "journeys",
|
|
5585
|
+
kind: "track",
|
|
5586
|
+
label: "journey docs",
|
|
5587
|
+
matches: (item) => item.track === "docs" && String(item.canonical_rel_path || "").startsWith("docs/journeys/")
|
|
5588
|
+
},
|
|
5589
|
+
{ selector: "workflows", kind: "track", label: "workflows", matches: (item) => item.track === "workflows" || item.kind === "decision" },
|
|
5590
|
+
{ selector: "verification", kind: "kind", label: "verification", matches: (item) => item.kind === "verification" },
|
|
5591
|
+
{ selector: "ui", kind: "track", label: "UI reports and components", matches: (item) => item.track === "ui" }
|
|
5592
|
+
];
|
|
5593
|
+
|
|
5561
5594
|
function readImportAdoptionArtifacts(inputPath) {
|
|
5562
5595
|
const projectRoot = normalizeProjectRoot(inputPath);
|
|
5563
5596
|
const topogramRoot = normalizeTopogramPath(inputPath);
|
|
@@ -5582,6 +5615,27 @@ function readImportAdoptionArtifacts(inputPath) {
|
|
|
5582
5615
|
};
|
|
5583
5616
|
}
|
|
5584
5617
|
|
|
5618
|
+
function buildBrownfieldBroadAdoptSelectors(projectRoot, adoptionPlan) {
|
|
5619
|
+
const surfaces = adoptionPlan.imported_proposal_surfaces || [];
|
|
5620
|
+
return BROWNFIELD_BROAD_ADOPT_SELECTORS.map((definition) => {
|
|
5621
|
+
const items = surfaces.filter(definition.matches);
|
|
5622
|
+
const pendingItems = items.filter((item) => !["accept", "accepted", "applied"].includes(item.current_state));
|
|
5623
|
+
const appliedItems = items.filter((item) => ["accept", "accepted", "applied"].includes(item.current_state));
|
|
5624
|
+
const blockedItems = items.filter((item) => item.human_review_required);
|
|
5625
|
+
return {
|
|
5626
|
+
selector: definition.selector,
|
|
5627
|
+
kind: definition.kind,
|
|
5628
|
+
label: definition.label,
|
|
5629
|
+
itemCount: items.length,
|
|
5630
|
+
pendingItemCount: pendingItems.length,
|
|
5631
|
+
appliedItemCount: appliedItems.length,
|
|
5632
|
+
blockedItemCount: blockedItems.length,
|
|
5633
|
+
previewCommand: importAdoptCommand(projectRoot, definition.selector, false),
|
|
5634
|
+
writeCommand: importAdoptCommand(projectRoot, definition.selector, true)
|
|
5635
|
+
};
|
|
5636
|
+
}).filter((selector) => selector.itemCount > 0);
|
|
5637
|
+
}
|
|
5638
|
+
|
|
5585
5639
|
function summarizeImportAdoption(adoptionPlan, adoptionStatus, projectRoot) {
|
|
5586
5640
|
const surfaces = adoptionPlan.imported_proposal_surfaces || [];
|
|
5587
5641
|
const slugs = [];
|
|
@@ -5693,6 +5747,7 @@ function printBrownfieldImportPlan(payload) {
|
|
|
5693
5747
|
}
|
|
5694
5748
|
|
|
5695
5749
|
function buildBrownfieldImportAdoptListPayload(inputPath) {
|
|
5750
|
+
const artifacts = readImportAdoptionArtifacts(inputPath);
|
|
5696
5751
|
const plan = buildBrownfieldImportPlanPayload(inputPath);
|
|
5697
5752
|
const selectors = plan.bundles.map((bundle) => ({
|
|
5698
5753
|
selector: `bundle:${bundle.bundle}`,
|
|
@@ -5706,12 +5761,15 @@ function buildBrownfieldImportAdoptListPayload(inputPath) {
|
|
|
5706
5761
|
previewCommand: importAdoptCommand(plan.projectRoot, `bundle:${bundle.bundle}`, false),
|
|
5707
5762
|
writeCommand: importAdoptCommand(plan.projectRoot, `bundle:${bundle.bundle}`, true)
|
|
5708
5763
|
}));
|
|
5764
|
+
const broadSelectors = buildBrownfieldBroadAdoptSelectors(plan.projectRoot, artifacts.adoptionPlan);
|
|
5709
5765
|
return {
|
|
5710
5766
|
ok: true,
|
|
5711
5767
|
projectRoot: plan.projectRoot,
|
|
5712
5768
|
topogramRoot: plan.topogramRoot,
|
|
5713
5769
|
selectorCount: selectors.length,
|
|
5714
5770
|
selectors,
|
|
5771
|
+
broadSelectorCount: broadSelectors.length,
|
|
5772
|
+
broadSelectors,
|
|
5715
5773
|
nextCommand: selectors.find((selector) => !selector.complete)?.previewCommand || plan.commands.status
|
|
5716
5774
|
};
|
|
5717
5775
|
}
|
|
@@ -5727,6 +5785,15 @@ function printBrownfieldImportAdoptList(payload) {
|
|
|
5727
5785
|
console.log(` Preview: ${selector.previewCommand}`);
|
|
5728
5786
|
console.log(` Write: ${selector.writeCommand}`);
|
|
5729
5787
|
}
|
|
5788
|
+
if (payload.broadSelectors.length > 0) {
|
|
5789
|
+
console.log("");
|
|
5790
|
+
console.log("Broad selectors:");
|
|
5791
|
+
for (const selector of payload.broadSelectors) {
|
|
5792
|
+
console.log(`- ${selector.selector}: ${selector.itemCount} ${selector.label}`);
|
|
5793
|
+
console.log(` Preview: ${selector.previewCommand}`);
|
|
5794
|
+
console.log(` Write: ${selector.writeCommand}`);
|
|
5795
|
+
}
|
|
5796
|
+
}
|
|
5730
5797
|
console.log("");
|
|
5731
5798
|
console.log(`Next: ${payload.nextCommand}`);
|
|
5732
5799
|
}
|
|
@@ -10,6 +10,10 @@ import {
|
|
|
10
10
|
resolveGeneratorManifestForBinding,
|
|
11
11
|
validateGeneratorManifest
|
|
12
12
|
} from "./registry.js";
|
|
13
|
+
import {
|
|
14
|
+
generatorPolicyDiagnosticsForBindings,
|
|
15
|
+
loadGeneratorPolicy
|
|
16
|
+
} from "../generator-policy.js";
|
|
13
17
|
import { generateDbContractGraph } from "./surfaces/databases/contract.js";
|
|
14
18
|
import { generateDbLifecyclePlan } from "./surfaces/databases/lifecycle-shared.js";
|
|
15
19
|
import {
|
|
@@ -252,6 +256,26 @@ function loadPackageGeneratorAdapter(manifest, component, options = {}) {
|
|
|
252
256
|
throw new Error(`Component '${component?.id || "unknown"}' generator '${manifest.id}@${manifest.version}' is package-backed but does not declare a package.`);
|
|
253
257
|
}
|
|
254
258
|
const rootDir = options.configDir || options.rootDir || process.cwd();
|
|
259
|
+
const diagnostics = generatorPolicyDiagnosticsForBindings(
|
|
260
|
+
loadGeneratorPolicy(rootDir),
|
|
261
|
+
[{
|
|
262
|
+
componentId: String(component?.id || "unknown"),
|
|
263
|
+
componentType: String(component?.type || manifest.surface || "unknown"),
|
|
264
|
+
projection: String(component?.projection?.id || component?.projection || "unknown"),
|
|
265
|
+
generatorId: String(component?.generator?.id || manifest.id),
|
|
266
|
+
version: String(component?.generator?.version || manifest.version),
|
|
267
|
+
packageName
|
|
268
|
+
}],
|
|
269
|
+
"generator-adapter"
|
|
270
|
+
);
|
|
271
|
+
const errors = diagnostics.filter((diagnostic) => diagnostic.severity === "error");
|
|
272
|
+
if (errors.length > 0) {
|
|
273
|
+
throw new Error(errors.map((diagnostic) =>
|
|
274
|
+
diagnostic.suggestedFix
|
|
275
|
+
? `${diagnostic.message} Suggested fix: ${diagnostic.suggestedFix}`
|
|
276
|
+
: diagnostic.message
|
|
277
|
+
).join("\n"));
|
|
278
|
+
}
|
|
255
279
|
let moduleValue;
|
|
256
280
|
try {
|
|
257
281
|
moduleValue = requireFromProject(rootDir)(packageName);
|
package/src/generator/check.js
CHANGED
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
* @property {Array<{ name: string, ok: boolean, message: string }>} checks
|
|
26
26
|
* @property {string[]} errors
|
|
27
27
|
* @property {{ files: number, artifacts: number, diagnostics: number }|null} smoke
|
|
28
|
+
* @property {boolean} executesPackageCode
|
|
28
29
|
*/
|
|
29
30
|
|
|
30
31
|
/**
|
|
@@ -238,7 +239,8 @@ export function checkGeneratorPack(sourceSpec, options = {}) {
|
|
|
238
239
|
manifest: null,
|
|
239
240
|
checks: [],
|
|
240
241
|
errors: [],
|
|
241
|
-
smoke: null
|
|
242
|
+
smoke: null,
|
|
243
|
+
executesPackageCode: true
|
|
242
244
|
};
|
|
243
245
|
|
|
244
246
|
/** @type {any|null} */
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
|
|
3
3
|
import { getProjection } from "../shared.js";
|
|
4
|
+
import { generateServerContract } from "./server-contract.js";
|
|
4
5
|
|
|
5
6
|
function renderPackageJson(profile) {
|
|
6
7
|
const dependencies = profile === "express"
|
|
@@ -41,10 +42,10 @@ function routePath(path) {
|
|
|
41
42
|
return String(path || "/").replace(/:([A-Za-z0-9_]+)/g, ":$1");
|
|
42
43
|
}
|
|
43
44
|
|
|
44
|
-
function renderHonoIndex(projection) {
|
|
45
|
-
const routes = (
|
|
45
|
+
function renderHonoIndex(projection, contract) {
|
|
46
|
+
const routes = (contract.routes || []).map((route) => {
|
|
46
47
|
const method = String(route.method || "GET").toLowerCase();
|
|
47
|
-
return `app.${method}("${routePath(route.path)}", (c) => c.json({ ok: true, capability: "${route.capabilityId}", input: { params: c.req.param(), query: c.req.query() } }, ${route.
|
|
48
|
+
return `app.${method}("${routePath(route.path)}", (c) => c.json({ ok: true, capability: "${route.capabilityId}", input: { params: c.req.param(), query: c.req.query() } }, ${route.successStatus || 200} as any));`;
|
|
48
49
|
}).join("\n");
|
|
49
50
|
return `import { serve } from "@hono/node-server";
|
|
50
51
|
import { Hono } from "hono";
|
|
@@ -65,10 +66,10 @@ function expressPath(path) {
|
|
|
65
66
|
return routePath(path);
|
|
66
67
|
}
|
|
67
68
|
|
|
68
|
-
function renderExpressIndex(projection) {
|
|
69
|
-
const routes = (
|
|
69
|
+
function renderExpressIndex(projection, contract) {
|
|
70
|
+
const routes = (contract.routes || []).map((route) => {
|
|
70
71
|
const method = String(route.method || "GET").toLowerCase();
|
|
71
|
-
return `app.${method}("${expressPath(route.path)}", (req, res) => res.status(${route.
|
|
72
|
+
return `app.${method}("${expressPath(route.path)}", (req, res) => res.status(${route.successStatus || 200}).json({ ok: true, capability: "${route.capabilityId}", input: { params: req.params, query: req.query } }));`;
|
|
72
73
|
}).join("\n");
|
|
73
74
|
return `import express from "express";
|
|
74
75
|
|
|
@@ -88,10 +89,11 @@ app.listen(port, () => {
|
|
|
88
89
|
|
|
89
90
|
export function generateStatelessServer(graph, options = {}) {
|
|
90
91
|
const projection = getProjection(graph, options.projectionId);
|
|
92
|
+
const contract = generateServerContract(graph, { ...options, projectionId: projection.id });
|
|
91
93
|
const profile = options.profile === "express" ? "express" : "hono";
|
|
92
94
|
return {
|
|
93
95
|
"package.json": renderPackageJson(profile),
|
|
94
96
|
"tsconfig.json": renderTsconfig(),
|
|
95
|
-
"src/index.ts": profile === "express" ? renderExpressIndex(projection) : renderHonoIndex(projection)
|
|
97
|
+
"src/index.ts": profile === "express" ? renderExpressIndex(projection, contract) : renderHonoIndex(projection, contract)
|
|
96
98
|
};
|
|
97
99
|
}
|
package/src/workflows.js
CHANGED
|
@@ -1679,7 +1679,8 @@ function summarizeBundleParticipants(bundle) {
|
|
|
1679
1679
|
}
|
|
1680
1680
|
|
|
1681
1681
|
function summarizeBundleSurface(bundle, values, empty = "_none_") {
|
|
1682
|
-
|
|
1682
|
+
const list = Array.isArray(values) ? values : [];
|
|
1683
|
+
return list.length ? list.map((item) => `\`${item}\``).join(", ") : empty;
|
|
1683
1684
|
}
|
|
1684
1685
|
|
|
1685
1686
|
function buildBundleOperatorSummary(bundle) {
|
|
@@ -1693,6 +1694,7 @@ function buildBundleOperatorSummary(bundle) {
|
|
|
1693
1694
|
bundle.id;
|
|
1694
1695
|
const participants = summarizeBundleParticipants(bundle);
|
|
1695
1696
|
const capabilityIds = [...new Set((bundle.capabilities || []).map((entry) => entry.id_hint))].slice(0, 4);
|
|
1697
|
+
const componentIds = [...new Set((bundle.components || []).map((entry) => entry.id_hint))].slice(0, 4);
|
|
1696
1698
|
const screenIds = [...new Set((bundle.screens || []).map((entry) => entry.id_hint))].slice(0, 4);
|
|
1697
1699
|
const routePaths = [...new Set((bundle.uiRoutes || []).map((entry) => entry.path).filter(Boolean))].slice(0, 4);
|
|
1698
1700
|
const workflowIds = [...new Set((bundle.workflows || []).map((entry) => entry.id_hint))].slice(0, 4);
|
|
@@ -1708,6 +1710,7 @@ function buildBundleOperatorSummary(bundle) {
|
|
|
1708
1710
|
const evidenceKinds = [
|
|
1709
1711
|
(bundle.entities || []).length > 0 ? "entity evidence" : null,
|
|
1710
1712
|
(bundle.capabilities || []).length > 0 ? "API capability evidence" : null,
|
|
1713
|
+
(bundle.components || []).length > 0 ? "UI component evidence" : null,
|
|
1711
1714
|
(bundle.screens || []).length > 0 || (bundle.uiRoutes || []).length > 0 ? "UI screen/route evidence" : null,
|
|
1712
1715
|
(bundle.workflows || []).length > 0 ? "workflow evidence" : null,
|
|
1713
1716
|
(bundle.docs || []).length > 0 ? "doc evidence" : null,
|
|
@@ -1723,6 +1726,7 @@ function buildBundleOperatorSummary(bundle) {
|
|
|
1723
1726
|
primaryEntityId,
|
|
1724
1727
|
participants,
|
|
1725
1728
|
capabilityIds,
|
|
1729
|
+
componentIds,
|
|
1726
1730
|
screenIds,
|
|
1727
1731
|
routePaths,
|
|
1728
1732
|
workflowIds,
|
|
@@ -2711,6 +2715,7 @@ function renderCandidateBundleReadme(bundle, proposalSurfaces = []) {
|
|
|
2711
2715
|
`Enums: ${bundle.enums.length}`,
|
|
2712
2716
|
`Capabilities: ${bundle.capabilities.length}`,
|
|
2713
2717
|
`Shapes: ${bundle.shapes.length}`,
|
|
2718
|
+
`Components: ${bundle.components.length}`,
|
|
2714
2719
|
`Screens: ${bundle.screens.length}`,
|
|
2715
2720
|
`UI routes: ${bundle.uiRoutes.length}`,
|
|
2716
2721
|
`UI actions: ${bundle.uiActions.length}`,
|
|
@@ -2728,6 +2733,7 @@ function renderCandidateBundleReadme(bundle, proposalSurfaces = []) {
|
|
|
2728
2733
|
`- Primary entity: ${summary.primaryEntityId ? `\`${summary.primaryEntityId}\`` : "_none_"}`,
|
|
2729
2734
|
`- Participants: ${summary.participants.label}`,
|
|
2730
2735
|
`- Main capabilities: ${summarizeBundleSurface(bundle, summary.capabilityIds)}`,
|
|
2736
|
+
`- Main components: ${summarizeBundleSurface(bundle, summary.componentIds)}`,
|
|
2731
2737
|
`- Main screens: ${summarizeBundleSurface(bundle, summary.screenIds)}`,
|
|
2732
2738
|
`- Main routes: ${summarizeBundleSurface(bundle, summary.routePaths)}`,
|
|
2733
2739
|
`- Main workflows: ${summarizeBundleSurface(bundle, summary.workflowIds)}`,
|
|
@@ -7581,6 +7587,7 @@ function reconcileWorkflow(inputPath, options = {}) {
|
|
|
7581
7587
|
enums: bundle.enums.map((entry) => entry.id_hint),
|
|
7582
7588
|
capabilities: bundle.capabilities.map((entry) => entry.id_hint),
|
|
7583
7589
|
shapes: bundle.shapes.map((entry) => entry.id),
|
|
7590
|
+
components: bundle.components.map((entry) => entry.id_hint),
|
|
7584
7591
|
screens: bundle.screens.map((entry) => entry.id_hint),
|
|
7585
7592
|
workflows: bundle.workflows.map((entry) => entry.id_hint),
|
|
7586
7593
|
docs: bundle.docs.map((entry) => entry.id),
|
|
@@ -7604,10 +7611,11 @@ function reconcileWorkflow(inputPath, options = {}) {
|
|
|
7604
7611
|
: "## Promoted Canonical Items";
|
|
7605
7612
|
files["candidates/reconcile/report.json"] = `${stableStringify(report)}\n`;
|
|
7606
7613
|
const candidateModelBundlesMarkdown = report.candidate_model_bundles.length
|
|
7607
|
-
? report.candidate_model_bundles.map((bundle) => `- \`${bundle.slug}\` (${bundle.actors.length} actors, ${bundle.roles.length} roles, ${bundle.entities.length} entities, ${bundle.enums.length} enums, ${bundle.capabilities.length} capabilities, ${bundle.shapes.length} shapes, ${bundle.screens.length} screens, ${bundle.workflows.length} workflows, ${bundle.docs.length} docs)
|
|
7614
|
+
? report.candidate_model_bundles.map((bundle) => `- \`${bundle.slug}\` (${bundle.actors.length} actors, ${bundle.roles.length} roles, ${bundle.entities.length} entities, ${bundle.enums.length} enums, ${bundle.capabilities.length} capabilities, ${bundle.shapes.length} shapes, ${bundle.components.length} components, ${bundle.screens.length} screens, ${bundle.workflows.length} workflows, ${bundle.docs.length} docs)
|
|
7608
7615
|
- primary concept \`${bundle.operator_summary.primaryConcept}\`${bundle.operator_summary.primaryEntityId ? `, primary entity \`${bundle.operator_summary.primaryEntityId}\`` : ""}
|
|
7609
7616
|
- participants ${bundle.operator_summary.participants.label}
|
|
7610
7617
|
- main capabilities ${summarizeBundleSurface(bundle, bundle.operator_summary.capabilityIds)}
|
|
7618
|
+
- main components ${summarizeBundleSurface(bundle, bundle.operator_summary.componentIds)}
|
|
7611
7619
|
- main routes ${summarizeBundleSurface(bundle, bundle.operator_summary.routePaths)}
|
|
7612
7620
|
- candidate maintained seam mappings ${renderMaintainedSeamCandidatesInline(bundle)}
|
|
7613
7621
|
- permission hints ${bundle.auth_permission_hints?.length ? bundle.auth_permission_hints.map((entry) => formatAuthPermissionHintInline(entry)).join(", ") : "_none_"}
|