simplemkt-skillctl 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.
Files changed (3) hide show
  1. package/README.md +11 -0
  2. package/bin.mjs +81 -0
  3. package/package.json +19 -0
package/README.md ADDED
@@ -0,0 +1,11 @@
1
+ # simplemkt-skillctl
2
+
3
+ 购买者会在平台订单交付中直接收到一行带个人授权码的命令:
4
+
5
+ ```bash
6
+ npx simplemkt-skillctl install creator-benchmark --license SMKT-你的授权码 --agent codex --scope project
7
+ ```
8
+
9
+ 不需要登录网站、输入短信码或打开浏览器。安装器向授权 API 校验命令内的授权码,获得一个只可使用一次、有效期 5 分钟的下载地址,验证 SHA-256 后写入对应 Agent 的 Skill 目录;它不会执行 Skill 内的脚本。
10
+
11
+ 默认 `--agent auto` 写入当前项目的 `.agents/skills`。已知宿主可显式使用 `--agent codex` 或 `--agent claude-code`;任何其他宿主可以用 `--target /你的/Skill/目录` 指定目录。
package/bin.mjs ADDED
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/env node
2
+ import crypto from 'node:crypto';
3
+ import fs from 'node:fs/promises';
4
+ import os from 'node:os';
5
+ import path from 'node:path';
6
+ import process from 'node:process';
7
+ import * as tar from 'tar';
8
+
9
+ const DEFAULT_API = process.env.SMKT_SKILL_API || 'https://api.simplemkt.cc';
10
+ const KNOWN_AGENTS = new Set(['auto', 'generic', 'codex', 'claude-code']);
11
+
12
+ function usage(message) {
13
+ if (message) console.error(`Error: ${message}\n`);
14
+ console.error('Usage: skillctl install <skill-slug> --license <SMKT-...> [--agent auto|codex|claude-code|generic] [--scope project|user] [--target path] [--api URL]');
15
+ process.exitCode = 1;
16
+ }
17
+
18
+ function option(name, fallback) {
19
+ const index = process.argv.indexOf(name);
20
+ return index === -1 ? fallback : process.argv[index + 1];
21
+ }
22
+
23
+ function agentDirectory(agent, scope, target) {
24
+ if (target) return path.resolve(target);
25
+ const root = scope === 'user' ? os.homedir() : process.cwd();
26
+ if (agent === 'codex' && scope === 'user') return path.join(root, '.codex', 'skills');
27
+ if (agent === 'claude-code') return path.join(root, '.claude', 'skills');
28
+ return path.join(root, '.agents', 'skills');
29
+ }
30
+
31
+ function shouldExtract(entryPath) {
32
+ const name = path.posix.basename(entryPath);
33
+ return name !== '.DS_Store' && !name.startsWith('._');
34
+ }
35
+
36
+ async function request(api, pathname, init = {}) {
37
+ const response = await fetch(new URL(pathname, `${api.replace(/\/$/, '')}/`), {
38
+ ...init,
39
+ headers: { 'Content-Type': 'application/json', ...(init.headers || {}) },
40
+ });
41
+ const payload = response.headers.get('content-type')?.includes('application/json') ? await response.json() : null;
42
+ if (!response.ok) throw new Error(payload?.error || `Request failed (${response.status})`);
43
+ return payload;
44
+ }
45
+
46
+ async function install() {
47
+ const slug = process.argv[3];
48
+ const license = option('--license');
49
+ const agent = option('--agent', option('--host', 'auto'));
50
+ const scope = option('--scope', 'project');
51
+ const targetOption = option('--target');
52
+ const api = option('--api', DEFAULT_API);
53
+ if (!slug || !license || !KNOWN_AGENTS.has(agent) || !['project', 'user'].includes(scope)) return usage('Missing or invalid install options.');
54
+
55
+ const authorization = await request(api, '/v1/install/authorize', {
56
+ method: 'POST',
57
+ body: JSON.stringify({ product_slug: slug, license_key: license, agent, scope }),
58
+ });
59
+ const archiveResponse = await fetch(new URL(authorization.download_url, `${api.replace(/\/$/, '')}/`));
60
+ if (!archiveResponse.ok) throw new Error(`Release download failed (${archiveResponse.status})`);
61
+ const archive = Buffer.from(await archiveResponse.arrayBuffer());
62
+ const expectedHash = archiveResponse.headers.get('x-simplemkt-sha256');
63
+ const actualHash = crypto.createHash('sha256').update(archive).digest('hex');
64
+ if (!expectedHash || expectedHash !== actualHash) throw new Error('Release checksum verification failed');
65
+
66
+ const target = agentDirectory(agent, scope, targetOption);
67
+ const temporaryDirectory = await fs.mkdtemp(path.join(os.tmpdir(), 'simplemkt-skill-'));
68
+ try {
69
+ const archivePath = path.join(temporaryDirectory, 'release.tar.gz');
70
+ await fs.writeFile(archivePath, archive);
71
+ await fs.mkdir(target, { recursive: true });
72
+ await tar.x({ file: archivePath, cwd: target, strict: true, filter: shouldExtract });
73
+ } finally {
74
+ await fs.rm(temporaryDirectory, { recursive: true, force: true });
75
+ }
76
+ console.log(`Installed ${slug} to ${target}`);
77
+ console.log('Review the installed SKILL.md before allowing the agent to run any referenced script.');
78
+ }
79
+
80
+ if (process.argv[2] !== 'install') usage();
81
+ else install().catch((error) => { console.error(`Installation failed: ${error.message}`); process.exitCode = 1; });
package/package.json ADDED
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "simplemkt-skillctl",
3
+ "version": "0.1.0",
4
+ "description": "Install licensed SimpleMkt Skills into supported agent hosts.",
5
+ "type": "module",
6
+ "bin": {
7
+ "skillctl": "./bin.mjs"
8
+ },
9
+ "files": [
10
+ "bin.mjs",
11
+ "README.md"
12
+ ],
13
+ "engines": {
14
+ "node": ">=20"
15
+ },
16
+ "dependencies": {
17
+ "tar": "^7.4.3"
18
+ }
19
+ }