@canonical/pragma-cli 0.30.0 → 0.31.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 (254) hide show
  1. package/README.md +64 -35
  2. package/dist/pragma +0 -0
  3. package/package.json +15 -13
  4. package/src/completions/constants.ts +7 -0
  5. package/src/completions/handleQuery.test.ts +32 -0
  6. package/src/completions/handleQuery.ts +20 -1
  7. package/src/completions/queryCompletions.test.ts +5 -0
  8. package/src/completions/queryCompletions.ts +17 -3
  9. package/src/completions/querySocket.test.ts +31 -0
  10. package/src/completions/querySocket.ts +36 -9
  11. package/src/config/parseConfigValues.ts +2 -0
  12. package/src/config/readConfigLayers.test.ts +2 -0
  13. package/src/config/readConfigLayers.ts +3 -0
  14. package/src/config/types.ts +7 -0
  15. package/src/constants.ts +3 -1
  16. package/src/domains/block/commands/sample.ts +2 -1
  17. package/src/domains/block/formatters/list.test.ts +3 -3
  18. package/src/domains/block/formatters/lookup.test.ts +5 -5
  19. package/src/domains/block/orchestration/enrichBlocks.ts +6 -3
  20. package/src/domains/block/stories.ts +9 -3
  21. package/src/domains/config/commands/channel.test.ts +16 -0
  22. package/src/domains/config/commands/channel.ts +14 -1
  23. package/src/domains/config/commands/framework.test.ts +14 -0
  24. package/src/domains/config/commands/framework.ts +13 -1
  25. package/src/domains/config/commands/tier.test.ts +7 -0
  26. package/src/domains/config/commands/tier.ts +14 -1
  27. package/src/domains/config/operations/validateTier.test.ts +9 -0
  28. package/src/domains/config/operations/validateTier.ts +10 -2
  29. package/src/domains/create/generatorPack/bundled.ts +49 -0
  30. package/src/domains/create/generatorPack/compileGeneratorPack.test.ts +159 -0
  31. package/src/domains/create/generatorPack/compileGeneratorPack.ts +312 -0
  32. package/src/domains/create/index.ts +13 -7
  33. package/src/domains/create/mcp/specs.ts +6 -161
  34. package/src/domains/create/renderGeneratorUi.test.ts +103 -0
  35. package/src/domains/create/renderGeneratorUi.ts +65 -0
  36. package/src/domains/doctor/formatters/doctor.test.ts +50 -2
  37. package/src/domains/doctor/formatters/doctor.ts +90 -38
  38. package/src/domains/doctor/operations/checks/checkMcpCommands.ts +9 -6
  39. package/src/domains/doctor/operations/checks/checkPackageRefs.ts +30 -12
  40. package/src/domains/doctor/operations/checks.test.ts +6 -4
  41. package/src/domains/doctor/operations/types.ts +23 -1
  42. package/src/domains/graph/commands/inspect.test.ts +2 -2
  43. package/src/domains/graph/commands/query.test.ts +5 -3
  44. package/src/domains/graph/formatters/inspect.ts +7 -7
  45. package/src/domains/graph/formatters/query.test.ts +87 -0
  46. package/src/domains/graph/formatters/query.ts +42 -5
  47. package/src/domains/graph/operations/inspectUri.test.ts +5 -5
  48. package/src/domains/graphql/commands/serve.test.ts +12 -6
  49. package/src/domains/graphql/commands/serve.ts +16 -6
  50. package/src/domains/graphql/helpers/parsePrefixes.test.ts +3 -3
  51. package/src/domains/graphql/helpers/parsePrefixes.ts +3 -3
  52. package/src/domains/graphql/helpers/resolveSourceFiles.test.ts +9 -0
  53. package/src/domains/graphql/helpers/resolveSourceFiles.ts +24 -3
  54. package/src/domains/graphql/operations/compileSchema.test.ts +2 -2
  55. package/src/domains/graphql/operations/createSchemaServer.test.ts +2 -2
  56. package/src/domains/graphql/operations/ensureSchemaArtifact.test.ts +167 -0
  57. package/src/domains/graphql/operations/ensureSchemaArtifact.ts +178 -0
  58. package/src/domains/graphql/operations/index.ts +5 -0
  59. package/src/domains/info/formatters/upgrade.test.ts +7 -4
  60. package/src/domains/info/formatters/upgrade.ts +3 -1
  61. package/src/domains/info/operations/collectEntityCounts.test.ts +156 -0
  62. package/src/domains/info/operations/collectEntityCounts.ts +123 -0
  63. package/src/domains/info/operations/index.ts +1 -0
  64. package/src/domains/info/types.ts +13 -0
  65. package/src/domains/llm/capabilities.test.ts +23 -3
  66. package/src/domains/llm/commands/capabilities.ts +12 -3
  67. package/src/domains/llm/commands/llm.ts +5 -1
  68. package/src/domains/llm/data/commandReference.ts +20 -11
  69. package/src/domains/llm/data/decisionTrees.ts +10 -5
  70. package/src/domains/llm/data/toolCatalog.ts +49 -18
  71. package/src/domains/llm/formatters/orientation.ts +5 -1
  72. package/src/domains/llm/llmCommand.test.ts +11 -3
  73. package/src/domains/llm/mcp/specs.ts +3 -4
  74. package/src/domains/llm/operations/collectContext.test.ts +64 -0
  75. package/src/domains/llm/operations/collectContext.ts +7 -17
  76. package/src/domains/modifier/commands/sample.ts +2 -1
  77. package/src/domains/modifier/operations/lookup.ts +5 -3
  78. package/src/domains/modifier/stories.ts +9 -0
  79. package/src/domains/ontology/commands/list.test.ts +5 -3
  80. package/src/domains/ontology/commands/show.test.ts +85 -9
  81. package/src/domains/ontology/formatters/index.ts +1 -0
  82. package/src/domains/ontology/formatters/list.ts +37 -12
  83. package/src/domains/ontology/formatters/show.ts +358 -67
  84. package/src/domains/ontology/helpers/buildClassTree.ts +89 -0
  85. package/src/domains/ontology/helpers/completeClassNames.ts +43 -0
  86. package/src/domains/ontology/helpers/expandOntologyIris.ts +79 -0
  87. package/src/domains/ontology/helpers/index.ts +14 -0
  88. package/src/domains/ontology/helpers/queryClasses.ts +32 -16
  89. package/src/domains/ontology/helpers/queryProperties.ts +39 -6
  90. package/src/domains/ontology/helpers/queryTboxFacts.ts +160 -0
  91. package/src/domains/ontology/operations/listOntologies.test.ts +80 -3
  92. package/src/domains/ontology/operations/listOntologies.ts +126 -30
  93. package/src/domains/ontology/operations/showOntology.test.ts +131 -12
  94. package/src/domains/ontology/operations/showOntology.ts +289 -7
  95. package/src/domains/ontology/operations/showOntologyRaw.test.ts +4 -2
  96. package/src/domains/ontology/stories.ts +53 -8
  97. package/src/domains/refs/operations/updateRefs.ts +0 -1
  98. package/src/domains/setup/commands/index.ts +1 -0
  99. package/src/domains/setup/commands/setup.ts +70 -0
  100. package/src/domains/setup/index.ts +7 -3
  101. package/src/domains/setup/operations/setupLsp.test.ts +3 -2
  102. package/src/domains/setup/operations/setupLsp.ts +7 -2
  103. package/src/domains/shared/bootStore.bareCore.test.ts +63 -0
  104. package/src/domains/shared/bootStore.test.ts +82 -0
  105. package/src/domains/shared/bootStore.ts +56 -20
  106. package/src/domains/shared/emptyErrorRecovery.test.ts +23 -26
  107. package/src/domains/shared/extractLocalName.test.ts +3 -3
  108. package/src/domains/shared/formatters.ts +23 -2
  109. package/src/domains/shared/listTiers.ts +40 -0
  110. package/src/domains/shared/loaders/bundledLoader.ts +48 -0
  111. package/src/domains/shared/loaders/gitLoader.ts +1 -2
  112. package/src/domains/shared/loaders/localLoader.ts +2 -18
  113. package/src/domains/shared/loaders/readPackageDir.test.ts +58 -0
  114. package/src/domains/shared/loaders/readPackageDir.ts +46 -8
  115. package/src/domains/shared/lookupMany.test.ts +15 -0
  116. package/src/domains/shared/lookupMany.ts +22 -6
  117. package/src/domains/shared/namespaces.ts +13 -5
  118. package/src/domains/shared/parseSampleCount.test.ts +47 -0
  119. package/src/domains/shared/parseSampleCount.ts +45 -0
  120. package/src/domains/shared/prefixes.test.ts +211 -0
  121. package/src/domains/shared/prefixes.ts +182 -15
  122. package/src/domains/shared/renderers.ts +5 -5
  123. package/src/domains/shared/resolveLookupExitCode.test.ts +48 -0
  124. package/src/domains/shared/resolveLookupExitCode.ts +42 -0
  125. package/src/domains/shared/semanticPackage.test.ts +89 -0
  126. package/src/domains/shared/semanticPackage.ts +17 -2
  127. package/src/domains/shared/stories/compileLookupCommand.ts +3 -1
  128. package/src/domains/shared/stories/compileLookupTool.ts +1 -1
  129. package/src/domains/shared/stories/pack/applyPackFilters.test.ts +49 -0
  130. package/src/domains/shared/stories/pack/applyPackFilters.ts +46 -11
  131. package/src/domains/shared/stories/pack/applyPackSearch.test.ts +57 -0
  132. package/src/domains/shared/stories/pack/applyPackSearch.ts +41 -0
  133. package/src/domains/shared/stories/pack/buildLookupQuery.test.ts +30 -0
  134. package/src/domains/shared/stories/pack/buildLookupQuery.ts +75 -1
  135. package/src/domains/shared/stories/pack/bundled/index.ts +23 -0
  136. package/src/domains/shared/stories/pack/bundled/standardPack.ts +164 -0
  137. package/src/domains/shared/stories/pack/bundled/tierPack.ts +50 -0
  138. package/src/domains/shared/stories/pack/collectPackStories.test.ts +305 -7
  139. package/src/domains/shared/stories/pack/collectPackStories.ts +90 -8
  140. package/src/domains/shared/stories/pack/compilePackCommands.ts +17 -7
  141. package/src/domains/shared/stories/pack/compilePackStories.test.ts +607 -2
  142. package/src/domains/shared/stories/pack/compilePackStories.ts +544 -73
  143. package/src/domains/shared/stories/pack/compilePackToolSpecs.ts +20 -8
  144. package/src/domains/shared/stories/pack/index.ts +14 -0
  145. package/src/domains/shared/stories/pack/reservedVerbs.test.ts +213 -0
  146. package/src/domains/shared/stories/pack/reservedVerbs.ts +170 -0
  147. package/src/domains/shared/stories/pack/standardParity.test.ts +293 -220
  148. package/src/domains/shared/stories/pack/types.ts +123 -3
  149. package/src/domains/shared/stories/pack/validateStoryPackDefinition.test.ts +502 -0
  150. package/src/domains/shared/stories/pack/validateStoryPackDefinition.ts +475 -24
  151. package/src/domains/shared/stories/types.ts +9 -1
  152. package/src/domains/shared/types/index.ts +5 -9
  153. package/src/domains/shared/types/ontology.ts +119 -24
  154. package/src/domains/shared/types/standard.ts +9 -52
  155. package/src/domains/token/commands/lookup.test.ts +8 -0
  156. package/src/domains/token/commands/lookup.ts +12 -0
  157. package/src/domains/token/commands/sample.ts +2 -1
  158. package/src/domains/token/featureFlag.ts +17 -0
  159. package/src/domains/token/index.ts +5 -0
  160. package/src/domains/token/mcp/specs.ts +13 -1
  161. package/src/domains/trace/commands/resolveTraceLimit.test.ts +31 -0
  162. package/src/domains/trace/commands/show.ts +30 -4
  163. package/src/index.ts +1 -13
  164. package/src/mcp/registerResources.test.ts +2 -2
  165. package/src/mcp/resources/pickPrimaryType.test.ts +5 -5
  166. package/src/mcp/tools/index.ts +18 -10
  167. package/src/mcp/tools/registerTools.test.ts +106 -30
  168. package/src/pipeline/collectCommands.test.ts +151 -1
  169. package/src/pipeline/collectCommands.ts +34 -19
  170. package/src/pipeline/createProgram.test.ts +5 -1
  171. package/src/pipeline/createProgram.ts +2 -2
  172. package/src/pipeline/firstRun.test.ts +80 -0
  173. package/src/pipeline/firstRun.ts +99 -0
  174. package/src/pipeline/parseGlobalFlags.test.ts +102 -1
  175. package/src/pipeline/parseGlobalFlags.ts +98 -9
  176. package/src/pipeline/resolveCommandKind.test.ts +12 -0
  177. package/src/pipeline/resolveCommandKind.ts +4 -0
  178. package/src/pipeline/rootHelp.test.ts +87 -0
  179. package/src/pipeline/rootHelp.ts +265 -0
  180. package/src/pipeline/runCli.orchestration.test.ts +28 -12
  181. package/src/pipeline/runCli.test.ts +17 -4
  182. package/src/pipeline/runCli.ts +162 -19
  183. package/src/testing/cli.ts +30 -2
  184. package/src/testing/dsFixtures.ts +21 -4
  185. package/src/testing/index.ts +1 -4
  186. package/src/testing/integration/__snapshots__/executor-golden.test.ts.snap +4 -4
  187. package/src/testing/integration/cli-user-stories.test.ts +63 -0
  188. package/src/testing/integration/cross-binary-byte-equality.test.ts +2 -2
  189. package/src/testing/integration/edge-cases.test.ts +62 -50
  190. package/src/testing/integration/executor-execution.test.ts +6 -4
  191. package/src/testing/integration/executor-golden.test.ts +2 -2
  192. package/src/testing/integration/mcp-surface.test.ts +40 -15
  193. package/src/testing/integration/parity.test.ts +119 -70
  194. package/src/testing/setupXdgIsolation.ts +16 -5
  195. package/src/testing/standardParityFixtures.ts +26 -83
  196. package/src/testing/store.ts +4 -4
  197. package/src/domains/create/commands/component.test.ts +0 -166
  198. package/src/domains/create/commands/component.ts +0 -123
  199. package/src/domains/create/commands/index.ts +0 -3
  200. package/src/domains/create/commands/package.test.ts +0 -35
  201. package/src/domains/create/commands/package.ts +0 -21
  202. package/src/domains/create/generators.ts +0 -8
  203. package/src/domains/standard/commands/categories.test.ts +0 -70
  204. package/src/domains/standard/commands/categories.ts +0 -48
  205. package/src/domains/standard/commands/index.ts +0 -6
  206. package/src/domains/standard/commands/list.test.ts +0 -105
  207. package/src/domains/standard/commands/list.ts +0 -11
  208. package/src/domains/standard/commands/lookup.test.ts +0 -135
  209. package/src/domains/standard/commands/lookup.ts +0 -14
  210. package/src/domains/standard/commands/sample.ts +0 -57
  211. package/src/domains/standard/formatters/categories.test.ts +0 -44
  212. package/src/domains/standard/formatters/categories.ts +0 -38
  213. package/src/domains/standard/formatters/index.ts +0 -10
  214. package/src/domains/standard/formatters/list.test.ts +0 -169
  215. package/src/domains/standard/formatters/list.ts +0 -184
  216. package/src/domains/standard/formatters/lookup.test.ts +0 -95
  217. package/src/domains/standard/formatters/lookup.ts +0 -101
  218. package/src/domains/standard/formatters/sample.ts +0 -15
  219. package/src/domains/standard/formatters/types.ts +0 -31
  220. package/src/domains/standard/index.ts +0 -40
  221. package/src/domains/standard/mcp/index.ts +0 -2
  222. package/src/domains/standard/mcp/specs.ts +0 -89
  223. package/src/domains/standard/operations/categories.test.ts +0 -61
  224. package/src/domains/standard/operations/categories.ts +0 -38
  225. package/src/domains/standard/operations/index.ts +0 -6
  226. package/src/domains/standard/operations/list.test.ts +0 -75
  227. package/src/domains/standard/operations/list.ts +0 -64
  228. package/src/domains/standard/operations/lookup.test.ts +0 -58
  229. package/src/domains/standard/operations/lookup.ts +0 -151
  230. package/src/domains/standard/operations/sample.ts +0 -35
  231. package/src/domains/standard/orchestration/buildStandardFilters.ts +0 -11
  232. package/src/domains/standard/orchestration/index.ts +0 -4
  233. package/src/domains/standard/orchestration/resolveStandardList.ts +0 -45
  234. package/src/domains/standard/orchestration/resolveStandardLookup.ts +0 -33
  235. package/src/domains/standard/orchestration/standardEmptyError.test.ts +0 -33
  236. package/src/domains/standard/orchestration/standardEmptyError.ts +0 -29
  237. package/src/domains/standard/standardConfig.ts +0 -42
  238. package/src/domains/standard/stories.test.ts +0 -24
  239. package/src/domains/standard/stories.ts +0 -151
  240. package/src/domains/standard/types.ts +0 -15
  241. package/src/domains/tier/commands/index.ts +0 -3
  242. package/src/domains/tier/commands/list.test.ts +0 -67
  243. package/src/domains/tier/commands/list.ts +0 -9
  244. package/src/domains/tier/formatters/index.ts +0 -3
  245. package/src/domains/tier/formatters/list.test.ts +0 -33
  246. package/src/domains/tier/formatters/list.ts +0 -45
  247. package/src/domains/tier/index.ts +0 -17
  248. package/src/domains/tier/mcp/index.ts +0 -2
  249. package/src/domains/tier/mcp/specs.ts +0 -12
  250. package/src/domains/tier/operations/index.ts +0 -3
  251. package/src/domains/tier/operations/list.test.ts +0 -32
  252. package/src/domains/tier/operations/list.ts +0 -33
  253. package/src/domains/tier/stories.test.ts +0 -22
  254. package/src/domains/tier/stories.ts +0 -52
@@ -1,33 +0,0 @@
1
- import type { LookupContract, LookupResult } from "../../shared/contracts.js";
2
- import lookupMany from "../../shared/lookupMany.js";
3
- import type { PragmaRuntime } from "../../shared/runtime.js";
4
- import { expandLookupQueries } from "../../shared/suggestions/index.js";
5
- import type { StandardDetailed } from "../../shared/types/index.js";
6
- import { lookupStandard } from "../operations/index.js";
7
-
8
- export default async function resolveStandardLookup(
9
- store: Pick<PragmaRuntime, "store">["store"],
10
- queries: readonly string[],
11
- ): Promise<LookupContract<StandardDetailed>> {
12
- const { names, globErrors } = await expandLookupQueries(
13
- queries,
14
- store,
15
- "standard",
16
- );
17
-
18
- const lookupResult: LookupResult<StandardDetailed> =
19
- names.length > 0
20
- ? await lookupMany(names, (query) => lookupStandard(store, query))
21
- : { results: [], errors: [], meta: { internalErrorCount: 0 } };
22
-
23
- const result: LookupResult<StandardDetailed> = {
24
- results: lookupResult.results,
25
- errors: [...lookupResult.errors, ...globErrors],
26
- meta: lookupResult.meta ?? { internalErrorCount: 0 },
27
- };
28
-
29
- return {
30
- params: { names: queries },
31
- result,
32
- };
33
- }
@@ -1,33 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import standardEmptyError from "./standardEmptyError.js";
3
-
4
- describe("standardEmptyError", () => {
5
- it("filter-narrowing: a category/search was active → clear filters and re-list", () => {
6
- const err = standardEmptyError({ category: "react", search: "fold" });
7
-
8
- expect(err.filters).toEqual({ category: "react", search: "fold" });
9
- expect(err.recovery).toEqual({
10
- message: "List all standards without filters.",
11
- cli: "pragma standard list",
12
- mcp: { tool: "standard_list" },
13
- });
14
- });
15
-
16
- it("store-empty: no filter active → install, not a self-looping list", () => {
17
- const err = standardEmptyError({});
18
-
19
- expect(err.filters).toBeUndefined();
20
- // Must NOT suggest `pragma standard list` again — that just re-returns empty.
21
- expect(err.recovery).toEqual({
22
- message: "Install the code standards packages that provide standards.",
23
- cli: "bun add -D @canonical/code-standards",
24
- });
25
- expect(err.recovery?.mcp).toBeUndefined();
26
- });
27
-
28
- it("install branch cites the code-standards package", () => {
29
- const err = standardEmptyError({});
30
- expect(err.recovery?.cli).toContain("@canonical/code-standards");
31
- expect(err.recovery?.cli).not.toContain("ds-global");
32
- });
33
- });
@@ -1,29 +0,0 @@
1
- import { PragmaError } from "#error";
2
- import type { StandardListFilters } from "../../shared/types/index.js";
3
-
4
- export default function standardEmptyError(
5
- filters: StandardListFilters,
6
- ): PragmaError {
7
- const active: Record<string, string> = {};
8
- if (filters.category) active.category = filters.category;
9
- if (filters.search) active.search = filters.search;
10
- const hasFilter = Object.keys(active).length > 0;
11
-
12
- return PragmaError.emptyResults("standard", {
13
- filters: hasFilter ? active : undefined,
14
- recovery: hasFilter
15
- ? {
16
- // Filter-narrowing: clear the active category/search and re-list.
17
- message: "List all standards without filters.",
18
- cli: "pragma standard list",
19
- mcp: { tool: "standard_list" },
20
- }
21
- : {
22
- // Store-empty with no filter active: suggesting `standard list`
23
- // again would just re-return empty, so route to the install.
24
- message:
25
- "Install the code standards packages that provide standards.",
26
- cli: "bun add -D @canonical/code-standards",
27
- },
28
- });
29
- }
@@ -1,42 +0,0 @@
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
- };
@@ -1,24 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { standardListStory, standardLookupStory } from "./stories.js";
3
-
4
- describe("standardListStory", () => {
5
- it("renders the ink list view", () => {
6
- const view = standardListStory.renderInk?.({
7
- items: [],
8
- details: undefined,
9
- disclosure: { level: "summary" },
10
- });
11
- expect(typeof view).toBe("string");
12
- expect(view).toContain("Standards");
13
- });
14
- });
15
-
16
- describe("standardLookupStory", () => {
17
- it("renders the ink lookup view", () => {
18
- const view = standardLookupStory.renderInk?.(
19
- { results: [], errors: [] },
20
- { surface: "cli", detailed: false, params: {} },
21
- );
22
- expect(typeof view).toBe("string");
23
- });
24
- });
@@ -1,151 +0,0 @@
1
- /**
2
- * Standard read stories — the single declaration of `standard list` and
3
- * `standard lookup` for both surfaces.
4
- *
5
- * The story kernel compiles these into the CLI commands and MCP tools,
6
- * so descriptions, parameters, resolution, and rendering live here once.
7
- */
8
-
9
- import { createListView, createLookupView } from "#tui";
10
- import type { LookupStory, ReadStory } from "../shared/stories/index.js";
11
- import type { StandardDetailed } from "../shared/types/index.js";
12
- import {
13
- createInkLookupOptions,
14
- listFormatters,
15
- lookupFormatters,
16
- type StandardListOutput,
17
- type StandardLookupInput,
18
- } from "./formatters/index.js";
19
- import {
20
- resolveStandardList,
21
- resolveStandardLookup,
22
- } from "./orchestration/index.js";
23
- import { standardConfig } from "./standardConfig.js";
24
- import type { StandardListResolution } from "./types.js";
25
-
26
- /** The `standard list` / `standard_list` read story. */
27
- export const standardListStory: ReadStory<
28
- StandardListResolution,
29
- StandardListOutput
30
- > = {
31
- noun: "standard",
32
- verb: "list",
33
- description: "List all code standards",
34
- toolDescription:
35
- "List code standards. Optionally filter by category or search term. Use digest/detailed for progressive disclosure.",
36
- params: [
37
- {
38
- name: "category",
39
- type: "string",
40
- description: "Filter by category",
41
- toolDescription: "Filter by category name",
42
- },
43
- {
44
- name: "search",
45
- type: "string",
46
- description: "Search in name and description",
47
- },
48
- {
49
- name: "digest",
50
- type: "boolean",
51
- description: "Show description and first example for each standard",
52
- default: false,
53
- },
54
- {
55
- name: "detailed",
56
- type: "boolean",
57
- description: "Show full dos/donts for each standard",
58
- default: false,
59
- },
60
- ],
61
- examples: [
62
- "pragma standard list",
63
- "pragma standard list --category react",
64
- 'pragma standard list --search "folder"',
65
- "pragma standard list --digest",
66
- "pragma standard list --detailed",
67
- "pragma standard list --llm",
68
- ],
69
- resolve: (rt, params) =>
70
- resolveStandardList(rt, {
71
- category: params.category as string | undefined,
72
- search: params.search as string | undefined,
73
- digest: params.digest === true,
74
- detailed: params.detailed === true,
75
- }),
76
- toOutput: (resolution) => ({
77
- items: resolution.items,
78
- details: resolution.details,
79
- disclosure: resolution.disclosure,
80
- }),
81
- formatters: listFormatters,
82
- toEnvelope: (resolution) => {
83
- if (resolution.disclosure.level === "summary") {
84
- return {
85
- data: resolution.items,
86
- meta: { count: resolution.items.length },
87
- };
88
- }
89
- const output: StandardListOutput = {
90
- items: resolution.items,
91
- details: resolution.details,
92
- disclosure: resolution.disclosure,
93
- };
94
- return {
95
- data: JSON.parse(listFormatters.json(output)),
96
- meta: {
97
- count: resolution.items.length,
98
- disclosure: resolution.disclosure.level,
99
- },
100
- };
101
- },
102
- renderInk: (output) =>
103
- createListView({
104
- heading: "Standards",
105
- domain: "standard",
106
- items: output.items,
107
- columns: standardConfig.listColumns,
108
- }),
109
- };
110
-
111
- /** The `standard lookup` / `standard_lookup` read story. */
112
- export const standardLookupStory: LookupStory<
113
- StandardDetailed,
114
- StandardLookupInput
115
- > = {
116
- noun: "standard",
117
- description: "Look up detailed information for a standard by name or IRI",
118
- toolDescription:
119
- "Get detailed information about one or more code standards including dos and donts with code examples.",
120
- namesDescription: "Standard names or IRIs",
121
- namesToolDescription: "Standard names or IRIs to look up",
122
- detailedParam: {
123
- description: "Include dos and donts with code blocks",
124
- toolDescription:
125
- "Return full details with dos/donts (default: true for MCP)",
126
- },
127
- examples: [
128
- "pragma standard lookup react/component/folder-structure",
129
- "pragma standard lookup react/component/folder-structure react/component/props",
130
- "pragma standard lookup react/component/folder-structure --detailed",
131
- "pragma standard lookup react/component/folder-structure --llm",
132
- "pragma standard lookup cs:react_props",
133
- ],
134
- resolve: async (rt, names) => {
135
- const contract = await resolveStandardLookup(rt.store, names);
136
- return contract.result;
137
- },
138
- toFmtInput: (standard, view) => ({ standard, detailed: view.detailed }),
139
- formatters: lookupFormatters,
140
- project: (standard) => {
141
- const { uri, name, category, description } = standard;
142
- return { uri, name, category, description };
143
- },
144
- renderInk: (result, view) =>
145
- createLookupView({
146
- results: result.results,
147
- errors: result.errors,
148
- domain: "standard",
149
- options: createInkLookupOptions(view.detailed),
150
- }),
151
- };
@@ -1,15 +0,0 @@
1
- import type { ListParams } from "../shared/contracts.js";
2
- import type {
3
- Disclosure,
4
- StandardDetailed,
5
- StandardListFilters,
6
- StandardSummary,
7
- } from "../shared/types/index.js";
8
-
9
- export interface StandardListResolution {
10
- readonly params: ListParams & StandardListFilters;
11
- readonly items: readonly StandardSummary[];
12
- readonly filters: StandardListFilters;
13
- readonly disclosure: Disclosure;
14
- readonly details?: readonly (StandardDetailed | null)[];
15
- }
@@ -1,3 +0,0 @@
1
- /** @module Re-exports tier command builders (`list`). */
2
-
3
- export { default as listCommand } from "./list.js";
@@ -1,67 +0,0 @@
1
- import type { CommandOutputResult } from "@canonical/cli-core";
2
- import type { Store } from "@canonical/ke";
3
- import { afterAll, beforeAll, describe, expect, it } from "vitest";
4
- import { createTestStore, DS_ALL_TTL } from "#testing";
5
- import type { PragmaContext } from "../../shared/context.js";
6
- import listCommand from "./list.js";
7
-
8
- let store: Store;
9
- let cleanup: () => void;
10
-
11
- beforeAll(async () => {
12
- const result = await createTestStore({ ttl: DS_ALL_TTL });
13
- store = result.store;
14
- cleanup = result.cleanup;
15
- });
16
-
17
- afterAll(() => cleanup());
18
-
19
- function makeCtx(
20
- overrides?: Partial<PragmaContext["globalFlags"]>,
21
- ): PragmaContext {
22
- return {
23
- cwd: "/tmp",
24
- store,
25
- config: { tier: undefined, channel: "normal" },
26
- globalFlags: {
27
- llm: false,
28
- format: "text",
29
- verbose: false,
30
- ...overrides,
31
- },
32
- };
33
- }
34
-
35
- describe("tier list command", () => {
36
- it("returns tiers with hierarchy", async () => {
37
- const ctx = makeCtx();
38
- const cmd = listCommand(ctx);
39
- const result = await cmd.execute({}, ctx);
40
- expect(result.tag).toBe("output");
41
-
42
- const output = result as CommandOutputResult;
43
- const text = output.render.plain(output.value);
44
- expect(text).toContain("global");
45
- expect(text).toContain("apps");
46
- expect(text).toContain("apps/lxd");
47
- });
48
-
49
- it("renders flat tier list without parent references", async () => {
50
- const ctx = makeCtx();
51
- const cmd = listCommand(ctx);
52
- const result = await cmd.execute({}, ctx);
53
- const output = result as CommandOutputResult;
54
- const text = output.render.plain(output.value);
55
- expect(text).not.toContain("(parent:");
56
- });
57
-
58
- it("renders LLM format with --llm", async () => {
59
- const ctx = makeCtx({ llm: true });
60
- const cmd = listCommand(ctx);
61
- const result = await cmd.execute({}, ctx);
62
- const output = result as CommandOutputResult;
63
- const text = output.render.plain(output.value);
64
- expect(text).toContain("## Tiers");
65
- expect(text).toContain("**global**");
66
- });
67
- });
@@ -1,9 +0,0 @@
1
- import type { CommandDefinition } from "@canonical/cli-core";
2
- import type { PragmaContext } from "../../shared/context.js";
3
- import { compileReadCommand } from "../../shared/stories/index.js";
4
- import { tierListStory } from "../stories.js";
5
-
6
- /** Wire the `pragma tier list` CLI command from the tier list story. */
7
- export default function listCommand(ctx: PragmaContext): CommandDefinition {
8
- return compileReadCommand(ctx, tierListStory);
9
- }
@@ -1,3 +0,0 @@
1
- /** @module Re-exports tier formatters (`listFormatters`). */
2
-
3
- export { default as listFormatters } from "./list.js";
@@ -1,33 +0,0 @@
1
- import type { URI } from "@canonical/ke";
2
- import { describe, expect, it } from "vitest";
3
- import type { TierEntry } from "../../shared/types/index.js";
4
- import formatters from "./list.js";
5
-
6
- const TIERS: TierEntry[] = [
7
- { uri: "http://example.com/t1" as URI, path: "apps", depth: 0 },
8
- { uri: "http://example.com/t2" as URI, path: "apps/lxd", depth: 0 },
9
- { uri: "http://example.com/t3" as URI, path: "global", depth: 0 },
10
- ];
11
-
12
- describe("tier list formatters", () => {
13
- it("plain renders flat tier names", () => {
14
- const text = formatters.plain(TIERS);
15
- expect(text).toContain("global");
16
- expect(text).toContain("apps");
17
- expect(text).toContain("apps/lxd");
18
- });
19
-
20
- it("plain renders one tier per line", () => {
21
- const text = formatters.plain(TIERS);
22
- const lines = text.split("\n").filter(Boolean);
23
- expect(lines).toHaveLength(3);
24
- });
25
-
26
- it("llm renders markdown heading and bold paths", () => {
27
- const text = formatters.llm(TIERS);
28
- expect(text).toContain("## Tiers");
29
- expect(text).toContain("- **global**");
30
- expect(text).toContain("- **apps**");
31
- expect(text).toContain("- **apps/lxd**");
32
- });
33
- });
@@ -1,45 +0,0 @@
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
-
6
- /**
7
- * Three-mode formatter for `pragma tier list` output.
8
- *
9
- * - **plain** — indented terminal text showing tier hierarchy with
10
- * optional parent annotations.
11
- * - **llm** — condensed Markdown consumed by LLM agents and reused
12
- * by the MCP adapter when `condensed: true`.
13
- * - **json** — structured JSON array for programmatic consumption.
14
- */
15
- const formatters: Formatters<TierEntry[]> = {
16
- plain: (tiers) => {
17
- const lines: string[] = [];
18
- for (const t of tiers) {
19
- const indent = " ".repeat(t.depth);
20
- const parent = t.parent ? ` (parent: ${t.parent})` : "";
21
- lines.push(
22
- `${compactUri(t.uri, PREFIX_MAP)} ${indent}${t.path}${parent}`,
23
- );
24
- }
25
- return lines.join("\n");
26
- },
27
-
28
- llm: (tiers) => {
29
- const lines: string[] = [];
30
- lines.push("## Tiers");
31
- lines.push("");
32
- for (const t of tiers) {
33
- const indent = " ".repeat(t.depth);
34
- const parent = t.parent ? ` (parent: ${t.parent})` : "";
35
- lines.push(
36
- `${indent}- **${t.path}** \`${compactUri(t.uri, PREFIX_MAP)}\`${parent}`,
37
- );
38
- }
39
- return lines.join("\n");
40
- },
41
-
42
- json: (tiers) => JSON.stringify(tiers, null, 2),
43
- };
44
-
45
- export default formatters;
@@ -1,17 +0,0 @@
1
- /**
2
- * @module Tier domain — CLI commands and operations.
3
- *
4
- * Commands: `pragma tier list`.
5
- * Operations: {@link listTiers}.
6
- */
7
-
8
- import type { CommandDefinition } from "@canonical/cli-core";
9
- import type { PragmaContext } from "../shared/context.js";
10
- import { listCommand } from "./commands/index.js";
11
-
12
- export function commands(ctx: PragmaContext): CommandDefinition[] {
13
- return [listCommand(ctx)];
14
- }
15
-
16
- export { specs as mcpSpecs } from "./mcp/index.js";
17
- export { listTiers } from "./operations/index.js";
@@ -1,2 +0,0 @@
1
- /** @module Tier domain MCP barrel — tier_list. */
2
- export { default as specs } from "./specs.js";
@@ -1,12 +0,0 @@
1
- /**
2
- * MCP tool specs for the tier domain — tier_list, compiled from the tier
3
- * read story in `../stories.ts`.
4
- */
5
-
6
- import { compileReadTool } from "../../shared/stories/index.js";
7
- import type { ToolSpec } from "../../shared/ToolSpec.js";
8
- import { tierListStory } from "../stories.js";
9
-
10
- const specs: readonly ToolSpec[] = [compileReadTool(tierListStory)];
11
-
12
- export default specs;
@@ -1,3 +0,0 @@
1
- /** @module Re-exports tier operations (`listTiers`). */
2
-
3
- export { default as listTiers } from "./list.js";
@@ -1,32 +0,0 @@
1
- import type { Store } from "@canonical/ke";
2
- import { afterAll, beforeAll, describe, expect, it } from "vitest";
3
- import { createTestStore, DS_ALL_TTL } from "#testing";
4
- import listTiers from "./list.js";
5
-
6
- let store: Store;
7
- let cleanup: () => void;
8
-
9
- beforeAll(async () => {
10
- const result = await createTestStore({ ttl: DS_ALL_TTL });
11
- store = result.store;
12
- cleanup = result.cleanup;
13
- });
14
-
15
- afterAll(() => cleanup());
16
-
17
- describe("listTiers", () => {
18
- it("returns all tiers from the ontology", async () => {
19
- const result = await listTiers(store);
20
- const paths = result.map((t) => t.path);
21
- expect(paths).toContain("global");
22
- expect(paths).toContain("apps");
23
- expect(paths).toContain("apps/lxd");
24
- });
25
-
26
- it("returns sorted by name", async () => {
27
- const result = await listTiers(store);
28
- const paths = result.map((t) => t.path);
29
- const sorted = [...paths].sort();
30
- expect(paths).toEqual(sorted);
31
- });
32
- });
@@ -1,33 +0,0 @@
1
- /**
2
- * Lists all tiers defined in the design system ontology, ordered by name.
3
- *
4
- * @param store - ke store to query
5
- * @returns array of tier entries, empty when none exist
6
- * @note Queries ke store
7
- */
8
-
9
- import type { Store, URI } from "@canonical/ke";
10
- import { buildQuery } from "../../shared/buildQuery.js";
11
- import { P } from "../../shared/prefixes.js";
12
- import type { TierEntry } from "../../shared/types/index.js";
13
-
14
- export default async function listTiers(store: Store): Promise<TierEntry[]> {
15
- const result = await store.query(
16
- buildQuery(`
17
- SELECT ?tier ?name
18
- WHERE {
19
- ?tier a ${P.ds}Tier ;
20
- ${P.ds}name ?name .
21
- }
22
- ORDER BY ?name
23
- `),
24
- );
25
-
26
- if (result.type !== "select") return [];
27
-
28
- return result.bindings.map((b) => ({
29
- uri: (b.tier ?? "") as URI,
30
- path: b.name ?? "",
31
- depth: 0,
32
- }));
33
- }
@@ -1,22 +0,0 @@
1
- import type { URI } from "@canonical/ke";
2
- import { describe, expect, it } from "vitest";
3
- import { tierListStory } from "./stories.js";
4
-
5
- const tier = {
6
- uri: "https://ds.example/global" as URI,
7
- path: "global",
8
- depth: 0,
9
- };
10
-
11
- describe("tierListStory", () => {
12
- it("renders the ink list view", () => {
13
- const view = tierListStory.renderInk?.([tier]);
14
- expect(typeof view).toBe("string");
15
- expect(view).toContain("Tiers");
16
- });
17
-
18
- it("rejects only empty results", () => {
19
- expect(tierListStory.emptyError?.([], {})).toBeDefined();
20
- expect(tierListStory.emptyError?.([tier], {})).toBeUndefined();
21
- });
22
- });