@poolzin/pool-bot 2026.3.11 → 2026.3.14

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 (195) hide show
  1. package/CHANGELOG.md +121 -0
  2. package/dist/.buildstamp +1 -1
  3. package/dist/agents/checkpoint-manager.js +291 -0
  4. package/dist/agents/poolbot-tools.js +5 -0
  5. package/dist/agents/subagent-announce-reliability.js +160 -0
  6. package/dist/agents/tool-result-truncation.js +299 -0
  7. package/dist/agents/tools/nodes-file-tool.js +197 -0
  8. package/dist/build-info.json +3 -3
  9. package/dist/cli/config-cli.js +60 -0
  10. package/dist/cron/cron-improvements.js +195 -0
  11. package/dist/discord/discord-improvements.js +167 -0
  12. package/dist/gateway/auth-rate-limit.js +19 -0
  13. package/dist/gateway/auth.js +41 -0
  14. package/dist/gateway/gateway-improvements.js +294 -0
  15. package/dist/gateway/node-command-policy.js +7 -2
  16. package/dist/infra/net/ssrf.js +15 -2
  17. package/dist/infra/shell-security.js +201 -0
  18. package/dist/memory/memory-improvements.js +239 -0
  19. package/dist/node-host/runner.js +146 -79
  20. package/dist/security/prototype-pollution.js +141 -0
  21. package/dist/security/webhook-security.js +253 -0
  22. package/dist/shared/net/ip.js +52 -1
  23. package/dist/slack/slack-improvements.js +225 -0
  24. package/dist/telegram/telegram-improvements.js +220 -0
  25. package/dist/ui-plugins/ui-plugins-improvements.js +191 -0
  26. package/docs/ANALISE_OPENCLAW_PROFISSIONAL.md +520 -0
  27. package/docs/competitive-analysis.md +421 -0
  28. package/docs/implementation-analysis.md +393 -0
  29. package/docs/plans/2026-03-11-file-operations-security-hardening.md +307 -0
  30. package/docs/plans/2026-03-11-integracao-projetos-poolbot.md +666 -0
  31. package/docs/refactor/plugin-development-guide.md +281 -0
  32. package/extensions/agency-agents/README.md +301 -0
  33. package/extensions/agency-agents/agents/CONTRIBUTING.md +353 -0
  34. package/extensions/agency-agents/agents/README.md +602 -0
  35. package/extensions/agency-agents/agents/design/design-brand-guardian.md +320 -0
  36. package/extensions/agency-agents/agents/design/design-image-prompt-engineer.md +234 -0
  37. package/extensions/agency-agents/agents/design/design-ui-designer.md +381 -0
  38. package/extensions/agency-agents/agents/design/design-ux-architect.md +467 -0
  39. package/extensions/agency-agents/agents/design/design-ux-researcher.md +327 -0
  40. package/extensions/agency-agents/agents/design/design-visual-storyteller.md +147 -0
  41. package/extensions/agency-agents/agents/design/design-whimsy-injector.md +436 -0
  42. package/extensions/agency-agents/agents/engineering/engineering-ai-engineer.md +144 -0
  43. package/extensions/agency-agents/agents/engineering/engineering-backend-architect.md +233 -0
  44. package/extensions/agency-agents/agents/engineering/engineering-devops-automator.md +374 -0
  45. package/extensions/agency-agents/agents/engineering/engineering-frontend-developer.md +223 -0
  46. package/extensions/agency-agents/agents/engineering/engineering-mobile-app-builder.md +491 -0
  47. package/extensions/agency-agents/agents/engineering/engineering-rapid-prototyper.md +460 -0
  48. package/extensions/agency-agents/agents/engineering/engineering-security-engineer.md +275 -0
  49. package/extensions/agency-agents/agents/engineering/engineering-senior-developer.md +174 -0
  50. package/extensions/agency-agents/agents/examples/README.md +48 -0
  51. package/extensions/agency-agents/agents/examples/nexus-spatial-discovery.md +852 -0
  52. package/extensions/agency-agents/agents/examples/workflow-landing-page.md +119 -0
  53. package/extensions/agency-agents/agents/examples/workflow-startup-mvp.md +155 -0
  54. package/extensions/agency-agents/agents/integrations/README.md +117 -0
  55. package/extensions/agency-agents/agents/integrations/aider/README.md +38 -0
  56. package/extensions/agency-agents/agents/integrations/antigravity/README.md +49 -0
  57. package/extensions/agency-agents/agents/integrations/claude-code/README.md +31 -0
  58. package/extensions/agency-agents/agents/integrations/cursor/README.md +38 -0
  59. package/extensions/agency-agents/agents/integrations/gemini-cli/README.md +36 -0
  60. package/extensions/agency-agents/agents/integrations/opencode/README.md +58 -0
  61. package/extensions/agency-agents/agents/integrations/windsurf/README.md +26 -0
  62. package/extensions/agency-agents/agents/marketing/marketing-app-store-optimizer.md +319 -0
  63. package/extensions/agency-agents/agents/marketing/marketing-content-creator.md +52 -0
  64. package/extensions/agency-agents/agents/marketing/marketing-growth-hacker.md +52 -0
  65. package/extensions/agency-agents/agents/marketing/marketing-instagram-curator.md +111 -0
  66. package/extensions/agency-agents/agents/marketing/marketing-reddit-community-builder.md +121 -0
  67. package/extensions/agency-agents/agents/marketing/marketing-social-media-strategist.md +123 -0
  68. package/extensions/agency-agents/agents/marketing/marketing-tiktok-strategist.md +123 -0
  69. package/extensions/agency-agents/agents/marketing/marketing-twitter-engager.md +124 -0
  70. package/extensions/agency-agents/agents/marketing/marketing-wechat-official-account.md +143 -0
  71. package/extensions/agency-agents/agents/marketing/marketing-xiaohongshu-specialist.md +136 -0
  72. package/extensions/agency-agents/agents/marketing/marketing-zhihu-strategist.md +160 -0
  73. package/extensions/agency-agents/agents/product/product-feedback-synthesizer.md +117 -0
  74. package/extensions/agency-agents/agents/product/product-sprint-prioritizer.md +152 -0
  75. package/extensions/agency-agents/agents/product/product-trend-researcher.md +157 -0
  76. package/extensions/agency-agents/agents/project-management/project-management-experiment-tracker.md +196 -0
  77. package/extensions/agency-agents/agents/project-management/project-management-project-shepherd.md +192 -0
  78. package/extensions/agency-agents/agents/project-management/project-management-studio-operations.md +198 -0
  79. package/extensions/agency-agents/agents/project-management/project-management-studio-producer.md +201 -0
  80. package/extensions/agency-agents/agents/project-management/project-manager-senior.md +133 -0
  81. package/extensions/agency-agents/agents/scripts/convert.sh +362 -0
  82. package/extensions/agency-agents/agents/scripts/install.sh +465 -0
  83. package/extensions/agency-agents/agents/scripts/lint-agents.sh +115 -0
  84. package/extensions/agency-agents/agents/spatial-computing/macos-spatial-metal-engineer.md +335 -0
  85. package/extensions/agency-agents/agents/spatial-computing/terminal-integration-specialist.md +68 -0
  86. package/extensions/agency-agents/agents/spatial-computing/visionos-spatial-engineer.md +52 -0
  87. package/extensions/agency-agents/agents/spatial-computing/xr-cockpit-interaction-specialist.md +30 -0
  88. package/extensions/agency-agents/agents/spatial-computing/xr-immersive-developer.md +30 -0
  89. package/extensions/agency-agents/agents/spatial-computing/xr-interface-architect.md +30 -0
  90. package/extensions/agency-agents/agents/specialized/agentic-identity-trust.md +367 -0
  91. package/extensions/agency-agents/agents/specialized/agents-orchestrator.md +365 -0
  92. package/extensions/agency-agents/agents/specialized/data-analytics-reporter.md +52 -0
  93. package/extensions/agency-agents/agents/specialized/data-consolidation-agent.md +58 -0
  94. package/extensions/agency-agents/agents/specialized/lsp-index-engineer.md +312 -0
  95. package/extensions/agency-agents/agents/specialized/report-distribution-agent.md +63 -0
  96. package/extensions/agency-agents/agents/specialized/sales-data-extraction-agent.md +65 -0
  97. package/extensions/agency-agents/agents/strategy/EXECUTIVE-BRIEF.md +95 -0
  98. package/extensions/agency-agents/agents/strategy/QUICKSTART.md +194 -0
  99. package/extensions/agency-agents/agents/strategy/coordination/agent-activation-prompts.md +401 -0
  100. package/extensions/agency-agents/agents/strategy/coordination/handoff-templates.md +357 -0
  101. package/extensions/agency-agents/agents/strategy/nexus-strategy.md +1110 -0
  102. package/extensions/agency-agents/agents/strategy/playbooks/phase-0-discovery.md +178 -0
  103. package/extensions/agency-agents/agents/strategy/playbooks/phase-1-strategy.md +238 -0
  104. package/extensions/agency-agents/agents/strategy/playbooks/phase-2-foundation.md +278 -0
  105. package/extensions/agency-agents/agents/strategy/playbooks/phase-3-build.md +286 -0
  106. package/extensions/agency-agents/agents/strategy/playbooks/phase-4-hardening.md +332 -0
  107. package/extensions/agency-agents/agents/strategy/playbooks/phase-5-launch.md +277 -0
  108. package/extensions/agency-agents/agents/strategy/playbooks/phase-6-operate.md +318 -0
  109. package/extensions/agency-agents/agents/strategy/runbooks/scenario-enterprise-feature.md +157 -0
  110. package/extensions/agency-agents/agents/strategy/runbooks/scenario-incident-response.md +217 -0
  111. package/extensions/agency-agents/agents/strategy/runbooks/scenario-marketing-campaign.md +187 -0
  112. package/extensions/agency-agents/agents/strategy/runbooks/scenario-startup-mvp.md +154 -0
  113. package/extensions/agency-agents/agents/support/support-analytics-reporter.md +363 -0
  114. package/extensions/agency-agents/agents/support/support-executive-summary-generator.md +210 -0
  115. package/extensions/agency-agents/agents/support/support-finance-tracker.md +440 -0
  116. package/extensions/agency-agents/agents/support/support-infrastructure-maintainer.md +616 -0
  117. package/extensions/agency-agents/agents/support/support-legal-compliance-checker.md +586 -0
  118. package/extensions/agency-agents/agents/support/support-support-responder.md +583 -0
  119. package/extensions/agency-agents/agents/testing/testing-accessibility-auditor.md +313 -0
  120. package/extensions/agency-agents/agents/testing/testing-api-tester.md +304 -0
  121. package/extensions/agency-agents/agents/testing/testing-evidence-collector.md +208 -0
  122. package/extensions/agency-agents/agents/testing/testing-performance-benchmarker.md +266 -0
  123. package/extensions/agency-agents/agents/testing/testing-reality-checker.md +236 -0
  124. package/extensions/agency-agents/agents/testing/testing-test-results-analyzer.md +303 -0
  125. package/extensions/agency-agents/agents/testing/testing-tool-evaluator.md +392 -0
  126. package/extensions/agency-agents/agents/testing/testing-workflow-optimizer.md +448 -0
  127. package/extensions/agency-agents/index.ts +733 -0
  128. package/extensions/agency-agents/node_modules/.bin/jiti +21 -0
  129. package/extensions/agency-agents/node_modules/.bin/tsc +21 -0
  130. package/extensions/agency-agents/node_modules/.bin/tsserver +21 -0
  131. package/extensions/agency-agents/node_modules/.bin/tsx +21 -0
  132. package/extensions/agency-agents/node_modules/.bin/vite +21 -0
  133. package/extensions/agency-agents/node_modules/.bin/vitest +21 -0
  134. package/extensions/agency-agents/node_modules/.bin/yaml +21 -0
  135. package/extensions/agency-agents/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
  136. package/extensions/agency-agents/package.json +25 -0
  137. package/extensions/agency-agents/src/AgencyAgentsService.test.ts +443 -0
  138. package/extensions/agency-agents/src/AgencyAgentsService.ts +288 -0
  139. package/extensions/agency-agents/src/types.ts +147 -0
  140. package/extensions/agency-agents/vitest.config.ts +8 -0
  141. package/extensions/hexstrike-ai/README.md +98 -0
  142. package/extensions/hexstrike-ai/node_modules/.bin/tsc +21 -0
  143. package/extensions/hexstrike-ai/node_modules/.bin/tsserver +21 -0
  144. package/extensions/hexstrike-ai/package.json +29 -0
  145. package/extensions/hexstrike-ai/poolbot.plugin.json +31 -0
  146. package/extensions/hexstrike-ai/src/client.ts +91 -0
  147. package/extensions/hexstrike-ai/src/index.ts +170 -0
  148. package/extensions/hexstrike-ai/src/server/hexstrike_mcp.py +5470 -0
  149. package/extensions/hexstrike-ai/src/server/hexstrike_server.py +17289 -0
  150. package/extensions/hexstrike-ai/src/server/requirements.txt +84 -0
  151. package/extensions/hexstrike-ai/src/server-manager.ts +83 -0
  152. package/extensions/hexstrike-ai/tsconfig.json +20 -0
  153. package/extensions/hexstrike-bridge/package.json +1 -1
  154. package/extensions/hexstrike-bridge/poolbot.plugin.json +23 -0
  155. package/extensions/mcp-server/poolbot.plugin.json +10 -0
  156. package/extensions/page-agent/README.md +159 -0
  157. package/extensions/page-agent/index.ts +595 -0
  158. package/extensions/page-agent/node_modules/.bin/jiti +21 -0
  159. package/extensions/page-agent/node_modules/.bin/playwright +21 -0
  160. package/extensions/page-agent/node_modules/.bin/tsc +21 -0
  161. package/extensions/page-agent/node_modules/.bin/tsserver +21 -0
  162. package/extensions/page-agent/node_modules/.bin/tsx +21 -0
  163. package/extensions/page-agent/node_modules/.bin/vitest +21 -0
  164. package/extensions/page-agent/node_modules/.bin/yaml +21 -0
  165. package/extensions/page-agent/package.json +43 -0
  166. package/extensions/page-agent/src/PageAgentService.test.ts +517 -0
  167. package/extensions/page-agent/src/PageAgentService.ts +636 -0
  168. package/extensions/page-agent/src/PoolBotPageController.test.ts +358 -0
  169. package/extensions/page-agent/src/PoolBotPageController.ts +245 -0
  170. package/extensions/page-agent/src/index.ts +20 -0
  171. package/extensions/page-agent/src/tools.test.ts +231 -0
  172. package/extensions/page-agent/src/tools.ts +167 -0
  173. package/extensions/page-agent/src/types.ts +198 -0
  174. package/extensions/template/README.md +101 -0
  175. package/extensions/template/index.ts +38 -0
  176. package/extensions/template/package.json +15 -0
  177. package/extensions/template/poolbot.plugin.json +10 -0
  178. package/extensions/xyops/README.md +227 -0
  179. package/extensions/xyops/index.ts +342 -0
  180. package/extensions/xyops/node_modules/.bin/jiti +21 -0
  181. package/extensions/xyops/node_modules/.bin/tsc +21 -0
  182. package/extensions/xyops/node_modules/.bin/tsserver +21 -0
  183. package/extensions/xyops/node_modules/.bin/tsx +21 -0
  184. package/extensions/xyops/node_modules/.bin/vitest +21 -0
  185. package/extensions/xyops/node_modules/.bin/yaml +21 -0
  186. package/extensions/xyops/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
  187. package/extensions/xyops/package.json +39 -0
  188. package/extensions/xyops/src/client.test.ts +467 -0
  189. package/extensions/xyops/src/client.ts +157 -0
  190. package/extensions/xyops/src/types.ts +147 -0
  191. package/extensions/xyops/vitest.config.ts +8 -0
  192. package/package.json +1 -1
  193. package/extensions/mavalie/README.md +0 -97
  194. package/extensions/mavalie/package.json +0 -15
  195. package/extensions/mavalie/src/index.ts +0 -62
@@ -0,0 +1,358 @@
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest'
2
+ import { PoolBotPageController } from './PoolBotPageController.js'
3
+
4
+ // Mock the browser client modules
5
+ vi.mock('../../../src/browser/client.js', () => ({
6
+ browserSnapshot: vi.fn(),
7
+ }))
8
+
9
+ vi.mock('../../../src/browser/client-actions.js', () => ({
10
+ browserAct: vi.fn(),
11
+ browserNavigate: vi.fn(),
12
+ browserScreenshotAction: vi.fn(),
13
+ }))
14
+
15
+ import { browserSnapshot } from '../../../src/browser/client.js'
16
+ import { browserAct, browserNavigate, browserScreenshotAction } from '../../../src/browser/client-actions.js'
17
+
18
+ describe('PoolBotPageController', () => {
19
+ let controller: PoolBotPageController
20
+
21
+ beforeEach(() => {
22
+ vi.clearAllMocks()
23
+ controller = new PoolBotPageController({
24
+ browserBaseUrl: 'http://localhost:9222',
25
+ profile: 'test-profile',
26
+ })
27
+ })
28
+
29
+ describe('constructor', () => {
30
+ it('should create controller with default config', () => {
31
+ const defaultController = new PoolBotPageController()
32
+ expect(defaultController).toBeDefined()
33
+ })
34
+
35
+ it('should create controller with custom config', () => {
36
+ expect(controller).toBeDefined()
37
+ })
38
+
39
+ it('should store targetId from config', () => {
40
+ const controllerWithTarget = new PoolBotPageController({
41
+ targetId: 'test-target-id',
42
+ })
43
+ expect(controllerWithTarget.getTargetId()).toBe('test-target-id')
44
+ })
45
+ })
46
+
47
+ describe('getBrowserState', () => {
48
+ it('should return browser state in ai format', async () => {
49
+ vi.mocked(browserSnapshot).mockResolvedValue({
50
+ ok: true,
51
+ url: 'http://example.com',
52
+ snapshot: 'Test page content',
53
+ format: 'ai',
54
+ targetId: 'test-target',
55
+ })
56
+
57
+ const state = await controller.getBrowserState()
58
+
59
+ expect(state.url).toBe('http://example.com')
60
+ expect(state.content).toBe('Test page content')
61
+ expect(state.snapshot).toBe('Test page content')
62
+ })
63
+
64
+ it('should return browser state in aria format', async () => {
65
+ vi.mocked(browserSnapshot).mockResolvedValue({
66
+ ok: true,
67
+ url: 'http://example.com',
68
+ nodes: [
69
+ { ref: '1', role: 'heading', name: 'Title', depth: 0 },
70
+ { ref: '2', role: 'button', name: 'Click me', depth: 1 },
71
+ ],
72
+ format: 'aria',
73
+ targetId: 'test-target',
74
+ })
75
+
76
+ const state = await controller.getBrowserState()
77
+
78
+ expect(state.url).toBe('http://example.com')
79
+ expect(state.content).toContain('[1] heading: Title')
80
+ expect(state.content).toContain('[2] button: Click me')
81
+ })
82
+
83
+ it('should update targetId from snapshot', async () => {
84
+ vi.mocked(browserSnapshot).mockResolvedValue({
85
+ ok: true,
86
+ url: 'http://example.com',
87
+ snapshot: 'Content',
88
+ format: 'ai',
89
+ targetId: 'new-target-id',
90
+ })
91
+
92
+ await controller.getBrowserState()
93
+
94
+ expect(controller.getTargetId()).toBe('new-target-id')
95
+ })
96
+
97
+ it('should throw error if snapshot fails', async () => {
98
+ vi.mocked(browserSnapshot).mockResolvedValue({
99
+ ok: false,
100
+ } as never)
101
+
102
+ await expect(controller.getBrowserState()).rejects.toThrow('Failed to get browser snapshot')
103
+ })
104
+ })
105
+
106
+ describe('navigate', () => {
107
+ it('should navigate to URL successfully', async () => {
108
+ vi.mocked(browserNavigate).mockResolvedValue({
109
+ ok: true,
110
+ targetId: 'new-target',
111
+ })
112
+
113
+ const result = await controller.navigate('http://example.com')
114
+
115
+ expect(result.success).toBe(true)
116
+ expect(result.message).toContain('Navigated to')
117
+ expect(controller.getTargetId()).toBe('new-target')
118
+ })
119
+
120
+ it('should handle navigation failure', async () => {
121
+ vi.mocked(browserNavigate).mockRejectedValue(new Error('Navigation failed'))
122
+
123
+ const result = await controller.navigate('http://example.com')
124
+
125
+ expect(result.success).toBe(false)
126
+ expect(result.message).toContain('Failed to navigate')
127
+ })
128
+ })
129
+
130
+ describe('clickElement', () => {
131
+ it('should click element successfully', async () => {
132
+ vi.mocked(browserAct).mockResolvedValue({
133
+ ok: true,
134
+ targetId: 'test-target',
135
+ })
136
+
137
+ const result = await controller.clickElement('element-ref-1')
138
+
139
+ expect(result.success).toBe(true)
140
+ expect(browserAct).toHaveBeenCalledWith(
141
+ 'http://localhost:9222',
142
+ {
143
+ kind: 'click',
144
+ ref: 'element-ref-1',
145
+ targetId: undefined,
146
+ },
147
+ { profile: 'test-profile' }
148
+ )
149
+ })
150
+
151
+ it('should handle click failure', async () => {
152
+ vi.mocked(browserAct).mockRejectedValue(new Error('Click failed'))
153
+
154
+ const result = await controller.clickElement('element-ref-1')
155
+
156
+ expect(result.success).toBe(false)
157
+ expect(result.message).toContain('Action failed')
158
+ })
159
+ })
160
+
161
+ describe('inputText', () => {
162
+ it('should input text successfully', async () => {
163
+ vi.mocked(browserAct).mockResolvedValue({
164
+ ok: true,
165
+ targetId: 'test-target',
166
+ })
167
+
168
+ const result = await controller.inputText('input-ref', 'test text')
169
+
170
+ expect(result.success).toBe(true)
171
+ expect(browserAct).toHaveBeenCalledWith(
172
+ 'http://localhost:9222',
173
+ {
174
+ kind: 'type',
175
+ ref: 'input-ref',
176
+ text: 'test text',
177
+ targetId: undefined,
178
+ },
179
+ { profile: 'test-profile' }
180
+ )
181
+ })
182
+ })
183
+
184
+ describe('selectOption', () => {
185
+ it('should select option successfully', async () => {
186
+ vi.mocked(browserAct).mockResolvedValue({
187
+ ok: true,
188
+ targetId: 'test-target',
189
+ })
190
+
191
+ const result = await controller.selectOption('select-ref', 'option-value')
192
+
193
+ expect(result.success).toBe(true)
194
+ expect(browserAct).toHaveBeenCalledWith(
195
+ 'http://localhost:9222',
196
+ {
197
+ kind: 'select',
198
+ ref: 'select-ref',
199
+ values: ['option-value'],
200
+ targetId: undefined,
201
+ },
202
+ { profile: 'test-profile' }
203
+ )
204
+ })
205
+ })
206
+
207
+ describe('scroll', () => {
208
+ it('should scroll down by default', async () => {
209
+ vi.mocked(browserAct).mockResolvedValue({
210
+ ok: true,
211
+ targetId: 'test-target',
212
+ })
213
+
214
+ const result = await controller.scroll({})
215
+
216
+ expect(result.success).toBe(true)
217
+ expect(browserAct).toHaveBeenCalledWith(
218
+ 'http://localhost:9222',
219
+ expect.objectContaining({
220
+ kind: 'evaluate',
221
+ fn: expect.stringContaining('scrollBy'),
222
+ }),
223
+ { profile: 'test-profile' }
224
+ )
225
+ })
226
+
227
+ it('should scroll up when specified', async () => {
228
+ vi.mocked(browserAct).mockResolvedValue({
229
+ ok: true,
230
+ targetId: 'test-target',
231
+ })
232
+
233
+ const result = await controller.scroll({ down: false })
234
+
235
+ expect(result.success).toBe(true)
236
+ expect(browserAct).toHaveBeenCalledWith(
237
+ 'http://localhost:9222',
238
+ expect.objectContaining({
239
+ kind: 'evaluate',
240
+ fn: expect.stringContaining('-500'),
241
+ }),
242
+ { profile: 'test-profile' }
243
+ )
244
+ })
245
+
246
+ it('should use custom amount', async () => {
247
+ vi.mocked(browserAct).mockResolvedValue({
248
+ ok: true,
249
+ targetId: 'test-target',
250
+ })
251
+
252
+ const result = await controller.scroll({ amount: 1000 })
253
+
254
+ expect(result.success).toBe(true)
255
+ expect(browserAct).toHaveBeenCalledWith(
256
+ 'http://localhost:9222',
257
+ expect.objectContaining({
258
+ fn: expect.stringContaining('1000'),
259
+ }),
260
+ { profile: 'test-profile' }
261
+ )
262
+ })
263
+ })
264
+
265
+ describe('wait', () => {
266
+ it('should wait for specified seconds', async () => {
267
+ const start = Date.now()
268
+ const result = await controller.wait(0.1) // 100ms
269
+ const elapsed = Date.now() - start
270
+
271
+ expect(result.success).toBe(true)
272
+ expect(result.message).toContain('Waited for 0.1 seconds')
273
+ expect(elapsed).toBeGreaterThanOrEqual(90)
274
+ })
275
+ })
276
+
277
+ describe('executeJavaScript', () => {
278
+ it('should execute JavaScript successfully', async () => {
279
+ vi.mocked(browserAct).mockResolvedValue({
280
+ ok: true,
281
+ targetId: 'test-target',
282
+ })
283
+
284
+ const result = await controller.executeJavaScript('document.title')
285
+
286
+ expect(result.success).toBe(true)
287
+ expect(browserAct).toHaveBeenCalledWith(
288
+ 'http://localhost:9222',
289
+ {
290
+ kind: 'evaluate',
291
+ fn: 'document.title',
292
+ targetId: undefined,
293
+ },
294
+ { profile: 'test-profile' }
295
+ )
296
+ })
297
+ })
298
+
299
+ describe('screenshot', () => {
300
+ it('should take screenshot successfully', async () => {
301
+ vi.mocked(browserScreenshotAction).mockResolvedValue({
302
+ ok: true,
303
+ targetId: 'test-target',
304
+ path: 'base64-screenshot-data',
305
+ })
306
+
307
+ const result = await controller.screenshot()
308
+
309
+ expect(result.success).toBe(true)
310
+ expect(result.base64).toBe('base64-screenshot-data')
311
+ expect(result.message).toContain('Screenshot captured')
312
+ })
313
+
314
+ it('should handle screenshot failure', async () => {
315
+ vi.mocked(browserScreenshotAction).mockRejectedValue(new Error('Screenshot failed'))
316
+
317
+ const result = await controller.screenshot()
318
+
319
+ expect(result.success).toBe(false)
320
+ expect(result.message).toContain('Screenshot failed')
321
+ })
322
+
323
+ it('should pass fullPage option', async () => {
324
+ vi.mocked(browserScreenshotAction).mockResolvedValue({
325
+ ok: true,
326
+ targetId: 'test-target',
327
+ path: 'base64-data',
328
+ })
329
+
330
+ await controller.screenshot({ fullPage: true })
331
+
332
+ expect(browserScreenshotAction).toHaveBeenCalledWith(
333
+ 'http://localhost:9222',
334
+ expect.objectContaining({
335
+ fullPage: true,
336
+ type: 'png',
337
+ })
338
+ )
339
+ })
340
+ })
341
+
342
+ describe('getToolContext', () => {
343
+ it('should return tool context', () => {
344
+ const context = controller.getToolContext()
345
+
346
+ expect(context.browserBaseUrl).toBe('http://localhost:9222')
347
+ expect(context.profile).toBe('test-profile')
348
+ expect(context.targetId).toBeUndefined()
349
+ })
350
+ })
351
+
352
+ describe('setTargetId', () => {
353
+ it('should update targetId', () => {
354
+ controller.setTargetId('new-target')
355
+ expect(controller.getTargetId()).toBe('new-target')
356
+ })
357
+ })
358
+ })
@@ -0,0 +1,245 @@
1
+ /**
2
+ * PoolBot Page Controller
3
+ *
4
+ * Adapter that wraps PoolBot's native browser client to provide
5
+ * the PageController interface expected by Page Agent.
6
+ */
7
+
8
+ import {
9
+ browserSnapshot,
10
+ } from '../../../src/browser/client.js';
11
+ import {
12
+ browserAct,
13
+ browserNavigate,
14
+ browserScreenshotAction,
15
+ type BrowserActRequest,
16
+ } from '../../../src/browser/client-actions.js';
17
+ import type { BrowserState, ToolContext } from './types.js';
18
+
19
+ export interface PoolBotPageControllerConfig {
20
+ browserBaseUrl?: string;
21
+ profile?: string;
22
+ targetId?: string;
23
+ }
24
+
25
+ export class PoolBotPageController {
26
+ private config: PoolBotPageControllerConfig;
27
+ private currentTargetId: string | undefined;
28
+
29
+ constructor(config: PoolBotPageControllerConfig = {}) {
30
+ this.config = config;
31
+ this.currentTargetId = config.targetId;
32
+ }
33
+
34
+ /**
35
+ * Get current browser state for LLM consumption
36
+ */
37
+ async getBrowserState(): Promise<BrowserState> {
38
+ const snapshot = await browserSnapshot(this.config.browserBaseUrl, {
39
+ format: 'ai',
40
+ profile: this.config.profile,
41
+ targetId: this.currentTargetId,
42
+ interactive: true,
43
+ labels: true,
44
+ });
45
+
46
+ if (!snapshot.ok) {
47
+ throw new Error('Failed to get browser snapshot');
48
+ }
49
+
50
+ this.currentTargetId = snapshot.targetId;
51
+
52
+ // Handle both ai and aria formats
53
+ if (snapshot.format === 'ai') {
54
+ return {
55
+ url: snapshot.url,
56
+ title: '', // Extract from snapshot if needed
57
+ content: snapshot.snapshot,
58
+ snapshot: snapshot.snapshot,
59
+ };
60
+ } else {
61
+ // aria format - convert to string representation
62
+ const content = snapshot.nodes.map(n => `[${n.ref}] ${n.role}: ${n.name}`).join('\n');
63
+ return {
64
+ url: snapshot.url,
65
+ title: '',
66
+ content,
67
+ snapshot: content,
68
+ };
69
+ }
70
+ }
71
+
72
+ /**
73
+ * Navigate to a URL
74
+ */
75
+ async navigate(url: string): Promise<{ success: boolean; message: string }> {
76
+ try {
77
+ const result = await browserNavigate(this.config.browserBaseUrl, {
78
+ url,
79
+ profile: this.config.profile,
80
+ targetId: this.currentTargetId,
81
+ });
82
+
83
+ this.currentTargetId = result.targetId;
84
+
85
+ return {
86
+ success: true,
87
+ message: `Navigated to ${url}`,
88
+ };
89
+ } catch (error) {
90
+ return {
91
+ success: false,
92
+ message: `Failed to navigate: ${error}`,
93
+ };
94
+ }
95
+ }
96
+
97
+ /**
98
+ * Click element by ref
99
+ */
100
+ async clickElement(ref: string): Promise<{ success: boolean; message: string }> {
101
+ return this.executeAction({
102
+ kind: 'click',
103
+ ref,
104
+ targetId: this.currentTargetId,
105
+ });
106
+ }
107
+
108
+ /**
109
+ * Type text into element
110
+ */
111
+ async inputText(ref: string, text: string): Promise<{ success: boolean; message: string }> {
112
+ return this.executeAction({
113
+ kind: 'type',
114
+ ref,
115
+ text,
116
+ targetId: this.currentTargetId,
117
+ });
118
+ }
119
+
120
+ /**
121
+ * Select option from dropdown
122
+ */
123
+ async selectOption(ref: string, value: string): Promise<{ success: boolean; message: string }> {
124
+ return this.executeAction({
125
+ kind: 'select',
126
+ ref,
127
+ values: [value],
128
+ targetId: this.currentTargetId,
129
+ });
130
+ }
131
+
132
+ /**
133
+ * Scroll page
134
+ */
135
+ async scroll(options: {
136
+ down?: boolean;
137
+ amount?: number;
138
+ }): Promise<{ success: boolean; message: string }> {
139
+ const direction = options.down !== false ? 1 : -1;
140
+ const amount = options.amount || 500;
141
+
142
+ return this.executeAction({
143
+ kind: 'evaluate',
144
+ fn: `window.scrollBy(0, ${amount * direction})`,
145
+ targetId: this.currentTargetId,
146
+ });
147
+ }
148
+
149
+ /**
150
+ * Wait for a specified time
151
+ */
152
+ async wait(seconds: number): Promise<{ success: boolean; message: string }> {
153
+ await new Promise(resolve => setTimeout(resolve, seconds * 1000));
154
+ return {
155
+ success: true,
156
+ message: `Waited for ${seconds} seconds`,
157
+ };
158
+ }
159
+
160
+ /**
161
+ * Execute JavaScript on the page
162
+ */
163
+ async executeJavaScript(script: string): Promise<{ success: boolean; message: string }> {
164
+ return this.executeAction({
165
+ kind: 'evaluate',
166
+ fn: script,
167
+ targetId: this.currentTargetId,
168
+ });
169
+ }
170
+
171
+ /**
172
+ * Get tool context for executing actions
173
+ */
174
+ getToolContext(): ToolContext {
175
+ return {
176
+ browserBaseUrl: this.config.browserBaseUrl,
177
+ profile: this.config.profile,
178
+ targetId: this.currentTargetId,
179
+ };
180
+ }
181
+
182
+ /**
183
+ * Execute a browser action
184
+ */
185
+ private async executeAction(action: BrowserActRequest): Promise<{ success: boolean; message: string }> {
186
+ try {
187
+ const result = await browserAct(this.config.browserBaseUrl, action, {
188
+ profile: this.config.profile,
189
+ });
190
+
191
+ if (result.targetId) {
192
+ this.currentTargetId = result.targetId;
193
+ }
194
+
195
+ return {
196
+ success: true,
197
+ message: `Action completed successfully`,
198
+ };
199
+ } catch (error) {
200
+ return {
201
+ success: false,
202
+ message: `Action failed: ${error}`,
203
+ };
204
+ }
205
+ }
206
+
207
+ /**
208
+ * Update target ID
209
+ */
210
+ setTargetId(targetId: string): void {
211
+ this.currentTargetId = targetId;
212
+ }
213
+
214
+ /**
215
+ * Get current target ID
216
+ */
217
+ getTargetId(): string | undefined {
218
+ return this.currentTargetId;
219
+ }
220
+
221
+ /**
222
+ * Take a screenshot of the current page
223
+ */
224
+ async screenshot(options?: { fullPage?: boolean }): Promise<{ success: boolean; base64?: string; message: string }> {
225
+ try {
226
+ const result = await browserScreenshotAction(this.config.browserBaseUrl, {
227
+ profile: this.config.profile,
228
+ targetId: this.currentTargetId,
229
+ fullPage: options?.fullPage,
230
+ type: 'png',
231
+ });
232
+
233
+ return {
234
+ success: true,
235
+ base64: result.path,
236
+ message: `Screenshot captured successfully`,
237
+ };
238
+ } catch (error) {
239
+ return {
240
+ success: false,
241
+ message: `Screenshot failed: ${error}`,
242
+ };
243
+ }
244
+ }
245
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Page Agent Integration for PoolBot
3
+ *
4
+ * This module provides AI-powered browser automation by integrating
5
+ * the Page Agent core logic with PoolBot's native browser system.
6
+ *
7
+ * Instead of creating a separate browser instance, this integration
8
+ * leverages PoolBot's existing CDP/Playwright infrastructure for
9
+ * efficient resource usage and seamless operation.
10
+ */
11
+
12
+ export { PageAgentService } from './PageAgentService.js';
13
+ export { PoolBotPageController } from './PoolBotPageController.js';
14
+ export { createPageAgentTools } from './tools.js';
15
+ export type {
16
+ PageAgentConfig,
17
+ PageAgentExecutionResult,
18
+ PageAgentStep,
19
+ PageAgentStatus
20
+ } from './types.js';