@matchkit.io/cli 0.1.0 → 0.1.1

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 ADDED
@@ -0,0 +1,154 @@
1
+ # @matchkit.io/cli
2
+
3
+ Command-line interface for MatchKit design system skills. Sync your design system, add components, and integrate with CI/CD pipelines.
4
+
5
+ ## Features
6
+
7
+ - 🔐 **Browser-based authentication** - Secure OAuth flow via matchkit.io
8
+ - 📦 **Component management** - Add individual components with automatic dependency resolution
9
+ - 🔄 **Sync & update** - Pull latest design system updates from your MatchKit configuration
10
+ - 🤖 **CI/CD ready** - Use API keys for automated deployments
11
+ - 📊 **Status tracking** - See what's installed, what's available, and what's changed
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ npm install -g @matchkit.io/cli
17
+ ```
18
+
19
+ ## Quick Start
20
+
21
+ ```bash
22
+ # 1. Authenticate (opens browser)
23
+ matchkit login
24
+
25
+ # 2. Initialize your project
26
+ matchkit init
27
+
28
+ # 3. Pull your design system
29
+ matchkit pull
30
+ ```
31
+
32
+ Your design system files are installed to `.claude/skills/[theme]-ui/` and work automatically with Claude Code, Cursor, VS Code, and Windsurf.
33
+
34
+ ## Commands
35
+
36
+ ### `matchkit login`
37
+
38
+ Authenticate with MatchKit. Opens your browser to sign in, then saves your API key locally.
39
+
40
+ ```bash
41
+ matchkit login
42
+ ```
43
+
44
+ ### `matchkit init`
45
+
46
+ Initialize a MatchKit design system in your project. Links to your configuration on matchkit.io.
47
+
48
+ ```bash
49
+ matchkit init
50
+ ```
51
+
52
+ ### `matchkit pull`
53
+
54
+ Download your latest resolved design system from MatchKit.
55
+
56
+ ```bash
57
+ matchkit pull
58
+ ```
59
+
60
+ ### `matchkit add <component>`
61
+
62
+ Install a single component with its dependencies.
63
+
64
+ ```bash
65
+ matchkit add button
66
+ matchkit add data-table
67
+ ```
68
+
69
+ ### `matchkit list`
70
+
71
+ Show all 27 components with their installation status.
72
+
73
+ ```bash
74
+ matchkit list
75
+ ```
76
+
77
+ ### `matchkit status`
78
+
79
+ Show current configuration, theme, version, and sync status.
80
+
81
+ ```bash
82
+ matchkit status
83
+ ```
84
+
85
+ ### `matchkit diff`
86
+
87
+ Show what changed since your last pull.
88
+
89
+ ```bash
90
+ matchkit diff
91
+ ```
92
+
93
+ ## Configuration
94
+
95
+ The CLI stores:
96
+ - **Project config**: `.matchkit/config.json` (in your project)
97
+ - **API key**: `~/.matchkit/credentials` (global, never committed)
98
+
99
+ ### .matchkit/config.json
100
+
101
+ ```json
102
+ {
103
+ "$schema": "https://matchkit.io/schemas/config.json",
104
+ "configId": "cfg_a1b2c3d4e5f6",
105
+ "version": 3,
106
+ "theme": "soft",
107
+ "accent": "#14B8A6",
108
+ "overrides": { "radius": "xl", "button-style": "ghost" },
109
+ "componentsDir": "src/components/ui",
110
+ "skillDir": ".claude/skills/soft-ui",
111
+ "registryUrl": "https://matchkit.io/api/registry"
112
+ }
113
+ ```
114
+
115
+ ## CI/CD Usage
116
+
117
+ For automated deployments, set the `MATCHKIT_API_KEY` environment variable:
118
+
119
+ ```yaml
120
+ # GitHub Actions
121
+ - name: Pull MatchKit design system
122
+ env:
123
+ MATCHKIT_API_KEY: ${{ secrets.MATCHKIT_API_KEY }}
124
+ run: |
125
+ npm install -g @matchkit.io/cli
126
+ matchkit pull
127
+ ```
128
+
129
+ Get your API key from https://matchkit.io/app/keys
130
+
131
+ ## How It Works
132
+
133
+ 1. **Authentication**: Browser OAuth flow creates an API key
134
+ 2. **Configuration**: Links your project to your MatchKit design system
135
+ 3. **Resolution**: Server-side resolution generates your personalized skill
136
+ 4. **Download**: ZIP download with all components, tokens, and documentation
137
+ 5. **Extraction**: Files land in `.claude/skills/[theme]-ui/`
138
+
139
+ ## Requirements
140
+
141
+ - Node.js 18 or later
142
+ - A MatchKit account (free tier available at https://matchkit.io)
143
+
144
+ ## Links
145
+
146
+ - **Website**: https://matchkit.io
147
+ - **Documentation**: https://matchkit.io/docs
148
+ - **Dashboard**: https://matchkit.io/app
149
+ - **Repository**: https://github.com/Maes9/matchkit
150
+ - **Issues**: https://github.com/Maes9/matchkit/issues
151
+
152
+ ## License
153
+
154
+ MIT
@@ -33,17 +33,7 @@ async function verifyKey(apiKey) {
33
33
  }
34
34
  export async function loginCommand(options) {
35
35
  p.intro(pc.bold("matchkit login"));
36
- const existing = getApiKey();
37
- if (existing) {
38
- const overwrite = await p.confirm({
39
- message: "You already have an API key stored. Replace it?",
40
- });
41
- if (p.isCancel(overwrite) || !overwrite) {
42
- p.outro("Keeping existing key.");
43
- return;
44
- }
45
- }
46
- // --key flag or non-interactive: fall back to manual key entry
36
+ // --key flag or non-interactive: skip all interactive prompts
47
37
  if (options?.key || !process.stdin.isTTY) {
48
38
  const apiKey = options?.key ?? process.env.MATCHKIT_API_KEY;
49
39
  if (!apiKey) {
@@ -64,6 +54,17 @@ export async function loginCommand(options) {
64
54
  p.outro("Key stored in " + pc.dim("~/.matchkit/credentials"));
65
55
  return;
66
56
  }
57
+ // Interactive flow below: requires TTY
58
+ const existing = getApiKey();
59
+ if (existing) {
60
+ const overwrite = await p.confirm({
61
+ message: "You already have an API key stored. Replace it?",
62
+ });
63
+ if (p.isCancel(overwrite) || !overwrite) {
64
+ p.outro("Keeping existing key.");
65
+ return;
66
+ }
67
+ }
67
68
  // Browser-based auth flow
68
69
  const s = p.spinner();
69
70
  const callbackPromise = new Promise((resolve, reject) => {
@@ -1 +1,3 @@
1
- export declare function pullCommand(): Promise<void>;
1
+ export declare function pullCommand(options?: {
2
+ configId?: string;
3
+ }): Promise<void>;
@@ -2,32 +2,61 @@ import * as p from "@clack/prompts";
2
2
  import pc from "picocolors";
3
3
  import { writeFileSync, mkdirSync, existsSync } from "node:fs";
4
4
  import { join, dirname } from "node:path";
5
- import { readConfig, configExists, writeConfig } from "../utils/config.js";
5
+ import { readConfig, configExists, writeConfig, createDefaultConfig } from "../utils/config.js";
6
6
  import { getApiKey, authFetch, API_BASE_URL } from "../utils/auth.js";
7
- export async function pullCommand() {
7
+ export async function pullCommand(options) {
8
8
  p.intro(pc.bold("matchkit pull"));
9
9
  // Check auth
10
10
  const apiKey = getApiKey();
11
11
  if (!apiKey) {
12
- p.log.error("Not logged in. Run " + pc.bold("matchkit login") + " first.");
12
+ p.log.error("Not logged in. Run " + pc.bold("matchkit login --key <key>") + " first.");
13
13
  process.exit(1);
14
14
  }
15
+ // Auto-create config.json if --config-id provided and no config exists
16
+ if (options?.configId) {
17
+ if (!configExists()) {
18
+ const cs = p.spinner();
19
+ cs.start("Fetching project details...");
20
+ try {
21
+ const res = await authFetch(`${API_BASE_URL}/api/v1/configs/${options.configId}`);
22
+ if (!res.ok) {
23
+ cs.stop("Failed");
24
+ p.log.error(`Project ${pc.dim(options.configId)} not found (${res.status})`);
25
+ process.exit(1);
26
+ }
27
+ const data = (await res.json());
28
+ cs.stop("Project found");
29
+ const newConfig = createDefaultConfig(data.theme, data.accent ?? "#4F46E5", (data.overrides ?? {}));
30
+ writeConfig({ ...newConfig, configId: options.configId });
31
+ p.log.success(`Created .matchkit/config.json for ${pc.bold(data.theme + "-ui")}`);
32
+ }
33
+ catch {
34
+ cs.stop("Failed");
35
+ p.log.error("Could not fetch project details. Check your connection and API key.");
36
+ process.exit(1);
37
+ }
38
+ }
39
+ else {
40
+ // Config exists — update configId
41
+ const existing = readConfig();
42
+ writeConfig({ ...existing, configId: options.configId });
43
+ }
44
+ }
15
45
  // Check config
16
46
  if (!configExists()) {
17
- p.log.error("No .matchkit/config.json found. Run " +
47
+ p.log.error("No .matchkit/config.json found. Use " +
48
+ pc.bold("--config-id <id>") +
49
+ " or run " +
18
50
  pc.bold("matchkit init") +
19
- " first.");
51
+ ".");
20
52
  process.exit(1);
21
53
  }
22
54
  const config = readConfig();
23
55
  const configId = config.configId;
24
56
  if (!configId) {
25
- p.log.error("No configId in .matchkit/config.json. This project was set up before the hosted resolution model.");
26
- p.log.info("Create a config at " +
27
- pc.cyan("matchkit.io/app") +
28
- " and run " +
29
- pc.bold("matchkit init") +
30
- " again.");
57
+ p.log.error("No configId in .matchkit/config.json. Use " +
58
+ pc.bold("matchkit pull --config-id <id>") +
59
+ " to link a project.");
31
60
  process.exit(1);
32
61
  }
33
62
  const s = p.spinner();
package/dist/index.js CHANGED
@@ -11,7 +11,7 @@ const program = new Command();
11
11
  program
12
12
  .name("matchkit")
13
13
  .description("MatchKit — style-agnostic design system CLI")
14
- .version("0.1.0");
14
+ .version("0.1.1");
15
15
  program
16
16
  .command("init")
17
17
  .description("Initialize a MatchKit design system in your project")
@@ -37,6 +37,7 @@ program
37
37
  program
38
38
  .command("pull")
39
39
  .description("Pull your latest resolved design system from the server")
40
+ .option("--config-id <id>", "Server config ID (skips matchkit init)")
40
41
  .action(pullCommand);
41
42
  program
42
43
  .command("status")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@matchkit.io/cli",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "CLI for MatchKit design system skills. Init projects, add components, manage your design system.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",