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.
Files changed (140) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +160 -0
  3. package/bin/cli.ts +17 -0
  4. package/bin/install.ts +34 -0
  5. package/bin/mcp.ts +2 -0
  6. package/dist/bin/cli.d.ts +3 -0
  7. package/dist/bin/cli.d.ts.map +1 -0
  8. package/dist/bin/cli.js +19 -0
  9. package/dist/bin/cli.js.map +1 -0
  10. package/dist/bin/install.d.ts +3 -0
  11. package/dist/bin/install.d.ts.map +1 -0
  12. package/dist/bin/install.js +28 -0
  13. package/dist/bin/install.js.map +1 -0
  14. package/dist/bin/mcp.d.ts +3 -0
  15. package/dist/bin/mcp.d.ts.map +1 -0
  16. package/dist/bin/mcp.js +3 -0
  17. package/dist/bin/mcp.js.map +1 -0
  18. package/dist/src/detect/dev-server.d.ts +11 -0
  19. package/dist/src/detect/dev-server.d.ts.map +1 -0
  20. package/dist/src/detect/dev-server.js +92 -0
  21. package/dist/src/detect/dev-server.js.map +1 -0
  22. package/dist/src/detect/spawn-dev.d.ts +4 -0
  23. package/dist/src/detect/spawn-dev.d.ts.map +1 -0
  24. package/dist/src/detect/spawn-dev.js +37 -0
  25. package/dist/src/detect/spawn-dev.js.map +1 -0
  26. package/dist/src/install/detect-ai-tool.d.ts +7 -0
  27. package/dist/src/install/detect-ai-tool.d.ts.map +1 -0
  28. package/dist/src/install/detect-ai-tool.js +38 -0
  29. package/dist/src/install/detect-ai-tool.js.map +1 -0
  30. package/dist/src/install/write-mcp-config.d.ts +6 -0
  31. package/dist/src/install/write-mcp-config.d.ts.map +1 -0
  32. package/dist/src/install/write-mcp-config.js +47 -0
  33. package/dist/src/install/write-mcp-config.js.map +1 -0
  34. package/dist/src/mcp/index.d.ts +2 -0
  35. package/dist/src/mcp/index.d.ts.map +1 -0
  36. package/dist/src/mcp/index.js +263 -0
  37. package/dist/src/mcp/index.js.map +1 -0
  38. package/dist/src/mcp/tools/checklist.d.ts +22 -0
  39. package/dist/src/mcp/tools/checklist.d.ts.map +1 -0
  40. package/dist/src/mcp/tools/checklist.js +58 -0
  41. package/dist/src/mcp/tools/checklist.js.map +1 -0
  42. package/dist/src/mcp/tools/get-feedback.d.ts +13 -0
  43. package/dist/src/mcp/tools/get-feedback.d.ts.map +1 -0
  44. package/dist/src/mcp/tools/get-feedback.js +27 -0
  45. package/dist/src/mcp/tools/get-feedback.js.map +1 -0
  46. package/dist/src/mcp/tools/list-feedbacks.d.ts +20 -0
  47. package/dist/src/mcp/tools/list-feedbacks.d.ts.map +1 -0
  48. package/dist/src/mcp/tools/list-feedbacks.js +29 -0
  49. package/dist/src/mcp/tools/list-feedbacks.js.map +1 -0
  50. package/dist/src/mcp/tools/resolve-feedback.d.ts +8 -0
  51. package/dist/src/mcp/tools/resolve-feedback.d.ts.map +1 -0
  52. package/dist/src/mcp/tools/resolve-feedback.js +28 -0
  53. package/dist/src/mcp/tools/resolve-feedback.js.map +1 -0
  54. package/dist/src/mcp/tools/start-session.d.ts +11 -0
  55. package/dist/src/mcp/tools/start-session.d.ts.map +1 -0
  56. package/dist/src/mcp/tools/start-session.js +56 -0
  57. package/dist/src/mcp/tools/start-session.js.map +1 -0
  58. package/dist/src/mcp/tools/stop-session.d.ts +6 -0
  59. package/dist/src/mcp/tools/stop-session.d.ts.map +1 -0
  60. package/dist/src/mcp/tools/stop-session.js +80 -0
  61. package/dist/src/mcp/tools/stop-session.js.map +1 -0
  62. package/dist/src/mcp/tools/test-history.d.ts +33 -0
  63. package/dist/src/mcp/tools/test-history.d.ts.map +1 -0
  64. package/dist/src/mcp/tools/test-history.js +66 -0
  65. package/dist/src/mcp/tools/test-history.js.map +1 -0
  66. package/dist/src/server/feedback-api.d.ts +4 -0
  67. package/dist/src/server/feedback-api.d.ts.map +1 -0
  68. package/dist/src/server/feedback-api.js +152 -0
  69. package/dist/src/server/feedback-api.js.map +1 -0
  70. package/dist/src/server/html-injector.d.ts +10 -0
  71. package/dist/src/server/html-injector.d.ts.map +1 -0
  72. package/dist/src/server/html-injector.js +34 -0
  73. package/dist/src/server/html-injector.js.map +1 -0
  74. package/dist/src/server/proxy-server.d.ts +8 -0
  75. package/dist/src/server/proxy-server.d.ts.map +1 -0
  76. package/dist/src/server/proxy-server.js +87 -0
  77. package/dist/src/server/proxy-server.js.map +1 -0
  78. package/dist/src/server/sdk-serve.d.ts +3 -0
  79. package/dist/src/server/sdk-serve.d.ts.map +1 -0
  80. package/dist/src/server/sdk-serve.js +20 -0
  81. package/dist/src/server/sdk-serve.js.map +1 -0
  82. package/dist/src/storage/store.d.ts +21 -0
  83. package/dist/src/storage/store.d.ts.map +1 -0
  84. package/dist/src/storage/store.js +138 -0
  85. package/dist/src/storage/store.js.map +1 -0
  86. package/dist/src/storage/types.d.ts +74 -0
  87. package/dist/src/storage/types.d.ts.map +1 -0
  88. package/dist/src/storage/types.js +2 -0
  89. package/dist/src/storage/types.js.map +1 -0
  90. package/dist/vibe-feedback.js +399 -0
  91. package/package.json +67 -0
  92. package/src/client/annotation-mode/canvas-editor.ts +178 -0
  93. package/src/client/annotation-mode/history.ts +32 -0
  94. package/src/client/annotation-mode/region-selector.ts +123 -0
  95. package/src/client/annotation-mode/screenshot.ts +17 -0
  96. package/src/client/annotation-mode/toolbar.ts +139 -0
  97. package/src/client/annotation-mode/tools/arrow.ts +57 -0
  98. package/src/client/annotation-mode/tools/base-tool.ts +25 -0
  99. package/src/client/annotation-mode/tools/circle.ts +37 -0
  100. package/src/client/annotation-mode/tools/freehand.ts +23 -0
  101. package/src/client/annotation-mode/tools/rect.ts +32 -0
  102. package/src/client/annotation-mode/tools/text.ts +93 -0
  103. package/src/client/api/client.ts +48 -0
  104. package/src/client/capture/action-recorder.ts +157 -0
  105. package/src/client/capture/console-interceptor.ts +65 -0
  106. package/src/client/capture/context-buffer.ts +23 -0
  107. package/src/client/capture/error-interceptor.ts +52 -0
  108. package/src/client/capture/network-interceptor.ts +143 -0
  109. package/src/client/core/event-bus.ts +20 -0
  110. package/src/client/core/i18n.ts +83 -0
  111. package/src/client/core/sdk.ts +373 -0
  112. package/src/client/core/shadow-host.ts +27 -0
  113. package/src/client/element-mode/highlighter.ts +79 -0
  114. package/src/client/element-mode/inspector.ts +73 -0
  115. package/src/client/element-mode/selector.ts +22 -0
  116. package/src/client/index.ts +10 -0
  117. package/src/client/styles/sdk.css.ts +222 -0
  118. package/src/client/ui/checklist-panel.ts +279 -0
  119. package/src/client/ui/feedback-panel.ts +149 -0
  120. package/src/client/ui/floating-button.ts +103 -0
  121. package/src/client/ui/toast.ts +17 -0
  122. package/src/client/ui/verify-panel.ts +111 -0
  123. package/src/detect/dev-server.ts +110 -0
  124. package/src/detect/spawn-dev.ts +50 -0
  125. package/src/install/detect-ai-tool.ts +49 -0
  126. package/src/install/write-mcp-config.ts +49 -0
  127. package/src/mcp/index.ts +327 -0
  128. package/src/mcp/tools/checklist.ts +61 -0
  129. package/src/mcp/tools/get-feedback.ts +34 -0
  130. package/src/mcp/tools/list-feedbacks.ts +37 -0
  131. package/src/mcp/tools/resolve-feedback.ts +34 -0
  132. package/src/mcp/tools/start-session.ts +65 -0
  133. package/src/mcp/tools/stop-session.ts +93 -0
  134. package/src/mcp/tools/test-history.ts +97 -0
  135. package/src/server/feedback-api.ts +164 -0
  136. package/src/server/html-injector.ts +41 -0
  137. package/src/server/proxy-server.ts +107 -0
  138. package/src/server/sdk-serve.ts +24 -0
  139. package/src/storage/store.ts +172 -0
  140. package/src/storage/types.ts +68 -0
@@ -0,0 +1,263 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
3
+ import { z } from 'zod';
4
+ import { FeedbackStore } from '../storage/store.js';
5
+ import { startTestSession } from './tools/start-session.js';
6
+ import { stopTestSession } from './tools/stop-session.js';
7
+ import { listFeedbacks } from './tools/list-feedbacks.js';
8
+ import { getFeedback } from './tools/get-feedback.js';
9
+ import { resolveFeedback } from './tools/resolve-feedback.js';
10
+ import { createChecklist, getChecklistStatus } from './tools/checklist.js';
11
+ import { saveTestRecord, getTestHistory } from './tools/test-history.js';
12
+ const store = new FeedbackStore();
13
+ const WORKFLOW_GUIDE = `# yo-bug — AI Workflow Guide
14
+
15
+ You have visual test feedback capabilities. Here is the complete workflow:
16
+
17
+ ## When to Use
18
+ - After writing or modifying frontend code, before telling the user "it's done"
19
+ - When the user says "let me test" or "something looks wrong"
20
+ - When you want the user to verify your changes
21
+
22
+ ## Complete Workflow (follow this order)
23
+
24
+ ### 1. Start test session
25
+ Call start_test_session() to launch the test environment.
26
+ This auto-detects the dev server, starts a reverse proxy with the test SDK injected, and opens the browser.
27
+ The user's project code is NOT modified — the SDK is injected via the proxy.
28
+
29
+ ### 2. Check test history (if applicable)
30
+ Call get_test_history(module) to see if this module has been tested before.
31
+ Look for frequently failing scenarios — make sure your checklist covers them.
32
+
33
+ ### 3. Push a test checklist
34
+ Call create_checklist(title, items) with structured test items.
35
+ Follow the 8 QA dimensions in the tool description. Each item needs:
36
+ - step: exactly what the user should do
37
+ - expect: exactly what they should see
38
+ - priority: "critical" for core paths, "normal" for edge cases
39
+ - dimension: which QA dimension this tests
40
+
41
+ ### 4. Wait for the user to test
42
+ Tell the user: "Test session is ready. Go through the checklist in the browser. When you find issues, press Alt+Q to quick-flag them, or Alt+S to screenshot and annotate."
43
+ The user tests at their own pace. Don't rush them.
44
+
45
+ ### 5. Check results
46
+ Call get_checklist_status() to see pass/fail results.
47
+ Call list_feedbacks() to see any bug reports the user submitted.
48
+ Call get_feedback(id) to see full details including:
49
+ - Annotated screenshots (returned as image content you can see)
50
+ - Element CSS selectors and computed styles
51
+ - Console errors and stack traces
52
+ - Failed network requests
53
+ - User's action recording (what they clicked/typed before the bug)
54
+
55
+ ### 6. Fix issues
56
+ Fix the code based on the feedback details.
57
+ After fixing each issue, call resolve_feedback(id).
58
+ This pushes a "Verify Fix" card to the user's browser — they click "Fixed" or "Still broken".
59
+
60
+ ### 7. Save test record
61
+ Call save_test_record(module, title, items, results, failedItems) to persist the test results.
62
+ Next time you modify this module, get_test_history will show what failed before.
63
+
64
+ ### 8. End session
65
+ When testing is complete, call stop_test_session().
66
+ This returns a session summary with stats and weak dimension analysis.
67
+
68
+ ## Keyboard Shortcuts (tell user about these)
69
+ - Alt+Q: Quick flag mode — click an element to instantly report it
70
+ - Alt+D: Detail mode — click an element, then describe the issue
71
+ - Alt+S: Screenshot mode — drag to select area, annotate with drawings
72
+ - Alt+X: Toggle test mode
73
+ - Esc: Exit test mode
74
+
75
+ ## Tips
76
+ - The user's browser automatically captures console errors, network failures, and action steps. You don't need to ask them to check DevTools.
77
+ - When you see a feedback with action steps, you can trace the exact reproduction path.
78
+ - Screenshots are returned as image content blocks — you can see the annotations directly.
79
+ - The checklist appears in the user's browser automatically. You don't need to list the items in chat.
80
+ `;
81
+ const server = new McpServer({
82
+ name: 'yo-bug',
83
+ version: '0.1.0',
84
+ });
85
+ // --- Resource: workflow guide ---
86
+ server.resource('workflow-guide', 'yo-bug://workflow', { description: 'Complete workflow guide for using yo-bug. READ THIS FIRST before calling any tools.', mimeType: 'text/markdown' }, async () => ({
87
+ contents: [{
88
+ uri: 'yo-bug://workflow',
89
+ mimeType: 'text/markdown',
90
+ text: WORKFLOW_GUIDE,
91
+ }],
92
+ }));
93
+ // --- Tool: start_test_session ---
94
+ server.tool('start_test_session', `Start test mode. Auto-detects dev server, starts a reverse proxy with injected test feedback SDK, and opens the browser.
95
+
96
+ After calling this, follow these steps:
97
+ 1. Call get_test_history(module) to check past test records
98
+ 2. Call create_checklist(title, items) to push a structured test plan
99
+ 3. Tell the user to test. Shortcuts: Alt+Q (quick flag), Alt+D (describe), Alt+S (screenshot), Esc (exit)
100
+ 4. Call get_checklist_status() and list_feedbacks() to read results
101
+ 5. Fix issues, call resolve_feedback(id) for each — user verifies in browser
102
+ 6. Call save_test_record() to persist results
103
+ 7. Call stop_test_session() when done`, {
104
+ port: z.number().optional().describe('Dev server port. Auto-detected from package.json if not provided.'),
105
+ open: z.boolean().optional().describe('Whether to auto-open browser. Default: true.'),
106
+ }, async ({ port, open }) => {
107
+ const result = await startTestSession(store, { port, open });
108
+ return {
109
+ content: [{ type: 'text', text: result.message }],
110
+ isError: result.status === 'error',
111
+ };
112
+ });
113
+ // --- Tool: stop_test_session ---
114
+ server.tool('stop_test_session', 'Stop test mode. Shuts down the reverse proxy and any auto-started dev server. Returns a test session summary.', {}, async () => {
115
+ const result = await stopTestSession(store);
116
+ return {
117
+ content: [{ type: 'text', text: result.message }],
118
+ };
119
+ });
120
+ // --- Tool: list_feedbacks ---
121
+ server.tool('list_feedbacks', 'List user-submitted test feedback. Returns a summary of each feedback item.', {
122
+ status: z.enum(['open', 'verify', 'resolved', 'all']).optional().describe('Filter by status. Default: open.'),
123
+ type: z.string().optional().describe('Filter by problem type: bug, ui-issue, performance, feature-request, other.'),
124
+ limit: z.number().optional().describe('Max items to return. Default: 20.'),
125
+ }, async ({ status, type, limit }) => {
126
+ const result = await listFeedbacks(store, { status, type, limit });
127
+ return {
128
+ content: [{
129
+ type: 'text',
130
+ text: result.text + '\n\n' + JSON.stringify(result.items, null, 2),
131
+ }],
132
+ };
133
+ });
134
+ // --- Tool: get_feedback ---
135
+ server.tool('get_feedback', 'Get full details of a feedback item, including element info, console errors, network errors, action steps, and annotated screenshot (as image content).', {
136
+ id: z.string().describe('Feedback ID.'),
137
+ }, async ({ id }) => {
138
+ const result = await getFeedback(store, { id });
139
+ if (result.error) {
140
+ return { content: [{ type: 'text', text: result.text }], isError: true };
141
+ }
142
+ return { content: result.content };
143
+ });
144
+ // --- Tool: resolve_feedback ---
145
+ server.tool('resolve_feedback', 'Mark a feedback item as fixed. This pushes a verification request to the browser — the user will confirm whether the fix actually works. Status changes to "verify" until user confirms.', {
146
+ id: z.string().describe('Feedback ID.'),
147
+ }, async ({ id }) => {
148
+ const result = await resolveFeedback(store, { id });
149
+ return {
150
+ content: [{ type: 'text', text: result.text }],
151
+ isError: result.error,
152
+ };
153
+ });
154
+ // --- Tool: create_checklist ---
155
+ server.tool('create_checklist', `Create a test checklist and push it to the user's browser. Users can go through items one by one and mark each as passed/failed.
156
+
157
+ You MUST systematically generate the checklist based on the actual code changes, reviewing each of the 8 test dimensions below. Include items for every dimension that is relevant to your changes:
158
+
159
+ 1. Happy path (critical)
160
+ - Complete positive flow of core functionality
161
+ - Use realistic data (not "test"/"123")
162
+ - Verify results display correctly and remain interactive
163
+
164
+ 2. Empty/boundary values
165
+ - Submit all input fields empty
166
+ - Input only whitespace
167
+ - Input exceeding max length (200+ characters)
168
+ - Special characters: < > " ' & ; \` ${"${}"}
169
+ - Numeric fields: 0, negative, decimal, non-numeric text
170
+ - Date fields: past, future, invalid format
171
+ - Lists/tables: 0 items, 1 item, 100+ items
172
+
173
+ 3. Error states
174
+ - Submit while offline (DevTools Network → Offline)
175
+ - Server returns 400/500 error
176
+ - Request timeout (DevTools Network → Slow 3G)
177
+ - Error messages are clear and positioned near the problem
178
+ - Can recover and retry after an error
179
+
180
+ 4. Duplicate operations
181
+ - Rapidly click submit button 3 times
182
+ - Submit the same form data twice consecutively
183
+ - Trigger action while previous request is still pending
184
+ - Buttons/forms show disabled state during processing
185
+
186
+ 5. State recovery
187
+ - Refresh page (F5) after completing action — data persists?
188
+ - Browser back then forward — state correct?
189
+ - Direct URL access to a deep page
190
+ - Close tab and reopen
191
+ - Refresh mid-way through a form — data recovered or warning shown?
192
+
193
+ 6. Loading/async
194
+ - First load shows loading state (not blank)
195
+ - Failed data load shows empty state or error message
196
+ - Can interact with other parts while loading
197
+ - UI updates promptly after data changes
198
+
199
+ 7. Responsive
200
+ - Shrink browser to 375px width (or DevTools mobile mode)
201
+ - Key buttons and forms are usable, not obscured
202
+ - Text doesn't overflow or get clipped
203
+ - No horizontal scrollbar
204
+
205
+ 8. Interaction details
206
+ - Tab key follows logical focus order
207
+ - Enter key submits forms
208
+ - Escape key closes modals/cancels actions
209
+ - Disabled buttons are truly non-clickable
210
+ - Focus moves to the correct element after actions
211
+
212
+ Each item MUST have a specific step and expected result.
213
+ Step should be specific: "Type 200 'a' characters in the email field, click Submit".
214
+ Expected should be specific: "Red error text appears below email field: 'Invalid email format'".
215
+ Never write vague expectations like "should work normally".
216
+
217
+ Important: Before generating a checklist, call get_test_history to check historical test records for this module. Focus on previously failed scenarios. After testing is complete, call save_test_record to save the results.`, {
218
+ title: z.string().describe('Checklist title. Briefly describe test scope, e.g. "Login feature test".'),
219
+ items: z.array(z.object({
220
+ step: z.string().describe('Specific action steps for the user. Be concrete: what to click, what to type, under what conditions.'),
221
+ expect: z.string().describe('Expected result after the action. Be concrete: what text appears, where it navigates, what changes.'),
222
+ priority: z.enum(['critical', 'normal']).optional().describe('critical = core path must pass, normal = boundary/error/detail scenario. Default: normal.'),
223
+ dimension: z.string().optional().describe('Test dimension: happy-path / empty-boundary / error-state / duplicate-ops / state-recovery / loading-async / responsive / interaction-detail'),
224
+ })).describe('Test items. List critical items first, then normal, ensuring systematic coverage.'),
225
+ }, async ({ title, items }) => {
226
+ const result = await createChecklist({ title, items });
227
+ return { content: [{ type: 'text', text: result.text }] };
228
+ });
229
+ // --- Tool: get_checklist_status ---
230
+ server.tool('get_checklist_status', 'Get current checklist status: which items passed, failed, or are pending, and any user feedback on failed items.', {}, async () => {
231
+ const result = await getChecklistStatus();
232
+ return { content: [{ type: 'text', text: result.text }] };
233
+ });
234
+ // --- Tool: save_test_record ---
235
+ server.tool('save_test_record', 'Save test results for a module. Call after checklist testing is complete to accumulate test history. This data is used by get_test_history to identify frequently failing scenarios.', {
236
+ module: z.string().describe('Feature module name, e.g. "login", "order-submit", "user-management".'),
237
+ title: z.string().describe('Test session title.'),
238
+ items: z.array(z.any()).describe('Test items (from get_checklist_status).'),
239
+ results: z.object({
240
+ passed: z.number(),
241
+ failed: z.number(),
242
+ total: z.number(),
243
+ }).describe('Test result counts.'),
244
+ failedItems: z.array(z.string()).describe('Descriptions of failed test items.'),
245
+ }, async ({ module, title, items, results, failedItems }) => {
246
+ const result = await saveTestRecord({ module, title, items, results, failedItems });
247
+ return { content: [{ type: 'text', text: result.text }] };
248
+ });
249
+ // --- Tool: get_test_history ---
250
+ server.tool('get_test_history', 'Get historical test records for a module, including frequently failing scenarios. Call this BEFORE generating a new checklist to ensure coverage of previously problematic areas.', {
251
+ module: z.string().describe('Feature module name, e.g. "login", "order-submit", "user-management".'),
252
+ }, async ({ module }) => {
253
+ const result = await getTestHistory({ module });
254
+ return { content: [{ type: 'text', text: result.text }] };
255
+ });
256
+ // --- Start ---
257
+ async function main() {
258
+ await store.init();
259
+ const transport = new StdioServerTransport();
260
+ await server.connect(transport);
261
+ }
262
+ main().catch(console.error);
263
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/mcp/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC3E,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAEzE,MAAM,KAAK,GAAG,IAAI,aAAa,EAAE,CAAC;AAElC,MAAM,cAAc,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmEtB,CAAC;AAEF,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;IAC3B,IAAI,EAAE,QAAQ;IACd,OAAO,EAAE,OAAO;CACjB,CAAC,CAAC;AAEH,mCAAmC;AACnC,MAAM,CAAC,QAAQ,CACb,gBAAgB,EAChB,mBAAmB,EACnB,EAAE,WAAW,EAAE,qFAAqF,EAAE,QAAQ,EAAE,eAAe,EAAE,EACjI,KAAK,IAAI,EAAE,CAAC,CAAC;IACX,QAAQ,EAAE,CAAC;YACT,GAAG,EAAE,mBAAmB;YACxB,QAAQ,EAAE,eAAe;YACzB,IAAI,EAAE,cAAc;SACrB,CAAC;CACH,CAAC,CACH,CAAC;AAEF,mCAAmC;AACnC,MAAM,CAAC,IAAI,CACT,oBAAoB,EACpB;;;;;;;;;sCASoC,EACpC;IACE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,mEAAmE,CAAC;IACzG,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,8CAA8C,CAAC;CACtF,EACD,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE;IACvB,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7D,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC;QACjD,OAAO,EAAE,MAAM,CAAC,MAAM,KAAK,OAAO;KACnC,CAAC;AACJ,CAAC,CACF,CAAC;AAEF,kCAAkC;AAClC,MAAM,CAAC,IAAI,CACT,mBAAmB,EACnB,+GAA+G,EAC/G,EAAE,EACF,KAAK,IAAI,EAAE;IACT,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,KAAK,CAAC,CAAC;IAC5C,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC;KAClD,CAAC;AACJ,CAAC,CACF,CAAC;AAEF,+BAA+B;AAC/B,MAAM,CAAC,IAAI,CACT,gBAAgB,EAChB,6EAA6E,EAC7E;IACE,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,KAAK,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,kCAAkC,CAAC;IAC7G,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,6EAA6E,CAAC;IACnH,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,mCAAmC,CAAC;CAC3E,EACD,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE;IAChC,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACnE,OAAO;QACL,OAAO,EAAE,CAAC;gBACR,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,MAAM,CAAC,IAAI,GAAG,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;aACnE,CAAC;KACH,CAAC;AACJ,CAAC,CACF,CAAC;AAEF,6BAA6B;AAC7B,MAAM,CAAC,IAAI,CACT,cAAc,EACd,yJAAyJ,EACzJ;IACE,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC;CACxC,EACD,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE;IACf,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;IAChD,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QACjB,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,IAAK,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC5E,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,OAAQ,EAAE,CAAC;AACtC,CAAC,CACF,CAAC;AAEF,iCAAiC;AACjC,MAAM,CAAC,IAAI,CACT,kBAAkB,EAClB,0LAA0L,EAC1L;IACE,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC;CACxC,EACD,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE;IACf,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;IACpD,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC;QAC9C,OAAO,EAAE,MAAM,CAAC,KAAK;KACtB,CAAC;AACJ,CAAC,CACF,CAAC;AAEF,iCAAiC;AACjC,MAAM,CAAC,IAAI,CACT,kBAAkB,EAClB;;;;;;;;;;;;;0CAawC,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8NAiD+K,EAC5N;IACE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,0EAA0E,CAAC;IACtG,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;QACtB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,sGAAsG,CAAC;QACjI,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,qGAAqG,CAAC;QAClI,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,2FAA2F,CAAC;QACzJ,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,8IAA8I,CAAC;KAC1L,CAAC,CAAC,CAAC,QAAQ,CAAC,mFAAmF,CAAC;CAClG,EACD,KAAK,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE;IACzB,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;IACvD,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;AAC5D,CAAC,CACF,CAAC;AAEF,qCAAqC;AACrC,MAAM,CAAC,IAAI,CACT,sBAAsB,EACtB,kHAAkH,EAClH,EAAE,EACF,KAAK,IAAI,EAAE;IACT,MAAM,MAAM,GAAG,MAAM,kBAAkB,EAAE,CAAC;IAC1C,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;AAC5D,CAAC,CACF,CAAC;AAEF,iCAAiC;AACjC,MAAM,CAAC,IAAI,CACT,kBAAkB,EAClB,sLAAsL,EACtL;IACE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,uEAAuE,CAAC;IACpG,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,qBAAqB,CAAC;IACjD,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,QAAQ,CAAC,yCAAyC,CAAC;IAC3E,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC;QAChB,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;QAClB,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;QAClB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;KAClB,CAAC,CAAC,QAAQ,CAAC,qBAAqB,CAAC;IAClC,WAAW,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,CAAC,oCAAoC,CAAC;CAChF,EACD,KAAK,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,EAAE,EAAE;IACvD,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,CAAC;IACpF,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;AAC5D,CAAC,CACF,CAAC;AAEF,iCAAiC;AACjC,MAAM,CAAC,IAAI,CACT,kBAAkB,EAClB,mLAAmL,EACnL;IACE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,uEAAuE,CAAC;CACrG,EACD,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE;IACnB,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;IAChD,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;AAC5D,CAAC,CACF,CAAC;AAEF,gBAAgB;AAChB,KAAK,UAAU,IAAI;IACjB,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC;IACnB,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Create a test checklist and push it to the browser.
3
+ */
4
+ export declare function createChecklist(args: {
5
+ title: string;
6
+ items: {
7
+ step: string;
8
+ expect: string;
9
+ priority?: string;
10
+ dimension?: string;
11
+ }[];
12
+ }): Promise<{
13
+ text: string;
14
+ }>;
15
+ /**
16
+ * Get the current checklist status from the browser.
17
+ */
18
+ export declare function getChecklistStatus(): Promise<{
19
+ text: string;
20
+ data: any;
21
+ }>;
22
+ //# sourceMappingURL=checklist.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checklist.d.ts","sourceRoot":"","sources":["../../../../src/mcp/tools/checklist.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE;IAC1C,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAClF,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAe5B;AAED;;GAEG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,GAAG,CAAA;CAAE,CAAC,CAkC/E"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Create a test checklist and push it to the browser.
3
+ */
4
+ export async function createChecklist(args) {
5
+ try {
6
+ const res = await fetch('http://localhost:3695/api/checklist', {
7
+ method: 'POST',
8
+ headers: { 'Content-Type': 'application/json' },
9
+ body: JSON.stringify({ title: args.title, items: args.items }),
10
+ });
11
+ if (!res.ok)
12
+ throw new Error(`HTTP ${res.status}`);
13
+ const data = await res.json();
14
+ return {
15
+ text: `测试清单已推送到浏览器(${data.count} 项)。用户可以在页面上逐项测试并勾选结果。`,
16
+ };
17
+ }
18
+ catch {
19
+ return { text: '推送失败。测试模式可能未启动。' };
20
+ }
21
+ }
22
+ /**
23
+ * Get the current checklist status from the browser.
24
+ */
25
+ export async function getChecklistStatus() {
26
+ try {
27
+ const res = await fetch('http://localhost:3695/api/checklist');
28
+ if (!res.ok)
29
+ throw new Error(`HTTP ${res.status}`);
30
+ const data = await res.json();
31
+ if (!data.items || data.items.length === 0) {
32
+ return { text: '当前没有测试清单。', data: null };
33
+ }
34
+ const passed = data.items.filter((i) => i.status === 'passed').length;
35
+ const failed = data.items.filter((i) => i.status === 'failed').length;
36
+ const pending = data.items.filter((i) => i.status === 'pending').length;
37
+ const lines = [
38
+ `测试清单: ${data.title}`,
39
+ `进度: ${passed} 通过 / ${failed} 失败 / ${pending} 待测`,
40
+ '',
41
+ ];
42
+ for (const item of data.items) {
43
+ const icon = item.status === 'passed' ? '[PASS]' :
44
+ item.status === 'failed' ? '[FAIL]' : '[ ]';
45
+ const priority = item.priority === 'critical' ? ' [!]' : '';
46
+ const dim = item.dimension ? ` [${item.dimension}]` : '';
47
+ lines.push(`${icon}${priority}${dim} ${item.step}`);
48
+ lines.push(` 预期: ${item.expect}`);
49
+ if (item.feedback)
50
+ lines.push(` 反馈: ${item.feedback}`);
51
+ }
52
+ return { text: lines.join('\n'), data };
53
+ }
54
+ catch {
55
+ return { text: '无法获取清单状态。测试模式可能未启动。', data: null };
56
+ }
57
+ }
58
+ //# sourceMappingURL=checklist.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checklist.js","sourceRoot":"","sources":["../../../../src/mcp/tools/checklist.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import { FeedbackStore } from '../../storage/store.js';
2
+ export declare function getFeedback(store: FeedbackStore, args: {
3
+ id: string;
4
+ }): Promise<{
5
+ error: boolean;
6
+ text: string;
7
+ content?: undefined;
8
+ } | {
9
+ error: boolean;
10
+ content: any[];
11
+ text?: undefined;
12
+ }>;
13
+ //# sourceMappingURL=get-feedback.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-feedback.d.ts","sourceRoot":"","sources":["../../../../src/mcp/tools/get-feedback.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAEvD,wBAAsB,WAAW,CAC/B,KAAK,EAAE,aAAa,EACpB,IAAI,EAAE;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE;;;;;;;;GA6BrB"}
@@ -0,0 +1,27 @@
1
+ export async function getFeedback(store, args) {
2
+ await store.init();
3
+ const item = await store.getById(args.id);
4
+ if (!item) {
5
+ return { error: true, text: `反馈 ${args.id} 不存在。` };
6
+ }
7
+ // Build content blocks
8
+ const content = [
9
+ {
10
+ type: 'text',
11
+ text: JSON.stringify(item, null, 2),
12
+ },
13
+ ];
14
+ // Include screenshot if available
15
+ if (item.hasScreenshot) {
16
+ const screenshot = await store.getScreenshot(args.id);
17
+ if (screenshot) {
18
+ content.push({
19
+ type: 'image',
20
+ data: screenshot.toString('base64'),
21
+ mimeType: 'image/png',
22
+ });
23
+ }
24
+ }
25
+ return { error: false, content };
26
+ }
27
+ //# sourceMappingURL=get-feedback.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-feedback.js","sourceRoot":"","sources":["../../../../src/mcp/tools/get-feedback.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,KAAoB,EACpB,IAAoB;IAEpB,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC;IACnB,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC1C,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,IAAI,CAAC,EAAE,OAAO,EAAE,CAAC;IACrD,CAAC;IAED,uBAAuB;IACvB,MAAM,OAAO,GAAU;QACrB;YACE,IAAI,EAAE,MAAe;YACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;SACpC;KACF,CAAC;IAEF,kCAAkC;IAClC,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;QACvB,MAAM,UAAU,GAAG,MAAM,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACtD,IAAI,UAAU,EAAE,CAAC;YACf,OAAO,CAAC,IAAI,CAAC;gBACX,IAAI,EAAE,OAAgB;gBACtB,IAAI,EAAE,UAAU,CAAC,QAAQ,CAAC,QAAQ,CAAC;gBACnC,QAAQ,EAAE,WAAW;aACtB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;AACnC,CAAC"}
@@ -0,0 +1,20 @@
1
+ import { FeedbackStore } from '../../storage/store.js';
2
+ export declare function listFeedbacks(store: FeedbackStore, args: {
3
+ status?: string;
4
+ type?: string;
5
+ limit?: number;
6
+ }): Promise<{
7
+ text: string;
8
+ items: {
9
+ id: string;
10
+ mode: "element" | "annotation";
11
+ problemType: import("../../storage/types.js").ProblemType;
12
+ description: string;
13
+ pageUrl: string;
14
+ status: "open" | "verify" | "resolved";
15
+ createdAt: string;
16
+ hasScreenshot: boolean;
17
+ errorCount: number;
18
+ }[];
19
+ }>;
20
+ //# sourceMappingURL=list-feedbacks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-feedbacks.d.ts","sourceRoot":"","sources":["../../../../src/mcp/tools/list-feedbacks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAEvD,wBAAsB,aAAa,CACjC,KAAK,EAAE,aAAa,EACpB,IAAI,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE;;;;;;;;;;;;;GAgCzD"}
@@ -0,0 +1,29 @@
1
+ export async function listFeedbacks(store, args) {
2
+ await store.init();
3
+ const result = await store.list({
4
+ status: args.status || 'open',
5
+ type: args.type,
6
+ limit: args.limit || 20,
7
+ });
8
+ if (result.items.length === 0) {
9
+ return { text: '当前没有反馈。', items: [] };
10
+ }
11
+ const summary = result.items.map((item) => ({
12
+ id: item.id,
13
+ mode: item.mode,
14
+ problemType: item.problemType,
15
+ description: item.description.slice(0, 100),
16
+ pageUrl: item.pageUrl,
17
+ status: item.status,
18
+ createdAt: item.createdAt,
19
+ hasScreenshot: item.hasScreenshot,
20
+ errorCount: item.consoleErrors.length +
21
+ item.networkErrors.length +
22
+ item.unhandledErrors.length,
23
+ }));
24
+ return {
25
+ text: `共 ${result.total} 条反馈(显示 ${summary.length} 条)`,
26
+ items: summary,
27
+ };
28
+ }
29
+ //# sourceMappingURL=list-feedbacks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-feedbacks.js","sourceRoot":"","sources":["../../../../src/mcp/tools/list-feedbacks.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,KAAoB,EACpB,IAAwD;IAExD,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC;IACnB,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC;QAC9B,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,MAAM;QAC7B,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,EAAE;KACxB,CAAC,CAAC;IAEH,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC9B,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;IACxC,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAC1C,EAAE,EAAE,IAAI,CAAC,EAAE;QACX,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,WAAW,EAAE,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;QAC3C,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,aAAa,EAAE,IAAI,CAAC,aAAa;QACjC,UAAU,EACR,IAAI,CAAC,aAAa,CAAC,MAAM;YACzB,IAAI,CAAC,aAAa,CAAC,MAAM;YACzB,IAAI,CAAC,eAAe,CAAC,MAAM;KAC9B,CAAC,CAAC,CAAC;IAEJ,OAAO;QACL,IAAI,EAAE,KAAK,MAAM,CAAC,KAAK,WAAW,OAAO,CAAC,MAAM,KAAK;QACrD,KAAK,EAAE,OAAO;KACf,CAAC;AACJ,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { FeedbackStore } from '../../storage/store.js';
2
+ export declare function resolveFeedback(store: FeedbackStore, args: {
3
+ id: string;
4
+ }): Promise<{
5
+ error: boolean;
6
+ text: string;
7
+ }>;
8
+ //# sourceMappingURL=resolve-feedback.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve-feedback.d.ts","sourceRoot":"","sources":["../../../../src/mcp/tools/resolve-feedback.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAEvD,wBAAsB,eAAe,CACnC,KAAK,EAAE,aAAa,EACpB,IAAI,EAAE;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE;;;GA6BrB"}
@@ -0,0 +1,28 @@
1
+ export async function resolveFeedback(store, args) {
2
+ await store.init();
3
+ const item = await store.getById(args.id);
4
+ if (!item) {
5
+ return { error: true, text: `反馈 ${args.id} 不存在。` };
6
+ }
7
+ // Mark as "verify" — waiting for user to confirm the fix
8
+ await store.updateStatus(args.id, 'verify');
9
+ // Push verification request to browser
10
+ try {
11
+ await fetch('http://localhost:3695/api/verify', {
12
+ method: 'POST',
13
+ headers: { 'Content-Type': 'application/json' },
14
+ body: JSON.stringify({
15
+ feedbackId: args.id,
16
+ description: item.description,
17
+ problemType: item.problemType,
18
+ element: item.element?.selector,
19
+ }),
20
+ });
21
+ }
22
+ catch { }
23
+ return {
24
+ error: false,
25
+ text: `反馈 ${args.id} 已标记为待验证。已通知用户在浏览器中确认修复效果。`,
26
+ };
27
+ }
28
+ //# sourceMappingURL=resolve-feedback.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve-feedback.js","sourceRoot":"","sources":["../../../../src/mcp/tools/resolve-feedback.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,KAAoB,EACpB,IAAoB;IAEpB,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC;IACnB,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC1C,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,IAAI,CAAC,EAAE,OAAO,EAAE,CAAC;IACrD,CAAC;IAED,yDAAyD;IACzD,MAAM,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;IAE5C,uCAAuC;IACvC,IAAI,CAAC;QACH,MAAM,KAAK,CAAC,kCAAkC,EAAE;YAC9C,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,UAAU,EAAE,IAAI,CAAC,EAAE;gBACnB,WAAW,EAAE,IAAI,CAAC,WAAW;gBAC7B,WAAW,EAAE,IAAI,CAAC,WAAW;gBAC7B,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,QAAQ;aAChC,CAAC;SACH,CAAC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC,CAAA,CAAC;IAEV,OAAO;QACL,KAAK,EAAE,KAAK;QACZ,IAAI,EAAE,MAAM,IAAI,CAAC,EAAE,4BAA4B;KAChD,CAAC;AACJ,CAAC"}
@@ -0,0 +1,11 @@
1
+ import { FeedbackStore } from '../../storage/store.js';
2
+ export declare function startTestSession(store: FeedbackStore, args: {
3
+ port?: number;
4
+ open?: boolean;
5
+ }): Promise<{
6
+ proxyUrl: string;
7
+ targetUrl: string;
8
+ status: string;
9
+ message: string;
10
+ }>;
11
+ //# sourceMappingURL=start-session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"start-session.d.ts","sourceRoot":"","sources":["../../../../src/mcp/tools/start-session.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAEvD,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,aAAa,EACpB,IAAI,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,GACtC,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAuDnF"}
@@ -0,0 +1,56 @@
1
+ import open from 'open';
2
+ import { detectDevServer } from '../../detect/dev-server.js';
3
+ import { spawnDevServer } from '../../detect/spawn-dev.js';
4
+ import { startProxyServer, isProxyRunning } from '../../server/proxy-server.js';
5
+ export async function startTestSession(store, args) {
6
+ if (isProxyRunning()) {
7
+ return {
8
+ proxyUrl: 'http://localhost:3695',
9
+ targetUrl: '',
10
+ status: 'already_running',
11
+ message: '测试模式已在运行中。浏览器访问 http://localhost:3695 即可测试。',
12
+ };
13
+ }
14
+ const cwd = process.cwd();
15
+ const info = await detectDevServer(cwd, args.port);
16
+ let message = '';
17
+ if (info.isRunning) {
18
+ message = `检测到 ${info.framework} dev server 已在运行 → localhost:${info.port}`;
19
+ }
20
+ else if (info.command) {
21
+ message = `启动 ${info.framework} dev server...`;
22
+ const started = await spawnDevServer(cwd, info.command, info.port);
23
+ if (!started) {
24
+ return {
25
+ proxyUrl: '',
26
+ targetUrl: '',
27
+ status: 'error',
28
+ message: `Dev server 启动超时(端口 ${info.port})。请确认 dev server 能正常启动,或使用 port 参数手动指定端口。`,
29
+ };
30
+ }
31
+ message = `${info.framework} dev server 已启动 → localhost:${info.port}`;
32
+ }
33
+ else {
34
+ return {
35
+ proxyUrl: '',
36
+ targetUrl: '',
37
+ status: 'error',
38
+ message: '未找到 package.json 或 dev 脚本。请使用 port 参数指定 dev server 端口。',
39
+ };
40
+ }
41
+ // Initialize store
42
+ await store.init();
43
+ // Start proxy
44
+ const { proxyUrl, targetUrl } = await startProxyServer(info.port, store);
45
+ // Open browser
46
+ if (args.open !== false) {
47
+ await open(proxyUrl);
48
+ }
49
+ return {
50
+ proxyUrl,
51
+ targetUrl,
52
+ status: 'running',
53
+ message: `${message}\n代理已启动 → ${proxyUrl}\n测试模式已开启,用户可以在浏览器中提交反馈。`,
54
+ };
55
+ }
56
+ //# sourceMappingURL=start-session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"start-session.js","sourceRoot":"","sources":["../../../../src/mcp/tools/start-session.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAGhF,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,KAAoB,EACpB,IAAuC;IAEvC,IAAI,cAAc,EAAE,EAAE,CAAC;QACrB,OAAO;YACL,QAAQ,EAAE,uBAAuB;YACjC,SAAS,EAAE,EAAE;YACb,MAAM,EAAE,iBAAiB;YACzB,OAAO,EAAE,6CAA6C;SACvD,CAAC;IACJ,CAAC;IAED,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAC1B,MAAM,IAAI,GAAG,MAAM,eAAe,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IAEnD,IAAI,OAAO,GAAG,EAAE,CAAC;IAEjB,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;QACnB,OAAO,GAAG,OAAO,IAAI,CAAC,SAAS,gCAAgC,IAAI,CAAC,IAAI,EAAE,CAAC;IAC7E,CAAC;SAAM,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;QACxB,OAAO,GAAG,MAAM,IAAI,CAAC,SAAS,gBAAgB,CAAC;QAC/C,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,GAAG,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QACnE,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO;gBACL,QAAQ,EAAE,EAAE;gBACZ,SAAS,EAAE,EAAE;gBACb,MAAM,EAAE,OAAO;gBACf,OAAO,EAAE,sBAAsB,IAAI,CAAC,IAAI,2CAA2C;aACpF,CAAC;QACJ,CAAC;QACD,OAAO,GAAG,GAAG,IAAI,CAAC,SAAS,+BAA+B,IAAI,CAAC,IAAI,EAAE,CAAC;IACxE,CAAC;SAAM,CAAC;QACN,OAAO;YACL,QAAQ,EAAE,EAAE;YACZ,SAAS,EAAE,EAAE;YACb,MAAM,EAAE,OAAO;YACf,OAAO,EAAE,wDAAwD;SAClE,CAAC;IACJ,CAAC;IAED,mBAAmB;IACnB,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC;IAEnB,cAAc;IACd,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,MAAM,gBAAgB,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAEzE,eAAe;IACf,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;QACxB,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAC;IACvB,CAAC;IAED,OAAO;QACL,QAAQ;QACR,SAAS;QACT,MAAM,EAAE,SAAS;QACjB,OAAO,EAAE,GAAG,OAAO,aAAa,QAAQ,0BAA0B;KACnE,CAAC;AACJ,CAAC"}
@@ -0,0 +1,6 @@
1
+ import { FeedbackStore } from '../../storage/store.js';
2
+ export declare function stopTestSession(store: FeedbackStore): Promise<{
3
+ status: string;
4
+ message: string;
5
+ }>;
6
+ //# sourceMappingURL=stop-session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stop-session.d.ts","sourceRoot":"","sources":["../../../../src/mcp/tools/stop-session.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAEvD,wBAAsB,eAAe,CACnC,KAAK,EAAE,aAAa,GACnB,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAsF9C"}