explorbot 0.0.1

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 (329) hide show
  1. package/LICENSE +94 -0
  2. package/README.md +267 -0
  3. package/assets/sample-files/sample.docx +0 -0
  4. package/assets/sample-files/sample.mp3 +0 -0
  5. package/assets/sample-files/sample.mp4 +0 -0
  6. package/assets/sample-files/sample.pdf +21 -0
  7. package/assets/sample-files/sample.png +0 -0
  8. package/assets/sample-files/sample.xlsx +0 -0
  9. package/assets/sample-files/sample.zip +0 -0
  10. package/dist/assets/sample-files/sample.docx +0 -0
  11. package/dist/assets/sample-files/sample.mp3 +0 -0
  12. package/dist/assets/sample-files/sample.mp4 +0 -0
  13. package/dist/assets/sample-files/sample.pdf +21 -0
  14. package/dist/assets/sample-files/sample.png +0 -0
  15. package/dist/assets/sample-files/sample.xlsx +0 -0
  16. package/dist/assets/sample-files/sample.zip +0 -0
  17. package/dist/bin/explorbot-cli.js +683 -0
  18. package/dist/bin/explorbot-cli.js.map +1 -0
  19. package/dist/boat/api-tester/bin/apibot-cli.js +5 -0
  20. package/dist/boat/api-tester/bin/apibot-cli.js.map +1 -0
  21. package/dist/boat/api-tester/example/apibot.config.js +31 -0
  22. package/dist/boat/api-tester/example/apibot.config.js.map +1 -0
  23. package/dist/boat/api-tester/src/ai/chief/styles.js +13 -0
  24. package/dist/boat/api-tester/src/ai/chief/styles.js.map +1 -0
  25. package/dist/boat/api-tester/src/ai/chief.js +301 -0
  26. package/dist/boat/api-tester/src/ai/chief.js.map +1 -0
  27. package/dist/boat/api-tester/src/ai/curler-tools.js +263 -0
  28. package/dist/boat/api-tester/src/ai/curler-tools.js.map +1 -0
  29. package/dist/boat/api-tester/src/ai/curler.js +271 -0
  30. package/dist/boat/api-tester/src/ai/curler.js.map +1 -0
  31. package/dist/boat/api-tester/src/api-client.js +26 -0
  32. package/dist/boat/api-tester/src/api-client.js.map +1 -0
  33. package/dist/boat/api-tester/src/apibot.js +166 -0
  34. package/dist/boat/api-tester/src/apibot.js.map +1 -0
  35. package/dist/boat/api-tester/src/cli.js +262 -0
  36. package/dist/boat/api-tester/src/cli.js.map +1 -0
  37. package/dist/boat/api-tester/src/config.js +159 -0
  38. package/dist/boat/api-tester/src/config.js.map +1 -0
  39. package/dist/prompts/audit-rules.md +124 -0
  40. package/dist/rules/chief/general.md +11 -0
  41. package/dist/rules/chief/styles/curious.md +12 -0
  42. package/dist/rules/chief/styles/hacker.md +19 -0
  43. package/dist/rules/chief/styles/normal.md +11 -0
  44. package/dist/rules/chief/styles/psycho.md +17 -0
  45. package/dist/rules/navigator/multiple-locator.md +47 -0
  46. package/dist/rules/navigator/output.md +69 -0
  47. package/dist/rules/navigator/verification-actions.md +122 -0
  48. package/dist/rules/navigator/verification-output.md +53 -0
  49. package/dist/rules/planner/styles/curious.md +39 -0
  50. package/dist/rules/planner/styles/normal.md +21 -0
  51. package/dist/rules/planner/styles/psycho.md +14 -0
  52. package/dist/rules/researcher/list-element.md +11 -0
  53. package/dist/rules/researcher/screenshot-ui-map.md +30 -0
  54. package/dist/rules/researcher/section-ui-map.md +18 -0
  55. package/dist/rules/researcher/ui-map-table.md +18 -0
  56. package/dist/src/action-result.js +574 -0
  57. package/dist/src/action-result.js.map +1 -0
  58. package/dist/src/action.js +388 -0
  59. package/dist/src/action.js.map +1 -0
  60. package/dist/src/activity.js +86 -0
  61. package/dist/src/activity.js.map +1 -0
  62. package/dist/src/ai/agent.js +2 -0
  63. package/dist/src/ai/agent.js.map +1 -0
  64. package/dist/src/ai/bosun.js +443 -0
  65. package/dist/src/ai/bosun.js.map +1 -0
  66. package/dist/src/ai/captain/idle-mode.js +102 -0
  67. package/dist/src/ai/captain/idle-mode.js.map +1 -0
  68. package/dist/src/ai/captain/mixin.js +11 -0
  69. package/dist/src/ai/captain/mixin.js.map +1 -0
  70. package/dist/src/ai/captain/test-mode.js +251 -0
  71. package/dist/src/ai/captain/test-mode.js.map +1 -0
  72. package/dist/src/ai/captain/web-mode.js +124 -0
  73. package/dist/src/ai/captain/web-mode.js.map +1 -0
  74. package/dist/src/ai/captain.js +442 -0
  75. package/dist/src/ai/captain.js.map +1 -0
  76. package/dist/src/ai/conversation.js +176 -0
  77. package/dist/src/ai/conversation.js.map +1 -0
  78. package/dist/src/ai/experience-compactor.js +232 -0
  79. package/dist/src/ai/experience-compactor.js.map +1 -0
  80. package/dist/src/ai/fisherman-tools.js +154 -0
  81. package/dist/src/ai/fisherman-tools.js.map +1 -0
  82. package/dist/src/ai/fisherman.js +184 -0
  83. package/dist/src/ai/fisherman.js.map +1 -0
  84. package/dist/src/ai/historian.js +384 -0
  85. package/dist/src/ai/historian.js.map +1 -0
  86. package/dist/src/ai/navigator.js +493 -0
  87. package/dist/src/ai/navigator.js.map +1 -0
  88. package/dist/src/ai/pilot.js +684 -0
  89. package/dist/src/ai/pilot.js.map +1 -0
  90. package/dist/src/ai/planner/session-dedup.js +28 -0
  91. package/dist/src/ai/planner/session-dedup.js.map +1 -0
  92. package/dist/src/ai/planner/styles.js +15 -0
  93. package/dist/src/ai/planner/styles.js.map +1 -0
  94. package/dist/src/ai/planner/subpages.js +118 -0
  95. package/dist/src/ai/planner/subpages.js.map +1 -0
  96. package/dist/src/ai/planner.js +486 -0
  97. package/dist/src/ai/planner.js.map +1 -0
  98. package/dist/src/ai/provider.js +540 -0
  99. package/dist/src/ai/provider.js.map +1 -0
  100. package/dist/src/ai/quartermaster.js +210 -0
  101. package/dist/src/ai/quartermaster.js.map +1 -0
  102. package/dist/src/ai/researcher/cache.js +95 -0
  103. package/dist/src/ai/researcher/cache.js.map +1 -0
  104. package/dist/src/ai/researcher/coordinates.js +210 -0
  105. package/dist/src/ai/researcher/coordinates.js.map +1 -0
  106. package/dist/src/ai/researcher/deep-analysis.js +364 -0
  107. package/dist/src/ai/researcher/deep-analysis.js.map +1 -0
  108. package/dist/src/ai/researcher/fingerprint-worker.js +46 -0
  109. package/dist/src/ai/researcher/fingerprint-worker.js.map +1 -0
  110. package/dist/src/ai/researcher/focus.js +37 -0
  111. package/dist/src/ai/researcher/focus.js.map +1 -0
  112. package/dist/src/ai/researcher/locators.js +242 -0
  113. package/dist/src/ai/researcher/locators.js.map +1 -0
  114. package/dist/src/ai/researcher/mixin.js +3 -0
  115. package/dist/src/ai/researcher/mixin.js.map +1 -0
  116. package/dist/src/ai/researcher/parser.js +160 -0
  117. package/dist/src/ai/researcher/parser.js.map +1 -0
  118. package/dist/src/ai/researcher/research-result.js +110 -0
  119. package/dist/src/ai/researcher/research-result.js.map +1 -0
  120. package/dist/src/ai/researcher.js +776 -0
  121. package/dist/src/ai/researcher.js.map +1 -0
  122. package/dist/src/ai/rules.js +368 -0
  123. package/dist/src/ai/rules.js.map +1 -0
  124. package/dist/src/ai/task-agent.js +110 -0
  125. package/dist/src/ai/task-agent.js.map +1 -0
  126. package/dist/src/ai/tester.js +840 -0
  127. package/dist/src/ai/tester.js.map +1 -0
  128. package/dist/src/ai/tools.js +980 -0
  129. package/dist/src/ai/tools.js.map +1 -0
  130. package/dist/src/api/api-client.js +91 -0
  131. package/dist/src/api/api-client.js.map +1 -0
  132. package/dist/src/api/request-result.js +177 -0
  133. package/dist/src/api/request-result.js.map +1 -0
  134. package/dist/src/api/request-store.js +109 -0
  135. package/dist/src/api/request-store.js.map +1 -0
  136. package/dist/src/api/spec-reader.js +148 -0
  137. package/dist/src/api/spec-reader.js.map +1 -0
  138. package/dist/src/api/xhr-capture.js +91 -0
  139. package/dist/src/api/xhr-capture.js.map +1 -0
  140. package/dist/src/browser-server.js +67 -0
  141. package/dist/src/browser-server.js.map +1 -0
  142. package/dist/src/command-handler.js +363 -0
  143. package/dist/src/command-handler.js.map +1 -0
  144. package/dist/src/commands/add-rule-command.js +52 -0
  145. package/dist/src/commands/add-rule-command.js.map +1 -0
  146. package/dist/src/commands/base-command.js +14 -0
  147. package/dist/src/commands/base-command.js.map +1 -0
  148. package/dist/src/commands/clean-command.js +67 -0
  149. package/dist/src/commands/clean-command.js.map +1 -0
  150. package/dist/src/commands/context-aria-command.js +18 -0
  151. package/dist/src/commands/context-aria-command.js.map +1 -0
  152. package/dist/src/commands/context-command.js +57 -0
  153. package/dist/src/commands/context-command.js.map +1 -0
  154. package/dist/src/commands/context-data-command.js +25 -0
  155. package/dist/src/commands/context-data-command.js.map +1 -0
  156. package/dist/src/commands/context-experience-command.js +41 -0
  157. package/dist/src/commands/context-experience-command.js.map +1 -0
  158. package/dist/src/commands/context-html-command.js +26 -0
  159. package/dist/src/commands/context-html-command.js.map +1 -0
  160. package/dist/src/commands/context-knowledge-command.js +36 -0
  161. package/dist/src/commands/context-knowledge-command.js.map +1 -0
  162. package/dist/src/commands/debug-command.js +12 -0
  163. package/dist/src/commands/debug-command.js.map +1 -0
  164. package/dist/src/commands/drill-command.js +29 -0
  165. package/dist/src/commands/drill-command.js.map +1 -0
  166. package/dist/src/commands/exit-command.js +26 -0
  167. package/dist/src/commands/exit-command.js.map +1 -0
  168. package/dist/src/commands/explore-command.js +124 -0
  169. package/dist/src/commands/explore-command.js.map +1 -0
  170. package/dist/src/commands/freesail-command.js +84 -0
  171. package/dist/src/commands/freesail-command.js.map +1 -0
  172. package/dist/src/commands/help-command.js +7 -0
  173. package/dist/src/commands/help-command.js.map +1 -0
  174. package/dist/src/commands/index.js +63 -0
  175. package/dist/src/commands/index.js.map +1 -0
  176. package/dist/src/commands/knows-command.js +54 -0
  177. package/dist/src/commands/knows-command.js.map +1 -0
  178. package/dist/src/commands/learn-command.js +35 -0
  179. package/dist/src/commands/learn-command.js.map +1 -0
  180. package/dist/src/commands/navigate-command.js +16 -0
  181. package/dist/src/commands/navigate-command.js.map +1 -0
  182. package/dist/src/commands/path-command.js +70 -0
  183. package/dist/src/commands/path-command.js.map +1 -0
  184. package/dist/src/commands/plan-clear-command.js +13 -0
  185. package/dist/src/commands/plan-clear-command.js.map +1 -0
  186. package/dist/src/commands/plan-command.js +36 -0
  187. package/dist/src/commands/plan-command.js.map +1 -0
  188. package/dist/src/commands/plan-edit-command.js +8 -0
  189. package/dist/src/commands/plan-edit-command.js.map +1 -0
  190. package/dist/src/commands/plan-load-command.js +16 -0
  191. package/dist/src/commands/plan-load-command.js.map +1 -0
  192. package/dist/src/commands/plan-reload-command.js +23 -0
  193. package/dist/src/commands/plan-reload-command.js.map +1 -0
  194. package/dist/src/commands/plan-save-command.js +22 -0
  195. package/dist/src/commands/plan-save-command.js.map +1 -0
  196. package/dist/src/commands/research-command.js +38 -0
  197. package/dist/src/commands/research-command.js.map +1 -0
  198. package/dist/src/commands/start-command.js +12 -0
  199. package/dist/src/commands/start-command.js.map +1 -0
  200. package/dist/src/commands/status-command.js +19 -0
  201. package/dist/src/commands/status-command.js.map +1 -0
  202. package/dist/src/commands/test-command.js +85 -0
  203. package/dist/src/commands/test-command.js.map +1 -0
  204. package/dist/src/components/ActivityPane.js +55 -0
  205. package/dist/src/components/ActivityPane.js.map +1 -0
  206. package/dist/src/components/AddKnowledge.js +122 -0
  207. package/dist/src/components/AddKnowledge.js.map +1 -0
  208. package/dist/src/components/AddRule.js +117 -0
  209. package/dist/src/components/AddRule.js.map +1 -0
  210. package/dist/src/components/App.js +313 -0
  211. package/dist/src/components/App.js.map +1 -0
  212. package/dist/src/components/Autocomplete.js +43 -0
  213. package/dist/src/components/Autocomplete.js.map +1 -0
  214. package/dist/src/components/InputPane.js +207 -0
  215. package/dist/src/components/InputPane.js.map +1 -0
  216. package/dist/src/components/InputReadline.js +598 -0
  217. package/dist/src/components/InputReadline.js.map +1 -0
  218. package/dist/src/components/LogPane.js +123 -0
  219. package/dist/src/components/LogPane.js.map +1 -0
  220. package/dist/src/components/PlanEditor.js +126 -0
  221. package/dist/src/components/PlanEditor.js.map +1 -0
  222. package/dist/src/components/PlanPane.js +51 -0
  223. package/dist/src/components/PlanPane.js.map +1 -0
  224. package/dist/src/components/SessionTimer.js +26 -0
  225. package/dist/src/components/SessionTimer.js.map +1 -0
  226. package/dist/src/components/StateTransitionPane.js +107 -0
  227. package/dist/src/components/StateTransitionPane.js.map +1 -0
  228. package/dist/src/components/StatusPane.js +37 -0
  229. package/dist/src/components/StatusPane.js.map +1 -0
  230. package/dist/src/components/TaskPane.js +96 -0
  231. package/dist/src/components/TaskPane.js.map +1 -0
  232. package/dist/src/components/Welcome.js +52 -0
  233. package/dist/src/components/Welcome.js.map +1 -0
  234. package/dist/src/components/WelcomeChecklist.js +96 -0
  235. package/dist/src/components/WelcomeChecklist.js.map +1 -0
  236. package/dist/src/components/WelcomeCommands.js +61 -0
  237. package/dist/src/components/WelcomeCommands.js.map +1 -0
  238. package/dist/src/components/autocomplete-store.js +22 -0
  239. package/dist/src/components/autocomplete-store.js.map +1 -0
  240. package/dist/src/components/parse-keypress.js +174 -0
  241. package/dist/src/components/parse-keypress.js.map +1 -0
  242. package/dist/src/config.js +249 -0
  243. package/dist/src/config.js.map +1 -0
  244. package/dist/src/execution-controller.js +92 -0
  245. package/dist/src/execution-controller.js.map +1 -0
  246. package/dist/src/experience-tracker.js +294 -0
  247. package/dist/src/experience-tracker.js.map +1 -0
  248. package/dist/src/explorbot.js +348 -0
  249. package/dist/src/explorbot.js.map +1 -0
  250. package/dist/src/explorer.js +611 -0
  251. package/dist/src/explorer.js.map +1 -0
  252. package/dist/src/index.js +56 -0
  253. package/dist/src/index.js.map +1 -0
  254. package/dist/src/knowledge-tracker.js +184 -0
  255. package/dist/src/knowledge-tracker.js.map +1 -0
  256. package/dist/src/observability.js +126 -0
  257. package/dist/src/observability.js.map +1 -0
  258. package/dist/src/reporter.js +185 -0
  259. package/dist/src/reporter.js.map +1 -0
  260. package/dist/src/state-manager.js +427 -0
  261. package/dist/src/state-manager.js.map +1 -0
  262. package/dist/src/stats.js +44 -0
  263. package/dist/src/stats.js.map +1 -0
  264. package/dist/src/test-plan.js +343 -0
  265. package/dist/src/test-plan.js.map +1 -0
  266. package/dist/src/utils/aria.js +588 -0
  267. package/dist/src/utils/aria.js.map +1 -0
  268. package/dist/src/utils/code-extractor.js +21 -0
  269. package/dist/src/utils/code-extractor.js.map +1 -0
  270. package/dist/src/utils/context-formatter.js +205 -0
  271. package/dist/src/utils/context-formatter.js.map +1 -0
  272. package/dist/src/utils/error-page.js +19 -0
  273. package/dist/src/utils/error-page.js.map +1 -0
  274. package/dist/src/utils/expandable.js +35 -0
  275. package/dist/src/utils/expandable.js.map +1 -0
  276. package/dist/src/utils/hooks-runner.js +77 -0
  277. package/dist/src/utils/hooks-runner.js.map +1 -0
  278. package/dist/src/utils/html-diff.js +734 -0
  279. package/dist/src/utils/html-diff.js.map +1 -0
  280. package/dist/src/utils/html.js +1163 -0
  281. package/dist/src/utils/html.js.map +1 -0
  282. package/dist/src/utils/logger.js +465 -0
  283. package/dist/src/utils/logger.js.map +1 -0
  284. package/dist/src/utils/loop.js +126 -0
  285. package/dist/src/utils/loop.js.map +1 -0
  286. package/dist/src/utils/markdown-parser.js +117 -0
  287. package/dist/src/utils/markdown-parser.js.map +1 -0
  288. package/dist/src/utils/markdown-query.js +393 -0
  289. package/dist/src/utils/markdown-query.js.map +1 -0
  290. package/dist/src/utils/markdown-terminal.js +40 -0
  291. package/dist/src/utils/markdown-terminal.js.map +1 -0
  292. package/dist/src/utils/research-parser.js +2 -0
  293. package/dist/src/utils/research-parser.js.map +1 -0
  294. package/dist/src/utils/retry.js +55 -0
  295. package/dist/src/utils/retry.js.map +1 -0
  296. package/dist/src/utils/rules-loader.js +104 -0
  297. package/dist/src/utils/rules-loader.js.map +1 -0
  298. package/dist/src/utils/strings.js +14 -0
  299. package/dist/src/utils/strings.js.map +1 -0
  300. package/dist/src/utils/test-plan-markdown.js +301 -0
  301. package/dist/src/utils/test-plan-markdown.js.map +1 -0
  302. package/dist/src/utils/throttle.js +16 -0
  303. package/dist/src/utils/throttle.js.map +1 -0
  304. package/dist/src/utils/unique-names.js +13 -0
  305. package/dist/src/utils/unique-names.js.map +1 -0
  306. package/dist/src/utils/url-matcher.js +48 -0
  307. package/dist/src/utils/url-matcher.js.map +1 -0
  308. package/dist/src/utils/web-element.js +131 -0
  309. package/dist/src/utils/web-element.js.map +1 -0
  310. package/dist/src/utils/xpath.js +110 -0
  311. package/dist/src/utils/xpath.js.map +1 -0
  312. package/package.json +119 -0
  313. package/prompts/audit-rules.md +124 -0
  314. package/rules/chief/general.md +11 -0
  315. package/rules/chief/styles/curious.md +12 -0
  316. package/rules/chief/styles/hacker.md +19 -0
  317. package/rules/chief/styles/normal.md +11 -0
  318. package/rules/chief/styles/psycho.md +17 -0
  319. package/rules/navigator/multiple-locator.md +47 -0
  320. package/rules/navigator/output.md +69 -0
  321. package/rules/navigator/verification-actions.md +122 -0
  322. package/rules/navigator/verification-output.md +53 -0
  323. package/rules/planner/styles/curious.md +39 -0
  324. package/rules/planner/styles/normal.md +21 -0
  325. package/rules/planner/styles/psycho.md +14 -0
  326. package/rules/researcher/list-element.md +11 -0
  327. package/rules/researcher/screenshot-ui-map.md +30 -0
  328. package/rules/researcher/section-ui-map.md +18 -0
  329. package/rules/researcher/ui-map-table.md +18 -0
@@ -0,0 +1,232 @@
1
+ import { readFileSync, unlinkSync } from 'node:fs';
2
+ import dedent from 'dedent';
3
+ import matter from 'gray-matter';
4
+ import { z } from 'zod';
5
+ import { Observability } from '../observability.js';
6
+ import { createDebug, log, tag } from '../utils/logger.js';
7
+ const debugLog = createDebug('explorbot:experience-compactor');
8
+ export class ExperienceCompactor {
9
+ emoji = '🗜️';
10
+ provider;
11
+ experienceTracker;
12
+ MAX_LENGTH = 5000;
13
+ constructor(provider, experienceTracker) {
14
+ this.provider = provider;
15
+ this.experienceTracker = experienceTracker;
16
+ }
17
+ async compactExperience(experience) {
18
+ if (experience.length < this.MAX_LENGTH) {
19
+ return experience;
20
+ }
21
+ const prompt = this.buildCompactionPrompt(experience);
22
+ const model = this.provider.getModelForAgent('experience-compactor');
23
+ const response = await this.provider.chat([
24
+ { role: 'user', content: this.getSystemPrompt() },
25
+ { role: 'user', content: prompt },
26
+ ], model, { telemetryFunctionId: 'experience.compact' });
27
+ return response.text;
28
+ }
29
+ async compactAllExperiences() {
30
+ return Observability.run('experience-compactor.compactAll', { tags: ['experience-compactor'] }, async () => {
31
+ await this.mergeSimilarExperiences();
32
+ const experienceFiles = this.experienceTracker.getAllExperience();
33
+ let compactedCount = 0;
34
+ for (const experience of experienceFiles) {
35
+ const prevContent = experience.content;
36
+ const frontmatter = experience.data;
37
+ const compactedContent = await this.compactExperienceFile(experience.filePath);
38
+ if (prevContent !== compactedContent) {
39
+ const stateHash = experience.filePath.split('/').pop()?.replace('.md', '') || '';
40
+ this.experienceTracker.writeExperienceFile(stateHash, compactedContent, frontmatter);
41
+ debugLog('Experience file compacted:', experience.filePath);
42
+ compactedCount++;
43
+ }
44
+ }
45
+ return compactedCount;
46
+ });
47
+ }
48
+ async mergeSimilarExperiences() {
49
+ return Observability.run('experience-compactor.merge', { tags: ['experience-compactor'] }, async () => {
50
+ const experienceFiles = this.experienceTracker.getAllExperience();
51
+ if (experienceFiles.length < 2) {
52
+ return 0;
53
+ }
54
+ const mergeGroups = await this.identifyMergeGroups(experienceFiles);
55
+ let mergedCount = 0;
56
+ for (const group of mergeGroups) {
57
+ if (group.files.length < 2) {
58
+ continue;
59
+ }
60
+ await this.mergeExperienceGroup(group);
61
+ mergedCount += group.files.length - 1;
62
+ }
63
+ return mergedCount;
64
+ });
65
+ }
66
+ async identifyMergeGroups(files) {
67
+ const filesWithUrl = files.filter((f) => f.data.url && !f.data.url.startsWith('~'));
68
+ if (filesWithUrl.length < 2) {
69
+ return [];
70
+ }
71
+ const urlList = filesWithUrl.map((f) => f.data.url);
72
+ const mergeDecisions = await this.askAiForMergeDecisions(urlList);
73
+ const groups = [];
74
+ const usedFiles = new Set();
75
+ for (const decision of mergeDecisions) {
76
+ const matchingFiles = filesWithUrl.filter((f) => decision.urls.includes(f.data.url) && !usedFiles.has(f.filePath));
77
+ if (matchingFiles.length >= 2) {
78
+ groups.push({
79
+ pattern: decision.pattern,
80
+ files: matchingFiles,
81
+ });
82
+ for (const f of matchingFiles) {
83
+ usedFiles.add(f.filePath);
84
+ }
85
+ }
86
+ }
87
+ return groups;
88
+ }
89
+ async askAiForMergeDecisions(urls) {
90
+ const prompt = this.buildMergePrompt(urls);
91
+ const model = this.provider.getModelForAgent('experience-compactor');
92
+ const schema = z.object({
93
+ mergeGroups: z.array(z.object({
94
+ urls: z.array(z.string()).describe('URLs that should be merged together'),
95
+ pattern: z.string().describe('Regex pattern that matches all URLs in the group, wrapped in ~ delimiters'),
96
+ })),
97
+ });
98
+ try {
99
+ const response = await this.provider.generateObject([{ role: 'user', content: prompt }], schema, model, {
100
+ telemetryFunctionId: 'experience.mergeDecisions',
101
+ });
102
+ debugLog('AI merge decisions:', response.object);
103
+ return response.object.mergeGroups || [];
104
+ }
105
+ catch (error) {
106
+ debugLog('Error getting merge decisions from AI:', error);
107
+ return [];
108
+ }
109
+ }
110
+ buildMergePrompt(urls) {
111
+ return dedent `
112
+ Analyze these experience file URLs and identify groups that represent the same page type with dynamic URL parameters.
113
+
114
+ <urls>
115
+ ${urls.map((u, i) => `${i + 1}. ${u}`).join('\n')}
116
+ </urls>
117
+
118
+ <rules>
119
+ - Identify URLs that represent the same page structure but with different dynamic values (IDs, slugs, etc.)
120
+ - Example: /item/101, /item/102, /item/105 should be grouped with pattern ~/item/\\d+~
121
+ - Example: /user/john, /user/jane should be grouped with pattern ~/user/[^/]+~
122
+ - Only group URLs that are clearly the same page type with dynamic segments
123
+ - Do NOT group unrelated pages
124
+ - Return regex patterns wrapped in ~ delimiters (e.g., ~/path/\\d+~)
125
+ - If no URLs should be merged, return empty mergeGroups array
126
+ </rules>
127
+
128
+ Return JSON with mergeGroups array. Each group should have:
129
+ - urls: array of URLs that should be merged
130
+ - pattern: regex pattern (wrapped in ~) that matches all URLs in the group
131
+ `;
132
+ }
133
+ async mergeExperienceGroup(group) {
134
+ const [targetFile, ...sourceFiles] = group.files;
135
+ const combinedContent = group.files.map((f) => f.content).join('\n\n---\n\n');
136
+ const targetStateHash = targetFile.filePath.split('/').pop()?.replace('.md', '') || '';
137
+ const newFrontmatter = {
138
+ ...targetFile.data,
139
+ url: group.pattern,
140
+ mergedFrom: group.files.map((f) => f.data.url),
141
+ };
142
+ this.experienceTracker.writeExperienceFile(targetStateHash, combinedContent, newFrontmatter);
143
+ log(`Merged ${group.files.length} experience files into ${targetFile.filePath}`);
144
+ debugLog('New URL pattern:', group.pattern);
145
+ for (const sourceFile of sourceFiles) {
146
+ try {
147
+ unlinkSync(sourceFile.filePath);
148
+ debugLog('Deleted merged source file:', sourceFile.filePath);
149
+ }
150
+ catch (error) {
151
+ debugLog('Error deleting source file:', error);
152
+ }
153
+ }
154
+ }
155
+ async compactExperienceFile(filePath) {
156
+ try {
157
+ const fileContent = readFileSync(filePath, 'utf8');
158
+ const parsed = matter(fileContent);
159
+ if (parsed.content.length < this.MAX_LENGTH) {
160
+ return parsed.content;
161
+ }
162
+ debugLog('Experience file to compact:', filePath);
163
+ const text = await this.compactExperience(parsed.content);
164
+ tag('substep').log('Experience file compacted:', filePath);
165
+ debugLog('Experience file compacted:', text);
166
+ return text;
167
+ }
168
+ catch (error) {
169
+ debugLog('Error compacting experience file:', error);
170
+ return '';
171
+ }
172
+ }
173
+ getSystemPrompt() {
174
+ const customPrompt = this.provider.getSystemPromptForAgent('experience-compactor', '*');
175
+ return dedent `
176
+ You are an expert test automation engineer specializing in CodeceptJS.
177
+ Your task is to compact experience data from test automation attempts into clean markdown format.
178
+
179
+ ${customPrompt || ''}
180
+ `;
181
+ }
182
+ buildCompactionPrompt(content) {
183
+ return dedent `
184
+ <rules>
185
+ - Use markdown headers only (##, ###) - NO XML tags or wrappers in output
186
+ - Merge similar flows to remove duplicates
187
+ - Keep output under ${this.MAX_LENGTH} characters
188
+ - Be explicit and short - no proposals or explanations
189
+
190
+ KEEP only:
191
+ - Positive flows that complete a business action (create, edit, delete, navigate)
192
+ - Reusable interaction patterns (opening dropdowns, filling forms, using pickers)
193
+ - Discovery lines (> prefixed) that document UI elements appearing at each step — keep at most 5 per flow step
194
+ - Working CodeceptJS code for common interactions
195
+
196
+ REMOVE:
197
+ - All FAILED entries
198
+ - Edge-case and negative flows (empty values, disabled buttons, validation errors, boundary testing)
199
+ - Flows whose purpose is to test what happens when something goes wrong
200
+ - All I.amOnPage, I.grab, I.see, I.seeElement, I.dontSee calls
201
+ - Duplicate approaches that achieve the same goal
202
+ </rules>
203
+
204
+ <output_format>
205
+ Use this markdown structure:
206
+
207
+ ## Flows
208
+
209
+ For each unique positive flow (merge duplicates):
210
+ - Purpose: what was accomplished
211
+ \`\`\`js
212
+ // working code
213
+ \`\`\`
214
+
215
+ ## Reusable Actions
216
+
217
+ For each reusable interaction pattern not covered by flows:
218
+ - Purpose: what was accomplished
219
+ \`\`\`js
220
+ // working code
221
+ \`\`\`
222
+ </output_format>
223
+
224
+ <context>
225
+ ${content}
226
+ </context>
227
+
228
+ Compact this experience data following the format above.
229
+ `;
230
+ }
231
+ }
232
+ //# sourceMappingURL=experience-compactor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"experience-compactor.js","sourceRoot":"","sources":["../../../src/ai/experience-compactor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,154 @@
1
+ import { tool } from 'ai';
2
+ import dedent from 'dedent';
3
+ import { z } from 'zod';
4
+ import { extractEndpointDefinition } from "../api/spec-reader.js";
5
+ import { tag } from "../utils/logger.js";
6
+ export function createFishermanTools(apiClient, requestStore, opts) {
7
+ let finished = false;
8
+ let result = { success: false, summary: '', created: [], failed: [] };
9
+ const getResult = () => result;
10
+ const isFinished = () => finished;
11
+ const tools = {
12
+ getEndpointSpec: tool({
13
+ description: dedent `
14
+ Get the request specification for an endpoint.
15
+ Returns the request body example from a previously captured request, or OpenAPI spec definition.
16
+ Call this before making a request to an endpoint you haven't used before.
17
+ `,
18
+ inputSchema: z.object({
19
+ method: z.enum(['GET', 'POST', 'PUT', 'PATCH', 'DELETE']).describe('HTTP method'),
20
+ path: z.string().describe('Endpoint path, e.g. /suites'),
21
+ }),
22
+ execute: async ({ method, path }) => {
23
+ tag('step').log(`Fisherman: spec lookup ${method} ${path}`);
24
+ const captured = requestStore.findCapturedRequest(method, path);
25
+ if (captured) {
26
+ return {
27
+ source: 'captured',
28
+ method: captured.method,
29
+ path: captured.path,
30
+ status: captured.status,
31
+ requestBody: captured.requestBody || 'no body',
32
+ };
33
+ }
34
+ if (opts.spec) {
35
+ try {
36
+ const definition = extractEndpointDefinition(opts.spec, path, opts.baseEndpoint);
37
+ return { source: 'spec', definition };
38
+ }
39
+ catch (err) {
40
+ return { source: 'none', error: err.message };
41
+ }
42
+ }
43
+ return { source: 'none', error: `No spec found for ${method} ${path}` };
44
+ },
45
+ }),
46
+ request: tool({
47
+ description: dedent `
48
+ Make an HTTP request to the API.
49
+ Returns status, timing, and auto-extracted IDs and names from the response.
50
+ `,
51
+ inputSchema: z.object({
52
+ method: z.enum(['GET', 'POST', 'PUT', 'PATCH', 'DELETE']).describe('HTTP method'),
53
+ path: z.string().describe('API path (e.g., /suites, /suites/1)'),
54
+ body: z.any().optional().describe('Request body (JSON object)'),
55
+ queryParams: z.record(z.string(), z.string()).optional().describe('Query parameters'),
56
+ }),
57
+ execute: async (input) => {
58
+ tag('step').log(`Fisherman: ${input.method} ${input.path}`);
59
+ const reqResult = await apiClient.request({
60
+ method: input.method,
61
+ path: input.path,
62
+ body: input.body,
63
+ queryParams: input.queryParams,
64
+ });
65
+ requestStore.addMadeRequest(reqResult);
66
+ if (reqResult.error) {
67
+ tag('error').log(`Fisherman: ${input.method} ${input.path} > Network error: ${reqResult.error}`);
68
+ return { success: false, error: reqResult.error };
69
+ }
70
+ const statusLine = `${reqResult.status} ${reqResult.statusText}`;
71
+ if (reqResult.status >= 400) {
72
+ tag('error').log(`Fisherman: ${input.method} ${input.path} > ${statusLine}`);
73
+ return {
74
+ success: false,
75
+ status: reqResult.status,
76
+ statusText: reqResult.statusText,
77
+ errorPreview: reqResult.rawResponseBody.substring(0, 300),
78
+ };
79
+ }
80
+ const extracted = extractKeyFields(reqResult.responseBody);
81
+ tag('success').log(`Fisherman: ${input.method} ${input.path} > ${statusLine}`);
82
+ return {
83
+ success: true,
84
+ status: reqResult.status,
85
+ ...extracted,
86
+ };
87
+ },
88
+ }),
89
+ finish: tool({
90
+ description: 'Report completion of data preparation. Call when all requested items have been created.',
91
+ inputSchema: z.object({
92
+ summary: z.string().describe('Summary of what was created'),
93
+ created: z
94
+ .array(z.object({
95
+ type: z.string().describe('Item type (e.g., suite, test, label)'),
96
+ id: z.union([z.string(), z.number()]).optional().describe('Created item ID'),
97
+ title: z.string().optional().describe('Created item name/title'),
98
+ }))
99
+ .describe('List of successfully created items'),
100
+ failed: z
101
+ .array(z.object({
102
+ type: z.string().describe('Item type that failed'),
103
+ reason: z.string().describe('Why it failed'),
104
+ }))
105
+ .optional()
106
+ .describe('List of items that could not be created'),
107
+ }),
108
+ execute: async ({ summary, created, failed }) => {
109
+ tag('success').log(`Fisherman done: ${summary}`);
110
+ finished = true;
111
+ result = { success: true, summary, created, failed: failed || [] };
112
+ return { finished: true };
113
+ },
114
+ }),
115
+ stop: tool({
116
+ description: 'Abort data preparation when it cannot be completed.',
117
+ inputSchema: z.object({
118
+ reason: z.string().describe('Why preparation cannot continue'),
119
+ }),
120
+ execute: async ({ reason }) => {
121
+ tag('warning').log(`Fisherman stopped: ${reason}`);
122
+ finished = true;
123
+ result = { success: false, summary: reason, created: [], failed: [] };
124
+ return { stopped: true };
125
+ },
126
+ }),
127
+ };
128
+ return { tools, getResult, isFinished };
129
+ }
130
+ function extractKeyFields(body, result = {}, depth = 0) {
131
+ if (!body || typeof body !== 'object' || depth > 5)
132
+ return result;
133
+ if (Array.isArray(body)) {
134
+ if (body.length > 0)
135
+ extractKeyFields(body[0], result, depth + 1);
136
+ return result;
137
+ }
138
+ for (const [key, value] of Object.entries(body)) {
139
+ if (value === null || value === undefined)
140
+ continue;
141
+ if (typeof value === 'object') {
142
+ extractKeyFields(value, result, depth + 1);
143
+ continue;
144
+ }
145
+ if (key === 'id' || key === '_id' || key === 'uuid' || key.endsWith('_id')) {
146
+ result[key] ??= value;
147
+ }
148
+ if (key === 'name' || key === 'title' || key === 'status') {
149
+ result[key] ??= String(value).slice(0, 100);
150
+ }
151
+ }
152
+ return result;
153
+ }
154
+ //# sourceMappingURL=fisherman-tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fisherman-tools.js","sourceRoot":"","sources":["../../../src/ai/fisherman-tools.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,184 @@
1
+ import dedent from 'dedent';
2
+ import { listAllEndpoints } from "../api/spec-reader.js";
3
+ import { createDebug, tag } from "../utils/logger.js";
4
+ const debugLog = createDebug('explorbot:fisherman');
5
+ import { loop } from "../utils/loop.js";
6
+ import { createFishermanTools } from "./fisherman-tools.js";
7
+ const MAX_ITERATIONS = 15;
8
+ const MAX_TOOL_ROUNDTRIPS = 5;
9
+ export class Fisherman {
10
+ emoji = '🎣';
11
+ provider;
12
+ apiClient;
13
+ requestStore;
14
+ specLoader;
15
+ cookieProvider;
16
+ configHeaders;
17
+ sessionName;
18
+ baseEndpoint;
19
+ spec = null;
20
+ mode = 'disabled';
21
+ hasApiConfig;
22
+ constructor(provider, apiClient, requestStore, specLoader, baseEndpoint, cookieProvider, configHeaders = {}, hasApiConfig = false) {
23
+ this.provider = provider;
24
+ this.apiClient = apiClient;
25
+ this.requestStore = requestStore;
26
+ this.specLoader = specLoader;
27
+ this.baseEndpoint = baseEndpoint;
28
+ this.cookieProvider = cookieProvider;
29
+ this.configHeaders = configHeaders;
30
+ this.hasApiConfig = hasApiConfig;
31
+ this.mode = hasApiConfig ? 'achieve' : 'replicate';
32
+ }
33
+ isAvailable() {
34
+ return this.mode !== 'disabled';
35
+ }
36
+ getMode() {
37
+ return this.mode;
38
+ }
39
+ async ensureReady(scopeUrl) {
40
+ await this.detectMode(scopeUrl);
41
+ this.spec ??= await this.specLoader();
42
+ debugLog(`ensureReady: mode=${this.mode}, scope=${scopeUrl}`);
43
+ }
44
+ getEndpointList(scopeUrl) {
45
+ return this.buildEndpointList(scopeUrl);
46
+ }
47
+ async prepareData(instructions, scopeUrl, sessionName) {
48
+ this.sessionName = sessionName;
49
+ tag('info').log(`Fisherman [${this.mode}]: preparing data — ${instructions}`);
50
+ await this.ensureReady(scopeUrl);
51
+ if (this.mode === 'disabled') {
52
+ debugLog('disabled — no data for scope');
53
+ return { success: false, summary: 'No API data available for this scope', created: [], failed: [] };
54
+ }
55
+ const endpointList = this.buildEndpointList(scopeUrl);
56
+ debugLog(`endpoints:\n${endpointList || '(none)'}`);
57
+ if (!endpointList) {
58
+ tag('warning').log('Fisherman: no endpoints available');
59
+ this.mode = 'disabled';
60
+ return { success: false, summary: 'No API endpoints available', created: [], failed: [] };
61
+ }
62
+ await this.refreshAuth();
63
+ debugLog(`auth headers: ${Object.keys(this.apiClient.getHeaders()).join(', ')}`);
64
+ const { tools, getResult, isFinished } = createFishermanTools(this.apiClient, this.requestStore, {
65
+ spec: this.spec,
66
+ baseEndpoint: this.baseEndpoint,
67
+ });
68
+ const conversation = this.provider.startConversation(this.buildSystemPrompt(endpointList, scopeUrl), 'fisherman');
69
+ conversation.addUserText(this.buildTaskPrompt(instructions));
70
+ await loop(async ({ stop, iteration }) => {
71
+ debugLog(`iteration ${iteration}`);
72
+ const invokeResult = await this.provider.invokeConversation(conversation, tools, {
73
+ maxToolRoundtrips: MAX_TOOL_ROUNDTRIPS,
74
+ toolChoice: 'required',
75
+ agentName: 'fisherman',
76
+ });
77
+ debugLog(`iteration ${iteration} done, text: ${invokeResult?.response?.text?.slice(0, 200) || '(none)'}`);
78
+ if (isFinished()) {
79
+ stop();
80
+ return;
81
+ }
82
+ if (iteration >= MAX_ITERATIONS) {
83
+ tag('warning').log('Fisherman: max iterations reached');
84
+ stop();
85
+ }
86
+ }, {
87
+ maxAttempts: MAX_ITERATIONS,
88
+ observability: {
89
+ name: `fisherman: ${instructions.slice(0, 50)}`,
90
+ agent: 'fisherman',
91
+ sessionId: this.sessionName,
92
+ },
93
+ catch: async ({ error, stop }) => {
94
+ debugLog(`error: ${error.message}`);
95
+ tag('warning').log(`Fisherman error: ${error.message}`);
96
+ stop();
97
+ },
98
+ });
99
+ const result = getResult();
100
+ tag('info').log(`Fisherman result: ${result.summary}`);
101
+ return result;
102
+ }
103
+ async detectMode(scopeUrl) {
104
+ if (this.hasApiConfig) {
105
+ this.mode = 'achieve';
106
+ debugLog('achieve mode — api config present');
107
+ return;
108
+ }
109
+ this.requestStore.loadFromDisk();
110
+ const allRequests = this.requestStore.getCapturedRequests();
111
+ debugLog(`total stored requests: ${allRequests.length}, scope: ${scopeUrl}`);
112
+ if (allRequests.length > 0) {
113
+ this.mode = 'replicate';
114
+ return;
115
+ }
116
+ this.mode = 'disabled';
117
+ }
118
+ async refreshAuth() {
119
+ const cookies = await this.cookieProvider();
120
+ if (Object.keys(cookies).length > 0) {
121
+ this.apiClient.setHeaders(cookies);
122
+ }
123
+ const xhrHeaders = this.requestStore.extractAuthHeaders();
124
+ if (Object.keys(xhrHeaders).length > 0) {
125
+ this.apiClient.setHeaders(xhrHeaders);
126
+ }
127
+ if (Object.keys(this.configHeaders).length > 0) {
128
+ this.apiClient.setHeaders(this.configHeaders);
129
+ }
130
+ }
131
+ buildEndpointList(scopeUrl) {
132
+ if (this.mode === 'achieve' && this.spec) {
133
+ const specEndpoints = listAllEndpoints(this.spec, this.baseEndpoint);
134
+ if (specEndpoints)
135
+ return specEndpoints;
136
+ }
137
+ let writeRequests = this.requestStore.getWriteRequestsForScope(scopeUrl || '/');
138
+ if (writeRequests.length === 0) {
139
+ writeRequests = this.requestStore.getWriteRequestsForScope('/');
140
+ }
141
+ const seen = new Set();
142
+ const lines = [];
143
+ for (const req of writeRequests) {
144
+ const key = `${req.method} ${req.path}`;
145
+ if (seen.has(key))
146
+ continue;
147
+ seen.add(key);
148
+ lines.push(key);
149
+ }
150
+ return lines.join('\n');
151
+ }
152
+ buildSystemPrompt(endpointList, scopeUrl) {
153
+ const scopeBlock = scopeUrl ? `\n\nSCOPE: You are operating within ${scopeUrl}.\nAll created items must belong to this scope.` : '';
154
+ return dedent `
155
+ You are Fisherman — a data preparation agent. You create test data by making API requests.
156
+
157
+ AVAILABLE ENDPOINTS:
158
+ ${endpointList}
159
+ ${scopeBlock}
160
+
161
+ WORKFLOW:
162
+ 1. Call getEndpointSpec to see the request body example for the endpoint
163
+ 2. Make requests — the response automatically extracts IDs, names, and status fields
164
+ 3. Use extracted IDs to chain requests (e.g., create suite, use its id to create tests in it)
165
+ 4. Call finish with a summary and IDs of all created items
166
+
167
+ RULES:
168
+ - Always call getEndpointSpec before your first request to an unfamiliar endpoint
169
+ - Chain requests logically — create parent resources before children
170
+ - If a request fails, try once more with adjusted data before reporting failure
171
+ - Use realistic but unique data for each item (vary names, titles)
172
+ `;
173
+ }
174
+ buildTaskPrompt(instructions) {
175
+ return dedent `
176
+ Prepare the following test data:
177
+
178
+ ${instructions}
179
+
180
+ Execute the necessary API requests to create this data. When done, call finish with the summary.
181
+ `;
182
+ }
183
+ }
184
+ //# sourceMappingURL=fisherman.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fisherman.js","sourceRoot":"","sources":["../../../src/ai/fisherman.ts"],"names":[],"mappings":"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"}