@fragments-sdk/cli 0.15.10 → 0.16.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/bin.js +896 -787
- package/dist/bin.js.map +1 -1
- package/dist/{chunk-6SQPP47U.js → chunk-77AAP6R6.js} +532 -31
- package/dist/chunk-77AAP6R6.js.map +1 -0
- package/dist/{chunk-5JF26E55.js → chunk-ACFVKMVZ.js} +11 -11
- package/dist/{chunk-BJE3425I.js → chunk-ACX7YWZW.js} +2 -2
- package/dist/{chunk-ONUP6Z4W.js → chunk-G6UVWMFU.js} +8 -8
- package/dist/{chunk-2WXKALIG.js → chunk-OZZ4SVZX.js} +2 -2
- package/dist/{chunk-32LIWN2P.js → chunk-SJFSG7QF.js} +582 -261
- package/dist/chunk-SJFSG7QF.js.map +1 -0
- package/dist/{chunk-HQ6A6DTV.js → chunk-XRADMHMV.js} +315 -1089
- package/dist/chunk-XRADMHMV.js.map +1 -0
- package/dist/core/index.js +53 -1
- package/dist/{create-EXURTBKK.js → create-3ZFYQB3T.js} +2 -2
- package/dist/{doctor-BDPMYYE6.js → doctor-4IDUM7HI.js} +2 -2
- package/dist/{generate-PVOLUAAC.js → generate-VNUUWVWQ.js} +4 -4
- package/dist/{govern-scan-DW4QUAYD.js → govern-scan-HTACKYPF.js} +158 -120
- package/dist/govern-scan-HTACKYPF.js.map +1 -0
- package/dist/index.js +6 -7
- package/dist/index.js.map +1 -1
- package/dist/{init-SSGUSP7Z.js → init-PXFRAQ64.js} +5 -5
- package/dist/mcp-bin.js +2 -2
- package/dist/{scan-PKSYSTRR.js → scan-L4GWGEZX.js} +5 -6
- package/dist/{scan-generate-VY27PIOX.js → scan-generate-74EYSAGH.js} +4 -4
- package/dist/{service-QJGWUIVL.js → service-VELQHEWV.js} +12 -14
- package/dist/{snapshot-WIJMEIFT.js → snapshot-DT4B6DPR.js} +2 -2
- package/dist/{static-viewer-7QIBQZRC.js → static-viewer-E4OJWFDJ.js} +3 -3
- package/dist/{test-64Z5BKBA.js → test-QJY2QO4X.js} +3 -3
- package/dist/{token-normalizer-TEPOVBPV.js → token-normalizer-56H4242J.js} +2 -2
- package/dist/{tokens-NZWFQIAB.js → tokens-K6URXFPK.js} +7 -8
- package/dist/{tokens-NZWFQIAB.js.map → tokens-K6URXFPK.js.map} +1 -1
- package/dist/{tokens-generate-5JQSJ27E.js → tokens-generate-EL6IN536.js} +2 -2
- package/package.json +7 -6
- package/src/bin.ts +49 -88
- package/src/commands/__fixtures__/shadcn-label-wrapper/src/components/ui/label.contract.json +1 -1
- package/src/commands/__fixtures__/shadcn-label-wrapper/src/components/ui/primitive.contract.json +1 -1
- package/src/commands/__tests__/context-cloud.test.ts +291 -0
- package/src/commands/__tests__/govern-scan.test.ts +185 -0
- package/src/commands/__tests__/govern.test.ts +1 -0
- package/src/commands/context-cloud.ts +355 -0
- package/src/commands/govern-scan-report.ts +170 -0
- package/src/commands/govern-scan.ts +42 -147
- package/src/commands/govern.ts +0 -157
- package/dist/chunk-32LIWN2P.js.map +0 -1
- package/dist/chunk-6SQPP47U.js.map +0 -1
- package/dist/chunk-HQ6A6DTV.js.map +0 -1
- package/dist/chunk-MHIBEEW4.js +0 -511
- package/dist/chunk-MHIBEEW4.js.map +0 -1
- package/dist/govern-scan-DW4QUAYD.js.map +0 -1
- package/dist/init-cloud-3DNKPWFB.js +0 -304
- package/dist/init-cloud-3DNKPWFB.js.map +0 -1
- package/dist/node-37AUE74M.js +0 -65
- package/dist/push-contracts-WY32TFP6.js +0 -84
- package/dist/push-contracts-WY32TFP6.js.map +0 -1
- package/dist/static-viewer-7QIBQZRC.js.map +0 -1
- package/dist/token-parser-32KOIOFN.js +0 -22
- package/dist/token-parser-32KOIOFN.js.map +0 -1
- package/dist/tokens-push-HY3KO36V.js +0 -148
- package/dist/tokens-push-HY3KO36V.js.map +0 -1
- package/src/commands/init-cloud.ts +0 -382
- package/src/commands/push-contracts.ts +0 -112
- package/src/commands/tokens-push.ts +0 -199
- /package/dist/{chunk-5JF26E55.js.map → chunk-ACFVKMVZ.js.map} +0 -0
- /package/dist/{chunk-BJE3425I.js.map → chunk-ACX7YWZW.js.map} +0 -0
- /package/dist/{chunk-ONUP6Z4W.js.map → chunk-G6UVWMFU.js.map} +0 -0
- /package/dist/{chunk-2WXKALIG.js.map → chunk-OZZ4SVZX.js.map} +0 -0
- /package/dist/{create-EXURTBKK.js.map → create-3ZFYQB3T.js.map} +0 -0
- /package/dist/{doctor-BDPMYYE6.js.map → doctor-4IDUM7HI.js.map} +0 -0
- /package/dist/{generate-PVOLUAAC.js.map → generate-VNUUWVWQ.js.map} +0 -0
- /package/dist/{init-SSGUSP7Z.js.map → init-PXFRAQ64.js.map} +0 -0
- /package/dist/{node-37AUE74M.js.map → scan-L4GWGEZX.js.map} +0 -0
- /package/dist/{scan-generate-VY27PIOX.js.map → scan-generate-74EYSAGH.js.map} +0 -0
- /package/dist/{scan-PKSYSTRR.js.map → service-VELQHEWV.js.map} +0 -0
- /package/dist/{snapshot-WIJMEIFT.js.map → snapshot-DT4B6DPR.js.map} +0 -0
- /package/dist/{service-QJGWUIVL.js.map → static-viewer-E4OJWFDJ.js.map} +0 -0
- /package/dist/{test-64Z5BKBA.js.map → test-QJY2QO4X.js.map} +0 -0
- /package/dist/{token-normalizer-TEPOVBPV.js.map → token-normalizer-56H4242J.js.map} +0 -0
- /package/dist/{tokens-generate-5JQSJ27E.js.map → tokens-generate-EL6IN536.js.map} +0 -0
|
@@ -1,199 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* fragments tokens push — Push code tokens to Fragments Cloud for drift comparison.
|
|
3
|
-
*
|
|
4
|
-
* Extracts CSS custom properties from Tailwind v4 @theme blocks (or config-based
|
|
5
|
-
* token files) and POSTs them to the Fragments Cloud /api/ingest endpoint.
|
|
6
|
-
* Supports --dry-run for local inspection without pushing.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { resolve } from 'node:path';
|
|
10
|
-
import pc from 'picocolors';
|
|
11
|
-
|
|
12
|
-
// ---------------------------------------------------------------------------
|
|
13
|
-
// Options
|
|
14
|
-
// ---------------------------------------------------------------------------
|
|
15
|
-
|
|
16
|
-
export interface TokensPushOptions {
|
|
17
|
-
/** Path to fragments config file */
|
|
18
|
-
config?: string;
|
|
19
|
-
/** Path to Tailwind v4 CSS file with @theme block */
|
|
20
|
-
tailwindV4?: string;
|
|
21
|
-
/** Parse and display tokens without pushing */
|
|
22
|
-
dryRun?: boolean;
|
|
23
|
-
/** Show detailed output */
|
|
24
|
-
verbose?: boolean;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// ---------------------------------------------------------------------------
|
|
28
|
-
// tokensPush
|
|
29
|
-
// ---------------------------------------------------------------------------
|
|
30
|
-
|
|
31
|
-
export async function tokensPush(options: TokensPushOptions): Promise<void> {
|
|
32
|
-
const startTime = Date.now();
|
|
33
|
-
|
|
34
|
-
// 1. Resolve API credentials
|
|
35
|
-
const apiKey = process.env.FRAGMENTS_API_KEY;
|
|
36
|
-
const baseUrl = process.env.FRAGMENTS_URL || 'https://app.usefragments.com';
|
|
37
|
-
|
|
38
|
-
if (!apiKey && !options.dryRun) {
|
|
39
|
-
console.error(pc.red('Error: FRAGMENTS_API_KEY environment variable is required'));
|
|
40
|
-
console.error(pc.dim('Get your API key from https://app.usefragments.com/api-keys'));
|
|
41
|
-
process.exit(1);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// 2. Token extraction
|
|
45
|
-
const flatMap: Record<string, string> = {};
|
|
46
|
-
|
|
47
|
-
if (options.tailwindV4) {
|
|
48
|
-
// Use @theme parser for Tailwind v4 CSS files
|
|
49
|
-
const { parseTailwindV4File } = await import('../service/token-parser.js');
|
|
50
|
-
|
|
51
|
-
const filePath = resolve(process.cwd(), options.tailwindV4);
|
|
52
|
-
const result = parseTailwindV4File(filePath);
|
|
53
|
-
|
|
54
|
-
if (result.errors.length > 0) {
|
|
55
|
-
for (const err of result.errors) {
|
|
56
|
-
console.error(pc.red(` Error: ${err.message}`));
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
if (options.verbose && result.warnings.length > 0) {
|
|
61
|
-
for (const warn of result.warnings) {
|
|
62
|
-
console.warn(pc.yellow(` Warning: ${warn}`));
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
for (const token of result.tokens) {
|
|
67
|
-
flatMap[token.name] = token.resolvedValue;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
if (options.verbose) {
|
|
71
|
-
console.log(
|
|
72
|
-
pc.dim(` Parsed ${result.tokens.length} tokens from ${options.tailwindV4} (${result.parseTimeMs.toFixed(1)}ms)`),
|
|
73
|
-
);
|
|
74
|
-
}
|
|
75
|
-
} else if (options.config) {
|
|
76
|
-
// Use config-based token extraction
|
|
77
|
-
try {
|
|
78
|
-
const { loadConfig } = await import('../core/node.js');
|
|
79
|
-
const { parseTokenFiles } = await import('../service/index.js');
|
|
80
|
-
|
|
81
|
-
const { config, configDir } = await loadConfig(options.config);
|
|
82
|
-
if (config.tokens?.include?.length) {
|
|
83
|
-
const result = await parseTokenFiles(config.tokens, configDir);
|
|
84
|
-
for (const token of result.tokens) {
|
|
85
|
-
flatMap[token.name] = token.resolvedValue;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
if (options.verbose) {
|
|
89
|
-
console.log(
|
|
90
|
-
pc.dim(` Parsed ${result.tokens.length} tokens from config (${result.parseTimeMs.toFixed(1)}ms)`),
|
|
91
|
-
);
|
|
92
|
-
}
|
|
93
|
-
} else {
|
|
94
|
-
console.error(pc.red('Error: Config file has no tokens.include patterns'));
|
|
95
|
-
process.exit(1);
|
|
96
|
-
}
|
|
97
|
-
} catch (error) {
|
|
98
|
-
console.error(pc.red('Error loading config:'), error instanceof Error ? error.message : error);
|
|
99
|
-
process.exit(1);
|
|
100
|
-
}
|
|
101
|
-
} else {
|
|
102
|
-
// No source specified — try auto-detection
|
|
103
|
-
try {
|
|
104
|
-
const { loadConfig } = await import('../core/node.js');
|
|
105
|
-
const { parseTokenFiles } = await import('../service/index.js');
|
|
106
|
-
|
|
107
|
-
const { config, configDir } = await loadConfig();
|
|
108
|
-
if (config.tokens?.include?.length) {
|
|
109
|
-
const result = await parseTokenFiles(config.tokens, configDir);
|
|
110
|
-
for (const token of result.tokens) {
|
|
111
|
-
flatMap[token.name] = token.resolvedValue;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
if (options.verbose) {
|
|
115
|
-
console.log(
|
|
116
|
-
pc.dim(` Parsed ${result.tokens.length} tokens from auto-detected config (${result.parseTimeMs.toFixed(1)}ms)`),
|
|
117
|
-
);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
} catch {
|
|
121
|
-
// No config found — fall through to error
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
if (Object.keys(flatMap).length === 0) {
|
|
125
|
-
console.error(pc.red('Error: No token source specified'));
|
|
126
|
-
console.error(pc.dim('Provide one of:'));
|
|
127
|
-
console.error(pc.dim(' --tailwind-v4 <path> Path to Tailwind v4 CSS file with @theme block'));
|
|
128
|
-
console.error(pc.dim(' --config <path> Path to fragments config with tokens.include'));
|
|
129
|
-
console.error(pc.dim('\nExample: fragments tokens push --tailwind-v4 ./app.css'));
|
|
130
|
-
process.exit(1);
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
const tokenCount = Object.keys(flatMap).length;
|
|
135
|
-
|
|
136
|
-
if (tokenCount === 0) {
|
|
137
|
-
console.log(pc.yellow('No tokens found.'));
|
|
138
|
-
return;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
console.log(pc.cyan(`Found ${tokenCount} tokens`));
|
|
142
|
-
|
|
143
|
-
// 3. Dry run — display tokens and exit
|
|
144
|
-
if (options.dryRun) {
|
|
145
|
-
console.log(pc.dim('\nDry run — tokens that would be pushed:\n'));
|
|
146
|
-
const entries = Object.entries(flatMap);
|
|
147
|
-
for (const [name, value] of entries.slice(0, 20)) {
|
|
148
|
-
console.log(` ${pc.bold(name)}: ${value}`);
|
|
149
|
-
}
|
|
150
|
-
if (entries.length > 20) {
|
|
151
|
-
console.log(pc.dim(` ... and ${entries.length - 20} more`));
|
|
152
|
-
}
|
|
153
|
-
return;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
// 4. POST to Fragments Cloud
|
|
157
|
-
try {
|
|
158
|
-
const response = await fetch(`${baseUrl}/api/ingest`, {
|
|
159
|
-
method: 'POST',
|
|
160
|
-
headers: {
|
|
161
|
-
'Content-Type': 'application/json',
|
|
162
|
-
'Authorization': `Bearer ${apiKey}`,
|
|
163
|
-
},
|
|
164
|
-
body: JSON.stringify({
|
|
165
|
-
codeTokens: JSON.stringify(flatMap),
|
|
166
|
-
}),
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
if (!response.ok) {
|
|
170
|
-
const errorText = await response.text();
|
|
171
|
-
console.error(pc.red(`Error: API returned ${response.status}`));
|
|
172
|
-
console.error(pc.dim(errorText));
|
|
173
|
-
process.exit(1);
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
const result = await response.json() as Record<string, unknown>;
|
|
177
|
-
|
|
178
|
-
console.log(pc.green(`\nPushed ${tokenCount} tokens to Fragments Cloud`));
|
|
179
|
-
|
|
180
|
-
if (result.tokenDrift) {
|
|
181
|
-
const drift = result.tokenDrift as Record<string, unknown>;
|
|
182
|
-
const summary = drift.summary as Record<string, number> | undefined;
|
|
183
|
-
if (summary) {
|
|
184
|
-
console.log(pc.cyan('\nDrift Summary:'));
|
|
185
|
-
if (summary.total !== undefined) console.log(pc.dim(` Total issues: ${summary.total}`));
|
|
186
|
-
if (summary.missingInCode > 0) console.log(pc.yellow(` Missing in code: ${summary.missingInCode}`));
|
|
187
|
-
if (summary.missingInFigma > 0) console.log(pc.yellow(` Missing in Figma: ${summary.missingInFigma}`));
|
|
188
|
-
if (summary.valueMismatch > 0) console.log(pc.yellow(` Value mismatches: ${summary.valueMismatch}`));
|
|
189
|
-
if (summary.score !== undefined) console.log(` Health score: ${summary.score}%`);
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
console.log(pc.dim(`\nView dashboard: ${baseUrl}/tokens`));
|
|
194
|
-
console.log(pc.dim(`Completed in ${Date.now() - startTime}ms`));
|
|
195
|
-
} catch (error) {
|
|
196
|
-
console.error(pc.red('Error pushing tokens:'), error instanceof Error ? error.message : error);
|
|
197
|
-
process.exit(1);
|
|
198
|
-
}
|
|
199
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|