@osovv/grace-cli 3.4.0 → 3.6.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/README.md +26 -4
- package/package.json +5 -2
- package/src/grace-file.ts +78 -0
- package/src/grace-module.ts +126 -0
- package/src/grace.ts +6 -2
- package/src/query/core.ts +817 -0
- package/src/query/render.ts +188 -0
- package/src/query/types.ts +134 -0
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import type { FileMarkupRecord, ModuleMatch, ModuleRecord, ModuleVerificationRecord } from "./types";
|
|
2
|
+
import { getModuleDepends, getModuleName, getModulePath, getModuleType, getModuleVerificationIds } from "./core";
|
|
3
|
+
|
|
4
|
+
function formatList(label: string, items: string[]) {
|
|
5
|
+
if (items.length === 0) {
|
|
6
|
+
return [`${label}: none`];
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
return [label, ...items.map((item) => `- ${item}`)];
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function formatFieldMap(fields: Record<string, string>) {
|
|
13
|
+
const entries = Object.entries(fields);
|
|
14
|
+
if (entries.length === 0) {
|
|
15
|
+
return ["- none"];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return entries.map(([key, value]) => `- ${key}: ${value}`);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function formatVerificationDetails(entry: ModuleVerificationRecord) {
|
|
22
|
+
const lines = [
|
|
23
|
+
`Verification ${entry.id}`,
|
|
24
|
+
`- Module: ${entry.moduleId ?? "unknown"}`,
|
|
25
|
+
`- Priority: ${entry.priority ?? "n/a"}`,
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
lines.push(...formatList("Test Files", entry.testFiles));
|
|
29
|
+
lines.push(...formatList("Module Checks", entry.moduleChecks));
|
|
30
|
+
|
|
31
|
+
if (entry.scenarios.length > 0) {
|
|
32
|
+
lines.push("Scenarios");
|
|
33
|
+
for (const scenario of entry.scenarios) {
|
|
34
|
+
const prefix = scenario.kind ? `${scenario.tag} (${scenario.kind})` : scenario.tag;
|
|
35
|
+
lines.push(`- ${prefix}: ${scenario.text}`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
lines.push(...formatList("Required Log Markers", entry.requiredLogMarkers));
|
|
40
|
+
lines.push(...formatList("Required Trace Assertions", entry.requiredTraceAssertions));
|
|
41
|
+
|
|
42
|
+
if (entry.waveFollowUp) {
|
|
43
|
+
lines.push(`- Wave Follow-Up: ${entry.waveFollowUp}`);
|
|
44
|
+
}
|
|
45
|
+
if (entry.phaseFollowUp) {
|
|
46
|
+
lines.push(`- Phase Follow-Up: ${entry.phaseFollowUp}`);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return lines;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function renderTable(rows: string[][], headers: string[]) {
|
|
53
|
+
const widths = headers.map((header, index) => Math.max(header.length, ...rows.map((row) => row[index]?.length ?? 0)));
|
|
54
|
+
const formatRow = (row: string[]) => row.map((cell, index) => cell.padEnd(widths[index])).join(" ");
|
|
55
|
+
|
|
56
|
+
const separator = widths.map((width) => "-".repeat(width)).join(" ");
|
|
57
|
+
return [formatRow(headers), separator, ...rows.map((row) => formatRow(row))].join("\n");
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function formatModuleFindTable(matches: ModuleMatch[]) {
|
|
61
|
+
if (matches.length === 0) {
|
|
62
|
+
return "No modules found.";
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const rows = matches.map(({ module }) => [
|
|
66
|
+
module.id,
|
|
67
|
+
getModuleName(module),
|
|
68
|
+
getModuleType(module) ?? "-",
|
|
69
|
+
getModulePath(module) ?? "-",
|
|
70
|
+
getModuleVerificationIds(module).join(", ") || "-",
|
|
71
|
+
]);
|
|
72
|
+
|
|
73
|
+
return renderTable(rows, ["ID", "NAME", "TYPE", "PATH", "VERIFICATION"]);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function formatModuleText(moduleRecord: ModuleRecord, options: { withVerification: boolean }) {
|
|
77
|
+
const lines = [
|
|
78
|
+
"GRACE Module",
|
|
79
|
+
"============",
|
|
80
|
+
`ID: ${moduleRecord.id}`,
|
|
81
|
+
`Name: ${getModuleName(moduleRecord)}`,
|
|
82
|
+
`Type: ${getModuleType(moduleRecord) ?? "unknown"}`,
|
|
83
|
+
`Graph Path: ${moduleRecord.graph?.path ?? "n/a"}`,
|
|
84
|
+
`Verification: ${getModuleVerificationIds(moduleRecord).join(", ") || "none"}`,
|
|
85
|
+
`Dependencies: ${getModuleDepends(moduleRecord).join(", ") || "none"}`,
|
|
86
|
+
];
|
|
87
|
+
|
|
88
|
+
if (moduleRecord.plan) {
|
|
89
|
+
lines.push("", "Plan Contract");
|
|
90
|
+
lines.push(`- Purpose: ${moduleRecord.plan.contract.purpose ?? "n/a"}`);
|
|
91
|
+
lines.push(...formatList("Inputs", moduleRecord.plan.contract.inputs.map((input) => input.text)));
|
|
92
|
+
lines.push(...formatList("Outputs", moduleRecord.plan.contract.outputs.map((output) => output.text)));
|
|
93
|
+
lines.push(...formatList("Errors", moduleRecord.plan.contract.errors));
|
|
94
|
+
|
|
95
|
+
lines.push("", "Public Interface (Plan)");
|
|
96
|
+
lines.push(
|
|
97
|
+
...(moduleRecord.plan.interfaceItems.length > 0
|
|
98
|
+
? moduleRecord.plan.interfaceItems.map((item) => `- ${item.tag}${item.purpose ? `: ${item.purpose}` : ""}`)
|
|
99
|
+
: ["- none"]),
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (moduleRecord.graph) {
|
|
104
|
+
lines.push("", "Knowledge Graph");
|
|
105
|
+
lines.push(`- Purpose: ${moduleRecord.graph.purpose ?? "n/a"}`);
|
|
106
|
+
lines.push(`- Status: ${moduleRecord.graph.status ?? "n/a"}`);
|
|
107
|
+
lines.push(
|
|
108
|
+
...(moduleRecord.graph.annotations.length > 0
|
|
109
|
+
? moduleRecord.graph.annotations.map((item) => `- ${item.tag}${item.purpose ? `: ${item.purpose}` : ""}`)
|
|
110
|
+
: ["- Annotations: none"]),
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
lines.push("", "Linked Files");
|
|
115
|
+
lines.push(...(moduleRecord.localFiles.length > 0 ? moduleRecord.localFiles.map((file) => `- ${file.path}`) : ["- none"]));
|
|
116
|
+
|
|
117
|
+
lines.push("", "Plan Steps");
|
|
118
|
+
lines.push(
|
|
119
|
+
...(moduleRecord.steps.length > 0
|
|
120
|
+
? moduleRecord.steps.map(
|
|
121
|
+
(step) =>
|
|
122
|
+
`- ${step.phaseTag}${step.phaseName ? ` (${step.phaseName})` : ""} / ${step.stepTag}${step.stepStatus ? ` [${step.stepStatus}]` : ""}: ${step.text}`,
|
|
123
|
+
)
|
|
124
|
+
: ["- none"]),
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
if (options.withVerification) {
|
|
128
|
+
lines.push("", "Verification");
|
|
129
|
+
if (moduleRecord.verifications.length === 0) {
|
|
130
|
+
lines.push("- none");
|
|
131
|
+
} else {
|
|
132
|
+
for (const entry of moduleRecord.verifications) {
|
|
133
|
+
lines.push(...formatVerificationDetails(entry), "");
|
|
134
|
+
}
|
|
135
|
+
if (lines[lines.length - 1] === "") {
|
|
136
|
+
lines.pop();
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return lines.join("\n");
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export function formatFileText(
|
|
145
|
+
fileRecord: FileMarkupRecord,
|
|
146
|
+
options: { includeContracts: boolean; includeBlocks: boolean },
|
|
147
|
+
) {
|
|
148
|
+
const lines = [
|
|
149
|
+
"GRACE File",
|
|
150
|
+
"==========",
|
|
151
|
+
`Path: ${fileRecord.path}`,
|
|
152
|
+
`Linked Modules: ${fileRecord.linkedModuleIds.join(", ") || "none"}`,
|
|
153
|
+
`Contracts: ${fileRecord.contracts.length}`,
|
|
154
|
+
`Blocks: ${fileRecord.blocks.length}`,
|
|
155
|
+
"",
|
|
156
|
+
"MODULE_CONTRACT",
|
|
157
|
+
...formatFieldMap(fileRecord.moduleContract?.fields ?? {}),
|
|
158
|
+
"",
|
|
159
|
+
"MODULE_MAP",
|
|
160
|
+
...(fileRecord.moduleMap.length > 0 ? fileRecord.moduleMap.map((item) => `- ${item.label}`) : ["- none"]),
|
|
161
|
+
"",
|
|
162
|
+
"CHANGE_SUMMARY",
|
|
163
|
+
...formatFieldMap(fileRecord.changeSummary?.fields ?? {}),
|
|
164
|
+
];
|
|
165
|
+
|
|
166
|
+
if (options.includeContracts) {
|
|
167
|
+
lines.push("", "Contracts");
|
|
168
|
+
if (fileRecord.contracts.length === 0) {
|
|
169
|
+
lines.push("- none");
|
|
170
|
+
} else {
|
|
171
|
+
for (const contract of fileRecord.contracts) {
|
|
172
|
+
lines.push(`Contract ${contract.name} (lines ${contract.startLine}-${contract.endLine})`);
|
|
173
|
+
lines.push(...formatFieldMap(contract.fields));
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (options.includeBlocks) {
|
|
179
|
+
lines.push("", "Blocks");
|
|
180
|
+
lines.push(
|
|
181
|
+
...(fileRecord.blocks.length > 0
|
|
182
|
+
? fileRecord.blocks.map((block) => `- ${block.name} (lines ${block.startLine}-${block.endLine})`)
|
|
183
|
+
: ["- none"]),
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return lines.join("\n");
|
|
188
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
export type ModulePlanParam = {
|
|
2
|
+
name?: string;
|
|
3
|
+
type?: string;
|
|
4
|
+
text: string;
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export type ModulePlanContract = {
|
|
8
|
+
purpose?: string;
|
|
9
|
+
inputs: ModulePlanParam[];
|
|
10
|
+
outputs: ModulePlanParam[];
|
|
11
|
+
errors: string[];
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export type ModuleInterfaceItem = {
|
|
15
|
+
tag: string;
|
|
16
|
+
purpose?: string;
|
|
17
|
+
text?: string;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export type ModulePlanRecord = {
|
|
21
|
+
id: string;
|
|
22
|
+
name?: string;
|
|
23
|
+
type?: string;
|
|
24
|
+
layer?: string;
|
|
25
|
+
order?: string;
|
|
26
|
+
depends: string[];
|
|
27
|
+
contract: ModulePlanContract;
|
|
28
|
+
interfaceItems: ModuleInterfaceItem[];
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export type ModuleGraphRecord = {
|
|
32
|
+
id: string;
|
|
33
|
+
name?: string;
|
|
34
|
+
type?: string;
|
|
35
|
+
status?: string;
|
|
36
|
+
purpose?: string;
|
|
37
|
+
path?: string;
|
|
38
|
+
depends: string[];
|
|
39
|
+
annotations: ModuleInterfaceItem[];
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export type VerificationScenario = {
|
|
43
|
+
tag: string;
|
|
44
|
+
kind?: string;
|
|
45
|
+
text: string;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export type ModuleVerificationRecord = {
|
|
49
|
+
id: string;
|
|
50
|
+
moduleId?: string;
|
|
51
|
+
priority?: string;
|
|
52
|
+
testFiles: string[];
|
|
53
|
+
moduleChecks: string[];
|
|
54
|
+
scenarios: VerificationScenario[];
|
|
55
|
+
requiredLogMarkers: string[];
|
|
56
|
+
requiredTraceAssertions: string[];
|
|
57
|
+
waveFollowUp?: string;
|
|
58
|
+
phaseFollowUp?: string;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export type PlanStepRecord = {
|
|
62
|
+
phaseTag: string;
|
|
63
|
+
phaseName?: string;
|
|
64
|
+
phaseStatus?: string;
|
|
65
|
+
stepTag: string;
|
|
66
|
+
stepStatus?: string;
|
|
67
|
+
moduleId?: string;
|
|
68
|
+
verificationId?: string;
|
|
69
|
+
text: string;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export type FileFieldSection = {
|
|
73
|
+
fields: Record<string, string>;
|
|
74
|
+
startLine: number;
|
|
75
|
+
endLine: number;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
export type FileListItem = {
|
|
79
|
+
label: string;
|
|
80
|
+
line: number;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
export type FileContractRecord = {
|
|
84
|
+
name: string;
|
|
85
|
+
fields: Record<string, string>;
|
|
86
|
+
startLine: number;
|
|
87
|
+
endLine: number;
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
export type FileBlockRecord = {
|
|
91
|
+
name: string;
|
|
92
|
+
startLine: number;
|
|
93
|
+
endLine: number;
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
export type FileMarkupRecord = {
|
|
97
|
+
path: string;
|
|
98
|
+
moduleContract: FileFieldSection | null;
|
|
99
|
+
moduleMap: FileListItem[];
|
|
100
|
+
changeSummary: FileFieldSection | null;
|
|
101
|
+
contracts: FileContractRecord[];
|
|
102
|
+
blocks: FileBlockRecord[];
|
|
103
|
+
linkedModuleIds: string[];
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
export type ModuleRecord = {
|
|
107
|
+
id: string;
|
|
108
|
+
name?: string;
|
|
109
|
+
type?: string;
|
|
110
|
+
plan: ModulePlanRecord | null;
|
|
111
|
+
graph: ModuleGraphRecord | null;
|
|
112
|
+
verifications: ModuleVerificationRecord[];
|
|
113
|
+
localFiles: FileMarkupRecord[];
|
|
114
|
+
steps: PlanStepRecord[];
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
export type GraceArtifactIndex = {
|
|
118
|
+
root: string;
|
|
119
|
+
modules: ModuleRecord[];
|
|
120
|
+
verifications: ModuleVerificationRecord[];
|
|
121
|
+
files: FileMarkupRecord[];
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
export type ModuleFindOptions = {
|
|
125
|
+
query?: string;
|
|
126
|
+
type?: string;
|
|
127
|
+
dependsOn?: string;
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
export type ModuleMatch = {
|
|
131
|
+
module: ModuleRecord;
|
|
132
|
+
score: number;
|
|
133
|
+
matchedBy: string[];
|
|
134
|
+
};
|