mkt-skills 1.2.1 → 1.3.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 +4 -0
- package/bin/mkt-skills.mjs +4 -3
- package/lib/api.mjs +8 -1
- package/lib/commands.mjs +32 -28
- package/lib/paths.mjs +6 -0
- package/lib/video.mjs +6 -7
- package/package.json +10 -3
package/README.md
CHANGED
package/bin/mkt-skills.mjs
CHANGED
|
@@ -37,7 +37,7 @@ if (!command || command === '--help' || command === '-h') {
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
if (command === '--version' || command === '-v') {
|
|
40
|
-
console.log('mkt-skills 1.
|
|
40
|
+
console.log('mkt-skills 1.3.1');
|
|
41
41
|
process.exit(0);
|
|
42
42
|
}
|
|
43
43
|
|
|
@@ -47,7 +47,8 @@ if (!commandMap[command]) {
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
try {
|
|
50
|
-
|
|
50
|
+
// subCommand is argv[3]; reassemble the full positional list (it was dropped before)
|
|
51
|
+
await commandMap[command]([subCommand, ...args].filter(Boolean));
|
|
51
52
|
} catch (err) {
|
|
52
53
|
if (err.name === 'AbortError') {
|
|
53
54
|
console.error('Request timed out. Check your internet connection.');
|
|
@@ -69,7 +70,7 @@ Usage:
|
|
|
69
70
|
Commands:
|
|
70
71
|
install <slug> Install a skill to ~/.claude/skills/
|
|
71
72
|
list List all available skills
|
|
72
|
-
search <
|
|
73
|
+
search "<query>" Find skills by what you want to do (ranked)
|
|
73
74
|
info <slug> Show details about a skill
|
|
74
75
|
uninstall <slug> Remove an installed skill
|
|
75
76
|
sets List available skill sets
|
package/lib/api.mjs
CHANGED
|
@@ -8,7 +8,7 @@ async function request(path) {
|
|
|
8
8
|
try {
|
|
9
9
|
const res = await fetch(`${BASE_URL}${path}`, {
|
|
10
10
|
signal: controller.signal,
|
|
11
|
-
headers: { 'User-Agent': 'mkt-skills-cli/1.1
|
|
11
|
+
headers: { 'User-Agent': 'mkt-skills-cli/1.3.1' },
|
|
12
12
|
});
|
|
13
13
|
return res;
|
|
14
14
|
} finally {
|
|
@@ -40,6 +40,13 @@ export async function fetchSet(slug) {
|
|
|
40
40
|
return res.json();
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
export async function fetchSearch(query, limit = 5) {
|
|
44
|
+
const params = new URLSearchParams({ q: query, limit: String(limit) });
|
|
45
|
+
const res = await request(`/search?${params.toString()}`);
|
|
46
|
+
if (!res.ok) throw new Error(`Failed to fetch search results (HTTP ${res.status})`);
|
|
47
|
+
return res.json();
|
|
48
|
+
}
|
|
49
|
+
|
|
43
50
|
export async function fetchInstall(slug, code) {
|
|
44
51
|
const path = `/install/${encodeURIComponent(slug)}` + (code ? `?code=${encodeURIComponent(code)}` : '');
|
|
45
52
|
const res = await request(path);
|
package/lib/commands.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { mkdir, rm, access, writeFile } from 'fs/promises';
|
|
2
2
|
import { createInterface } from 'readline';
|
|
3
|
-
import { fetchCatalog, fetchInstall, fetchSets, fetchSet } from './api.mjs';
|
|
3
|
+
import { fetchCatalog, fetchInstall, fetchSets, fetchSet, fetchSearch } from './api.mjs';
|
|
4
4
|
import { skillDir, skillFile, installedSlugs } from './paths.mjs';
|
|
5
5
|
import { bold, dim, green, red, yellow, cyan } from './ui.mjs';
|
|
6
6
|
|
|
@@ -112,39 +112,43 @@ export async function list(args) {
|
|
|
112
112
|
|
|
113
113
|
// ── search ──────────────────────────────────────────────────
|
|
114
114
|
|
|
115
|
-
export
|
|
116
|
-
const query =
|
|
115
|
+
export function renderSearchResults(payload) {
|
|
116
|
+
const { query, results = [] } = payload;
|
|
117
|
+
const out = [];
|
|
117
118
|
|
|
118
|
-
if (!
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
const catalog = await fetchCatalog();
|
|
124
|
-
const results = catalog.filter(s =>
|
|
125
|
-
s.slug.includes(query) ||
|
|
126
|
-
s.title.toLowerCase().includes(query) ||
|
|
127
|
-
s.description.toLowerCase().includes(query) ||
|
|
128
|
-
s.categories.some(c => c.toLowerCase().includes(query))
|
|
129
|
-
);
|
|
130
|
-
|
|
131
|
-
if (results.length === 0) {
|
|
132
|
-
console.log(`\nNo skills found matching "${query}".`);
|
|
133
|
-
console.log(`${dim('->')} Browse all: ${cyan('npx mkt-skills list')}\n`);
|
|
134
|
-
return;
|
|
119
|
+
if (!results.length) {
|
|
120
|
+
out.push(`\nNo close matches for ${bold(`"${query}"`)}.`);
|
|
121
|
+
out.push(`${dim('->')} Browse all: ${cyan('npx mkt-skills list')}\n`);
|
|
122
|
+
return out.join('\n');
|
|
135
123
|
}
|
|
136
124
|
|
|
137
|
-
|
|
125
|
+
out.push(`\n${bold(`Best matches for "${query}"`)}\n`);
|
|
126
|
+
results.forEach((r, i) => {
|
|
127
|
+
const price = r.price === 'paid' ? yellow(' [premium]') : '';
|
|
128
|
+
const cats = r.categories?.length ? dim(` (${r.categories.join(', ')})`) : '';
|
|
129
|
+
out.push(` ${bold(`${i + 1}. ${r.slug}`)}${price}${cats}`);
|
|
130
|
+
out.push(` ${r.description}`);
|
|
131
|
+
if (r.matched && r.matched.length) {
|
|
132
|
+
out.push(` ${dim(`↳ matched: ${r.matched.join(', ')}`)}`);
|
|
133
|
+
}
|
|
134
|
+
out.push(` ${dim('Install:')} ${cyan(`npx mkt-skills install ${r.slug}`)}`);
|
|
135
|
+
out.push('');
|
|
136
|
+
});
|
|
137
|
+
return out.join('\n');
|
|
138
|
+
}
|
|
138
139
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
console.
|
|
143
|
-
|
|
144
|
-
console.log('');
|
|
140
|
+
export async function search(args) {
|
|
141
|
+
const query = args.filter(a => !a.startsWith('-')).join(' ');
|
|
142
|
+
if (!query) {
|
|
143
|
+
console.error('Usage: mkt-skills search "<what you want to do>"\n');
|
|
144
|
+
process.exit(1);
|
|
145
145
|
}
|
|
146
|
+
const limitFlag = args.find(a => a.startsWith('--limit='));
|
|
147
|
+
const parsedLimit = limitFlag ? parseInt(limitFlag.split('=')[1], 10) : NaN;
|
|
148
|
+
const limit = Number.isInteger(parsedLimit) && parsedLimit > 0 ? parsedLimit : 5;
|
|
146
149
|
|
|
147
|
-
|
|
150
|
+
const payload = await fetchSearch(query, limit);
|
|
151
|
+
console.log(renderSearchResults(payload));
|
|
148
152
|
}
|
|
149
153
|
|
|
150
154
|
// ── info ────────────────────────────────────────────────────
|
package/lib/paths.mjs
CHANGED
|
@@ -4,7 +4,13 @@ import { readdir } from 'fs/promises';
|
|
|
4
4
|
|
|
5
5
|
const SKILLS_ROOT = join(homedir(), '.claude', 'skills');
|
|
6
6
|
|
|
7
|
+
const SLUG_RE = /^[a-z0-9][a-z0-9-]*$/;
|
|
8
|
+
|
|
9
|
+
// Slugs come from the user and from the server. Never let one escape SKILLS_ROOT.
|
|
7
10
|
export function skillDir(slug) {
|
|
11
|
+
if (typeof slug !== 'string' || !SLUG_RE.test(slug)) {
|
|
12
|
+
throw new Error(`Invalid skill slug: ${JSON.stringify(slug)}`);
|
|
13
|
+
}
|
|
8
14
|
return join(SKILLS_ROOT, slug);
|
|
9
15
|
}
|
|
10
16
|
|
package/lib/video.mjs
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { createInterface } from "readline";
|
|
2
|
-
import { mkdir, rm, writeFile, readFile } from "fs/promises";
|
|
2
|
+
import { mkdir, mkdtemp, rm, writeFile, readFile } from "fs/promises";
|
|
3
3
|
import { existsSync } from "fs";
|
|
4
4
|
import { join, dirname } from "path";
|
|
5
|
-
import { execSync } from "child_process";
|
|
5
|
+
import { execSync, execFileSync } from "child_process";
|
|
6
|
+
import { tmpdir } from "os";
|
|
6
7
|
import { bold, dim, green, red, cyan } from "./ui.mjs";
|
|
7
8
|
|
|
8
9
|
const TEMPLATE_REPO = "https://github.com/sandeepkelvadi/tm-videogen-template.git";
|
|
9
10
|
const TEMPLATE_BRANCH = "main";
|
|
10
|
-
|
|
11
|
+
let TEMPLATE_DIR; // private temp dir, created per run in cloneTemplate()
|
|
11
12
|
|
|
12
13
|
async function question(query) {
|
|
13
14
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
@@ -105,10 +106,8 @@ function exec(cmd, cwd) {
|
|
|
105
106
|
}
|
|
106
107
|
|
|
107
108
|
async function cloneTemplate() {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
}
|
|
111
|
-
execSync(`git clone --depth=1 --branch ${TEMPLATE_BRANCH} ${TEMPLATE_REPO} "${TEMPLATE_DIR}"`, { stdio: "pipe" });
|
|
109
|
+
TEMPLATE_DIR = await mkdtemp(join(tmpdir(), "tm-videogen-"));
|
|
110
|
+
execFileSync("git", ["clone", "--depth=1", "--branch", TEMPLATE_BRANCH, TEMPLATE_REPO, TEMPLATE_DIR], { stdio: "pipe" });
|
|
112
111
|
}
|
|
113
112
|
|
|
114
113
|
export async function video(args) {
|
package/package.json
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mkt-skills",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.1",
|
|
4
4
|
"description": "Install Claude Code marketing skills from marketingskills.directory",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"mkt-skills": "bin/mkt-skills.mjs"
|
|
8
8
|
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"test": "node --test"
|
|
11
|
+
},
|
|
9
12
|
"engines": {
|
|
10
13
|
"node": ">=18.0.0"
|
|
11
14
|
},
|
|
@@ -30,7 +33,11 @@
|
|
|
30
33
|
"license": "MIT",
|
|
31
34
|
"repository": {
|
|
32
35
|
"type": "git",
|
|
33
|
-
"url": "git+https://github.com/sandeepkelvadi/mkt-skills
|
|
36
|
+
"url": "git+https://github.com/sandeepkelvadi/mkt-skills.git",
|
|
37
|
+
"directory": "cli"
|
|
34
38
|
},
|
|
35
|
-
"homepage": "https://marketingskills.directory"
|
|
39
|
+
"homepage": "https://marketingskills.directory",
|
|
40
|
+
"bugs": {
|
|
41
|
+
"url": "https://github.com/sandeepkelvadi/mkt-skills/issues"
|
|
42
|
+
}
|
|
36
43
|
}
|