@osovv/grace-cli 3.2.0 → 3.3.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 +5 -10
- package/package.json +1 -1
- package/src/grace-lint.ts +0 -8
- package/src/grace.ts +1 -1
- package/src/lint/config.ts +18 -4
- package/src/lint/core.ts +5 -59
- package/src/lint/types.ts +0 -6
package/README.md
CHANGED
|
@@ -10,13 +10,13 @@ This repository packages GRACE as reusable skills for coding agents. The current
|
|
|
10
10
|
- knowledge-graph synchronization
|
|
11
11
|
- controller-managed sequential or multi-agent implementation
|
|
12
12
|
|
|
13
|
-
Current packaged version: `3.
|
|
13
|
+
Current packaged version: `3.3.0`
|
|
14
14
|
|
|
15
15
|
## What Changed In This Version
|
|
16
16
|
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
17
|
+
- Removed profile selection from `grace lint`; the CLI now validates only against the current GRACE artifact set.
|
|
18
|
+
- Limited `.grace-lint.json` to the current config schema, such as `ignoredDirs`.
|
|
19
|
+
- Kept the role-aware/adaptive lint model while making older GRACE repos fail loudly until they are updated.
|
|
20
20
|
|
|
21
21
|
## Repository Layout
|
|
22
22
|
|
|
@@ -215,16 +215,11 @@ Optional repository config file:
|
|
|
215
215
|
|
|
216
216
|
```json
|
|
217
217
|
{
|
|
218
|
-
"profile": "auto",
|
|
219
218
|
"ignoredDirs": ["tmp"]
|
|
220
219
|
}
|
|
221
220
|
```
|
|
222
221
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
- `auto` => require `docs/verification-plan.xml` only when the repo already looks verification-aware
|
|
226
|
-
- `current` => require current GRACE artifacts
|
|
227
|
-
- `legacy` => allow older GRACE repos without a verification plan
|
|
222
|
+
`grace lint` is current-only. Older GRACE repositories should fail until they are updated to the current artifact set, especially `docs/verification-plan.xml`.
|
|
228
223
|
|
|
229
224
|
The validator checks marketplace/plugin metadata sync, version consistency, required fields, `.claude-plugin` structure, and hardcoded absolute paths. In branch or PR context it scopes validation to changed plugins via `git diff origin/main...HEAD`; otherwise it validates all plugins.
|
|
230
225
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@osovv/grace-cli",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.3.0",
|
|
4
4
|
"description": "GRACE CLI for linting semantic markup, contracts, and GRACE XML artifacts with a Bun-powered grace binary.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://github.com/osovv/grace-marketplace#readme",
|
package/src/grace-lint.ts
CHANGED
|
@@ -6,7 +6,6 @@ import { formatTextReport, isValidTextFormat, lintGraceProject } from "./lint/co
|
|
|
6
6
|
import type { LintOptions, LintResult } from "./lint/types";
|
|
7
7
|
|
|
8
8
|
export type {
|
|
9
|
-
EffectiveProfile,
|
|
10
9
|
GraceLintConfig,
|
|
11
10
|
LanguageAdapter,
|
|
12
11
|
LanguageAnalysis,
|
|
@@ -16,7 +15,6 @@ export type {
|
|
|
16
15
|
LintSeverity,
|
|
17
16
|
MapMode,
|
|
18
17
|
ModuleRole,
|
|
19
|
-
RepoProfile,
|
|
20
18
|
} from "./lint/types";
|
|
21
19
|
|
|
22
20
|
export { formatTextReport, lintGraceProject } from "./lint/core";
|
|
@@ -48,11 +46,6 @@ export const lintCommand = defineCommand({
|
|
|
48
46
|
description: "Output format: text or json",
|
|
49
47
|
default: "text",
|
|
50
48
|
},
|
|
51
|
-
profile: {
|
|
52
|
-
type: "string",
|
|
53
|
-
description: "Lint profile: auto, current, or legacy",
|
|
54
|
-
default: "auto",
|
|
55
|
-
},
|
|
56
49
|
allowMissingDocs: {
|
|
57
50
|
type: "boolean",
|
|
58
51
|
description: "Allow repositories that do not yet have full GRACE docs",
|
|
@@ -67,7 +60,6 @@ export const lintCommand = defineCommand({
|
|
|
67
60
|
|
|
68
61
|
const result = lintGraceProject(String(context.args.path ?? "."), {
|
|
69
62
|
allowMissingDocs: Boolean(context.args.allowMissingDocs),
|
|
70
|
-
profile: String(context.args.profile ?? "auto") as LintOptions["profile"],
|
|
71
63
|
});
|
|
72
64
|
|
|
73
65
|
writeResult(format, result);
|
package/src/grace.ts
CHANGED
package/src/lint/config.ts
CHANGED
|
@@ -4,7 +4,7 @@ import path from "node:path";
|
|
|
4
4
|
import type { GraceLintConfig, LintIssue } from "./types";
|
|
5
5
|
|
|
6
6
|
const CONFIG_FILE_NAME = ".grace-lint.json";
|
|
7
|
-
const
|
|
7
|
+
const SUPPORTED_KEYS = new Set(["ignoredDirs"]);
|
|
8
8
|
|
|
9
9
|
export function loadGraceLintConfig(projectRoot: string) {
|
|
10
10
|
const configPath = path.join(projectRoot, CONFIG_FILE_NAME);
|
|
@@ -16,12 +16,26 @@ export function loadGraceLintConfig(projectRoot: string) {
|
|
|
16
16
|
const parsed = JSON.parse(readFileSync(configPath, "utf8")) as GraceLintConfig;
|
|
17
17
|
const issues: LintIssue[] = [];
|
|
18
18
|
|
|
19
|
-
if (parsed
|
|
19
|
+
if (!parsed || Array.isArray(parsed) || typeof parsed !== "object") {
|
|
20
20
|
issues.push({
|
|
21
21
|
severity: "error",
|
|
22
|
-
code: "config.invalid-
|
|
22
|
+
code: "config.invalid-shape",
|
|
23
23
|
file: CONFIG_FILE_NAME,
|
|
24
|
-
message:
|
|
24
|
+
message: `${CONFIG_FILE_NAME} must contain a JSON object.`,
|
|
25
|
+
});
|
|
26
|
+
return { config: parsed, issues };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
for (const key of Object.keys(parsed)) {
|
|
30
|
+
if (SUPPORTED_KEYS.has(key)) {
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
issues.push({
|
|
35
|
+
severity: "error",
|
|
36
|
+
code: "config.unknown-key",
|
|
37
|
+
file: CONFIG_FILE_NAME,
|
|
38
|
+
message: `Unsupported key \`${key}\` in ${CONFIG_FILE_NAME}. Supported keys: ignoredDirs.`,
|
|
25
39
|
});
|
|
26
40
|
}
|
|
27
41
|
|
package/src/lint/core.ts
CHANGED
|
@@ -4,7 +4,6 @@ import path from "node:path";
|
|
|
4
4
|
import { loadGraceLintConfig } from "./config";
|
|
5
5
|
import { getLanguageAdapter } from "./adapters/base";
|
|
6
6
|
import type {
|
|
7
|
-
EffectiveProfile,
|
|
8
7
|
GraceLintConfig,
|
|
9
8
|
LanguageAnalysis,
|
|
10
9
|
LintIssue,
|
|
@@ -15,13 +14,9 @@ import type {
|
|
|
15
14
|
ModuleContractInfo,
|
|
16
15
|
ModuleMapItem,
|
|
17
16
|
ModuleRole,
|
|
18
|
-
RepoProfile,
|
|
19
17
|
} from "./types";
|
|
20
18
|
|
|
21
|
-
const
|
|
22
|
-
legacy: ["docs/knowledge-graph.xml", "docs/development-plan.xml"],
|
|
23
|
-
current: ["docs/knowledge-graph.xml", "docs/development-plan.xml", "docs/verification-plan.xml"],
|
|
24
|
-
};
|
|
19
|
+
const REQUIRED_DOCS = ["docs/knowledge-graph.xml", "docs/development-plan.xml", "docs/verification-plan.xml"] as const;
|
|
25
20
|
|
|
26
21
|
const OPTIONAL_PACKET_DOC = "docs/operational-packets.xml";
|
|
27
22
|
const LINT_CONFIG_FILE = ".grace-lint.json";
|
|
@@ -557,46 +552,6 @@ function lintRequiredPacketSections(result: LintResult, relativePath: string, te
|
|
|
557
552
|
}
|
|
558
553
|
}
|
|
559
554
|
|
|
560
|
-
function resolveProfile(
|
|
561
|
-
requestedProfile: RepoProfile | undefined,
|
|
562
|
-
configProfile: RepoProfile | undefined,
|
|
563
|
-
docs: Record<string, string | null>,
|
|
564
|
-
) {
|
|
565
|
-
const desiredProfile = requestedProfile ?? configProfile ?? "auto";
|
|
566
|
-
if (desiredProfile !== "auto") {
|
|
567
|
-
return desiredProfile;
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
const verificationPlan = docs["docs/verification-plan.xml"];
|
|
571
|
-
if (verificationPlan) {
|
|
572
|
-
return "current" as const;
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
const joinedDocs = `${docs["docs/knowledge-graph.xml"] ?? ""}\n${docs["docs/development-plan.xml"] ?? ""}`;
|
|
576
|
-
return /<verification-ref>|<V-M-/.test(joinedDocs) ? "current" : "legacy";
|
|
577
|
-
}
|
|
578
|
-
|
|
579
|
-
function validateProfileSelection(profile: string | undefined) {
|
|
580
|
-
if (!profile) {
|
|
581
|
-
return null;
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
if (profile === "auto" || profile === "current" || profile === "legacy") {
|
|
585
|
-
return null;
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
return {
|
|
589
|
-
severity: "error",
|
|
590
|
-
code: "config.invalid-profile-selection",
|
|
591
|
-
file: "CLI",
|
|
592
|
-
message: `Unsupported profile \`${profile}\`. Use \`auto\`, \`current\`, or \`legacy\`.`,
|
|
593
|
-
} satisfies LintIssue;
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
function isInvalidProfileIssue(issue: LintIssue) {
|
|
597
|
-
return issue.code === "config.invalid-profile" || issue.code === "config.invalid-profile-selection";
|
|
598
|
-
}
|
|
599
|
-
|
|
600
555
|
function lintExportMapParity(
|
|
601
556
|
result: LintResult,
|
|
602
557
|
relativePath: string,
|
|
@@ -771,11 +726,6 @@ function lintGovernedFile(result: LintResult, root: string, filePath: string, te
|
|
|
771
726
|
export function lintGraceProject(projectRoot: string, options: LintOptions = {}): LintResult {
|
|
772
727
|
const root = path.resolve(projectRoot);
|
|
773
728
|
const { config, issues: configIssues } = loadGraceLintConfig(root);
|
|
774
|
-
const requestedProfileIssue = validateProfileSelection(options.profile as string | undefined);
|
|
775
|
-
const effectiveRequestedProfile = requestedProfileIssue ? undefined : options.profile;
|
|
776
|
-
const effectiveConfigProfile = configIssues.some((issue) => issue.code === "config.invalid-profile")
|
|
777
|
-
? undefined
|
|
778
|
-
: config?.profile;
|
|
779
729
|
|
|
780
730
|
const docs = {
|
|
781
731
|
"docs/knowledge-graph.xml": readTextIfExists(path.join(root, "docs/knowledge-graph.xml")),
|
|
@@ -783,29 +733,26 @@ export function lintGraceProject(projectRoot: string, options: LintOptions = {})
|
|
|
783
733
|
"docs/verification-plan.xml": readTextIfExists(path.join(root, "docs/verification-plan.xml")),
|
|
784
734
|
} satisfies Record<string, string | null>;
|
|
785
735
|
|
|
786
|
-
const profile = resolveProfile(effectiveRequestedProfile, effectiveConfigProfile, docs);
|
|
787
736
|
const result: LintResult = {
|
|
788
737
|
root,
|
|
789
|
-
profile,
|
|
790
738
|
filesChecked: 0,
|
|
791
739
|
governedFiles: 0,
|
|
792
740
|
xmlFilesChecked: 0,
|
|
793
|
-
issues: [...configIssues
|
|
741
|
+
issues: [...configIssues],
|
|
794
742
|
};
|
|
795
743
|
|
|
796
|
-
if (configIssues.some((issue) => issue.severity === "error" && issue.file === LINT_CONFIG_FILE
|
|
744
|
+
if (configIssues.some((issue) => issue.severity === "error" && issue.file === LINT_CONFIG_FILE)) {
|
|
797
745
|
return result;
|
|
798
746
|
}
|
|
799
747
|
|
|
800
|
-
const requiredDocs = REQUIRED_DOCS_BY_PROFILE[profile];
|
|
801
748
|
if (!options.allowMissingDocs) {
|
|
802
|
-
for (const relativePath of
|
|
749
|
+
for (const relativePath of REQUIRED_DOCS) {
|
|
803
750
|
if (!docs[relativePath]) {
|
|
804
751
|
addIssue(result, {
|
|
805
752
|
severity: "error",
|
|
806
753
|
code: "docs.missing-required-artifact",
|
|
807
754
|
file: relativePath,
|
|
808
|
-
message: `Missing required GRACE artifact \`${relativePath}
|
|
755
|
+
message: `Missing required current GRACE artifact \`${relativePath}\`.`,
|
|
809
756
|
});
|
|
810
757
|
}
|
|
811
758
|
}
|
|
@@ -928,7 +875,6 @@ export function formatTextReport(result: LintResult) {
|
|
|
928
875
|
"GRACE Lint Report",
|
|
929
876
|
"=================",
|
|
930
877
|
`Root: ${result.root}`,
|
|
931
|
-
`Profile: ${result.profile}`,
|
|
932
878
|
`Code files checked: ${result.filesChecked}`,
|
|
933
879
|
`Governed files checked: ${result.governedFiles}`,
|
|
934
880
|
`XML files checked: ${result.xmlFilesChecked}`,
|
package/src/lint/types.ts
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
export type LintSeverity = "error" | "warning";
|
|
2
2
|
|
|
3
|
-
export type RepoProfile = "auto" | "current" | "legacy";
|
|
4
|
-
export type EffectiveProfile = Exclude<RepoProfile, "auto">;
|
|
5
|
-
|
|
6
3
|
export type ModuleRole = "RUNTIME" | "TEST" | "BARREL" | "CONFIG" | "TYPES" | "SCRIPT";
|
|
7
4
|
export type MapMode = "EXPORTS" | "LOCALS" | "SUMMARY" | "NONE";
|
|
8
5
|
|
|
@@ -16,7 +13,6 @@ export type LintIssue = {
|
|
|
16
13
|
|
|
17
14
|
export type LintResult = {
|
|
18
15
|
root: string;
|
|
19
|
-
profile: EffectiveProfile;
|
|
20
16
|
filesChecked: number;
|
|
21
17
|
governedFiles: number;
|
|
22
18
|
xmlFilesChecked: number;
|
|
@@ -25,11 +21,9 @@ export type LintResult = {
|
|
|
25
21
|
|
|
26
22
|
export type LintOptions = {
|
|
27
23
|
allowMissingDocs?: boolean;
|
|
28
|
-
profile?: RepoProfile;
|
|
29
24
|
};
|
|
30
25
|
|
|
31
26
|
export type GraceLintConfig = {
|
|
32
|
-
profile?: RepoProfile;
|
|
33
27
|
ignoredDirs?: string[];
|
|
34
28
|
};
|
|
35
29
|
|