@hanzo/browser-extension 1.7.6 → 1.9.33
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 +9 -18
- package/dist/browser-extension/content-script.js +1642 -123
- package/images/icon128.png +0 -0
- package/images/icon16.png +0 -0
- package/images/icon48.png +0 -0
- package/manifest.json +7 -2
- package/package.json +28 -10
- package/src/answer/AnswerEngine.tsx +553 -0
- package/src/chat-widget.tsx +96 -0
- package/src/gui-primitives.tsx +116 -0
- package/src/icon128.png +0 -0
- package/src/icon16.png +0 -0
- package/src/icon32.png +0 -0
- package/src/icon48.png +0 -0
- package/src/manifest-firefox.json +32 -13
- package/src/manifest.json +35 -11
- package/src/newtab.css +277 -0
- package/src/newtab.html +13 -0
- package/src/package.json +1 -1
- package/src/popup.css +352 -110
- package/src/popup.html +186 -47
- package/src/popup.js +196 -0
- package/src/sidebar.css +772 -156
- package/src/sidebar.html +268 -85
- package/src/sidebar.js +885 -0
- package/.github/workflows/docs.yml +0 -44
- package/.github/workflows/release.yml +0 -55
- package/README.md +0 -126
- package/dist/browser-extension/README.md +0 -43
- package/dist/browser-extension/ai-worker.js +0 -30
- package/dist/browser-extension/background-firefox.js +0 -875
- package/dist/browser-extension/background.js +0 -2732
- package/dist/browser-extension/browser-control.js +0 -683
- package/dist/browser-extension/cdp-bridge-server.js +0 -444
- package/dist/browser-extension/chrome/ai-worker.js +0 -571
- package/dist/browser-extension/chrome/background.js +0 -2732
- package/dist/browser-extension/chrome/callback.html +0 -17
- package/dist/browser-extension/chrome/content-script.js +0 -1270
- package/dist/browser-extension/chrome/icon128.png +0 -0
- package/dist/browser-extension/chrome/icon16.png +0 -0
- package/dist/browser-extension/chrome/icon32.png +0 -0
- package/dist/browser-extension/chrome/icon48.png +0 -0
- package/dist/browser-extension/chrome/manifest.json +0 -57
- package/dist/browser-extension/chrome/popup.css +0 -519
- package/dist/browser-extension/chrome/popup.html +0 -242
- package/dist/browser-extension/chrome/popup.js +0 -278
- package/dist/browser-extension/chrome/sidebar.css +0 -1176
- package/dist/browser-extension/chrome/sidebar.html +0 -280
- package/dist/browser-extension/chrome/sidebar.js +0 -779
- package/dist/browser-extension/cli.js +0 -233
- package/dist/browser-extension/firefox/ai-worker.js +0 -571
- package/dist/browser-extension/firefox/background.js +0 -875
- package/dist/browser-extension/firefox/callback.html +0 -17
- package/dist/browser-extension/firefox/content-script.js +0 -1270
- package/dist/browser-extension/firefox/icon128.png +0 -0
- package/dist/browser-extension/firefox/icon16.png +0 -0
- package/dist/browser-extension/firefox/icon32.png +0 -0
- package/dist/browser-extension/firefox/icon48.png +0 -0
- package/dist/browser-extension/firefox/manifest.json +0 -66
- package/dist/browser-extension/firefox/popup.css +0 -519
- package/dist/browser-extension/firefox/popup.html +0 -242
- package/dist/browser-extension/firefox/popup.js +0 -278
- package/dist/browser-extension/firefox/sidebar.css +0 -1176
- package/dist/browser-extension/firefox/sidebar.html +0 -280
- package/dist/browser-extension/firefox/sidebar.js +0 -779
- package/dist/browser-extension/hanzo-browser-extension-firefox-1.1.0.zip +0 -0
- package/dist/browser-extension/icon128.png +0 -0
- package/dist/browser-extension/icon16.png +0 -0
- package/dist/browser-extension/icon32.png +0 -0
- package/dist/browser-extension/icon48.png +0 -0
- package/dist/browser-extension/manifest.json +0 -57
- package/dist/browser-extension/package.json +0 -41
- package/dist/browser-extension/popup.css +0 -468
- package/dist/browser-extension/popup.html +0 -191
- package/dist/browser-extension/popup.js +0 -278
- package/dist/browser-extension/safari/Info.plist +0 -21
- package/dist/browser-extension/safari/ai-worker.js +0 -571
- package/dist/browser-extension/safari/background.js +0 -2732
- package/dist/browser-extension/safari/callback.html +0 -17
- package/dist/browser-extension/safari/content-script.js +0 -1270
- package/dist/browser-extension/safari/icon128.png +0 -0
- package/dist/browser-extension/safari/icon16.png +0 -0
- package/dist/browser-extension/safari/icon32.png +0 -0
- package/dist/browser-extension/safari/icon48.png +0 -0
- package/dist/browser-extension/safari/popup.css +0 -519
- package/dist/browser-extension/safari/popup.html +0 -242
- package/dist/browser-extension/safari/popup.js +0 -278
- package/dist/browser-extension/safari/sidebar.css +0 -1176
- package/dist/browser-extension/safari/sidebar.html +0 -280
- package/dist/browser-extension/safari/sidebar.js +0 -779
- package/dist/browser-extension/sidebar.css +0 -718
- package/dist/browser-extension/sidebar.html +0 -184
- package/dist/browser-extension/sidebar.js +0 -779
- package/dist/browser-extension/webgpu-ai.js +0 -495
- package/dist/cdp-bridge-server.js +0 -411
- package/dist/hanzo-ai-chrome-1.7.2.zip +0 -0
- package/dist/hanzo-ai-chrome-1.7.3.zip +0 -0
- package/dist/hanzo-ai-firefox-1.7.2.zip +0 -0
- package/dist/hanzo-ai-firefox-1.7.3.zip +0 -0
- package/dist/safari/Hanzo AI/Hanzo AI.xcodeproj/project.pbxproj +0 -1047
- package/dist/safari/Hanzo AI/Hanzo AI.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -7
- package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AccentColor.colorset/Contents.json +0 -11
- package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/Contents.json +0 -98
- package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-128@1x.png +0 -0
- package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-128@2x.png +0 -0
- package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-16@1x.png +0 -0
- package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-16@2x.png +0 -0
- package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-256@1x.png +0 -0
- package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-256@2x.png +0 -0
- package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-32@1x.png +0 -0
- package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-32@2x.png +0 -0
- package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-512@1x.png +0 -0
- package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-512@2x.png +0 -0
- package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/universal-icon-1024@1x.png +0 -0
- package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/Contents.json +0 -6
- package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/LargeIcon.imageset/Contents.json +0 -21
- package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/LargeIcon.imageset/icon128.png +0 -0
- package/dist/safari/Hanzo AI/Shared (App)/Resources/Base.lproj/Main.html +0 -20
- package/dist/safari/Hanzo AI/Shared (App)/Resources/Icon.png +0 -0
- package/dist/safari/Hanzo AI/Shared (App)/Resources/Script.js +0 -24
- package/dist/safari/Hanzo AI/Shared (App)/Resources/Style.css +0 -61
- package/dist/safari/Hanzo AI/Shared (App)/ViewController.swift +0 -81
- package/dist/safari/Hanzo AI/Shared (Extension)/SafariWebExtensionHandler.swift +0 -42
- package/dist/safari/Hanzo AI/iOS (App)/AppDelegate.swift +0 -24
- package/dist/safari/Hanzo AI/iOS (App)/Base.lproj/LaunchScreen.storyboard +0 -36
- package/dist/safari/Hanzo AI/iOS (App)/Base.lproj/Main.storyboard +0 -38
- package/dist/safari/Hanzo AI/iOS (App)/Info.plist +0 -27
- package/dist/safari/Hanzo AI/iOS (App)/SceneDelegate.swift +0 -18
- package/dist/safari/Hanzo AI/iOS (Extension)/Info.plist +0 -13
- package/dist/safari/Hanzo AI/macOS (App)/AppDelegate.swift +0 -21
- package/dist/safari/Hanzo AI/macOS (App)/Base.lproj/Main.storyboard +0 -124
- package/dist/safari/Hanzo AI/macOS (App)/Info.plist +0 -8
- package/dist/safari/Hanzo AI/macOS (Extension)/Info.plist +0 -13
- package/docs/_config.yml +0 -13
- package/docs/_layouts/default.html +0 -435
- package/docs/index.md +0 -54
- package/hanzo-ai-chrome-v1.7.6.zip +0 -0
- package/hanzo-ai-firefox-v1.7.6.zip +0 -0
- package/install-extension.sh +0 -75
- package/test/claude-integration.test.ts +0 -251
- package/test/server-frameworks-edge-cases.test.ts +0 -145
- package/test/server-frameworks.test.ts +0 -395
- package/test-cdp-connection.js +0 -140
- package/tsconfig.json +0 -19
|
@@ -1,395 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
|
-
import { ServerFrameworkDetector } from '../src/server-frameworks';
|
|
3
|
-
import { JSDOM } from 'jsdom';
|
|
4
|
-
|
|
5
|
-
describe('Server Framework Detection', () => {
|
|
6
|
-
let detector: ServerFrameworkDetector;
|
|
7
|
-
let dom: JSDOM;
|
|
8
|
-
let document: Document;
|
|
9
|
-
|
|
10
|
-
beforeEach(() => {
|
|
11
|
-
detector = new ServerFrameworkDetector();
|
|
12
|
-
dom = new JSDOM('<!DOCTYPE html><html><body></body></html>');
|
|
13
|
-
document = dom.window.document;
|
|
14
|
-
// @ts-ignore
|
|
15
|
-
global.document = document;
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
describe('Rails detection', () => {
|
|
19
|
-
it('should detect Rails via CSRF token', () => {
|
|
20
|
-
document.head.innerHTML = '<meta name="csrf-token" content="abc123">';
|
|
21
|
-
const element = document.createElement('div');
|
|
22
|
-
element.setAttribute('data-controller', 'posts');
|
|
23
|
-
element.setAttribute('data-action', 'show');
|
|
24
|
-
|
|
25
|
-
const result = detector.detectRails(element);
|
|
26
|
-
|
|
27
|
-
expect(result).toMatchObject({
|
|
28
|
-
framework: 'rails',
|
|
29
|
-
controller: 'posts',
|
|
30
|
-
action: 'show'
|
|
31
|
-
});
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
it('should detect Rails ViewComponent', () => {
|
|
35
|
-
document.head.innerHTML = '<meta name="csrf-token" content="abc123">';
|
|
36
|
-
const element = document.createElement('div');
|
|
37
|
-
element.setAttribute('data-view-component', 'ButtonComponent');
|
|
38
|
-
element.setAttribute('data-view-component-path', 'app/components/button_component.rb');
|
|
39
|
-
|
|
40
|
-
const result = detector.detectRails(element);
|
|
41
|
-
|
|
42
|
-
expect(result).toMatchObject({
|
|
43
|
-
framework: 'rails-viewcomponent',
|
|
44
|
-
file: 'app/components/button_component.rb',
|
|
45
|
-
controller: 'ButtonComponent'
|
|
46
|
-
});
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
it('should extract Rails template from comments', () => {
|
|
50
|
-
document.head.innerHTML = '<meta name="csrf-token" content="abc123">';
|
|
51
|
-
const element = document.createElement('div');
|
|
52
|
-
element.innerHTML = '<!-- BEGIN app/views/posts/show.html.erb --><p>Content</p>';
|
|
53
|
-
|
|
54
|
-
const result = detector.detectRails(element);
|
|
55
|
-
|
|
56
|
-
expect(result).toMatchObject({
|
|
57
|
-
framework: 'rails',
|
|
58
|
-
template: 'app/views/posts/show.html.erb',
|
|
59
|
-
controller: 'PostsController',
|
|
60
|
-
action: 'show'
|
|
61
|
-
});
|
|
62
|
-
});
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
describe('Django detection', () => {
|
|
66
|
-
it('should detect Django Debug Toolbar', () => {
|
|
67
|
-
const debugEl = document.createElement('div');
|
|
68
|
-
debugEl.id = 'djDebug';
|
|
69
|
-
document.body.appendChild(debugEl);
|
|
70
|
-
|
|
71
|
-
const element = document.createElement('div');
|
|
72
|
-
|
|
73
|
-
const result = detector.detectDjango(element);
|
|
74
|
-
|
|
75
|
-
expect(result).toMatchObject({
|
|
76
|
-
framework: 'django'
|
|
77
|
-
});
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
it('should detect Django templates from comments', () => {
|
|
81
|
-
const element = document.createElement('div');
|
|
82
|
-
element.innerHTML = '<!-- TEMPLATE_DEBUG: templates/blog/post_detail.html --><p>Content</p>';
|
|
83
|
-
|
|
84
|
-
const result = detector.detectDjango(element);
|
|
85
|
-
|
|
86
|
-
expect(result).toMatchObject({
|
|
87
|
-
framework: 'django',
|
|
88
|
-
template: 'blog/post_detail.html'
|
|
89
|
-
});
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
it('should detect Django CMS plugins', () => {
|
|
93
|
-
const element = document.createElement('div');
|
|
94
|
-
element.setAttribute('data-cms-plugin', 'TextPlugin');
|
|
95
|
-
|
|
96
|
-
const result = detector.detectDjango(element);
|
|
97
|
-
|
|
98
|
-
expect(result).toMatchObject({
|
|
99
|
-
framework: 'django',
|
|
100
|
-
controller: 'TextPlugin'
|
|
101
|
-
});
|
|
102
|
-
});
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
describe('Flask detection', () => {
|
|
106
|
-
it('should detect Flask debug mode', () => {
|
|
107
|
-
const debugEl = document.createElement('div');
|
|
108
|
-
debugEl.className = 'flask-debugger';
|
|
109
|
-
document.body.appendChild(debugEl);
|
|
110
|
-
|
|
111
|
-
const element = document.createElement('div');
|
|
112
|
-
|
|
113
|
-
const result = detector.detectFlask(element);
|
|
114
|
-
|
|
115
|
-
expect(result).toMatchObject({
|
|
116
|
-
framework: 'flask'
|
|
117
|
-
});
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
it('should detect Werkzeug debugger', () => {
|
|
121
|
-
const debugEl = document.createElement('div');
|
|
122
|
-
debugEl.id = 'werkzeug-debugger';
|
|
123
|
-
document.body.appendChild(debugEl);
|
|
124
|
-
|
|
125
|
-
const element = document.createElement('div');
|
|
126
|
-
|
|
127
|
-
const result = detector.detectFlask(element);
|
|
128
|
-
|
|
129
|
-
expect(result).toMatchObject({
|
|
130
|
-
framework: 'flask'
|
|
131
|
-
});
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
it('should detect Jinja2 templates', () => {
|
|
135
|
-
const element = document.createElement('div');
|
|
136
|
-
element.innerHTML = '<!-- Template: templates/user/profile.html --><p>{{ user.name }}</p>';
|
|
137
|
-
|
|
138
|
-
const result = detector.detectFlask(element);
|
|
139
|
-
|
|
140
|
-
expect(result).toMatchObject({
|
|
141
|
-
framework: 'flask',
|
|
142
|
-
template: 'templates/user/profile.html'
|
|
143
|
-
});
|
|
144
|
-
});
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
describe('Laravel detection', () => {
|
|
148
|
-
it('should detect Laravel via CSRF and Blade templates', () => {
|
|
149
|
-
document.head.innerHTML = '<meta name="csrf-token" content="laravel-token">';
|
|
150
|
-
const element = document.createElement('div');
|
|
151
|
-
element.innerHTML = '<!-- resources/views/posts/index.blade.php --><p>Content</p>';
|
|
152
|
-
|
|
153
|
-
const result = detector.detectLaravel(element);
|
|
154
|
-
|
|
155
|
-
expect(result).toMatchObject({
|
|
156
|
-
framework: 'laravel',
|
|
157
|
-
template: 'posts/index.blade.php'
|
|
158
|
-
});
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
it('should detect PHP Debugbar', () => {
|
|
162
|
-
const debugbar = document.createElement('div');
|
|
163
|
-
debugbar.className = 'phpdebugbar';
|
|
164
|
-
document.body.appendChild(debugbar);
|
|
165
|
-
|
|
166
|
-
const element = document.createElement('div');
|
|
167
|
-
|
|
168
|
-
const result = detector.detectLaravel(element);
|
|
169
|
-
|
|
170
|
-
expect(result).toMatchObject({
|
|
171
|
-
framework: 'laravel'
|
|
172
|
-
});
|
|
173
|
-
});
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
describe('Phoenix/LiveView detection', () => {
|
|
177
|
-
it('should detect Phoenix LiveView', () => {
|
|
178
|
-
const main = document.createElement('div');
|
|
179
|
-
main.setAttribute('data-phx-main', 'true');
|
|
180
|
-
document.body.appendChild(main);
|
|
181
|
-
|
|
182
|
-
const element = document.createElement('div');
|
|
183
|
-
element.setAttribute('data-phx-session', 'session-id');
|
|
184
|
-
element.setAttribute('data-phx-view', 'UserLive.Index');
|
|
185
|
-
|
|
186
|
-
const result = detector.detectPhoenix(element);
|
|
187
|
-
|
|
188
|
-
expect(result).toMatchObject({
|
|
189
|
-
framework: 'phoenix',
|
|
190
|
-
controller: 'UserLive.Index'
|
|
191
|
-
});
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
it('should detect Phoenix components', () => {
|
|
195
|
-
const element = document.createElement('div');
|
|
196
|
-
element.setAttribute('data-phx-component', 'MyAppWeb.ButtonComponent');
|
|
197
|
-
element.setAttribute('data-phx-static', 'static-id');
|
|
198
|
-
|
|
199
|
-
const result = detector.detectPhoenix(element);
|
|
200
|
-
|
|
201
|
-
expect(result).toMatchObject({
|
|
202
|
-
framework: 'phoenix',
|
|
203
|
-
controller: 'MyAppWeb.ButtonComponent'
|
|
204
|
-
});
|
|
205
|
-
});
|
|
206
|
-
});
|
|
207
|
-
|
|
208
|
-
describe('ASP.NET detection', () => {
|
|
209
|
-
it('should detect ASP.NET tag helpers', () => {
|
|
210
|
-
const element = document.createElement('a');
|
|
211
|
-
element.setAttribute('asp-controller', 'Home');
|
|
212
|
-
element.setAttribute('asp-action', 'Index');
|
|
213
|
-
|
|
214
|
-
const result = detector.detectASPNET(element);
|
|
215
|
-
|
|
216
|
-
expect(result).toMatchObject({
|
|
217
|
-
framework: 'aspnet',
|
|
218
|
-
controller: 'Home',
|
|
219
|
-
action: 'Index'
|
|
220
|
-
});
|
|
221
|
-
});
|
|
222
|
-
|
|
223
|
-
it('should detect Blazor components', () => {
|
|
224
|
-
const element = document.createElement('div');
|
|
225
|
-
element.setAttribute('b-component', 'Counter');
|
|
226
|
-
|
|
227
|
-
const result = detector.detectASPNET(element);
|
|
228
|
-
|
|
229
|
-
expect(result).toMatchObject({
|
|
230
|
-
framework: 'blazor',
|
|
231
|
-
controller: 'Counter'
|
|
232
|
-
});
|
|
233
|
-
});
|
|
234
|
-
|
|
235
|
-
it('should detect Razor pages', () => {
|
|
236
|
-
const element = document.createElement('form');
|
|
237
|
-
element.setAttribute('asp-page', '/Users/Edit');
|
|
238
|
-
|
|
239
|
-
const result = detector.detectASPNET(element);
|
|
240
|
-
|
|
241
|
-
expect(result).toMatchObject({
|
|
242
|
-
framework: 'aspnet',
|
|
243
|
-
template: '/Users/Edit'
|
|
244
|
-
});
|
|
245
|
-
});
|
|
246
|
-
});
|
|
247
|
-
|
|
248
|
-
describe('Express.js detection', () => {
|
|
249
|
-
it('should detect Pug templates', () => {
|
|
250
|
-
const element = document.createElement('div');
|
|
251
|
-
element.innerHTML = '<!-- views/layout.pug --><p>Content</p>';
|
|
252
|
-
|
|
253
|
-
const result = detector.detectExpress(element);
|
|
254
|
-
|
|
255
|
-
expect(result).toMatchObject({
|
|
256
|
-
framework: 'express',
|
|
257
|
-
template: 'layout.pug'
|
|
258
|
-
});
|
|
259
|
-
});
|
|
260
|
-
|
|
261
|
-
it('should detect EJS templates', () => {
|
|
262
|
-
const element = document.createElement('div');
|
|
263
|
-
element.innerHTML = '<!-- views/users/profile.ejs --><p><%= user.name %></p>';
|
|
264
|
-
|
|
265
|
-
const result = detector.detectExpress(element);
|
|
266
|
-
|
|
267
|
-
expect(result).toMatchObject({
|
|
268
|
-
framework: 'express',
|
|
269
|
-
template: 'users/profile.ejs'
|
|
270
|
-
});
|
|
271
|
-
});
|
|
272
|
-
|
|
273
|
-
it('should detect Handlebars templates', () => {
|
|
274
|
-
const element = document.createElement('div');
|
|
275
|
-
element.innerHTML = '<!-- views/partials/header.hbs --><p>{{title}}</p>';
|
|
276
|
-
|
|
277
|
-
const result = detector.detectExpress(element);
|
|
278
|
-
|
|
279
|
-
expect(result).toMatchObject({
|
|
280
|
-
framework: 'express',
|
|
281
|
-
template: 'partials/header.hbs'
|
|
282
|
-
});
|
|
283
|
-
});
|
|
284
|
-
});
|
|
285
|
-
|
|
286
|
-
describe('WordPress detection', () => {
|
|
287
|
-
it('should detect WordPress via generator meta tag', () => {
|
|
288
|
-
document.head.innerHTML = '<meta name="generator" content="WordPress 6.0">';
|
|
289
|
-
const element = document.createElement('div');
|
|
290
|
-
|
|
291
|
-
const result = detector.detectWordPress(element);
|
|
292
|
-
|
|
293
|
-
expect(result).toMatchObject({
|
|
294
|
-
framework: 'wordpress'
|
|
295
|
-
});
|
|
296
|
-
});
|
|
297
|
-
|
|
298
|
-
it('should detect WordPress admin bar', () => {
|
|
299
|
-
const adminBar = document.createElement('div');
|
|
300
|
-
adminBar.id = 'wpadminbar';
|
|
301
|
-
document.body.appendChild(adminBar);
|
|
302
|
-
|
|
303
|
-
const element = document.createElement('div');
|
|
304
|
-
|
|
305
|
-
const result = detector.detectWordPress(element);
|
|
306
|
-
|
|
307
|
-
expect(result).toMatchObject({
|
|
308
|
-
framework: 'wordpress'
|
|
309
|
-
});
|
|
310
|
-
});
|
|
311
|
-
|
|
312
|
-
it('should extract WordPress template info', () => {
|
|
313
|
-
document.head.innerHTML = '<meta name="generator" content="WordPress">';
|
|
314
|
-
const element = document.createElement('div');
|
|
315
|
-
element.innerHTML = '<!-- Template: single-post.php --><article>Content</article>';
|
|
316
|
-
|
|
317
|
-
const result = detector.detectWordPress(element);
|
|
318
|
-
|
|
319
|
-
expect(result).toMatchObject({
|
|
320
|
-
framework: 'wordpress',
|
|
321
|
-
template: 'single-post.php'
|
|
322
|
-
});
|
|
323
|
-
});
|
|
324
|
-
});
|
|
325
|
-
|
|
326
|
-
describe('Main detect method', () => {
|
|
327
|
-
it('should try all detectors and return first match', () => {
|
|
328
|
-
// Setup Rails
|
|
329
|
-
document.head.innerHTML = '<meta name="csrf-token" content="abc123">';
|
|
330
|
-
const element = document.createElement('div');
|
|
331
|
-
element.setAttribute('data-controller', 'posts');
|
|
332
|
-
|
|
333
|
-
const result = detector.detect(element);
|
|
334
|
-
|
|
335
|
-
expect(result).toMatchObject({
|
|
336
|
-
framework: 'rails',
|
|
337
|
-
controller: 'posts'
|
|
338
|
-
});
|
|
339
|
-
});
|
|
340
|
-
|
|
341
|
-
it('should return null if no framework detected', () => {
|
|
342
|
-
const element = document.createElement('div');
|
|
343
|
-
|
|
344
|
-
const result = detector.detect(element);
|
|
345
|
-
|
|
346
|
-
expect(result).toBeNull();
|
|
347
|
-
});
|
|
348
|
-
|
|
349
|
-
it('should handle multiple frameworks (first wins)', () => {
|
|
350
|
-
// Setup both Rails and Django markers
|
|
351
|
-
document.head.innerHTML = '<meta name="csrf-token" content="abc123">';
|
|
352
|
-
const djangoDebug = document.createElement('div');
|
|
353
|
-
djangoDebug.id = 'djDebug';
|
|
354
|
-
document.body.appendChild(djangoDebug);
|
|
355
|
-
|
|
356
|
-
const element = document.createElement('div');
|
|
357
|
-
element.setAttribute('data-controller', 'posts');
|
|
358
|
-
|
|
359
|
-
const result = detector.detect(element);
|
|
360
|
-
|
|
361
|
-
// Rails is checked first, so it should win
|
|
362
|
-
expect(result?.framework).toBe('rails');
|
|
363
|
-
});
|
|
364
|
-
});
|
|
365
|
-
|
|
366
|
-
describe('Helper methods', () => {
|
|
367
|
-
it('should extract HTML comments from element tree', () => {
|
|
368
|
-
const element = document.createElement('div');
|
|
369
|
-
element.innerHTML = `
|
|
370
|
-
<!-- First comment -->
|
|
371
|
-
<p>Content</p>
|
|
372
|
-
<!-- Second comment -->
|
|
373
|
-
<div>
|
|
374
|
-
<!-- Nested comment -->
|
|
375
|
-
</div>
|
|
376
|
-
`;
|
|
377
|
-
|
|
378
|
-
const comments = detector['extractHTMLComments'](element);
|
|
379
|
-
|
|
380
|
-
expect(comments).toContain('First comment');
|
|
381
|
-
expect(comments).toContain('Second comment');
|
|
382
|
-
expect(comments).toContain('Nested comment');
|
|
383
|
-
});
|
|
384
|
-
|
|
385
|
-
it('should extract Rails controller name from template path', () => {
|
|
386
|
-
const controller = detector['extractRailsController']('app/views/admin/users/index.html.erb');
|
|
387
|
-
expect(controller).toBe('AdminUsersController');
|
|
388
|
-
});
|
|
389
|
-
|
|
390
|
-
it('should extract Rails action name from template path', () => {
|
|
391
|
-
const action = detector['extractRailsAction']('app/views/posts/show.html.erb');
|
|
392
|
-
expect(action).toBe('show');
|
|
393
|
-
});
|
|
394
|
-
});
|
|
395
|
-
});
|
package/test-cdp-connection.js
DELETED
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* Test CDP Bridge Connection
|
|
4
|
-
* Verifies the browser extension is connected and can receive commands
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
const WebSocket = require('ws');
|
|
8
|
-
|
|
9
|
-
const CDP_PORT = process.env.CDP_PORT || 9223;
|
|
10
|
-
const CDP_URL = `ws://localhost:${CDP_PORT}/cdp`;
|
|
11
|
-
|
|
12
|
-
console.log(`[Test] Connecting to CDP Bridge at ${CDP_URL}...`);
|
|
13
|
-
|
|
14
|
-
const ws = new WebSocket(CDP_URL);
|
|
15
|
-
let commandId = 0;
|
|
16
|
-
const pending = new Map();
|
|
17
|
-
|
|
18
|
-
ws.on('open', () => {
|
|
19
|
-
console.log('[Test] Connected to CDP Bridge');
|
|
20
|
-
console.log('[Test] Registering as client...');
|
|
21
|
-
|
|
22
|
-
ws.send(JSON.stringify({
|
|
23
|
-
type: 'register',
|
|
24
|
-
role: 'mcp-client',
|
|
25
|
-
capabilities: ['control', 'screenshot', 'evaluate']
|
|
26
|
-
}));
|
|
27
|
-
|
|
28
|
-
// Wait a bit for extension to be ready
|
|
29
|
-
setTimeout(runTests, 1000);
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
ws.on('message', (data) => {
|
|
33
|
-
try {
|
|
34
|
-
const msg = JSON.parse(data.toString());
|
|
35
|
-
|
|
36
|
-
if (msg.id !== undefined && pending.has(msg.id)) {
|
|
37
|
-
const { resolve, reject, name } = pending.get(msg.id);
|
|
38
|
-
pending.delete(msg.id);
|
|
39
|
-
|
|
40
|
-
if (msg.error) {
|
|
41
|
-
console.log(`[Test] ${name}: FAILED - ${msg.error.message}`);
|
|
42
|
-
reject(new Error(msg.error.message));
|
|
43
|
-
} else {
|
|
44
|
-
console.log(`[Test] ${name}: OK`);
|
|
45
|
-
resolve(msg.result);
|
|
46
|
-
}
|
|
47
|
-
} else if (msg.type === 'event') {
|
|
48
|
-
console.log(`[Test] Event: ${msg.method}`);
|
|
49
|
-
}
|
|
50
|
-
} catch (e) {
|
|
51
|
-
console.error('[Test] Error parsing message:', e);
|
|
52
|
-
}
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
ws.on('error', (err) => {
|
|
56
|
-
console.error('[Test] Connection error:', err.message);
|
|
57
|
-
console.log('[Test] Make sure:');
|
|
58
|
-
console.log(' 1. CDP bridge server is running (node dist/cdp-bridge-server.js)');
|
|
59
|
-
console.log(' 2. Browser extension is loaded and connected');
|
|
60
|
-
process.exit(1);
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
ws.on('close', () => {
|
|
64
|
-
console.log('[Test] Connection closed');
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
function sendCommand(method, params = {}) {
|
|
68
|
-
return new Promise((resolve, reject) => {
|
|
69
|
-
const id = ++commandId;
|
|
70
|
-
pending.set(id, { resolve, reject, name: method });
|
|
71
|
-
ws.send(JSON.stringify({ id, method, params }));
|
|
72
|
-
|
|
73
|
-
// Timeout
|
|
74
|
-
setTimeout(() => {
|
|
75
|
-
if (pending.has(id)) {
|
|
76
|
-
pending.delete(id);
|
|
77
|
-
reject(new Error('Timeout'));
|
|
78
|
-
}
|
|
79
|
-
}, 10000);
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
async function runTests() {
|
|
84
|
-
console.log('\n[Test] Running browser control tests...\n');
|
|
85
|
-
|
|
86
|
-
try {
|
|
87
|
-
// Test 1: Get browser version
|
|
88
|
-
console.log('[Test] 1. Getting browser version...');
|
|
89
|
-
const version = await sendCommand('Browser.getVersion');
|
|
90
|
-
console.log(` Version: ${JSON.stringify(version)}`);
|
|
91
|
-
|
|
92
|
-
// Test 2: Get targets (tabs)
|
|
93
|
-
console.log('\n[Test] 2. Getting browser tabs...');
|
|
94
|
-
const targets = await sendCommand('Target.getTargets');
|
|
95
|
-
console.log(` Found ${targets.targetInfos?.length || 0} tabs`);
|
|
96
|
-
if (targets.targetInfos) {
|
|
97
|
-
targets.targetInfos.forEach((t, i) => {
|
|
98
|
-
console.log(` [${i}] ${t.title || 'Untitled'} - ${t.url}`);
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// Test 3: Take screenshot
|
|
103
|
-
console.log('\n[Test] 3. Taking screenshot...');
|
|
104
|
-
const screenshot = await sendCommand('hanzo.screenshot', { format: 'png' });
|
|
105
|
-
if (screenshot.data) {
|
|
106
|
-
console.log(` Screenshot captured: ${screenshot.data.length} bytes (base64)`);
|
|
107
|
-
} else {
|
|
108
|
-
console.log(' No screenshot data returned');
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// Test 4: Evaluate JavaScript
|
|
112
|
-
console.log('\n[Test] 4. Evaluating JavaScript...');
|
|
113
|
-
const evalResult = await sendCommand('Runtime.evaluate', {
|
|
114
|
-
expression: 'document.title',
|
|
115
|
-
returnByValue: true
|
|
116
|
-
});
|
|
117
|
-
console.log(` Page title: ${evalResult?.result?.value || 'N/A'}`);
|
|
118
|
-
|
|
119
|
-
// Test 5: Get page URL
|
|
120
|
-
console.log('\n[Test] 5. Getting page URL...');
|
|
121
|
-
const urlResult = await sendCommand('Runtime.evaluate', {
|
|
122
|
-
expression: 'window.location.href',
|
|
123
|
-
returnByValue: true
|
|
124
|
-
});
|
|
125
|
-
console.log(` URL: ${urlResult?.result?.value || 'N/A'}`);
|
|
126
|
-
|
|
127
|
-
console.log('\n[Test] All tests completed successfully!');
|
|
128
|
-
console.log('[Test] The browser extension is working correctly.\n');
|
|
129
|
-
|
|
130
|
-
} catch (err) {
|
|
131
|
-
console.error(`\n[Test] Test failed: ${err.message}`);
|
|
132
|
-
console.log('\n[Test] Troubleshooting:');
|
|
133
|
-
console.log(' 1. Is the browser extension loaded?');
|
|
134
|
-
console.log(' 2. Is there an active tab in the browser?');
|
|
135
|
-
console.log(' 3. Check browser console for extension errors');
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
ws.close();
|
|
139
|
-
process.exit(0);
|
|
140
|
-
}
|
package/tsconfig.json
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"module": "esnext",
|
|
4
|
-
"moduleResolution": "node",
|
|
5
|
-
"target": "ES2020",
|
|
6
|
-
"outDir": "dist",
|
|
7
|
-
"rootDir": "src",
|
|
8
|
-
"sourceMap": true,
|
|
9
|
-
"strict": true,
|
|
10
|
-
"noImplicitAny": true,
|
|
11
|
-
"esModuleInterop": true,
|
|
12
|
-
"resolveJsonModule": true,
|
|
13
|
-
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
|
14
|
-
"skipLibCheck": true,
|
|
15
|
-
"types": ["chrome", "firefox-webext-browser"]
|
|
16
|
-
},
|
|
17
|
-
"include": ["src"],
|
|
18
|
-
"exclude": ["node_modules", "dist"]
|
|
19
|
-
}
|