@matchkit.io/cli 0.1.3 → 0.1.4
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/pull.js +42 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/dist/commands/pull.js
CHANGED
|
@@ -138,6 +138,37 @@ function writeAiRulesFiles(cwd, skillDir, theme) {
|
|
|
138
138
|
}
|
|
139
139
|
return written;
|
|
140
140
|
}
|
|
141
|
+
/**
|
|
142
|
+
* Detect if ZIP paths share a common prefix that matches the skillDir.
|
|
143
|
+
* e.g., if skillDir is ".claude/skills/glass-ui" and ZIP paths start with
|
|
144
|
+
* ".claude/skills/glass-ui/components/...", return ".claude/skills/glass-ui/"
|
|
145
|
+
* so we can strip it and avoid double nesting.
|
|
146
|
+
*
|
|
147
|
+
* Returns the prefix string (with trailing slash) or null if paths are flat.
|
|
148
|
+
*/
|
|
149
|
+
function detectPrefix(paths, skillDir) {
|
|
150
|
+
if (paths.length === 0)
|
|
151
|
+
return null;
|
|
152
|
+
// Normalize skillDir: remove leading/trailing slashes, then add trailing slash
|
|
153
|
+
const normalized = skillDir.replace(/^\/+|\/+$/g, "") + "/";
|
|
154
|
+
// Check if most paths start with the skillDir prefix
|
|
155
|
+
const matchCount = paths.filter((p) => p.startsWith(normalized)).length;
|
|
156
|
+
// If >50% of paths match, it's a prefixed ZIP
|
|
157
|
+
if (matchCount > paths.length / 2) {
|
|
158
|
+
return normalized;
|
|
159
|
+
}
|
|
160
|
+
// Also check for .claude/skills/<theme>-ui/ pattern in case skillDir differs
|
|
161
|
+
const firstPath = paths[0];
|
|
162
|
+
const match = firstPath.match(/^(\.claude\/skills\/[^/]+\/)/);
|
|
163
|
+
if (match) {
|
|
164
|
+
const candidatePrefix = match[1];
|
|
165
|
+
const prefixCount = paths.filter((p) => p.startsWith(candidatePrefix)).length;
|
|
166
|
+
if (prefixCount > paths.length / 2) {
|
|
167
|
+
return candidatePrefix;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return null;
|
|
171
|
+
}
|
|
141
172
|
export async function pullCommand(options) {
|
|
142
173
|
p.intro(pc.bold("matchkit pull"));
|
|
143
174
|
// Check auth
|
|
@@ -243,12 +274,22 @@ export async function pullCommand(options) {
|
|
|
243
274
|
if (!existsSync(fullSkillDir)) {
|
|
244
275
|
mkdirSync(fullSkillDir, { recursive: true });
|
|
245
276
|
}
|
|
277
|
+
// Detect if ZIP paths are prefixed with a skill directory
|
|
278
|
+
// (e.g., ".claude/skills/glass-ui/components/..." vs "components/...")
|
|
279
|
+
// The server may include the full skillDir prefix — we need to strip it
|
|
280
|
+
// so files land directly in fullSkillDir, not double-nested.
|
|
281
|
+
const allPaths = Object.keys(zip.files).filter((p) => !zip.files[p].dir);
|
|
282
|
+
const skillDirPrefix = detectPrefix(allPaths, config.skillDir);
|
|
246
283
|
let fileCount = 0;
|
|
247
284
|
for (const [path, entry] of Object.entries(zip.files)) {
|
|
248
285
|
if (entry.dir)
|
|
249
286
|
continue;
|
|
287
|
+
// Strip the detected prefix to avoid double nesting
|
|
288
|
+
const relativePath = skillDirPrefix && path.startsWith(skillDirPrefix)
|
|
289
|
+
? path.slice(skillDirPrefix.length)
|
|
290
|
+
: path;
|
|
250
291
|
const content = await entry.async("string");
|
|
251
|
-
const fullPath = join(fullSkillDir,
|
|
292
|
+
const fullPath = join(fullSkillDir, relativePath);
|
|
252
293
|
const dir = dirname(fullPath);
|
|
253
294
|
if (!existsSync(dir)) {
|
|
254
295
|
mkdirSync(dir, { recursive: true });
|
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.
|
|
14
|
+
.version("0.1.4");
|
|
15
15
|
program
|
|
16
16
|
.command("init")
|
|
17
17
|
.description("Initialize a MatchKit design system in your project")
|
package/package.json
CHANGED