@fragments-sdk/cli 0.14.3 → 0.15.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 +0 -3
- package/dist/bin.js +4290 -3754
- package/dist/bin.js.map +1 -1
- package/dist/{chunk-TXFCEDOC.js → chunk-2WXKALIG.js} +2 -2
- package/dist/{chunk-I34BC3CU.js → chunk-32LIWN2P.js} +1006 -3
- package/dist/chunk-32LIWN2P.js.map +1 -0
- package/dist/{chunk-55KERLWL.js → chunk-65WSVDV5.js} +314 -89
- package/dist/chunk-65WSVDV5.js.map +1 -0
- package/dist/chunk-7DZC4YEV.js +294 -0
- package/dist/chunk-7DZC4YEV.js.map +1 -0
- package/dist/{chunk-LOYS64QS.js → chunk-7WHVW72L.js} +230 -19
- package/dist/chunk-7WHVW72L.js.map +1 -0
- package/dist/{chunk-PJT5IZ37.js → chunk-BJE3425I.js} +19 -52
- package/dist/{chunk-PJT5IZ37.js.map → chunk-BJE3425I.js.map} +1 -1
- package/dist/{chunk-5A6X2Y73.js → chunk-CZD3AD4Q.js} +12 -11
- package/dist/chunk-CZD3AD4Q.js.map +1 -0
- package/dist/{chunk-EYXVAMEX.js → chunk-MN3TJ3D5.js} +72 -3
- package/dist/chunk-MN3TJ3D5.js.map +1 -0
- package/dist/chunk-QCN35LJU.js +630 -0
- package/dist/chunk-QCN35LJU.js.map +1 -0
- package/dist/chunk-T47OLCSF.js +36 -0
- package/dist/chunk-T47OLCSF.js.map +1 -0
- package/dist/{chunk-APTQIBS5.js → chunk-XJQ5BIWI.js} +144 -1049
- package/dist/chunk-XJQ5BIWI.js.map +1 -0
- package/dist/codebase-scanner-VOTPXRYW.js +22 -0
- package/dist/converter-JLINP7CJ.js +34 -0
- package/dist/converter-JLINP7CJ.js.map +1 -0
- package/dist/core/index.js +43 -1
- package/dist/{generate-RYWIPDN2.js → generate-A4FP5426.js} +3 -4
- package/dist/{generate-RYWIPDN2.js.map → generate-A4FP5426.js.map} +1 -1
- package/dist/govern-scan-UCBZR6D6.js +280 -0
- package/dist/govern-scan-UCBZR6D6.js.map +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +11 -11
- package/dist/{init-WRUSW7R5.js → init-HGSM35XA.js} +131 -128
- package/dist/init-HGSM35XA.js.map +1 -0
- package/dist/{init-cloud-REQ3XLHO.js → init-cloud-MQ6GRJAZ.js} +2 -2
- package/dist/mcp-bin.js +5 -36
- package/dist/mcp-bin.js.map +1 -1
- package/dist/scan-VNNKACG2.js +15 -0
- package/dist/{scan-generate-TFZVL3BT.js → scan-generate-TWRHNU5M.js} +335 -46
- package/dist/scan-generate-TWRHNU5M.js.map +1 -0
- package/dist/scanner-7LAZYPWZ.js +13 -0
- package/dist/{service-HKJ6B7P7.js → service-FHQU7YS7.js} +27 -23
- package/dist/{snapshot-C5DYIGIV.js → snapshot-KQEQ6XHL.js} +2 -2
- package/dist/{static-viewer-DUVC4UIM.js → static-viewer-63PG6FWY.js} +3 -3
- package/dist/static-viewer-63PG6FWY.js.map +1 -0
- package/dist/{test-JW7JIDFG.js → test-UQYUCZIS.js} +4 -6
- package/dist/{test-JW7JIDFG.js.map → test-UQYUCZIS.js.map} +1 -1
- package/dist/{tokens-KE73G5JC.js → tokens-6GYKDV6U.js} +6 -5
- package/dist/{tokens-KE73G5JC.js.map → tokens-6GYKDV6U.js.map} +1 -1
- package/dist/tokens-generate-VTZV5EEW.js +86 -0
- package/dist/tokens-generate-VTZV5EEW.js.map +1 -0
- package/package.json +6 -6
- package/src/bin.ts +210 -48
- package/src/build.ts +130 -6
- package/src/commands/__fixtures__/shadcn-label-wrapper/package.json +7 -0
- package/src/commands/__fixtures__/shadcn-label-wrapper/src/components/ui/label.contract.json +42 -0
- package/src/commands/__fixtures__/shadcn-label-wrapper/src/components/ui/label.tsx +11 -0
- package/src/commands/__fixtures__/shadcn-label-wrapper/src/components/ui/primitive.contract.json +20 -0
- package/src/commands/__fixtures__/shadcn-label-wrapper/src/components/ui/primitive.tsx +14 -0
- package/src/commands/__fixtures__/shadcn-label-wrapper/tsconfig.app.json +23 -0
- package/src/commands/__tests__/init.test.ts +113 -0
- package/src/commands/__tests__/scan-generate.test.ts +188 -69
- package/src/commands/__tests__/verify.test.ts +91 -0
- package/src/commands/discover.ts +151 -0
- package/src/commands/enhance.ts +3 -1
- package/src/commands/govern-scan.ts +386 -0
- package/src/commands/govern.ts +2 -2
- package/src/commands/init.ts +152 -28
- package/src/commands/inspect.ts +290 -0
- package/src/commands/migrate-contract.ts +85 -0
- package/src/commands/scan-generate.ts +438 -50
- package/src/commands/scan.ts +1 -0
- package/src/commands/setup.ts +27 -50
- package/src/commands/tokens-generate.ts +113 -0
- package/src/commands/verify.ts +195 -1
- package/src/core/__fixtures__/shadcn-input/input.tsx +7 -0
- package/src/core/__fixtures__/shadcn-input/tsconfig.json +14 -0
- package/src/core/__fixtures__/shadcn-label/label.tsx +11 -0
- package/src/core/__fixtures__/shadcn-label/primitive.tsx +14 -0
- package/src/core/__fixtures__/shadcn-label/tsconfig.json +14 -0
- package/src/core/__fixtures__/shadcn-radix-label/label.tsx +11 -0
- package/src/core/__fixtures__/shadcn-radix-label/node_modules/radix-ui/index.d.ts +12 -0
- package/src/core/__fixtures__/shadcn-radix-label/tsconfig.json +14 -0
- package/src/core/__tests__/contract-parity.test.ts +316 -0
- package/src/core/component-extractor.test.ts +39 -0
- package/src/core/component-extractor.ts +92 -1
- package/src/core/config.ts +2 -1
- package/src/core/discovery.ts +13 -2
- package/src/core/drift-verifier.ts +123 -0
- package/src/core/extractor-adapter.ts +80 -0
- package/src/mcp/__tests__/projectFields.test.ts +1 -1
- package/src/mcp/utils.ts +1 -50
- package/src/migrate/converter.ts +3 -3
- package/src/migrate/fragment-to-contract.ts +253 -0
- package/src/migrate/report.ts +1 -1
- package/src/scripts/token-benchmark.ts +121 -0
- package/src/service/__tests__/props-extractor.test.ts +94 -0
- package/src/service/__tests__/token-normalizer.test.ts +690 -0
- package/src/service/ast-utils.ts +4 -23
- package/src/service/babel-config.ts +23 -0
- package/src/service/enhance/converter.ts +61 -0
- package/src/service/enhance/props-extractor.ts +25 -8
- package/src/service/enhance/scanner.ts +5 -24
- package/src/service/snippet-validation.ts +9 -3
- package/src/service/token-normalizer.ts +510 -0
- package/src/shared/index.ts +1 -0
- package/src/shared/project-fields.ts +46 -0
- package/src/viewer/__tests__/viewer-integration.test.ts +8 -8
- package/src/viewer/preview-adapter.ts +116 -0
- package/src/viewer/style-utils.ts +27 -412
- package/src/viewer/vite-plugin.ts +2 -2
- package/dist/chunk-55KERLWL.js.map +0 -1
- package/dist/chunk-5A6X2Y73.js.map +0 -1
- package/dist/chunk-APTQIBS5.js.map +0 -1
- package/dist/chunk-EYXVAMEX.js.map +0 -1
- package/dist/chunk-I34BC3CU.js.map +0 -1
- package/dist/chunk-LOYS64QS.js.map +0 -1
- package/dist/chunk-ZKTFKHWN.js +0 -324
- package/dist/chunk-ZKTFKHWN.js.map +0 -1
- package/dist/discovery-VDANZAJ2.js +0 -28
- package/dist/init-WRUSW7R5.js.map +0 -1
- package/dist/scan-YJHQIRKG.js +0 -14
- package/dist/scan-generate-TFZVL3BT.js.map +0 -1
- package/dist/viewer-2TZS3NDL.js +0 -2730
- package/dist/viewer-2TZS3NDL.js.map +0 -1
- package/src/commands/dev.ts +0 -107
- /package/dist/{chunk-TXFCEDOC.js.map → chunk-2WXKALIG.js.map} +0 -0
- /package/dist/{discovery-VDANZAJ2.js.map → codebase-scanner-VOTPXRYW.js.map} +0 -0
- /package/dist/{init-cloud-REQ3XLHO.js.map → init-cloud-MQ6GRJAZ.js.map} +0 -0
- /package/dist/{scan-YJHQIRKG.js.map → scan-VNNKACG2.js.map} +0 -0
- /package/dist/{service-HKJ6B7P7.js.map → scanner-7LAZYPWZ.js.map} +0 -0
- /package/dist/{static-viewer-DUVC4UIM.js.map → service-FHQU7YS7.js.map} +0 -0
- /package/dist/{snapshot-C5DYIGIV.js.map → snapshot-KQEQ6XHL.js.map} +0 -0
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
import { createRequire as __banner_createRequire } from 'module'; const require = __banner_createRequire(import.meta.url);
|
|
2
|
+
import "./chunk-D2CDBRNU.js";
|
|
3
|
+
import {
|
|
4
|
+
BRAND
|
|
5
|
+
} from "./chunk-32LIWN2P.js";
|
|
6
|
+
import "./chunk-Z7EY4VHE.js";
|
|
7
|
+
|
|
8
|
+
// src/commands/govern-scan.ts
|
|
9
|
+
import pc from "picocolors";
|
|
10
|
+
import { resolve, relative } from "path";
|
|
11
|
+
import { existsSync } from "fs";
|
|
12
|
+
var SCAN_DEFAULT_RULES = {
|
|
13
|
+
"safety/no-dangerous-html": true,
|
|
14
|
+
"safety/sanitize-hrefs": true,
|
|
15
|
+
"safety/no-inline-scripts": true,
|
|
16
|
+
"safety/no-exposed-secrets": true,
|
|
17
|
+
"tokens/require-design-tokens": true
|
|
18
|
+
};
|
|
19
|
+
function detectRootDir(cwd) {
|
|
20
|
+
const candidates = ["src", "app", "pages", "components"];
|
|
21
|
+
for (const dir of candidates) {
|
|
22
|
+
if (existsSync(resolve(cwd, dir))) {
|
|
23
|
+
return cwd;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return cwd;
|
|
27
|
+
}
|
|
28
|
+
function groupByFile(usages) {
|
|
29
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
30
|
+
for (const usage of usages) {
|
|
31
|
+
const existing = grouped.get(usage.filePath);
|
|
32
|
+
if (existing) {
|
|
33
|
+
existing.push(usage);
|
|
34
|
+
} else {
|
|
35
|
+
grouped.set(usage.filePath, [usage]);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return grouped;
|
|
39
|
+
}
|
|
40
|
+
async function governScan(options = {}) {
|
|
41
|
+
const {
|
|
42
|
+
loadPolicy,
|
|
43
|
+
createEngine,
|
|
44
|
+
buildAdaptersFromConfig,
|
|
45
|
+
createCloudAdapter,
|
|
46
|
+
formatVerdict
|
|
47
|
+
} = await import("@fragments-sdk/govern");
|
|
48
|
+
const { scanCodebase } = await import("./codebase-scanner-VOTPXRYW.js");
|
|
49
|
+
const { usagesToSpec } = await import("./converter-JLINP7CJ.js");
|
|
50
|
+
const format = options.format ?? "summary";
|
|
51
|
+
const quiet = options.quiet ?? false;
|
|
52
|
+
if (!quiet) {
|
|
53
|
+
console.log(pc.cyan(`
|
|
54
|
+
${BRAND.name} Governance Scan
|
|
55
|
+
`));
|
|
56
|
+
}
|
|
57
|
+
const rootDir = resolve(options.dir ?? detectRootDir(process.cwd()));
|
|
58
|
+
if (!quiet) {
|
|
59
|
+
console.log(pc.dim(` Root: ${rootDir}
|
|
60
|
+
`));
|
|
61
|
+
}
|
|
62
|
+
let policy = await loadPolicy(options.config);
|
|
63
|
+
const hasRules = Object.keys(policy.rules).length > 0;
|
|
64
|
+
if (!hasRules) {
|
|
65
|
+
policy = { ...policy, rules: SCAN_DEFAULT_RULES };
|
|
66
|
+
if (!quiet) {
|
|
67
|
+
console.log(pc.dim(" No config found \u2014 using scan defaults (safety + tokens)\n"));
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
const adapters = buildAdaptersFromConfig(policy.audit);
|
|
71
|
+
const hasCloudAdapter = adapters.length > 0 && policy.audit?.cloud;
|
|
72
|
+
if (!hasCloudAdapter && process.env.FRAGMENTS_API_KEY) {
|
|
73
|
+
adapters.push(createCloudAdapter());
|
|
74
|
+
if (!quiet) {
|
|
75
|
+
console.log(pc.dim(" Cloud audit enabled (FRAGMENTS_API_KEY detected)\n"));
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
const engine = createEngine(policy, adapters);
|
|
79
|
+
if (!quiet) {
|
|
80
|
+
console.log(pc.dim(" Scanning files...\n"));
|
|
81
|
+
}
|
|
82
|
+
const analysis = await scanCodebase({
|
|
83
|
+
rootDir,
|
|
84
|
+
useCache: true,
|
|
85
|
+
onProgress: quiet ? void 0 : (progress) => {
|
|
86
|
+
if (progress.phase === "scanning") {
|
|
87
|
+
process.stdout.write(
|
|
88
|
+
`\r ${pc.dim(`[${progress.current}/${progress.total}]`)} ${pc.dim(relative(rootDir, progress.currentFile))}`
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
if (!quiet) {
|
|
94
|
+
process.stdout.write("\r" + " ".repeat(80) + "\r");
|
|
95
|
+
console.log(
|
|
96
|
+
pc.dim(` Scanned ${analysis.totalFiles} files, found ${analysis.totalComponents} component types
|
|
97
|
+
`)
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
const allUsages = [];
|
|
101
|
+
for (const comp of Object.values(analysis.components)) {
|
|
102
|
+
allUsages.push(...comp.usages);
|
|
103
|
+
}
|
|
104
|
+
if (allUsages.length === 0) {
|
|
105
|
+
if (!quiet) {
|
|
106
|
+
console.log(pc.yellow(" No component usages found.\n"));
|
|
107
|
+
}
|
|
108
|
+
return { exitCode: 0 };
|
|
109
|
+
}
|
|
110
|
+
const grouped = groupByFile(allUsages);
|
|
111
|
+
let totalFiles = 0;
|
|
112
|
+
let passedFiles = 0;
|
|
113
|
+
let totalViolations = 0;
|
|
114
|
+
const violationCounts = /* @__PURE__ */ new Map();
|
|
115
|
+
for (const [filePath, usages] of grouped) {
|
|
116
|
+
const spec = usagesToSpec(usages, filePath, rootDir);
|
|
117
|
+
const relPath = relative(rootDir, filePath);
|
|
118
|
+
const verdict = await engine.check(spec, {
|
|
119
|
+
runner: "cli",
|
|
120
|
+
input: relPath
|
|
121
|
+
});
|
|
122
|
+
totalFiles++;
|
|
123
|
+
if (verdict.passed) {
|
|
124
|
+
passedFiles++;
|
|
125
|
+
} else {
|
|
126
|
+
if (!quiet) {
|
|
127
|
+
console.log(pc.red(` \u2717 ${relPath}`));
|
|
128
|
+
if (format === "summary") {
|
|
129
|
+
for (const result of verdict.results) {
|
|
130
|
+
for (const v of result.violations) {
|
|
131
|
+
const count = violationCounts.get(v.rule) ?? 0;
|
|
132
|
+
violationCounts.set(v.rule, count + 1);
|
|
133
|
+
totalViolations++;
|
|
134
|
+
console.log(
|
|
135
|
+
pc.dim(` ${v.severity} `) + pc.yellow(v.rule) + pc.dim(` \u2014 ${v.message}`)
|
|
136
|
+
);
|
|
137
|
+
if (v.nodeId) {
|
|
138
|
+
console.log(pc.dim(` at ${v.nodeId}`));
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
if (verdict.passed && !quiet && format === "summary") {
|
|
146
|
+
console.log(pc.green(` \u2713 ${relPath}`) + pc.dim(` (${usages.length} components, score: ${verdict.score}/100)`));
|
|
147
|
+
}
|
|
148
|
+
if (format === "json" || format === "sarif") {
|
|
149
|
+
const output = formatVerdict(verdict, format);
|
|
150
|
+
console.log(output);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
if (!quiet && format === "summary") {
|
|
154
|
+
console.log(pc.dim("\n \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n"));
|
|
155
|
+
console.log(` Files checked: ${totalFiles}`);
|
|
156
|
+
console.log(` Passed: ${passedFiles}/${totalFiles}`);
|
|
157
|
+
console.log(` Violations: ${totalViolations}`);
|
|
158
|
+
if (violationCounts.size > 0) {
|
|
159
|
+
console.log(pc.dim("\n Top violations:"));
|
|
160
|
+
const sorted = [...violationCounts.entries()].sort((a, b) => b[1] - a[1]);
|
|
161
|
+
for (const [rule, count] of sorted.slice(0, 5)) {
|
|
162
|
+
console.log(pc.dim(` ${count}\xD7 `) + pc.yellow(rule));
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
console.log();
|
|
166
|
+
if (passedFiles === totalFiles) {
|
|
167
|
+
console.log(pc.green(` \u2713 All files passed governance checks
|
|
168
|
+
`));
|
|
169
|
+
} else {
|
|
170
|
+
console.log(
|
|
171
|
+
pc.red(` \u2717 ${totalFiles - passedFiles} file(s) failed governance checks
|
|
172
|
+
`)
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return { exitCode: passedFiles === totalFiles ? 0 : 1 };
|
|
177
|
+
}
|
|
178
|
+
async function governWatch(options = {}) {
|
|
179
|
+
const {
|
|
180
|
+
loadPolicy,
|
|
181
|
+
createEngine,
|
|
182
|
+
buildAdaptersFromConfig,
|
|
183
|
+
createCloudAdapter,
|
|
184
|
+
formatVerdict
|
|
185
|
+
} = await import("@fragments-sdk/govern");
|
|
186
|
+
const { scanFile } = await import("./scanner-7LAZYPWZ.js");
|
|
187
|
+
const { usagesToSpec } = await import("./converter-JLINP7CJ.js");
|
|
188
|
+
const quiet = options.quiet ?? false;
|
|
189
|
+
const debounceMs = options.debounce ?? 300;
|
|
190
|
+
const format = options.format ?? "summary";
|
|
191
|
+
console.log(pc.cyan(`
|
|
192
|
+
${BRAND.name} Governance Watch
|
|
193
|
+
`));
|
|
194
|
+
const { exitCode } = await governScan(options);
|
|
195
|
+
if (!quiet) {
|
|
196
|
+
console.log(
|
|
197
|
+
pc.dim(` Initial scan ${exitCode === 0 ? "passed" : "completed with violations"}
|
|
198
|
+
`)
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
const rootDir = resolve(options.dir ?? detectRootDir(process.cwd()));
|
|
202
|
+
let policy = await loadPolicy(options.config);
|
|
203
|
+
if (Object.keys(policy.rules).length === 0) {
|
|
204
|
+
policy = { ...policy, rules: SCAN_DEFAULT_RULES };
|
|
205
|
+
}
|
|
206
|
+
const adapters = buildAdaptersFromConfig(policy.audit);
|
|
207
|
+
if (!adapters.some(() => policy.audit?.cloud) && process.env.FRAGMENTS_API_KEY) {
|
|
208
|
+
adapters.push(createCloudAdapter());
|
|
209
|
+
}
|
|
210
|
+
const engine = createEngine(policy, adapters);
|
|
211
|
+
console.log(pc.dim(" Watching for changes... (Ctrl+C to stop)\n"));
|
|
212
|
+
const chokidar = await import("chokidar");
|
|
213
|
+
const watcher = chokidar.watch(
|
|
214
|
+
["**/*.tsx", "**/*.ts", "**/*.jsx", "**/*.js"],
|
|
215
|
+
{
|
|
216
|
+
cwd: rootDir,
|
|
217
|
+
ignoreInitial: true,
|
|
218
|
+
ignored: [
|
|
219
|
+
"**/node_modules/**",
|
|
220
|
+
"**/dist/**",
|
|
221
|
+
"**/build/**",
|
|
222
|
+
"**/.next/**",
|
|
223
|
+
"**/*.test.*",
|
|
224
|
+
"**/*.spec.*",
|
|
225
|
+
"**/*.stories.*"
|
|
226
|
+
],
|
|
227
|
+
awaitWriteFinish: { stabilityThreshold: debounceMs }
|
|
228
|
+
}
|
|
229
|
+
);
|
|
230
|
+
const handleChange = async (changedRelPath) => {
|
|
231
|
+
const absolutePath = resolve(rootDir, changedRelPath);
|
|
232
|
+
try {
|
|
233
|
+
const { usages } = await scanFile(absolutePath);
|
|
234
|
+
if (usages.length === 0) {
|
|
235
|
+
if (!quiet) {
|
|
236
|
+
console.log(pc.dim(` \u25CB ${changedRelPath} \u2014 no component usages`));
|
|
237
|
+
}
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
const spec = usagesToSpec(usages, absolutePath, rootDir);
|
|
241
|
+
const verdict = await engine.check(spec, {
|
|
242
|
+
runner: "cli",
|
|
243
|
+
input: changedRelPath
|
|
244
|
+
});
|
|
245
|
+
if (verdict.passed) {
|
|
246
|
+
console.log(
|
|
247
|
+
pc.green(` \u2713 ${changedRelPath}`) + pc.dim(` (${usages.length} components, score: ${verdict.score}/100)`)
|
|
248
|
+
);
|
|
249
|
+
} else {
|
|
250
|
+
console.log(pc.red(` \u2717 ${changedRelPath}`));
|
|
251
|
+
if (format === "summary") {
|
|
252
|
+
for (const result of verdict.results) {
|
|
253
|
+
for (const v of result.violations) {
|
|
254
|
+
console.log(
|
|
255
|
+
pc.dim(` ${v.severity} `) + pc.yellow(v.rule) + pc.dim(` \u2014 ${v.message}`)
|
|
256
|
+
);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
} else {
|
|
260
|
+
console.log(formatVerdict(verdict, format));
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
} catch (error) {
|
|
264
|
+
if (!quiet) {
|
|
265
|
+
console.log(
|
|
266
|
+
pc.dim(` \u26A0 ${changedRelPath} \u2014 `) + pc.yellow(error instanceof Error ? error.message : "parse error")
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
};
|
|
271
|
+
watcher.on("change", handleChange);
|
|
272
|
+
watcher.on("add", handleChange);
|
|
273
|
+
await new Promise(() => {
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
export {
|
|
277
|
+
governScan,
|
|
278
|
+
governWatch
|
|
279
|
+
};
|
|
280
|
+
//# sourceMappingURL=govern-scan-UCBZR6D6.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/govern-scan.ts"],"sourcesContent":["/**\n * govern scan / govern watch — Zero-config governance scanning\n *\n * Parses real JSX/TSX files via the existing codebase scanner, converts\n * component usages to UISpec, and runs governance checks per file.\n * Optionally submits results to Fragments Cloud.\n */\n\nimport pc from 'picocolors';\nimport { resolve, relative } from 'node:path';\nimport { existsSync } from 'node:fs';\nimport { BRAND } from '../core/index.js';\nimport type { ComponentUsage } from '../service/enhance/types.js';\n\n// ---------------------------------------------------------------------------\n// Options\n// ---------------------------------------------------------------------------\n\nexport interface GovernScanOptions {\n /** Root directory to scan (default: auto-detect) */\n dir?: string;\n /** Path to govern.config.ts */\n config?: string;\n /** Output format */\n format?: 'summary' | 'json' | 'sarif';\n /** Suppress non-error output */\n quiet?: boolean;\n}\n\nexport interface GovernWatchOptions extends GovernScanOptions {\n /** Debounce interval in ms (default: 300) */\n debounce?: number;\n}\n\n// ---------------------------------------------------------------------------\n// Scan defaults — applied when no config file exists\n// ---------------------------------------------------------------------------\n\nconst SCAN_DEFAULT_RULES: Record<string, boolean | object> = {\n 'safety/no-dangerous-html': true,\n 'safety/sanitize-hrefs': true,\n 'safety/no-inline-scripts': true,\n 'safety/no-exposed-secrets': true,\n 'tokens/require-design-tokens': true,\n};\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Auto-detect root directory by looking for common React project dirs\n */\nfunction detectRootDir(cwd: string): string {\n const candidates = ['src', 'app', 'pages', 'components'];\n for (const dir of candidates) {\n if (existsSync(resolve(cwd, dir))) {\n return cwd;\n }\n }\n return cwd;\n}\n\n/**\n * Group component usages by their source file\n */\nfunction groupByFile(usages: ComponentUsage[]): Map<string, ComponentUsage[]> {\n const grouped = new Map<string, ComponentUsage[]>();\n for (const usage of usages) {\n const existing = grouped.get(usage.filePath);\n if (existing) {\n existing.push(usage);\n } else {\n grouped.set(usage.filePath, [usage]);\n }\n }\n return grouped;\n}\n\n// ---------------------------------------------------------------------------\n// governScan\n// ---------------------------------------------------------------------------\n\nexport async function governScan(\n options: GovernScanOptions = {},\n): Promise<{ exitCode: number }> {\n const {\n loadPolicy,\n createEngine,\n buildAdaptersFromConfig,\n createCloudAdapter,\n formatVerdict,\n } = await import('@fragments-sdk/govern');\n\n const { scanCodebase } = await import(\n '../service/enhance/codebase-scanner.js'\n );\n const { usagesToSpec } = await import(\n '../service/enhance/converter.js'\n );\n\n const format = options.format ?? 'summary';\n const quiet = options.quiet ?? false;\n\n if (!quiet) {\n console.log(pc.cyan(`\\n${BRAND.name} Governance Scan\\n`));\n }\n\n // 1. Resolve root directory\n const rootDir = resolve(options.dir ?? detectRootDir(process.cwd()));\n if (!quiet) {\n console.log(pc.dim(` Root: ${rootDir}\\n`));\n }\n\n // 2. Load policy — use scan defaults if no config exists\n let policy = await loadPolicy(options.config);\n const hasRules = Object.keys(policy.rules).length > 0;\n\n if (!hasRules) {\n policy = { ...policy, rules: SCAN_DEFAULT_RULES };\n if (!quiet) {\n console.log(pc.dim(' No config found — using scan defaults (safety + tokens)\\n'));\n }\n }\n\n // 3. Build adapters. Auto-add cloud if FRAGMENTS_API_KEY is set\n const adapters = buildAdaptersFromConfig(policy.audit);\n const hasCloudAdapter = adapters.length > 0 && policy.audit?.cloud;\n if (!hasCloudAdapter && process.env.FRAGMENTS_API_KEY) {\n adapters.push(createCloudAdapter());\n if (!quiet) {\n console.log(pc.dim(' Cloud audit enabled (FRAGMENTS_API_KEY detected)\\n'));\n }\n }\n\n // 4. Create engine\n const engine = createEngine(policy, adapters);\n\n // 5. Scan codebase\n if (!quiet) {\n console.log(pc.dim(' Scanning files...\\n'));\n }\n\n const analysis = await scanCodebase({\n rootDir,\n useCache: true,\n onProgress: quiet\n ? undefined\n : (progress) => {\n if (progress.phase === 'scanning') {\n process.stdout.write(\n `\\r ${pc.dim(`[${progress.current}/${progress.total}]`)} ${pc.dim(relative(rootDir, progress.currentFile))}`,\n );\n }\n },\n });\n\n if (!quiet) {\n // Clear progress line\n process.stdout.write('\\r' + ' '.repeat(80) + '\\r');\n console.log(\n pc.dim(` Scanned ${analysis.totalFiles} files, found ${analysis.totalComponents} component types\\n`),\n );\n }\n\n // 6. Collect all usages across components\n const allUsages: ComponentUsage[] = [];\n for (const comp of Object.values(analysis.components)) {\n allUsages.push(...comp.usages);\n }\n\n if (allUsages.length === 0) {\n if (!quiet) {\n console.log(pc.yellow(' No component usages found.\\n'));\n }\n return { exitCode: 0 };\n }\n\n // 7. Group by file and run checks\n const grouped = groupByFile(allUsages);\n let totalFiles = 0;\n let passedFiles = 0;\n let totalViolations = 0;\n const violationCounts = new Map<string, number>();\n\n for (const [filePath, usages] of grouped) {\n const spec = usagesToSpec(usages, filePath, rootDir);\n const relPath = relative(rootDir, filePath);\n\n const verdict = await engine.check(spec, {\n runner: 'cli',\n input: relPath,\n });\n\n totalFiles++;\n\n if (verdict.passed) {\n passedFiles++;\n } else {\n if (!quiet) {\n console.log(pc.red(` ✗ ${relPath}`));\n if (format === 'summary') {\n for (const result of verdict.results) {\n for (const v of result.violations) {\n const count = violationCounts.get(v.rule) ?? 0;\n violationCounts.set(v.rule, count + 1);\n totalViolations++;\n console.log(\n pc.dim(` ${v.severity} `) +\n pc.yellow(v.rule) +\n pc.dim(` — ${v.message}`),\n );\n if (v.nodeId) {\n console.log(pc.dim(` at ${v.nodeId}`));\n }\n }\n }\n }\n }\n }\n\n if (verdict.passed && !quiet && format === 'summary') {\n console.log(pc.green(` ✓ ${relPath}`) + pc.dim(` (${usages.length} components, score: ${verdict.score}/100)`));\n }\n\n // JSON/SARIF: print per-file\n if (format === 'json' || format === 'sarif') {\n const output = formatVerdict(verdict, format);\n console.log(output);\n }\n }\n\n // 8. Summary\n if (!quiet && format === 'summary') {\n console.log(pc.dim('\\n ─────────────────────────────────────\\n'));\n console.log(` Files checked: ${totalFiles}`);\n console.log(` Passed: ${passedFiles}/${totalFiles}`);\n console.log(` Violations: ${totalViolations}`);\n\n if (violationCounts.size > 0) {\n console.log(pc.dim('\\n Top violations:'));\n const sorted = [...violationCounts.entries()].sort((a, b) => b[1] - a[1]);\n for (const [rule, count] of sorted.slice(0, 5)) {\n console.log(pc.dim(` ${count}× `) + pc.yellow(rule));\n }\n }\n\n console.log();\n\n if (passedFiles === totalFiles) {\n console.log(pc.green(` ✓ All files passed governance checks\\n`));\n } else {\n console.log(\n pc.red(` ✗ ${totalFiles - passedFiles} file(s) failed governance checks\\n`),\n );\n }\n }\n\n return { exitCode: passedFiles === totalFiles ? 0 : 1 };\n}\n\n// ---------------------------------------------------------------------------\n// governWatch\n// ---------------------------------------------------------------------------\n\nexport async function governWatch(\n options: GovernWatchOptions = {},\n): Promise<void> {\n const {\n loadPolicy,\n createEngine,\n buildAdaptersFromConfig,\n createCloudAdapter,\n formatVerdict,\n } = await import('@fragments-sdk/govern');\n\n const { scanFile } = await import('../service/enhance/scanner.js');\n const { usagesToSpec } = await import(\n '../service/enhance/converter.js'\n );\n\n const quiet = options.quiet ?? false;\n const debounceMs = options.debounce ?? 300;\n const format = options.format ?? 'summary';\n\n // 1. Run initial scan\n console.log(pc.cyan(`\\n${BRAND.name} Governance Watch\\n`));\n\n const { exitCode } = await governScan(options);\n if (!quiet) {\n console.log(\n pc.dim(` Initial scan ${exitCode === 0 ? 'passed' : 'completed with violations'}\\n`),\n );\n }\n\n // 2. Set up engine for incremental checks\n const rootDir = resolve(options.dir ?? detectRootDir(process.cwd()));\n let policy = await loadPolicy(options.config);\n if (Object.keys(policy.rules).length === 0) {\n policy = { ...policy, rules: SCAN_DEFAULT_RULES };\n }\n const adapters = buildAdaptersFromConfig(policy.audit);\n if (!adapters.some(() => policy.audit?.cloud) && process.env.FRAGMENTS_API_KEY) {\n adapters.push(createCloudAdapter());\n }\n const engine = createEngine(policy, adapters);\n\n // 3. Watch for changes\n console.log(pc.dim(' Watching for changes... (Ctrl+C to stop)\\n'));\n\n const chokidar = await import('chokidar');\n\n const watcher = chokidar.watch(\n ['**/*.tsx', '**/*.ts', '**/*.jsx', '**/*.js'],\n {\n cwd: rootDir,\n ignoreInitial: true,\n ignored: [\n '**/node_modules/**',\n '**/dist/**',\n '**/build/**',\n '**/.next/**',\n '**/*.test.*',\n '**/*.spec.*',\n '**/*.stories.*',\n ],\n awaitWriteFinish: { stabilityThreshold: debounceMs },\n },\n );\n\n const handleChange = async (changedRelPath: string) => {\n const absolutePath = resolve(rootDir, changedRelPath);\n\n try {\n const { usages } = await scanFile(absolutePath);\n\n if (usages.length === 0) {\n if (!quiet) {\n console.log(pc.dim(` ○ ${changedRelPath} — no component usages`));\n }\n return;\n }\n\n const spec = usagesToSpec(usages, absolutePath, rootDir);\n const verdict = await engine.check(spec, {\n runner: 'cli',\n input: changedRelPath,\n });\n\n if (verdict.passed) {\n console.log(\n pc.green(` ✓ ${changedRelPath}`) +\n pc.dim(` (${usages.length} components, score: ${verdict.score}/100)`),\n );\n } else {\n console.log(pc.red(` ✗ ${changedRelPath}`));\n if (format === 'summary') {\n for (const result of verdict.results) {\n for (const v of result.violations) {\n console.log(\n pc.dim(` ${v.severity} `) +\n pc.yellow(v.rule) +\n pc.dim(` — ${v.message}`),\n );\n }\n }\n } else {\n console.log(formatVerdict(verdict, format));\n }\n }\n } catch (error) {\n if (!quiet) {\n console.log(\n pc.dim(` ⚠ ${changedRelPath} — `) +\n pc.yellow(error instanceof Error ? error.message : 'parse error'),\n );\n }\n }\n };\n\n watcher.on('change', handleChange);\n watcher.on('add', handleChange);\n\n // Keep process alive\n await new Promise(() => {});\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.d.ts
CHANGED
|
@@ -22,7 +22,8 @@ interface DiscoveredFile {
|
|
|
22
22
|
relativePath: string;
|
|
23
23
|
}
|
|
24
24
|
/**
|
|
25
|
-
* Discover fragment files matching the config patterns
|
|
25
|
+
* Discover fragment files matching the config patterns.
|
|
26
|
+
* Also discovers .contract.json files for framework-agnostic component contracts.
|
|
26
27
|
*/
|
|
27
28
|
declare function discoverFragmentFiles(config: FragmentsConfig, configDir: string): Promise<DiscoveredFile[]>;
|
|
28
29
|
/**
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { createRequire as __banner_createRequire } from 'module'; const require
|
|
|
2
2
|
import {
|
|
3
3
|
generateStaticViewer,
|
|
4
4
|
generateViewerFromJson
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-2WXKALIG.js";
|
|
6
6
|
import {
|
|
7
7
|
buildFragments,
|
|
8
8
|
runAnalyzeCommand,
|
|
@@ -12,23 +12,23 @@ import {
|
|
|
12
12
|
validateCoverage,
|
|
13
13
|
validateSchema,
|
|
14
14
|
validateSnippets
|
|
15
|
-
} from "./chunk-
|
|
16
|
-
import "./chunk-
|
|
17
|
-
import {
|
|
18
|
-
findConfigFile,
|
|
19
|
-
loadConfig
|
|
20
|
-
} from "./chunk-55KERLWL.js";
|
|
15
|
+
} from "./chunk-7WHVW72L.js";
|
|
16
|
+
import "./chunk-MN3TJ3D5.js";
|
|
21
17
|
import {
|
|
22
18
|
discoverComponentFiles,
|
|
23
19
|
discoverFragmentFiles,
|
|
24
|
-
extractComponentName
|
|
25
|
-
|
|
26
|
-
|
|
20
|
+
extractComponentName,
|
|
21
|
+
findConfigFile,
|
|
22
|
+
loadConfig
|
|
23
|
+
} from "./chunk-65WSVDV5.js";
|
|
24
|
+
import "./chunk-XJQ5BIWI.js";
|
|
27
25
|
import "./chunk-D2CDBRNU.js";
|
|
28
26
|
import {
|
|
29
27
|
defineBlock,
|
|
30
28
|
defineFragment
|
|
31
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-32LIWN2P.js";
|
|
30
|
+
import "./chunk-QCN35LJU.js";
|
|
31
|
+
import "./chunk-7DZC4YEV.js";
|
|
32
32
|
import "./chunk-Z7EY4VHE.js";
|
|
33
33
|
|
|
34
34
|
// src/cli-commands.ts
|