@ppdocs/mcp 2.5.1 → 2.6.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/cli.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
2
  * ppdocs MCP CLI
3
- * 命令: init - 初始化项目配置 + 安装工作流模板
3
+ * 命令: init - 初始化项目配置 + 安装工作流模板 + 自动注册 MCP
4
4
  */
5
5
  export declare function runCli(args: string[]): boolean;
package/dist/cli.js CHANGED
@@ -1,10 +1,11 @@
1
1
  /**
2
2
  * ppdocs MCP CLI
3
- * 命令: init - 初始化项目配置 + 安装工作流模板
3
+ * 命令: init - 初始化项目配置 + 安装工作流模板 + 自动注册 MCP
4
4
  */
5
5
  import * as fs from 'fs';
6
6
  import * as path from 'path';
7
7
  import { fileURLToPath } from 'url';
8
+ import { execSync } from 'child_process';
8
9
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
9
10
  const TEMPLATES_DIR = path.join(__dirname, '..', 'templates');
10
11
  /** 生成随机用户名 (8位字母数字) */
@@ -84,6 +85,7 @@ export function runCli(args) {
84
85
  }
85
86
  function initProject(opts) {
86
87
  const cwd = process.cwd();
88
+ const apiUrl = `http://${opts.api}:${opts.port}/api/${opts.project}/${opts.key}`;
87
89
  // Create .ppdocs config
88
90
  const ppdocsConfig = {
89
91
  api: `http://${opts.api}:${opts.port}`,
@@ -94,7 +96,85 @@ function initProject(opts) {
94
96
  const ppdocsPath = path.join(cwd, '.ppdocs');
95
97
  fs.writeFileSync(ppdocsPath, JSON.stringify(ppdocsConfig, null, 2));
96
98
  console.log(`✅ Created ${ppdocsPath}`);
97
- // Create or update .mcp.json
99
+ // Install workflow templates
100
+ if (opts.codex) {
101
+ installCodexTemplates(cwd);
102
+ }
103
+ else {
104
+ installClaudeTemplates(cwd);
105
+ }
106
+ // 自动检测并注册 MCP
107
+ const registered = autoRegisterMcp(apiUrl, opts.user);
108
+ // 如果没有检测到任何 AI CLI,创建 .mcp.json 作为备用
109
+ if (!registered) {
110
+ createMcpJson(cwd);
111
+ }
112
+ console.log(`
113
+ 🎉 Done! ppdocs MCP configured for project: ${opts.project}
114
+ User: ${opts.user}
115
+
116
+ Restart your AI tool to use ppdocs knowledge graph.
117
+ `);
118
+ }
119
+ /** 检测命令是否存在 */
120
+ function commandExists(cmd) {
121
+ try {
122
+ const checkCmd = process.platform === 'win32' ? `where ${cmd}` : `which ${cmd}`;
123
+ execSync(checkCmd, { stdio: 'ignore' });
124
+ return true;
125
+ }
126
+ catch {
127
+ return false;
128
+ }
129
+ }
130
+ /** 自动检测 AI CLI 并注册 MCP */
131
+ function autoRegisterMcp(apiUrl, user) {
132
+ const detected = [];
133
+ // 检测 Claude CLI
134
+ if (commandExists('claude')) {
135
+ detected.push('Claude');
136
+ try {
137
+ const cmd = `claude mcp add ppdocs-kg -e PPDOCS_API_URL=${apiUrl} -e PPDOCS_USER=${user} -- npx -y @ppdocs/mcp`;
138
+ console.log(`✅ Detected Claude CLI, registering MCP...`);
139
+ execSync(cmd, { stdio: 'inherit' });
140
+ }
141
+ catch (e) {
142
+ console.log(`⚠️ Claude MCP registration failed: ${e}`);
143
+ }
144
+ }
145
+ // 检测 Codex CLI (OpenAI)
146
+ if (commandExists('codex')) {
147
+ detected.push('Codex');
148
+ try {
149
+ const cmd = `codex mcp add ppdocs-kg -e PPDOCS_API_URL=${apiUrl} -e PPDOCS_USER=${user} -- npx -y @ppdocs/mcp`;
150
+ console.log(`✅ Detected Codex CLI, registering MCP...`);
151
+ execSync(cmd, { stdio: 'inherit' });
152
+ }
153
+ catch (e) {
154
+ console.log(`⚠️ Codex MCP registration failed: ${e}`);
155
+ }
156
+ }
157
+ // 检测 Gemini CLI
158
+ if (commandExists('gemini')) {
159
+ detected.push('Gemini');
160
+ try {
161
+ const cmd = `gemini mcp add ppdocs-kg -e PPDOCS_API_URL=${apiUrl} -e PPDOCS_USER=${user} -- npx -y @ppdocs/mcp`;
162
+ console.log(`✅ Detected Gemini CLI, registering MCP...`);
163
+ execSync(cmd, { stdio: 'inherit' });
164
+ }
165
+ catch (e) {
166
+ console.log(`⚠️ Gemini MCP registration failed: ${e}`);
167
+ }
168
+ }
169
+ if (detected.length === 0) {
170
+ console.log(`ℹ️ No AI CLI detected (claude/codex/gemini), creating .mcp.json for manual config`);
171
+ return false;
172
+ }
173
+ console.log(`✅ Registered MCP for: ${detected.join(', ')}`);
174
+ return true;
175
+ }
176
+ /** 创建 .mcp.json (手动配置备用) */
177
+ function createMcpJson(cwd) {
98
178
  const mcpPath = path.join(cwd, '.mcp.json');
99
179
  let mcpConfig = {};
100
180
  if (fs.existsSync(mcpPath)) {
@@ -105,28 +185,17 @@ function initProject(opts) {
105
185
  // ignore parse error
106
186
  }
107
187
  }
188
+ // Windows 需要 cmd /c 包装才能执行 npx
189
+ const isWindows = process.platform === 'win32';
190
+ const ppdocsServer = isWindows
191
+ ? { command: 'cmd', args: ['/c', 'npx', '@ppdocs/mcp'] }
192
+ : { command: 'npx', args: ['@ppdocs/mcp'] };
108
193
  mcpConfig.mcpServers = {
109
194
  ...(mcpConfig.mcpServers || {}),
110
- ppdocs: {
111
- command: 'npx',
112
- args: ['@ppdocs/mcp'],
113
- },
195
+ ppdocs: ppdocsServer,
114
196
  };
115
197
  fs.writeFileSync(mcpPath, JSON.stringify(mcpConfig, null, 2));
116
198
  console.log(`✅ Created ${mcpPath}`);
117
- // Install workflow templates
118
- if (opts.codex) {
119
- installCodexTemplates(cwd);
120
- }
121
- else {
122
- installClaudeTemplates(cwd);
123
- }
124
- console.log(`
125
- 🎉 Done! ppdocs MCP configured for project: ${opts.project}
126
- User: ${opts.user}
127
-
128
- Restart Claude Code to use ppdocs knowledge graph.
129
- `);
130
199
  }
131
200
  /** 递归复制目录 */
132
201
  function copyDirRecursive(src, dest) {
@@ -144,6 +213,23 @@ function copyDirRecursive(src, dest) {
144
213
  }
145
214
  }
146
215
  }
216
+ /** 生成跨平台的 hooks 配置 */
217
+ function generateHooksConfig() {
218
+ const isWindows = process.platform === 'win32';
219
+ const command = isWindows
220
+ ? 'type ".claude\\hooks\\SystemPrompt.md"'
221
+ : 'cat ".claude/hooks/SystemPrompt.md"';
222
+ return {
223
+ hooks: {
224
+ UserPromptSubmit: [
225
+ {
226
+ matcher: '*',
227
+ hooks: [{ type: 'command', command }]
228
+ }
229
+ ]
230
+ }
231
+ };
232
+ }
147
233
  /** 安装 Claude Code 模板 */
148
234
  function installClaudeTemplates(cwd) {
149
235
  const claudeDir = path.join(cwd, '.claude');
@@ -161,26 +247,23 @@ function installClaudeTemplates(cwd) {
161
247
  copyDirRecursive(srcHooks, destHooks);
162
248
  console.log(`✅ Installed .claude/hooks/`);
163
249
  }
164
- // 3. 合并 settings.local.json hooks 配置
165
- const settingsHooksPath = path.join(TEMPLATES_DIR, 'settings-hooks.json');
250
+ // 3. 生成跨平台 hooks 配置并合并到 settings.local.json
166
251
  const settingsLocalPath = path.join(claudeDir, 'settings.local.json');
167
- if (fs.existsSync(settingsHooksPath)) {
168
- let existingSettings = {};
169
- if (fs.existsSync(settingsLocalPath)) {
170
- try {
171
- existingSettings = JSON.parse(fs.readFileSync(settingsLocalPath, 'utf-8'));
172
- }
173
- catch { /* ignore */ }
174
- }
175
- const hooksConfig = JSON.parse(fs.readFileSync(settingsHooksPath, 'utf-8'));
176
- const mergedSettings = {
177
- ...existingSettings,
178
- hooks: hooksConfig.hooks
179
- };
180
- fs.mkdirSync(claudeDir, { recursive: true });
181
- fs.writeFileSync(settingsLocalPath, JSON.stringify(mergedSettings, null, 2));
182
- console.log(`✅ Configured .claude/settings.local.json hooks`);
252
+ let existingSettings = {};
253
+ if (fs.existsSync(settingsLocalPath)) {
254
+ try {
255
+ existingSettings = JSON.parse(fs.readFileSync(settingsLocalPath, 'utf-8'));
256
+ }
257
+ catch { /* ignore */ }
183
258
  }
259
+ const hooksConfig = generateHooksConfig();
260
+ const mergedSettings = {
261
+ ...existingSettings,
262
+ ...hooksConfig
263
+ };
264
+ fs.mkdirSync(claudeDir, { recursive: true });
265
+ fs.writeFileSync(settingsLocalPath, JSON.stringify(mergedSettings, null, 2));
266
+ console.log(`✅ Configured .claude/settings.local.json hooks (${process.platform})`);
184
267
  }
185
268
  /** 安装 Codex 模板 (生成 AGENTS.md) */
186
269
  function installCodexTemplates(cwd) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ppdocs/mcp",
3
- "version": "2.5.1",
3
+ "version": "2.6.0",
4
4
  "description": "ppdocs MCP Server - Knowledge Graph for Claude",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -6,7 +6,7 @@
6
6
  "hooks": [
7
7
  {
8
8
  "type": "command",
9
- "command": "node -e \"console.log(require('fs').readFileSync('.claude/hooks/SystemPrompt.md','utf8'))\""
9
+ "command": "type \".claude\\hooks\\SystemPrompt.md\""
10
10
  }
11
11
  ]
12
12
  }