@topogram/cli 0.3.45 → 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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@topogram/cli",
3
- "version": "0.3.45",
3
+ "version": "0.3.46",
4
4
  "description": "Topogram CLI for checking Topogram workspaces and generating app bundles.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -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
@@ -5565,6 +5565,32 @@ function importAdoptCommand(projectRoot, selector, write = false) {
5565
5565
  return `topogram import adopt ${selector} ${importProjectCommandPath(projectRoot)} ${write ? "--write" : "--dry-run"}`;
5566
5566
  }
5567
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
+
5568
5594
  function readImportAdoptionArtifacts(inputPath) {
5569
5595
  const projectRoot = normalizeProjectRoot(inputPath);
5570
5596
  const topogramRoot = normalizeTopogramPath(inputPath);
@@ -5589,6 +5615,27 @@ function readImportAdoptionArtifacts(inputPath) {
5589
5615
  };
5590
5616
  }
5591
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
+
5592
5639
  function summarizeImportAdoption(adoptionPlan, adoptionStatus, projectRoot) {
5593
5640
  const surfaces = adoptionPlan.imported_proposal_surfaces || [];
5594
5641
  const slugs = [];
@@ -5700,6 +5747,7 @@ function printBrownfieldImportPlan(payload) {
5700
5747
  }
5701
5748
 
5702
5749
  function buildBrownfieldImportAdoptListPayload(inputPath) {
5750
+ const artifacts = readImportAdoptionArtifacts(inputPath);
5703
5751
  const plan = buildBrownfieldImportPlanPayload(inputPath);
5704
5752
  const selectors = plan.bundles.map((bundle) => ({
5705
5753
  selector: `bundle:${bundle.bundle}`,
@@ -5713,12 +5761,15 @@ function buildBrownfieldImportAdoptListPayload(inputPath) {
5713
5761
  previewCommand: importAdoptCommand(plan.projectRoot, `bundle:${bundle.bundle}`, false),
5714
5762
  writeCommand: importAdoptCommand(plan.projectRoot, `bundle:${bundle.bundle}`, true)
5715
5763
  }));
5764
+ const broadSelectors = buildBrownfieldBroadAdoptSelectors(plan.projectRoot, artifacts.adoptionPlan);
5716
5765
  return {
5717
5766
  ok: true,
5718
5767
  projectRoot: plan.projectRoot,
5719
5768
  topogramRoot: plan.topogramRoot,
5720
5769
  selectorCount: selectors.length,
5721
5770
  selectors,
5771
+ broadSelectorCount: broadSelectors.length,
5772
+ broadSelectors,
5722
5773
  nextCommand: selectors.find((selector) => !selector.complete)?.previewCommand || plan.commands.status
5723
5774
  };
5724
5775
  }
@@ -5734,6 +5785,15 @@ function printBrownfieldImportAdoptList(payload) {
5734
5785
  console.log(` Preview: ${selector.previewCommand}`);
5735
5786
  console.log(` Write: ${selector.writeCommand}`);
5736
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
+ }
5737
5797
  console.log("");
5738
5798
  console.log(`Next: ${payload.nextCommand}`);
5739
5799
  }
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
- return values.length ? values.map((item) => `\`${item}\``).join(", ") : empty;
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_"}