yo-bug 0.1.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/LICENSE +21 -0
- package/README.md +160 -0
- package/bin/cli.ts +17 -0
- package/bin/install.ts +34 -0
- package/bin/mcp.ts +2 -0
- package/dist/bin/cli.d.ts +3 -0
- package/dist/bin/cli.d.ts.map +1 -0
- package/dist/bin/cli.js +19 -0
- package/dist/bin/cli.js.map +1 -0
- package/dist/bin/install.d.ts +3 -0
- package/dist/bin/install.d.ts.map +1 -0
- package/dist/bin/install.js +28 -0
- package/dist/bin/install.js.map +1 -0
- package/dist/bin/mcp.d.ts +3 -0
- package/dist/bin/mcp.d.ts.map +1 -0
- package/dist/bin/mcp.js +3 -0
- package/dist/bin/mcp.js.map +1 -0
- package/dist/src/detect/dev-server.d.ts +11 -0
- package/dist/src/detect/dev-server.d.ts.map +1 -0
- package/dist/src/detect/dev-server.js +92 -0
- package/dist/src/detect/dev-server.js.map +1 -0
- package/dist/src/detect/spawn-dev.d.ts +4 -0
- package/dist/src/detect/spawn-dev.d.ts.map +1 -0
- package/dist/src/detect/spawn-dev.js +37 -0
- package/dist/src/detect/spawn-dev.js.map +1 -0
- package/dist/src/install/detect-ai-tool.d.ts +7 -0
- package/dist/src/install/detect-ai-tool.d.ts.map +1 -0
- package/dist/src/install/detect-ai-tool.js +38 -0
- package/dist/src/install/detect-ai-tool.js.map +1 -0
- package/dist/src/install/write-mcp-config.d.ts +6 -0
- package/dist/src/install/write-mcp-config.d.ts.map +1 -0
- package/dist/src/install/write-mcp-config.js +47 -0
- package/dist/src/install/write-mcp-config.js.map +1 -0
- package/dist/src/mcp/index.d.ts +2 -0
- package/dist/src/mcp/index.d.ts.map +1 -0
- package/dist/src/mcp/index.js +263 -0
- package/dist/src/mcp/index.js.map +1 -0
- package/dist/src/mcp/tools/checklist.d.ts +22 -0
- package/dist/src/mcp/tools/checklist.d.ts.map +1 -0
- package/dist/src/mcp/tools/checklist.js +58 -0
- package/dist/src/mcp/tools/checklist.js.map +1 -0
- package/dist/src/mcp/tools/get-feedback.d.ts +13 -0
- package/dist/src/mcp/tools/get-feedback.d.ts.map +1 -0
- package/dist/src/mcp/tools/get-feedback.js +27 -0
- package/dist/src/mcp/tools/get-feedback.js.map +1 -0
- package/dist/src/mcp/tools/list-feedbacks.d.ts +20 -0
- package/dist/src/mcp/tools/list-feedbacks.d.ts.map +1 -0
- package/dist/src/mcp/tools/list-feedbacks.js +29 -0
- package/dist/src/mcp/tools/list-feedbacks.js.map +1 -0
- package/dist/src/mcp/tools/resolve-feedback.d.ts +8 -0
- package/dist/src/mcp/tools/resolve-feedback.d.ts.map +1 -0
- package/dist/src/mcp/tools/resolve-feedback.js +28 -0
- package/dist/src/mcp/tools/resolve-feedback.js.map +1 -0
- package/dist/src/mcp/tools/start-session.d.ts +11 -0
- package/dist/src/mcp/tools/start-session.d.ts.map +1 -0
- package/dist/src/mcp/tools/start-session.js +56 -0
- package/dist/src/mcp/tools/start-session.js.map +1 -0
- package/dist/src/mcp/tools/stop-session.d.ts +6 -0
- package/dist/src/mcp/tools/stop-session.d.ts.map +1 -0
- package/dist/src/mcp/tools/stop-session.js +80 -0
- package/dist/src/mcp/tools/stop-session.js.map +1 -0
- package/dist/src/mcp/tools/test-history.d.ts +33 -0
- package/dist/src/mcp/tools/test-history.d.ts.map +1 -0
- package/dist/src/mcp/tools/test-history.js +66 -0
- package/dist/src/mcp/tools/test-history.js.map +1 -0
- package/dist/src/server/feedback-api.d.ts +4 -0
- package/dist/src/server/feedback-api.d.ts.map +1 -0
- package/dist/src/server/feedback-api.js +152 -0
- package/dist/src/server/feedback-api.js.map +1 -0
- package/dist/src/server/html-injector.d.ts +10 -0
- package/dist/src/server/html-injector.d.ts.map +1 -0
- package/dist/src/server/html-injector.js +34 -0
- package/dist/src/server/html-injector.js.map +1 -0
- package/dist/src/server/proxy-server.d.ts +8 -0
- package/dist/src/server/proxy-server.d.ts.map +1 -0
- package/dist/src/server/proxy-server.js +87 -0
- package/dist/src/server/proxy-server.js.map +1 -0
- package/dist/src/server/sdk-serve.d.ts +3 -0
- package/dist/src/server/sdk-serve.d.ts.map +1 -0
- package/dist/src/server/sdk-serve.js +20 -0
- package/dist/src/server/sdk-serve.js.map +1 -0
- package/dist/src/storage/store.d.ts +21 -0
- package/dist/src/storage/store.d.ts.map +1 -0
- package/dist/src/storage/store.js +138 -0
- package/dist/src/storage/store.js.map +1 -0
- package/dist/src/storage/types.d.ts +74 -0
- package/dist/src/storage/types.d.ts.map +1 -0
- package/dist/src/storage/types.js +2 -0
- package/dist/src/storage/types.js.map +1 -0
- package/dist/vibe-feedback.js +399 -0
- package/package.json +67 -0
- package/src/client/annotation-mode/canvas-editor.ts +178 -0
- package/src/client/annotation-mode/history.ts +32 -0
- package/src/client/annotation-mode/region-selector.ts +123 -0
- package/src/client/annotation-mode/screenshot.ts +17 -0
- package/src/client/annotation-mode/toolbar.ts +139 -0
- package/src/client/annotation-mode/tools/arrow.ts +57 -0
- package/src/client/annotation-mode/tools/base-tool.ts +25 -0
- package/src/client/annotation-mode/tools/circle.ts +37 -0
- package/src/client/annotation-mode/tools/freehand.ts +23 -0
- package/src/client/annotation-mode/tools/rect.ts +32 -0
- package/src/client/annotation-mode/tools/text.ts +93 -0
- package/src/client/api/client.ts +48 -0
- package/src/client/capture/action-recorder.ts +157 -0
- package/src/client/capture/console-interceptor.ts +65 -0
- package/src/client/capture/context-buffer.ts +23 -0
- package/src/client/capture/error-interceptor.ts +52 -0
- package/src/client/capture/network-interceptor.ts +143 -0
- package/src/client/core/event-bus.ts +20 -0
- package/src/client/core/i18n.ts +83 -0
- package/src/client/core/sdk.ts +373 -0
- package/src/client/core/shadow-host.ts +27 -0
- package/src/client/element-mode/highlighter.ts +79 -0
- package/src/client/element-mode/inspector.ts +73 -0
- package/src/client/element-mode/selector.ts +22 -0
- package/src/client/index.ts +10 -0
- package/src/client/styles/sdk.css.ts +222 -0
- package/src/client/ui/checklist-panel.ts +279 -0
- package/src/client/ui/feedback-panel.ts +149 -0
- package/src/client/ui/floating-button.ts +103 -0
- package/src/client/ui/toast.ts +17 -0
- package/src/client/ui/verify-panel.ts +111 -0
- package/src/detect/dev-server.ts +110 -0
- package/src/detect/spawn-dev.ts +50 -0
- package/src/install/detect-ai-tool.ts +49 -0
- package/src/install/write-mcp-config.ts +49 -0
- package/src/mcp/index.ts +327 -0
- package/src/mcp/tools/checklist.ts +61 -0
- package/src/mcp/tools/get-feedback.ts +34 -0
- package/src/mcp/tools/list-feedbacks.ts +37 -0
- package/src/mcp/tools/resolve-feedback.ts +34 -0
- package/src/mcp/tools/start-session.ts +65 -0
- package/src/mcp/tools/stop-session.ts +93 -0
- package/src/mcp/tools/test-history.ts +97 -0
- package/src/server/feedback-api.ts +164 -0
- package/src/server/html-injector.ts +41 -0
- package/src/server/proxy-server.ts +107 -0
- package/src/server/sdk-serve.ts +24 -0
- package/src/storage/store.ts +172 -0
- package/src/storage/types.ts +68 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 vibe-feedback contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# yo-bug 🐛
|
|
2
|
+
|
|
3
|
+
**"Yo, bug!"** — Point at bugs, AI fixes them.
|
|
4
|
+
|
|
5
|
+
MCP Server that gives AI coding assistants QA superpowers. One install, then your AI handles the entire test-feedback-fix loop.
|
|
6
|
+
|
|
7
|
+
In vibe coding, the bottleneck is testing: humans find bugs but struggle to describe them. yo-bug solves this by letting users point, click, and annotate — while the AI automatically receives element locations, console errors, network failures, action recordings, and annotated screenshots.
|
|
8
|
+
|
|
9
|
+
## What it does
|
|
10
|
+
|
|
11
|
+
| For the Human | For the AI |
|
|
12
|
+
|---|---|
|
|
13
|
+
| Click a broken element → done | Gets: CSS selector + computed styles + React/Vue component name |
|
|
14
|
+
| Draw a circle on a screenshot → done | Gets: annotated screenshot as image content |
|
|
15
|
+
| Just use the app normally | Gets: last 100 user actions (clicks, inputs, navigation) |
|
|
16
|
+
| Check off a test list | Gets: which tests passed/failed with linked feedback |
|
|
17
|
+
|
|
18
|
+
The AI drives the entire workflow through MCP tools. Humans never need to learn commands, configure proxies, or modify their code.
|
|
19
|
+
|
|
20
|
+
## Install
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npx yo-bug install
|
|
24
|
+
|
|
25
|
+
# That's it. Your AI now has QA superpowers.
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
This auto-detects your AI tool (Claude Code / Cursor / Windsurf) and writes the MCP config. One time, done forever.
|
|
29
|
+
|
|
30
|
+
## How it works
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
AI writes code
|
|
34
|
+
→ AI calls start_test_session()
|
|
35
|
+
→ Browser opens with test overlay injected (zero code changes)
|
|
36
|
+
→ AI pushes a test checklist (8 QA dimensions, 40+ sub-scenarios)
|
|
37
|
+
→ Human tests, clicks problems, checks off items
|
|
38
|
+
→ AI calls list_feedbacks() → sees everything
|
|
39
|
+
→ AI fixes → calls resolve_feedback() → browser asks human to verify
|
|
40
|
+
→ Loop until done
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## MCP Tools (9 total)
|
|
44
|
+
|
|
45
|
+
### Session Control
|
|
46
|
+
| Tool | Description |
|
|
47
|
+
|---|---|
|
|
48
|
+
| `start_test_session(port?, open?)` | Start test mode: auto-detect dev server, launch reverse proxy with SDK injection, open browser |
|
|
49
|
+
| `stop_test_session()` | Stop test mode, return session summary (feedback stats, checklist results, weak dimensions) |
|
|
50
|
+
|
|
51
|
+
### Feedback
|
|
52
|
+
| Tool | Description |
|
|
53
|
+
|---|---|
|
|
54
|
+
| `list_feedbacks(status?, type?, limit?)` | List submitted feedback (filter by status: open/verify/resolved) |
|
|
55
|
+
| `get_feedback(id)` | Full details: element info, console errors, network errors, action steps, annotated screenshot |
|
|
56
|
+
| `resolve_feedback(id)` | Mark as fixed → pushes verification request to browser → human confirms |
|
|
57
|
+
|
|
58
|
+
### Test Checklist
|
|
59
|
+
| Tool | Description |
|
|
60
|
+
|---|---|
|
|
61
|
+
| `create_checklist(title, items)` | Push structured test checklist to browser. Items have step, expected result, priority, and dimension |
|
|
62
|
+
| `get_checklist_status()` | See which items passed/failed and any user feedback |
|
|
63
|
+
|
|
64
|
+
### Test History
|
|
65
|
+
| Tool | Description |
|
|
66
|
+
|---|---|
|
|
67
|
+
| `save_test_record(module, ...)` | Save test results per module. Accumulates history for future reference |
|
|
68
|
+
| `get_test_history(module)` | Get historical test records. Shows frequently failing scenarios |
|
|
69
|
+
|
|
70
|
+
## 8 QA Test Dimensions
|
|
71
|
+
|
|
72
|
+
The `create_checklist` tool embeds professional QA methodology. AI is guided to systematically cover:
|
|
73
|
+
|
|
74
|
+
1. **Happy path** — Core functionality works end-to-end
|
|
75
|
+
2. **Empty/boundary** — Empty inputs, special chars, max length, zero/negative values
|
|
76
|
+
3. **Error states** — Offline, server errors, timeouts, recovery
|
|
77
|
+
4. **Duplicate ops** — Double-click, re-submit, concurrent requests
|
|
78
|
+
5. **State recovery** — Refresh, back/forward, deep links, tab close/reopen
|
|
79
|
+
6. **Loading/async** — Loading states, failed loads, stale data
|
|
80
|
+
7. **Responsive** — 375px mobile width, touch targets, overflow
|
|
81
|
+
8. **Interaction detail** — Tab order, Enter/Escape, disabled states, focus
|
|
82
|
+
|
|
83
|
+
Each dimension has detailed sub-scenario templates that the AI selects from based on actual code changes.
|
|
84
|
+
|
|
85
|
+
## Three Feedback Modes
|
|
86
|
+
|
|
87
|
+
Users choose how to report issues:
|
|
88
|
+
|
|
89
|
+
| Mode | Shortcut | How it works |
|
|
90
|
+
|---|---|---|
|
|
91
|
+
| **Quick** | `Alt+Q` | Click an element → instantly flagged with full context. One click, done. |
|
|
92
|
+
| **Describe** | `Alt+D` | Click an element → fill a form with problem type and description |
|
|
93
|
+
| **Screenshot** | `Alt+S` | Drag to select screen region → annotate with arrows/shapes/text → submit |
|
|
94
|
+
|
|
95
|
+
Other shortcuts: `Alt+X` toggle test mode, `Esc` exit.
|
|
96
|
+
|
|
97
|
+
## Auto-Captured Context
|
|
98
|
+
|
|
99
|
+
Every feedback submission automatically includes:
|
|
100
|
+
|
|
101
|
+
- **Console errors** — last 50 `console.error`/`console.warn` entries with stack traces
|
|
102
|
+
- **Network failures** — failed `fetch`/`XHR` requests with status, URL, duration
|
|
103
|
+
- **Unhandled exceptions** — `window.onerror` + `unhandledrejection`
|
|
104
|
+
- **Action recording** — last 100 user actions (clicks, inputs, keypresses, navigation) with timestamps
|
|
105
|
+
- **Element info** — CSS selector, tag, text content, bounding rect, computed styles, React/Vue component name
|
|
106
|
+
|
|
107
|
+
## Verify-Fix Flow
|
|
108
|
+
|
|
109
|
+
When AI calls `resolve_feedback()`, instead of silently marking it done:
|
|
110
|
+
|
|
111
|
+
1. Browser shows a "Verify Fix" card to the user
|
|
112
|
+
2. User clicks "Fixed" or "Still broken"
|
|
113
|
+
3. Status updates accordingly — AI knows if the fix actually worked
|
|
114
|
+
|
|
115
|
+
## i18n
|
|
116
|
+
|
|
117
|
+
SDK auto-detects `<html lang="...">`:
|
|
118
|
+
- `zh-*` → Chinese interface
|
|
119
|
+
- Everything else → English interface
|
|
120
|
+
|
|
121
|
+
MCP tool descriptions are in English (AI translates to user's language naturally).
|
|
122
|
+
|
|
123
|
+
## Architecture
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
Browser → Reverse Proxy (localhost:3695) → Dev Server (localhost:5173)
|
|
127
|
+
│
|
|
128
|
+
├─ Auto-injects SDK into HTML responses
|
|
129
|
+
├─ WebSocket passthrough (HMR works normally)
|
|
130
|
+
├─ Feedback API (POST/GET)
|
|
131
|
+
├─ Checklist API (push/poll/update)
|
|
132
|
+
└─ Verify API (push/confirm)
|
|
133
|
+
|
|
134
|
+
MCP Server (stdio) → AI Tool (Claude Code / Cursor / Windsurf)
|
|
135
|
+
│
|
|
136
|
+
├─ start/stop_test_session → controls proxy lifecycle
|
|
137
|
+
├─ feedback tools → reads user submissions
|
|
138
|
+
├─ checklist tools → pushes test plans, reads results
|
|
139
|
+
└─ history tools → persists test records per module
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
The proxy auto-detects dev server framework (Vite, Next.js, CRA, Webpack, Nuxt, Angular, Svelte, Astro) and port. If the dev server is already running, it connects. If not, it starts one.
|
|
143
|
+
|
|
144
|
+
## Security
|
|
145
|
+
|
|
146
|
+
- All data stays local (`~/.yo-bug/`)
|
|
147
|
+
- Feedback IDs validated against path traversal
|
|
148
|
+
- Input fields whitelist-filtered and length-limited
|
|
149
|
+
- Network interceptor uses exact pathname matching (no substring false positives)
|
|
150
|
+
- No data sent to any external service
|
|
151
|
+
|
|
152
|
+
## Requirements
|
|
153
|
+
|
|
154
|
+
- Node.js >= 18
|
|
155
|
+
- Any MCP-compatible AI tool
|
|
156
|
+
- Any web application running in a browser
|
|
157
|
+
|
|
158
|
+
## License
|
|
159
|
+
|
|
160
|
+
MIT
|
package/bin/cli.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const command = process.argv[2];
|
|
4
|
+
|
|
5
|
+
if (command === 'mcp') {
|
|
6
|
+
// Start MCP server (stdio mode)
|
|
7
|
+
import('../src/mcp/index.js');
|
|
8
|
+
} else if (command === 'install') {
|
|
9
|
+
// Install MCP config to AI tools
|
|
10
|
+
import('./install.js');
|
|
11
|
+
} else {
|
|
12
|
+
console.log('yo-bug — AI Agent 的测试之眼\n');
|
|
13
|
+
console.log('用法:');
|
|
14
|
+
console.log(' npx yo-bug install 安装 MCP 到你的 AI 工具');
|
|
15
|
+
console.log(' npx yo-bug mcp 启动 MCP Server(由 AI 工具自动调用)');
|
|
16
|
+
console.log('\n安装后,AI 会自动获得测试模式能力,你不需要其他操作。');
|
|
17
|
+
}
|
package/bin/install.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { detectAITools } from '../src/install/detect-ai-tool.js';
|
|
3
|
+
import { writeMcpConfig } from '../src/install/write-mcp-config.js';
|
|
4
|
+
|
|
5
|
+
async function main() {
|
|
6
|
+
console.log('yo-bug — 安装 MCP Server\n');
|
|
7
|
+
|
|
8
|
+
const tools = await detectAITools();
|
|
9
|
+
const detected = tools.filter((t) => t.detected);
|
|
10
|
+
|
|
11
|
+
if (detected.length === 0) {
|
|
12
|
+
console.log('未检测到任何 AI 工具(Claude Code / Cursor / Windsurf)。');
|
|
13
|
+
console.log('请先安装至少一个 AI 编程工具后再运行此命令。\n');
|
|
14
|
+
console.log('手动配置方法:');
|
|
15
|
+
console.log(' 在 AI 工具的 MCP 配置中添加:');
|
|
16
|
+
console.log(' {');
|
|
17
|
+
console.log(' "command": "npx",');
|
|
18
|
+
console.log(' "args": ["yo-bug", "mcp"]');
|
|
19
|
+
console.log(' }');
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
console.log(`检测到 ${detected.length} 个 AI 工具:\n`);
|
|
24
|
+
|
|
25
|
+
for (const tool of detected) {
|
|
26
|
+
const result = await writeMcpConfig(tool);
|
|
27
|
+
console.log(` ${result.success ? '✓' : '✗'} ${result.message}`);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
console.log('\n安装完成!重启你的 AI 工具后即可使用 yo-bug。');
|
|
31
|
+
console.log('AI 会自动获得 start_test_session 等工具,无需其他操作。');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
main().catch(console.error);
|
package/bin/mcp.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../bin/cli.ts"],"names":[],"mappings":";AAEA,QAAA,MAAM,OAAO,QAAkB,CAAC"}
|
package/dist/bin/cli.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
const command = process.argv[2];
|
|
4
|
+
if (command === 'mcp') {
|
|
5
|
+
// Start MCP server (stdio mode)
|
|
6
|
+
import('../src/mcp/index.js');
|
|
7
|
+
}
|
|
8
|
+
else if (command === 'install') {
|
|
9
|
+
// Install MCP config to AI tools
|
|
10
|
+
import('./install.js');
|
|
11
|
+
}
|
|
12
|
+
else {
|
|
13
|
+
console.log('yo-bug — AI Agent 的测试之眼\n');
|
|
14
|
+
console.log('用法:');
|
|
15
|
+
console.log(' npx yo-bug install 安装 MCP 到你的 AI 工具');
|
|
16
|
+
console.log(' npx yo-bug mcp 启动 MCP Server(由 AI 工具自动调用)');
|
|
17
|
+
console.log('\n安装后,AI 会自动获得测试模式能力,你不需要其他操作。');
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../bin/cli.ts"],"names":[],"mappings":";;AAEA,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAEhC,IAAI,OAAO,KAAK,KAAK,EAAE,CAAC;IACtB,gCAAgC;IAChC,MAAM,CAAC,qBAAqB,CAAC,CAAC;AAChC,CAAC;KAAM,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;IACjC,iCAAiC;IACjC,MAAM,CAAC,cAAc,CAAC,CAAC;AACzB,CAAC;KAAM,CAAC;IACN,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;IACzC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACnB,OAAO,CAAC,GAAG,CAAC,yCAAyC,CAAC,CAAC;IACvD,OAAO,CAAC,GAAG,CAAC,mDAAmD,CAAC,CAAC;IACjE,OAAO,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC;AAChD,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../bin/install.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { detectAITools } from '../src/install/detect-ai-tool.js';
|
|
3
|
+
import { writeMcpConfig } from '../src/install/write-mcp-config.js';
|
|
4
|
+
async function main() {
|
|
5
|
+
console.log('yo-bug — 安装 MCP Server\n');
|
|
6
|
+
const tools = await detectAITools();
|
|
7
|
+
const detected = tools.filter((t) => t.detected);
|
|
8
|
+
if (detected.length === 0) {
|
|
9
|
+
console.log('未检测到任何 AI 工具(Claude Code / Cursor / Windsurf)。');
|
|
10
|
+
console.log('请先安装至少一个 AI 编程工具后再运行此命令。\n');
|
|
11
|
+
console.log('手动配置方法:');
|
|
12
|
+
console.log(' 在 AI 工具的 MCP 配置中添加:');
|
|
13
|
+
console.log(' {');
|
|
14
|
+
console.log(' "command": "npx",');
|
|
15
|
+
console.log(' "args": ["yo-bug", "mcp"]');
|
|
16
|
+
console.log(' }');
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
console.log(`检测到 ${detected.length} 个 AI 工具:\n`);
|
|
20
|
+
for (const tool of detected) {
|
|
21
|
+
const result = await writeMcpConfig(tool);
|
|
22
|
+
console.log(` ${result.success ? '✓' : '✗'} ${result.message}`);
|
|
23
|
+
}
|
|
24
|
+
console.log('\n安装完成!重启你的 AI 工具后即可使用 yo-bug。');
|
|
25
|
+
console.log('AI 会自动获得 start_test_session 等工具,无需其他操作。');
|
|
26
|
+
}
|
|
27
|
+
main().catch(console.error);
|
|
28
|
+
//# sourceMappingURL=install.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install.js","sourceRoot":"","sources":["../../bin/install.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AACjE,OAAO,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAEpE,KAAK,UAAU,IAAI;IACjB,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC;IAExC,MAAM,KAAK,GAAG,MAAM,aAAa,EAAE,CAAC;IACpC,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;IAEjD,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,CAAC,GAAG,CAAC,gDAAgD,CAAC,CAAC;QAC9D,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC;QAC1C,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACvB,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;QACrC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACnB,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;QACrC,OAAO,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAC;QAC7C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACnB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,OAAO,QAAQ,CAAC,MAAM,aAAa,CAAC,CAAC;IAEjD,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;QAC5B,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,IAAI,CAAC,CAAC;QAC1C,OAAO,CAAC,GAAG,CAAC,KAAK,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;IACnE,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC;IAC9C,OAAO,CAAC,GAAG,CAAC,yCAAyC,CAAC,CAAC;AACzD,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../../bin/mcp.ts"],"names":[],"mappings":";AACA,OAAO,qBAAqB,CAAC"}
|
package/dist/bin/mcp.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../bin/mcp.ts"],"names":[],"mappings":";AACA,OAAO,qBAAqB,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
interface DevServerInfo {
|
|
2
|
+
framework: string;
|
|
3
|
+
port: number;
|
|
4
|
+
command: string;
|
|
5
|
+
isRunning: boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare function detectDevServer(cwd: string, manualPort?: number): Promise<DevServerInfo>;
|
|
8
|
+
export declare function isPortInUse(port: number): Promise<boolean>;
|
|
9
|
+
export declare function waitForPort(port: number, timeout?: number): Promise<boolean>;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=dev-server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dev-server.d.ts","sourceRoot":"","sources":["../../../src/detect/dev-server.ts"],"names":[],"mappings":"AAIA,UAAU,aAAa;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;CACpB;AAaD,wBAAsB,eAAe,CACnC,GAAG,EAAE,MAAM,EACX,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,aAAa,CAAC,CAqDxB;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAiB1D;AAED,wBAAsB,WAAW,CAC/B,IAAI,EAAE,MAAM,EACZ,OAAO,SAAQ,GACd,OAAO,CAAC,OAAO,CAAC,CAOlB"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import net from 'net';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
const FRAMEWORK_PORTS = {
|
|
5
|
+
vite: { port: 5173, keywords: ['vite'] },
|
|
6
|
+
next: { port: 3000, keywords: ['next'] },
|
|
7
|
+
'create-react-app': { port: 3000, keywords: ['react-scripts'] },
|
|
8
|
+
webpack: { port: 8080, keywords: ['webpack serve', 'webpack-dev-server'] },
|
|
9
|
+
nuxt: { port: 3000, keywords: ['nuxt'] },
|
|
10
|
+
angular: { port: 4200, keywords: ['ng serve'] },
|
|
11
|
+
svelte: { port: 5173, keywords: ['svelte-kit', 'vite'] },
|
|
12
|
+
astro: { port: 4321, keywords: ['astro'] },
|
|
13
|
+
};
|
|
14
|
+
export async function detectDevServer(cwd, manualPort) {
|
|
15
|
+
// Read package.json
|
|
16
|
+
let devCommand = '';
|
|
17
|
+
let framework = 'unknown';
|
|
18
|
+
let port = manualPort || 0;
|
|
19
|
+
try {
|
|
20
|
+
const pkgPath = path.join(cwd, 'package.json');
|
|
21
|
+
const pkg = JSON.parse(await fs.readFile(pkgPath, 'utf-8'));
|
|
22
|
+
const scripts = pkg.scripts || {};
|
|
23
|
+
// Check "dev" or "start" scripts
|
|
24
|
+
devCommand = scripts.dev || scripts.start || '';
|
|
25
|
+
// Match framework
|
|
26
|
+
for (const [name, info] of Object.entries(FRAMEWORK_PORTS)) {
|
|
27
|
+
if (info.keywords.some((kw) => devCommand.includes(kw))) {
|
|
28
|
+
framework = name;
|
|
29
|
+
if (!manualPort)
|
|
30
|
+
port = info.port;
|
|
31
|
+
break;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
// Also check dependencies for framework detection
|
|
35
|
+
if (framework === 'unknown') {
|
|
36
|
+
const allDeps = {
|
|
37
|
+
...pkg.dependencies,
|
|
38
|
+
...pkg.devDependencies,
|
|
39
|
+
};
|
|
40
|
+
for (const [name, info] of Object.entries(FRAMEWORK_PORTS)) {
|
|
41
|
+
if (info.keywords.some((kw) => kw in allDeps)) {
|
|
42
|
+
framework = name;
|
|
43
|
+
if (!manualPort)
|
|
44
|
+
port = info.port;
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
// No package.json found
|
|
52
|
+
}
|
|
53
|
+
// Default port
|
|
54
|
+
if (!port)
|
|
55
|
+
port = 3000;
|
|
56
|
+
// Check if port is already in use
|
|
57
|
+
const isRunning = await isPortInUse(port);
|
|
58
|
+
return {
|
|
59
|
+
framework,
|
|
60
|
+
port,
|
|
61
|
+
command: devCommand,
|
|
62
|
+
isRunning,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
export function isPortInUse(port) {
|
|
66
|
+
return new Promise((resolve) => {
|
|
67
|
+
const socket = new net.Socket();
|
|
68
|
+
socket.setTimeout(1000);
|
|
69
|
+
socket.on('connect', () => {
|
|
70
|
+
socket.destroy();
|
|
71
|
+
resolve(true);
|
|
72
|
+
});
|
|
73
|
+
socket.on('timeout', () => {
|
|
74
|
+
socket.destroy();
|
|
75
|
+
resolve(false);
|
|
76
|
+
});
|
|
77
|
+
socket.on('error', () => {
|
|
78
|
+
resolve(false);
|
|
79
|
+
});
|
|
80
|
+
socket.connect(port, '127.0.0.1');
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
export async function waitForPort(port, timeout = 30000) {
|
|
84
|
+
const start = Date.now();
|
|
85
|
+
while (Date.now() - start < timeout) {
|
|
86
|
+
if (await isPortInUse(port))
|
|
87
|
+
return true;
|
|
88
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
89
|
+
}
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=dev-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dev-server.js","sourceRoot":"","sources":["../../../src/detect/dev-server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spawn-dev.d.ts","sourceRoot":"","sources":["../../../src/detect/spawn-dev.ts"],"names":[],"mappings":"AAKA,wBAAsB,cAAc,CAClC,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,OAAO,CAAC,CA6BlB;AAED,wBAAgB,aAAa,IAAI,IAAI,CAKpC;AAED,wBAAgB,kBAAkB,IAAI,OAAO,CAE5C"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { spawn } from 'child_process';
|
|
2
|
+
import { waitForPort } from './dev-server.js';
|
|
3
|
+
let devProcess = null;
|
|
4
|
+
export async function spawnDevServer(cwd, command, port) {
|
|
5
|
+
const isWindows = process.platform === 'win32';
|
|
6
|
+
const npmCmd = isWindows ? 'npm.cmd' : 'npm';
|
|
7
|
+
// Use the detected script name (e.g., "dev" or "start")
|
|
8
|
+
const scriptName = command.includes('start') ? 'start' : 'dev';
|
|
9
|
+
devProcess = spawn(npmCmd, ['run', scriptName], {
|
|
10
|
+
cwd,
|
|
11
|
+
shell: isWindows,
|
|
12
|
+
stdio: 'pipe', // Don't inherit — we're an MCP server using stdio
|
|
13
|
+
env: { ...process.env },
|
|
14
|
+
});
|
|
15
|
+
devProcess.stdout?.on('data', () => {
|
|
16
|
+
// Silently consume output — MCP server uses stdio
|
|
17
|
+
});
|
|
18
|
+
devProcess.stderr?.on('data', () => {
|
|
19
|
+
// Silently consume stderr
|
|
20
|
+
});
|
|
21
|
+
devProcess.on('error', () => {
|
|
22
|
+
// Silently handle — MCP server uses stdio, can't write to stderr
|
|
23
|
+
});
|
|
24
|
+
// Wait for the port to become available
|
|
25
|
+
const ready = await waitForPort(port, 30000);
|
|
26
|
+
return ready;
|
|
27
|
+
}
|
|
28
|
+
export function killDevServer() {
|
|
29
|
+
if (devProcess) {
|
|
30
|
+
devProcess.kill();
|
|
31
|
+
devProcess = null;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
export function isDevServerSpawned() {
|
|
35
|
+
return devProcess !== null && !devProcess.killed;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=spawn-dev.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spawn-dev.js","sourceRoot":"","sources":["../../../src/detect/spawn-dev.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAgB,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAE9C,IAAI,UAAU,GAAwB,IAAI,CAAC;AAE3C,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,GAAW,EACX,OAAe,EACf,IAAY;IAEZ,MAAM,SAAS,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC;IAC/C,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC;IAE7C,wDAAwD;IACxD,MAAM,UAAU,GAAG,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;IAE/D,UAAU,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,UAAU,CAAC,EAAE;QAC9C,GAAG;QACH,KAAK,EAAE,SAAS;QAChB,KAAK,EAAE,MAAM,EAAE,kDAAkD;QACjE,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE;KACxB,CAAC,CAAC;IAEH,UAAU,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE;QACjC,kDAAkD;IACpD,CAAC,CAAC,CAAC;IAEH,UAAU,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE;QACjC,0BAA0B;IAC5B,CAAC,CAAC,CAAC;IAEH,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;QAC1B,iEAAiE;IACnE,CAAC,CAAC,CAAC;IAEH,wCAAwC;IACxC,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAC7C,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,IAAI,UAAU,EAAE,CAAC;QACf,UAAU,CAAC,IAAI,EAAE,CAAC;QAClB,UAAU,GAAG,IAAI,CAAC;IACpB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,kBAAkB;IAChC,OAAO,UAAU,KAAK,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC;AACnD,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detect-ai-tool.d.ts","sourceRoot":"","sources":["../../../src/install/detect-ai-tool.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAID,wBAAsB,aAAa,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CA4BvD"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
const HOME = process.env.HOME || process.env.USERPROFILE || '';
|
|
4
|
+
export async function detectAITools() {
|
|
5
|
+
const tools = [];
|
|
6
|
+
// Claude Code
|
|
7
|
+
const claudeDir = path.join(HOME, '.claude');
|
|
8
|
+
tools.push({
|
|
9
|
+
name: 'Claude Code',
|
|
10
|
+
configPath: path.join(claudeDir, 'settings.json'),
|
|
11
|
+
detected: await dirExists(claudeDir),
|
|
12
|
+
});
|
|
13
|
+
// Cursor
|
|
14
|
+
const cursorDir = path.join(HOME, '.cursor');
|
|
15
|
+
tools.push({
|
|
16
|
+
name: 'Cursor',
|
|
17
|
+
configPath: path.join(cursorDir, 'mcp.json'),
|
|
18
|
+
detected: await dirExists(cursorDir),
|
|
19
|
+
});
|
|
20
|
+
// Windsurf
|
|
21
|
+
const windsurfDir = path.join(HOME, '.windsurf');
|
|
22
|
+
tools.push({
|
|
23
|
+
name: 'Windsurf',
|
|
24
|
+
configPath: path.join(windsurfDir, 'mcp.json'),
|
|
25
|
+
detected: await dirExists(windsurfDir),
|
|
26
|
+
});
|
|
27
|
+
return tools;
|
|
28
|
+
}
|
|
29
|
+
async function dirExists(dir) {
|
|
30
|
+
try {
|
|
31
|
+
const stat = await fs.stat(dir);
|
|
32
|
+
return stat.isDirectory();
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=detect-ai-tool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detect-ai-tool.js","sourceRoot":"","sources":["../../../src/install/detect-ai-tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,aAAa,CAAC;AAC7B,OAAO,IAAI,MAAM,MAAM,CAAC;AAQxB,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,EAAE,CAAC;AAE/D,MAAM,CAAC,KAAK,UAAU,aAAa;IACjC,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,cAAc;IACd,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IAC7C,KAAK,CAAC,IAAI,CAAC;QACT,IAAI,EAAE,aAAa;QACnB,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,eAAe,CAAC;QACjD,QAAQ,EAAE,MAAM,SAAS,CAAC,SAAS,CAAC;KACrC,CAAC,CAAC;IAEH,SAAS;IACT,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IAC7C,KAAK,CAAC,IAAI,CAAC;QACT,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC;QAC5C,QAAQ,EAAE,MAAM,SAAS,CAAC,SAAS,CAAC;KACrC,CAAC,CAAC;IAEH,WAAW;IACX,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;IACjD,KAAK,CAAC,IAAI,CAAC;QACT,IAAI,EAAE,UAAU;QAChB,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,UAAU,CAAC;QAC9C,QAAQ,EAAE,MAAM,SAAS,CAAC,WAAW,CAAC;KACvC,CAAC,CAAC;IAEH,OAAO,KAAK,CAAC;AACf,CAAC;AAED,KAAK,UAAU,SAAS,CAAC,GAAW;IAClC,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAChC,OAAO,IAAI,CAAC,WAAW,EAAE,CAAC;IAC5B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"write-mcp-config.d.ts","sourceRoot":"","sources":["../../../src/install/write-mcp-config.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAOlD,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAuCjG"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
const MCP_SERVER_CONFIG = {
|
|
4
|
+
command: 'npx',
|
|
5
|
+
args: ['yo-bug', 'mcp'],
|
|
6
|
+
};
|
|
7
|
+
export async function writeMcpConfig(tool) {
|
|
8
|
+
try {
|
|
9
|
+
// Ensure directory exists
|
|
10
|
+
await fs.mkdir(path.dirname(tool.configPath), { recursive: true });
|
|
11
|
+
// Read existing config
|
|
12
|
+
let config = {};
|
|
13
|
+
try {
|
|
14
|
+
const content = await fs.readFile(tool.configPath, 'utf-8');
|
|
15
|
+
config = JSON.parse(content);
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
// File doesn't exist or invalid JSON — start fresh
|
|
19
|
+
}
|
|
20
|
+
// Check if already configured
|
|
21
|
+
if (tool.name === 'Claude Code') {
|
|
22
|
+
config.mcpServers = config.mcpServers || {};
|
|
23
|
+
if (config.mcpServers['yo-bug']) {
|
|
24
|
+
return { success: true, message: `${tool.name}: 已配置,跳过。` };
|
|
25
|
+
}
|
|
26
|
+
config.mcpServers['yo-bug'] = {
|
|
27
|
+
type: 'stdio',
|
|
28
|
+
...MCP_SERVER_CONFIG,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
// Cursor / Windsurf format
|
|
33
|
+
config.mcpServers = config.mcpServers || {};
|
|
34
|
+
if (config.mcpServers['yo-bug']) {
|
|
35
|
+
return { success: true, message: `${tool.name}: 已配置,跳过。` };
|
|
36
|
+
}
|
|
37
|
+
config.mcpServers['yo-bug'] = MCP_SERVER_CONFIG;
|
|
38
|
+
}
|
|
39
|
+
// Write config
|
|
40
|
+
await fs.writeFile(tool.configPath, JSON.stringify(config, null, 2), 'utf-8');
|
|
41
|
+
return { success: true, message: `${tool.name}: MCP 配置已写入 ${tool.configPath}` };
|
|
42
|
+
}
|
|
43
|
+
catch (err) {
|
|
44
|
+
return { success: false, message: `${tool.name}: 写入失败 — ${err.message}` };
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=write-mcp-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"write-mcp-config.js","sourceRoot":"","sources":["../../../src/install/write-mcp-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,aAAa,CAAC;AAC7B,OAAO,IAAI,MAAM,MAAM,CAAC;AAGxB,MAAM,iBAAiB,GAAG;IACxB,OAAO,EAAE,KAAK;IACd,IAAI,EAAE,CAAC,QAAQ,EAAE,KAAK,CAAC;CACxB,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,IAAY;IAC/C,IAAI,CAAC;QACH,0BAA0B;QAC1B,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAEnE,uBAAuB;QACvB,IAAI,MAAM,GAAQ,EAAE,CAAC;QACrB,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;YAC5D,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC/B,CAAC;QAAC,MAAM,CAAC;YACP,mDAAmD;QACrD,CAAC;QAED,8BAA8B;QAC9B,IAAI,IAAI,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;YAChC,MAAM,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,IAAI,EAAE,CAAC;YAC5C,IAAI,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAChC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,IAAI,WAAW,EAAE,CAAC;YAC7D,CAAC;YACD,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,GAAG;gBAC5B,IAAI,EAAE,OAAO;gBACb,GAAG,iBAAiB;aACrB,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,2BAA2B;YAC3B,MAAM,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,IAAI,EAAE,CAAC;YAC5C,IAAI,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAChC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,IAAI,WAAW,EAAE,CAAC;YAC7D,CAAC;YACD,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,GAAG,iBAAiB,CAAC;QAClD,CAAC;QAED,eAAe;QACf,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;QAC9E,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,IAAI,eAAe,IAAI,CAAC,UAAU,EAAE,EAAE,CAAC;IAClF,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,IAAI,YAAY,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC;IAC5E,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/mcp/index.ts"],"names":[],"mappings":""}
|