@canonical/pragma-cli 0.20.0 → 0.21.0

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 (199) hide show
  1. package/dist/pragma +0 -0
  2. package/package.json +30 -18
  3. package/src/constants.ts +1 -1
  4. package/src/domains/block/blockConfig.ts +47 -3
  5. package/src/domains/block/commands/list.test.ts +1 -1
  6. package/src/domains/block/commands/list.ts +27 -0
  7. package/src/domains/block/commands/lookup.ts +26 -52
  8. package/src/domains/block/formatters/index.ts +1 -1
  9. package/src/domains/block/formatters/list.test.ts +1 -1
  10. package/src/domains/block/formatters/list.ts +28 -42
  11. package/src/domains/block/formatters/lookup.test.ts +3 -2
  12. package/src/domains/block/formatters/lookup.ts +91 -296
  13. package/src/domains/block/formatters/types.ts +1 -1
  14. package/src/domains/block/operations/list.test.ts +1 -1
  15. package/src/domains/block/operations/list.ts +1 -1
  16. package/src/domains/block/operations/lookup.test.ts +29 -8
  17. package/src/domains/block/operations/lookup.ts +94 -16
  18. package/src/domains/block/orchestration/blockEmptyError.ts +1 -1
  19. package/src/domains/block/orchestration/buildBlockFilters.ts +1 -1
  20. package/src/domains/block/orchestration/enrichBlocks.ts +6 -2
  21. package/src/domains/block/orchestration/resolveBlockList.ts +1 -1
  22. package/src/domains/block/orchestration/resolveBlockLookup.ts +8 -2
  23. package/src/domains/block/types.ts +1 -1
  24. package/src/domains/config/commands/channel.ts +6 -4
  25. package/src/domains/config/commands/tier.ts +6 -4
  26. package/src/domains/config/mcp/specs.ts +18 -6
  27. package/src/domains/config/operations/validateTier.ts +1 -1
  28. package/src/domains/config/tasks/index.ts +3 -0
  29. package/src/domains/config/tasks/setChannel.ts +30 -0
  30. package/src/domains/config/tasks/setTier.ts +33 -0
  31. package/src/domains/create/commands/package.test.ts +2 -2
  32. package/src/domains/doctor/mcp/index.ts +1 -1
  33. package/src/domains/doctor/mcp/specs.ts +2 -49
  34. package/src/domains/graph/commands/inspect.test.ts +1 -1
  35. package/src/domains/graph/formatters/inspect.ts +12 -7
  36. package/src/domains/graph/operations/inspectUri.ts +4 -1
  37. package/src/domains/info/commands/upgrade.ts +6 -3
  38. package/src/domains/info/index.ts +3 -1
  39. package/src/domains/info/mcp/index.ts +2 -0
  40. package/src/domains/info/mcp/specs.ts +65 -0
  41. package/src/domains/llm/data/commandReference.ts +4 -4
  42. package/src/domains/llm/data/decisionTrees.ts +14 -12
  43. package/src/domains/llm/operations/collectContext.ts +1 -1
  44. package/src/domains/modifier/commands/list.ts +9 -0
  45. package/src/domains/modifier/commands/lookup.ts +22 -42
  46. package/src/domains/modifier/formatters/index.ts +4 -1
  47. package/src/domains/modifier/formatters/list.test.ts +1 -1
  48. package/src/domains/modifier/formatters/list.ts +13 -26
  49. package/src/domains/modifier/formatters/lookup.test.ts +1 -1
  50. package/src/domains/modifier/formatters/lookup.ts +41 -29
  51. package/src/domains/modifier/index.ts +1 -0
  52. package/src/domains/modifier/modifierConfig.ts +36 -0
  53. package/src/domains/modifier/operations/list.ts +1 -1
  54. package/src/domains/modifier/operations/lookup.ts +4 -3
  55. package/src/domains/modifier/orchestration/resolveModifierLookup.ts +1 -1
  56. package/src/domains/modifier/types.ts +1 -1
  57. package/src/domains/ontology/commands/list.test.ts +1 -1
  58. package/src/domains/ontology/commands/list.ts +18 -0
  59. package/src/domains/ontology/commands/show.test.ts +1 -1
  60. package/src/domains/ontology/formatters/list.ts +5 -3
  61. package/src/domains/ontology/formatters/show.ts +38 -13
  62. package/src/domains/ontology/helpers/queryClasses.ts +1 -1
  63. package/src/domains/ontology/helpers/queryProperties.ts +1 -1
  64. package/src/domains/ontology/operations/listOntologies.ts +1 -1
  65. package/src/domains/ontology/operations/showOntology.ts +1 -1
  66. package/src/domains/setup/helpers/completionScripts.test.ts +3 -3
  67. package/src/domains/setup/helpers/completionScripts.ts +4 -4
  68. package/src/domains/shared/ToolSpec.ts +1 -1
  69. package/src/domains/shared/context.ts +3 -2
  70. package/src/domains/shared/contracts.ts +40 -1
  71. package/src/domains/shared/filters/buildFilterConfig.ts +1 -2
  72. package/src/domains/shared/filters/buildFilters.ts +1 -1
  73. package/src/domains/shared/filters/describeFilters.ts +1 -1
  74. package/src/domains/shared/formatters.ts +47 -0
  75. package/src/domains/shared/renderers.ts +410 -0
  76. package/src/domains/shared/runtime.ts +7 -22
  77. package/src/domains/shared/types/block.ts +107 -0
  78. package/src/domains/shared/types/common.ts +33 -0
  79. package/src/domains/shared/types/graph.ts +17 -0
  80. package/src/domains/shared/types/index.ts +49 -0
  81. package/src/domains/shared/types/modifier.ts +22 -0
  82. package/src/domains/shared/types/ontology.ts +50 -0
  83. package/src/domains/shared/types/runtime.ts +21 -0
  84. package/src/domains/shared/types/standard.ts +64 -0
  85. package/src/domains/shared/types/tier.ts +15 -0
  86. package/src/domains/shared/types/token.ts +30 -0
  87. package/src/domains/standard/commands/list.ts +9 -0
  88. package/src/domains/standard/commands/lookup.ts +22 -50
  89. package/src/domains/standard/formatters/categories.test.ts +1 -1
  90. package/src/domains/standard/formatters/categories.ts +1 -1
  91. package/src/domains/standard/formatters/index.ts +4 -1
  92. package/src/domains/standard/formatters/list.test.ts +4 -1
  93. package/src/domains/standard/formatters/list.ts +112 -84
  94. package/src/domains/standard/formatters/lookup.test.ts +1 -1
  95. package/src/domains/standard/formatters/lookup.ts +85 -70
  96. package/src/domains/standard/formatters/types.ts +1 -1
  97. package/src/domains/standard/index.ts +1 -0
  98. package/src/domains/standard/operations/categories.ts +1 -1
  99. package/src/domains/standard/operations/list.ts +1 -1
  100. package/src/domains/standard/operations/lookup.ts +1 -1
  101. package/src/domains/standard/orchestration/buildStandardFilters.ts +1 -1
  102. package/src/domains/standard/orchestration/resolveStandardList.ts +4 -1
  103. package/src/domains/standard/orchestration/resolveStandardLookup.ts +1 -1
  104. package/src/domains/standard/orchestration/standardEmptyError.ts +1 -1
  105. package/src/domains/standard/standardConfig.ts +42 -0
  106. package/src/domains/standard/types.ts +1 -1
  107. package/src/domains/tier/commands/list.ts +16 -0
  108. package/src/domains/tier/formatters/list.test.ts +1 -1
  109. package/src/domains/tier/formatters/list.ts +11 -6
  110. package/src/domains/tier/operations/list.ts +1 -1
  111. package/src/domains/token/commands/list.ts +9 -0
  112. package/src/domains/token/commands/lookup.ts +22 -48
  113. package/src/domains/token/formatters/index.ts +4 -1
  114. package/src/domains/token/formatters/list.test.ts +1 -1
  115. package/src/domains/token/formatters/list.ts +15 -28
  116. package/src/domains/token/formatters/lookup.test.ts +2 -2
  117. package/src/domains/token/formatters/lookup.ts +80 -45
  118. package/src/domains/token/index.ts +1 -0
  119. package/src/domains/token/operations/list.ts +1 -1
  120. package/src/domains/token/operations/lookup.ts +1 -1
  121. package/src/domains/token/orchestration/resolveTokenLookup.ts +1 -1
  122. package/src/domains/token/tokenConfig.ts +38 -0
  123. package/src/domains/token/types.ts +1 -1
  124. package/src/index.ts +1 -1
  125. package/src/mcp/runMcpServer.test.ts +2 -2
  126. package/src/mcp/tools/index.ts +2 -0
  127. package/src/mcp/tools/registerTools.test.ts +8 -3
  128. package/src/package-manager/types.ts +1 -3
  129. package/src/pipeline/createProgram.ts +20 -1
  130. package/src/pipeline/index.ts +4 -1
  131. package/src/pipeline/parseGlobalFlags.test.ts +92 -0
  132. package/src/pipeline/parseGlobalFlags.ts +25 -0
  133. package/src/pipeline/runCli.orchestration.test.ts +1 -0
  134. package/src/pipeline/runCli.ts +11 -4
  135. package/src/pipeline/runInteractiveCommand.ts +198 -0
  136. package/src/testing/cli.ts +2 -2
  137. package/src/testing/fixtures.ts +2 -2
  138. package/src/testing/integration/boot.test.ts +2 -2
  139. package/src/testing/integration/cli-user-stories.test.ts +198 -0
  140. package/src/testing/integration/edge-cases.test.ts +263 -0
  141. package/src/testing/integration/parity.test.ts +377 -27
  142. package/src/testing/store.ts +1 -1
  143. package/src/tui/components/BulletList/BulletList.tsx +46 -0
  144. package/src/tui/components/BulletList/index.ts +2 -0
  145. package/src/tui/components/BulletList/types.ts +6 -0
  146. package/src/tui/components/Card/Card.tsx +73 -0
  147. package/src/tui/components/Card/index.ts +1 -0
  148. package/src/tui/components/Card/types.ts +12 -0
  149. package/src/tui/components/CodeBlock/CodeBlock.tsx +37 -0
  150. package/src/tui/components/CodeBlock/index.ts +2 -0
  151. package/src/tui/components/CodeBlock/types.ts +6 -0
  152. package/src/tui/components/DataRow/DataRow.tsx +80 -0
  153. package/src/tui/components/DataRow/index.ts +2 -0
  154. package/src/tui/components/DataRow/types.ts +14 -0
  155. package/src/tui/components/FieldRow/FieldRow.tsx +24 -0
  156. package/src/tui/components/FieldRow/index.ts +2 -0
  157. package/src/tui/components/FieldRow/types.ts +10 -0
  158. package/src/tui/components/HeaderRow/HeaderRow.tsx +32 -0
  159. package/src/tui/components/HeaderRow/index.ts +2 -0
  160. package/src/tui/components/HeaderRow/types.ts +8 -0
  161. package/src/tui/components/MarkdownText/MarkdownText.tsx +19 -0
  162. package/src/tui/components/MarkdownText/index.ts +2 -0
  163. package/src/tui/components/MarkdownText/types.ts +4 -0
  164. package/src/tui/components/MiniTable/MiniTable.tsx +82 -0
  165. package/src/tui/components/MiniTable/index.ts +2 -0
  166. package/src/tui/components/MiniTable/types.ts +6 -0
  167. package/src/tui/components/SectionRenderer/SectionRenderer.tsx +91 -0
  168. package/src/tui/components/SectionRenderer/index.ts +2 -0
  169. package/src/tui/components/SectionRenderer/types.ts +15 -0
  170. package/src/tui/components/TreeView/TreeView.tsx +84 -0
  171. package/src/tui/components/TreeView/index.ts +2 -0
  172. package/src/tui/components/TreeView/types.ts +6 -0
  173. package/src/tui/components/index.ts +19 -0
  174. package/src/tui/constants.ts +39 -0
  175. package/src/tui/createListView.ts +23 -0
  176. package/src/tui/createLookupView.ts +26 -0
  177. package/src/tui/helpers/computeWidths.ts +53 -0
  178. package/src/tui/helpers/fitColumns.ts +33 -0
  179. package/src/tui/helpers/formatMarkdown.ts +19 -0
  180. package/src/tui/helpers/getTerminalSize.ts +16 -0
  181. package/src/tui/helpers/index.ts +6 -0
  182. package/src/tui/helpers/syntaxColor.ts +67 -0
  183. package/src/tui/helpers/truncateText.ts +12 -0
  184. package/src/tui/hooks/index.ts +3 -0
  185. package/src/tui/hooks/types.ts +7 -0
  186. package/src/tui/hooks/useAutoExit.ts +17 -0
  187. package/src/tui/hooks/useTerminalSize.ts +19 -0
  188. package/src/tui/index.ts +15 -0
  189. package/src/tui/renderInk.tsx +18 -0
  190. package/src/tui/types.ts +12 -0
  191. package/src/tui/views/ListView/ListView.tsx +104 -0
  192. package/src/tui/views/ListView/index.ts +2 -0
  193. package/src/tui/views/ListView/types.ts +14 -0
  194. package/src/tui/views/LookupView/LookupView.tsx +244 -0
  195. package/src/tui/views/LookupView/index.ts +2 -0
  196. package/src/tui/views/LookupView/types.ts +16 -0
  197. package/src/tui/views/index.ts +4 -0
  198. package/src/domains/shared/types.test-d.ts +0 -127
  199. package/src/domains/shared/types.ts +0 -348
package/dist/pragma ADDED
Binary file
package/package.json CHANGED
@@ -1,15 +1,16 @@
1
1
  {
2
2
  "name": "@canonical/pragma-cli",
3
3
  "description": "CLI and MCP server for Canonical's design system.",
4
- "version": "0.20.0",
4
+ "version": "0.21.0",
5
5
  "type": "module",
6
6
  "module": "src/index.ts",
7
7
  "types": "src/index.ts",
8
8
  "bin": {
9
- "pragma": "src/bin.ts"
9
+ "pragma": "dist/pragma"
10
10
  },
11
11
  "files": [
12
- "src"
12
+ "src",
13
+ "dist"
13
14
  ],
14
15
  "author": {
15
16
  "email": "webteam@canonical.com",
@@ -19,6 +20,12 @@
19
20
  "type": "git",
20
21
  "url": "https://github.com/canonical/pragma"
21
22
  },
23
+ "os": [
24
+ "linux"
25
+ ],
26
+ "cpu": [
27
+ "x64"
28
+ ],
22
29
  "license": "GPL-3.0",
23
30
  "bugs": {
24
31
  "url": "https://github.com/canonical/pragma/issues"
@@ -30,11 +37,13 @@
30
37
  "#error": "./src/error/index.ts",
31
38
  "#package-manager": "./src/package-manager/index.ts",
32
39
  "#pipeline": "./src/pipeline/index.ts",
33
- "#testing": "./src/testing/index.ts"
40
+ "#testing": "./src/testing/index.ts",
41
+ "#tui": "./src/tui/index.ts"
34
42
  },
35
43
  "scripts": {
36
- "build": "echo 'No build needed - runs directly from TypeScript'",
37
- "build:compile": "bun build --compile --minify src/bin.ts --outfile dist/pragma",
44
+ "build": "bun build --compile --minify --target=bun-linux-x64 src/bin.ts --outfile dist/pragma",
45
+ "build:compile": "bun build --compile --minify --target=bun-linux-x64 src/bin.ts --outfile dist/pragma",
46
+ "prepublishOnly": "bun run build",
38
47
  "check": "bun run check:biome && bun run check:ts && bun run check:webarchitect",
39
48
  "check:webarchitect": "webarchitect tool-ts",
40
49
  "check:fix": "bun run check:biome:fix && bun run check:ts",
@@ -47,12 +56,13 @@
47
56
  "test:compile": "bun run src/compile-validation.runner.ts"
48
57
  },
49
58
  "devDependencies": {
50
- "@biomejs/biome": "2.4.6",
51
- "@canonical/biome-config": "^0.20.0",
52
- "@canonical/typescript-config": "^0.20.0",
53
- "@canonical/webarchitect": "^0.20.0",
59
+ "@biomejs/biome": "2.4.9",
60
+ "@canonical/biome-config": "^0.21.0",
61
+ "@canonical/typescript-config": "^0.21.0",
62
+ "@canonical/webarchitect": "^0.21.0",
54
63
  "@types/bun": "^1.3.10",
55
64
  "@types/node": "^24.12.0",
65
+ "@types/react": "^19.2.14",
56
66
  "expect-type": "^1.3.0",
57
67
  "typescript": "^5.9.3",
58
68
  "vitest": "^4.0.18"
@@ -63,17 +73,19 @@
63
73
  "@canonical/design-system": "^0.1.2"
64
74
  },
65
75
  "dependencies": {
66
- "@canonical/cli-core": "^0.20.0",
67
- "@canonical/harnesses": "^0.20.0",
68
- "@canonical/ke": "^0.20.0",
69
- "@canonical/summon-component": "^0.20.0",
70
- "@canonical/summon-core": "^0.20.0",
71
- "@canonical/summon-package": "^0.20.0",
72
- "@canonical/task": "^0.20.0",
76
+ "@canonical/cli-core": "^0.21.0",
77
+ "@canonical/harnesses": "^0.21.0",
78
+ "@canonical/ke": "^0.21.0",
79
+ "@canonical/summon-component": "^0.21.0",
80
+ "@canonical/summon-core": "^0.21.0",
81
+ "@canonical/summon-package": "^0.21.0",
82
+ "@canonical/task": "^0.21.0",
73
83
  "@modelcontextprotocol/sdk": "^1.12.0",
74
84
  "chalk": "^5.6.2",
75
85
  "commander": "^14.0.3",
86
+ "ink": "^6.8.0",
87
+ "react": "^19.2.4",
76
88
  "zod": "^3.25.0"
77
89
  },
78
- "gitHead": "1aee634b278922f2aa1cfe2a11d3b14e64280905"
90
+ "gitHead": "4a39c954e7bbad4903397f8371f801982034a26d"
79
91
  }
package/src/constants.ts CHANGED
@@ -68,6 +68,7 @@ const PROPERTY_MAP: Record<string, OntologyPropertyMap> = {
68
68
  },
69
69
  };
70
70
 
71
+ export type { Channel, OntologyPropertyMap };
71
72
  export {
72
73
  PROGRAM_DESCRIPTION,
73
74
  PROGRAM_NAME,
@@ -75,4 +76,3 @@ export {
75
76
  VALID_CHANNELS,
76
77
  VERSION,
77
78
  };
78
- export type { Channel, OntologyPropertyMap };
@@ -5,8 +5,9 @@ import type {
5
5
  BlockDigest,
6
6
  BlockSummary,
7
7
  FilterConfig,
8
- } from "../shared/types.js";
8
+ } from "../shared/types/index.js";
9
9
 
10
+ /** Display-contract configuration for block entities (components, patterns, layouts). */
10
11
  export const blockConfig: EntityDisplayConfig<
11
12
  BlockSummary,
12
13
  BlockDigest,
@@ -25,6 +26,48 @@ export const blockConfig: EntityDisplayConfig<
25
26
  { key: "name", label: "Name" },
26
27
  { key: "type", label: "Type" },
27
28
  { key: "tier", label: "Tier" },
29
+ {
30
+ key: "modifiers",
31
+ label: "Modifiers",
32
+ showWhenEmpty: false,
33
+ format: (value) =>
34
+ Array.isArray(value)
35
+ ? value.filter((entry) => typeof entry === "string").join(", ")
36
+ : "",
37
+ },
38
+ {
39
+ key: "implementations",
40
+ label: "Implementations",
41
+ showWhenEmpty: false,
42
+ format: (value) =>
43
+ Array.isArray(value)
44
+ ? value
45
+ .filter(
46
+ (entry): entry is { framework: string; available: boolean } =>
47
+ typeof entry === "object" &&
48
+ entry !== null &&
49
+ "framework" in entry &&
50
+ "available" in entry,
51
+ )
52
+ .filter((entry) => entry.available)
53
+ .map((entry) => entry.framework)
54
+ .join(", ")
55
+ : "",
56
+ },
57
+ {
58
+ key: "nodeCount",
59
+ label: "Nodes",
60
+ showWhenEmpty: false,
61
+ format: (value) =>
62
+ typeof value === "number" && value > 0 ? String(value) : "",
63
+ },
64
+ {
65
+ key: "tokenCount",
66
+ label: "Tokens",
67
+ showWhenEmpty: false,
68
+ format: (value) =>
69
+ typeof value === "number" && value > 0 ? String(value) : "",
70
+ },
28
71
  ],
29
72
  digestColumns: [{ key: "summary", label: "Summary", showWhenEmpty: false }],
30
73
  lookupSections: [
@@ -32,11 +75,12 @@ export const blockConfig: EntityDisplayConfig<
32
75
  { key: "whenToUse", heading: "When to use", kind: "field" },
33
76
  { key: "whenNotToUse", heading: "When not to use", kind: "field" },
34
77
  { key: "guidelines", heading: "Guidelines", kind: "field" },
78
+ { key: "anatomy", heading: "Anatomy", kind: "tree" },
35
79
  { key: "anatomyDsl", heading: "Anatomy (DSL)", kind: "code" },
36
80
  { key: "anatomyClassic", heading: "Anatomy (classic)", kind: "field" },
37
- { key: "modifierFamilies", heading: "Modifier Families", kind: "table" },
81
+ { key: "modifierFamilies", heading: "Modifiers", kind: "table" },
38
82
  { key: "properties", heading: "Properties", kind: "nested-table" },
39
- { key: "subcomponents", heading: "Subcomponents", kind: "list" },
83
+ { key: "subcomponents", heading: "Subcomponents", kind: "tree" },
40
84
  { key: "implementationPaths", heading: "Implementations", kind: "list" },
41
85
  { key: "tokens", heading: "Tokens", kind: "list" },
42
86
  ],
@@ -3,7 +3,7 @@ import type { Store } from "@canonical/ke";
3
3
  import { afterAll, beforeAll, describe, expect, it } from "vitest";
4
4
  import { createTestStore, DS_ALL_TTL } from "#testing";
5
5
  import type { PragmaContext } from "../../shared/context.js";
6
- import type { BlockSummary } from "../../shared/types.js";
6
+ import type { BlockSummary } from "../../shared/types/index.js";
7
7
  import buildListCommand from "./list.js";
8
8
 
9
9
  let store: Store;
@@ -11,8 +11,11 @@ import {
11
11
  type CommandResult,
12
12
  createOutputResult,
13
13
  } from "@canonical/cli-core";
14
+ import { createListView } from "#tui";
14
15
  import type { PragmaContext } from "../../shared/context.js";
16
+ import type { ColumnDef } from "../../shared/contracts.js";
15
17
  import { selectFormatter } from "../../shared/formatters.js";
18
+ import { blockConfig } from "../blockConfig.js";
16
19
  import { listFormatters } from "../formatters/index.js";
17
20
  import { resolveBlockList } from "../orchestration/index.js";
18
21
 
@@ -63,7 +66,31 @@ export default function buildListCommand(
63
66
 
64
67
  return createOutputResult(contract.result.items, {
65
68
  plain: selectFormatter(ctx, listFormatters),
69
+ ink: (data) =>
70
+ createListView({
71
+ heading: "Blocks",
72
+ domain: "block",
73
+ items: data,
74
+ columns: reorderColumns(blockConfig.listColumns, [
75
+ "name",
76
+ "type",
77
+ "tier",
78
+ "modifiers",
79
+ "uri",
80
+ ]),
81
+ }),
66
82
  });
67
83
  },
68
84
  };
69
85
  }
86
+
87
+ function reorderColumns<T>(
88
+ columns: readonly ColumnDef<T>[],
89
+ order: readonly string[],
90
+ ): readonly ColumnDef<T>[] {
91
+ const byKey = new Map(columns.map((col) => [col.key, col]));
92
+ return order.flatMap((key) => {
93
+ const col = byKey.get(key as keyof T & string);
94
+ return col ? [col] : [];
95
+ });
96
+ }
@@ -12,11 +12,14 @@ import {
12
12
  createOutputResult,
13
13
  } from "@canonical/cli-core";
14
14
  import { PragmaError } from "#error";
15
+ import { createLookupView } from "#tui";
15
16
  import type { PragmaContext } from "../../shared/context.js";
16
17
  import type { LookupResult } from "../../shared/contracts.js";
17
- import { lookupFormatters } from "../formatters/index.js";
18
+ import { renderLookupResults } from "../../shared/formatters.js";
19
+ import type { BlockDetailed } from "../../shared/types/index.js";
20
+ import { createLookupOptions, lookupFormatters } from "../formatters/index.js";
18
21
  import { resolveAspects } from "../helpers/index.js";
19
- import { listBlocks, type lookupBlock } from "../operations/index.js";
22
+ import { listBlocks } from "../operations/index.js";
20
23
  import {
21
24
  buildBlockFilters,
22
25
  resolveBlockLookup,
@@ -24,7 +27,7 @@ import {
24
27
  import type { AspectFlags } from "../types.js";
25
28
 
26
29
  interface BlockLookupOutput {
27
- readonly result: LookupResult<Awaited<ReturnType<typeof lookupBlock>>>;
30
+ readonly result: LookupResult<BlockDetailed>;
28
31
  readonly detailed: boolean;
29
32
  readonly aspects: AspectFlags;
30
33
  }
@@ -132,7 +135,26 @@ export default function buildLookupCommand(
132
135
 
133
136
  return createOutputResult<BlockLookupOutput>(
134
137
  { result: contract.result, detailed: showDetailed, aspects },
135
- { plain: renderBlockLookupOutput(ctx) },
138
+ {
139
+ plain: ({ result, detailed: isDetailed, aspects: selectedAspects }) =>
140
+ renderLookupResults({
141
+ ctx,
142
+ result,
143
+ formatters: lookupFormatters,
144
+ mapResult: (block) => ({
145
+ block,
146
+ detailed: isDetailed,
147
+ aspects: selectedAspects,
148
+ }),
149
+ }),
150
+ ink: ({ result, detailed: isDetailed, aspects: selectedAspects }) =>
151
+ createLookupView({
152
+ results: result.results,
153
+ errors: result.errors,
154
+ domain: "block",
155
+ options: createLookupOptions(isDetailed, selectedAspects),
156
+ }),
157
+ },
136
158
  );
137
159
  },
138
160
  };
@@ -149,51 +171,3 @@ function normalizeNames(names: unknown, legacyName?: unknown): string[] {
149
171
  }
150
172
  return [];
151
173
  }
152
-
153
- function renderBlockLookupOutput(
154
- ctx: PragmaContext,
155
- ): (data: BlockLookupOutput) => string {
156
- return ({ result, detailed, aspects }) => {
157
- const formatOne =
158
- ctx.globalFlags.format === "json"
159
- ? lookupFormatters.json
160
- : ctx.globalFlags.llm
161
- ? lookupFormatters.llm
162
- : lookupFormatters.plain;
163
-
164
- if (ctx.globalFlags.format === "json") {
165
- if (result.results.length === 1 && result.errors.length === 0) {
166
- const only = result.results[0];
167
- return only
168
- ? lookupFormatters.json({ block: only, detailed, aspects })
169
- : JSON.stringify({ results: [], errors: result.errors }, null, 2);
170
- }
171
-
172
- return JSON.stringify(
173
- {
174
- results: result.results.map((block) =>
175
- JSON.parse(lookupFormatters.json({ block, detailed, aspects })),
176
- ),
177
- errors: result.errors,
178
- },
179
- null,
180
- 2,
181
- );
182
- }
183
-
184
- const parts = result.results.map((block) =>
185
- formatOne({ block, detailed, aspects }),
186
- );
187
-
188
- if (result.errors.length > 0) {
189
- parts.push(
190
- [
191
- "Errors:",
192
- ...result.errors.map((error) => `- ${error.query}: ${error.message}`),
193
- ].join("\n"),
194
- );
195
- }
196
-
197
- return parts.join("\n\n");
198
- };
199
- }
@@ -1,4 +1,4 @@
1
1
  /** @module Re-exports block formatters (`lookupFormatters`, `listFormatters`). */
2
2
 
3
3
  export { default as listFormatters } from "./list.js";
4
- export { default as lookupFormatters } from "./lookup.js";
4
+ export { createLookupOptions, default as lookupFormatters } from "./lookup.js";
@@ -1,7 +1,7 @@
1
1
  import type { URI } from "@canonical/ke";
2
2
  import { describe, expect, it } from "vitest";
3
3
  import { PREFIX_MAP } from "../../shared/prefixes.js";
4
- import type { BlockSummary } from "../../shared/types.js";
4
+ import type { BlockSummary } from "../../shared/types/index.js";
5
5
  import formatters from "./list.js";
6
6
 
7
7
  const BUTTON: BlockSummary = {
@@ -1,55 +1,41 @@
1
- /**
2
- * Three-mode formatter for `pragma block list` output.
3
- *
4
- * - **plain** — styled terminal output with chalk; one line per block
5
- * showing name, tier, modifiers, and available implementations.
6
- * - **llm** — condensed Markdown consumed by LLM agents and reused
7
- * by the MCP adapter when `condensed: true`.
8
- * - **json** — structured JSON array for programmatic consumption.
9
- */
10
-
11
- import chalk from "chalk";
12
1
  import type { Formatters } from "../../shared/formatters.js";
13
- import type { BlockSummary } from "../../shared/types.js";
2
+ import { renderListPlain } from "../../shared/renderers.js";
3
+ import type { BlockSummary } from "../../shared/types/index.js";
4
+ import { blockConfig } from "../blockConfig.js";
14
5
 
6
+ /** Three-mode formatter for `pragma block list` output. */
15
7
  const formatters: Formatters<readonly BlockSummary[]> = {
16
- plain(components) {
17
- const lines: string[] = [];
18
-
19
- for (const c of components) {
20
- const tier = chalk.dim(`[${c.tier}]`);
21
- const mods =
22
- c.modifiers.length > 0 ? chalk.dim(` (${c.modifiers.join(", ")})`) : "";
23
- const impl = c.implementations
24
- .filter((i) => i.available)
25
- .map((i) => i.framework);
26
- const implStr = impl.length > 0 ? chalk.dim(` → ${impl.join(", ")}`) : "";
8
+ plain: (blocks) =>
9
+ renderListPlain(blocks, {
10
+ heading: "Blocks",
11
+ columns: blockConfig.listColumns,
12
+ }),
27
13
 
28
- lines.push(`${chalk.bold(c.name)} ${tier}${mods}${implStr}`);
29
- }
14
+ llm(blocks) {
15
+ const lines = ["## Blocks", ""];
30
16
 
31
- return lines.join("\n");
32
- },
17
+ for (const block of blocks) {
18
+ const parts = [`**${block.name}**`, `tier: ${block.tier}`];
33
19
 
34
- llm(components) {
35
- const lines: string[] = [];
20
+ if (block.modifiers.length > 0) {
21
+ parts.push(`modifiers: ${block.modifiers.join(", ")}`);
22
+ }
36
23
 
37
- lines.push("## Blocks");
38
- lines.push("");
24
+ const implementations = block.implementations
25
+ .filter((implementation) => implementation.available)
26
+ .map((implementation) => implementation.framework);
27
+ if (implementations.length > 0) {
28
+ parts.push(`implementations: ${implementations.join(", ")}`);
29
+ }
39
30
 
40
- for (const c of components) {
41
- const parts = [`**${c.name}**`, `tier: ${c.tier}`];
42
- if (c.modifiers.length > 0) {
43
- parts.push(`modifiers: ${c.modifiers.join(", ")}`);
31
+ if (block.nodeCount > 0) {
32
+ parts.push(`nodes: ${block.nodeCount}`);
44
33
  }
45
- const impl = c.implementations
46
- .filter((i) => i.available)
47
- .map((i) => i.framework);
48
- if (impl.length > 0) {
49
- parts.push(`implementations: ${impl.join(", ")}`);
34
+
35
+ if (block.tokenCount > 0) {
36
+ parts.push(`tokens: ${block.tokenCount}`);
50
37
  }
51
- if (c.nodeCount > 0) parts.push(`nodes: ${c.nodeCount}`);
52
- if (c.tokenCount > 0) parts.push(`tokens: ${c.tokenCount}`);
38
+
53
39
  lines.push(`- ${parts.join(" | ")}`);
54
40
  }
55
41
 
@@ -1,7 +1,7 @@
1
1
  import type { URI } from "@canonical/ke";
2
2
  import { describe, expect, it } from "vitest";
3
3
  import { PREFIX_MAP } from "../../shared/prefixes.js";
4
- import type { BlockDetailed } from "../../shared/types.js";
4
+ import type { BlockDetailed } from "../../shared/types/index.js";
5
5
  import type { AspectFlags } from "../types.js";
6
6
  import formatters from "./lookup.js";
7
7
 
@@ -263,7 +263,8 @@ describe("formatters.llm", () => {
263
263
  });
264
264
  expect(text).toContain("### Modifiers");
265
265
  expect(text).toContain("### Tokens");
266
- expect(text).not.toContain("### Anatomy");
266
+ expect(text).toContain("### Anatomy (DSL)");
267
+ expect(text).not.toContain("### Anatomy\n");
267
268
  });
268
269
  });
269
270