ccjk 9.5.6 → 9.7.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/chunks/agent.mjs +1 -1
- package/dist/chunks/api-providers.mjs +1 -1
- package/dist/chunks/api.mjs +3 -3
- package/dist/chunks/auto-bootstrap.mjs +1 -1
- package/dist/chunks/auto-updater.mjs +1 -1
- package/dist/chunks/boost.mjs +160 -0
- package/dist/chunks/ccjk-agents.mjs +1 -1
- package/dist/chunks/ccjk-all.mjs +1 -1
- package/dist/chunks/ccjk-config.mjs +1 -1
- package/dist/chunks/ccjk-hooks.mjs +1 -1
- package/dist/chunks/ccjk-mcp.mjs +2 -2
- package/dist/chunks/ccjk-setup.mjs +1 -1
- package/dist/chunks/ccjk-skills.mjs +1 -1
- package/dist/chunks/ccr.mjs +25 -30
- package/dist/chunks/ccu.mjs +1 -1
- package/dist/chunks/check-updates.mjs +3 -4
- package/dist/chunks/claude-code-config-manager.mjs +7 -7
- package/dist/chunks/claude-code-incremental-manager.mjs +2 -2
- package/dist/chunks/claude-config.mjs +4 -4
- package/dist/chunks/claude-wrapper.mjs +2 -2
- package/dist/chunks/codex-config-switch.mjs +4 -5
- package/dist/chunks/codex-provider-manager.mjs +2 -3
- package/dist/chunks/codex-uninstaller.mjs +2 -2
- package/dist/chunks/codex.mjs +207 -6
- package/dist/chunks/commands.mjs +391 -88
- package/dist/chunks/commands2.mjs +88 -391
- package/dist/chunks/completion.mjs +1 -1
- package/dist/chunks/config-consolidator.mjs +2 -2
- package/dist/chunks/config-switch.mjs +3 -4
- package/dist/chunks/config.mjs +78 -7
- package/dist/chunks/config2.mjs +400 -410
- package/dist/chunks/config3.mjs +410 -400
- package/dist/chunks/constants.mjs +1 -1
- package/dist/chunks/doctor.mjs +4 -4
- package/dist/chunks/features.mjs +24 -17
- package/dist/chunks/index.mjs +178 -7
- package/dist/chunks/index2.mjs +1162 -169
- package/dist/chunks/index3.mjs +910 -1076
- package/dist/chunks/index4.mjs +137 -947
- package/dist/chunks/index5.mjs +635 -167
- package/dist/chunks/init.mjs +141 -99
- package/dist/chunks/installer.mjs +147 -649
- package/dist/chunks/installer2.mjs +649 -147
- package/dist/chunks/interview.mjs +2 -2
- package/dist/chunks/marketplace.mjs +1 -1
- package/dist/chunks/mcp.mjs +1058 -17
- package/dist/chunks/menu.mjs +147 -56
- package/dist/chunks/monitor.mjs +2 -2
- package/dist/chunks/notification.mjs +1 -1
- package/dist/chunks/onboarding.mjs +2 -2
- package/dist/chunks/package.mjs +2 -210
- package/dist/chunks/permission-manager.mjs +2 -2
- package/dist/chunks/permissions.mjs +1 -1
- package/dist/chunks/platform.mjs +1 -1
- package/dist/chunks/plugin.mjs +1 -1
- package/dist/chunks/prompts.mjs +1 -1
- package/dist/chunks/providers.mjs +1 -1
- package/dist/chunks/quick-setup.mjs +16 -20
- package/dist/chunks/silent-updater.mjs +1 -1
- package/dist/chunks/simple-config.mjs +2 -2
- package/dist/chunks/skill.mjs +1 -1
- package/dist/chunks/skills-sync.mjs +1 -1
- package/dist/chunks/skills.mjs +1 -1
- package/dist/chunks/startup.mjs +1 -1
- package/dist/chunks/stats.mjs +1 -1
- package/dist/chunks/status.mjs +159 -0
- package/dist/chunks/team.mjs +1 -1
- package/dist/chunks/thinking.mjs +2 -2
- package/dist/chunks/uninstall.mjs +6 -6
- package/dist/chunks/update.mjs +6 -9
- package/dist/chunks/upgrade-manager.mjs +2 -2
- package/dist/chunks/version-checker.mjs +3 -3
- package/dist/chunks/vim.mjs +1 -1
- package/dist/chunks/workflows.mjs +616 -215
- package/dist/cli.mjs +70 -121
- package/dist/index.d.mts +17 -1482
- package/dist/index.d.ts +17 -1482
- package/dist/index.mjs +950 -4740
- package/dist/shared/{ccjk.zCqdxT2Y.mjs → ccjk.Br91zBIG.mjs} +2 -2
- package/dist/shared/ccjk.CSkyCZIM.mjs +638 -0
- package/dist/shared/{ccjk.BKoi8-Hy.mjs → ccjk.DE91nClQ.mjs} +1 -1
- package/dist/shared/{ccjk.f40us0yY.mjs → ccjk.DvIrK0wz.mjs} +2 -2
- package/dist/shared/ccjk.LsPZ2PYo.mjs +1048 -0
- package/dist/shared/{ccjk.DRweXU5F.mjs → ccjk.q1koQxEE.mjs} +2 -2
- package/package.json +1 -1
- package/templates/claude-code/common/settings.json +15 -111
- package/dist/chunks/api-adapter.mjs +0 -180
- package/dist/chunks/cli.mjs +0 -2227
- package/dist/chunks/context-menu.mjs +0 -913
- package/dist/chunks/hooks-sync.mjs +0 -1627
- package/dist/chunks/index6.mjs +0 -663
- package/dist/chunks/mcp-market.mjs +0 -1077
- package/dist/chunks/mcp-server.mjs +0 -776
- package/dist/chunks/project-detector.mjs +0 -131
- package/dist/chunks/provider-registry.mjs +0 -92
- package/dist/chunks/setup-wizard.mjs +0 -362
- package/dist/chunks/tools.mjs +0 -143
- package/dist/chunks/workflows2.mjs +0 -633
- package/dist/shared/ccjk.BM_HZogn.mjs +0 -347
- package/dist/shared/ccjk.BaEp4UHQ.mjs +0 -75
- package/dist/shared/ccjk.CS0ybJCf.mjs +0 -490
- package/dist/shared/ccjk.CZgIwikC.mjs +0 -209
- package/dist/shared/ccjk.tO8zeFh1.mjs +0 -397
package/dist/chunks/index4.mjs
CHANGED
|
@@ -1,1005 +1,195 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import process__default from 'node:process';
|
|
4
|
+
import { join } from 'pathe';
|
|
5
|
+
import { i as installSuperpowers } from '../shared/ccjk.DE91nClQ.mjs';
|
|
6
|
+
import 'node:child_process';
|
|
7
|
+
import 'node:fs/promises';
|
|
8
|
+
import 'node:util';
|
|
9
|
+
import './index.mjs';
|
|
10
|
+
import 'node:url';
|
|
11
|
+
import 'i18next';
|
|
12
|
+
import 'i18next-fs-backend';
|
|
8
13
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
+
const CORE_SKILLS = [
|
|
15
|
+
"agent-browser",
|
|
16
|
+
"tdd",
|
|
17
|
+
"debugging",
|
|
18
|
+
"code-review",
|
|
19
|
+
"git-worktrees"
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
function getSuperpowersDir$1() {
|
|
23
|
+
return join(homedir(), ".claude", "plugins", "superpowers");
|
|
14
24
|
}
|
|
15
|
-
function
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
skill: "skills",
|
|
19
|
-
mcp: "mcp-servers",
|
|
20
|
-
agent: "agents",
|
|
21
|
-
hook: "hooks"
|
|
22
|
-
}[pluginType];
|
|
23
|
-
return path__default.join(configDir, typeDir, name);
|
|
25
|
+
function isSuperpowersInstalled() {
|
|
26
|
+
const superpowersDir = getSuperpowersDir$1();
|
|
27
|
+
return existsSync(superpowersDir) && existsSync(join(superpowersDir, "skills"));
|
|
24
28
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
const srcPath = path__default.join(src, entry.name);
|
|
30
|
-
const destPath = path__default.join(dest, entry.name);
|
|
31
|
-
if (entry.isDirectory()) {
|
|
32
|
-
await copyDirectory(srcPath, destPath);
|
|
33
|
-
} else {
|
|
34
|
-
await fs__default.copyFile(srcPath, destPath);
|
|
35
|
-
}
|
|
29
|
+
function areCoreSkillsInstalled() {
|
|
30
|
+
const skillsDir = join(getSuperpowersDir$1(), "skills");
|
|
31
|
+
if (!existsSync(skillsDir)) {
|
|
32
|
+
return false;
|
|
36
33
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
},
|
|
43
|
-
redirect: "follow"
|
|
44
|
-
});
|
|
45
|
-
if (!response.ok) {
|
|
46
|
-
throw new Error(`Failed to download: ${response.statusText}`);
|
|
34
|
+
for (const skill of CORE_SKILLS) {
|
|
35
|
+
const skillPath = join(skillsDir, skill);
|
|
36
|
+
if (!existsSync(skillPath) || !existsSync(join(skillPath, "skill.json"))) {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
47
39
|
}
|
|
48
|
-
|
|
49
|
-
await fs__default.writeFile(destPath, buffer);
|
|
40
|
+
return true;
|
|
50
41
|
}
|
|
51
|
-
|
|
52
|
-
async function installFromGitHub(sourceInfo, pluginType, options = {}) {
|
|
53
|
-
const { force = false, dryRun = false } = options;
|
|
54
|
-
const { owner, repo, ref = "main", subpath } = sourceInfo;
|
|
42
|
+
async function autoInstallSuperpowers(lang = "zh-CN") {
|
|
55
43
|
try {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const actualRef = ref || defaultBranch;
|
|
59
|
-
const installPath = getInstallPath(pluginType, repo);
|
|
60
|
-
if (!force) {
|
|
61
|
-
try {
|
|
62
|
-
await fs__default.access(installPath);
|
|
63
|
-
return {
|
|
64
|
-
success: false,
|
|
65
|
-
source: sourceInfo.originalUrl,
|
|
66
|
-
sourceType: "github",
|
|
67
|
-
pluginType,
|
|
68
|
-
error: `Plugin already exists at ${installPath}. Use --force to overwrite.`
|
|
69
|
-
};
|
|
70
|
-
} catch {
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
if (dryRun) {
|
|
74
|
-
const files = await listRepoFiles(owner, repo, actualRef, subpath);
|
|
75
|
-
return {
|
|
76
|
-
success: true,
|
|
77
|
-
source: sourceInfo.originalUrl,
|
|
78
|
-
sourceType: "github",
|
|
79
|
-
pluginType,
|
|
80
|
-
installedPath: installPath,
|
|
81
|
-
details: {
|
|
82
|
-
name: repo,
|
|
83
|
-
version: actualRef,
|
|
84
|
-
description: repoInfo.description || void 0,
|
|
85
|
-
files: files.slice(0, 20)
|
|
86
|
-
}
|
|
87
|
-
};
|
|
44
|
+
if (isSuperpowersInstalled() && areCoreSkillsInstalled()) {
|
|
45
|
+
return true;
|
|
88
46
|
}
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
source: sourceInfo.originalUrl,
|
|
98
|
-
sourceType: "github",
|
|
99
|
-
pluginType,
|
|
100
|
-
installedPath: installPath,
|
|
101
|
-
details: {
|
|
102
|
-
name: repo,
|
|
103
|
-
version: actualRef,
|
|
104
|
-
description: repoInfo.description || void 0,
|
|
105
|
-
files: installedFiles
|
|
47
|
+
const result = await installSuperpowers({
|
|
48
|
+
lang,
|
|
49
|
+
skipPrompt: true
|
|
50
|
+
// Skip user prompts for silent installation
|
|
51
|
+
});
|
|
52
|
+
if (!result.success) {
|
|
53
|
+
if (process__default.env.DEBUG) {
|
|
54
|
+
console.error("[CCJK Zero-Config] Installation failed:", result.error || result.message);
|
|
106
55
|
}
|
|
107
|
-
|
|
108
|
-
} catch (error) {
|
|
109
|
-
return {
|
|
110
|
-
success: false,
|
|
111
|
-
source: sourceInfo.originalUrl,
|
|
112
|
-
sourceType: "github",
|
|
113
|
-
pluginType,
|
|
114
|
-
error: error instanceof Error ? error.message : String(error)
|
|
115
|
-
};
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
async function fetchRepoInfo(owner, repo) {
|
|
119
|
-
const url = `https://api.github.com/repos/${owner}/${repo}`;
|
|
120
|
-
const response = await fetch(url, {
|
|
121
|
-
headers: {
|
|
122
|
-
"Accept": "application/vnd.github.v3+json",
|
|
123
|
-
"User-Agent": "ccjk-cli"
|
|
124
|
-
}
|
|
125
|
-
});
|
|
126
|
-
if (!response.ok) {
|
|
127
|
-
if (response.status === 404) {
|
|
128
|
-
throw new Error(`Repository not found: ${owner}/${repo}`);
|
|
56
|
+
return false;
|
|
129
57
|
}
|
|
130
|
-
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
async function listRepoFiles(owner, repo, ref, subpath) {
|
|
135
|
-
const treePath = subpath || "";
|
|
136
|
-
const url = `https://api.github.com/repos/${owner}/${repo}/git/trees/${ref}?recursive=1`;
|
|
137
|
-
const response = await fetch(url, {
|
|
138
|
-
headers: {
|
|
139
|
-
"Accept": "application/vnd.github.v3+json",
|
|
140
|
-
"User-Agent": "ccjk-cli"
|
|
58
|
+
return isSuperpowersInstalled() && areCoreSkillsInstalled();
|
|
59
|
+
} catch (error) {
|
|
60
|
+
if (process__default.env.DEBUG) {
|
|
61
|
+
console.error("[CCJK Zero-Config] Auto-install failed:", error);
|
|
141
62
|
}
|
|
142
|
-
|
|
143
|
-
if (!response.ok) {
|
|
144
|
-
return [];
|
|
63
|
+
return false;
|
|
145
64
|
}
|
|
146
|
-
const data = await response.json();
|
|
147
|
-
const files = (data.tree || []).filter((item) => item.type === "blob").map((item) => item.path).filter((filePath) => !treePath || filePath.startsWith(treePath));
|
|
148
|
-
return files;
|
|
149
|
-
}
|
|
150
|
-
async function downloadRepo(owner, repo, ref) {
|
|
151
|
-
const zipUrl = `https://github.com/${owner}/${repo}/archive/${ref}.zip`;
|
|
152
|
-
const tempDir = path__default.join(os__default.tmpdir(), `ccjk-${repo}-${Date.now()}`);
|
|
153
|
-
const zipPath = path__default.join(tempDir, "repo.zip");
|
|
154
|
-
await fs__default.mkdir(tempDir, { recursive: true });
|
|
155
|
-
await downloadFile(zipUrl, zipPath);
|
|
156
|
-
const extractedDir = await extractZip(zipPath, tempDir);
|
|
157
|
-
await fs__default.unlink(zipPath);
|
|
158
|
-
return extractedDir;
|
|
159
65
|
}
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
const execAsync = promisify(exec);
|
|
164
|
-
try {
|
|
165
|
-
await execAsync(`unzip -q "${zipPath}" -d "${destDir}"`);
|
|
166
|
-
} catch {
|
|
167
|
-
try {
|
|
168
|
-
await execAsync(`tar -xf "${zipPath}" -C "${destDir}"`);
|
|
169
|
-
} catch {
|
|
170
|
-
throw new Error("Failed to extract archive. Please ensure unzip or tar is installed.");
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
const entries = await fs__default.readdir(destDir);
|
|
174
|
-
const extractedDir = entries.find((entry) => !entry.endsWith(".zip"));
|
|
175
|
-
if (!extractedDir) {
|
|
176
|
-
throw new Error("Failed to find extracted directory");
|
|
177
|
-
}
|
|
178
|
-
return path__default.join(destDir, extractedDir);
|
|
66
|
+
|
|
67
|
+
function getSkillsDir() {
|
|
68
|
+
return join(homedir(), ".claude", "plugins", "superpowers", "skills");
|
|
179
69
|
}
|
|
180
|
-
|
|
181
|
-
const
|
|
182
|
-
|
|
183
|
-
const entries = await fs__default.readdir(currentDir, { withFileTypes: true });
|
|
184
|
-
for (const entry of entries) {
|
|
185
|
-
const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
186
|
-
if (entry.isDirectory()) {
|
|
187
|
-
await walk(path__default.join(currentDir, entry.name), relativePath);
|
|
188
|
-
} else {
|
|
189
|
-
files.push(relativePath);
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
await walk(dir);
|
|
194
|
-
return files;
|
|
70
|
+
function isSkillInstalled(skillName) {
|
|
71
|
+
const skillPath = join(getSkillsDir(), skillName);
|
|
72
|
+
return existsSync(skillPath) && existsSync(join(skillPath, "skill.json"));
|
|
195
73
|
}
|
|
196
|
-
|
|
197
|
-
async function installFromLocal(sourceInfo, pluginType, options = {}) {
|
|
198
|
-
const { force = false, dryRun = false } = options;
|
|
199
|
-
const { absolutePath, originalPath } = sourceInfo;
|
|
74
|
+
async function loadSkill(skillName) {
|
|
200
75
|
try {
|
|
201
|
-
|
|
202
|
-
const isFile = stat.isFile();
|
|
203
|
-
const isDirectory = stat.isDirectory();
|
|
204
|
-
if (!isFile && !isDirectory) {
|
|
76
|
+
if (!isSkillInstalled(skillName)) {
|
|
205
77
|
return {
|
|
78
|
+
skill: skillName,
|
|
206
79
|
success: false,
|
|
207
|
-
|
|
208
|
-
sourceType: "local",
|
|
209
|
-
pluginType,
|
|
210
|
-
error: `Source path is neither a file nor a directory: ${absolutePath}`
|
|
80
|
+
error: "Skill not installed"
|
|
211
81
|
};
|
|
212
82
|
}
|
|
213
|
-
const
|
|
214
|
-
const
|
|
215
|
-
if (!
|
|
216
|
-
try {
|
|
217
|
-
await fs__default.access(installPath);
|
|
218
|
-
return {
|
|
219
|
-
success: false,
|
|
220
|
-
source: originalPath,
|
|
221
|
-
sourceType: "local",
|
|
222
|
-
pluginType,
|
|
223
|
-
error: `Plugin already exists at ${installPath}. Use --force to overwrite.`
|
|
224
|
-
};
|
|
225
|
-
} catch {
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
const files = isFile ? [path__default.basename(absolutePath)] : await listFiles(absolutePath);
|
|
229
|
-
const pluginInfo = await readPluginInfo(absolutePath, isFile);
|
|
230
|
-
if (dryRun) {
|
|
83
|
+
const skillJsonPath = join(getSkillsDir(), skillName, "skill.json");
|
|
84
|
+
const skillJson = JSON.parse(readFileSync(skillJsonPath, "utf-8"));
|
|
85
|
+
if (!skillJson.name || !skillJson.version) {
|
|
231
86
|
return {
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
pluginType,
|
|
236
|
-
installedPath: installPath,
|
|
237
|
-
details: {
|
|
238
|
-
name: pluginInfo.name || pluginName,
|
|
239
|
-
version: pluginInfo.version,
|
|
240
|
-
description: pluginInfo.description,
|
|
241
|
-
files
|
|
242
|
-
}
|
|
87
|
+
skill: skillName,
|
|
88
|
+
success: false,
|
|
89
|
+
error: "Invalid skill.json format"
|
|
243
90
|
};
|
|
244
91
|
}
|
|
245
|
-
if (isFile) {
|
|
246
|
-
await fs__default.mkdir(path__default.dirname(installPath), { recursive: true });
|
|
247
|
-
if (absolutePath.endsWith(".md")) {
|
|
248
|
-
await fs__default.copyFile(absolutePath, installPath);
|
|
249
|
-
} else {
|
|
250
|
-
await fs__default.mkdir(installPath, { recursive: true });
|
|
251
|
-
await fs__default.copyFile(
|
|
252
|
-
absolutePath,
|
|
253
|
-
path__default.join(installPath, path__default.basename(absolutePath))
|
|
254
|
-
);
|
|
255
|
-
}
|
|
256
|
-
} else {
|
|
257
|
-
await fs__default.mkdir(path__default.dirname(installPath), { recursive: true });
|
|
258
|
-
await copyDirectory(absolutePath, installPath);
|
|
259
|
-
}
|
|
260
|
-
const installedFiles = isFile ? [path__default.basename(absolutePath)] : await listFiles(installPath);
|
|
261
92
|
return {
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
sourceType: "local",
|
|
265
|
-
pluginType,
|
|
266
|
-
installedPath: installPath,
|
|
267
|
-
details: {
|
|
268
|
-
name: pluginInfo.name || pluginName,
|
|
269
|
-
version: pluginInfo.version,
|
|
270
|
-
description: pluginInfo.description,
|
|
271
|
-
files: installedFiles
|
|
272
|
-
}
|
|
93
|
+
skill: skillName,
|
|
94
|
+
success: true
|
|
273
95
|
};
|
|
274
96
|
} catch (error) {
|
|
275
97
|
return {
|
|
98
|
+
skill: skillName,
|
|
276
99
|
success: false,
|
|
277
|
-
|
|
278
|
-
sourceType: "local",
|
|
279
|
-
pluginType,
|
|
280
|
-
error: error instanceof Error ? error.message : String(error)
|
|
100
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
281
101
|
};
|
|
282
102
|
}
|
|
283
103
|
}
|
|
284
|
-
async function
|
|
285
|
-
const
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
await walk(path__default.join(currentDir, entry.name), relativePath);
|
|
295
|
-
} else {
|
|
296
|
-
files.push(relativePath);
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
await walk(dir);
|
|
301
|
-
return files;
|
|
302
|
-
}
|
|
303
|
-
async function readPluginInfo(sourcePath, isFile) {
|
|
304
|
-
if (isFile) {
|
|
305
|
-
const name = path__default.basename(sourcePath, path__default.extname(sourcePath));
|
|
306
|
-
return { name };
|
|
307
|
-
}
|
|
308
|
-
try {
|
|
309
|
-
const packageJsonPath = path__default.join(sourcePath, "package.json");
|
|
310
|
-
const content = await fs__default.readFile(packageJsonPath, "utf-8");
|
|
311
|
-
const packageJson = JSON.parse(content);
|
|
312
|
-
return {
|
|
313
|
-
name: packageJson.name,
|
|
314
|
-
version: packageJson.version,
|
|
315
|
-
description: packageJson.description
|
|
316
|
-
};
|
|
317
|
-
} catch {
|
|
318
|
-
}
|
|
319
|
-
const metaFiles = ["SKILL.md", "skill.md", "README.md", "readme.md"];
|
|
320
|
-
for (const metaFile of metaFiles) {
|
|
321
|
-
try {
|
|
322
|
-
const metaPath = path__default.join(sourcePath, metaFile);
|
|
323
|
-
const content = await fs__default.readFile(metaPath, "utf-8");
|
|
324
|
-
const titleMatch = content.match(/^#\s+(.+)$/m);
|
|
325
|
-
if (titleMatch) {
|
|
326
|
-
return { name: titleMatch[1].trim() };
|
|
327
|
-
}
|
|
328
|
-
} catch {
|
|
104
|
+
async function loadCoreSkills(_lang = "zh-CN") {
|
|
105
|
+
const results = await Promise.all(
|
|
106
|
+
CORE_SKILLS.map((skill) => loadSkill(skill))
|
|
107
|
+
);
|
|
108
|
+
if (process__default.env.DEBUG) {
|
|
109
|
+
const successful = results.filter((r) => r.success);
|
|
110
|
+
const failed = results.filter((r) => !r.success);
|
|
111
|
+
console.log(`[Zero-Config] Loaded ${successful.length}/${CORE_SKILLS.length} core skills`);
|
|
112
|
+
if (failed.length > 0) {
|
|
113
|
+
console.log(`[Zero-Config] Failed skills: ${failed.map((r) => r.skill).join(", ")}`);
|
|
329
114
|
}
|
|
330
115
|
}
|
|
331
|
-
return
|
|
116
|
+
return results;
|
|
332
117
|
}
|
|
333
118
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
const { force = false, dryRun = false } = options;
|
|
337
|
-
const { packageName, version } = sourceInfo;
|
|
338
|
-
try {
|
|
339
|
-
const packageInfo = await fetchPackageInfo(packageName, version);
|
|
340
|
-
const packageVersion = version || packageInfo.version;
|
|
341
|
-
const shortName = getShortName(packageName);
|
|
342
|
-
const installPath = getInstallPath(pluginType, shortName);
|
|
343
|
-
if (!force) {
|
|
344
|
-
try {
|
|
345
|
-
await fs__default.access(installPath);
|
|
346
|
-
return {
|
|
347
|
-
success: false,
|
|
348
|
-
source: packageName,
|
|
349
|
-
sourceType: "npm",
|
|
350
|
-
pluginType,
|
|
351
|
-
error: `Plugin already exists at ${installPath}. Use --force to overwrite.`
|
|
352
|
-
};
|
|
353
|
-
} catch {
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
if (dryRun) {
|
|
357
|
-
const files = packageInfo.files || ["(package files)"];
|
|
358
|
-
return {
|
|
359
|
-
success: true,
|
|
360
|
-
source: packageName,
|
|
361
|
-
sourceType: "npm",
|
|
362
|
-
pluginType,
|
|
363
|
-
installedPath: installPath,
|
|
364
|
-
details: {
|
|
365
|
-
name: packageName,
|
|
366
|
-
version: packageVersion,
|
|
367
|
-
description: packageInfo.description,
|
|
368
|
-
files
|
|
369
|
-
}
|
|
370
|
-
};
|
|
371
|
-
}
|
|
372
|
-
if (pluginType === "mcp") {
|
|
373
|
-
await installMcpPackage(packageName, packageVersion, installPath);
|
|
374
|
-
} else {
|
|
375
|
-
await installGenericPackage(packageName, packageVersion, installPath);
|
|
376
|
-
}
|
|
377
|
-
const installedFiles = await listInstalledFiles(installPath);
|
|
378
|
-
return {
|
|
379
|
-
success: true,
|
|
380
|
-
source: packageName,
|
|
381
|
-
sourceType: "npm",
|
|
382
|
-
pluginType,
|
|
383
|
-
installedPath: installPath,
|
|
384
|
-
details: {
|
|
385
|
-
name: packageName,
|
|
386
|
-
version: packageVersion,
|
|
387
|
-
description: packageInfo.description,
|
|
388
|
-
files: installedFiles
|
|
389
|
-
}
|
|
390
|
-
};
|
|
391
|
-
} catch (error) {
|
|
392
|
-
return {
|
|
393
|
-
success: false,
|
|
394
|
-
source: packageName,
|
|
395
|
-
sourceType: "npm",
|
|
396
|
-
pluginType,
|
|
397
|
-
error: error instanceof Error ? error.message : String(error)
|
|
398
|
-
};
|
|
399
|
-
}
|
|
119
|
+
function getActivationStatePath() {
|
|
120
|
+
return join(homedir(), ".claude", "plugins", "superpowers", ".activation-state.json");
|
|
400
121
|
}
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
const response = await fetch(url);
|
|
404
|
-
if (!response.ok) {
|
|
405
|
-
if (response.status === 404) {
|
|
406
|
-
throw new Error(`Package not found: ${packageName}`);
|
|
407
|
-
}
|
|
408
|
-
throw new Error(`Failed to fetch package info: ${response.statusText}`);
|
|
409
|
-
}
|
|
410
|
-
const data = await response.json();
|
|
411
|
-
return {
|
|
412
|
-
version: data.version,
|
|
413
|
-
description: data.description,
|
|
414
|
-
files: data.files
|
|
415
|
-
};
|
|
416
|
-
}
|
|
417
|
-
function getShortName(packageName) {
|
|
418
|
-
if (packageName.startsWith("@")) {
|
|
419
|
-
const parts = packageName.split("/");
|
|
420
|
-
return parts[1] || packageName;
|
|
421
|
-
}
|
|
422
|
-
return packageName;
|
|
122
|
+
function getSuperpowersDir() {
|
|
123
|
+
return join(homedir(), ".claude", "plugins", "superpowers");
|
|
423
124
|
}
|
|
424
|
-
|
|
425
|
-
await fs__default.mkdir(installPath, { recursive: true });
|
|
426
|
-
const packageJson = {
|
|
427
|
-
name: `ccjk-mcp-${getShortName(packageName)}`,
|
|
428
|
-
version: "1.0.0",
|
|
429
|
-
private: true,
|
|
430
|
-
dependencies: {
|
|
431
|
-
[packageName]: version
|
|
432
|
-
}
|
|
433
|
-
};
|
|
434
|
-
await fs__default.writeFile(
|
|
435
|
-
path__default.join(installPath, "package.json"),
|
|
436
|
-
JSON.stringify(packageJson, null, 2)
|
|
437
|
-
);
|
|
125
|
+
function loadActivationState() {
|
|
438
126
|
try {
|
|
439
|
-
|
|
127
|
+
const statePath = getActivationStatePath();
|
|
128
|
+
if (!existsSync(statePath)) {
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
const stateJson = readFileSync(statePath, "utf-8");
|
|
132
|
+
return JSON.parse(stateJson);
|
|
440
133
|
} catch (error) {
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
} catch {
|
|
444
|
-
throw new Error(
|
|
445
|
-
`Failed to install package. Original error: ${error instanceof Error ? error.message : String(error)}`
|
|
446
|
-
);
|
|
134
|
+
if (process__default.env.DEBUG) {
|
|
135
|
+
console.error("[Zero-Config] Failed to load activation state:", error);
|
|
447
136
|
}
|
|
137
|
+
return null;
|
|
448
138
|
}
|
|
449
139
|
}
|
|
450
|
-
|
|
451
|
-
const registryUrl = `https://registry.npmjs.org/${packageName}/${version}`;
|
|
452
|
-
const response = await fetch(registryUrl);
|
|
453
|
-
if (!response.ok) {
|
|
454
|
-
throw new Error(`Failed to fetch package info: ${response.statusText}`);
|
|
455
|
-
}
|
|
456
|
-
const data = await response.json();
|
|
457
|
-
const tarballUrl = data.dist?.tarball;
|
|
458
|
-
if (!tarballUrl) {
|
|
459
|
-
throw new Error("Failed to get tarball URL");
|
|
460
|
-
}
|
|
461
|
-
const tarballResponse = await fetch(tarballUrl);
|
|
462
|
-
if (!tarballResponse.ok) {
|
|
463
|
-
throw new Error(`Failed to download tarball: ${tarballResponse.statusText}`);
|
|
464
|
-
}
|
|
465
|
-
await fs__default.mkdir(installPath, { recursive: true });
|
|
466
|
-
const tarballBuffer = Buffer.from(await tarballResponse.arrayBuffer());
|
|
467
|
-
const tarballPath = path__default.join(installPath, "package.tgz");
|
|
468
|
-
await fs__default.writeFile(tarballPath, tarballBuffer);
|
|
140
|
+
function saveActivationState(status) {
|
|
469
141
|
try {
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
}
|
|
476
|
-
async function listInstalledFiles(dir) {
|
|
477
|
-
const files = [];
|
|
478
|
-
async function walk(currentDir, prefix = "") {
|
|
479
|
-
try {
|
|
480
|
-
const entries = await fs__default.readdir(currentDir, { withFileTypes: true });
|
|
481
|
-
for (const entry of entries) {
|
|
482
|
-
if (entry.name === "node_modules")
|
|
483
|
-
continue;
|
|
484
|
-
const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
485
|
-
if (entry.isDirectory()) {
|
|
486
|
-
await walk(path__default.join(currentDir, entry.name), relativePath);
|
|
487
|
-
} else {
|
|
488
|
-
files.push(relativePath);
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
} catch {
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
await walk(dir);
|
|
495
|
-
return files;
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
function parseSource(source) {
|
|
499
|
-
const trimmed = source.trim();
|
|
500
|
-
const githubInfo = parseGitHubSource(trimmed);
|
|
501
|
-
if (githubInfo) {
|
|
502
|
-
return githubInfo;
|
|
503
|
-
}
|
|
504
|
-
const localInfo = parseLocalSource(trimmed);
|
|
505
|
-
if (localInfo) {
|
|
506
|
-
return localInfo;
|
|
507
|
-
}
|
|
508
|
-
return parseNpmSource(trimmed);
|
|
509
|
-
}
|
|
510
|
-
function parseGitHubSource(source) {
|
|
511
|
-
const prefixMatch = source.match(/^(?:github|gh):([^/]+)\/([^#@/]+)(?:#(.+))?$/);
|
|
512
|
-
if (prefixMatch) {
|
|
513
|
-
return {
|
|
514
|
-
type: "github",
|
|
515
|
-
owner: prefixMatch[1],
|
|
516
|
-
repo: prefixMatch[2],
|
|
517
|
-
ref: prefixMatch[3],
|
|
518
|
-
originalUrl: source
|
|
519
|
-
};
|
|
520
|
-
}
|
|
521
|
-
const urlMatch = source.match(
|
|
522
|
-
/^https?:\/\/github\.com\/([^/]+)\/([^/]+?)(?:\.git)?(?:\/tree\/([^/]+))?(?:\/(.+))?$/
|
|
523
|
-
);
|
|
524
|
-
if (urlMatch) {
|
|
525
|
-
return {
|
|
526
|
-
type: "github",
|
|
527
|
-
owner: urlMatch[1],
|
|
528
|
-
repo: urlMatch[2],
|
|
529
|
-
ref: urlMatch[3],
|
|
530
|
-
subpath: urlMatch[4],
|
|
531
|
-
originalUrl: source
|
|
532
|
-
};
|
|
533
|
-
}
|
|
534
|
-
const shortMatch = source.match(/^([\w-]+)\/([\w.-]+)(?:#(.+))?$/);
|
|
535
|
-
if (shortMatch && !source.startsWith(".") && !source.startsWith("/") && !source.startsWith("~")) {
|
|
536
|
-
return {
|
|
537
|
-
type: "github",
|
|
538
|
-
owner: shortMatch[1],
|
|
539
|
-
repo: shortMatch[2],
|
|
540
|
-
ref: shortMatch[3],
|
|
541
|
-
originalUrl: source
|
|
542
|
-
};
|
|
543
|
-
}
|
|
544
|
-
return null;
|
|
545
|
-
}
|
|
546
|
-
function parseLocalSource(source) {
|
|
547
|
-
if (source.startsWith("./") || source.startsWith("../") || source.startsWith("/") || source.startsWith("~/")) {
|
|
548
|
-
let absolutePath;
|
|
549
|
-
if (source.startsWith("~/")) {
|
|
550
|
-
absolutePath = path__default.join(os__default.homedir(), source.slice(2));
|
|
551
|
-
} else if (path__default.isAbsolute(source)) {
|
|
552
|
-
absolutePath = source;
|
|
553
|
-
} else {
|
|
554
|
-
absolutePath = path__default.resolve(process.cwd(), source);
|
|
142
|
+
const statePath = getActivationStatePath();
|
|
143
|
+
writeFileSync(statePath, JSON.stringify(status, null, 2), "utf-8");
|
|
144
|
+
} catch (error) {
|
|
145
|
+
if (process__default.env.DEBUG) {
|
|
146
|
+
console.error("[Zero-Config] Failed to save activation state:", error);
|
|
555
147
|
}
|
|
556
|
-
return {
|
|
557
|
-
type: "local",
|
|
558
|
-
absolutePath,
|
|
559
|
-
originalPath: source
|
|
560
|
-
};
|
|
561
|
-
}
|
|
562
|
-
if (/^[a-z]:[\\/]/i.test(source)) {
|
|
563
|
-
return {
|
|
564
|
-
type: "local",
|
|
565
|
-
absolutePath: path__default.resolve(source),
|
|
566
|
-
originalPath: source
|
|
567
|
-
};
|
|
568
148
|
}
|
|
569
|
-
return null;
|
|
570
149
|
}
|
|
571
|
-
function
|
|
572
|
-
const
|
|
573
|
-
const
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
return {
|
|
577
|
-
type: "npm",
|
|
578
|
-
scope: scopedMatch[1],
|
|
579
|
-
packageName: `${scopedMatch[1]}/${scopedMatch[2]}`,
|
|
580
|
-
version: scopedMatch[3]
|
|
581
|
-
};
|
|
582
|
-
}
|
|
583
|
-
const versionMatch = packageStr.match(/^([^@]+)@(.+)$/);
|
|
584
|
-
if (versionMatch) {
|
|
585
|
-
return {
|
|
586
|
-
type: "npm",
|
|
587
|
-
packageName: versionMatch[1],
|
|
588
|
-
version: versionMatch[2]
|
|
589
|
-
};
|
|
150
|
+
function checkActivationStatus() {
|
|
151
|
+
const superpowersInstalled = existsSync(getSuperpowersDir());
|
|
152
|
+
const savedState = loadActivationState();
|
|
153
|
+
if (savedState) {
|
|
154
|
+
return savedState;
|
|
590
155
|
}
|
|
591
156
|
return {
|
|
592
|
-
|
|
593
|
-
|
|
157
|
+
isInstalled: superpowersInstalled,
|
|
158
|
+
coreSkillsLoaded: false,
|
|
159
|
+
loadedSkills: [],
|
|
160
|
+
needsActivation: true,
|
|
161
|
+
lastActivation: void 0
|
|
594
162
|
};
|
|
595
163
|
}
|
|
596
|
-
function
|
|
597
|
-
const
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
async function detectPluginType(sourceInfo) {
|
|
602
|
-
const result = await detectPluginTypeWithConfidence(sourceInfo);
|
|
603
|
-
return result.type;
|
|
604
|
-
}
|
|
605
|
-
async function detectPluginTypeWithConfidence(sourceInfo) {
|
|
606
|
-
switch (sourceInfo.type) {
|
|
607
|
-
case "github":
|
|
608
|
-
return detectFromGitHub(sourceInfo);
|
|
609
|
-
case "npm":
|
|
610
|
-
return detectFromNpm(sourceInfo);
|
|
611
|
-
case "local":
|
|
612
|
-
return detectFromLocal(sourceInfo);
|
|
613
|
-
default:
|
|
614
|
-
return { type: "skill", confidence: "low", reason: "Unknown source type" };
|
|
615
|
-
}
|
|
616
|
-
}
|
|
617
|
-
async function detectFromGitHub(info) {
|
|
618
|
-
const repoNameResult = detectFromRepoName(info.repo);
|
|
619
|
-
if (repoNameResult.confidence === "high") {
|
|
620
|
-
return repoNameResult;
|
|
164
|
+
async function activateSuperpowers(lang = "zh-CN") {
|
|
165
|
+
const currentStatus = checkActivationStatus();
|
|
166
|
+
if (!currentStatus.needsActivation) {
|
|
167
|
+
return currentStatus;
|
|
621
168
|
}
|
|
622
|
-
|
|
623
|
-
const
|
|
624
|
-
|
|
625
|
-
if (response.ok) {
|
|
626
|
-
const packageJson = await response.json();
|
|
627
|
-
const pkgResult = detectFromPackageJson(packageJson);
|
|
628
|
-
if (pkgResult.confidence !== "low") {
|
|
629
|
-
return pkgResult;
|
|
630
|
-
}
|
|
631
|
-
}
|
|
632
|
-
} catch {
|
|
633
|
-
}
|
|
634
|
-
const filePatterns = [
|
|
635
|
-
{ file: "SKILL.md", type: "skill" },
|
|
636
|
-
{ file: "skill.md", type: "skill" },
|
|
637
|
-
{ file: "AGENT.md", type: "agent" },
|
|
638
|
-
{ file: "agent.md", type: "agent" },
|
|
639
|
-
{ file: "mcp.json", type: "mcp" },
|
|
640
|
-
{ file: "hook.json", type: "hook" }
|
|
641
|
-
];
|
|
642
|
-
for (const pattern of filePatterns) {
|
|
643
|
-
try {
|
|
644
|
-
const fileUrl = buildGitHubRawUrl(info, pattern.file);
|
|
645
|
-
const response = await fetch(fileUrl, { method: "HEAD" });
|
|
646
|
-
if (response.ok) {
|
|
647
|
-
return {
|
|
648
|
-
type: pattern.type,
|
|
649
|
-
confidence: "high",
|
|
650
|
-
reason: `Found ${pattern.file}`
|
|
651
|
-
};
|
|
652
|
-
}
|
|
653
|
-
} catch {
|
|
654
|
-
}
|
|
655
|
-
}
|
|
656
|
-
return repoNameResult.confidence !== "low" ? repoNameResult : { type: "skill", confidence: "low", reason: "Default type" };
|
|
657
|
-
}
|
|
658
|
-
async function detectFromNpm(info) {
|
|
659
|
-
const nameResult = detectFromPackageName(info.packageName);
|
|
660
|
-
if (nameResult.confidence === "high") {
|
|
661
|
-
return nameResult;
|
|
662
|
-
}
|
|
663
|
-
try {
|
|
664
|
-
const registryUrl = `https://registry.npmjs.org/${info.packageName}`;
|
|
665
|
-
const response = await fetch(registryUrl);
|
|
666
|
-
if (response.ok) {
|
|
667
|
-
const data = await response.json();
|
|
668
|
-
const latestVersion = data["dist-tags"]?.latest;
|
|
669
|
-
if (latestVersion && data.versions?.[latestVersion]) {
|
|
670
|
-
const packageJson = data.versions[latestVersion];
|
|
671
|
-
const pkgResult = detectFromPackageJson(packageJson);
|
|
672
|
-
if (pkgResult.confidence !== "low") {
|
|
673
|
-
return pkgResult;
|
|
674
|
-
}
|
|
675
|
-
}
|
|
676
|
-
}
|
|
677
|
-
} catch {
|
|
678
|
-
}
|
|
679
|
-
return nameResult.confidence !== "low" ? nameResult : { type: "skill", confidence: "low", reason: "Default type" };
|
|
680
|
-
}
|
|
681
|
-
async function detectFromLocal(info) {
|
|
682
|
-
const { absolutePath } = info;
|
|
683
|
-
const dirName = path__default.basename(absolutePath);
|
|
684
|
-
const dirResult = detectFromRepoName(dirName);
|
|
685
|
-
if (dirResult.confidence === "high") {
|
|
686
|
-
return dirResult;
|
|
687
|
-
}
|
|
688
|
-
try {
|
|
689
|
-
const packageJsonPath = path__default.join(absolutePath, "package.json");
|
|
690
|
-
const content = await fs__default.readFile(packageJsonPath, "utf-8");
|
|
691
|
-
const packageJson = JSON.parse(content);
|
|
692
|
-
const pkgResult = detectFromPackageJson(packageJson);
|
|
693
|
-
if (pkgResult.confidence !== "low") {
|
|
694
|
-
return pkgResult;
|
|
695
|
-
}
|
|
696
|
-
} catch {
|
|
697
|
-
}
|
|
698
|
-
const filePatterns = [
|
|
699
|
-
{ file: "SKILL.md", type: "skill" },
|
|
700
|
-
{ file: "skill.md", type: "skill" },
|
|
701
|
-
{ file: "AGENT.md", type: "agent" },
|
|
702
|
-
{ file: "agent.md", type: "agent" },
|
|
703
|
-
{ file: "mcp.json", type: "mcp" },
|
|
704
|
-
{ file: "hook.json", type: "hook" }
|
|
705
|
-
];
|
|
706
|
-
for (const pattern of filePatterns) {
|
|
707
|
-
try {
|
|
708
|
-
const filePath = path__default.join(absolutePath, pattern.file);
|
|
709
|
-
await fs__default.access(filePath);
|
|
169
|
+
if (!currentStatus.isInstalled) {
|
|
170
|
+
const installSuccess = await autoInstallSuperpowers(lang);
|
|
171
|
+
if (!installSuccess) {
|
|
710
172
|
return {
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
173
|
+
isInstalled: false,
|
|
174
|
+
coreSkillsLoaded: false,
|
|
175
|
+
loadedSkills: [],
|
|
176
|
+
needsActivation: true,
|
|
177
|
+
lastActivation: void 0
|
|
714
178
|
};
|
|
715
|
-
} catch {
|
|
716
|
-
}
|
|
717
|
-
}
|
|
718
|
-
try {
|
|
719
|
-
const stat = await fs__default.stat(absolutePath);
|
|
720
|
-
if (stat.isFile() && absolutePath.endsWith(".md")) {
|
|
721
|
-
return {
|
|
722
|
-
type: "skill",
|
|
723
|
-
confidence: "high",
|
|
724
|
-
reason: "Single markdown file"
|
|
725
|
-
};
|
|
726
|
-
}
|
|
727
|
-
} catch {
|
|
728
|
-
}
|
|
729
|
-
return dirResult.confidence !== "low" ? dirResult : { type: "skill", confidence: "low", reason: "Default type" };
|
|
730
|
-
}
|
|
731
|
-
function detectFromRepoName(name) {
|
|
732
|
-
const lowerName = name.toLowerCase();
|
|
733
|
-
if (lowerName.includes("mcp-server") || lowerName.includes("mcp_server") || lowerName.startsWith("mcp-") || lowerName.endsWith("-mcp")) {
|
|
734
|
-
return { type: "mcp", confidence: "high", reason: `Name contains MCP pattern: ${name}` };
|
|
735
|
-
}
|
|
736
|
-
if (lowerName.includes("agent") || lowerName.includes("-agent") || lowerName.endsWith("-agent")) {
|
|
737
|
-
return { type: "agent", confidence: "medium", reason: `Name contains agent pattern: ${name}` };
|
|
738
|
-
}
|
|
739
|
-
if (lowerName.includes("hook") || lowerName.includes("-hook") || lowerName.endsWith("-hook")) {
|
|
740
|
-
return { type: "hook", confidence: "medium", reason: `Name contains hook pattern: ${name}` };
|
|
741
|
-
}
|
|
742
|
-
if (lowerName.includes("skill") || lowerName.includes("-skill") || lowerName.endsWith("-skill")) {
|
|
743
|
-
return { type: "skill", confidence: "medium", reason: `Name contains skill pattern: ${name}` };
|
|
744
|
-
}
|
|
745
|
-
return { type: "skill", confidence: "low", reason: "No pattern matched" };
|
|
746
|
-
}
|
|
747
|
-
function detectFromPackageName(packageName) {
|
|
748
|
-
const lowerName = packageName.toLowerCase();
|
|
749
|
-
if (lowerName.startsWith("@modelcontextprotocol/")) {
|
|
750
|
-
return { type: "mcp", confidence: "high", reason: "MCP official scope" };
|
|
751
|
-
}
|
|
752
|
-
if (lowerName.includes("mcp-server") || lowerName.includes("mcp_server")) {
|
|
753
|
-
return { type: "mcp", confidence: "high", reason: "MCP server pattern in name" };
|
|
754
|
-
}
|
|
755
|
-
return detectFromRepoName(packageName);
|
|
756
|
-
}
|
|
757
|
-
function detectFromPackageJson(packageJson) {
|
|
758
|
-
if (packageJson.ccjk && typeof packageJson.ccjk === "object") {
|
|
759
|
-
const ccjk = packageJson.ccjk;
|
|
760
|
-
if (ccjk.type && typeof ccjk.type === "string") {
|
|
761
|
-
const type = ccjk.type;
|
|
762
|
-
if (["skill", "mcp", "agent", "hook"].includes(type)) {
|
|
763
|
-
return { type, confidence: "high", reason: "Explicit ccjk.type field" };
|
|
764
|
-
}
|
|
765
|
-
}
|
|
766
|
-
}
|
|
767
|
-
if (Array.isArray(packageJson.keywords)) {
|
|
768
|
-
const keywords = packageJson.keywords;
|
|
769
|
-
const keywordMap = {
|
|
770
|
-
"mcp-server": "mcp",
|
|
771
|
-
"mcp": "mcp",
|
|
772
|
-
"model-context-protocol": "mcp",
|
|
773
|
-
"ccjk-skill": "skill",
|
|
774
|
-
"claude-skill": "skill",
|
|
775
|
-
"ccjk-agent": "agent",
|
|
776
|
-
"ccjk-hook": "hook"
|
|
777
|
-
};
|
|
778
|
-
for (const keyword of keywords) {
|
|
779
|
-
const type = keywordMap[keyword.toLowerCase()];
|
|
780
|
-
if (type) {
|
|
781
|
-
return { type, confidence: "high", reason: `Keyword: ${keyword}` };
|
|
782
|
-
}
|
|
783
|
-
}
|
|
784
|
-
}
|
|
785
|
-
if (packageJson.bin) {
|
|
786
|
-
const binKeys = Object.keys(packageJson.bin);
|
|
787
|
-
for (const key of binKeys) {
|
|
788
|
-
if (key.includes("mcp") || key.includes("server")) {
|
|
789
|
-
return { type: "mcp", confidence: "medium", reason: `Binary name: ${key}` };
|
|
790
|
-
}
|
|
791
|
-
}
|
|
792
|
-
}
|
|
793
|
-
if (typeof packageJson.main === "string") {
|
|
794
|
-
const main = packageJson.main.toLowerCase();
|
|
795
|
-
if (main.includes("server") || main.includes("mcp")) {
|
|
796
|
-
return { type: "mcp", confidence: "low", reason: `Main file: ${packageJson.main}` };
|
|
797
179
|
}
|
|
798
180
|
}
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
sourceInfo = parseSource(source);
|
|
809
|
-
spinner?.succeed(i18n.parsed(sourceInfo.type));
|
|
810
|
-
} catch (error) {
|
|
811
|
-
spinner?.fail(i18n.parseFailed);
|
|
812
|
-
const result = {
|
|
813
|
-
success: false,
|
|
814
|
-
source,
|
|
815
|
-
sourceType: "local",
|
|
816
|
-
pluginType: "skill",
|
|
817
|
-
error: error instanceof Error ? error.message : String(error)
|
|
818
|
-
};
|
|
819
|
-
if (json) {
|
|
820
|
-
console.log(JSON.stringify(result, null, 2));
|
|
821
|
-
} else {
|
|
822
|
-
console.error(ansis.red(`
|
|
823
|
-
${i18n.error}: ${result.error}
|
|
824
|
-
`));
|
|
825
|
-
}
|
|
826
|
-
return result;
|
|
827
|
-
}
|
|
828
|
-
let pluginType = options.type;
|
|
829
|
-
if (!pluginType) {
|
|
830
|
-
spinner?.start(i18n.detectingType);
|
|
831
|
-
try {
|
|
832
|
-
pluginType = await detectPluginType(sourceInfo);
|
|
833
|
-
spinner?.succeed(i18n.detectedType(pluginType));
|
|
834
|
-
} catch {
|
|
835
|
-
spinner?.info(i18n.defaultType);
|
|
836
|
-
pluginType = "skill";
|
|
837
|
-
}
|
|
838
|
-
}
|
|
839
|
-
spinner?.start(dryRun ? i18n.previewInstall : i18n.installing);
|
|
840
|
-
try {
|
|
841
|
-
let result;
|
|
842
|
-
switch (sourceInfo.type) {
|
|
843
|
-
case "github":
|
|
844
|
-
result = await installFromGitHub(sourceInfo, pluginType, { force, dryRun });
|
|
845
|
-
break;
|
|
846
|
-
case "npm":
|
|
847
|
-
result = await installFromNpm(sourceInfo, pluginType, { force, dryRun });
|
|
848
|
-
break;
|
|
849
|
-
case "local":
|
|
850
|
-
result = await installFromLocal(sourceInfo, pluginType, { force, dryRun });
|
|
851
|
-
break;
|
|
852
|
-
default:
|
|
853
|
-
throw new Error(`Unsupported source type: ${sourceInfo.type}`);
|
|
854
|
-
}
|
|
855
|
-
if (result.success) {
|
|
856
|
-
spinner?.succeed(dryRun ? i18n.previewSuccess : i18n.installSuccess);
|
|
857
|
-
} else {
|
|
858
|
-
spinner?.fail(i18n.installFailed);
|
|
859
|
-
}
|
|
860
|
-
if (json) {
|
|
861
|
-
console.log(JSON.stringify(result, null, 2));
|
|
862
|
-
} else if (result.success && !dryRun) {
|
|
863
|
-
printSuccessMessage(result, i18n);
|
|
864
|
-
} else if (result.success && dryRun) {
|
|
865
|
-
printPreviewMessage(result, i18n);
|
|
866
|
-
} else {
|
|
867
|
-
console.error(ansis.red(`
|
|
868
|
-
${i18n.error}: ${result.error}
|
|
869
|
-
`));
|
|
870
|
-
}
|
|
871
|
-
return result;
|
|
872
|
-
} catch (error) {
|
|
873
|
-
spinner?.fail(i18n.installFailed);
|
|
874
|
-
const result = {
|
|
875
|
-
success: false,
|
|
876
|
-
source,
|
|
877
|
-
sourceType: sourceInfo.type,
|
|
878
|
-
pluginType,
|
|
879
|
-
error: error instanceof Error ? error.message : String(error)
|
|
880
|
-
};
|
|
881
|
-
if (json) {
|
|
882
|
-
console.log(JSON.stringify(result, null, 2));
|
|
883
|
-
} else {
|
|
884
|
-
console.error(ansis.red(`
|
|
885
|
-
${i18n.error}: ${result.error}
|
|
886
|
-
`));
|
|
887
|
-
}
|
|
888
|
-
return result;
|
|
889
|
-
}
|
|
890
|
-
}
|
|
891
|
-
function printSuccessMessage(result, i18n) {
|
|
892
|
-
console.log();
|
|
893
|
-
console.log(ansis.green.bold(`\u2713 ${i18n.installed}`));
|
|
894
|
-
console.log();
|
|
895
|
-
console.log(` ${ansis.gray(i18n.name)}: ${result.details?.name || result.source}`);
|
|
896
|
-
if (result.details?.version) {
|
|
897
|
-
console.log(` ${ansis.gray(i18n.version)}: ${result.details.version}`);
|
|
898
|
-
}
|
|
899
|
-
console.log(` ${ansis.gray(i18n.type)}: ${result.pluginType}`);
|
|
900
|
-
console.log(` ${ansis.gray(i18n.path)}: ${result.installedPath}`);
|
|
901
|
-
console.log();
|
|
902
|
-
console.log(ansis.cyan(i18n.nextSteps));
|
|
903
|
-
switch (result.pluginType) {
|
|
904
|
-
case "skill":
|
|
905
|
-
console.log(` ${ansis.gray("\u2022")} ${i18n.skillHint}`);
|
|
906
|
-
break;
|
|
907
|
-
case "mcp":
|
|
908
|
-
console.log(` ${ansis.gray("\u2022")} ${i18n.mcpHint}`);
|
|
909
|
-
break;
|
|
910
|
-
case "agent":
|
|
911
|
-
console.log(` ${ansis.gray("\u2022")} ${i18n.agentHint}`);
|
|
912
|
-
break;
|
|
913
|
-
case "hook":
|
|
914
|
-
console.log(` ${ansis.gray("\u2022")} ${i18n.hookHint}`);
|
|
915
|
-
break;
|
|
916
|
-
}
|
|
917
|
-
console.log();
|
|
918
|
-
}
|
|
919
|
-
function printPreviewMessage(result, i18n) {
|
|
920
|
-
console.log();
|
|
921
|
-
console.log(ansis.yellow.bold(`\u26A1 ${i18n.preview}`));
|
|
922
|
-
console.log();
|
|
923
|
-
console.log(` ${ansis.gray(i18n.source)}: ${result.source}`);
|
|
924
|
-
console.log(` ${ansis.gray(i18n.type)}: ${result.pluginType}`);
|
|
925
|
-
console.log(` ${ansis.gray(i18n.target)}: ${result.installedPath}`);
|
|
926
|
-
if (result.details?.files?.length) {
|
|
927
|
-
console.log(` ${ansis.gray(i18n.files)}:`);
|
|
928
|
-
for (const file of result.details.files.slice(0, 5)) {
|
|
929
|
-
console.log(` ${ansis.gray("\u2022")} ${file}`);
|
|
930
|
-
}
|
|
931
|
-
if (result.details.files.length > 5) {
|
|
932
|
-
console.log(` ${ansis.gray("...")} ${i18n.andMore(result.details.files.length - 5)}`);
|
|
933
|
-
}
|
|
934
|
-
}
|
|
935
|
-
console.log();
|
|
936
|
-
console.log(ansis.gray(i18n.dryRunNote));
|
|
937
|
-
console.log();
|
|
938
|
-
}
|
|
939
|
-
function getI18n(lang) {
|
|
940
|
-
const texts = {
|
|
941
|
-
"zh-CN": {
|
|
942
|
-
parsing: "\u89E3\u6790\u6765\u6E90...",
|
|
943
|
-
parsed: (type) => `\u6765\u6E90\u7C7B\u578B: ${type}`,
|
|
944
|
-
parseFailed: "\u89E3\u6790\u6765\u6E90\u5931\u8D25",
|
|
945
|
-
detectingType: "\u68C0\u6D4B\u63D2\u4EF6\u7C7B\u578B...",
|
|
946
|
-
detectedType: (type) => `\u68C0\u6D4B\u5230\u7C7B\u578B: ${type}`,
|
|
947
|
-
defaultType: "\u4F7F\u7528\u9ED8\u8BA4\u7C7B\u578B: skill",
|
|
948
|
-
installing: "\u5B89\u88C5\u4E2D...",
|
|
949
|
-
previewInstall: "\u9884\u89C8\u5B89\u88C5...",
|
|
950
|
-
installSuccess: "\u5B89\u88C5\u6210\u529F",
|
|
951
|
-
previewSuccess: "\u9884\u89C8\u5B8C\u6210",
|
|
952
|
-
installFailed: "\u5B89\u88C5\u5931\u8D25",
|
|
953
|
-
error: "\u9519\u8BEF",
|
|
954
|
-
installed: "\u63D2\u4EF6\u5DF2\u5B89\u88C5",
|
|
955
|
-
preview: "\u5B89\u88C5\u9884\u89C8 (dry-run)",
|
|
956
|
-
name: "\u540D\u79F0",
|
|
957
|
-
version: "\u7248\u672C",
|
|
958
|
-
type: "\u7C7B\u578B",
|
|
959
|
-
path: "\u8DEF\u5F84",
|
|
960
|
-
source: "\u6765\u6E90",
|
|
961
|
-
target: "\u76EE\u6807",
|
|
962
|
-
files: "\u6587\u4EF6",
|
|
963
|
-
nextSteps: "\u4E0B\u4E00\u6B65:",
|
|
964
|
-
skillHint: "\u4F7F\u7528 /skill-name \u5728 Claude Code \u4E2D\u8C03\u7528",
|
|
965
|
-
mcpHint: "\u8FD0\u884C ccjk mcp status \u67E5\u770B\u72B6\u6001",
|
|
966
|
-
agentHint: "\u4F7F\u7528 ccjk agent list \u67E5\u770B\u5DF2\u5B89\u88C5\u7684 agent",
|
|
967
|
-
hookHint: "\u8FD0\u884C ccjk hooks list \u67E5\u770B\u5DF2\u5B89\u88C5\u7684 hook",
|
|
968
|
-
dryRunNote: "\u8FD9\u662F\u9884\u89C8\u6A21\u5F0F\uFF0C\u672A\u5B9E\u9645\u5B89\u88C5\u3002\u79FB\u9664 --dry-run \u6267\u884C\u5B89\u88C5\u3002",
|
|
969
|
-
andMore: (n) => `\u8FD8\u6709 ${n} \u4E2A\u6587\u4EF6`
|
|
970
|
-
},
|
|
971
|
-
"en": {
|
|
972
|
-
parsing: "Parsing source...",
|
|
973
|
-
parsed: (type) => `Source type: ${type}`,
|
|
974
|
-
parseFailed: "Failed to parse source",
|
|
975
|
-
detectingType: "Detecting plugin type...",
|
|
976
|
-
detectedType: (type) => `Detected type: ${type}`,
|
|
977
|
-
defaultType: "Using default type: skill",
|
|
978
|
-
installing: "Installing...",
|
|
979
|
-
previewInstall: "Previewing installation...",
|
|
980
|
-
installSuccess: "Installation successful",
|
|
981
|
-
previewSuccess: "Preview complete",
|
|
982
|
-
installFailed: "Installation failed",
|
|
983
|
-
error: "Error",
|
|
984
|
-
installed: "Plugin installed",
|
|
985
|
-
preview: "Installation preview (dry-run)",
|
|
986
|
-
name: "Name",
|
|
987
|
-
version: "Version",
|
|
988
|
-
type: "Type",
|
|
989
|
-
path: "Path",
|
|
990
|
-
source: "Source",
|
|
991
|
-
target: "Target",
|
|
992
|
-
files: "Files",
|
|
993
|
-
nextSteps: "Next steps:",
|
|
994
|
-
skillHint: "Use /skill-name in Claude Code to invoke",
|
|
995
|
-
mcpHint: "Run ccjk mcp status to check status",
|
|
996
|
-
agentHint: "Use ccjk agent list to see installed agents",
|
|
997
|
-
hookHint: "Run ccjk hooks list to see installed hooks",
|
|
998
|
-
dryRunNote: "This is preview mode, nothing was installed. Remove --dry-run to install.",
|
|
999
|
-
andMore: (n) => `and ${n} more files`
|
|
1000
|
-
}
|
|
181
|
+
const loadResults = await loadCoreSkills(lang);
|
|
182
|
+
const successfulLoads = loadResults.filter((r) => r.success);
|
|
183
|
+
const allCoreSkillsLoaded = successfulLoads.length === loadResults.length;
|
|
184
|
+
const newStatus = {
|
|
185
|
+
isInstalled: true,
|
|
186
|
+
coreSkillsLoaded: allCoreSkillsLoaded,
|
|
187
|
+
loadedSkills: successfulLoads.map((r) => r.skill),
|
|
188
|
+
needsActivation: false,
|
|
189
|
+
lastActivation: (/* @__PURE__ */ new Date()).toISOString()
|
|
1001
190
|
};
|
|
1002
|
-
|
|
191
|
+
saveActivationState(newStatus);
|
|
192
|
+
return newStatus;
|
|
1003
193
|
}
|
|
1004
194
|
|
|
1005
|
-
export {
|
|
195
|
+
export { activateSuperpowers, autoInstallSuperpowers, checkActivationStatus, loadCoreSkills, loadSkill };
|