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,249 @@
1
+ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
2
+ if (typeof path === "string" && /^\.\.?\//.test(path)) {
3
+ return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
4
+ return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
5
+ });
6
+ }
7
+ return path;
8
+ };
9
+ import { existsSync, mkdirSync, readFileSync, rmSync } from 'node:fs';
10
+ import path, { dirname, join, resolve } from 'node:path';
11
+ import { parseEnv } from 'node:util';
12
+ import { log } from './utils/logger.js';
13
+ const config = {
14
+ playwright: {
15
+ browser: 'chromium',
16
+ url: 'http://localhost:3000',
17
+ },
18
+ ai: {
19
+ model: null,
20
+ },
21
+ };
22
+ export const EXPLORBOT_CONFIG_PATHS = ['explorbot.config.js', 'explorbot.config.mjs', 'explorbot.config.ts'];
23
+ export class ConfigParser {
24
+ static instance;
25
+ config = null;
26
+ configPath = null;
27
+ constructor() { }
28
+ static loadEnv(filePath) {
29
+ const resolved = resolve(filePath);
30
+ if (!existsSync(resolved))
31
+ return;
32
+ Object.assign(process.env, parseEnv(readFileSync(resolved, 'utf8')));
33
+ }
34
+ static getInstance() {
35
+ if (!ConfigParser.instance) {
36
+ ConfigParser.instance = new ConfigParser();
37
+ }
38
+ return ConfigParser.instance;
39
+ }
40
+ async loadConfig(options) {
41
+ if (this.config && !options?.config && !options?.path) {
42
+ return this.config;
43
+ }
44
+ // Store the initial working directory for reference
45
+ if (!process.env.INITIAL_CWD) {
46
+ process.env.INITIAL_CWD = process.cwd();
47
+ }
48
+ const originalCwd = process.cwd();
49
+ if (options?.path) {
50
+ const resolvedWorkingPath = resolve(options.path);
51
+ process.chdir(resolvedWorkingPath);
52
+ }
53
+ ConfigParser.loadEnv('.env');
54
+ try {
55
+ const resolvedPath = options?.config || this.findConfigFile();
56
+ if (!resolvedPath) {
57
+ throw new Error('No configuration file found. Please create explorbot.config.js or explorbot.config.ts');
58
+ }
59
+ const configModule = await this.loadConfigModule(resolvedPath);
60
+ const loadedConfig = configModule.default || configModule;
61
+ if (!loadedConfig) {
62
+ throw new Error('Configuration file is empty or invalid');
63
+ }
64
+ this.config = this.resolveConfig(loadedConfig);
65
+ this.configPath = resolvedPath;
66
+ log(`Configuration loaded from: ${resolvedPath}`);
67
+ // Restore original directory after successful config load
68
+ if (options?.path && originalCwd !== process.cwd()) {
69
+ process.chdir(originalCwd);
70
+ }
71
+ return this.config;
72
+ }
73
+ catch (error) {
74
+ // Restore original directory on error
75
+ if (options?.path && originalCwd !== process.cwd()) {
76
+ process.chdir(originalCwd);
77
+ }
78
+ throw new Error(`Failed to load configuration: ${error}`);
79
+ }
80
+ }
81
+ getConfig() {
82
+ if (!this.config) {
83
+ throw new Error('Configuration not loaded. Call loadConfig() first.');
84
+ }
85
+ return this.config;
86
+ }
87
+ getConfigPath() {
88
+ return this.configPath;
89
+ }
90
+ getOutputDir() {
91
+ const config = this.getConfig();
92
+ const configPath = this.getConfigPath();
93
+ if (!configPath)
94
+ throw new Error('Config path not found');
95
+ return path.join(path.dirname(configPath), config.dirs?.output || 'output');
96
+ }
97
+ getStatesDir() {
98
+ return outputPath('states');
99
+ }
100
+ getPlansDir() {
101
+ return outputPath('plans');
102
+ }
103
+ // For testing purposes only
104
+ static resetForTesting() {
105
+ if (ConfigParser.instance) {
106
+ ConfigParser.instance.config = null;
107
+ ConfigParser.instance.configPath = null;
108
+ }
109
+ }
110
+ // For testing purposes only - sets up minimal default config
111
+ static setupTestConfig() {
112
+ const instance = ConfigParser.getInstance();
113
+ // Create unique directory names for this test run to ensure isolation
114
+ const testId = `${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
115
+ const testBaseDir = join(process.cwd(), 'test-dirs', testId);
116
+ instance.config = {
117
+ playwright: {
118
+ url: 'https://example.com',
119
+ browser: 'chromium',
120
+ show: false,
121
+ },
122
+ ai: {
123
+ model: { modelId: 'test-model', provider: 'test' },
124
+ config: {},
125
+ vision: false,
126
+ },
127
+ dirs: {
128
+ knowledge: join(testBaseDir, 'knowledge'),
129
+ experience: join(testBaseDir, 'experience'),
130
+ output: join(testBaseDir, 'output'),
131
+ },
132
+ };
133
+ instance.configPath = join(testBaseDir, 'test-config');
134
+ }
135
+ // For testing purposes only - get test directories for cleanup
136
+ static getTestDirectories() {
137
+ const instance = ConfigParser.getInstance();
138
+ if (!instance.config?.dirs)
139
+ return [];
140
+ return [instance.config.dirs.knowledge, instance.config.dirs.experience, instance.config.dirs.output, dirname(instance.configPath || '')].filter((dir) => dir?.includes('test-dirs'));
141
+ }
142
+ // For testing purposes only - clean up all test directories
143
+ static cleanupAllTestDirectories() {
144
+ try {
145
+ const testDirsBase = join(process.cwd(), 'test-dirs');
146
+ if (existsSync(testDirsBase)) {
147
+ rmSync(testDirsBase, { recursive: true, force: true });
148
+ }
149
+ }
150
+ catch (error) {
151
+ // Ignore cleanup errors
152
+ }
153
+ }
154
+ findConfigFile() {
155
+ const possiblePaths = [...EXPLORBOT_CONFIG_PATHS, 'config/explorbot.config.js', 'config/explorbot.config.mjs', 'config/explorbot.config.ts', 'src/config/explorbot.config.js', 'src/config/explorbot.config.mjs', 'src/config/explorbot.config.ts'];
156
+ for (const path of possiblePaths) {
157
+ const fullPath = resolve(process.cwd(), path);
158
+ if (existsSync(fullPath)) {
159
+ return fullPath;
160
+ }
161
+ }
162
+ return null;
163
+ }
164
+ async loadConfigModule(configPath) {
165
+ const ext = configPath.split('.').pop();
166
+ if (ext === 'ts') {
167
+ try {
168
+ const module = await import(__rewriteRelativeImportExtension(configPath));
169
+ return module;
170
+ }
171
+ catch (error) {
172
+ const require = (await import('node:module')).createRequire(import.meta.url);
173
+ return require(configPath);
174
+ }
175
+ }
176
+ else if (ext === 'js' || ext === 'mjs') {
177
+ const module = await import(__rewriteRelativeImportExtension(configPath));
178
+ return module;
179
+ }
180
+ else {
181
+ const content = readFileSync(configPath, 'utf8');
182
+ return JSON.parse(content);
183
+ }
184
+ }
185
+ resolveConfig(config) {
186
+ if (config.web?.url && !config.playwright?.url) {
187
+ config.playwright = config.playwright || { browser: 'chromium', url: '' };
188
+ config.playwright.url = config.web.url;
189
+ }
190
+ return config;
191
+ }
192
+ validateConfig(config) {
193
+ if (!config.ai?.model) {
194
+ throw new Error('Missing required configuration field: ai.model');
195
+ }
196
+ const url = config.playwright?.url || config.web?.url;
197
+ if (!url) {
198
+ throw new Error('Missing required configuration: web.url or playwright.url');
199
+ }
200
+ try {
201
+ new URL(url);
202
+ }
203
+ catch {
204
+ throw new Error(`Invalid URL in configuration: ${url}`);
205
+ }
206
+ }
207
+ getNestedValue(obj, path) {
208
+ return path.split('.').reduce((current, key) => current?.[key], obj);
209
+ }
210
+ mergeWithDefaults(config) {
211
+ const defaults = {
212
+ playwright: {
213
+ browser: 'chromium',
214
+ show: false, // we need headless
215
+ },
216
+ action: {
217
+ delay: 1000,
218
+ retries: 3,
219
+ },
220
+ dirs: {
221
+ knowledge: 'knowledge',
222
+ experience: 'experience',
223
+ output: 'output',
224
+ },
225
+ };
226
+ return this.deepMerge(defaults, config);
227
+ }
228
+ deepMerge(target, source) {
229
+ const result = { ...target };
230
+ for (const key in source) {
231
+ if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key]) && source[key].constructor === Object) {
232
+ result[key] = this.deepMerge(result[key] || {}, source[key]);
233
+ }
234
+ else {
235
+ result[key] = source[key];
236
+ }
237
+ }
238
+ return result;
239
+ }
240
+ ensureDirectory(path) {
241
+ if (!existsSync(path)) {
242
+ mkdirSync(path, { recursive: true });
243
+ }
244
+ }
245
+ }
246
+ export function outputPath(...segments) {
247
+ return path.join(ConfigParser.getInstance().getOutputDir(), ...segments);
248
+ }
249
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,92 @@
1
+ import { EventEmitter } from 'node:events';
2
+ import * as readline from 'node:readline';
3
+ import { clearActivity } from "./activity.js";
4
+ export class ExecutionController extends EventEmitter {
5
+ static instance;
6
+ interrupted = false;
7
+ inputCallback = null;
8
+ interruptResolvers = [];
9
+ abortController = null;
10
+ constructor() {
11
+ super();
12
+ }
13
+ static getInstance() {
14
+ if (!ExecutionController.instance) {
15
+ ExecutionController.instance = new ExecutionController();
16
+ }
17
+ return ExecutionController.instance;
18
+ }
19
+ setInputCallback(callback) {
20
+ this.inputCallback = callback;
21
+ }
22
+ startExecution() {
23
+ this.interrupted = false;
24
+ this.abortController = new AbortController();
25
+ }
26
+ getAbortSignal() {
27
+ return this.abortController?.signal;
28
+ }
29
+ interrupt() {
30
+ clearActivity();
31
+ if (this.interrupted)
32
+ return;
33
+ this.interrupted = true;
34
+ this.abortController?.abort();
35
+ this.emit('interrupt');
36
+ for (const resolve of this.interruptResolvers) {
37
+ resolve();
38
+ }
39
+ this.interruptResolvers = [];
40
+ this.emit('idle');
41
+ }
42
+ isInterrupted() {
43
+ return this.interrupted;
44
+ }
45
+ waitForInterrupt() {
46
+ if (this.interrupted) {
47
+ return Promise.resolve();
48
+ }
49
+ return new Promise((resolve) => {
50
+ this.interruptResolvers.push(resolve);
51
+ });
52
+ }
53
+ async checkInterrupt() {
54
+ if (!this.interrupted)
55
+ return null;
56
+ const userInput = await this.requestInput('Execution interrupted. What should we do instead?');
57
+ this.interrupted = false;
58
+ return userInput;
59
+ }
60
+ async handleInterrupt(prompt) {
61
+ const message = prompt || 'Execution interrupted. Enter new instruction (or "stop"/"exit" to cancel):';
62
+ const userInput = await this.requestInput(message);
63
+ this.interrupted = false;
64
+ return userInput;
65
+ }
66
+ async requestInput(prompt) {
67
+ if (this.inputCallback) {
68
+ return await this.inputCallback(prompt);
69
+ }
70
+ return await this.readlineInput(prompt);
71
+ }
72
+ async readlineInput(prompt) {
73
+ const rl = readline.createInterface({
74
+ input: process.stdin,
75
+ output: process.stdout,
76
+ });
77
+ return new Promise((resolve) => {
78
+ rl.question(`${prompt}\n> `, (answer) => {
79
+ rl.close();
80
+ const trimmed = answer.trim();
81
+ resolve(trimmed || null);
82
+ });
83
+ });
84
+ }
85
+ reset() {
86
+ this.interrupted = false;
87
+ this.interruptResolvers = [];
88
+ this.abortController = null;
89
+ }
90
+ }
91
+ export const executionController = ExecutionController.getInstance();
92
+ //# sourceMappingURL=execution-controller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"execution-controller.js","sourceRoot":"","sources":["../../src/execution-controller.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,294 @@
1
+ import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from 'node:fs';
2
+ import { dirname, join } from 'node:path';
3
+ import matter from 'gray-matter';
4
+ import { ConfigParser } from './config.js';
5
+ import { KnowledgeTracker } from './knowledge-tracker.js';
6
+ import { createDebug, tag } from './utils/logger.js';
7
+ import { mdq } from './utils/markdown-query.js';
8
+ import { extractStatePath } from './utils/url-matcher.js';
9
+ const debugLog = createDebug('explorbot:experience');
10
+ const DEFAULT_MAX_EXPERIENCE_LINES = 100;
11
+ export class ExperienceTracker {
12
+ experienceDir;
13
+ disabled;
14
+ knowledgeTracker;
15
+ constructor(options = {}) {
16
+ const configParser = ConfigParser.getInstance();
17
+ const config = configParser.getConfig();
18
+ const configPath = configParser.getConfigPath();
19
+ this.disabled = options.disabled ?? false;
20
+ this.knowledgeTracker = new KnowledgeTracker();
21
+ // Resolve experience directory relative to the config file location (project root)
22
+ if (configPath) {
23
+ const projectRoot = dirname(configPath);
24
+ this.experienceDir = join(projectRoot, config.dirs?.experience || 'experience');
25
+ }
26
+ else {
27
+ this.experienceDir = config.dirs?.experience || 'experience';
28
+ }
29
+ if (!this.disabled) {
30
+ this.ensureDirectory(this.experienceDir);
31
+ }
32
+ }
33
+ getExperienceDirectories() {
34
+ const directories = [this.experienceDir];
35
+ // Also check for experience directory in current working directory
36
+ const cwdExperienceDir = join(process.cwd(), 'experience');
37
+ debugLog('Checking for experience directory in CWD:', cwdExperienceDir);
38
+ debugLog('CWD experience dir exists:', existsSync(cwdExperienceDir));
39
+ debugLog('CWD experience dir different from main:', cwdExperienceDir !== this.experienceDir);
40
+ if (existsSync(cwdExperienceDir) && cwdExperienceDir !== this.experienceDir) {
41
+ directories.push(cwdExperienceDir);
42
+ debugLog('Added CWD experience directory:', cwdExperienceDir);
43
+ }
44
+ // Also check for experience directory in the directory where the script was run from
45
+ // This is useful when running from subdirectories like 'example'
46
+ const scriptCwd = process.env.INITIAL_CWD || process.cwd();
47
+ const scriptExperienceDir = join(scriptCwd, 'experience');
48
+ debugLog('Checking for experience directory in script CWD:', scriptExperienceDir);
49
+ debugLog('Script CWD experience dir exists:', existsSync(scriptExperienceDir));
50
+ if (existsSync(scriptExperienceDir) && scriptExperienceDir !== this.experienceDir && !directories.includes(scriptExperienceDir)) {
51
+ directories.push(scriptExperienceDir);
52
+ debugLog('Added script CWD experience directory:', scriptExperienceDir);
53
+ }
54
+ debugLog('Final experience directories:', directories);
55
+ return directories;
56
+ }
57
+ ensureDirectory(dir) {
58
+ if (this.disabled) {
59
+ return;
60
+ }
61
+ if (!existsSync(dir)) {
62
+ mkdirSync(dir, { recursive: true });
63
+ }
64
+ }
65
+ readExperienceFile(stateHash) {
66
+ const filePath = this.getExperienceFilePath(stateHash);
67
+ const fileContent = readFileSync(filePath, 'utf8');
68
+ const { content, data } = matter(fileContent);
69
+ return { content, data };
70
+ }
71
+ writeExperienceFile(stateHash, content, frontmatter) {
72
+ if (this.disabled) {
73
+ return;
74
+ }
75
+ const filePath = this.getExperienceFilePath(stateHash);
76
+ const fileContent = matter.stringify(content, frontmatter || {});
77
+ writeFileSync(filePath, fileContent, 'utf8');
78
+ }
79
+ hasRecentExperience(stateHash, prefix = '') {
80
+ if (this.disabled) {
81
+ return false;
82
+ }
83
+ if (prefix) {
84
+ stateHash = `${prefix}_${stateHash}`;
85
+ }
86
+ const filePath = this.getExperienceFilePath(stateHash);
87
+ if (!existsSync(filePath)) {
88
+ return false;
89
+ }
90
+ const stats = statSync(filePath);
91
+ return stats.mtime.getTime() > Date.now() - 1000 * 60 * 60 * 24;
92
+ }
93
+ getExperienceFilePath(stateHash) {
94
+ return join(this.experienceDir, `${stateHash}.md`);
95
+ }
96
+ ensureExperienceFile(state) {
97
+ if (this.disabled) {
98
+ return '';
99
+ }
100
+ const stateHash = state.getStateHash();
101
+ const filePath = this.getExperienceFilePath(stateHash);
102
+ if (!existsSync(filePath)) {
103
+ const frontmatter = {
104
+ url: state.url ? extractStatePath(state.url) : '',
105
+ title: state.title,
106
+ };
107
+ this.writeExperienceFile(stateHash, '', frontmatter);
108
+ }
109
+ return filePath;
110
+ }
111
+ updateSummary(state, summary) {
112
+ if (this.disabled)
113
+ return;
114
+ const stateHash = state.getStateHash();
115
+ this.ensureExperienceFile(state);
116
+ const { content, data } = this.readExperienceFile(stateHash);
117
+ data.summary = summary;
118
+ this.writeExperienceFile(stateHash, content, data);
119
+ debugLog(`Updated summary for ${stateHash}`);
120
+ }
121
+ isWritingDisabled(state) {
122
+ return this.knowledgeTracker.getRelevantKnowledge(state).some((k) => k.noExperienceWriting === true || k.noExperienceWriting === 'true');
123
+ }
124
+ async saveSuccessfulResolution(state, originalMessage, code, explanation) {
125
+ if (this.disabled || this.isWritingDisabled(state))
126
+ return;
127
+ this.ensureExperienceFile(state);
128
+ const stateHash = state.getStateHash();
129
+ const { content, data } = this.readExperienceFile(stateHash);
130
+ if (content.includes(code)) {
131
+ debugLog('Skipping duplicate successful resolution', code);
132
+ return;
133
+ }
134
+ const filteredCode = code.replace(/I\.amOnPage\s*\([^)]*\)/gs, '');
135
+ const newEntryContent = `### SUCCEEDED: ${originalMessage.split('\n')[0]}
136
+
137
+ ${explanation ? `Solution: ${explanation}` : ''}
138
+
139
+ \`\`\`javascript
140
+ ${filteredCode}
141
+ \`\`\`
142
+ `;
143
+ const updatedContent = `${newEntryContent}\n\n${content}`;
144
+ this.writeExperienceFile(stateHash, updatedContent, data);
145
+ tag('substep').log(` Added successful resolution to: ${stateHash}.md`);
146
+ }
147
+ getAllExperience() {
148
+ const allFiles = [];
149
+ for (const experienceDir of this.getExperienceDirectories()) {
150
+ if (!existsSync(experienceDir)) {
151
+ continue;
152
+ }
153
+ try {
154
+ const files = readdirSync(experienceDir)
155
+ .filter((file) => file.endsWith('.md'))
156
+ .map((file) => join(experienceDir, file));
157
+ for (const file of files) {
158
+ try {
159
+ const content = readFileSync(file, 'utf8');
160
+ const parsed = matter(content);
161
+ allFiles.push({
162
+ filePath: file,
163
+ data: parsed.data,
164
+ content: parsed.content,
165
+ });
166
+ }
167
+ catch (error) {
168
+ debugLog(`Failed to read experience file ${file}:`, error);
169
+ }
170
+ }
171
+ }
172
+ catch (error) {
173
+ debugLog(`Failed to read experience directory ${experienceDir}:`, error);
174
+ }
175
+ }
176
+ return allFiles;
177
+ }
178
+ getRelevantExperience(state, options) {
179
+ const relevantKnowledge = this.knowledgeTracker.getRelevantKnowledge(state);
180
+ const readingDisabled = relevantKnowledge.some((knowledge) => knowledge.noExperienceReading === true || knowledge.noExperienceReading === 'true');
181
+ if (readingDisabled) {
182
+ return [];
183
+ }
184
+ const config = ConfigParser.getInstance().getConfig();
185
+ const maxLines = config.experience?.maxReadLines ?? DEFAULT_MAX_EXPERIENCE_LINES;
186
+ return this.getAllExperience()
187
+ .filter((experience) => {
188
+ const experienceState = experience.data;
189
+ return state.isRelevantExperienceRecord(experienceState, {
190
+ includeDescendantExperience: options?.includeDescendantExperience,
191
+ });
192
+ })
193
+ .map((experience) => {
194
+ const lines = experience.content.split('\n');
195
+ if (lines.length <= maxLines)
196
+ return experience;
197
+ return { ...experience, content: lines.slice(0, maxLines).join('\n') };
198
+ });
199
+ }
200
+ /**
201
+ * Clean up experience tracker (for testing)
202
+ */
203
+ cleanup() {
204
+ // Clear any in-memory state if needed
205
+ // The actual files will be cleaned up by test cleanup
206
+ }
207
+ saveSessionExperience(state, entry) {
208
+ if (this.disabled || this.isWritingDisabled(state))
209
+ return;
210
+ this.ensureExperienceFile(state);
211
+ const stateHash = state.getStateHash();
212
+ const { content, data } = this.readExperienceFile(stateHash);
213
+ if (entry.relatedUrls?.length) {
214
+ const currentPath = extractStatePath(state.url || '');
215
+ const existingRelated = Array.isArray(data.related) ? data.related : [];
216
+ const allRelated = [...new Set([...existingRelated, ...entry.relatedUrls])];
217
+ data.related = allRelated.filter((url) => url !== currentPath);
218
+ }
219
+ const sessionContent = this.trimSessionContent(this.generateSessionContent(entry));
220
+ if (!sessionContent)
221
+ return;
222
+ const updatedContent = `${sessionContent}\n${content}`;
223
+ this.writeExperienceFile(stateHash, updatedContent, data);
224
+ tag('substep').log(`Added session experience to: ${stateHash}.md`);
225
+ }
226
+ generateSessionContent(entry) {
227
+ let content = `## Successful Flow: ${entry.scenario}\n\n`;
228
+ for (const step of entry.steps) {
229
+ content += `* ${step.message}\n\n`;
230
+ if (step.code) {
231
+ content += '```js\n';
232
+ content += `${step.code}\n`;
233
+ content += '```\n\n';
234
+ }
235
+ if (step.discovery) {
236
+ const discoveries = step.discovery.split('\n').filter((d) => d.trim());
237
+ for (const discovery of discoveries) {
238
+ content += `> ${discovery.trim()}\n\n`;
239
+ }
240
+ }
241
+ }
242
+ content += '---\n';
243
+ return content;
244
+ }
245
+ trimSessionContent(content) {
246
+ const q = mdq(content);
247
+ if (q.query('heading').count() === 0)
248
+ return null;
249
+ if (q.query('code').count() === 0)
250
+ return null;
251
+ let result = content;
252
+ const codeBlocks = q.query('code').each();
253
+ if (codeBlocks.length > 2) {
254
+ for (const block of codeBlocks.slice(2)) {
255
+ result = result.replace(block.text(), '');
256
+ }
257
+ }
258
+ const blockquotes = mdq(result).query('blockquote').each();
259
+ if (blockquotes.length > 5) {
260
+ for (const bq of blockquotes.slice(5)) {
261
+ result = result.replace(bq.text(), '');
262
+ }
263
+ }
264
+ const lines = result.split('\n');
265
+ if (lines.length > 40) {
266
+ result = lines.slice(0, 40).join('\n');
267
+ }
268
+ if (!result.trim())
269
+ return null;
270
+ return result;
271
+ }
272
+ getSuccessfulExperience(state, options) {
273
+ const records = this.getRelevantExperience(state, {
274
+ includeDescendantExperience: options?.includeDescendants,
275
+ });
276
+ const results = [];
277
+ for (const record of records) {
278
+ if (!record.content)
279
+ continue;
280
+ const successFlows = mdq(record.content).query('section(~"Successful Flow")').text();
281
+ const succeeded = mdq(record.content).query('section(~"SUCCEEDED")').text();
282
+ let combined = [successFlows, succeeded].filter(Boolean).join('\n\n');
283
+ if (!combined.trim())
284
+ continue;
285
+ if (options?.stripCode) {
286
+ combined = mdq(combined).query('code').replace('');
287
+ }
288
+ if (combined.trim())
289
+ results.push(combined.trim());
290
+ }
291
+ return results;
292
+ }
293
+ }
294
+ //# sourceMappingURL=experience-tracker.js.map