@moon791017/neo-skills 1.0.8 → 1.0.10

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 CHANGED
@@ -68,19 +68,30 @@
68
68
 
69
69
  本套件支援多種 AI Agent 環境。請依據您的 CLI 工具執行對應指令:
70
70
 
71
- ### 🛠️ Gemini CLI
71
+ ### Gemini CLI
72
72
 
73
73
  ```bash
74
74
  gemini extension install https://github.com/Benknightdark/neo-skills --auto-update
75
75
  ```
76
76
 
77
- ### 🤖 Claude Code
77
+ ### Claude Code
78
+
79
+ ```bash
80
+ npx -p @moon791017/neo-skills install-claude-skills
81
+ ```
82
+
83
+ ### Copilot CLI
84
+
85
+ ```bash
86
+ npx -p @moon791017/neo-skills install-copilot-skills
87
+ ```
88
+
89
+ ### 安裝全部AI Agent技能
90
+
91
+ ```bash
92
+ npx -p @moon791017/neo-skills install-skills
93
+ ```
78
94
 
79
- | 說明 | 執行指令 |
80
- | :--- | :--- |
81
- | Claude 內建外掛安裝 | `claude plugin add https://github.com/Benknightdark/neo-skills` |
82
- | 透過 `npx` 執行安裝腳本 | `npx @moon791017/neo-skills install-claude-skills` |
83
- | `npm` 全域安裝後執行 | `npm i @moon791017/neo-skills -g` <br> `install-claude-skills` |
84
95
 
85
96
  ## 💡 常用指令範例
86
97
 
@@ -127,4 +138,4 @@ gemini extension install https://github.com/Benknightdark/neo-skills --auto-upda
127
138
  4. **類型檢查**
128
139
  ```bash
129
140
  bun run typecheck
130
- ```
141
+ ```
package/bin/_utils.js ADDED
@@ -0,0 +1,141 @@
1
+ /**
2
+ * Shared utilities for agent skill installers.
3
+ *
4
+ * 新增 AI agent 只需兩步:
5
+ * 1. 在 AGENTS 加入設定
6
+ * 2. 建立 bin/install-{key}-skills.js(複製任一現有檔案,改 named export 即可)
7
+ */
8
+ import { realpathSync } from 'node:fs';
9
+ import { cp, mkdir, access } from 'node:fs/promises';
10
+ import { join, resolve, dirname, basename } from 'node:path';
11
+ import { homedir } from 'node:os';
12
+ import { fileURLToPath } from 'node:url';
13
+
14
+ const __filename = fileURLToPath(import.meta.url);
15
+ const __dirname = dirname(__filename);
16
+ const packageRoot = resolve(__dirname, '..');
17
+ const sourceDir = join(packageRoot, 'skills');
18
+
19
+ /**
20
+ * Agent 設定中心 — 所有 agent 的安裝參數集中管理於此。
21
+ * key 須與檔名 install-{key}-skills.js 一致。
22
+ */
23
+ export const AGENTS = {
24
+ claude: {
25
+ name: 'Claude',
26
+ targetSubDir: '.claude/skills',
27
+ hint: '請確保您的 Claude Desktop 或相關插件已指向此目錄。',
28
+ },
29
+ copilot: {
30
+ name: 'Copilot',
31
+ targetSubDir: '.copilot/skills',
32
+ hint: '請確保您的 GitHub Copilot CLI 已指向此目錄。',
33
+ },
34
+ // gemini: {
35
+ // name: 'Gemini',
36
+ // targetSubDir: '.gemini/skills',
37
+ // hint: '請確保您的 Gemini CLI 已指向此目錄。',
38
+ // },
39
+ };
40
+
41
+ /**
42
+ * 從檔名解析 agent key: install-{key}-skills.js → key
43
+ */
44
+ function extractAgentKey(importMetaUrl) {
45
+ const filename = basename(fileURLToPath(importMetaUrl), '.js');
46
+ const match = filename.match(/^install-(.+)-skills$/);
47
+ if (!match) throw new Error(`無法從檔名 "${filename}" 解析 agent key`);
48
+ return match[1];
49
+ }
50
+
51
+ /**
52
+ * 根據 agent config 建立 installer 函式
53
+ */
54
+ export function createInstaller({ name: agentName, targetSubDir, hint }) {
55
+ return async function install() {
56
+ console.log(`🚀 [${agentName}] 開始同步 Neo Skills...`);
57
+
58
+ try {
59
+ await access(sourceDir);
60
+ } catch {
61
+ const msg = `在 ${sourceDir} 找不到來源技能目錄。`;
62
+ console.error(`❌ 錯誤: ${msg}`);
63
+ return { success: false, message: msg };
64
+ }
65
+
66
+ const targetSkillsDir = join(homedir(), targetSubDir);
67
+
68
+ console.log(`📁 來源路徑: ${sourceDir}`);
69
+ console.log(`🎯 目標路徑: ${targetSkillsDir}`);
70
+
71
+ await mkdir(targetSkillsDir, { recursive: true });
72
+
73
+ let copyCount = 0;
74
+ await cp(sourceDir, targetSkillsDir, {
75
+ recursive: true,
76
+ force: true,
77
+ filter: (src) => {
78
+ const relativePath = src.replace(sourceDir, '');
79
+ const isIgnored = relativePath.includes('node_modules') || relativePath.includes('.git');
80
+ if (!isIgnored) { copyCount++; return true; }
81
+ return false;
82
+ }
83
+ });
84
+
85
+ if (copyCount === 0) {
86
+ console.warn('⚠️ 警告: 沒有任何檔案被複製。請檢查來源目錄是否正確。');
87
+ return { success: true, message: '沒有任何檔案被複製' };
88
+ }
89
+
90
+ const msg = `已同步 ${copyCount} 個檔案/資料夾至 ${targetSubDir}`;
91
+ console.log(`✅ [${agentName}] 安裝成功!${msg}`);
92
+ if (hint) console.log(`💡 提示: ${hint}`);
93
+ return { success: true, message: msg };
94
+ };
95
+ }
96
+
97
+ /**
98
+ * 從呼叫端的檔名自動解析 agent,建立對應的 installer。
99
+ * @param {string} importMetaUrl - 呼叫端的 import.meta.url
100
+ */
101
+ export function createInstallerFromFile(importMetaUrl) {
102
+ const key = extractAgentKey(importMetaUrl);
103
+ const config = AGENTS[key];
104
+ if (!config) throw new Error(`未知的 agent: "${key}"。請在 _utils.js 的 AGENTS 中註冊。`);
105
+ return createInstaller(config);
106
+ }
107
+
108
+ /**
109
+ * 當腳本被直接執行時(非 import),自動呼叫 installer。
110
+ * Agent 名稱從檔名自動推導。
111
+ * @param {() => Promise<{ success: boolean, message: string }>} installFn
112
+ * @param {string} callerUrl - 呼叫端的 import.meta.url
113
+ */
114
+ export function runAsMain(installFn, callerUrl) {
115
+ const callerPath = fileURLToPath(callerUrl);
116
+ const argvPath = process.argv[1];
117
+ const isMain = Boolean(argvPath) && (
118
+ resolve(argvPath) === resolve(callerPath) ||
119
+ realpathSync.native(resolve(argvPath)) === realpathSync.native(resolve(callerPath))
120
+ );
121
+ if (!isMain) return;
122
+
123
+ const key = extractAgentKey(callerUrl);
124
+ const agentName = AGENTS[key]?.name || key;
125
+
126
+ process.on('uncaughtException', (err) => {
127
+ console.error('💥 [Fatal Error]:', err);
128
+ process.exit(1);
129
+ });
130
+ process.on('unhandledRejection', (reason) => {
131
+ console.error('💥 [Unhandled Rejection]:', reason);
132
+ process.exit(1);
133
+ });
134
+
135
+ installFn().then((result) => {
136
+ if (!result.success) process.exit(1);
137
+ }).catch((error) => {
138
+ console.error(`❌ [${agentName}] 安裝失敗:`, error.message || error);
139
+ process.exit(1);
140
+ });
141
+ }
@@ -1,84 +1,7 @@
1
1
  #!/usr/bin/env node
2
- import { cp, mkdir, access } from 'node:fs/promises';
3
- import { join, resolve, dirname } from 'node:path';
4
- import { homedir } from 'node:os';
5
- import { fileURLToPath } from 'node:url';
2
+ import { createInstallerFromFile, runAsMain } from './_utils.js';
6
3
 
7
- // 立即輸出日誌以確認腳本已啟動
8
- console.log('🏁 [Debug] 腳本已啟動...');
4
+ export const install = createInstallerFromFile(import.meta.url);
5
+ export { install as installClaudeSkills };
9
6
 
10
- // 捕捉全域錯誤
11
- process.on('uncaughtException', (err) => {
12
- console.error('💥 [Fatal Error]:', err);
13
- process.exit(1);
14
- });
15
-
16
- process.on('unhandledRejection', (reason, promise) => {
17
- console.error('💥 [Unhandled Rejection]:', reason);
18
- process.exit(1);
19
- });
20
-
21
- // 取得當前檔案路徑
22
- const __filename = fileURLToPath(import.meta.url);
23
- const __dirname = dirname(__filename);
24
-
25
- async function installClaudeSkills() {
26
- try {
27
- // 1. 定義來源目錄: 腳本所在目錄的上一層的 skills 資料夾
28
- // 當透過 npx 執行時,它會指向臨時下載的 package 內容
29
- const packageRoot = resolve(__dirname, '..');
30
- const sourceDir = join(packageRoot, 'skills');
31
-
32
- // 2. 定義目標目錄: ~/.claude/skills (跨平台自動處理)
33
- const targetBaseDir = join(homedir(), '.claude');
34
- const targetSkillsDir = join(targetBaseDir, 'skills');
35
-
36
- console.log('🚀 [Claude] 開始同步 Neo Skills...');
37
-
38
- // 檢查來源是否存在
39
- try {
40
- await access(sourceDir);
41
- } catch {
42
- console.error(`❌ 錯誤: 在 ${sourceDir} 找不到來源技能目錄。`);
43
- process.exit(1);
44
- }
45
-
46
- console.log(`📁 來源路徑: ${sourceDir}`);
47
- console.log(`🎯 目標路徑: ${targetSkillsDir}`);
48
-
49
- // 3. 確保目標目錄存在 (recursive: true 會自動建立多層目錄)
50
- await mkdir(targetSkillsDir, { recursive: true });
51
-
52
- // 4. 執行複製
53
- let copyCount = 0;
54
- await cp(sourceDir, targetSkillsDir, {
55
- recursive: true,
56
- force: true,
57
- // 過濾掉不必要的開發檔案
58
- filter: (src) => {
59
- // 取得相對於來源目錄的路徑
60
- const relativePath = src.replace(sourceDir, '');
61
- const isIgnored = relativePath.includes('node_modules') || relativePath.includes('.git');
62
-
63
- if (!isIgnored) {
64
- copyCount++;
65
- return true;
66
- }
67
- return false;
68
- }
69
- });
70
-
71
- if (copyCount === 0) {
72
- console.warn('⚠️ 警告: 沒有任何檔案被複製。請檢查來源目錄是否正確。');
73
- } else {
74
- console.log(`✅ [Claude] 安裝成功!已同步 ${copyCount} 個檔案/資料夾至 .claude/skills`);
75
- }
76
- console.log('💡 提示: 請確保您的 Claude Desktop 或相關插件已指向此目錄。');
77
-
78
- } catch (error) {
79
- console.error('❌ [Claude] 安裝失敗:', error.message || error);
80
- process.exit(1);
81
- }
82
- }
83
-
84
- installClaudeSkills();
7
+ runAsMain(install, import.meta.url);
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ import { createInstallerFromFile, runAsMain } from './_utils.js';
3
+
4
+ export const install = createInstallerFromFile(import.meta.url);
5
+ export { install as installCopilotSkills };
6
+
7
+ runAsMain(install, import.meta.url);
@@ -0,0 +1,55 @@
1
+ #!/usr/bin/env node
2
+ import { AGENTS, createInstaller } from './_utils.js';
3
+
4
+ process.on('uncaughtException', (err) => {
5
+ console.error('💥 [Fatal Error]:', err);
6
+ process.exit(1);
7
+ });
8
+
9
+ process.on('unhandledRejection', (reason) => {
10
+ console.error('💥 [Unhandled Rejection]:', reason);
11
+ process.exit(1);
12
+ });
13
+
14
+ async function main() {
15
+ console.log('╔══════════════════════════════════════════╗');
16
+ console.log('║ 🧠 Neo Skills — 統一安裝程式 ║');
17
+ console.log('╚══════════════════════════════════════════╝');
18
+ console.log('');
19
+
20
+ const results = [];
21
+
22
+ for (const [key, config] of Object.entries(AGENTS)) {
23
+ console.log(`━━━ 正在安裝: ${config.name} ━━━`);
24
+ try {
25
+ const installFn = createInstaller(config);
26
+ const result = await installFn();
27
+ results.push({ name: config.name, ...result });
28
+ } catch (error) {
29
+ console.error(`❌ [${config.name}] 安裝失敗:`, error.message || error);
30
+ results.push({ name: config.name, success: false, message: error.message || String(error) });
31
+ }
32
+ console.log('');
33
+ }
34
+
35
+ // 彙總報告
36
+ console.log('══════════════════════════════════════════');
37
+ console.log('📊 安裝結果彙總:');
38
+ const failed = results.filter(r => !r.success);
39
+
40
+ for (const r of results) {
41
+ console.log(` ${r.success ? '✅' : '❌'} ${r.name}: ${r.message}`);
42
+ }
43
+
44
+ console.log('');
45
+ console.log(`成功: ${results.length - failed.length} / ${results.length}`);
46
+
47
+ if (failed.length > 0) {
48
+ console.log(`失敗: ${failed.length} — ${failed.map(r => r.name).join(', ')}`);
49
+ process.exit(1);
50
+ }
51
+
52
+ console.log('🎉 全部安裝完成!');
53
+ }
54
+
55
+ main();
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "neo-skills",
3
3
  "description": "A universal capability extension for Gemini CLI",
4
- "version": "0.43.3",
4
+ "version": "0.45.0",
5
5
  "mcpServers": {
6
6
  "neo-skills": {
7
7
  "command": "node",
package/package.json CHANGED
@@ -1,11 +1,13 @@
1
1
  {
2
2
  "name": "@moon791017/neo-skills",
3
- "version": "1.0.8",
3
+ "version": "1.0.10",
4
4
  "type": "module",
5
5
  "description": "Neo Skills: A Universal Expert Agent Extension",
6
6
  "bin": {
7
- "neo-skills": "./bin/install-claude-skills.js",
8
- "install-claude-skills": "./bin/install-claude-skills.js"
7
+ "neo-skills": "./bin/install-skills.js",
8
+ "install-skills": "./bin/install-skills.js",
9
+ "install-claude-skills": "./bin/install-claude-skills.js",
10
+ "install-copilot-skills": "./bin/install-copilot-skills.js"
9
11
  },
10
12
  "files": [
11
13
  "dist",