@canonical/pragma-cli 0.18.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 (200) hide show
  1. package/LICENSE +166 -0
  2. package/dist/pragma +0 -0
  3. package/package.json +31 -18
  4. package/src/constants.ts +1 -1
  5. package/src/domains/block/blockConfig.ts +47 -3
  6. package/src/domains/block/commands/list.test.ts +1 -1
  7. package/src/domains/block/commands/list.ts +27 -0
  8. package/src/domains/block/commands/lookup.ts +26 -52
  9. package/src/domains/block/formatters/index.ts +1 -1
  10. package/src/domains/block/formatters/list.test.ts +1 -1
  11. package/src/domains/block/formatters/list.ts +28 -42
  12. package/src/domains/block/formatters/lookup.test.ts +3 -2
  13. package/src/domains/block/formatters/lookup.ts +91 -296
  14. package/src/domains/block/formatters/types.ts +1 -1
  15. package/src/domains/block/operations/list.test.ts +1 -1
  16. package/src/domains/block/operations/list.ts +1 -1
  17. package/src/domains/block/operations/lookup.test.ts +29 -8
  18. package/src/domains/block/operations/lookup.ts +94 -16
  19. package/src/domains/block/orchestration/blockEmptyError.ts +1 -1
  20. package/src/domains/block/orchestration/buildBlockFilters.ts +1 -1
  21. package/src/domains/block/orchestration/enrichBlocks.ts +6 -2
  22. package/src/domains/block/orchestration/resolveBlockList.ts +1 -1
  23. package/src/domains/block/orchestration/resolveBlockLookup.ts +8 -2
  24. package/src/domains/block/types.ts +1 -1
  25. package/src/domains/config/commands/channel.ts +6 -4
  26. package/src/domains/config/commands/tier.ts +6 -4
  27. package/src/domains/config/mcp/specs.ts +18 -6
  28. package/src/domains/config/operations/validateTier.ts +1 -1
  29. package/src/domains/config/tasks/index.ts +3 -0
  30. package/src/domains/config/tasks/setChannel.ts +30 -0
  31. package/src/domains/config/tasks/setTier.ts +33 -0
  32. package/src/domains/create/commands/package.test.ts +2 -2
  33. package/src/domains/doctor/mcp/index.ts +1 -1
  34. package/src/domains/doctor/mcp/specs.ts +2 -49
  35. package/src/domains/graph/commands/inspect.test.ts +1 -1
  36. package/src/domains/graph/formatters/inspect.ts +12 -7
  37. package/src/domains/graph/operations/inspectUri.ts +4 -1
  38. package/src/domains/info/commands/upgrade.ts +6 -3
  39. package/src/domains/info/index.ts +3 -1
  40. package/src/domains/info/mcp/index.ts +2 -0
  41. package/src/domains/info/mcp/specs.ts +65 -0
  42. package/src/domains/llm/data/commandReference.ts +4 -4
  43. package/src/domains/llm/data/decisionTrees.ts +14 -12
  44. package/src/domains/llm/operations/collectContext.ts +1 -1
  45. package/src/domains/modifier/commands/list.ts +9 -0
  46. package/src/domains/modifier/commands/lookup.ts +22 -42
  47. package/src/domains/modifier/formatters/index.ts +4 -1
  48. package/src/domains/modifier/formatters/list.test.ts +1 -1
  49. package/src/domains/modifier/formatters/list.ts +13 -26
  50. package/src/domains/modifier/formatters/lookup.test.ts +1 -1
  51. package/src/domains/modifier/formatters/lookup.ts +41 -29
  52. package/src/domains/modifier/index.ts +1 -0
  53. package/src/domains/modifier/modifierConfig.ts +36 -0
  54. package/src/domains/modifier/operations/list.ts +1 -1
  55. package/src/domains/modifier/operations/lookup.ts +4 -3
  56. package/src/domains/modifier/orchestration/resolveModifierLookup.ts +1 -1
  57. package/src/domains/modifier/types.ts +1 -1
  58. package/src/domains/ontology/commands/list.test.ts +1 -1
  59. package/src/domains/ontology/commands/list.ts +18 -0
  60. package/src/domains/ontology/commands/show.test.ts +1 -1
  61. package/src/domains/ontology/formatters/list.ts +5 -3
  62. package/src/domains/ontology/formatters/show.ts +38 -13
  63. package/src/domains/ontology/helpers/queryClasses.ts +1 -1
  64. package/src/domains/ontology/helpers/queryProperties.ts +1 -1
  65. package/src/domains/ontology/operations/listOntologies.ts +1 -1
  66. package/src/domains/ontology/operations/showOntology.ts +1 -1
  67. package/src/domains/setup/helpers/completionScripts.test.ts +3 -3
  68. package/src/domains/setup/helpers/completionScripts.ts +4 -4
  69. package/src/domains/shared/ToolSpec.ts +1 -1
  70. package/src/domains/shared/context.ts +3 -2
  71. package/src/domains/shared/contracts.ts +40 -1
  72. package/src/domains/shared/filters/buildFilterConfig.ts +1 -2
  73. package/src/domains/shared/filters/buildFilters.ts +1 -1
  74. package/src/domains/shared/filters/describeFilters.ts +1 -1
  75. package/src/domains/shared/formatters.ts +47 -0
  76. package/src/domains/shared/renderers.ts +410 -0
  77. package/src/domains/shared/runtime.ts +7 -22
  78. package/src/domains/shared/types/block.ts +107 -0
  79. package/src/domains/shared/types/common.ts +33 -0
  80. package/src/domains/shared/types/graph.ts +17 -0
  81. package/src/domains/shared/types/index.ts +49 -0
  82. package/src/domains/shared/types/modifier.ts +22 -0
  83. package/src/domains/shared/types/ontology.ts +50 -0
  84. package/src/domains/shared/types/runtime.ts +21 -0
  85. package/src/domains/shared/types/standard.ts +64 -0
  86. package/src/domains/shared/types/tier.ts +15 -0
  87. package/src/domains/shared/types/token.ts +30 -0
  88. package/src/domains/standard/commands/list.ts +9 -0
  89. package/src/domains/standard/commands/lookup.ts +22 -50
  90. package/src/domains/standard/formatters/categories.test.ts +1 -1
  91. package/src/domains/standard/formatters/categories.ts +1 -1
  92. package/src/domains/standard/formatters/index.ts +4 -1
  93. package/src/domains/standard/formatters/list.test.ts +4 -1
  94. package/src/domains/standard/formatters/list.ts +112 -84
  95. package/src/domains/standard/formatters/lookup.test.ts +1 -1
  96. package/src/domains/standard/formatters/lookup.ts +85 -70
  97. package/src/domains/standard/formatters/types.ts +1 -1
  98. package/src/domains/standard/index.ts +1 -0
  99. package/src/domains/standard/operations/categories.ts +1 -1
  100. package/src/domains/standard/operations/list.ts +1 -1
  101. package/src/domains/standard/operations/lookup.ts +1 -1
  102. package/src/domains/standard/orchestration/buildStandardFilters.ts +1 -1
  103. package/src/domains/standard/orchestration/resolveStandardList.ts +4 -1
  104. package/src/domains/standard/orchestration/resolveStandardLookup.ts +1 -1
  105. package/src/domains/standard/orchestration/standardEmptyError.ts +1 -1
  106. package/src/domains/standard/standardConfig.ts +42 -0
  107. package/src/domains/standard/types.ts +1 -1
  108. package/src/domains/tier/commands/list.ts +16 -0
  109. package/src/domains/tier/formatters/list.test.ts +1 -1
  110. package/src/domains/tier/formatters/list.ts +11 -6
  111. package/src/domains/tier/operations/list.ts +1 -1
  112. package/src/domains/token/commands/list.ts +9 -0
  113. package/src/domains/token/commands/lookup.ts +22 -48
  114. package/src/domains/token/formatters/index.ts +4 -1
  115. package/src/domains/token/formatters/list.test.ts +1 -1
  116. package/src/domains/token/formatters/list.ts +15 -28
  117. package/src/domains/token/formatters/lookup.test.ts +2 -2
  118. package/src/domains/token/formatters/lookup.ts +80 -45
  119. package/src/domains/token/index.ts +1 -0
  120. package/src/domains/token/operations/list.ts +1 -1
  121. package/src/domains/token/operations/lookup.ts +1 -1
  122. package/src/domains/token/orchestration/resolveTokenLookup.ts +1 -1
  123. package/src/domains/token/tokenConfig.ts +38 -0
  124. package/src/domains/token/types.ts +1 -1
  125. package/src/index.ts +1 -1
  126. package/src/mcp/runMcpServer.test.ts +2 -2
  127. package/src/mcp/tools/index.ts +2 -0
  128. package/src/mcp/tools/registerTools.test.ts +8 -3
  129. package/src/package-manager/types.ts +1 -3
  130. package/src/pipeline/createProgram.ts +20 -1
  131. package/src/pipeline/index.ts +4 -1
  132. package/src/pipeline/parseGlobalFlags.test.ts +92 -0
  133. package/src/pipeline/parseGlobalFlags.ts +25 -0
  134. package/src/pipeline/runCli.orchestration.test.ts +1 -0
  135. package/src/pipeline/runCli.ts +11 -4
  136. package/src/pipeline/runInteractiveCommand.ts +198 -0
  137. package/src/testing/cli.ts +2 -2
  138. package/src/testing/fixtures.ts +2 -2
  139. package/src/testing/integration/boot.test.ts +2 -2
  140. package/src/testing/integration/cli-user-stories.test.ts +198 -0
  141. package/src/testing/integration/edge-cases.test.ts +263 -0
  142. package/src/testing/integration/parity.test.ts +377 -27
  143. package/src/testing/store.ts +1 -1
  144. package/src/tui/components/BulletList/BulletList.tsx +46 -0
  145. package/src/tui/components/BulletList/index.ts +2 -0
  146. package/src/tui/components/BulletList/types.ts +6 -0
  147. package/src/tui/components/Card/Card.tsx +73 -0
  148. package/src/tui/components/Card/index.ts +1 -0
  149. package/src/tui/components/Card/types.ts +12 -0
  150. package/src/tui/components/CodeBlock/CodeBlock.tsx +37 -0
  151. package/src/tui/components/CodeBlock/index.ts +2 -0
  152. package/src/tui/components/CodeBlock/types.ts +6 -0
  153. package/src/tui/components/DataRow/DataRow.tsx +80 -0
  154. package/src/tui/components/DataRow/index.ts +2 -0
  155. package/src/tui/components/DataRow/types.ts +14 -0
  156. package/src/tui/components/FieldRow/FieldRow.tsx +24 -0
  157. package/src/tui/components/FieldRow/index.ts +2 -0
  158. package/src/tui/components/FieldRow/types.ts +10 -0
  159. package/src/tui/components/HeaderRow/HeaderRow.tsx +32 -0
  160. package/src/tui/components/HeaderRow/index.ts +2 -0
  161. package/src/tui/components/HeaderRow/types.ts +8 -0
  162. package/src/tui/components/MarkdownText/MarkdownText.tsx +19 -0
  163. package/src/tui/components/MarkdownText/index.ts +2 -0
  164. package/src/tui/components/MarkdownText/types.ts +4 -0
  165. package/src/tui/components/MiniTable/MiniTable.tsx +82 -0
  166. package/src/tui/components/MiniTable/index.ts +2 -0
  167. package/src/tui/components/MiniTable/types.ts +6 -0
  168. package/src/tui/components/SectionRenderer/SectionRenderer.tsx +91 -0
  169. package/src/tui/components/SectionRenderer/index.ts +2 -0
  170. package/src/tui/components/SectionRenderer/types.ts +15 -0
  171. package/src/tui/components/TreeView/TreeView.tsx +84 -0
  172. package/src/tui/components/TreeView/index.ts +2 -0
  173. package/src/tui/components/TreeView/types.ts +6 -0
  174. package/src/tui/components/index.ts +19 -0
  175. package/src/tui/constants.ts +39 -0
  176. package/src/tui/createListView.ts +23 -0
  177. package/src/tui/createLookupView.ts +26 -0
  178. package/src/tui/helpers/computeWidths.ts +53 -0
  179. package/src/tui/helpers/fitColumns.ts +33 -0
  180. package/src/tui/helpers/formatMarkdown.ts +19 -0
  181. package/src/tui/helpers/getTerminalSize.ts +16 -0
  182. package/src/tui/helpers/index.ts +6 -0
  183. package/src/tui/helpers/syntaxColor.ts +67 -0
  184. package/src/tui/helpers/truncateText.ts +12 -0
  185. package/src/tui/hooks/index.ts +3 -0
  186. package/src/tui/hooks/types.ts +7 -0
  187. package/src/tui/hooks/useAutoExit.ts +17 -0
  188. package/src/tui/hooks/useTerminalSize.ts +19 -0
  189. package/src/tui/index.ts +15 -0
  190. package/src/tui/renderInk.tsx +18 -0
  191. package/src/tui/types.ts +12 -0
  192. package/src/tui/views/ListView/ListView.tsx +104 -0
  193. package/src/tui/views/ListView/index.ts +2 -0
  194. package/src/tui/views/ListView/types.ts +14 -0
  195. package/src/tui/views/LookupView/LookupView.tsx +244 -0
  196. package/src/tui/views/LookupView/index.ts +2 -0
  197. package/src/tui/views/LookupView/types.ts +16 -0
  198. package/src/tui/views/index.ts +4 -0
  199. package/src/domains/shared/types.test-d.ts +0 -127
  200. package/src/domains/shared/types.ts +0 -348
@@ -1,78 +1,45 @@
1
- /**
2
- * Three-mode formatter for `pragma standard lookup` output.
3
- *
4
- * - **plain** — terminal text showing name, category, description, and
5
- * optional dos/donts when detailed.
6
- * - **llm** — condensed Markdown consumed by LLM agents and reused
7
- * by the MCP adapter when `condensed: true`.
8
- * - **json** — structured JSON; omits dos/donts unless detailed.
9
- */
10
-
1
+ import type { RenderLookupOptions } from "../../shared/contracts.js";
11
2
  import type { Formatters } from "../../shared/formatters.js";
3
+ import { renderLookupLlm, renderLookupPlain } from "../../shared/renderers.js";
4
+ import type { StandardDetailed } from "../../shared/types/index.js";
5
+ import { standardConfig } from "../standardConfig.js";
12
6
  import type { StandardLookupInput } from "./types.js";
13
7
 
8
+ /** Three-mode formatter for `pragma standard lookup` output. */
14
9
  const formatters: Formatters<StandardLookupInput> = {
15
- plain({ standard, detailed }) {
16
- const lines: string[] = [];
17
- lines.push(standard.name);
18
- lines.push(`URI: ${standard.uri}`);
19
- lines.push(`Category: ${standard.category || "—"}`);
20
- lines.push(`Description: ${standard.description}`);
21
- if (standard.extends) {
22
- lines.push(`Extends: ${standard.extends}`);
23
- }
24
-
25
- if (detailed) {
26
- if (standard.dos.length > 0) {
27
- lines.push("");
28
- lines.push("Do:");
29
- for (const d of standard.dos) {
30
- lines.push(` ${d.code}`);
31
- }
32
- }
33
-
34
- if (standard.donts.length > 0) {
35
- lines.push("");
36
- lines.push("Don't:");
37
- for (const d of standard.donts) {
38
- lines.push(` ${d.code}`);
39
- }
40
- }
41
- }
42
-
43
- return lines.join("\n");
44
- },
45
-
46
- llm({ standard, detailed }) {
47
- const lines: string[] = [];
48
- lines.push(`## ${standard.name}`);
49
- lines.push(`URI: ${standard.uri}`);
50
- lines.push(`Category: ${standard.category || "—"}`);
51
- if (standard.extends) {
52
- lines.push(`Extends: ${standard.extends}`);
53
- }
54
- lines.push(standard.description);
10
+ plain: ({ standard, detailed }) =>
11
+ renderLookupPlain(standard, {
12
+ title: (entry) => entry.name,
13
+ fields: [
14
+ { label: "URI", value: (entry) => entry.uri },
15
+ { label: "Category", value: (entry) => entry.category || "—" },
16
+ { label: "Description", value: (entry) => entry.description },
17
+ { label: "Extends", value: (entry) => entry.extends },
18
+ ],
19
+ sections: detailed
20
+ ? standardConfig.lookupSections.filter(
21
+ (section) => section.key === "dos" || section.key === "donts",
22
+ )
23
+ : [],
24
+ sectionOverrides: standardSectionOverrides,
25
+ }),
55
26
 
56
- if (detailed) {
57
- if (standard.dos.length > 0) {
58
- lines.push("");
59
- lines.push("### Do");
60
- for (const d of standard.dos) {
61
- lines.push(`- ${d.code}`);
62
- }
63
- }
64
-
65
- if (standard.donts.length > 0) {
66
- lines.push("");
67
- lines.push("### Don't");
68
- for (const d of standard.donts) {
69
- lines.push(`- ${d.code}`);
70
- }
71
- }
72
- }
73
-
74
- return lines.join("\n");
75
- },
27
+ llm: ({ standard, detailed }) =>
28
+ renderLookupLlm(standard, {
29
+ title: (entry) => entry.name,
30
+ fields: [
31
+ { label: "URI", value: (entry) => entry.uri },
32
+ { label: "Category", value: (entry) => entry.category || "—" },
33
+ { label: "Description", value: (entry) => entry.description },
34
+ { label: "Extends", value: (entry) => entry.extends },
35
+ ],
36
+ sections: detailed
37
+ ? standardConfig.lookupSections.filter(
38
+ (section) => section.key === "dos" || section.key === "donts",
39
+ )
40
+ : [],
41
+ sectionOverrides: standardSectionOverrides,
42
+ }),
76
43
 
77
44
  json({ standard, detailed }) {
78
45
  if (detailed) {
@@ -84,3 +51,51 @@ const formatters: Formatters<StandardLookupInput> = {
84
51
  };
85
52
 
86
53
  export default formatters;
54
+
55
+ /**
56
+ * Build lookup rendering options for the Ink TUI view.
57
+ *
58
+ * @param detailed - whether to include dos/donts sections
59
+ * @returns Options compatible with the LookupView component.
60
+ */
61
+ export function createInkLookupOptions(
62
+ detailed: boolean,
63
+ ): RenderLookupOptions<StandardDetailed> {
64
+ return {
65
+ title: (entry) => entry.name,
66
+ fields: [
67
+ { label: "URI", value: (entry) => entry.uri },
68
+ { label: "Category", value: (entry) => entry.category || "—" },
69
+ { label: "Description", value: (entry) => entry.description },
70
+ { label: "Extends", value: (entry) => entry.extends },
71
+ ],
72
+ sections: detailed
73
+ ? standardConfig.lookupSections.filter(
74
+ (section) => section.key === "dos" || section.key === "donts",
75
+ )
76
+ : [],
77
+ };
78
+ }
79
+
80
+ const standardSectionOverrides = {
81
+ dos: {
82
+ plain: (entry: StandardLookupInput["standard"]) =>
83
+ entry.dos.length > 0
84
+ ? entry.dos.map((item) => ` ${item.code}`).join("\n")
85
+ : null,
86
+ llm: (entry: StandardLookupInput["standard"]) =>
87
+ entry.dos.length > 0
88
+ ? entry.dos.map((item) => `- ${item.code}`).join("\n")
89
+ : null,
90
+ },
91
+ donts: {
92
+ plain: (entry: StandardLookupInput["standard"]) =>
93
+ entry.donts.length > 0
94
+ ? entry.donts.map((item) => ` ${item.code}`).join("\n")
95
+ : null,
96
+ llm: (entry: StandardLookupInput["standard"]) =>
97
+ entry.donts.length > 0
98
+ ? entry.donts.map((item) => `- ${item.code}`).join("\n")
99
+ : null,
100
+ },
101
+ };
@@ -9,7 +9,7 @@ import type {
9
9
  Disclosure,
10
10
  StandardDetailed,
11
11
  StandardSummary,
12
- } from "../../shared/types.js";
12
+ } from "../../shared/types/index.js";
13
13
 
14
14
  /** Input payload for the standard-lookup formatter, pairing data with a detail flag. */
15
15
  export interface StandardLookupInput {
@@ -30,3 +30,4 @@ export {
30
30
  resolveStandardLookup,
31
31
  standardEmptyError,
32
32
  } from "./orchestration/index.js";
33
+ export { standardConfig } from "./standardConfig.js";
@@ -9,7 +9,7 @@
9
9
  import type { Store } from "@canonical/ke";
10
10
  import { buildQuery } from "../../shared/buildQuery.js";
11
11
  import { P } from "../../shared/prefixes.js";
12
- import type { CategorySummary } from "../../shared/types.js";
12
+ import type { CategorySummary } from "../../shared/types/index.js";
13
13
 
14
14
  export default async function listCategories(
15
15
  store: Store,
@@ -14,7 +14,7 @@ import { P } from "../../shared/prefixes.js";
14
14
  import type {
15
15
  StandardListFilters,
16
16
  StandardSummary,
17
- } from "../../shared/types.js";
17
+ } from "../../shared/types/index.js";
18
18
 
19
19
  export default async function listStandards(
20
20
  store: Store,
@@ -18,7 +18,7 @@ import resolveUri from "../../graph/helpers/resolveUri.js";
18
18
  import { buildQuery } from "../../shared/buildQuery.js";
19
19
  import compactUri from "../../shared/compactUri.js";
20
20
  import { P } from "../../shared/prefixes.js";
21
- import type { CodeBlock, StandardDetailed } from "../../shared/types.js";
21
+ import type { CodeBlock, StandardDetailed } from "../../shared/types/index.js";
22
22
 
23
23
  export default async function lookupStandard(
24
24
  store: Store,
@@ -1,4 +1,4 @@
1
- import type { StandardListFilters } from "../../shared/types.js";
1
+ import type { StandardListFilters } from "../../shared/types/index.js";
2
2
 
3
3
  export default function buildStandardFilters(params: {
4
4
  category?: string;
@@ -1,6 +1,9 @@
1
1
  import type { ListParams } from "../../shared/contracts.js";
2
2
  import type { PragmaRuntime } from "../../shared/runtime.js";
3
- import type { Disclosure, StandardListFilters } from "../../shared/types.js";
3
+ import type {
4
+ Disclosure,
5
+ StandardListFilters,
6
+ } from "../../shared/types/index.js";
4
7
  import { listStandards, lookupStandard } from "../operations/index.js";
5
8
  import type { StandardListResolution } from "../types.js";
6
9
  import buildStandardFilters from "./buildStandardFilters.js";
@@ -1,7 +1,7 @@
1
1
  import type { LookupContract, LookupResult } from "../../shared/contracts.js";
2
2
  import lookupMany from "../../shared/lookupMany.js";
3
3
  import type { PragmaRuntime } from "../../shared/runtime.js";
4
- import type { StandardDetailed } from "../../shared/types.js";
4
+ import type { StandardDetailed } from "../../shared/types/index.js";
5
5
  import { lookupStandard } from "../operations/index.js";
6
6
 
7
7
  export default async function resolveStandardLookup(
@@ -1,5 +1,5 @@
1
1
  import { PragmaError } from "#error";
2
- import type { StandardListFilters } from "../../shared/types.js";
2
+ import type { StandardListFilters } from "../../shared/types/index.js";
3
3
 
4
4
  export default function standardEmptyError(
5
5
  filters: StandardListFilters,
@@ -0,0 +1,42 @@
1
+ import type { EntityDisplayConfig } from "../shared/contracts.js";
2
+ import { P } from "../shared/prefixes.js";
3
+ import type {
4
+ FilterConfig,
5
+ StandardDetailed,
6
+ StandardDigest,
7
+ StandardSummary,
8
+ } from "../shared/types/index.js";
9
+
10
+ /** Display-contract configuration for code-standard entities. */
11
+ export const standardConfig: EntityDisplayConfig<
12
+ StandardSummary,
13
+ StandardDigest,
14
+ StandardDetailed
15
+ > = {
16
+ domain: "standard",
17
+ entityName: "standard",
18
+ rdfTypes: [`${P.cs}CodeStandard`],
19
+ listColumns: [
20
+ { key: "uri", label: "IRI" },
21
+ { key: "name", label: "Name" },
22
+ { key: "category", label: "Category" },
23
+ { key: "description", label: "Description" },
24
+ ],
25
+ digestColumns: [{ key: "extends", label: "Extends", showWhenEmpty: false }],
26
+ lookupSections: [
27
+ { key: "description", heading: "Description", kind: "field" },
28
+ { key: "extends", heading: "Extends", kind: "field", showWhenEmpty: false },
29
+ { key: "dos", heading: "Do", kind: "table", showWhenEmpty: false },
30
+ { key: "donts", heading: "Don't", kind: "table", showWhenEmpty: false },
31
+ ],
32
+ emptyRecovery: (_filters: FilterConfig) => ({
33
+ message: "List available standards.",
34
+ cli: "pragma standard list",
35
+ mcp: { tool: "standard_list" },
36
+ }),
37
+ notFoundRecovery: (_query: string) => ({
38
+ message: "List available standards.",
39
+ cli: "pragma standard list",
40
+ mcp: { tool: "standard_list" },
41
+ }),
42
+ };
@@ -4,7 +4,7 @@ import type {
4
4
  StandardDetailed,
5
5
  StandardListFilters,
6
6
  StandardSummary,
7
- } from "../shared/types.js";
7
+ } from "../shared/types/index.js";
8
8
 
9
9
  export interface StandardListResolution {
10
10
  readonly params: ListParams & StandardListFilters;
@@ -10,11 +10,20 @@ import {
10
10
  createOutputResult,
11
11
  } from "@canonical/cli-core";
12
12
  import { PragmaError } from "#error";
13
+ import { createListView } from "#tui";
13
14
  import type { PragmaContext } from "../../shared/context.js";
15
+ import type { ColumnDef } from "../../shared/contracts.js";
14
16
  import { selectFormatter } from "../../shared/formatters.js";
17
+ import type { TierEntry } from "../../shared/types/tier.js";
15
18
  import { listFormatters } from "../formatters/index.js";
16
19
  import { listTiers } from "../operations/index.js";
17
20
 
21
+ const tierListColumns: readonly ColumnDef<TierEntry>[] = [
22
+ { key: "uri", label: "IRI" },
23
+ { key: "path", label: "Path" },
24
+ { key: "parent", label: "Parent" },
25
+ ];
26
+
18
27
  export default function listCommand(ctx: PragmaContext): CommandDefinition {
19
28
  return {
20
29
  path: ["tier", "list"],
@@ -37,6 +46,13 @@ export default function listCommand(ctx: PragmaContext): CommandDefinition {
37
46
 
38
47
  return createOutputResult(tiers, {
39
48
  plain: selectFormatter(ctx, listFormatters),
49
+ ink: (data) =>
50
+ createListView({
51
+ heading: "Tiers",
52
+ domain: "tier",
53
+ items: data,
54
+ columns: tierListColumns,
55
+ }),
40
56
  });
41
57
  },
42
58
  };
@@ -1,6 +1,6 @@
1
1
  import type { URI } from "@canonical/ke";
2
2
  import { describe, expect, it } from "vitest";
3
- import type { TierEntry } from "../../shared/types.js";
3
+ import type { TierEntry } from "../../shared/types/index.js";
4
4
  import formatters from "./list.js";
5
5
 
6
6
  const TIERS: TierEntry[] = [
@@ -1,3 +1,8 @@
1
+ import compactUri from "../../shared/compactUri.js";
2
+ import type { Formatters } from "../../shared/formatters.js";
3
+ import { PREFIX_MAP } from "../../shared/prefixes.js";
4
+ import type { TierEntry } from "../../shared/types/index.js";
5
+
1
6
  /**
2
7
  * Three-mode formatter for `pragma tier list` output.
3
8
  *
@@ -7,17 +12,15 @@
7
12
  * by the MCP adapter when `condensed: true`.
8
13
  * - **json** — structured JSON array for programmatic consumption.
9
14
  */
10
-
11
- import type { Formatters } from "../../shared/formatters.js";
12
- import type { TierEntry } from "../../shared/types.js";
13
-
14
15
  const formatters: Formatters<TierEntry[]> = {
15
16
  plain: (tiers) => {
16
17
  const lines: string[] = [];
17
18
  for (const t of tiers) {
18
19
  const indent = " ".repeat(t.depth);
19
20
  const parent = t.parent ? ` (parent: ${t.parent})` : "";
20
- lines.push(`${indent}${t.path}${parent}`);
21
+ lines.push(
22
+ `${compactUri(t.uri, PREFIX_MAP)} ${indent}${t.path}${parent}`,
23
+ );
21
24
  }
22
25
  return lines.join("\n");
23
26
  },
@@ -29,7 +32,9 @@ const formatters: Formatters<TierEntry[]> = {
29
32
  for (const t of tiers) {
30
33
  const indent = " ".repeat(t.depth);
31
34
  const parent = t.parent ? ` (parent: ${t.parent})` : "";
32
- lines.push(`${indent}- **${t.path}**${parent}`);
35
+ lines.push(
36
+ `${indent}- **${t.path}** \`${compactUri(t.uri, PREFIX_MAP)}\`${parent}`,
37
+ );
33
38
  }
34
39
  return lines.join("\n");
35
40
  },
@@ -9,7 +9,7 @@
9
9
  import type { Store, URI } from "@canonical/ke";
10
10
  import { buildQuery } from "../../shared/buildQuery.js";
11
11
  import { P } from "../../shared/prefixes.js";
12
- import type { TierEntry } from "../../shared/types.js";
12
+ import type { TierEntry } from "../../shared/types/index.js";
13
13
 
14
14
  export default async function listTiers(store: Store): Promise<TierEntry[]> {
15
15
  const result = await store.query(
@@ -9,10 +9,12 @@ import {
9
9
  type CommandDefinition,
10
10
  createOutputResult,
11
11
  } from "@canonical/cli-core";
12
+ import { createListView } from "#tui";
12
13
  import type { PragmaContext } from "../../shared/context.js";
13
14
  import { selectFormatter } from "../../shared/formatters.js";
14
15
  import { listFormatters } from "../formatters/index.js";
15
16
  import { resolveTokenList } from "../orchestration/index.js";
17
+ import { tokenConfig } from "../tokenConfig.js";
16
18
 
17
19
  export default function listCommand(ctx: PragmaContext): CommandDefinition {
18
20
  return {
@@ -39,6 +41,13 @@ export default function listCommand(ctx: PragmaContext): CommandDefinition {
39
41
 
40
42
  return createOutputResult([...resolution.items], {
41
43
  plain: selectFormatter(ctx, listFormatters),
44
+ ink: (data) =>
45
+ createListView({
46
+ heading: "Tokens",
47
+ domain: "token",
48
+ items: data,
49
+ columns: tokenConfig.listColumns,
50
+ }),
42
51
  });
43
52
  },
44
53
  };
@@ -9,9 +9,14 @@ import {
9
9
  type CommandDefinition,
10
10
  createOutputResult,
11
11
  } from "@canonical/cli-core";
12
+ import { createLookupView } from "#tui";
12
13
  import type { PragmaContext } from "../../shared/context.js";
13
14
  import type { LookupResult } from "../../shared/contracts.js";
14
- import { createLookupFormatters } from "../formatters/index.js";
15
+ import { renderLookupResults } from "../../shared/formatters.js";
16
+ import {
17
+ createLookupFormatters,
18
+ createTokenInkLookupOptions,
19
+ } from "../formatters/index.js";
15
20
  import type { lookupToken } from "../operations/index.js";
16
21
  import { resolveTokenLookup } from "../orchestration/index.js";
17
22
 
@@ -56,7 +61,22 @@ export default function buildLookupCommand(
56
61
 
57
62
  return createOutputResult<TokenLookupOutput>(
58
63
  { result: contract.result, detailed },
59
- { plain: renderTokenLookupOutput(ctx) },
64
+ {
65
+ plain: ({ result, detailed: isDetailed }) =>
66
+ renderLookupResults({
67
+ ctx,
68
+ result,
69
+ formatters: createLookupFormatters({ detailed: isDetailed }),
70
+ mapResult: (token) => token,
71
+ }),
72
+ ink: ({ result, detailed: isDetailed }) =>
73
+ createLookupView({
74
+ results: result.results,
75
+ errors: result.errors,
76
+ domain: "token",
77
+ options: createTokenInkLookupOptions({ detailed: isDetailed }),
78
+ }),
79
+ },
60
80
  );
61
81
  },
62
82
  };
@@ -73,49 +93,3 @@ function normalizeNames(names: unknown, legacyName?: unknown): string[] {
73
93
  }
74
94
  return [];
75
95
  }
76
-
77
- function renderTokenLookupOutput(
78
- ctx: PragmaContext,
79
- ): (data: TokenLookupOutput) => string {
80
- return ({ result, detailed }) => {
81
- const formatters = createLookupFormatters({ detailed });
82
- const formatOne =
83
- ctx.globalFlags.format === "json"
84
- ? formatters.json
85
- : ctx.globalFlags.llm
86
- ? formatters.llm
87
- : formatters.plain;
88
-
89
- if (ctx.globalFlags.format === "json") {
90
- if (result.results.length === 1 && result.errors.length === 0) {
91
- const only = result.results[0];
92
- return only
93
- ? formatters.json(only)
94
- : JSON.stringify({ results: [], errors: result.errors }, null, 2);
95
- }
96
-
97
- return JSON.stringify(
98
- {
99
- results: result.results.map((token) =>
100
- JSON.parse(formatters.json(token)),
101
- ),
102
- errors: result.errors,
103
- },
104
- null,
105
- 2,
106
- );
107
- }
108
-
109
- const parts = result.results.map((token) => formatOne(token));
110
- if (result.errors.length > 0) {
111
- parts.push(
112
- [
113
- "Errors:",
114
- ...result.errors.map((error) => `- ${error.query}: ${error.message}`),
115
- ].join("\n"),
116
- );
117
- }
118
-
119
- return parts.join("\n\n");
120
- };
121
- }
@@ -1,4 +1,7 @@
1
1
  /** @module Re-exports token formatters (`createLookupFormatters`, `listFormatters`). */
2
2
 
3
3
  export { default as listFormatters } from "./list.js";
4
- export { createLookupFormatters } from "./lookup.js";
4
+ export {
5
+ createInkLookupOptions as createTokenInkLookupOptions,
6
+ default as createLookupFormatters,
7
+ } from "./lookup.js";
@@ -1,6 +1,6 @@
1
1
  import type { URI } from "@canonical/ke";
2
2
  import { describe, expect, it } from "vitest";
3
- import type { TokenSummary } from "../../shared/types.js";
3
+ import type { TokenSummary } from "../../shared/types/index.js";
4
4
  import formatters from "./list.js";
5
5
 
6
6
  const TOKENS: TokenSummary[] = [
@@ -1,35 +1,22 @@
1
- /**
2
- * Three-mode formatter for `pragma token list` output.
3
- *
4
- * - **plain** — one line per token showing name and optional category.
5
- * - **llm** — condensed Markdown consumed by LLM agents and reused
6
- * by the MCP adapter when `condensed: true`.
7
- * - **json** — structured JSON array for programmatic consumption.
8
- */
9
-
10
1
  import type { Formatters } from "../../shared/formatters.js";
11
- import type { TokenSummary } from "../../shared/types.js";
2
+ import { renderListLlm } from "../../shared/renderers.js";
3
+ import type { TokenSummary } from "../../shared/types/index.js";
4
+ import { tokenConfig } from "../tokenConfig.js";
12
5
 
6
+ /** Three-mode formatter for `pragma token list` output. */
13
7
  const formatters: Formatters<TokenSummary[]> = {
14
- plain: (tokens) => {
15
- const lines: string[] = [];
16
- for (const t of tokens) {
17
- const cat = t.category ? ` [${t.category}]` : "";
18
- lines.push(`${t.name}${cat}`);
19
- }
20
- return lines.join("\n");
21
- },
8
+ plain: (tokens) =>
9
+ tokens
10
+ .map((token) =>
11
+ token.category ? `${token.name} [${token.category}]` : token.name,
12
+ )
13
+ .join("\n"),
22
14
 
23
- llm: (tokens) => {
24
- const lines: string[] = [];
25
- lines.push("## Design Tokens");
26
- lines.push("");
27
- for (const t of tokens) {
28
- const cat = t.category ? ` [${t.category}]` : "";
29
- lines.push(`- **${t.name}**${cat}`);
30
- }
31
- return lines.join("\n");
32
- },
15
+ llm: (tokens) =>
16
+ renderListLlm(tokens, {
17
+ heading: "Design Tokens",
18
+ columns: tokenConfig.listColumns,
19
+ }),
33
20
 
34
21
  json: (tokens) => JSON.stringify(tokens, null, 2),
35
22
  };
@@ -1,7 +1,7 @@
1
1
  import type { URI } from "@canonical/ke";
2
2
  import { describe, expect, it } from "vitest";
3
- import type { TokenDetailed } from "../../shared/types.js";
4
- import { createLookupFormatters } from "./lookup.js";
3
+ import type { TokenDetailed } from "../../shared/types/index.js";
4
+ import createLookupFormatters from "./lookup.js";
5
5
 
6
6
  const DETAILED: TokenDetailed = {
7
7
  uri: "http://example.com/t1" as URI,