@canonical/pragma-cli 0.20.0 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/pragma +0 -0
- package/package.json +30 -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
|
@@ -1,65 +1,80 @@
|
|
|
1
|
-
|
|
2
|
-
* Three-mode formatter factory for `pragma token lookup` output.
|
|
3
|
-
*
|
|
4
|
-
* - **plain** — terminal text showing token name, category, and optional
|
|
5
|
-
* per-theme values 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 values unless detailed.
|
|
9
|
-
*/
|
|
10
|
-
|
|
1
|
+
import type { RenderLookupOptions } from "../../shared/contracts.js";
|
|
11
2
|
import type { Formatters } from "../../shared/formatters.js";
|
|
12
|
-
import
|
|
3
|
+
import { renderLookupLlm, renderLookupPlain } from "../../shared/renderers.js";
|
|
4
|
+
import type { TokenDetailed } from "../../shared/types/index.js";
|
|
5
|
+
import { tokenConfig } from "../tokenConfig.js";
|
|
13
6
|
|
|
14
7
|
/** Options controlling detail level for the token-lookup formatter. */
|
|
15
|
-
|
|
8
|
+
interface TokenLookupFormatterOptions {
|
|
16
9
|
readonly detailed: boolean;
|
|
17
10
|
}
|
|
18
11
|
|
|
19
12
|
/**
|
|
20
|
-
*
|
|
21
|
-
*
|
|
13
|
+
* Create a three-mode formatter set for a single token.
|
|
14
|
+
*
|
|
15
|
+
* Captures the detail level in the closure so callers only pass the token data.
|
|
22
16
|
*
|
|
23
17
|
* @param options - detail-level options
|
|
24
18
|
* @returns plain/llm/json formatters for {@link TokenDetailed}
|
|
25
19
|
*/
|
|
26
|
-
export function createLookupFormatters(
|
|
20
|
+
export default function createLookupFormatters(
|
|
27
21
|
options: TokenLookupFormatterOptions,
|
|
28
22
|
): Formatters<TokenDetailed> {
|
|
29
23
|
const { detailed } = options;
|
|
24
|
+
const sections = detailed ? tokenConfig.lookupSections : [];
|
|
30
25
|
|
|
31
26
|
return {
|
|
32
|
-
plain: (token) =>
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
lines.push(`- ${v.theme}: \`${v.value}\``);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
27
|
+
plain: (token) =>
|
|
28
|
+
renderLookupPlain(token, {
|
|
29
|
+
title: (entry) => entry.name,
|
|
30
|
+
fields: [
|
|
31
|
+
{ label: "URI", value: (entry) => entry.uri },
|
|
32
|
+
{ label: "Category", value: (entry) => entry.category || "—" },
|
|
33
|
+
],
|
|
34
|
+
sections,
|
|
35
|
+
sectionOverrides: {
|
|
36
|
+
values: {
|
|
37
|
+
plain: (entry) =>
|
|
38
|
+
entry.values.length > 0
|
|
39
|
+
? entry.values
|
|
40
|
+
.map((value) => ` ${value.theme}: ${value.value}`)
|
|
41
|
+
.join("\n")
|
|
42
|
+
: null,
|
|
43
|
+
llm: (entry) =>
|
|
44
|
+
entry.values.length > 0
|
|
45
|
+
? entry.values
|
|
46
|
+
.map((value) => `- ${value.theme}: \`${value.value}\``)
|
|
47
|
+
.join("\n")
|
|
48
|
+
: null,
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
}),
|
|
60
52
|
|
|
61
|
-
|
|
62
|
-
|
|
53
|
+
llm: (token) =>
|
|
54
|
+
renderLookupLlm(token, {
|
|
55
|
+
title: (entry) => entry.name,
|
|
56
|
+
fields: [
|
|
57
|
+
{ label: "URI", value: (entry) => entry.uri },
|
|
58
|
+
{ label: "Category", value: (entry) => entry.category || "—" },
|
|
59
|
+
],
|
|
60
|
+
sections,
|
|
61
|
+
sectionOverrides: {
|
|
62
|
+
values: {
|
|
63
|
+
plain: (entry) =>
|
|
64
|
+
entry.values.length > 0
|
|
65
|
+
? entry.values
|
|
66
|
+
.map((value) => ` ${value.theme}: ${value.value}`)
|
|
67
|
+
.join("\n")
|
|
68
|
+
: null,
|
|
69
|
+
llm: (entry) =>
|
|
70
|
+
entry.values.length > 0
|
|
71
|
+
? entry.values
|
|
72
|
+
.map((value) => `- ${value.theme}: \`${value.value}\``)
|
|
73
|
+
.join("\n")
|
|
74
|
+
: null,
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
}),
|
|
63
78
|
|
|
64
79
|
json: (token) => {
|
|
65
80
|
if (detailed) {
|
|
@@ -70,3 +85,23 @@ export function createLookupFormatters(
|
|
|
70
85
|
},
|
|
71
86
|
};
|
|
72
87
|
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Build lookup rendering options for the Ink TUI view.
|
|
91
|
+
*
|
|
92
|
+
* @param options - detail-level options
|
|
93
|
+
* @returns Options compatible with the LookupView component.
|
|
94
|
+
*/
|
|
95
|
+
export function createInkLookupOptions(
|
|
96
|
+
options: TokenLookupFormatterOptions,
|
|
97
|
+
): RenderLookupOptions<TokenDetailed> {
|
|
98
|
+
const sections = options.detailed ? tokenConfig.lookupSections : [];
|
|
99
|
+
return {
|
|
100
|
+
title: (entry) => entry.name,
|
|
101
|
+
fields: [
|
|
102
|
+
{ label: "URI", value: (entry) => entry.uri },
|
|
103
|
+
{ label: "Category", value: (entry) => entry.category || "—" },
|
|
104
|
+
],
|
|
105
|
+
sections,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
@@ -11,7 +11,7 @@ import type { Store, URI } from "@canonical/ke";
|
|
|
11
11
|
import { escapeSparqlValue } from "@canonical/ke";
|
|
12
12
|
import { buildQuery } from "../../shared/buildQuery.js";
|
|
13
13
|
import { P } from "../../shared/prefixes.js";
|
|
14
|
-
import type { TokenSummary } from "../../shared/types.js";
|
|
14
|
+
import type { TokenSummary } from "../../shared/types/index.js";
|
|
15
15
|
|
|
16
16
|
/** Optional filters for the token list operation. */
|
|
17
17
|
export interface TokenListFilters {
|
|
@@ -15,7 +15,7 @@ import { escapeSparqlValue } from "@canonical/ke";
|
|
|
15
15
|
import { PragmaError } from "#error";
|
|
16
16
|
import { buildQuery } from "../../shared/buildQuery.js";
|
|
17
17
|
import { P } from "../../shared/prefixes.js";
|
|
18
|
-
import type { TokenDetailed } from "../../shared/types.js";
|
|
18
|
+
import type { TokenDetailed } from "../../shared/types/index.js";
|
|
19
19
|
|
|
20
20
|
export default async function lookupToken(
|
|
21
21
|
store: Store,
|
|
@@ -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 { TokenDetailed } from "../../shared/types.js";
|
|
4
|
+
import type { TokenDetailed } from "../../shared/types/index.js";
|
|
5
5
|
import { lookupToken } from "../operations/index.js";
|
|
6
6
|
|
|
7
7
|
export default async function resolveTokenLookup(
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { EntityDisplayConfig } from "../shared/contracts.js";
|
|
2
|
+
import { P } from "../shared/prefixes.js";
|
|
3
|
+
import type {
|
|
4
|
+
FilterConfig,
|
|
5
|
+
TokenDetailed,
|
|
6
|
+
TokenDigest,
|
|
7
|
+
TokenSummary,
|
|
8
|
+
} from "../shared/types/index.js";
|
|
9
|
+
|
|
10
|
+
/** Display-contract configuration for design-token entities. */
|
|
11
|
+
export const tokenConfig: EntityDisplayConfig<
|
|
12
|
+
TokenSummary,
|
|
13
|
+
TokenDigest,
|
|
14
|
+
TokenDetailed
|
|
15
|
+
> = {
|
|
16
|
+
domain: "token",
|
|
17
|
+
entityName: "token",
|
|
18
|
+
rdfTypes: [`${P.ds}Token`],
|
|
19
|
+
listColumns: [
|
|
20
|
+
{ key: "uri", label: "IRI" },
|
|
21
|
+
{ key: "name", label: "Name" },
|
|
22
|
+
{ key: "category", label: "Category" },
|
|
23
|
+
],
|
|
24
|
+
digestColumns: [],
|
|
25
|
+
lookupSections: [
|
|
26
|
+
{ key: "values", heading: "Values", kind: "table", showWhenEmpty: false },
|
|
27
|
+
],
|
|
28
|
+
emptyRecovery: (_filters: FilterConfig) => ({
|
|
29
|
+
message: "List available tokens.",
|
|
30
|
+
cli: "pragma token list",
|
|
31
|
+
mcp: { tool: "token_list" },
|
|
32
|
+
}),
|
|
33
|
+
notFoundRecovery: (_query: string) => ({
|
|
34
|
+
message: "List available tokens.",
|
|
35
|
+
cli: "pragma token list",
|
|
36
|
+
mcp: { tool: "token_list" },
|
|
37
|
+
}),
|
|
38
|
+
};
|
package/src/index.ts
CHANGED
|
@@ -53,7 +53,7 @@ describe("runMcpServer", () => {
|
|
|
53
53
|
const result = spawnSync("bun", ["run", binPath, "mcp"], {
|
|
54
54
|
input: "",
|
|
55
55
|
encoding: "utf-8",
|
|
56
|
-
timeout:
|
|
56
|
+
timeout: 20_000,
|
|
57
57
|
});
|
|
58
58
|
|
|
59
59
|
expect(result.error).toBeUndefined();
|
|
@@ -62,5 +62,5 @@ describe("runMcpServer", () => {
|
|
|
62
62
|
console.error("pragma mcp stderr:", result.stderr);
|
|
63
63
|
}
|
|
64
64
|
expect(result.status).toBe(0);
|
|
65
|
-
});
|
|
65
|
+
}, 20_000);
|
|
66
66
|
});
|
package/src/mcp/tools/index.ts
CHANGED
|
@@ -13,6 +13,7 @@ import { specs as configSpecs } from "../../domains/config/mcp/index.js";
|
|
|
13
13
|
import { specs as createSpecs } from "../../domains/create/mcp/index.js";
|
|
14
14
|
import { specs as diagnosticSpecs } from "../../domains/doctor/mcp/index.js";
|
|
15
15
|
import { specs as graphSpecs } from "../../domains/graph/mcp/index.js";
|
|
16
|
+
import { specs as infoSpecs } from "../../domains/info/mcp/index.js";
|
|
16
17
|
import { specs as orientationSpecs } from "../../domains/llm/mcp/index.js";
|
|
17
18
|
import { specs as modifierSpecs } from "../../domains/modifier/mcp/index.js";
|
|
18
19
|
import { specs as ontologySpecs } from "../../domains/ontology/mcp/index.js";
|
|
@@ -35,6 +36,7 @@ const allSpecs: readonly ToolSpec[] = [
|
|
|
35
36
|
...graphSpecs,
|
|
36
37
|
...skillSpecs,
|
|
37
38
|
...diagnosticSpecs,
|
|
39
|
+
...infoSpecs,
|
|
38
40
|
...orientationSpecs,
|
|
39
41
|
...createSpecs,
|
|
40
42
|
];
|
|
@@ -476,11 +476,15 @@ describe("config_show", () => {
|
|
|
476
476
|
arguments: {},
|
|
477
477
|
});
|
|
478
478
|
const data = parseData(result) as {
|
|
479
|
-
tier: string |
|
|
479
|
+
tier: string | undefined;
|
|
480
480
|
channel: string;
|
|
481
|
+
tierChain: string[];
|
|
482
|
+
includedReleases: string[];
|
|
481
483
|
};
|
|
482
484
|
expect(data.channel).toBe("normal");
|
|
483
|
-
expect(data.tier).
|
|
485
|
+
expect(data.tier).toBeUndefined();
|
|
486
|
+
expect(data.tierChain).toEqual([]);
|
|
487
|
+
expect(data.includedReleases).toContain("stable");
|
|
484
488
|
});
|
|
485
489
|
|
|
486
490
|
it("returns condensed config text", async () => {
|
|
@@ -491,7 +495,8 @@ describe("config_show", () => {
|
|
|
491
495
|
const envelope = parseEnvelope(result);
|
|
492
496
|
expect(envelope.ok).toBe(true);
|
|
493
497
|
expect(envelope.condensed).toBe(true);
|
|
494
|
-
expect(envelope.text).toBe("
|
|
498
|
+
expect(typeof envelope.text).toBe("string");
|
|
499
|
+
expect(envelope.text as string).toContain("Configuration");
|
|
495
500
|
});
|
|
496
501
|
});
|
|
497
502
|
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
type CommandDefinition,
|
|
3
|
+
detectRenderMode,
|
|
3
4
|
formatHelp,
|
|
4
5
|
formatLlmHelp,
|
|
6
|
+
type HandleResultOptions,
|
|
5
7
|
registerAll,
|
|
6
8
|
} from "@canonical/cli-core";
|
|
7
9
|
import { Command } from "commander";
|
|
@@ -35,6 +37,9 @@ export default function createProgram(
|
|
|
35
37
|
writeErr: (str) => process.stderr.write(str),
|
|
36
38
|
});
|
|
37
39
|
|
|
40
|
+
// Global flags (--llm, --format, --verbose) are pre-parsed by
|
|
41
|
+
// parseGlobalFlags() and stripped from argv before Commander sees it.
|
|
42
|
+
// Declaring them here keeps them visible in --help output.
|
|
38
43
|
program.option(
|
|
39
44
|
"--llm",
|
|
40
45
|
"Condensed Markdown output for LLM consumption",
|
|
@@ -42,6 +47,8 @@ export default function createProgram(
|
|
|
42
47
|
);
|
|
43
48
|
program.option("--format <type>", "Output format (text or json)", "text");
|
|
44
49
|
program.option("--verbose", "Diagnostic output to stderr", false);
|
|
50
|
+
// Commander will never see these flags in argv (they're stripped),
|
|
51
|
+
// so enablePositionalOptions() scoping can't reject them.
|
|
45
52
|
|
|
46
53
|
program.addHelpText("beforeAll", (_ctx) => {
|
|
47
54
|
// Only show root-level help when the help is for the root program itself.
|
|
@@ -64,7 +71,19 @@ export default function createProgram(
|
|
|
64
71
|
await runMcpServer();
|
|
65
72
|
});
|
|
66
73
|
|
|
67
|
-
|
|
74
|
+
const mode = detectRenderMode(ctx.globalFlags);
|
|
75
|
+
const resultOptions: HandleResultOptions = {
|
|
76
|
+
mode,
|
|
77
|
+
renderInk:
|
|
78
|
+
mode === "ink"
|
|
79
|
+
? async (element: unknown) => {
|
|
80
|
+
const { renderInk } = await import("#tui");
|
|
81
|
+
await renderInk(element as import("react").ReactElement);
|
|
82
|
+
}
|
|
83
|
+
: undefined,
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
registerAll(program, commands, ctx, resultOptions);
|
|
68
87
|
|
|
69
88
|
return program;
|
|
70
89
|
}
|
package/src/pipeline/index.ts
CHANGED
|
@@ -8,7 +8,10 @@ export {
|
|
|
8
8
|
formatSection,
|
|
9
9
|
} from "./formatTerminal.js";
|
|
10
10
|
export { default as mapExitCode } from "./mapExitCode.js";
|
|
11
|
-
export {
|
|
11
|
+
export {
|
|
12
|
+
default as parseGlobalFlags,
|
|
13
|
+
stripGlobalFlags,
|
|
14
|
+
} from "./parseGlobalFlags.js";
|
|
12
15
|
export {
|
|
13
16
|
renderErrorJson,
|
|
14
17
|
renderErrorLlm,
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import parseGlobalFlags, { stripGlobalFlags } from "./parseGlobalFlags.js";
|
|
3
|
+
|
|
4
|
+
describe("parseGlobalFlags", () => {
|
|
5
|
+
it("extracts --llm", () => {
|
|
6
|
+
const flags = parseGlobalFlags([
|
|
7
|
+
"node",
|
|
8
|
+
"pragma",
|
|
9
|
+
"block",
|
|
10
|
+
"list",
|
|
11
|
+
"--llm",
|
|
12
|
+
]);
|
|
13
|
+
expect(flags.llm).toBe(true);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it("extracts --format json", () => {
|
|
17
|
+
const flags = parseGlobalFlags([
|
|
18
|
+
"node",
|
|
19
|
+
"pragma",
|
|
20
|
+
"--format",
|
|
21
|
+
"json",
|
|
22
|
+
"info",
|
|
23
|
+
]);
|
|
24
|
+
expect(flags.format).toBe("json");
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it("defaults to text when --format is absent", () => {
|
|
28
|
+
const flags = parseGlobalFlags(["node", "pragma", "info"]);
|
|
29
|
+
expect(flags.format).toBe("text");
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it("extracts --verbose", () => {
|
|
33
|
+
const flags = parseGlobalFlags([
|
|
34
|
+
"node",
|
|
35
|
+
"pragma",
|
|
36
|
+
"--verbose",
|
|
37
|
+
"block",
|
|
38
|
+
"list",
|
|
39
|
+
]);
|
|
40
|
+
expect(flags.verbose).toBe(true);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
describe("stripGlobalFlags", () => {
|
|
45
|
+
it("removes --llm from any position", () => {
|
|
46
|
+
expect(
|
|
47
|
+
stripGlobalFlags(["node", "pragma", "--llm", "tier", "list"]),
|
|
48
|
+
).toEqual(["node", "pragma", "tier", "list"]);
|
|
49
|
+
expect(
|
|
50
|
+
stripGlobalFlags(["node", "pragma", "tier", "list", "--llm"]),
|
|
51
|
+
).toEqual(["node", "pragma", "tier", "list"]);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it("removes --format and its value", () => {
|
|
55
|
+
expect(
|
|
56
|
+
stripGlobalFlags(["node", "pragma", "--format", "json", "info"]),
|
|
57
|
+
).toEqual(["node", "pragma", "info"]);
|
|
58
|
+
expect(
|
|
59
|
+
stripGlobalFlags(["node", "pragma", "info", "--format", "json"]),
|
|
60
|
+
).toEqual(["node", "pragma", "info"]);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it("removes --verbose from any position", () => {
|
|
64
|
+
expect(
|
|
65
|
+
stripGlobalFlags(["node", "pragma", "block", "list", "--verbose"]),
|
|
66
|
+
).toEqual(["node", "pragma", "block", "list"]);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it("removes all global flags at once", () => {
|
|
70
|
+
expect(
|
|
71
|
+
stripGlobalFlags([
|
|
72
|
+
"node",
|
|
73
|
+
"pragma",
|
|
74
|
+
"--llm",
|
|
75
|
+
"--verbose",
|
|
76
|
+
"--format",
|
|
77
|
+
"json",
|
|
78
|
+
"block",
|
|
79
|
+
"list",
|
|
80
|
+
]),
|
|
81
|
+
).toEqual(["node", "pragma", "block", "list"]);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it("preserves argv when no global flags present", () => {
|
|
85
|
+
expect(stripGlobalFlags(["node", "pragma", "block", "list"])).toEqual([
|
|
86
|
+
"node",
|
|
87
|
+
"pragma",
|
|
88
|
+
"block",
|
|
89
|
+
"list",
|
|
90
|
+
]);
|
|
91
|
+
});
|
|
92
|
+
});
|
|
@@ -19,3 +19,28 @@ export default function parseGlobalFlags(argv: readonly string[]): GlobalFlags {
|
|
|
19
19
|
verbose: argv.includes("--verbose"),
|
|
20
20
|
};
|
|
21
21
|
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Return a copy of argv with global flags stripped out.
|
|
25
|
+
*
|
|
26
|
+
* Since {@link parseGlobalFlags} pre-parses these flags before Commander
|
|
27
|
+
* runs, we remove them so they don't collide with Commander's
|
|
28
|
+
* `enablePositionalOptions()` scoping. This lets users place `--llm`,
|
|
29
|
+
* `--format`, and `--verbose` anywhere in the command line.
|
|
30
|
+
*
|
|
31
|
+
* @param argv - Raw process.argv array.
|
|
32
|
+
* @returns New array with global flags removed.
|
|
33
|
+
*/
|
|
34
|
+
export function stripGlobalFlags(argv: readonly string[]): string[] {
|
|
35
|
+
const result: string[] = [];
|
|
36
|
+
for (let i = 0; i < argv.length; i++) {
|
|
37
|
+
const arg = argv[i];
|
|
38
|
+
if (arg === "--llm" || arg === "--verbose") continue;
|
|
39
|
+
if (arg === "--format") {
|
|
40
|
+
i += 1; // skip the value too
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
result.push(arg as string);
|
|
44
|
+
}
|
|
45
|
+
return result;
|
|
46
|
+
}
|
package/src/pipeline/runCli.ts
CHANGED
|
@@ -8,13 +8,14 @@ import { PragmaError } from "../error/index.js";
|
|
|
8
8
|
import collectCommands from "./collectCommands.js";
|
|
9
9
|
import createProgram from "./createProgram.js";
|
|
10
10
|
import mapExitCode from "./mapExitCode.js";
|
|
11
|
-
import parseGlobalFlags from "./parseGlobalFlags.js";
|
|
11
|
+
import parseGlobalFlags, { stripGlobalFlags } from "./parseGlobalFlags.js";
|
|
12
12
|
import {
|
|
13
13
|
renderErrorJson,
|
|
14
14
|
renderErrorLlm,
|
|
15
15
|
renderErrorPlain,
|
|
16
16
|
} from "./renderError.js";
|
|
17
17
|
import resolveCommandKind from "./resolveCommandKind.js";
|
|
18
|
+
import runInteractiveCommand from "./runInteractiveCommand.js";
|
|
18
19
|
|
|
19
20
|
function hasCommandArg(argv: readonly string[]): boolean {
|
|
20
21
|
const args = argv.slice(2);
|
|
@@ -78,6 +79,7 @@ async function handleRootHelp(globalFlags: GlobalFlags): Promise<void> {
|
|
|
78
79
|
cwd: process.cwd(),
|
|
79
80
|
dispose: () => {},
|
|
80
81
|
globalFlags,
|
|
82
|
+
interactive: runInteractiveCommand,
|
|
81
83
|
};
|
|
82
84
|
const commands = collectCommands(stubCtx);
|
|
83
85
|
const program = createProgram(commands, stubCtx);
|
|
@@ -111,10 +113,14 @@ async function bootAndRun(
|
|
|
111
113
|
}
|
|
112
114
|
|
|
113
115
|
try {
|
|
114
|
-
const ctx: PragmaContext = {
|
|
116
|
+
const ctx: PragmaContext = {
|
|
117
|
+
...runtime,
|
|
118
|
+
globalFlags,
|
|
119
|
+
interactive: runInteractiveCommand,
|
|
120
|
+
};
|
|
115
121
|
const commands = collectCommands(ctx);
|
|
116
122
|
const program = createProgram(commands, ctx);
|
|
117
|
-
await program.parseAsync(argv);
|
|
123
|
+
await program.parseAsync(stripGlobalFlags(argv));
|
|
118
124
|
} catch (err) {
|
|
119
125
|
handleProgramError(err, globalFlags);
|
|
120
126
|
} finally {
|
|
@@ -132,12 +138,13 @@ async function runStoreSkip(
|
|
|
132
138
|
cwd: process.cwd(),
|
|
133
139
|
dispose: () => {},
|
|
134
140
|
globalFlags,
|
|
141
|
+
interactive: runInteractiveCommand,
|
|
135
142
|
};
|
|
136
143
|
const commands = [...setupCommands()];
|
|
137
144
|
const program = createProgram(commands, stubCtx);
|
|
138
145
|
|
|
139
146
|
try {
|
|
140
|
-
await program.parseAsync(argv);
|
|
147
|
+
await program.parseAsync(stripGlobalFlags(argv));
|
|
141
148
|
} catch (err) {
|
|
142
149
|
handleProgramError(err, globalFlags);
|
|
143
150
|
}
|