@yubild/cli 0.1.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/commands/deploy.d.ts +6 -0
- package/dist/commands/deploy.d.ts.map +1 -0
- package/dist/commands/deploy.js +73 -0
- package/dist/commands/deploy.js.map +1 -0
- package/dist/commands/diff.d.ts +6 -0
- package/dist/commands/diff.d.ts.map +1 -0
- package/dist/commands/diff.js +97 -0
- package/dist/commands/diff.js.map +1 -0
- package/dist/commands/export.d.ts +9 -0
- package/dist/commands/export.d.ts.map +1 -0
- package/dist/commands/export.js +93 -0
- package/dist/commands/export.js.map +1 -0
- package/dist/commands/init.d.ts +8 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +95 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/login.d.ts +9 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +81 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/logout.d.ts +6 -0
- package/dist/commands/logout.d.ts.map +1 -0
- package/dist/commands/logout.js +17 -0
- package/dist/commands/logout.js.map +1 -0
- package/dist/commands/projects.d.ts +6 -0
- package/dist/commands/projects.d.ts.map +1 -0
- package/dist/commands/projects.js +76 -0
- package/dist/commands/projects.js.map +1 -0
- package/dist/commands/publish.d.ts +8 -0
- package/dist/commands/publish.d.ts.map +1 -0
- package/dist/commands/publish.js +81 -0
- package/dist/commands/publish.js.map +1 -0
- package/dist/commands/pull.d.ts +8 -0
- package/dist/commands/pull.d.ts.map +1 -0
- package/dist/commands/pull.js +86 -0
- package/dist/commands/pull.js.map +1 -0
- package/dist/commands/push.d.ts +6 -0
- package/dist/commands/push.d.ts.map +1 -0
- package/dist/commands/push.js +73 -0
- package/dist/commands/push.js.map +1 -0
- package/dist/commands/sync.d.ts +8 -0
- package/dist/commands/sync.d.ts.map +1 -0
- package/dist/commands/sync.js +111 -0
- package/dist/commands/sync.js.map +1 -0
- package/dist/commands/watch.d.ts +8 -0
- package/dist/commands/watch.d.ts.map +1 -0
- package/dist/commands/watch.js +91 -0
- package/dist/commands/watch.js.map +1 -0
- package/dist/commands/whoami.d.ts +6 -0
- package/dist/commands/whoami.d.ts.map +1 -0
- package/dist/commands/whoami.js +32 -0
- package/dist/commands/whoami.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +89 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/api-client.d.ts +141 -0
- package/dist/lib/api-client.d.ts.map +1 -0
- package/dist/lib/api-client.js +154 -0
- package/dist/lib/api-client.js.map +1 -0
- package/dist/lib/auth.d.ts +36 -0
- package/dist/lib/auth.d.ts.map +1 -0
- package/dist/lib/auth.js +108 -0
- package/dist/lib/auth.js.map +1 -0
- package/dist/lib/config.d.ts +28 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +100 -0
- package/dist/lib/config.js.map +1 -0
- package/package.json +30 -0
- package/src/commands/deploy.ts +42 -0
- package/src/commands/diff.ts +81 -0
- package/src/commands/export.ts +71 -0
- package/src/commands/init.ts +69 -0
- package/src/commands/login.ts +52 -0
- package/src/commands/logout.ts +16 -0
- package/src/commands/projects.ts +53 -0
- package/src/commands/publish.ts +51 -0
- package/src/commands/pull.ts +59 -0
- package/src/commands/push.ts +42 -0
- package/src/commands/sync.ts +86 -0
- package/src/commands/watch.ts +71 -0
- package/src/commands/whoami.ts +31 -0
- package/src/index.ts +104 -0
- package/src/lib/api-client.ts +231 -0
- package/src/lib/auth.ts +86 -0
- package/src/lib/config.ts +77 -0
- package/src/types/esm-modules.d.ts +41 -0
- package/tsconfig.json +19 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Configuration file management for .yubildrc
|
|
4
|
+
*/
|
|
5
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
8
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
9
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
10
|
+
}
|
|
11
|
+
Object.defineProperty(o, k2, desc);
|
|
12
|
+
}) : (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
o[k2] = m[k];
|
|
15
|
+
}));
|
|
16
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
17
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
18
|
+
}) : function(o, v) {
|
|
19
|
+
o["default"] = v;
|
|
20
|
+
});
|
|
21
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
22
|
+
var ownKeys = function(o) {
|
|
23
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
24
|
+
var ar = [];
|
|
25
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
26
|
+
return ar;
|
|
27
|
+
};
|
|
28
|
+
return ownKeys(o);
|
|
29
|
+
};
|
|
30
|
+
return function (mod) {
|
|
31
|
+
if (mod && mod.__esModule) return mod;
|
|
32
|
+
var result = {};
|
|
33
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
34
|
+
__setModuleDefault(result, mod);
|
|
35
|
+
return result;
|
|
36
|
+
};
|
|
37
|
+
})();
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.findConfigFile = findConfigFile;
|
|
40
|
+
exports.loadConfig = loadConfig;
|
|
41
|
+
exports.saveConfig = saveConfig;
|
|
42
|
+
exports.getConfigPath = getConfigPath;
|
|
43
|
+
const fs = __importStar(require("fs"));
|
|
44
|
+
const path = __importStar(require("path"));
|
|
45
|
+
const CONFIG_FILENAME = '.yubildrc';
|
|
46
|
+
const DEFAULT_CONFIG = {
|
|
47
|
+
apiUrl: 'https://yubild.com',
|
|
48
|
+
outputDir: './src/tokens',
|
|
49
|
+
formats: ['css', 'tailwind', 'json'],
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Find .yubildrc by walking up from cwd
|
|
53
|
+
*/
|
|
54
|
+
function findConfigFile() {
|
|
55
|
+
let dir = process.cwd();
|
|
56
|
+
while (true) {
|
|
57
|
+
const configPath = path.join(dir, CONFIG_FILENAME);
|
|
58
|
+
if (fs.existsSync(configPath)) {
|
|
59
|
+
return configPath;
|
|
60
|
+
}
|
|
61
|
+
const parentDir = path.dirname(dir);
|
|
62
|
+
if (parentDir === dir)
|
|
63
|
+
break;
|
|
64
|
+
dir = parentDir;
|
|
65
|
+
}
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Load configuration from .yubildrc
|
|
70
|
+
*/
|
|
71
|
+
function loadConfig() {
|
|
72
|
+
const configPath = findConfigFile();
|
|
73
|
+
if (!configPath)
|
|
74
|
+
return null;
|
|
75
|
+
try {
|
|
76
|
+
const content = fs.readFileSync(configPath, 'utf-8');
|
|
77
|
+
const config = JSON.parse(content);
|
|
78
|
+
return {
|
|
79
|
+
...DEFAULT_CONFIG,
|
|
80
|
+
...config,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Save configuration to .yubildrc in cwd
|
|
89
|
+
*/
|
|
90
|
+
function saveConfig(config) {
|
|
91
|
+
const configPath = path.join(process.cwd(), CONFIG_FILENAME);
|
|
92
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n', 'utf-8');
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Get config path in cwd
|
|
96
|
+
*/
|
|
97
|
+
function getConfigPath() {
|
|
98
|
+
return path.join(process.cwd(), CONFIG_FILENAME);
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":";AAAA;;GAEG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwBH,wCAeC;AAKD,gCAeC;AAKD,gCAGC;AAKD,sCAEC;AAxED,uCAAyB;AACzB,2CAA6B;AAW7B,MAAM,eAAe,GAAG,WAAW,CAAC;AACpC,MAAM,cAAc,GAA0B;IAC5C,MAAM,EAAE,oBAAoB;IAC5B,SAAS,EAAE,cAAc;IACzB,OAAO,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,MAAM,CAAC;CACrC,CAAC;AAEF;;GAEG;AACH,SAAgB,cAAc;IAC5B,IAAI,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAExB,OAAO,IAAI,EAAE,CAAC;QACZ,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC;QACnD,IAAI,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAC9B,OAAO,UAAU,CAAC;QACpB,CAAC;QAED,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACpC,IAAI,SAAS,KAAK,GAAG;YAAE,MAAM;QAC7B,GAAG,GAAG,SAAS,CAAC;IAClB,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,SAAgB,UAAU;IACxB,MAAM,UAAU,GAAG,cAAc,EAAE,CAAC;IACpC,IAAI,CAAC,UAAU;QAAE,OAAO,IAAI,CAAC;IAE7B,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QACrD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAiB,CAAC;QAEnD,OAAO;YACL,GAAG,cAAc;YACjB,GAAG,MAAM;SACM,CAAC;IACpB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAgB,UAAU,CAAC,MAAoB;IAC7C,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,eAAe,CAAC,CAAC;IAC7D,EAAE,CAAC,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC;AAChF,CAAC;AAED;;GAEG;AACH,SAAgB,aAAa;IAC3B,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,eAAe,CAAC,CAAC;AACnD,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@yubild/cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "CLI tool for Yubild design system management",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"yubild": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "tsc",
|
|
11
|
+
"dev": "tsc --watch",
|
|
12
|
+
"start": "node dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"keywords": ["yubild", "design-system", "design-tokens", "cli"],
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"commander": "^12.0.0",
|
|
18
|
+
"chalk": "^5.3.0",
|
|
19
|
+
"ora": "^8.0.0",
|
|
20
|
+
"inquirer": "^9.2.0",
|
|
21
|
+
"conf": "^12.0.0"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"@types/node": "^20.0.0",
|
|
25
|
+
"typescript": "^5.0.0"
|
|
26
|
+
},
|
|
27
|
+
"engines": {
|
|
28
|
+
"node": ">=18.0.0"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* yubild deploy
|
|
3
|
+
* Deploy design tokens to CDN
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { loadConfig } from '../lib/config';
|
|
7
|
+
import { isAuthenticated } from '../lib/auth';
|
|
8
|
+
import { ApiClient } from '../lib/api-client';
|
|
9
|
+
|
|
10
|
+
export async function deployCommand(): Promise<void> {
|
|
11
|
+
if (!isAuthenticated()) {
|
|
12
|
+
console.error('Error: Not authenticated. Run `yubild login` first.');
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const config = loadConfig();
|
|
17
|
+
if (!config) {
|
|
18
|
+
console.error('Error: No .yubildrc found. Run `yubild init` first.');
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const { default: chalk } = await import('chalk');
|
|
23
|
+
const { default: ora } = await import('ora');
|
|
24
|
+
|
|
25
|
+
const spinner = ora('Deploying to CDN...').start();
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
const client = new ApiClient();
|
|
29
|
+
const result = await client.deployToCdn(config.projectId);
|
|
30
|
+
|
|
31
|
+
spinner.succeed('Deployed to CDN!');
|
|
32
|
+
console.log('');
|
|
33
|
+
console.log(` Version: ${chalk.cyan(result.version)}`);
|
|
34
|
+
console.log(` Build ID: ${chalk.gray(result.buildId)}`);
|
|
35
|
+
console.log(` CDN URL: ${chalk.green(result.cdnUrl)}`);
|
|
36
|
+
console.log('');
|
|
37
|
+
} catch (error) {
|
|
38
|
+
spinner.fail('Deploy failed');
|
|
39
|
+
console.error(`\nFailed to deploy: ${(error as Error).message}`);
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* yubild diff
|
|
3
|
+
* Show differences between local tokens and Figma tokens
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { loadConfig } from '../lib/config';
|
|
7
|
+
import { isAuthenticated } from '../lib/auth';
|
|
8
|
+
import { ApiClient } from '../lib/api-client';
|
|
9
|
+
|
|
10
|
+
export async function diffCommand(): Promise<void> {
|
|
11
|
+
if (!isAuthenticated()) {
|
|
12
|
+
console.error('Error: Not authenticated. Run `yubild login` first.');
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const config = loadConfig();
|
|
17
|
+
if (!config) {
|
|
18
|
+
console.error('Error: No .yubildrc found. Run `yubild init` first.');
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const { default: chalk } = await import('chalk');
|
|
23
|
+
|
|
24
|
+
try {
|
|
25
|
+
const client = new ApiClient();
|
|
26
|
+
const result = await client.diffTokens(config.projectId);
|
|
27
|
+
|
|
28
|
+
if (result.entries.length === 0) {
|
|
29
|
+
console.log(chalk.green('No differences found. Local and Figma tokens are in sync.'));
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const padKey = Math.max(...result.entries.map((e) => e.tokenKey.length), 10);
|
|
34
|
+
const padStatus = 10;
|
|
35
|
+
|
|
36
|
+
console.log('');
|
|
37
|
+
console.log(
|
|
38
|
+
` ${'Token'.padEnd(padKey)} ${'Status'.padEnd(padStatus)} ${'Local Value'.padEnd(20)} Figma Value`
|
|
39
|
+
);
|
|
40
|
+
console.log(
|
|
41
|
+
` ${''.padEnd(padKey, '-')} ${''.padEnd(padStatus, '-')} ${''.padEnd(20, '-')} ${''.padEnd(20, '-')}`
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
for (const entry of result.entries) {
|
|
45
|
+
const statusColor =
|
|
46
|
+
entry.status === 'added'
|
|
47
|
+
? chalk.green
|
|
48
|
+
: entry.status === 'modified'
|
|
49
|
+
? chalk.yellow
|
|
50
|
+
: entry.status === 'removed'
|
|
51
|
+
? chalk.red
|
|
52
|
+
: chalk.gray;
|
|
53
|
+
console.log(
|
|
54
|
+
` ${entry.tokenKey.padEnd(padKey)} ${statusColor(entry.status.padEnd(padStatus))} ${(entry.localValue ?? '-').padEnd(20)} ${entry.figmaValue ?? '-'}`
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const s = result.summary;
|
|
59
|
+
console.log('');
|
|
60
|
+
console.log(
|
|
61
|
+
` Summary: ${chalk.green(`+${s.added} added`)} ${chalk.yellow(`~${s.modified} modified`)} ${chalk.red(`-${s.removed} removed`)} ${chalk.gray(`${s.unchanged} unchanged`)}`
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
if (result.hasConflicts) {
|
|
65
|
+
console.log('');
|
|
66
|
+
console.log(` ${chalk.red('Conflicts detected.')} Use ${chalk.cyan('yubild sync')} to resolve.`);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (result.warnings && result.warnings.length > 0) {
|
|
70
|
+
console.log('');
|
|
71
|
+
for (const warning of result.warnings) {
|
|
72
|
+
console.log(` ${chalk.yellow('Warning:')} ${warning}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
console.log('');
|
|
77
|
+
} catch (error) {
|
|
78
|
+
console.error(`\nFailed to diff tokens: ${(error as Error).message}`);
|
|
79
|
+
process.exit(1);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* yubild export
|
|
3
|
+
* Export design tokens in a specific format
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import * as fs from 'fs';
|
|
7
|
+
import * as path from 'path';
|
|
8
|
+
import { loadConfig } from '../lib/config';
|
|
9
|
+
import { isAuthenticated } from '../lib/auth';
|
|
10
|
+
import { ApiClient } from '../lib/api-client';
|
|
11
|
+
|
|
12
|
+
export async function exportCommand(options: {
|
|
13
|
+
format: string;
|
|
14
|
+
output?: string;
|
|
15
|
+
}): Promise<void> {
|
|
16
|
+
if (!isAuthenticated()) {
|
|
17
|
+
console.error('Error: Not authenticated. Run `yubild login` first.');
|
|
18
|
+
process.exit(1);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const config = loadConfig();
|
|
22
|
+
if (!config) {
|
|
23
|
+
console.error('Error: No .yubildrc found. Run `yubild init` first.');
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const { default: chalk } = await import('chalk');
|
|
28
|
+
const { default: ora } = await import('ora');
|
|
29
|
+
|
|
30
|
+
const spinner = ora(`Exporting tokens as ${options.format}...`).start();
|
|
31
|
+
|
|
32
|
+
try {
|
|
33
|
+
const client = new ApiClient();
|
|
34
|
+
const result = await client.exportTokens(config.projectId, options.format);
|
|
35
|
+
|
|
36
|
+
const outputDir = path.resolve(options.output ?? config.outputDir);
|
|
37
|
+
if (!fs.existsSync(outputDir)) {
|
|
38
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
let writtenCount = 0;
|
|
42
|
+
for (const file of result.files) {
|
|
43
|
+
const filePath = path.join(outputDir, file.path);
|
|
44
|
+
const fileDir = path.dirname(filePath);
|
|
45
|
+
|
|
46
|
+
if (!fs.existsSync(fileDir)) {
|
|
47
|
+
fs.mkdirSync(fileDir, { recursive: true });
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
fs.writeFileSync(filePath, file.content, 'utf-8');
|
|
51
|
+
writtenCount++;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
spinner.succeed('Export complete!');
|
|
55
|
+
console.log('');
|
|
56
|
+
console.log(` Format: ${chalk.cyan(result.format)}`);
|
|
57
|
+
console.log(` Version: ${chalk.gray(result.version)}`);
|
|
58
|
+
console.log(` Files written: ${chalk.green(String(writtenCount))}`);
|
|
59
|
+
console.log(` Output: ${chalk.gray(outputDir)}`);
|
|
60
|
+
|
|
61
|
+
for (const file of result.files) {
|
|
62
|
+
console.log(` ${chalk.gray(file.path)}`);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
console.log('');
|
|
66
|
+
} catch (error) {
|
|
67
|
+
spinner.fail('Export failed');
|
|
68
|
+
console.error(`\nFailed to export tokens: ${(error as Error).message}`);
|
|
69
|
+
process.exit(1);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* yubild init
|
|
3
|
+
* Initialize a project configuration file (.yubildrc)
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import * as fs from 'fs';
|
|
7
|
+
import { saveConfig, getConfigPath, type YubildConfig } from '../lib/config';
|
|
8
|
+
import { getApiUrl, isAuthenticated } from '../lib/auth';
|
|
9
|
+
import { ApiClient } from '../lib/api-client';
|
|
10
|
+
|
|
11
|
+
export async function initCommand(options: { projectId?: string }): Promise<void> {
|
|
12
|
+
const configPath = getConfigPath();
|
|
13
|
+
|
|
14
|
+
if (fs.existsSync(configPath)) {
|
|
15
|
+
console.error(`Error: ${configPath} already exists.`);
|
|
16
|
+
console.error('Delete it first if you want to reinitialize.');
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (!isAuthenticated()) {
|
|
21
|
+
console.error('Error: Not authenticated. Run `yubild login` first.');
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
let projectId = options.projectId;
|
|
26
|
+
|
|
27
|
+
if (!projectId) {
|
|
28
|
+
const readline = await import('readline');
|
|
29
|
+
const rl = readline.createInterface({
|
|
30
|
+
input: process.stdin,
|
|
31
|
+
output: process.stdout,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
projectId = await new Promise<string>((resolve) => {
|
|
35
|
+
rl.question('Enter your Yubild project ID: ', (answer: string) => {
|
|
36
|
+
rl.close();
|
|
37
|
+
resolve(answer.trim());
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (!projectId) {
|
|
43
|
+
console.error('Error: Project ID is required.');
|
|
44
|
+
process.exit(1);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Verify project exists
|
|
48
|
+
try {
|
|
49
|
+
const client = new ApiClient();
|
|
50
|
+
const { project } = await client.getProjectStatus(projectId);
|
|
51
|
+
|
|
52
|
+
const config: YubildConfig = {
|
|
53
|
+
projectId,
|
|
54
|
+
apiUrl: getApiUrl(),
|
|
55
|
+
outputDir: './src/tokens',
|
|
56
|
+
formats: ['css', 'tailwind', 'json'],
|
|
57
|
+
framework: project.framework.toLowerCase(),
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
saveConfig(config);
|
|
61
|
+
|
|
62
|
+
console.log(`\nInitialized Yubild for project "${project.name}"`);
|
|
63
|
+
console.log(`Configuration saved to ${configPath}`);
|
|
64
|
+
console.log(`\nRun \`yubild pull\` to download your design tokens.\n`);
|
|
65
|
+
} catch (error) {
|
|
66
|
+
console.error(`\nFailed to initialize: ${(error as Error).message}`);
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* yubild login
|
|
3
|
+
* Authenticate with Yubild using an API key
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { saveCredentials } from '../lib/auth';
|
|
7
|
+
import { ApiClient } from '../lib/api-client';
|
|
8
|
+
|
|
9
|
+
export async function loginCommand(options: { apiKey?: string; apiUrl?: string }): Promise<void> {
|
|
10
|
+
const apiUrl = options.apiUrl || 'https://yubild.com';
|
|
11
|
+
|
|
12
|
+
let apiKey = options.apiKey;
|
|
13
|
+
|
|
14
|
+
if (!apiKey) {
|
|
15
|
+
// Use readline for simple input since we want minimal dependencies
|
|
16
|
+
const readline = await import('readline');
|
|
17
|
+
const rl = readline.createInterface({
|
|
18
|
+
input: process.stdin,
|
|
19
|
+
output: process.stdout,
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
apiKey = await new Promise<string>((resolve) => {
|
|
23
|
+
rl.question('Enter your Yubild API key (nxui_sk_...): ', (answer: string) => {
|
|
24
|
+
rl.close();
|
|
25
|
+
resolve(answer.trim());
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (!apiKey || !apiKey.startsWith('nxui_sk_')) {
|
|
31
|
+
console.error('Error: Invalid API key format. API keys must start with "nxui_sk_"');
|
|
32
|
+
console.error('Generate one at: ' + apiUrl + '/api-keys');
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
try {
|
|
37
|
+
const client = new ApiClient(apiUrl, apiKey);
|
|
38
|
+
const { user } = await client.authenticate();
|
|
39
|
+
|
|
40
|
+
saveCredentials({
|
|
41
|
+
apiKey,
|
|
42
|
+
apiUrl,
|
|
43
|
+
email: user.email,
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
console.log(`\nAuthenticated as ${user.email}`);
|
|
47
|
+
console.log('Credentials saved. You can now use yubild commands.\n');
|
|
48
|
+
} catch (error) {
|
|
49
|
+
console.error(`\nAuthentication failed: ${(error as Error).message}`);
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* yubild logout
|
|
3
|
+
* Clear stored authentication credentials
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { clearCredentials, isAuthenticated } from '../lib/auth';
|
|
7
|
+
|
|
8
|
+
export function logoutCommand(): void {
|
|
9
|
+
if (!isAuthenticated()) {
|
|
10
|
+
console.log('Not authenticated.');
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
clearCredentials();
|
|
15
|
+
console.log('Logged out. Credentials have been removed.');
|
|
16
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* yubild projects
|
|
3
|
+
* List all projects
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { isAuthenticated } from '../lib/auth';
|
|
7
|
+
import { ApiClient } from '../lib/api-client';
|
|
8
|
+
|
|
9
|
+
export async function projectsCommand(): Promise<void> {
|
|
10
|
+
if (!isAuthenticated()) {
|
|
11
|
+
console.error('Error: Not authenticated. Run `yubild login` first.');
|
|
12
|
+
process.exit(1);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const { default: chalk } = await import('chalk');
|
|
16
|
+
|
|
17
|
+
try {
|
|
18
|
+
const client = new ApiClient();
|
|
19
|
+
const { projects } = await client.listProjects();
|
|
20
|
+
|
|
21
|
+
if (projects.length === 0) {
|
|
22
|
+
console.log('No projects found.');
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const padName = Math.max(...projects.map((p) => p.name.length), 4);
|
|
27
|
+
const padSlug = Math.max(...projects.map((p) => p.slug.length), 4);
|
|
28
|
+
const padVersion = Math.max(...projects.map((p) => p.version.length), 7);
|
|
29
|
+
const padFramework = Math.max(...projects.map((p) => p.framework.length), 9);
|
|
30
|
+
|
|
31
|
+
console.log('');
|
|
32
|
+
console.log(
|
|
33
|
+
` ${chalk.bold('Name'.padEnd(padName))} ${chalk.bold('Slug'.padEnd(padSlug))} ${chalk.bold('Version'.padEnd(padVersion))} ${chalk.bold('Framework'.padEnd(padFramework))} ${chalk.bold('Last Updated')}`
|
|
34
|
+
);
|
|
35
|
+
console.log(
|
|
36
|
+
` ${''.padEnd(padName, '-')} ${''.padEnd(padSlug, '-')} ${''.padEnd(padVersion, '-')} ${''.padEnd(padFramework, '-')} ${''.padEnd(20, '-')}`
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
for (const project of projects) {
|
|
40
|
+
const updatedAt = new Date(project.updatedAt).toLocaleDateString();
|
|
41
|
+
console.log(
|
|
42
|
+
` ${project.name.padEnd(padName)} ${chalk.gray(project.slug.padEnd(padSlug))} ${chalk.cyan(project.version.padEnd(padVersion))} ${project.framework.padEnd(padFramework)} ${chalk.gray(updatedAt)}`
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
console.log('');
|
|
47
|
+
console.log(` ${chalk.gray(`${projects.length} project(s)`)}`);
|
|
48
|
+
console.log('');
|
|
49
|
+
} catch (error) {
|
|
50
|
+
console.error(`\nFailed to list projects: ${(error as Error).message}`);
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* yubild publish
|
|
3
|
+
* Publish design tokens to Git via Pull Request
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { loadConfig } from '../lib/config';
|
|
7
|
+
import { isAuthenticated } from '../lib/auth';
|
|
8
|
+
import { ApiClient } from '../lib/api-client';
|
|
9
|
+
|
|
10
|
+
export async function publishCommand(options: {
|
|
11
|
+
repo?: string;
|
|
12
|
+
}): Promise<void> {
|
|
13
|
+
if (!isAuthenticated()) {
|
|
14
|
+
console.error('Error: Not authenticated. Run `yubild login` first.');
|
|
15
|
+
process.exit(1);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const config = loadConfig();
|
|
19
|
+
if (!config) {
|
|
20
|
+
console.error('Error: No .yubildrc found. Run `yubild init` first.');
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const { default: chalk } = await import('chalk');
|
|
25
|
+
const { default: ora } = await import('ora');
|
|
26
|
+
|
|
27
|
+
const spinner = ora('Creating Pull Request...').start();
|
|
28
|
+
|
|
29
|
+
try {
|
|
30
|
+
const client = new ApiClient();
|
|
31
|
+
const result = await client.publishToGit(config.projectId, options.repo);
|
|
32
|
+
|
|
33
|
+
if (result.published) {
|
|
34
|
+
spinner.succeed('Pull Request created!');
|
|
35
|
+
console.log('');
|
|
36
|
+
if (result.prUrl) {
|
|
37
|
+
console.log(` PR URL: ${chalk.green(result.prUrl)}`);
|
|
38
|
+
}
|
|
39
|
+
if (result.prNumber) {
|
|
40
|
+
console.log(` PR #${chalk.cyan(String(result.prNumber))}`);
|
|
41
|
+
}
|
|
42
|
+
console.log('');
|
|
43
|
+
} else {
|
|
44
|
+
spinner.warn('Publish completed but no PR was created.');
|
|
45
|
+
}
|
|
46
|
+
} catch (error) {
|
|
47
|
+
spinner.fail('Publish failed');
|
|
48
|
+
console.error(`\nFailed to publish: ${(error as Error).message}`);
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* yubild pull
|
|
3
|
+
* Pull design tokens from Yubild and write them to local files
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import * as fs from 'fs';
|
|
7
|
+
import * as path from 'path';
|
|
8
|
+
import { loadConfig } from '../lib/config';
|
|
9
|
+
import { isAuthenticated } from '../lib/auth';
|
|
10
|
+
import { ApiClient } from '../lib/api-client';
|
|
11
|
+
|
|
12
|
+
export async function pullCommand(options: { format?: string }): Promise<void> {
|
|
13
|
+
if (!isAuthenticated()) {
|
|
14
|
+
console.error('Error: Not authenticated. Run `yubild login` first.');
|
|
15
|
+
process.exit(1);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const config = loadConfig();
|
|
19
|
+
if (!config) {
|
|
20
|
+
console.error('Error: No .yubildrc found. Run `yubild init` first.');
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const formats = options.format ? [options.format] : config.formats;
|
|
25
|
+
|
|
26
|
+
console.log(`Pulling tokens for project ${config.projectId}...`);
|
|
27
|
+
console.log(`Formats: ${formats.join(', ')}`);
|
|
28
|
+
|
|
29
|
+
try {
|
|
30
|
+
const client = new ApiClient();
|
|
31
|
+
const { files, version } = await client.pullTokens(config.projectId, formats);
|
|
32
|
+
|
|
33
|
+
// Ensure output directory exists
|
|
34
|
+
const outputDir = path.resolve(config.outputDir);
|
|
35
|
+
if (!fs.existsSync(outputDir)) {
|
|
36
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Write each file
|
|
40
|
+
let writtenCount = 0;
|
|
41
|
+
for (const file of files) {
|
|
42
|
+
const filePath = path.join(outputDir, file.path);
|
|
43
|
+
const fileDir = path.dirname(filePath);
|
|
44
|
+
|
|
45
|
+
if (!fs.existsSync(fileDir)) {
|
|
46
|
+
fs.mkdirSync(fileDir, { recursive: true });
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
fs.writeFileSync(filePath, file.content, 'utf-8');
|
|
50
|
+
writtenCount++;
|
|
51
|
+
console.log(` Written: ${file.path}`);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
console.log(`\nPulled ${writtenCount} files (v${version}) to ${config.outputDir}\n`);
|
|
55
|
+
} catch (error) {
|
|
56
|
+
console.error(`\nFailed to pull tokens: ${(error as Error).message}`);
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* yubild push
|
|
3
|
+
* Push design tokens to Figma
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { loadConfig } from '../lib/config';
|
|
7
|
+
import { isAuthenticated } from '../lib/auth';
|
|
8
|
+
import { ApiClient } from '../lib/api-client';
|
|
9
|
+
|
|
10
|
+
export async function pushCommand(): Promise<void> {
|
|
11
|
+
if (!isAuthenticated()) {
|
|
12
|
+
console.error('Error: Not authenticated. Run `yubild login` first.');
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const config = loadConfig();
|
|
17
|
+
if (!config) {
|
|
18
|
+
console.error('Error: No .yubildrc found. Run `yubild init` first.');
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const { default: chalk } = await import('chalk');
|
|
23
|
+
const { default: ora } = await import('ora');
|
|
24
|
+
|
|
25
|
+
const spinner = ora('Pushing tokens to Figma...').start();
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
const client = new ApiClient();
|
|
29
|
+
const result = await client.pushToFigma(config.projectId);
|
|
30
|
+
|
|
31
|
+
spinner.succeed('Tokens pushed to Figma!');
|
|
32
|
+
console.log('');
|
|
33
|
+
console.log(` Project: ${chalk.cyan(result.data.projectName)}`);
|
|
34
|
+
console.log(` Variables: ${result.data.variables.length}`);
|
|
35
|
+
console.log(` Exported at: ${chalk.gray(result.data.exportedAt)}`);
|
|
36
|
+
console.log('');
|
|
37
|
+
} catch (error) {
|
|
38
|
+
spinner.fail('Push failed');
|
|
39
|
+
console.error(`\nFailed to push tokens: ${(error as Error).message}`);
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
}
|