@moon791017/neo-skills 1.0.18 → 1.0.20

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
@@ -1,5 +1,7 @@
1
1
  # Neo Skills
2
2
 
3
+ [![test-on-develop](https://github.com/Benknightdark/neo-skills/actions/workflows/test-on-develop.yml/badge.svg)](https://github.com/Benknightdark/neo-skills/actions/workflows/test-on-develop.yml)
4
+
3
5
  **Neo Skills** 是專為現代 **AI Agent** 設計的**全方位能力擴充套件**。本專案透過標準化的通訊架構,為 AI 代理安裝可插拔的「技能模組 (Skills)」,使其不僅僅是一個聊天機器人,而是能轉化為具備「感知-推理-行動」能力的**多領域專家**。
4
6
 
5
7
  無論是 DevOps 自動化、軟體架構設計,或是未來的資料分析與專案管理,Neo Skills 都能透過掛載不同的知識庫與工具,讓 AI 成為您最強大的全能助手。
@@ -74,42 +76,36 @@
74
76
  gemini extension install https://github.com/Benknightdark/neo-skills --auto-update
75
77
  ```
76
78
 
77
- ### Claude Code
79
+ ### 安裝指定 AI Agent 技能
78
80
 
79
- ```bash
80
- npx -p @moon791017/neo-skills install-claude-skills
81
- ```
82
-
83
- ### Copilot CLI
81
+ 使用 `--ai-agent` 指定要安裝的 agent(可用值:`claude`、`copilot`、`codex`):
84
82
 
85
83
  ```bash
86
- npx -p @moon791017/neo-skills install-copilot-skills
84
+ npx -p @moon791017/neo-skills install-skills --ai-agent claude
85
+ npx -p @moon791017/neo-skills install-skills --ai-agent copilot
86
+ npx -p @moon791017/neo-skills install-skills --ai-agent codex
87
87
  ```
88
88
 
89
- ### Codex CLI
89
+ ### 安裝至指定專案
90
90
 
91
- ```bash
92
- npx -p @moon791017/neo-skills install-codex-skills
93
- ```
94
-
95
- ### 自訂安裝根目錄
96
-
97
- Claude Code、Copilot CLI、Codex CLI 三種安裝指令皆支援 `--target-path` 參數,可指定安裝的根目錄(取代預設的 `$HOME`)。技能子目錄(如 `.claude/skills`)會自動附加:
91
+ 搭配 `--project-path` 可將技能安裝至指定專案目錄(技能子目錄會自動附加):
98
92
 
99
93
  ```bash
100
94
  # 安裝至 /my/project/.claude/skills
101
- npx -p @moon791017/neo-skills install-claude-skills --target-path /my/project
95
+ npx -p @moon791017/neo-skills install-skills --ai-agent claude --project-path /my/project
102
96
 
103
- # 安裝至 /my/project/.copilot/skills
104
- npx -p @moon791017/neo-skills install-copilot-skills --target-path /my/project
97
+ # 安裝至 /my/project/.github/skills
98
+ npx -p @moon791017/neo-skills install-skills --ai-agent copilot --project-path /my/project
105
99
 
106
100
  # 安裝至 /my/project/.codex/skills
107
- npx -p @moon791017/neo-skills install-codex-skills --target-path /my/project
101
+ npx -p @moon791017/neo-skills install-skills --ai-agent codex --project-path /my/project
108
102
  ```
109
103
 
110
- 若未指定 `--target-path`,則使用預設根目錄 `$HOME`(即 `~/.claude/skills`、`~/.copilot/skills`、`~/.codex/skills`)。
104
+ 若未指定 `--project-path`,則安裝至全域路徑(`~/.claude/skills`、`~/.copilot/skills`、`~/.codex/skills`)。
105
+
106
+ ### 安裝全部 AI Agent 技能
111
107
 
112
- ### 安裝全部AI Agent技能
108
+ 不帶 `--ai-agent` 即可一次安裝全部:
113
109
 
114
110
  ```bash
115
111
  npx -p @moon791017/neo-skills install-skills
package/bin/_utils.js CHANGED
@@ -1,74 +1,65 @@
1
1
  /**
2
2
  * Shared utilities for agent skill installers.
3
- *
4
- * 新增 AI agent 只需兩步:
5
- * 1. 在 AGENTS 加入設定
6
- * 2. 建立 bin/install-{key}-skills.js(複製任一現有檔案,改 named export 即可)
7
3
  */
8
- import { realpathSync } from 'node:fs';
9
4
  import { cp, mkdir, access } from 'node:fs/promises';
10
- import { join, resolve, dirname, basename } from 'node:path';
5
+ import { join, resolve, dirname } from 'node:path';
11
6
  import { homedir } from 'node:os';
12
7
  import { fileURLToPath } from 'node:url';
13
8
 
14
- const __filename = fileURLToPath(import.meta.url);
15
- const __dirname = dirname(__filename);
9
+ const __dirname = dirname(fileURLToPath(import.meta.url));
16
10
  const packageRoot = resolve(__dirname, '..');
17
11
  const sourceDir = join(packageRoot, 'skills');
18
12
 
19
13
  /**
20
14
  * Agent 設定中心 — 所有 agent 的安裝參數集中管理於此。
21
- * key 須與檔名 install-{key}-skills.js 一致。
15
+ *
16
+ * 各欄位說明:
17
+ * name — 顯示用名稱,用於 CLI 輸出的 log 標籤。
18
+ * homePath — 全域安裝路徑(相對於 $HOME)。未指定 --project-path 時使用。
19
+ * projectPath — (選填)專案安裝路徑(相對於 --project-path)。
20
+ * 指定 --project-path 且此欄位有值時,優先使用此路徑取代 homePath。
21
+ * 例如 Copilot:全域 ~/.copilot/skills,專案 <project>/.github/skills。
22
+ * hint — 安裝成功後顯示的提示訊息。
22
23
  */
23
24
  export const AGENTS = {
24
25
  claude: {
25
26
  name: 'Claude',
26
- targetSubDir: '.claude/skills',
27
+ homePath: '.claude/skills',
27
28
  hint: '請確保您的 Claude Desktop 或相關插件已指向此目錄。',
28
29
  },
29
30
  copilot: {
30
31
  name: 'Copilot',
31
- targetSubDir: '.copilot/skills',
32
+ homePath: '.copilot/skills',
33
+ projectPath: '.github/skills',
32
34
  hint: '請確保您的 GitHub Copilot CLI 已指向此目錄。',
33
35
  },
34
36
  codex: {
35
37
  name: 'Codex',
36
- targetSubDir: '.codex/skills',
38
+ homePath: '.codex/skills',
37
39
  hint: '請確保您的 Codex CLI 已指向此目錄。',
38
40
  },
39
- // gemini: {
40
- // name: 'Gemini',
41
- // targetSubDir: '.gemini/skills/neo-skills',
42
- // hint: '請確保您的 Gemini CLI 已指向此目錄。',
43
- // },
44
41
  };
45
42
 
46
43
  /**
47
- * CLI 參數解析 --target-path
48
- * @returns {string | undefined}
49
- */
50
- function parseTargetPath() {
51
- const idx = process.argv.indexOf('--target-path');
52
- if (idx === -1 || idx + 1 >= process.argv.length) return undefined;
53
- return process.argv[idx + 1];
54
- }
55
-
56
- /**
57
- * 從檔名解析 agent key: install-{key}-skills.js → key
58
- */
59
- function extractAgentKey(importMetaUrl) {
60
- const filename = basename(fileURLToPath(importMetaUrl), '.js');
61
- const match = filename.match(/^install-(.+)-skills$/);
62
- if (!match) throw new Error(`無法從檔名 "${filename}" 解析 agent key`);
63
- return match[1];
64
- }
65
-
66
- /**
67
- * 根據 agent config 建立 installer 函式
68
- * @param {object} config - agent 設定
69
- * @param {string} [targetPath] - 使用者透過 --target-path 指定的自訂路徑
44
+ * 根據 agent config 建立 installer 函式。
45
+ *
46
+ * 路徑解析邏輯:
47
+ * 1. 決定根目錄 (baseDir)
48
+ * - --project-path → 使用者指定的絕對路徑
49
+ * - --project-path $HOME
50
+ * 2. 決定子目錄 (subDir):
51
+ * - 有 --project-path 且 config 定義了 projectPath → 使用 projectPath
52
+ * - 其餘情況 → 使用 homePath
53
+ * 3. 最終安裝路徑 = baseDir + subDir
54
+ *
55
+ * 範例(以 Copilot 為例):
56
+ * 預設: ~/.copilot/skills (homedir + homePath)
57
+ * --project-path /my/project: /my/project/.github/skills (projectPath + projectPath)
58
+ *
59
+ * @param {object} config - AGENTS 中的 agent 設定物件
60
+ * @param {string} [targetPath] - 使用者透過 --project-path 指定的自訂根目錄
70
61
  */
71
- export function createInstaller({ name: agentName, targetSubDir, hint }, targetPath) {
62
+ export function createInstaller({ name: agentName, homePath, projectPath, hint }, targetPath) {
72
63
  return async function install() {
73
64
  console.log(`🚀 [${agentName}] 開始同步 Neo Skills...`);
74
65
 
@@ -80,8 +71,11 @@ export function createInstaller({ name: agentName, targetSubDir, hint }, targetP
80
71
  return { success: false, message: msg };
81
72
  }
82
73
 
74
+ // 根目錄:--project-path 優先,否則 $HOME
83
75
  const baseDir = targetPath ? resolve(targetPath) : homedir();
84
- const targetSkillsDir = join(baseDir, targetSubDir);
76
+ // 子目錄:專案層級有獨立路徑時採用 projectPath,否則用預設的 homePath
77
+ const subDir = targetPath && projectPath ? projectPath : homePath;
78
+ const targetSkillsDir = join(baseDir, subDir);
85
79
 
86
80
  console.log(`📁 來源路徑: ${sourceDir}`);
87
81
  console.log(`🎯 目標路徑: ${targetSkillsDir}`);
@@ -105,62 +99,10 @@ export function createInstaller({ name: agentName, targetSubDir, hint }, targetP
105
99
  return { success: true, message: '沒有任何檔案被複製' };
106
100
  }
107
101
 
108
- const displayPath = targetPath || targetSubDir;
102
+ const displayPath = targetPath || homePath;
109
103
  const msg = `已同步 ${copyCount} 個檔案/資料夾至 ${displayPath}`;
110
104
  console.log(`✅ [${agentName}] 安裝成功!${msg}`);
111
105
  if (hint) console.log(`💡 提示: ${hint}`);
112
106
  return { success: true, message: msg };
113
107
  };
114
108
  }
115
-
116
- /**
117
- * 從呼叫端的檔名自動解析 agent,建立對應的 installer。
118
- * @param {string} importMetaUrl - 呼叫端的 import.meta.url
119
- * @param {string} [targetPath] - 使用者透過 --target-path 指定的自訂路徑
120
- */
121
- export function createInstallerFromFile(importMetaUrl, targetPath) {
122
- const key = extractAgentKey(importMetaUrl);
123
- const config = AGENTS[key];
124
- if (!config) throw new Error(`未知的 agent: "${key}"。請在 _utils.js 的 AGENTS 中註冊。`);
125
- return createInstaller(config, targetPath);
126
- }
127
-
128
- /**
129
- * 當腳本被直接執行時(非 import),自動呼叫 installer。
130
- * Agent 名稱從檔名自動推導。
131
- * @param {() => Promise<{ success: boolean, message: string }>} installFn
132
- * @param {string} callerUrl - 呼叫端的 import.meta.url
133
- */
134
- export function runAsMain(installFn, callerUrl) {
135
- const callerPath = fileURLToPath(callerUrl);
136
- const argvPath = process.argv[1];
137
- const isMain = Boolean(argvPath) && (
138
- resolve(argvPath) === resolve(callerPath) ||
139
- realpathSync.native(resolve(argvPath)) === realpathSync.native(resolve(callerPath))
140
- );
141
- if (!isMain) return;
142
-
143
- const key = extractAgentKey(callerUrl);
144
- const agentName = AGENTS[key]?.name || key;
145
-
146
- process.on('uncaughtException', (err) => {
147
- console.error('💥 [Fatal Error]:', err);
148
- process.exit(1);
149
- });
150
- process.on('unhandledRejection', (reason) => {
151
- console.error('💥 [Unhandled Rejection]:', reason);
152
- process.exit(1);
153
- });
154
-
155
- const targetPath = parseTargetPath();
156
- const actualInstallFn = targetPath
157
- ? createInstallerFromFile(callerUrl, targetPath)
158
- : installFn;
159
-
160
- actualInstallFn().then((result) => {
161
- if (!result.success) process.exit(1);
162
- }).catch((error) => {
163
- console.error(`❌ [${agentName}] 安裝失敗:`, error.message || error);
164
- process.exit(1);
165
- });
166
- }
@@ -1,17 +1,67 @@
1
1
  #!/usr/bin/env node
2
+ /**
3
+ * Neo Skills 統一安裝程式
4
+ *
5
+ * 用法:
6
+ * install-skills 安裝全部 AI Agent 技能至 $HOME
7
+ * install-skills --ai-agent claude 只安裝 Claude 技能至 $HOME
8
+ * install-skills --ai-agent copilot --project-path . 安裝 Copilot 技能至指定專案
9
+ *
10
+ * 參數:
11
+ * --ai-agent <name> 指定要安裝的 agent(可用值見 _utils.js 的 AGENTS)。
12
+ * 省略時安裝全部 agent。
13
+ * --project-path <path> 指定專案根目錄作為安裝基底(取代 $HOME)。
14
+ * 省略時安裝至全域路徑。
15
+ */
2
16
  import { AGENTS, createInstaller } from './_utils.js';
3
17
 
18
+ /**
19
+ * 從 process.argv 解析指定 flag 的值。
20
+ * 例如 parseArg('--ai-agent') 在 argv 含 ['--ai-agent', 'claude'] 時回傳 'claude'。
21
+ * @param {string} flag
22
+ * @returns {string | undefined}
23
+ */
24
+ function parseArg(flag) {
25
+ const idx = process.argv.indexOf(flag);
26
+ if (idx === -1 || idx + 1 >= process.argv.length) return undefined;
27
+ return process.argv[idx + 1];
28
+ }
29
+
30
+ // 全域錯誤攔截,確保非預期錯誤不會靜默失敗
4
31
  process.on('uncaughtException', (err) => {
5
32
  console.error('💥 [Fatal Error]:', err);
6
33
  process.exit(1);
7
34
  });
8
-
9
35
  process.on('unhandledRejection', (reason) => {
10
36
  console.error('💥 [Unhandled Rejection]:', reason);
11
37
  process.exit(1);
12
38
  });
13
39
 
14
40
  async function main() {
41
+ // 先統一解析 CLI 參數,後續分支都使用同一份輸入來源,
42
+ // 避免在不同模式中重複讀取 process.argv。
43
+ const agentKey = parseArg('--ai-agent');
44
+ const projectPath = parseArg('--project-path');
45
+
46
+ // ── 模式一:指定單一 agent ──
47
+ if (agentKey) {
48
+ // 以 AGENTS 作為唯一白名單來源,避免使用者輸入未支援的 agent 名稱。
49
+ const config = AGENTS[agentKey];
50
+ if (!config) {
51
+ const valid = Object.keys(AGENTS).join(', ');
52
+ console.error(`❌ 未知的 agent: "${agentKey}"。可用選項: ${valid}`);
53
+ process.exit(1);
54
+ }
55
+
56
+ // createInstaller 會根據 agent 設定與 projectPath
57
+ // 回傳對應的安裝函式,這裡只需執行一次即可完成單一 agent 安裝。
58
+ const installFn = createInstaller(config, projectPath);
59
+ const result = await installFn();
60
+ if (!result.success) process.exit(1);
61
+ return;
62
+ }
63
+
64
+ // ── 模式二:安裝全部 agent ──
15
65
  console.log('╔══════════════════════════════════════════╗');
16
66
  console.log('║ 🧠 Neo Skills — 統一安裝程式 ║');
17
67
  console.log('╚══════════════════════════════════════════╝');
@@ -19,10 +69,12 @@ async function main() {
19
69
 
20
70
  const results = [];
21
71
 
22
- for (const [key, config] of Object.entries(AGENTS)) {
72
+ // 未指定 --ai-agent 時,逐一嘗試安裝所有已註冊 agent。
73
+ // 每個 agent 的錯誤都獨立處理,確保單一失敗不會中斷整體彙總流程。
74
+ for (const [, config] of Object.entries(AGENTS)) {
23
75
  console.log(`━━━ 正在安裝: ${config.name} ━━━`);
24
76
  try {
25
- const installFn = createInstaller(config);
77
+ const installFn = createInstaller(config, projectPath);
26
78
  const result = await installFn();
27
79
  results.push({ name: config.name, ...result });
28
80
  } catch (error) {
@@ -37,6 +89,7 @@ async function main() {
37
89
  console.log('📊 安裝結果彙總:');
38
90
  const failed = results.filter(r => !r.success);
39
91
 
92
+ // 統一列出每個 agent 的最終結果,讓使用者能快速判斷成功與失敗原因。
40
93
  for (const r of results) {
41
94
  console.log(` ${r.success ? '✅' : '❌'} ${r.name}: ${r.message}`);
42
95
  }
@@ -52,4 +105,5 @@ async function main() {
52
105
  console.log('🎉 全部安裝完成!');
53
106
  }
54
107
 
108
+ // 以單一入口啟動 CLI,讓所有例外都集中經過上方的全域錯誤處理。
55
109
  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.47.0",
4
+ "version": "0.47.3",
5
5
  "mcpServers": {
6
6
  "neo-skills": {
7
7
  "command": "node",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moon791017/neo-skills",
3
- "version": "1.0.18",
3
+ "version": "1.0.20",
4
4
  "type": "module",
5
5
  "description": "Neo Skills: A Universal Expert Agent Extension",
6
6
  "homepage": "https://neo-blog-iota.vercel.app/",
@@ -12,10 +12,7 @@
12
12
  ],
13
13
  "bin": {
14
14
  "neo-skills": "./bin/install-skills.js",
15
- "install-skills": "./bin/install-skills.js",
16
- "install-claude-skills": "./bin/install-claude-skills.js",
17
- "install-copilot-skills": "./bin/install-copilot-skills.js",
18
- "install-codex-skills": "./bin/install-codex-skills.js"
15
+ "install-skills": "./bin/install-skills.js"
19
16
  },
20
17
  "files": [
21
18
  "dist",
@@ -38,7 +35,7 @@
38
35
  "start": "node dist/server.js",
39
36
  "dev": "bun src/server.ts",
40
37
  "typecheck": "tsc --noEmit",
41
- "test": "echo \"No tests specified\" && exit 0"
38
+ "test": "node --test"
42
39
  },
43
40
  "devDependencies": {
44
41
  "@types/bun": "latest",
@@ -1,7 +0,0 @@
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 installClaudeSkills };
6
-
7
- runAsMain(install, import.meta.url);
@@ -1,7 +0,0 @@
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 installCodexSkills };
6
-
7
- runAsMain(install, import.meta.url);
@@ -1,7 +0,0 @@
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);