@panguard-ai/panguard-mcp 1.2.0 → 1.3.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.
@@ -8,6 +8,6 @@ export { detectPlatforms, getConfigPath } from './platform-detector.js';
8
8
  export type { PlatformId, DetectedPlatform } from './platform-detector.js';
9
9
  export { injectMCPConfig, removeMCPConfig, injectAll, getInstallCommand } from './mcp-injector.js';
10
10
  export type { InjectionResult } from './mcp-injector.js';
11
- export { parseMCPServers, resolveSkillDir, discoverAllSkills, removeServer } from './mcp-config-reader.js';
11
+ export { parseMCPServers, resolveSkillDir, discoverAllSkills, removeServer, } from './mcp-config-reader.js';
12
12
  export type { MCPServerEntry } from './mcp-config-reader.js';
13
13
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACxE,YAAY,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC3E,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACnG,YAAY,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAC3G,YAAY,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACxE,YAAY,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC3E,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACnG,YAAY,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EACL,eAAe,EACf,eAAe,EACf,iBAAiB,EACjB,YAAY,GACb,MAAM,wBAAwB,CAAC;AAChC,YAAY,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC"}
@@ -6,5 +6,5 @@
6
6
  */
7
7
  export { detectPlatforms, getConfigPath } from './platform-detector.js';
8
8
  export { injectMCPConfig, removeMCPConfig, injectAll, getInstallCommand } from './mcp-injector.js';
9
- export { parseMCPServers, resolveSkillDir, discoverAllSkills, removeServer } from './mcp-config-reader.js';
9
+ export { parseMCPServers, resolveSkillDir, discoverAllSkills, removeServer, } from './mcp-config-reader.js';
10
10
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAExE,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAEnG,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAExE,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAEnG,OAAO,EACL,eAAe,EACf,eAAe,EACf,iBAAiB,EACjB,YAAY,GACb,MAAM,wBAAwB,CAAC"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * MCP Config Injector - Write Panguard MCP config to AI agent platforms
3
+ * MCP 設定注入器 - 將 Panguard MCP 設定寫入 AI Agent 平台
4
+ *
5
+ * Supports Claude Code, Claude Desktop, Cursor, OpenClaw, Codex, Workbuddy, NemoClaw, ArkClaw.
6
+ *
7
+ * @module @panguard-ai/panguard-mcp/config/mcp-injector
8
+ */
9
+ import type { PlatformId } from './platform-detector.js';
10
+ export interface InjectionResult {
11
+ platformId: PlatformId;
12
+ success: boolean;
13
+ configPath: string;
14
+ backupPath?: string;
15
+ error?: string;
16
+ }
17
+ /**
18
+ * Inject Panguard MCP config into a specific platform.
19
+ * 將 Panguard MCP 設定注入特定平台。
20
+ *
21
+ * @param platformId - Target platform / 目標平台
22
+ * @returns Injection result with success status and paths.
23
+ */
24
+ export declare function injectMCPConfig(platformId: PlatformId): InjectionResult;
25
+ /**
26
+ * Remove Panguard MCP config from a specific platform.
27
+ * 從特定平台移除 Panguard MCP 設定。
28
+ */
29
+ export declare function removeMCPConfig(platformId: PlatformId): InjectionResult;
30
+ /**
31
+ * Inject Panguard MCP config into all detected platforms.
32
+ * 將 Panguard MCP 設定注入所有偵測到的平台。
33
+ */
34
+ export declare function injectAll(platformIds: PlatformId[]): Promise<InjectionResult[]>;
35
+ /**
36
+ * Get the one-liner install command for display.
37
+ * 取得用於顯示的一行安裝指令。
38
+ */
39
+ export declare function getInstallCommand(): string;
40
+ //# sourceMappingURL=mcp-injector.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-injector.d.ts","sourceRoot":"","sources":["../../src/config/mcp-injector.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAOH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAKzD,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,UAAU,CAAC;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA0JD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,UAAU,GAAG,eAAe,CAwEvE;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,UAAU,GAAG,eAAe,CAqCvE;AAED;;;GAGG;AACH,wBAAsB,SAAS,CAAC,WAAW,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAErF;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C"}
1
+ {"version":3,"file":"mcp-injector.d.ts","sourceRoot":"","sources":["../../src/config/mcp-injector.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAOH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAKzD,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,UAAU,CAAC;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA0JD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,UAAU,GAAG,eAAe,CA2EvE;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,UAAU,GAAG,eAAe,CAqCvE;AAED;;;GAGG;AACH,wBAAsB,SAAS,CAAC,WAAW,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAErF;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C"}
@@ -0,0 +1,297 @@
1
+ /**
2
+ * MCP Config Injector - Write Panguard MCP config to AI agent platforms
3
+ * MCP 設定注入器 - 將 Panguard MCP 設定寫入 AI Agent 平台
4
+ *
5
+ * Supports Claude Code, Claude Desktop, Cursor, OpenClaw, Codex, Workbuddy, NemoClaw, ArkClaw.
6
+ *
7
+ * @module @panguard-ai/panguard-mcp/config/mcp-injector
8
+ */
9
+ import { existsSync, mkdirSync, readFileSync, writeFileSync, copyFileSync, rmSync } from 'node:fs';
10
+ import { dirname, join } from 'node:path';
11
+ import { fileURLToPath } from 'node:url';
12
+ import { execFileSync } from 'node:child_process';
13
+ import { createLogger } from '@panguard-ai/core';
14
+ import { getConfigPath } from './platform-detector.js';
15
+ const logger = createLogger('panguard-mcp:injector');
16
+ /** The MCP server entry Panguard adds to config files. */
17
+ const PANGUARD_MCP_ENTRY = {
18
+ command: 'npx',
19
+ args: ['-y', '@panguard-ai/panguard-mcp'],
20
+ };
21
+ /**
22
+ * Read an existing JSON config file, or return empty object.
23
+ * 讀取現有 JSON 設定檔,或回傳空物件。
24
+ */
25
+ function readJsonSafe(filePath) {
26
+ if (!existsSync(filePath))
27
+ return {};
28
+ try {
29
+ const raw = readFileSync(filePath, 'utf-8');
30
+ const parsed = JSON.parse(raw);
31
+ if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
32
+ return parsed;
33
+ }
34
+ return {};
35
+ }
36
+ catch {
37
+ return {};
38
+ }
39
+ }
40
+ /**
41
+ * Back up a config file before modifying it.
42
+ * 修改前備份設定檔。
43
+ */
44
+ function backupFile(filePath) {
45
+ if (!existsSync(filePath))
46
+ return undefined;
47
+ const backupPath = `${filePath}.bak.${Date.now()}`;
48
+ copyFileSync(filePath, backupPath);
49
+ logger.info(`Backed up ${filePath} -> ${backupPath}`);
50
+ return backupPath;
51
+ }
52
+ /**
53
+ * Ensure parent directory exists.
54
+ * 確保父目錄存在。
55
+ */
56
+ function ensureDir(filePath) {
57
+ const dir = dirname(filePath);
58
+ if (!existsSync(dir)) {
59
+ mkdirSync(dir, { recursive: true });
60
+ }
61
+ }
62
+ /**
63
+ * Inject Panguard MCP config for Claude Desktop.
64
+ * Claude Desktop uses: { "mcpServers": { "panguard": { "command": "...", "args": [...] } } }
65
+ */
66
+ function injectClaudeDesktop(configPath) {
67
+ const config = readJsonSafe(configPath);
68
+ const servers = config['mcpServers'] ?? {};
69
+ servers['panguard'] = { ...PANGUARD_MCP_ENTRY };
70
+ config['mcpServers'] = servers;
71
+ writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8');
72
+ }
73
+ /**
74
+ * Inject Panguard MCP config for Claude Code.
75
+ * Claude Code uses `claude mcp add` CLI (not JSON file).
76
+ * Falls back to writing settings.local.json if CLI not available.
77
+ */
78
+ function injectClaudeCode(_configPath) {
79
+ try {
80
+ // Try `claude mcp add` first (the correct way for Claude Code)
81
+ execFileSync('claude', ['mcp', 'add', '--scope', 'user', 'panguard', '--', 'npx', '-y', '@panguard-ai/panguard-mcp'], {
82
+ timeout: 15_000,
83
+ stdio: 'pipe',
84
+ });
85
+ logger.info('Added Panguard MCP via `claude mcp add --scope user`');
86
+ }
87
+ catch {
88
+ // Fallback: write JSON directly (older Claude Code versions)
89
+ logger.warn('`claude mcp add` failed, falling back to JSON config');
90
+ const config = readJsonSafe(_configPath);
91
+ const servers = config['mcpServers'] ?? {};
92
+ servers['panguard'] = { ...PANGUARD_MCP_ENTRY };
93
+ config['mcpServers'] = servers;
94
+ writeFileSync(_configPath, JSON.stringify(config, null, 2), 'utf-8');
95
+ }
96
+ }
97
+ /**
98
+ * Inject Panguard MCP config for Cursor.
99
+ * Cursor uses: { "mcpServers": { "panguard": { "command": "...", "args": [...] } } }
100
+ * in ~/.cursor/mcp.json
101
+ */
102
+ function injectCursor(configPath) {
103
+ const config = readJsonSafe(configPath);
104
+ const servers = config['mcpServers'] ?? {};
105
+ servers['panguard'] = { ...PANGUARD_MCP_ENTRY };
106
+ config['mcpServers'] = servers;
107
+ writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8');
108
+ }
109
+ /**
110
+ * Inject Panguard MCP config for Codex/Workbuddy/NemoClaw.
111
+ * Generic MCP JSON format: { "mcpServers": { "panguard": { ... } } }
112
+ */
113
+ function injectGenericMCP(configPath) {
114
+ const config = readJsonSafe(configPath);
115
+ const servers = config['mcpServers'] ?? {};
116
+ servers['panguard'] = { ...PANGUARD_MCP_ENTRY };
117
+ config['mcpServers'] = servers;
118
+ writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8');
119
+ }
120
+ /**
121
+ * Inject Panguard as an OpenClaw native skill.
122
+ * OpenClaw uses its own skill system (not MCP), so we copy SKILL.md
123
+ * to ~/.openclaw/skills/panguard/.
124
+ */
125
+ function injectOpenClawSkill(skillDir) {
126
+ mkdirSync(skillDir, { recursive: true });
127
+ // Resolve the bundled SKILL.md from this package
128
+ const thisDir = dirname(fileURLToPath(import.meta.url));
129
+ const bundledSkill = join(thisDir, '..', '..', 'openclaw-skill', 'SKILL.md');
130
+ if (existsSync(bundledSkill)) {
131
+ copyFileSync(bundledSkill, join(skillDir, 'SKILL.md'));
132
+ }
133
+ else {
134
+ // Fallback: write a minimal SKILL.md inline
135
+ const skillContent = [
136
+ '---',
137
+ 'name: panguard',
138
+ 'description: AI agent security platform -- audit skills, scan threats, run 24/7 protection',
139
+ 'homepage: https://panguard.ai',
140
+ 'license: MIT',
141
+ 'metadata: { "openclaw": { "requires": { "bins": ["npx"] }, "install": [{ "id": "node", "kind": "node", "package": "@panguard-ai/panguard", "bins": ["panguard"], "label": "Install Panguard AI" }] } }',
142
+ '---',
143
+ '',
144
+ '# Panguard AI',
145
+ '',
146
+ 'Security platform for AI agents with 10,400+ detection rules.',
147
+ '',
148
+ '## Commands',
149
+ '- `panguard audit skill .` -- Audit skills for threats',
150
+ '- `panguard scan` -- Security scan',
151
+ '- `panguard guard start` -- Start real-time protection',
152
+ '- `panguard status` -- Show status dashboard',
153
+ '',
154
+ ].join('\n');
155
+ writeFileSync(join(skillDir, 'SKILL.md'), skillContent, 'utf-8');
156
+ }
157
+ }
158
+ /**
159
+ * Inject Panguard MCP config into a specific platform.
160
+ * 將 Panguard MCP 設定注入特定平台。
161
+ *
162
+ * @param platformId - Target platform / 目標平台
163
+ * @returns Injection result with success status and paths.
164
+ */
165
+ export function injectMCPConfig(platformId) {
166
+ const configPath = getConfigPath(platformId);
167
+ const result = { platformId, success: false, configPath };
168
+ try {
169
+ ensureDir(configPath);
170
+ result.backupPath = backupFile(configPath);
171
+ switch (platformId) {
172
+ case 'claude-desktop':
173
+ injectClaudeDesktop(configPath);
174
+ break;
175
+ case 'claude-code':
176
+ injectClaudeCode(configPath);
177
+ break;
178
+ case 'cursor':
179
+ injectCursor(configPath);
180
+ break;
181
+ case 'openclaw':
182
+ injectOpenClawSkill(configPath);
183
+ break;
184
+ case 'codex':
185
+ case 'workbuddy':
186
+ case 'nemoclaw':
187
+ case 'arkclaw':
188
+ injectGenericMCP(configPath);
189
+ break;
190
+ }
191
+ // Verify the write succeeded
192
+ if (platformId === 'claude-code') {
193
+ // Claude Code: verify via `claude mcp list`
194
+ try {
195
+ const output = execFileSync('claude', ['mcp', 'list'], {
196
+ timeout: 10_000,
197
+ stdio: 'pipe',
198
+ }).toString();
199
+ if (output.includes('panguard')) {
200
+ result.success = true;
201
+ logger.info('Verified Panguard MCP in Claude Code via `claude mcp list`');
202
+ }
203
+ else {
204
+ // Might take a moment to register, assume success if inject didn't throw
205
+ result.success = true;
206
+ logger.info('Panguard MCP added to Claude Code (pending verification)');
207
+ }
208
+ }
209
+ catch {
210
+ result.success = true; // inject didn't throw, assume OK
211
+ logger.info('Panguard MCP injected into Claude Code');
212
+ }
213
+ }
214
+ else if (platformId === 'openclaw') {
215
+ // OpenClaw uses SKILL.md, not JSON
216
+ if (existsSync(join(configPath, 'SKILL.md'))) {
217
+ result.success = true;
218
+ logger.info(`Installed Panguard skill for OpenClaw at ${configPath}`);
219
+ }
220
+ else {
221
+ result.error = 'Verification failed: SKILL.md not found after write';
222
+ logger.error(result.error);
223
+ }
224
+ }
225
+ else {
226
+ const verify = readJsonSafe(configPath);
227
+ const servers = verify['mcpServers'];
228
+ if (servers && servers['panguard']) {
229
+ result.success = true;
230
+ logger.info(`Injected Panguard MCP config into ${platformId} at ${configPath}`);
231
+ }
232
+ else {
233
+ result.error = 'Verification failed: panguard entry not found after write';
234
+ logger.error(result.error);
235
+ }
236
+ }
237
+ }
238
+ catch (err) {
239
+ result.error = err instanceof Error ? err.message : String(err);
240
+ logger.error(`Failed to inject ${platformId}: ${result.error}`);
241
+ }
242
+ return result;
243
+ }
244
+ /**
245
+ * Remove Panguard MCP config from a specific platform.
246
+ * 從特定平台移除 Panguard MCP 設定。
247
+ */
248
+ export function removeMCPConfig(platformId) {
249
+ const configPath = getConfigPath(platformId);
250
+ const result = { platformId, success: false, configPath };
251
+ try {
252
+ if (platformId === 'openclaw') {
253
+ // Remove OpenClaw skill directory
254
+ const skillMd = join(configPath, 'SKILL.md');
255
+ if (existsSync(skillMd)) {
256
+ rmSync(configPath, { recursive: true, force: true });
257
+ logger.info(`Removed Panguard skill from OpenClaw`);
258
+ }
259
+ result.success = true;
260
+ return result;
261
+ }
262
+ if (!existsSync(configPath)) {
263
+ result.success = true;
264
+ return result;
265
+ }
266
+ result.backupPath = backupFile(configPath);
267
+ const config = readJsonSafe(configPath);
268
+ const servers = config['mcpServers'];
269
+ if (servers) {
270
+ delete servers['panguard'];
271
+ config['mcpServers'] = servers;
272
+ }
273
+ writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8');
274
+ result.success = true;
275
+ logger.info(`Removed Panguard MCP config from ${platformId}`);
276
+ }
277
+ catch (err) {
278
+ result.error = err instanceof Error ? err.message : String(err);
279
+ logger.error(`Failed to remove from ${platformId}: ${result.error}`);
280
+ }
281
+ return result;
282
+ }
283
+ /**
284
+ * Inject Panguard MCP config into all detected platforms.
285
+ * 將 Panguard MCP 設定注入所有偵測到的平台。
286
+ */
287
+ export async function injectAll(platformIds) {
288
+ return platformIds.map((id) => injectMCPConfig(id));
289
+ }
290
+ /**
291
+ * Get the one-liner install command for display.
292
+ * 取得用於顯示的一行安裝指令。
293
+ */
294
+ export function getInstallCommand() {
295
+ return 'npx panguard setup';
296
+ }
297
+ //# sourceMappingURL=mcp-injector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-injector.js","sourceRoot":"","sources":["../../src/config/mcp-injector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Platform Detector - Detect installed AI agent runtimes
3
+ * 平台偵測器 - 偵測已安裝的 AI Agent 執行環境
4
+ *
5
+ * Detects Claude Code, Claude Desktop, Cursor, OpenClaw, Codex, WorkBuddy, NemoClaw, and ArkClaw.
6
+ * 偵測 Claude Code、Claude Desktop、Cursor、OpenClaw、Codex、WorkBuddy、NemoClaw 和 ArkClaw。
7
+ *
8
+ * @module @panguard-ai/panguard-mcp/config/platform-detector
9
+ */
10
+ export type PlatformId = 'claude-code' | 'claude-desktop' | 'cursor' | 'openclaw' | 'codex' | 'workbuddy' | 'nemoclaw' | 'arkclaw';
11
+ export interface DetectedPlatform {
12
+ id: PlatformId;
13
+ name: string;
14
+ configPath: string;
15
+ detected: boolean;
16
+ alreadyConfigured: boolean;
17
+ }
18
+ /**
19
+ * Detect all supported AI agent platforms.
20
+ * 偵測所有支援的 AI Agent 平台。
21
+ *
22
+ * @returns Array of detected platforms with their config paths and status.
23
+ */
24
+ export declare function detectPlatforms(): Promise<DetectedPlatform[]>;
25
+ /**
26
+ * Get the MCP config path for a specific platform.
27
+ * 取得特定平台的 MCP 設定路徑。
28
+ */
29
+ export declare function getConfigPath(platformId: PlatformId): string;
30
+ //# sourceMappingURL=platform-detector.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"platform-detector.d.ts","sourceRoot":"","sources":["../../src/config/platform-detector.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAUH,MAAM,MAAM,UAAU,GAAG,aAAa,GAAG,gBAAgB,GAAG,QAAQ,GAAG,UAAU,GAAG,OAAO,CAAC;AAE5F,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,UAAU,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAClB,iBAAiB,EAAE,OAAO,CAAC;CAC5B;AAyFD;;;;;GAKG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAsEnE;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,UAAU,EAAE,UAAU,GAAG,MAAM,CAa5D"}
1
+ {"version":3,"file":"platform-detector.d.ts","sourceRoot":"","sources":["../../src/config/platform-detector.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAUH,MAAM,MAAM,UAAU,GAClB,aAAa,GACb,gBAAgB,GAChB,QAAQ,GACR,UAAU,GACV,OAAO,GACP,WAAW,GACX,UAAU,GACV,SAAS,CAAC;AAEd,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,UAAU,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAClB,iBAAiB,EAAE,OAAO,CAAC;CAC5B;AAwGD;;;;;GAKG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC,CA+GnE;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,UAAU,EAAE,UAAU,GAAG,MAAM,CAmB5D"}
@@ -0,0 +1,232 @@
1
+ /**
2
+ * Platform Detector - Detect installed AI agent runtimes
3
+ * 平台偵測器 - 偵測已安裝的 AI Agent 執行環境
4
+ *
5
+ * Detects Claude Code, Claude Desktop, Cursor, OpenClaw, Codex, WorkBuddy, NemoClaw, and ArkClaw.
6
+ * 偵測 Claude Code、Claude Desktop、Cursor、OpenClaw、Codex、WorkBuddy、NemoClaw 和 ArkClaw。
7
+ *
8
+ * @module @panguard-ai/panguard-mcp/config/platform-detector
9
+ */
10
+ import { existsSync, readFileSync } from 'node:fs';
11
+ import { join } from 'node:path';
12
+ import { homedir, platform } from 'node:os';
13
+ import { execFile, execFileSync } from 'node:child_process';
14
+ import { createLogger } from '@panguard-ai/core';
15
+ const logger = createLogger('panguard-mcp:platform-detector');
16
+ /** Check if a command exists on PATH. */
17
+ function commandExists(cmd) {
18
+ if (!/^[a-zA-Z0-9_.-]+$/.test(cmd))
19
+ return Promise.resolve(false);
20
+ return new Promise((resolve) => {
21
+ const bin = platform() === 'win32' ? 'where' : 'which';
22
+ execFile(bin, [cmd], (err) => resolve(!err));
23
+ });
24
+ }
25
+ /** Check if a JSON config file has a panguard MCP server entry. */
26
+ function hasPanguardMCPEntry(filePath) {
27
+ if (!existsSync(filePath))
28
+ return false;
29
+ try {
30
+ const parsed = JSON.parse(readFileSync(filePath, 'utf-8'));
31
+ if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
32
+ const servers = parsed['mcpServers'];
33
+ if (servers && typeof servers === 'object' && !Array.isArray(servers)) {
34
+ return 'panguard' in servers;
35
+ }
36
+ }
37
+ return false;
38
+ }
39
+ catch {
40
+ return false;
41
+ }
42
+ }
43
+ /** Check if Claude Code has panguard MCP configured via `claude mcp list`. */
44
+ function hasClaudeCodePanguard() {
45
+ try {
46
+ const output = execFileSync('claude', ['mcp', 'list'], {
47
+ timeout: 10_000,
48
+ stdio: 'pipe',
49
+ }).toString();
50
+ return output.includes('panguard');
51
+ }
52
+ catch {
53
+ // Fallback: check JSON config
54
+ return hasPanguardMCPEntry(getClaudeCodeConfigPath());
55
+ }
56
+ }
57
+ /** Check if OpenClaw has the panguard skill installed. */
58
+ function hasOpenClawSkill() {
59
+ return existsSync(getOpenClawSkillPath());
60
+ }
61
+ /** Get the MCP config path for Claude Desktop based on OS. */
62
+ function getClaudeDesktopConfigPath() {
63
+ const home = homedir();
64
+ switch (platform()) {
65
+ case 'darwin':
66
+ return join(home, 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json');
67
+ case 'win32':
68
+ return join(process.env['APPDATA'] ?? join(home, 'AppData', 'Roaming'), 'Claude', 'claude_desktop_config.json');
69
+ default:
70
+ return join(home, '.config', 'claude', 'claude_desktop_config.json');
71
+ }
72
+ }
73
+ /** Get the MCP settings path for Claude Code. */
74
+ function getClaudeCodeConfigPath() {
75
+ return join(homedir(), '.claude', 'settings.local.json');
76
+ }
77
+ /** Get the MCP config path for Cursor. */
78
+ function getCursorConfigPath() {
79
+ return join(homedir(), '.cursor', 'mcp.json');
80
+ }
81
+ /** Get the OpenClaw skill installation path for Panguard. */
82
+ function getOpenClawSkillPath() {
83
+ return join(homedir(), '.openclaw', 'skills', 'panguard', 'SKILL.md');
84
+ }
85
+ /** Get the OpenClaw skills directory for Panguard. */
86
+ function getOpenClawSkillDir() {
87
+ return join(homedir(), '.openclaw', 'skills', 'panguard');
88
+ }
89
+ /** Get the MCP config path for Codex. */
90
+ function getCodexConfigPath() {
91
+ return join(homedir(), '.codex', 'mcp.json');
92
+ }
93
+ /** Get the MCP config path for WorkBuddy. */
94
+ function getWorkbuddyConfigPath() {
95
+ return join(homedir(), '.workbuddy', '.mcp.json');
96
+ }
97
+ /** Get the MCP config path for NemoClaw. */
98
+ function getNemoClawConfigPath() {
99
+ return join(homedir(), '.nemoclaw', 'mcp.json');
100
+ }
101
+ /** Get the MCP config path for ArkClaw (ByteDance). */
102
+ function getArkClawConfigPath() {
103
+ return join(homedir(), '.arkclaw', 'mcp.json');
104
+ }
105
+ /**
106
+ * Detect all supported AI agent platforms.
107
+ * 偵測所有支援的 AI Agent 平台。
108
+ *
109
+ * @returns Array of detected platforms with their config paths and status.
110
+ */
111
+ export async function detectPlatforms() {
112
+ const platforms = [];
113
+ // Claude Code (uses `claude mcp add` CLI, not JSON config)
114
+ const claudeCodePath = getClaudeCodeConfigPath();
115
+ const claudeCodeDetected = (await commandExists('claude')) || existsSync(join(homedir(), '.claude'));
116
+ platforms.push({
117
+ id: 'claude-code',
118
+ name: 'Claude Code',
119
+ configPath: claudeCodePath,
120
+ detected: claudeCodeDetected,
121
+ alreadyConfigured: hasClaudeCodePanguard(),
122
+ });
123
+ // Claude Desktop
124
+ const claudeDesktopPath = getClaudeDesktopConfigPath();
125
+ const claudeDesktopDetected = existsSync(claudeDesktopPath) ||
126
+ (platform() === 'darwin' && existsSync('/Applications/Claude.app'));
127
+ platforms.push({
128
+ id: 'claude-desktop',
129
+ name: 'Claude Desktop',
130
+ configPath: claudeDesktopPath,
131
+ detected: claudeDesktopDetected,
132
+ alreadyConfigured: hasPanguardMCPEntry(claudeDesktopPath),
133
+ });
134
+ // Cursor
135
+ const cursorPath = getCursorConfigPath();
136
+ const cursorDetected = (await commandExists('cursor')) ||
137
+ existsSync(join(homedir(), '.cursor')) ||
138
+ (platform() === 'darwin' && existsSync('/Applications/Cursor.app'));
139
+ platforms.push({
140
+ id: 'cursor',
141
+ name: 'Cursor',
142
+ configPath: cursorPath,
143
+ detected: cursorDetected,
144
+ alreadyConfigured: hasPanguardMCPEntry(cursorPath),
145
+ });
146
+ // OpenClaw (uses native skill system, not MCP)
147
+ const openclawSkillDir = getOpenClawSkillDir();
148
+ const openclawDetected = (await commandExists('openclaw')) || existsSync(join(homedir(), '.openclaw'));
149
+ platforms.push({
150
+ id: 'openclaw',
151
+ name: 'OpenClaw',
152
+ configPath: openclawSkillDir,
153
+ detected: openclawDetected,
154
+ alreadyConfigured: hasOpenClawSkill(),
155
+ });
156
+ // Codex
157
+ const codexPath = getCodexConfigPath();
158
+ const codexDetected = (await commandExists('codex')) || existsSync(join(homedir(), '.codex'));
159
+ platforms.push({
160
+ id: 'codex',
161
+ name: 'Codex CLI',
162
+ configPath: codexPath,
163
+ detected: codexDetected,
164
+ alreadyConfigured: hasPanguardMCPEntry(codexPath),
165
+ });
166
+ // WorkBuddy
167
+ const wbPath = getWorkbuddyConfigPath();
168
+ const wbDetected = (await commandExists('workbuddy')) || existsSync(join(homedir(), '.workbuddy'));
169
+ platforms.push({
170
+ id: 'workbuddy',
171
+ name: 'WorkBuddy',
172
+ configPath: wbPath,
173
+ detected: wbDetected,
174
+ alreadyConfigured: hasPanguardMCPEntry(wbPath),
175
+ });
176
+ // NemoClaw
177
+ const ncPath = getNemoClawConfigPath();
178
+ const ncDetected = (await commandExists('nemoclaw')) || existsSync(join(homedir(), '.nemoclaw'));
179
+ platforms.push({
180
+ id: 'nemoclaw',
181
+ name: 'NemoClaw',
182
+ configPath: ncPath,
183
+ detected: ncDetected,
184
+ alreadyConfigured: hasPanguardMCPEntry(ncPath),
185
+ });
186
+ // ArkClaw (ByteDance)
187
+ try {
188
+ const acCmd = await commandExists('arkclaw');
189
+ const acDir = existsSync(join(homedir(), '.arkclaw'));
190
+ if (acCmd || acDir) {
191
+ const cfgPath = getArkClawConfigPath();
192
+ platforms.push({
193
+ id: 'arkclaw',
194
+ name: 'ArkClaw',
195
+ configPath: cfgPath,
196
+ detected: true,
197
+ alreadyConfigured: hasPanguardMCPEntry(cfgPath),
198
+ });
199
+ }
200
+ }
201
+ catch {
202
+ /* not installed */
203
+ }
204
+ const detected = platforms.filter((p) => p.detected);
205
+ logger.info(`Detected ${detected.length} platform(s): ${detected.map((p) => p.name).join(', ') || 'none'}`);
206
+ return platforms;
207
+ }
208
+ /**
209
+ * Get the MCP config path for a specific platform.
210
+ * 取得特定平台的 MCP 設定路徑。
211
+ */
212
+ export function getConfigPath(platformId) {
213
+ switch (platformId) {
214
+ case 'claude-code':
215
+ return getClaudeCodeConfigPath();
216
+ case 'claude-desktop':
217
+ return getClaudeDesktopConfigPath();
218
+ case 'cursor':
219
+ return getCursorConfigPath();
220
+ case 'openclaw':
221
+ return getOpenClawSkillDir();
222
+ case 'codex':
223
+ return getCodexConfigPath();
224
+ case 'workbuddy':
225
+ return getWorkbuddyConfigPath();
226
+ case 'nemoclaw':
227
+ return getNemoClawConfigPath();
228
+ case 'arkclaw':
229
+ return getArkClawConfigPath();
230
+ }
231
+ }
232
+ //# sourceMappingURL=platform-detector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform-detector.js","sourceRoot":"","sources":["../../src/config/platform-detector.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@panguard-ai/panguard-mcp",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -32,10 +32,10 @@
32
32
  ],
33
33
  "dependencies": {
34
34
  "@modelcontextprotocol/sdk": "^1.12.0",
35
- "@panguard-ai/core": "1.1.0",
36
- "@panguard-ai/panguard-skill-auditor": "1.3.0",
37
- "@panguard-ai/panguard-scan": "1.1.0",
38
- "@panguard-ai/panguard-guard": "1.2.0"
35
+ "@panguard-ai/core": "1.3.0",
36
+ "@panguard-ai/panguard-scan": "1.3.0",
37
+ "@panguard-ai/panguard-guard": "1.3.0",
38
+ "@panguard-ai/panguard-skill-auditor": "1.3.1"
39
39
  },
40
40
  "devDependencies": {
41
41
  "@types/node": "^22.14.0",