design-lazyyy-cli 0.2.0 → 0.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 +2 -2
- package/package.json +2 -2
- package/src/index.js +91 -7
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
**Control Figma Desktop from your terminal. No API key needed.**
|
|
6
6
|
|
|
7
7
|
[](LICENSE)
|
|
8
|
-
[](https://nodejs.org)
|
|
9
9
|
[]()
|
|
10
10
|
|
|
11
11
|
---
|
|
@@ -33,7 +33,7 @@ all through a single CLI connected to Figma Desktop via Chrome DevTools Protocol
|
|
|
33
33
|
|
|
34
34
|
### Prerequisites
|
|
35
35
|
|
|
36
|
-
- **Node.js** >=
|
|
36
|
+
- **Node.js** >= 24
|
|
37
37
|
- **Figma Desktop** (free account works)
|
|
38
38
|
|
|
39
39
|
### Installation
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "design-lazyyy-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "CLI for managing Figma design systems. Create variables, components, and more. No API key required.",
|
|
5
5
|
"author": "plugin87",
|
|
6
6
|
"license": "MIT",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"variables"
|
|
20
20
|
],
|
|
21
21
|
"engines": {
|
|
22
|
-
"node": ">=
|
|
22
|
+
"node": ">=24"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"chalk": "^5.3.0",
|
package/src/index.js
CHANGED
|
@@ -11,6 +11,13 @@ import { createInterface } from 'readline';
|
|
|
11
11
|
import { homedir, platform } from 'os';
|
|
12
12
|
import { FigJamClient } from './figjam-client.js';
|
|
13
13
|
|
|
14
|
+
// Auth — offline hash-based verification
|
|
15
|
+
import { createHash } from 'crypto';
|
|
16
|
+
const VALID_TOKEN_HASHES = [
|
|
17
|
+
// SHA-256 hashes of valid tokens (add more with: echo -n "token" | shasum -a 256)
|
|
18
|
+
'065ea2d80d8e1e61025f115d01d08518b00615047a3ec14bd4e6f7d4f8813929',
|
|
19
|
+
];
|
|
20
|
+
|
|
14
21
|
// Platform detection
|
|
15
22
|
const IS_WINDOWS = platform() === 'win32';
|
|
16
23
|
const IS_MAC = platform() === 'darwin';
|
|
@@ -95,6 +102,36 @@ function saveConfig(config) {
|
|
|
95
102
|
writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
|
|
96
103
|
}
|
|
97
104
|
|
|
105
|
+
// Helper: Hash token with SHA-256
|
|
106
|
+
function hashToken(token) {
|
|
107
|
+
return createHash('sha256').update(token).digest('hex');
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Helper: Verify token offline against known hashes
|
|
111
|
+
function verifyToken(token) {
|
|
112
|
+
return VALID_TOKEN_HASHES.includes(hashToken(token));
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Helper: Check API key (gate all commands)
|
|
116
|
+
function checkApiKey() {
|
|
117
|
+
const config = loadConfig();
|
|
118
|
+
if (!config.token) {
|
|
119
|
+
console.log(chalk.red('\n✗ Token required.\n'));
|
|
120
|
+
console.log(chalk.white(' Get a token from plugin87, then run:\n'));
|
|
121
|
+
console.log(chalk.cyan(' design-lazyyy-cli login <token>\n'));
|
|
122
|
+
process.exit(1);
|
|
123
|
+
}
|
|
124
|
+
if (!verifyToken(config.token)) {
|
|
125
|
+
console.log(chalk.red('\n✗ Token invalid or revoked.\n'));
|
|
126
|
+
console.log(chalk.white(' Get a new token from plugin87, then run:\n'));
|
|
127
|
+
console.log(chalk.cyan(' design-lazyyy-cli login <token>\n'));
|
|
128
|
+
delete config.token;
|
|
129
|
+
saveConfig(config);
|
|
130
|
+
process.exit(1);
|
|
131
|
+
}
|
|
132
|
+
return true;
|
|
133
|
+
}
|
|
134
|
+
|
|
98
135
|
// Resolve engine binary path (local node_modules)
|
|
99
136
|
const __filename2 = fileURLToPath(import.meta.url);
|
|
100
137
|
const __pkgRoot = dirname(dirname(__filename2));
|
|
@@ -115,8 +152,9 @@ function figmaUse(args, options = {}) {
|
|
|
115
152
|
}
|
|
116
153
|
}
|
|
117
154
|
|
|
118
|
-
// Helper: Check connection
|
|
155
|
+
// Helper: Check connection (also gates on API key)
|
|
119
156
|
function checkConnection() {
|
|
157
|
+
checkApiKey();
|
|
120
158
|
const result = figmaUse('status', { silent: true });
|
|
121
159
|
if (!result || result.includes('Not connected')) {
|
|
122
160
|
console.log(chalk.red('\n✗ Not connected to Figma\n'));
|
|
@@ -178,18 +216,20 @@ program
|
|
|
178
216
|
program.action(async () => {
|
|
179
217
|
const config = loadConfig();
|
|
180
218
|
|
|
219
|
+
// Auth gate
|
|
220
|
+
checkApiKey();
|
|
221
|
+
|
|
181
222
|
// First time? Run init
|
|
182
223
|
if (!config.patched || !checkDependencies(true)) {
|
|
183
224
|
showBanner();
|
|
184
225
|
console.log(chalk.white(' Welcome! Let\'s get you set up.\n'));
|
|
185
|
-
console.log(chalk.gray(' This takes about 30 seconds. No API key needed.\n'));
|
|
186
226
|
|
|
187
227
|
// Step 1: Check Node version
|
|
188
228
|
console.log(chalk.blue('Step 1/4: ') + 'Checking Node.js...');
|
|
189
229
|
const nodeVersion = process.version;
|
|
190
230
|
const nodeMajor = parseInt(nodeVersion.slice(1).split('.')[0]);
|
|
191
|
-
if (nodeMajor <
|
|
192
|
-
console.log(chalk.red(` ✗ Node.js ${nodeVersion} is too old. Please upgrade to Node
|
|
231
|
+
if (nodeMajor < 24) {
|
|
232
|
+
console.log(chalk.red(` ✗ Node.js ${nodeVersion} is too old. Please upgrade to Node 24+`));
|
|
193
233
|
process.exit(1);
|
|
194
234
|
}
|
|
195
235
|
console.log(chalk.green(` ✓ Node.js ${nodeVersion}`));
|
|
@@ -338,17 +378,17 @@ program
|
|
|
338
378
|
.command('init')
|
|
339
379
|
.description('Interactive setup wizard')
|
|
340
380
|
.action(async () => {
|
|
381
|
+
checkApiKey();
|
|
341
382
|
showBanner();
|
|
342
383
|
|
|
343
384
|
console.log(chalk.white(' Welcome! Let\'s get you set up.\n'));
|
|
344
|
-
console.log(chalk.gray(' This takes about 30 seconds. No API key needed.\n'));
|
|
345
385
|
|
|
346
386
|
// Step 1: Check Node version
|
|
347
387
|
console.log(chalk.blue('Step 1/4: ') + 'Checking Node.js...');
|
|
348
388
|
const nodeVersion = process.version;
|
|
349
389
|
const nodeMajor = parseInt(nodeVersion.slice(1).split('.')[0]);
|
|
350
|
-
if (nodeMajor <
|
|
351
|
-
console.log(chalk.red(` ✗ Node.js ${nodeVersion} is too old. Please upgrade to Node
|
|
390
|
+
if (nodeMajor < 24) {
|
|
391
|
+
console.log(chalk.red(` ✗ Node.js ${nodeVersion} is too old. Please upgrade to Node 24+`));
|
|
352
392
|
process.exit(1);
|
|
353
393
|
}
|
|
354
394
|
console.log(chalk.green(` ✓ Node.js ${nodeVersion}`));
|
|
@@ -447,12 +487,55 @@ program
|
|
|
447
487
|
execSync('design-lazyyy-cli init', { stdio: 'inherit' });
|
|
448
488
|
});
|
|
449
489
|
|
|
490
|
+
// ============ LOGIN ============
|
|
491
|
+
|
|
492
|
+
program
|
|
493
|
+
.command('login [token]')
|
|
494
|
+
.description('Authenticate with a token from plugin87')
|
|
495
|
+
.action(async (token) => {
|
|
496
|
+
if (!token) {
|
|
497
|
+
token = await prompt(chalk.white('Enter token: '));
|
|
498
|
+
}
|
|
499
|
+
token = token.trim();
|
|
500
|
+
if (!token) {
|
|
501
|
+
console.log(chalk.red('\n✗ Token cannot be empty.\n'));
|
|
502
|
+
process.exit(1);
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
if (!verifyToken(token)) {
|
|
506
|
+
console.log(chalk.red('\n✗ Invalid token.\n'));
|
|
507
|
+
process.exit(1);
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
const config = loadConfig();
|
|
511
|
+
config.token = token;
|
|
512
|
+
saveConfig(config);
|
|
513
|
+
console.log(chalk.green('\n✓ Token verified! Welcome.\n'));
|
|
514
|
+
});
|
|
515
|
+
|
|
516
|
+
// ============ LOGOUT ============
|
|
517
|
+
|
|
518
|
+
program
|
|
519
|
+
.command('logout')
|
|
520
|
+
.description('Remove saved token')
|
|
521
|
+
.action(() => {
|
|
522
|
+
const config = loadConfig();
|
|
523
|
+
if (!config.token) {
|
|
524
|
+
console.log(chalk.yellow('\nNo token saved.\n'));
|
|
525
|
+
return;
|
|
526
|
+
}
|
|
527
|
+
delete config.token;
|
|
528
|
+
saveConfig(config);
|
|
529
|
+
console.log(chalk.green('\n✓ Token removed. You are logged out.\n'));
|
|
530
|
+
});
|
|
531
|
+
|
|
450
532
|
// ============ STATUS ============
|
|
451
533
|
|
|
452
534
|
program
|
|
453
535
|
.command('status')
|
|
454
536
|
.description('Check connection to Figma')
|
|
455
537
|
.action(() => {
|
|
538
|
+
checkApiKey();
|
|
456
539
|
// Check if first run
|
|
457
540
|
const config = loadConfig();
|
|
458
541
|
if (!config.patched && !checkDependencies(true)) {
|
|
@@ -469,6 +552,7 @@ program
|
|
|
469
552
|
.command('connect')
|
|
470
553
|
.description('Start Figma with remote debugging enabled')
|
|
471
554
|
.action(async () => {
|
|
555
|
+
checkApiKey();
|
|
472
556
|
// Check if first run
|
|
473
557
|
const config = loadConfig();
|
|
474
558
|
if (!config.patched) {
|