@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.
- package/LICENSE +166 -0
- package/dist/pragma +0 -0
- package/package.json +31 -18
- package/src/constants.ts +1 -1
- package/src/domains/block/blockConfig.ts +47 -3
- package/src/domains/block/commands/list.test.ts +1 -1
- package/src/domains/block/commands/list.ts +27 -0
- package/src/domains/block/commands/lookup.ts +26 -52
- package/src/domains/block/formatters/index.ts +1 -1
- package/src/domains/block/formatters/list.test.ts +1 -1
- package/src/domains/block/formatters/list.ts +28 -42
- package/src/domains/block/formatters/lookup.test.ts +3 -2
- package/src/domains/block/formatters/lookup.ts +91 -296
- package/src/domains/block/formatters/types.ts +1 -1
- package/src/domains/block/operations/list.test.ts +1 -1
- package/src/domains/block/operations/list.ts +1 -1
- package/src/domains/block/operations/lookup.test.ts +29 -8
- package/src/domains/block/operations/lookup.ts +94 -16
- package/src/domains/block/orchestration/blockEmptyError.ts +1 -1
- package/src/domains/block/orchestration/buildBlockFilters.ts +1 -1
- package/src/domains/block/orchestration/enrichBlocks.ts +6 -2
- package/src/domains/block/orchestration/resolveBlockList.ts +1 -1
- package/src/domains/block/orchestration/resolveBlockLookup.ts +8 -2
- package/src/domains/block/types.ts +1 -1
- package/src/domains/config/commands/channel.ts +6 -4
- package/src/domains/config/commands/tier.ts +6 -4
- package/src/domains/config/mcp/specs.ts +18 -6
- package/src/domains/config/operations/validateTier.ts +1 -1
- package/src/domains/config/tasks/index.ts +3 -0
- package/src/domains/config/tasks/setChannel.ts +30 -0
- package/src/domains/config/tasks/setTier.ts +33 -0
- package/src/domains/create/commands/package.test.ts +2 -2
- package/src/domains/doctor/mcp/index.ts +1 -1
- package/src/domains/doctor/mcp/specs.ts +2 -49
- package/src/domains/graph/commands/inspect.test.ts +1 -1
- package/src/domains/graph/formatters/inspect.ts +12 -7
- package/src/domains/graph/operations/inspectUri.ts +4 -1
- package/src/domains/info/commands/upgrade.ts +6 -3
- package/src/domains/info/index.ts +3 -1
- package/src/domains/info/mcp/index.ts +2 -0
- package/src/domains/info/mcp/specs.ts +65 -0
- package/src/domains/llm/data/commandReference.ts +4 -4
- package/src/domains/llm/data/decisionTrees.ts +14 -12
- package/src/domains/llm/operations/collectContext.ts +1 -1
- package/src/domains/modifier/commands/list.ts +9 -0
- package/src/domains/modifier/commands/lookup.ts +22 -42
- package/src/domains/modifier/formatters/index.ts +4 -1
- package/src/domains/modifier/formatters/list.test.ts +1 -1
- package/src/domains/modifier/formatters/list.ts +13 -26
- package/src/domains/modifier/formatters/lookup.test.ts +1 -1
- package/src/domains/modifier/formatters/lookup.ts +41 -29
- package/src/domains/modifier/index.ts +1 -0
- package/src/domains/modifier/modifierConfig.ts +36 -0
- package/src/domains/modifier/operations/list.ts +1 -1
- package/src/domains/modifier/operations/lookup.ts +4 -3
- package/src/domains/modifier/orchestration/resolveModifierLookup.ts +1 -1
- package/src/domains/modifier/types.ts +1 -1
- package/src/domains/ontology/commands/list.test.ts +1 -1
- package/src/domains/ontology/commands/list.ts +18 -0
- package/src/domains/ontology/commands/show.test.ts +1 -1
- package/src/domains/ontology/formatters/list.ts +5 -3
- package/src/domains/ontology/formatters/show.ts +38 -13
- package/src/domains/ontology/helpers/queryClasses.ts +1 -1
- package/src/domains/ontology/helpers/queryProperties.ts +1 -1
- package/src/domains/ontology/operations/listOntologies.ts +1 -1
- package/src/domains/ontology/operations/showOntology.ts +1 -1
- package/src/domains/setup/helpers/completionScripts.test.ts +3 -3
- package/src/domains/setup/helpers/completionScripts.ts +4 -4
- package/src/domains/shared/ToolSpec.ts +1 -1
- package/src/domains/shared/context.ts +3 -2
- package/src/domains/shared/contracts.ts +40 -1
- package/src/domains/shared/filters/buildFilterConfig.ts +1 -2
- package/src/domains/shared/filters/buildFilters.ts +1 -1
- package/src/domains/shared/filters/describeFilters.ts +1 -1
- package/src/domains/shared/formatters.ts +47 -0
- package/src/domains/shared/renderers.ts +410 -0
- package/src/domains/shared/runtime.ts +7 -22
- package/src/domains/shared/types/block.ts +107 -0
- package/src/domains/shared/types/common.ts +33 -0
- package/src/domains/shared/types/graph.ts +17 -0
- package/src/domains/shared/types/index.ts +49 -0
- package/src/domains/shared/types/modifier.ts +22 -0
- package/src/domains/shared/types/ontology.ts +50 -0
- package/src/domains/shared/types/runtime.ts +21 -0
- package/src/domains/shared/types/standard.ts +64 -0
- package/src/domains/shared/types/tier.ts +15 -0
- package/src/domains/shared/types/token.ts +30 -0
- package/src/domains/standard/commands/list.ts +9 -0
- package/src/domains/standard/commands/lookup.ts +22 -50
- package/src/domains/standard/formatters/categories.test.ts +1 -1
- package/src/domains/standard/formatters/categories.ts +1 -1
- package/src/domains/standard/formatters/index.ts +4 -1
- package/src/domains/standard/formatters/list.test.ts +4 -1
- package/src/domains/standard/formatters/list.ts +112 -84
- package/src/domains/standard/formatters/lookup.test.ts +1 -1
- package/src/domains/standard/formatters/lookup.ts +85 -70
- package/src/domains/standard/formatters/types.ts +1 -1
- package/src/domains/standard/index.ts +1 -0
- package/src/domains/standard/operations/categories.ts +1 -1
- package/src/domains/standard/operations/list.ts +1 -1
- package/src/domains/standard/operations/lookup.ts +1 -1
- package/src/domains/standard/orchestration/buildStandardFilters.ts +1 -1
- package/src/domains/standard/orchestration/resolveStandardList.ts +4 -1
- package/src/domains/standard/orchestration/resolveStandardLookup.ts +1 -1
- package/src/domains/standard/orchestration/standardEmptyError.ts +1 -1
- package/src/domains/standard/standardConfig.ts +42 -0
- package/src/domains/standard/types.ts +1 -1
- package/src/domains/tier/commands/list.ts +16 -0
- package/src/domains/tier/formatters/list.test.ts +1 -1
- package/src/domains/tier/formatters/list.ts +11 -6
- package/src/domains/tier/operations/list.ts +1 -1
- package/src/domains/token/commands/list.ts +9 -0
- package/src/domains/token/commands/lookup.ts +22 -48
- package/src/domains/token/formatters/index.ts +4 -1
- package/src/domains/token/formatters/list.test.ts +1 -1
- package/src/domains/token/formatters/list.ts +15 -28
- package/src/domains/token/formatters/lookup.test.ts +2 -2
- package/src/domains/token/formatters/lookup.ts +80 -45
- package/src/domains/token/index.ts +1 -0
- package/src/domains/token/operations/list.ts +1 -1
- package/src/domains/token/operations/lookup.ts +1 -1
- package/src/domains/token/orchestration/resolveTokenLookup.ts +1 -1
- package/src/domains/token/tokenConfig.ts +38 -0
- package/src/domains/token/types.ts +1 -1
- package/src/index.ts +1 -1
- package/src/mcp/runMcpServer.test.ts +2 -2
- package/src/mcp/tools/index.ts +2 -0
- package/src/mcp/tools/registerTools.test.ts +8 -3
- package/src/package-manager/types.ts +1 -3
- package/src/pipeline/createProgram.ts +20 -1
- package/src/pipeline/index.ts +4 -1
- package/src/pipeline/parseGlobalFlags.test.ts +92 -0
- package/src/pipeline/parseGlobalFlags.ts +25 -0
- package/src/pipeline/runCli.orchestration.test.ts +1 -0
- package/src/pipeline/runCli.ts +11 -4
- package/src/pipeline/runInteractiveCommand.ts +198 -0
- package/src/testing/cli.ts +2 -2
- package/src/testing/fixtures.ts +2 -2
- package/src/testing/integration/boot.test.ts +2 -2
- package/src/testing/integration/cli-user-stories.test.ts +198 -0
- package/src/testing/integration/edge-cases.test.ts +263 -0
- package/src/testing/integration/parity.test.ts +377 -27
- package/src/testing/store.ts +1 -1
- package/src/tui/components/BulletList/BulletList.tsx +46 -0
- package/src/tui/components/BulletList/index.ts +2 -0
- package/src/tui/components/BulletList/types.ts +6 -0
- package/src/tui/components/Card/Card.tsx +73 -0
- package/src/tui/components/Card/index.ts +1 -0
- package/src/tui/components/Card/types.ts +12 -0
- package/src/tui/components/CodeBlock/CodeBlock.tsx +37 -0
- package/src/tui/components/CodeBlock/index.ts +2 -0
- package/src/tui/components/CodeBlock/types.ts +6 -0
- package/src/tui/components/DataRow/DataRow.tsx +80 -0
- package/src/tui/components/DataRow/index.ts +2 -0
- package/src/tui/components/DataRow/types.ts +14 -0
- package/src/tui/components/FieldRow/FieldRow.tsx +24 -0
- package/src/tui/components/FieldRow/index.ts +2 -0
- package/src/tui/components/FieldRow/types.ts +10 -0
- package/src/tui/components/HeaderRow/HeaderRow.tsx +32 -0
- package/src/tui/components/HeaderRow/index.ts +2 -0
- package/src/tui/components/HeaderRow/types.ts +8 -0
- package/src/tui/components/MarkdownText/MarkdownText.tsx +19 -0
- package/src/tui/components/MarkdownText/index.ts +2 -0
- package/src/tui/components/MarkdownText/types.ts +4 -0
- package/src/tui/components/MiniTable/MiniTable.tsx +82 -0
- package/src/tui/components/MiniTable/index.ts +2 -0
- package/src/tui/components/MiniTable/types.ts +6 -0
- package/src/tui/components/SectionRenderer/SectionRenderer.tsx +91 -0
- package/src/tui/components/SectionRenderer/index.ts +2 -0
- package/src/tui/components/SectionRenderer/types.ts +15 -0
- package/src/tui/components/TreeView/TreeView.tsx +84 -0
- package/src/tui/components/TreeView/index.ts +2 -0
- package/src/tui/components/TreeView/types.ts +6 -0
- package/src/tui/components/index.ts +19 -0
- package/src/tui/constants.ts +39 -0
- package/src/tui/createListView.ts +23 -0
- package/src/tui/createLookupView.ts +26 -0
- package/src/tui/helpers/computeWidths.ts +53 -0
- package/src/tui/helpers/fitColumns.ts +33 -0
- package/src/tui/helpers/formatMarkdown.ts +19 -0
- package/src/tui/helpers/getTerminalSize.ts +16 -0
- package/src/tui/helpers/index.ts +6 -0
- package/src/tui/helpers/syntaxColor.ts +67 -0
- package/src/tui/helpers/truncateText.ts +12 -0
- package/src/tui/hooks/index.ts +3 -0
- package/src/tui/hooks/types.ts +7 -0
- package/src/tui/hooks/useAutoExit.ts +17 -0
- package/src/tui/hooks/useTerminalSize.ts +19 -0
- package/src/tui/index.ts +15 -0
- package/src/tui/renderInk.tsx +18 -0
- package/src/tui/types.ts +12 -0
- package/src/tui/views/ListView/ListView.tsx +104 -0
- package/src/tui/views/ListView/index.ts +2 -0
- package/src/tui/views/ListView/types.ts +14 -0
- package/src/tui/views/LookupView/LookupView.tsx +244 -0
- package/src/tui/views/LookupView/index.ts +2 -0
- package/src/tui/views/LookupView/types.ts +16 -0
- package/src/tui/views/index.ts +4 -0
- package/src/domains/shared/types.test-d.ts +0 -127
- package/src/domains/shared/types.ts +0 -348
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Look up detailed information for a single block.
|
|
3
3
|
*
|
|
4
4
|
* Queries the base block, then resolves related modifiers, implementations,
|
|
5
|
-
* tokens, anatomy nodes, blank-node properties, and
|
|
5
|
+
* tokens, anatomy nodes, blank-node properties, and recursive subcomponents.
|
|
6
6
|
* The result is assembled into a {@link BlockDetailed} object.
|
|
7
7
|
*
|
|
8
8
|
* @param store - ke store to query
|
|
@@ -23,10 +23,11 @@ import { buildFilters } from "../../shared/filters/buildFilters.js";
|
|
|
23
23
|
import { P } from "../../shared/prefixes.js";
|
|
24
24
|
import type {
|
|
25
25
|
BlockDetailed,
|
|
26
|
+
BlockSubcomponent,
|
|
26
27
|
FilterConfig,
|
|
27
28
|
StandardRef,
|
|
28
29
|
TokenRef,
|
|
29
|
-
} from "../../shared/types.js";
|
|
30
|
+
} from "../../shared/types/index.js";
|
|
30
31
|
|
|
31
32
|
function normalizeBlockType(value: string | undefined): BlockDetailed["type"] {
|
|
32
33
|
const localName = extractLocalName(value ?? "").toLowerCase();
|
|
@@ -45,17 +46,17 @@ export default async function lookupBlock(
|
|
|
45
46
|
store: Store,
|
|
46
47
|
nameOrUri: string,
|
|
47
48
|
filters: FilterConfig,
|
|
48
|
-
): Promise<BlockDetailed> {
|
|
49
|
+
): Promise<BlockDetailed[]> {
|
|
49
50
|
const filterClauses = buildFilters(filters);
|
|
50
51
|
const subjectClause = buildLookupSubjectClause(nameOrUri, store.prefixes);
|
|
51
52
|
const bindClause =
|
|
52
53
|
subjectClause === null ? "" : `BIND(${subjectClause} AS ?component)`;
|
|
53
54
|
const matchClause =
|
|
54
55
|
subjectClause === null
|
|
55
|
-
? `?component ${P.ds}name ${escapeSparqlValue(nameOrUri)}
|
|
56
|
+
? `?component ${P.ds}name ?name . FILTER(LCASE(STR(?name)) = ${escapeSparqlValue(nameOrUri.toLowerCase())})`
|
|
56
57
|
: "";
|
|
57
58
|
|
|
58
|
-
// Base query: find the block
|
|
59
|
+
// Base query: find the block(s) — no LIMIT so ambiguous names return all matches
|
|
59
60
|
const baseResult = await store.query(
|
|
60
61
|
buildQuery(`
|
|
61
62
|
SELECT ?component ?name ?type ?tier ?summary ?whenToUse ?whenNotToUse ?guidelines ?anatomyDsl ?anatomyClassic ?figmaLink
|
|
@@ -75,7 +76,6 @@ export default async function lookupBlock(
|
|
|
75
76
|
OPTIONAL { ?component ${P.ds}figmaLink ?figmaLink }
|
|
76
77
|
${filterClauses}
|
|
77
78
|
}
|
|
78
|
-
LIMIT 1
|
|
79
79
|
`),
|
|
80
80
|
);
|
|
81
81
|
|
|
@@ -89,8 +89,18 @@ export default async function lookupBlock(
|
|
|
89
89
|
});
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
-
|
|
93
|
-
const base
|
|
92
|
+
const results: BlockDetailed[] = [];
|
|
93
|
+
for (const base of baseResult.bindings) {
|
|
94
|
+
results.push(await resolveBlockDetail(store, base, nameOrUri));
|
|
95
|
+
}
|
|
96
|
+
return results;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async function resolveBlockDetail(
|
|
100
|
+
store: Store,
|
|
101
|
+
base: Record<string, string>,
|
|
102
|
+
nameOrUri: string,
|
|
103
|
+
): Promise<BlockDetailed> {
|
|
94
104
|
const componentUri = base.component;
|
|
95
105
|
|
|
96
106
|
// Modifier families with values
|
|
@@ -231,24 +241,31 @@ export default async function lookupBlock(
|
|
|
231
241
|
}))
|
|
232
242
|
: [];
|
|
233
243
|
|
|
234
|
-
//
|
|
244
|
+
// Recursive subcomponents
|
|
235
245
|
const subcomponentsResult = await store.query(
|
|
236
246
|
buildQuery(`
|
|
237
|
-
SELECT ?subcomponent ?name
|
|
247
|
+
SELECT DISTINCT ?parent ?subcomponent ?name
|
|
238
248
|
WHERE {
|
|
239
|
-
<${componentUri}> ${P.ds}hasSubcomponent ?subcomponent .
|
|
249
|
+
<${componentUri}> (${P.ds}hasSubcomponent|^${P.ds}parentComponent)+ ?subcomponent .
|
|
250
|
+
?parent (${P.ds}hasSubcomponent|^${P.ds}parentComponent) ?subcomponent .
|
|
240
251
|
?subcomponent ${P.ds}name ?name .
|
|
252
|
+
FILTER(
|
|
253
|
+
?parent = <${componentUri}> ||
|
|
254
|
+
EXISTS {
|
|
255
|
+
<${componentUri}> (${P.ds}hasSubcomponent|^${P.ds}parentComponent)+ ?parent
|
|
256
|
+
}
|
|
257
|
+
)
|
|
241
258
|
}
|
|
242
|
-
ORDER BY ?name
|
|
259
|
+
ORDER BY ?parent ?name
|
|
243
260
|
`),
|
|
244
261
|
);
|
|
245
262
|
|
|
246
263
|
const subcomponents =
|
|
247
264
|
subcomponentsResult.type === "select"
|
|
248
|
-
?
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
265
|
+
? buildSubcomponentTree(
|
|
266
|
+
(componentUri ?? "") as URI,
|
|
267
|
+
subcomponentsResult.bindings,
|
|
268
|
+
)
|
|
252
269
|
: [];
|
|
253
270
|
|
|
254
271
|
// Standards (not linked directly to blocks in current ontology;
|
|
@@ -357,3 +374,64 @@ async function listAllFrameworks(store: Store): Promise<string[]> {
|
|
|
357
374
|
if (result.type !== "select") return [];
|
|
358
375
|
return result.bindings.map((b) => b.framework ?? "");
|
|
359
376
|
}
|
|
377
|
+
|
|
378
|
+
function buildSubcomponentTree(
|
|
379
|
+
rootUri: URI,
|
|
380
|
+
bindings: readonly Record<string, string>[],
|
|
381
|
+
): readonly BlockSubcomponent[] {
|
|
382
|
+
const nodeMap = new Map<string, BlockSubcomponent>();
|
|
383
|
+
const childrenByParent = new Map<string, string[]>();
|
|
384
|
+
|
|
385
|
+
for (const binding of bindings) {
|
|
386
|
+
const uri = (binding.subcomponent ?? "") as URI;
|
|
387
|
+
const parent = (binding.parent ?? "") as URI;
|
|
388
|
+
if (!uri || !parent) {
|
|
389
|
+
continue;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
nodeMap.set(String(uri), {
|
|
393
|
+
uri,
|
|
394
|
+
name: binding.name ?? extractLocalName(String(uri)),
|
|
395
|
+
children: [],
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
const siblings = childrenByParent.get(String(parent)) ?? [];
|
|
399
|
+
if (!siblings.includes(String(uri))) {
|
|
400
|
+
siblings.push(String(uri));
|
|
401
|
+
childrenByParent.set(String(parent), siblings);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
return buildSubcomponentChildren(String(rootUri), childrenByParent, nodeMap);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
function buildSubcomponentChildren(
|
|
409
|
+
parentUri: string,
|
|
410
|
+
childrenByParent: ReadonlyMap<string, readonly string[]>,
|
|
411
|
+
nodeMap: ReadonlyMap<string, BlockSubcomponent>,
|
|
412
|
+
visited = new Set<string>(),
|
|
413
|
+
): readonly BlockSubcomponent[] {
|
|
414
|
+
const childUris = childrenByParent.get(parentUri) ?? [];
|
|
415
|
+
|
|
416
|
+
return childUris.flatMap((childUri) => {
|
|
417
|
+
const node = nodeMap.get(childUri);
|
|
418
|
+
if (!node || visited.has(childUri)) {
|
|
419
|
+
return [];
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
const nextVisited = new Set(visited);
|
|
423
|
+
nextVisited.add(childUri);
|
|
424
|
+
|
|
425
|
+
return [
|
|
426
|
+
{
|
|
427
|
+
...node,
|
|
428
|
+
children: buildSubcomponentChildren(
|
|
429
|
+
childUri,
|
|
430
|
+
childrenByParent,
|
|
431
|
+
nodeMap,
|
|
432
|
+
nextVisited,
|
|
433
|
+
),
|
|
434
|
+
},
|
|
435
|
+
];
|
|
436
|
+
});
|
|
437
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { PragmaError } from "#error";
|
|
2
2
|
import { describeFilters } from "../../shared/filters/index.js";
|
|
3
|
-
import type { FilterConfig } from "../../shared/types.js";
|
|
3
|
+
import type { FilterConfig } from "../../shared/types/index.js";
|
|
4
4
|
|
|
5
5
|
export default function blockEmptyError(
|
|
6
6
|
filters: FilterConfig,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { PragmaRuntime } from "../../shared/runtime.js";
|
|
2
|
-
import type { FilterConfig } from "../../shared/types.js";
|
|
2
|
+
import type { FilterConfig } from "../../shared/types/index.js";
|
|
3
3
|
|
|
4
4
|
export default function buildBlockFilters(
|
|
5
5
|
rt: Pick<PragmaRuntime, "config">,
|
|
@@ -4,7 +4,7 @@ import type {
|
|
|
4
4
|
BlockSummary,
|
|
5
5
|
Disclosure,
|
|
6
6
|
FilterConfig,
|
|
7
|
-
} from "../../shared/types.js";
|
|
7
|
+
} from "../../shared/types/index.js";
|
|
8
8
|
import { lookupBlock } from "../operations/index.js";
|
|
9
9
|
import type { BlockListDigest } from "../types.js";
|
|
10
10
|
|
|
@@ -14,9 +14,13 @@ export default async function enrichBlocks(
|
|
|
14
14
|
filters: FilterConfig,
|
|
15
15
|
disclosure: Disclosure,
|
|
16
16
|
): Promise<readonly (BlockListDigest | BlockDetailed)[]> {
|
|
17
|
-
const
|
|
17
|
+
const nested = await Promise.all(
|
|
18
18
|
summaries.map((summary) => lookupBlock(store, summary.name, filters)),
|
|
19
19
|
);
|
|
20
|
+
// lookupBlock returns BlockDetailed[] — take the first match per summary
|
|
21
|
+
const details: BlockDetailed[] = nested.flatMap((matches) =>
|
|
22
|
+
matches[0] ? [matches[0]] : [],
|
|
23
|
+
);
|
|
20
24
|
|
|
21
25
|
if (disclosure.level === "detailed") {
|
|
22
26
|
return details;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ListParams } from "../../shared/contracts.js";
|
|
2
2
|
import type { PragmaRuntime } from "../../shared/runtime.js";
|
|
3
|
-
import type { Disclosure } from "../../shared/types.js";
|
|
3
|
+
import type { Disclosure } from "../../shared/types/index.js";
|
|
4
4
|
import { listBlocks } from "../operations/index.js";
|
|
5
5
|
import type { BlockListContract } from "../types.js";
|
|
6
6
|
import blockEmptyError from "./blockEmptyError.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 { BlockDetailed, FilterConfig } from "../../shared/types.js";
|
|
4
|
+
import type { BlockDetailed, FilterConfig } from "../../shared/types/index.js";
|
|
5
5
|
import { lookupBlock } from "../operations/index.js";
|
|
6
6
|
|
|
7
7
|
export default async function resolveBlockLookup(
|
|
@@ -9,11 +9,17 @@ export default async function resolveBlockLookup(
|
|
|
9
9
|
queries: readonly string[],
|
|
10
10
|
filters: FilterConfig,
|
|
11
11
|
): Promise<LookupContract<BlockDetailed>> {
|
|
12
|
-
const
|
|
12
|
+
const nested: LookupResult<BlockDetailed[]> = await lookupMany(
|
|
13
13
|
queries,
|
|
14
14
|
(query) => lookupBlock(store, query, filters),
|
|
15
15
|
);
|
|
16
16
|
|
|
17
|
+
// lookupBlock returns BlockDetailed[] (multiple matches per name) — flatten
|
|
18
|
+
const result: LookupResult<BlockDetailed> = {
|
|
19
|
+
results: nested.results.flat(),
|
|
20
|
+
errors: nested.errors,
|
|
21
|
+
};
|
|
22
|
+
|
|
17
23
|
return {
|
|
18
24
|
params: { names: queries },
|
|
19
25
|
result,
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import type { ListContract } from "../shared/contracts.js";
|
|
8
|
-
import type { BlockDetailed, BlockSummary } from "../shared/types.js";
|
|
8
|
+
import type { BlockDetailed, BlockSummary } from "../shared/types/index.js";
|
|
9
9
|
|
|
10
10
|
/** Flags controlling which detail aspects are included in block output. */
|
|
11
11
|
export interface AspectFlags {
|
|
@@ -3,11 +3,13 @@ import {
|
|
|
3
3
|
type CommandResult,
|
|
4
4
|
createOutputResult,
|
|
5
5
|
} from "@canonical/cli-core";
|
|
6
|
-
import {
|
|
6
|
+
import { runTask } from "@canonical/task";
|
|
7
|
+
import { readConfig } from "#config";
|
|
7
8
|
import type { PragmaContext } from "../../shared/context.js";
|
|
8
9
|
import { selectFormatter } from "../../shared/formatters.js";
|
|
9
10
|
import { channelFormatters } from "../formatters/index.js";
|
|
10
11
|
import { validateChannel } from "../operations/index.js";
|
|
12
|
+
import { setChannelTask } from "../tasks/index.js";
|
|
11
13
|
|
|
12
14
|
/**
|
|
13
15
|
* Build the `pragma config channel` command definition.
|
|
@@ -17,7 +19,7 @@ import { validateChannel } from "../operations/index.js";
|
|
|
17
19
|
*
|
|
18
20
|
* @param ctx - Pragma context providing cwd and formatter selection.
|
|
19
21
|
* @returns The command definition for `pragma config channel`.
|
|
20
|
-
* @note Impure
|
|
22
|
+
* @note - Impure — validates channel and writes config to disk.
|
|
21
23
|
*/
|
|
22
24
|
export default function buildChannelCommand(
|
|
23
25
|
ctx: PragmaContext,
|
|
@@ -52,7 +54,7 @@ export default function buildChannelCommand(
|
|
|
52
54
|
const value = params.value as string | undefined;
|
|
53
55
|
|
|
54
56
|
if (reset) {
|
|
55
|
-
|
|
57
|
+
await runTask(setChannelTask(ctx.cwd, undefined));
|
|
56
58
|
const format = selectFormatter(ctx, channelFormatters.reset);
|
|
57
59
|
return createOutputResult("Reset channel to default.", {
|
|
58
60
|
plain: format,
|
|
@@ -69,7 +71,7 @@ export default function buildChannelCommand(
|
|
|
69
71
|
|
|
70
72
|
const channel = validateChannel(value);
|
|
71
73
|
|
|
72
|
-
|
|
74
|
+
await runTask(setChannelTask(ctx.cwd, channel));
|
|
73
75
|
const format = selectFormatter(ctx, channelFormatters.set);
|
|
74
76
|
return createOutputResult(
|
|
75
77
|
{ field: "channel", value: channel },
|
|
@@ -3,11 +3,13 @@ import {
|
|
|
3
3
|
type CommandResult,
|
|
4
4
|
createOutputResult,
|
|
5
5
|
} from "@canonical/cli-core";
|
|
6
|
-
import {
|
|
6
|
+
import { runTask } from "@canonical/task";
|
|
7
|
+
import { readConfig } from "#config";
|
|
7
8
|
import type { PragmaContext } from "../../shared/context.js";
|
|
8
9
|
import { selectFormatter } from "../../shared/formatters.js";
|
|
9
10
|
import { tierFormatters } from "../formatters/index.js";
|
|
10
11
|
import { validateTier } from "../operations/index.js";
|
|
12
|
+
import { setTierTask } from "../tasks/index.js";
|
|
11
13
|
|
|
12
14
|
/**
|
|
13
15
|
* Build the `pragma config tier` command definition.
|
|
@@ -17,7 +19,7 @@ import { validateTier } from "../operations/index.js";
|
|
|
17
19
|
*
|
|
18
20
|
* @param ctx - Pragma context providing cwd, store, and formatter selection.
|
|
19
21
|
* @returns The command definition for `pragma config tier`.
|
|
20
|
-
* @note Impure
|
|
22
|
+
* @note - Impure — validates tier against the ke store and writes config to disk.
|
|
21
23
|
*/
|
|
22
24
|
export default function buildTierCommand(
|
|
23
25
|
ctx: PragmaContext,
|
|
@@ -49,7 +51,7 @@ export default function buildTierCommand(
|
|
|
49
51
|
const tierPath = params.path as string | undefined;
|
|
50
52
|
|
|
51
53
|
if (reset) {
|
|
52
|
-
|
|
54
|
+
await runTask(setTierTask(ctx.cwd, undefined));
|
|
53
55
|
const format = selectFormatter(ctx, tierFormatters.reset);
|
|
54
56
|
return createOutputResult("Reset tier to default.", {
|
|
55
57
|
plain: format,
|
|
@@ -67,7 +69,7 @@ export default function buildTierCommand(
|
|
|
67
69
|
// Validate tier against ontology
|
|
68
70
|
await validateTier(ctx.store, tierPath);
|
|
69
71
|
|
|
70
|
-
|
|
72
|
+
await runTask(setTierTask(ctx.cwd, tierPath));
|
|
71
73
|
const format = selectFormatter(ctx, tierFormatters.set);
|
|
72
74
|
return createOutputResult(
|
|
73
75
|
{ field: "tier", value: tierPath },
|
|
@@ -1,10 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* MCP tool specs for the config domain.
|
|
3
|
+
*
|
|
4
|
+
* config_show uses the shared resolveConfigShow() operation so that
|
|
5
|
+
* MCP data matches what the CLI produces (tierChain, includedReleases, etc.).
|
|
3
6
|
*/
|
|
4
7
|
|
|
5
8
|
import { readConfig, writeConfig } from "#config";
|
|
9
|
+
import { detectInstallSource } from "#package-manager";
|
|
6
10
|
import type { ToolSpec } from "../../shared/ToolSpec.js";
|
|
7
|
-
import {
|
|
11
|
+
import { showFormatters } from "../formatters/index.js";
|
|
12
|
+
import {
|
|
13
|
+
resolveConfigShow,
|
|
14
|
+
validateChannel,
|
|
15
|
+
validateTier,
|
|
16
|
+
} from "../operations/index.js";
|
|
8
17
|
|
|
9
18
|
const specs: readonly ToolSpec[] = [
|
|
10
19
|
{
|
|
@@ -20,13 +29,16 @@ const specs: readonly ToolSpec[] = [
|
|
|
20
29
|
},
|
|
21
30
|
readOnly: true,
|
|
22
31
|
async execute(rt, { condensed }) {
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
32
|
+
const install = detectInstallSource();
|
|
33
|
+
const data = resolveConfigShow(rt.config, {
|
|
34
|
+
packageManager: install.packageManager,
|
|
35
|
+
installSource: install.label,
|
|
36
|
+
configFilePath: "pragma.config.json",
|
|
37
|
+
configFileExists: true,
|
|
38
|
+
});
|
|
27
39
|
|
|
28
40
|
if (condensed) {
|
|
29
|
-
const text =
|
|
41
|
+
const text = showFormatters.llm(data);
|
|
30
42
|
return {
|
|
31
43
|
condensed: true,
|
|
32
44
|
text,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Store } from "@canonical/ke";
|
|
2
2
|
import { PragmaError } from "#error";
|
|
3
|
-
import type { TierEntry } from "../../shared/types.js";
|
|
3
|
+
import type { TierEntry } from "../../shared/types/index.js";
|
|
4
4
|
import { listTiers } from "../../tier/operations/index.js";
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { $, gen, type Task, writeFile } from "@canonical/task";
|
|
2
|
+
import { readConfig } from "../../../config/index.js";
|
|
3
|
+
import resolveConfigPath from "../../../config/resolveConfigPath.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Build a config-write task for setting or resetting the release channel.
|
|
7
|
+
*
|
|
8
|
+
* @param cwd - Working directory containing pragma.config.json.
|
|
9
|
+
* @param channel - Channel value to persist, or `undefined` to reset.
|
|
10
|
+
* @returns Task yielding the persisted field/value payload.
|
|
11
|
+
* @note - Impure — reads config and writes to the file system.
|
|
12
|
+
*/
|
|
13
|
+
export default function setChannel(
|
|
14
|
+
cwd: string,
|
|
15
|
+
channel: string | undefined,
|
|
16
|
+
): Task<{ field: "channel"; value: string | undefined }> {
|
|
17
|
+
return gen(function* () {
|
|
18
|
+
const current = readConfig(cwd);
|
|
19
|
+
const next = {
|
|
20
|
+
...(current.tier !== undefined ? { tier: current.tier } : {}),
|
|
21
|
+
...(channel !== undefined ? { channel } : {}),
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
yield* $(
|
|
25
|
+
writeFile(resolveConfigPath(cwd), `${JSON.stringify(next, null, 2)}\n`),
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
return { field: "channel", value: channel };
|
|
29
|
+
});
|
|
30
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { $, gen, type Task, writeFile } from "@canonical/task";
|
|
2
|
+
import { readConfig } from "../../../config/index.js";
|
|
3
|
+
import resolveConfigPath from "../../../config/resolveConfigPath.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Build a config-write task for setting or resetting the active tier.
|
|
7
|
+
*
|
|
8
|
+
* @param cwd - Working directory containing pragma.config.json.
|
|
9
|
+
* @param tier - Tier path to persist, or `undefined` to reset.
|
|
10
|
+
* @returns Task yielding the persisted field/value payload.
|
|
11
|
+
* @note - Impure — reads config and writes to the file system.
|
|
12
|
+
*/
|
|
13
|
+
export default function setTier(
|
|
14
|
+
cwd: string,
|
|
15
|
+
tier: string | undefined,
|
|
16
|
+
): Task<{
|
|
17
|
+
field: "tier";
|
|
18
|
+
value: string | undefined;
|
|
19
|
+
}> {
|
|
20
|
+
return gen(function* () {
|
|
21
|
+
const current = readConfig(cwd);
|
|
22
|
+
const next = {
|
|
23
|
+
...(tier !== undefined ? { tier } : {}),
|
|
24
|
+
...(current.channel !== undefined ? { channel: current.channel } : {}),
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
yield* $(
|
|
28
|
+
writeFile(resolveConfigPath(cwd), `${JSON.stringify(next, null, 2)}\n`),
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
return { field: "tier", value: tier };
|
|
32
|
+
});
|
|
33
|
+
}
|
|
@@ -27,9 +27,9 @@ describe("buildPackageCommand", () => {
|
|
|
27
27
|
expect(result.tag).toBe("output");
|
|
28
28
|
});
|
|
29
29
|
|
|
30
|
-
it("with missing required params returns
|
|
30
|
+
it("with missing required params returns batch output outside a TTY", async () => {
|
|
31
31
|
const cmd = buildPackageCommand();
|
|
32
32
|
const result = await cmd.execute({}, ctx);
|
|
33
|
-
expect(result.tag).toBe("
|
|
33
|
+
expect(result.tag).toBe("output");
|
|
34
34
|
});
|
|
35
35
|
});
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
/** @module Doctor domain MCP barrel — doctor
|
|
1
|
+
/** @module Doctor domain MCP barrel — doctor. */
|
|
2
2
|
export { default as specs } from "./specs.js";
|
|
@@ -1,15 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* MCP tool specs for doctor domain
|
|
2
|
+
* MCP tool specs for the doctor domain.
|
|
3
3
|
*
|
|
4
|
-
* The info tool
|
|
5
|
-
* the info domain, plus VERSION from #constants.
|
|
4
|
+
* The info tool has moved to its own domain: `info/mcp/specs.ts`.
|
|
6
5
|
*/
|
|
7
6
|
|
|
8
|
-
import { VERSION } from "#constants";
|
|
9
|
-
import { detectInstallSource } from "#package-manager";
|
|
10
|
-
import { renderInfoLlm } from "../../info/formatters/index.js";
|
|
11
|
-
import { collectStoreSummary } from "../../info/operations/index.js";
|
|
12
|
-
import type { InfoData } from "../../info/types.js";
|
|
13
7
|
import type { ToolSpec } from "../../shared/ToolSpec.js";
|
|
14
8
|
import { doctorFormatters } from "../formatters/index.js";
|
|
15
9
|
import { runChecks } from "../operations/index.js";
|
|
@@ -42,47 +36,6 @@ const specs: readonly ToolSpec[] = [
|
|
|
42
36
|
return { data: result };
|
|
43
37
|
},
|
|
44
38
|
},
|
|
45
|
-
{
|
|
46
|
-
name: "info",
|
|
47
|
-
description: "Show pragma version, configuration, and store summary.",
|
|
48
|
-
params: {
|
|
49
|
-
condensed: {
|
|
50
|
-
type: "boolean",
|
|
51
|
-
description: "Token-optimized output",
|
|
52
|
-
optional: true,
|
|
53
|
-
},
|
|
54
|
-
},
|
|
55
|
-
readOnly: true,
|
|
56
|
-
async execute(rt, params) {
|
|
57
|
-
const storeSummary = await collectStoreSummary(rt.store);
|
|
58
|
-
const install = detectInstallSource();
|
|
59
|
-
|
|
60
|
-
const data: InfoData = {
|
|
61
|
-
version: VERSION,
|
|
62
|
-
pm: install.packageManager,
|
|
63
|
-
installSource: install.label,
|
|
64
|
-
configPath: "pragma.config.json",
|
|
65
|
-
tier: rt.config.tier,
|
|
66
|
-
tierChain: [],
|
|
67
|
-
channel: rt.config.channel,
|
|
68
|
-
channelReleases: [],
|
|
69
|
-
update: undefined,
|
|
70
|
-
updateSkipped: true,
|
|
71
|
-
store: storeSummary,
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
if (params.condensed) {
|
|
75
|
-
const text = renderInfoLlm(data);
|
|
76
|
-
return {
|
|
77
|
-
condensed: true,
|
|
78
|
-
text,
|
|
79
|
-
tokens: `~${Math.ceil(text.length / 4)}`,
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
return { data };
|
|
84
|
-
},
|
|
85
|
-
},
|
|
86
39
|
];
|
|
87
40
|
|
|
88
41
|
export default specs;
|
|
@@ -4,7 +4,7 @@ import createTestRuntime from "../../../testing/helpers/createTestRuntime.js";
|
|
|
4
4
|
import type { PragmaContext } from "../../shared/context.js";
|
|
5
5
|
import { PREFIX_MAP } from "../../shared/prefixes.js";
|
|
6
6
|
import type { PragmaRuntime } from "../../shared/runtime.js";
|
|
7
|
-
import type { InspectResult } from "../../shared/types.js";
|
|
7
|
+
import type { InspectResult } from "../../shared/types/index.js";
|
|
8
8
|
import buildInspectCommand from "./inspect.js";
|
|
9
9
|
|
|
10
10
|
let runtime: PragmaRuntime;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
2
|
import { formatHeading } from "#pipeline";
|
|
3
|
+
import compactUri from "../../shared/compactUri.js";
|
|
3
4
|
import type { Formatters } from "../../shared/formatters.js";
|
|
4
|
-
import
|
|
5
|
+
import { PREFIX_MAP } from "../../shared/prefixes.js";
|
|
6
|
+
import type { InspectResult } from "../../shared/types/index.js";
|
|
5
7
|
|
|
6
8
|
/**
|
|
7
9
|
* Formatters for `pragma graph inspect` output.
|
|
@@ -13,13 +15,13 @@ import type { InspectResult } from "../../shared/types.js";
|
|
|
13
15
|
const formatters: Formatters<InspectResult> = {
|
|
14
16
|
plain(result) {
|
|
15
17
|
const lines: string[] = [];
|
|
16
|
-
lines.push(formatHeading(result.uri));
|
|
18
|
+
lines.push(formatHeading(compactUri(result.uri, PREFIX_MAP)));
|
|
17
19
|
|
|
18
20
|
for (const g of result.groups) {
|
|
19
21
|
lines.push("");
|
|
20
|
-
lines.push(chalk.bold(g.predicate));
|
|
22
|
+
lines.push(chalk.bold(compactUri(g.predicate, PREFIX_MAP)));
|
|
21
23
|
for (const o of g.objects) {
|
|
22
|
-
lines.push(` ${o}`);
|
|
24
|
+
lines.push(` ${compactUri(o, PREFIX_MAP)}`);
|
|
23
25
|
}
|
|
24
26
|
}
|
|
25
27
|
|
|
@@ -27,11 +29,14 @@ const formatters: Formatters<InspectResult> = {
|
|
|
27
29
|
},
|
|
28
30
|
|
|
29
31
|
llm(result) {
|
|
30
|
-
const lines = [
|
|
32
|
+
const lines = [
|
|
33
|
+
`## ${compactUri(result.uri, PREFIX_MAP)} (${result.uri})`,
|
|
34
|
+
"",
|
|
35
|
+
];
|
|
31
36
|
for (const g of result.groups) {
|
|
32
|
-
lines.push(`**${g.predicate}:**`);
|
|
37
|
+
lines.push(`**${compactUri(g.predicate, PREFIX_MAP)}:**`);
|
|
33
38
|
for (const o of g.objects) {
|
|
34
|
-
lines.push(` - ${o}`);
|
|
39
|
+
lines.push(` - ${compactUri(o, PREFIX_MAP)}`);
|
|
35
40
|
}
|
|
36
41
|
}
|
|
37
42
|
return lines.join("\n");
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import type { Store } from "@canonical/ke";
|
|
2
2
|
import { PragmaError } from "#error";
|
|
3
3
|
import { buildQuery } from "../../shared/buildQuery.js";
|
|
4
|
-
import type {
|
|
4
|
+
import type {
|
|
5
|
+
InspectResult,
|
|
6
|
+
PredicateGroup,
|
|
7
|
+
} from "../../shared/types/index.js";
|
|
5
8
|
import resolveUri from "../helpers/resolveUri.js";
|
|
6
9
|
|
|
7
10
|
/**
|
|
@@ -3,7 +3,7 @@ import type { CommandDefinition, CommandResult } from "@canonical/cli-core";
|
|
|
3
3
|
import { readConfig } from "#config";
|
|
4
4
|
import { VERSION } from "#constants";
|
|
5
5
|
import { PragmaError } from "#error";
|
|
6
|
-
import {
|
|
6
|
+
import { detectInstallSource, PM_COMMANDS } from "#package-manager";
|
|
7
7
|
import {
|
|
8
8
|
renderUpgradeJson,
|
|
9
9
|
renderUpgradeLlm,
|
|
@@ -58,9 +58,12 @@ async function executeUpgrade(
|
|
|
58
58
|
ctx: { cwd: string; globalFlags: { llm: boolean; format: "text" | "json" } },
|
|
59
59
|
): Promise<CommandResult> {
|
|
60
60
|
const dryRun = params.dryRun === true;
|
|
61
|
-
const
|
|
61
|
+
const source = detectInstallSource();
|
|
62
|
+
const pm = source.label;
|
|
62
63
|
const config = readConfig(ctx.cwd);
|
|
63
|
-
const command = PM_COMMANDS[
|
|
64
|
+
const command = PM_COMMANDS[source.packageManager].update(
|
|
65
|
+
"@canonical/pragma-cli",
|
|
66
|
+
);
|
|
64
67
|
|
|
65
68
|
const registryResult = await checkRegistryVersion(
|
|
66
69
|
"@canonical/pragma-cli",
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @module Info domain barrel.
|
|
3
3
|
*
|
|
4
|
-
* Provides the `pragma info` and `pragma upgrade` commands
|
|
4
|
+
* Provides the `pragma info` and `pragma upgrade` commands,
|
|
5
|
+
* and the `info` MCP tool spec.
|
|
5
6
|
*/
|
|
6
7
|
|
|
7
8
|
export { infoCommand, upgradeCommand } from "./commands/index.js";
|
|
9
|
+
export { specs as infoSpecs } from "./mcp/index.js";
|