explorbot 0.1.31 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (288) hide show
  1. package/README.md +14 -14
  2. package/bin/explorbot-cli.ts +4 -3
  3. package/boat/doc-collector/src/ai/documentarian.ts +22 -27
  4. package/boat/doc-collector/src/ai/tools.ts +67 -10
  5. package/boat/doc-collector/src/docbot.ts +28 -7
  6. package/boat/doc-collector/src/docs-renderer.ts +19 -24
  7. package/boat/doc-collector/src/screenshots.ts +33 -1
  8. package/boat/doc-collector/src/state-diagram.ts +281 -0
  9. package/dist/bin/explorbot-cli.js +3 -3
  10. package/dist/boat/doc-collector/src/ai/documentarian.js +16 -6
  11. package/dist/boat/doc-collector/src/ai/tools.js +47 -10
  12. package/dist/boat/doc-collector/src/docbot.js +25 -6
  13. package/dist/boat/doc-collector/src/docs-renderer.js +18 -3
  14. package/dist/boat/doc-collector/src/screenshots.js +29 -0
  15. package/dist/boat/doc-collector/src/state-diagram.js +200 -0
  16. package/dist/package.json +8 -6
  17. package/dist/src/action-result.d.ts +131 -0
  18. package/dist/src/action-result.js +82 -159
  19. package/dist/src/action.d.ts +43 -0
  20. package/dist/src/action.js +18 -106
  21. package/dist/src/activity.d.ts +26 -0
  22. package/dist/src/ai/agent.d.ts +3 -0
  23. package/dist/src/ai/captain/file-tools.d.ts +28 -0
  24. package/dist/src/ai/captain/idle-mode.d.ts +11 -0
  25. package/dist/src/ai/captain/mixin.d.ts +10 -0
  26. package/dist/src/ai/captain/test-mode.d.ts +13 -0
  27. package/dist/src/ai/captain/web-mode.d.ts +13 -0
  28. package/dist/src/ai/captain/web-mode.js +0 -7
  29. package/dist/src/ai/captain.d.ts +141 -0
  30. package/dist/src/ai/captain.js +4 -19
  31. package/dist/src/ai/conversation.d.ts +28 -0
  32. package/dist/src/ai/conversation.js +9 -28
  33. package/dist/src/ai/driller.d.ts +157 -0
  34. package/dist/src/ai/driller.js +3 -12
  35. package/dist/src/ai/experience-compactor.d.ts +53 -0
  36. package/dist/src/ai/experience-compactor.js +16 -33
  37. package/dist/src/ai/fisherman-tools.d.ts +90 -0
  38. package/dist/src/ai/fisherman-tools.js +1 -1
  39. package/dist/src/ai/fisherman.d.ts +29 -0
  40. package/dist/src/ai/fisherman.js +0 -3
  41. package/dist/src/ai/historian/codeceptjs.d.ts +17 -0
  42. package/dist/src/ai/historian/codeceptjs.js +3 -2
  43. package/dist/src/ai/historian/experience.d.ts +40 -0
  44. package/dist/src/ai/historian/mixin.d.ts +2 -0
  45. package/dist/src/ai/historian/playwright.d.ts +22 -0
  46. package/dist/src/ai/historian/playwright.js +3 -2
  47. package/dist/src/ai/historian/screencast.d.ts +32 -0
  48. package/dist/src/ai/historian/utils.d.ts +3 -0
  49. package/dist/src/ai/historian/utils.js +0 -1
  50. package/dist/src/ai/historian.d.ts +109 -0
  51. package/dist/src/ai/historian.js +1 -5
  52. package/dist/src/ai/navigator.d.ts +54 -0
  53. package/dist/src/ai/navigator.js +11 -46
  54. package/dist/src/ai/pilot.d.ts +81 -0
  55. package/dist/src/ai/pilot.js +6 -17
  56. package/dist/src/ai/planner/session-dedup.d.ts +12 -0
  57. package/dist/src/ai/planner/styles.d.ts +6 -0
  58. package/dist/src/ai/planner/subpages.d.ts +35 -0
  59. package/dist/src/ai/planner.d.ts +79 -0
  60. package/dist/src/ai/planner.js +49 -37
  61. package/dist/src/ai/provider.d.ts +53 -0
  62. package/dist/src/ai/provider.js +78 -130
  63. package/dist/src/ai/quartermaster.d.ts +56 -0
  64. package/dist/src/ai/quartermaster.js +4 -10
  65. package/dist/src/ai/rerunner.d.ts +48 -0
  66. package/dist/src/ai/rerunner.js +14 -22
  67. package/dist/src/ai/researcher/cache.d.ts +6 -0
  68. package/dist/src/ai/researcher/cache.js +11 -18
  69. package/dist/src/ai/researcher/coordinates.d.ts +56 -0
  70. package/dist/src/ai/researcher/deep-analysis.d.ts +74 -0
  71. package/dist/src/ai/researcher/deep-analysis.js +3 -6
  72. package/dist/src/ai/researcher/fingerprint-worker.d.ts +1 -0
  73. package/dist/src/ai/researcher/focus.d.ts +8 -0
  74. package/dist/src/ai/researcher/locators.d.ts +36 -0
  75. package/dist/src/ai/researcher/mixin.d.ts +2 -0
  76. package/dist/src/ai/researcher/parser.d.ts +35 -0
  77. package/dist/src/ai/researcher/parser.js +1 -1
  78. package/dist/src/ai/researcher/research-result.d.ts +15 -0
  79. package/dist/src/ai/researcher/research-result.js +0 -19
  80. package/dist/src/ai/researcher/sections.d.ts +19 -0
  81. package/dist/src/ai/researcher/sections.js +5 -1
  82. package/dist/src/ai/researcher.js +12 -53
  83. package/dist/src/ai/rules.d.ts +16 -0
  84. package/dist/src/ai/rules.js +22 -15
  85. package/dist/src/ai/session-analyst.d.ts +11 -0
  86. package/dist/src/ai/session-analyst.js +8 -5
  87. package/dist/src/ai/task-agent.d.ts +28 -0
  88. package/dist/src/ai/task-agent.js +2 -27
  89. package/dist/src/ai/tester.d.ts +101 -0
  90. package/dist/src/ai/tester.js +10 -61
  91. package/dist/src/ai/tools.d.ts +52 -0
  92. package/dist/src/ai/tools.js +119 -101
  93. package/dist/src/api/api-client.d.ts +17 -0
  94. package/dist/src/api/request-result.d.ts +44 -0
  95. package/dist/src/api/request-store.d.ts +29 -0
  96. package/dist/src/api/spec-reader.d.ts +5 -0
  97. package/dist/src/api/xhr-capture.d.ts +10 -0
  98. package/dist/src/browser-server.d.ts +10 -0
  99. package/dist/src/command-handler.d.ts +68 -0
  100. package/dist/src/commands/add-rule-command.d.ts +11 -0
  101. package/dist/src/commands/base-command.d.ts +26 -0
  102. package/dist/src/commands/clean-command.d.ts +12 -0
  103. package/dist/src/commands/compact-command.d.ts +20 -0
  104. package/dist/src/commands/compact-command.js +6 -6
  105. package/dist/src/commands/context-aria-command.d.ts +6 -0
  106. package/dist/src/commands/context-command.d.ts +11 -0
  107. package/dist/src/commands/context-command.js +1 -1
  108. package/dist/src/commands/context-data-command.d.ts +6 -0
  109. package/dist/src/commands/context-experience-command.d.ts +6 -0
  110. package/dist/src/commands/context-html-command.d.ts +6 -0
  111. package/dist/src/commands/context-knowledge-command.d.ts +6 -0
  112. package/dist/src/commands/context-knowledge-command.js +1 -1
  113. package/dist/src/commands/debug-command.d.ts +6 -0
  114. package/dist/src/commands/drill-command.d.ts +10 -0
  115. package/dist/src/commands/exit-command.d.ts +7 -0
  116. package/dist/src/commands/experience-command.d.ts +15 -0
  117. package/dist/src/commands/experience-command.js +1 -1
  118. package/dist/src/commands/explore-command.d.ts +51 -0
  119. package/dist/src/commands/freesail-command.d.ts +12 -0
  120. package/dist/src/commands/help-command.d.ts +6 -0
  121. package/dist/src/commands/index.d.ts +4 -0
  122. package/dist/src/commands/init-command.d.ts +7 -0
  123. package/dist/src/commands/knows-command.d.ts +10 -0
  124. package/dist/src/commands/knows-command.js +1 -1
  125. package/dist/src/commands/learn-command.d.ts +7 -0
  126. package/dist/src/commands/learn-command.js +3 -1
  127. package/dist/src/commands/navigate-command.d.ts +7 -0
  128. package/dist/src/commands/path-command.d.ts +10 -0
  129. package/dist/src/commands/plan-clear-command.d.ts +7 -0
  130. package/dist/src/commands/plan-command.d.ts +14 -0
  131. package/dist/src/commands/plan-edit-command.d.ts +7 -0
  132. package/dist/src/commands/plan-load-command.d.ts +7 -0
  133. package/dist/src/commands/plan-reload-command.d.ts +7 -0
  134. package/dist/src/commands/plan-save-command.d.ts +7 -0
  135. package/dist/src/commands/plans-command.d.ts +21 -0
  136. package/dist/src/commands/rerun-command.d.ts +7 -0
  137. package/dist/src/commands/research-command.d.ts +11 -0
  138. package/dist/src/commands/runs-command.d.ts +7 -0
  139. package/dist/src/commands/start-command.d.ts +7 -0
  140. package/dist/src/commands/status-command.d.ts +6 -0
  141. package/dist/src/commands/test-command.d.ts +11 -0
  142. package/dist/src/components/ActivityPane.d.ts +6 -0
  143. package/dist/src/components/AddKnowledge.d.ts +10 -0
  144. package/dist/src/components/AddKnowledge.js +3 -7
  145. package/dist/src/components/AddRule.d.ts +9 -0
  146. package/dist/src/components/App.d.ts +9 -0
  147. package/dist/src/components/App.js +2 -2
  148. package/dist/src/components/Autocomplete.d.ts +3 -0
  149. package/dist/src/components/InputPane.d.ts +13 -0
  150. package/dist/src/components/InputReadline.d.ts +17 -0
  151. package/dist/src/components/LogPane.d.ts +6 -0
  152. package/dist/src/components/PlanEditor.d.ts +9 -0
  153. package/dist/src/components/PlanPane.d.ts +13 -0
  154. package/dist/src/components/SessionTimer.d.ts +6 -0
  155. package/dist/src/components/StateTransitionPane.d.ts +8 -0
  156. package/dist/src/components/StatusPane.d.ts +4 -0
  157. package/dist/src/components/TaskPane.d.ts +9 -0
  158. package/dist/src/components/Welcome.d.ts +3 -0
  159. package/dist/src/components/WelcomeChecklist.d.ts +9 -0
  160. package/dist/src/components/WelcomeCommands.d.ts +6 -0
  161. package/dist/src/components/autocomplete-store.d.ts +10 -0
  162. package/dist/src/components/parse-keypress.d.ts +12 -0
  163. package/dist/src/config.d.ts +253 -0
  164. package/dist/src/config.js +12 -0
  165. package/dist/src/execution-controller.d.ts +25 -0
  166. package/dist/src/experience-tracker.d.ts +112 -0
  167. package/dist/src/experience-tracker.js +83 -155
  168. package/dist/src/explorbot.d.ts +106 -0
  169. package/dist/src/explorbot.js +17 -51
  170. package/dist/src/explorer.d.ts +129 -0
  171. package/dist/src/explorer.js +31 -77
  172. package/dist/src/index.d.ts +6 -0
  173. package/dist/src/index.js +2 -55
  174. package/dist/src/knowledge-tracker.d.ts +33 -0
  175. package/dist/src/knowledge-tracker.js +47 -47
  176. package/dist/src/observability.d.ts +13 -0
  177. package/dist/src/observability.js +2 -1
  178. package/dist/src/playwright-recorder.d.ts +31 -0
  179. package/dist/src/reporter.d.ts +34 -0
  180. package/dist/src/state-manager.d.ts +160 -0
  181. package/dist/src/state-manager.js +10 -136
  182. package/dist/src/stats.d.ts +24 -0
  183. package/dist/src/suite.d.ts +24 -0
  184. package/dist/src/test-plan.d.ts +166 -0
  185. package/dist/src/utils/aria.d.ts +25 -0
  186. package/dist/src/utils/aria.js +4 -1
  187. package/dist/src/utils/browser-errors.d.ts +8 -0
  188. package/dist/src/utils/cache.d.ts +15 -0
  189. package/dist/src/utils/cache.js +34 -0
  190. package/dist/src/utils/cli-name.d.ts +1 -0
  191. package/dist/src/utils/code-extractor.d.ts +1 -0
  192. package/dist/src/utils/context-formatter.d.ts +31 -0
  193. package/dist/src/utils/context-formatter.js +15 -27
  194. package/dist/src/utils/error-page.d.ts +12 -0
  195. package/dist/src/utils/expandable.d.ts +4 -0
  196. package/dist/src/utils/hooks-runner.d.ts +15 -0
  197. package/dist/src/utils/html-diff.d.ts +19 -0
  198. package/dist/src/utils/html.d.ts +129 -0
  199. package/dist/src/utils/html.js +71 -0
  200. package/dist/src/utils/log-filters.d.ts +6 -0
  201. package/dist/src/utils/logger.d.ts +35 -0
  202. package/dist/src/utils/loop.d.ts +35 -0
  203. package/dist/src/utils/markdown-files.d.ts +10 -0
  204. package/dist/src/utils/markdown-files.js +21 -0
  205. package/dist/src/utils/markdown-parser.d.ts +17 -0
  206. package/dist/src/utils/markdown-query.d.ts +46 -0
  207. package/dist/src/utils/markdown-query.js +14 -1
  208. package/dist/src/utils/markdown-terminal.d.ts +1 -0
  209. package/dist/src/utils/next-steps.d.ts +11 -0
  210. package/dist/src/utils/page-readiness.d.ts +7 -0
  211. package/dist/src/utils/page-readiness.js +1 -1
  212. package/dist/src/utils/research-parser.d.ts +1 -0
  213. package/dist/src/utils/retry.d.ts +8 -0
  214. package/dist/src/utils/rules-loader.d.ts +12 -0
  215. package/dist/src/utils/secrets.d.ts +4 -0
  216. package/dist/src/utils/secrets.js +28 -0
  217. package/dist/src/utils/step-analyzer.d.ts +11 -0
  218. package/dist/src/utils/strings.d.ts +5 -0
  219. package/dist/src/utils/strings.js +10 -0
  220. package/dist/src/utils/test-files.d.ts +3 -0
  221. package/dist/src/utils/test-plan-markdown.d.ts +9 -0
  222. package/dist/src/utils/throttle.d.ts +2 -0
  223. package/dist/src/utils/unique-names.d.ts +2 -0
  224. package/dist/src/utils/url-matcher.d.ts +6 -0
  225. package/dist/src/utils/web-element.d.ts +45 -0
  226. package/dist/src/utils/web-element.js +3 -0
  227. package/dist/src/utils/web-sandbox.d.ts +4 -0
  228. package/dist/src/utils/web-sandbox.js +37 -0
  229. package/dist/src/utils/xpath.d.ts +17 -0
  230. package/package.json +8 -6
  231. package/src/action-result.ts +80 -168
  232. package/src/action.ts +16 -123
  233. package/src/ai/captain/web-mode.ts +0 -7
  234. package/src/ai/captain.ts +5 -17
  235. package/src/ai/conversation.ts +9 -32
  236. package/src/ai/driller.ts +3 -16
  237. package/src/ai/experience-compactor.ts +16 -35
  238. package/src/ai/fisherman-tools.ts +1 -1
  239. package/src/ai/fisherman.ts +0 -4
  240. package/src/ai/historian/codeceptjs.ts +4 -2
  241. package/src/ai/historian/playwright.ts +4 -2
  242. package/src/ai/historian/utils.ts +0 -1
  243. package/src/ai/historian.ts +4 -7
  244. package/src/ai/navigator.ts +13 -49
  245. package/src/ai/pilot.ts +6 -16
  246. package/src/ai/planner.ts +56 -44
  247. package/src/ai/provider.ts +86 -139
  248. package/src/ai/quartermaster.ts +34 -41
  249. package/src/ai/rerunner.ts +17 -21
  250. package/src/ai/researcher/cache.ts +10 -16
  251. package/src/ai/researcher/deep-analysis.ts +3 -6
  252. package/src/ai/researcher/parser.ts +1 -1
  253. package/src/ai/researcher/research-result.ts +0 -18
  254. package/src/ai/researcher/sections.ts +5 -1
  255. package/src/ai/researcher.ts +11 -59
  256. package/src/ai/rules.ts +24 -13
  257. package/src/ai/session-analyst.ts +8 -5
  258. package/src/ai/task-agent.ts +3 -30
  259. package/src/ai/tester.ts +12 -73
  260. package/src/ai/tools.ts +119 -106
  261. package/src/commands/compact-command.ts +7 -8
  262. package/src/commands/context-command.ts +1 -1
  263. package/src/commands/context-knowledge-command.ts +1 -1
  264. package/src/commands/experience-command.ts +1 -1
  265. package/src/commands/knows-command.ts +1 -1
  266. package/src/commands/learn-command.ts +3 -1
  267. package/src/components/AddKnowledge.tsx +5 -7
  268. package/src/components/App.tsx +2 -2
  269. package/src/config.ts +12 -0
  270. package/src/experience-tracker.ts +90 -152
  271. package/src/explorbot.ts +17 -51
  272. package/src/explorer.ts +34 -81
  273. package/src/index.ts +9 -0
  274. package/src/knowledge-tracker.ts +49 -50
  275. package/src/observability.ts +2 -1
  276. package/src/state-manager.ts +15 -164
  277. package/src/utils/aria.ts +11 -2
  278. package/src/utils/cache.ts +40 -0
  279. package/src/utils/context-formatter.ts +12 -15
  280. package/src/utils/html.ts +79 -0
  281. package/src/utils/markdown-files.ts +30 -0
  282. package/src/utils/markdown-query.ts +15 -1
  283. package/src/utils/page-readiness.ts +1 -1
  284. package/src/utils/secrets.ts +28 -0
  285. package/src/utils/strings.ts +12 -0
  286. package/src/utils/web-element.ts +4 -0
  287. package/src/utils/web-sandbox.ts +43 -0
  288. package/src/index.tsx +0 -62
@@ -1,4 +1,5 @@
1
1
  import { trace } from '@opentelemetry/api';
2
+ import { redactSecrets } from './utils/secrets.js';
2
3
  let current = null;
3
4
  export const Observability = {
4
5
  async run(name, metadata, fn) {
@@ -70,7 +71,7 @@ function buildRootSpanAttributes(name, metadata) {
70
71
  attributes['langfuse.trace.tags'] = metadata.tags;
71
72
  }
72
73
  if (metadata.input !== undefined) {
73
- attributes['langfuse.trace.input'] = JSON.stringify(metadata.input);
74
+ attributes['langfuse.trace.input'] = redactSecrets(JSON.stringify(metadata.input));
74
75
  }
75
76
  return attributes;
76
77
  }
@@ -0,0 +1,31 @@
1
+ export interface TraceCall {
2
+ class: string;
3
+ method: string;
4
+ params: Record<string, any>;
5
+ }
6
+ export interface VerificationStep {
7
+ name: string;
8
+ args: any[];
9
+ }
10
+ export declare class PlaywrightRecorder {
11
+ context: any;
12
+ tracing: any;
13
+ active: boolean;
14
+ nextGroupId: number;
15
+ verifications: VerificationStep[];
16
+ recordVerification(steps: VerificationStep[]): void;
17
+ drainVerifications(): VerificationStep[];
18
+ start(browserContext: any): Promise<void>;
19
+ beginAction(title: string): Promise<string | null>;
20
+ endAction(): Promise<void>;
21
+ exportChunk(): Promise<Map<string, TraceCall[]>>;
22
+ stop(): Promise<void>;
23
+ isActive(): boolean;
24
+ }
25
+ declare function parseTrace(ndjson: string): Map<string, TraceCall[]>;
26
+ export declare function renderCall(call: TraceCall): string;
27
+ export declare function renderAssertion(assertion: {
28
+ name: string;
29
+ args: any[];
30
+ }): string;
31
+ export { parseTrace };
@@ -0,0 +1,34 @@
1
+ import { Client } from '@testomatio/reporter';
2
+ import type { Step } from '@testomatio/reporter/types/types.js';
3
+ import type { ReporterConfig } from './config.js';
4
+ import type { StateManager } from './state-manager.js';
5
+ import { Test } from './test-plan.js';
6
+ export type ReporterMeta = Record<string, string | undefined>;
7
+ export interface ReporterStep {
8
+ title: string;
9
+ status: 'passed' | 'failed';
10
+ code: string[];
11
+ discovery?: string;
12
+ }
13
+ export declare class Reporter {
14
+ client: Client;
15
+ isRunStarted: boolean;
16
+ reporterEnabled: boolean;
17
+ stateManager?: StateManager;
18
+ constructor(config?: ReporterConfig, stateManager?: StateManager);
19
+ buildTitle(): string;
20
+ static resolveEnabled(config?: ReporterConfig): boolean;
21
+ configureHtmlPipe(): void;
22
+ configureMarkdownPipe(): void;
23
+ configureRunGroup(runGroup: string | null | undefined): void;
24
+ startRun(): Promise<void>;
25
+ reportTestStart(test: Test): Promise<void>;
26
+ combineStepsAndNotes(test: Test, lastScreenshotFile?: string): Step[];
27
+ buildVerificationStep(test: Test, lastScreenshotFile?: string): Step | undefined;
28
+ reportTest(test: Test, meta?: ReporterMeta): Promise<void>;
29
+ finishRun(): Promise<void>;
30
+ isEnabled(): boolean;
31
+ setRunDescription(text: string): Promise<void>;
32
+ extractLastNoteMessage(test: Test): string;
33
+ reportSteps(test: Test, steps: ReporterStep[]): Promise<void>;
34
+ }
@@ -0,0 +1,160 @@
1
+ import { ActionResult } from './action-result.js';
2
+ import type { ExperienceTracker } from './experience-tracker.js';
3
+ import type { KnowledgeTracker, Knowledge } from './knowledge-tracker.js';
4
+ export interface Link {
5
+ title: string;
6
+ url: string;
7
+ visible?: boolean;
8
+ }
9
+ export interface WebPageState {
10
+ /** Unique incremental state identifier */
11
+ id?: number;
12
+ /** URL path without domain, including hash: /path/to/page#section */
13
+ url: string;
14
+ /** Page title */
15
+ title?: string;
16
+ /** HTTP status of the main document navigation */
17
+ httpStatus?: number;
18
+ /** Full URL for reference */
19
+ fullUrl?: string;
20
+ /** Timestamp when state was captured */
21
+ timestamp?: Date;
22
+ /** Hash of the state for unique identification */
23
+ hash?: string;
24
+ /** HTML file path */
25
+ htmlFile?: string;
26
+ /** Screenshot file path */
27
+ screenshotFile?: string;
28
+ /** Log file path */
29
+ logFile?: string;
30
+ /** HTML content */
31
+ html?: string;
32
+ notes?: string[];
33
+ /** Page headings */
34
+ h1?: string;
35
+ h2?: string;
36
+ h3?: string;
37
+ h4?: string;
38
+ ariaSnapshot?: string | null;
39
+ ariaSnapshotFile?: string;
40
+ links?: Link[];
41
+ verifications?: Record<string, boolean>;
42
+ }
43
+ export interface StateTransition {
44
+ /** Previous state (null if this is the first state) */
45
+ fromState: WebPageState | null;
46
+ /** Current state */
47
+ toState: WebPageState;
48
+ /** Code block that caused the transition */
49
+ codeBlock: string;
50
+ /** Timestamp of the transition */
51
+ timestamp: Date;
52
+ /** Any error that occurred during transition */
53
+ error?: string;
54
+ /** What triggered the state change */
55
+ trigger: 'manual' | 'navigation' | 'automatic';
56
+ }
57
+ export type StateChangeListener = (event: StateTransition) => void;
58
+ export type { Knowledge };
59
+ export declare class StateManager {
60
+ currentState: WebPageState | null;
61
+ stateHistory: StateTransition[];
62
+ allVisitedUrls: Set<string>;
63
+ stateChangeListeners: StateChangeListener[];
64
+ experienceTracker: ExperienceTracker;
65
+ knowledgeTracker: KnowledgeTracker;
66
+ nextStateId: number;
67
+ constructor(experienceTracker: ExperienceTracker, knowledgeTracker: KnowledgeTracker);
68
+ getExperienceTracker(): ExperienceTracker;
69
+ getKnowledgeTracker(): KnowledgeTracker;
70
+ /**
71
+ * Subscribe to state change events
72
+ */
73
+ onStateChange(listener: StateChangeListener): () => void;
74
+ /**
75
+ * Emit state change event to all listeners
76
+ */
77
+ emitStateChange(event: StateTransition): void;
78
+ /**
79
+ * Update current state from ActionResult and record transition if state changed
80
+ */
81
+ updateState(actionResult: ActionResult, codeBlock?: string, trigger?: 'manual' | 'navigation' | 'automatic'): WebPageState;
82
+ /**
83
+ * Update state from basic data (for navigation events)
84
+ */
85
+ updateStateFromBasic(url: string, title?: string, trigger?: 'manual' | 'navigation' | 'automatic'): WebPageState;
86
+ hasDialogAppeared(previousState: WebPageState | null, newState: WebPageState): boolean;
87
+ /**
88
+ * Generate a basic hash for state comparison
89
+ */
90
+ generateBasicHash(url: string, title?: string): string;
91
+ /**
92
+ * Get current state
93
+ */
94
+ getCurrentState(): WebPageState | null;
95
+ /**
96
+ * Check if state has changed since a given state
97
+ */
98
+ hasStateChanged(previousState: WebPageState | null): boolean;
99
+ /**
100
+ * Compare two states by their hash
101
+ */
102
+ statesEqual(state1: WebPageState | null, state2: WebPageState | null): boolean;
103
+ /**
104
+ * Get state history
105
+ */
106
+ getStateHistory(): StateTransition[];
107
+ isInDeadLoop(): boolean;
108
+ /**
109
+ * Get the last N transitions
110
+ */
111
+ getRecentTransitions(count?: number): StateTransition[];
112
+ /**
113
+ * Get relevant knowledge files for current state
114
+ */
115
+ getRelevantKnowledge(): Knowledge[];
116
+ /**
117
+ * Get relevant experience files for current state
118
+ */
119
+ getRelevantExperience(): string[];
120
+ /**
121
+ * Get all context for current state (knowledge + experience)
122
+ */
123
+ /**
124
+ * Check if we've been in this state before
125
+ */
126
+ hasVisitedState(path: string): boolean;
127
+ getAllVisitedUrls(): Set<string>;
128
+ /**
129
+ * Get how many times we've visited a specific path
130
+ */
131
+ getVisitCount(path: string): number;
132
+ /**
133
+ * Find the most recent transition to a specific path
134
+ */
135
+ getLastVisitToPath(path: string): StateTransition | null;
136
+ /**
137
+ * Get previous state from history for comparison.
138
+ * If the last transition changed URL, returns the fromState (for URL change detection).
139
+ * Otherwise returns the most recent toState with content (for diffing).
140
+ */
141
+ /**
142
+ * Clear state history (useful for testing or reset)
143
+ * Note: This preserves the current state, only clears navigation history
144
+ */
145
+ clearHistory(): void;
146
+ /**
147
+ * Get the number of active state change listeners
148
+ */
149
+ getListenerCount(): number;
150
+ /**
151
+ * Clear all state change listeners
152
+ */
153
+ clearListeners(): void;
154
+ /**
155
+ * Complete cleanup of the StateManager instance
156
+ * Clears all state, history, listeners, and caches
157
+ */
158
+ cleanup(): void;
159
+ }
160
+ export declare function normalizeUrl(url: string): string;
@@ -1,41 +1,27 @@
1
- import { existsSync, readFileSync, readdirSync } from 'node:fs';
2
- import { dirname, join } from 'node:path';
3
- import matter from 'gray-matter';
4
1
  import { ActionResult } from './action-result.js';
5
- import { ConfigParser, outputPath } from './config.js';
6
- import { ExperienceTracker } from './experience-tracker.js';
7
2
  import { detectFocusArea } from './utils/aria.js';
8
- import { htmlTextSnapshot } from './utils/html.js';
9
3
  import { createDebug } from './utils/logger.js';
4
+ import { slugify } from './utils/strings.js';
10
5
  import { extractStatePath } from './utils/url-matcher.js';
11
6
  const debugLog = createDebug('explorbot:state');
12
7
  export class StateManager {
13
8
  currentState = null;
14
9
  stateHistory = [];
15
10
  allVisitedUrls = new Set();
16
- knowledgeCache = [];
17
- lastKnowledgeScan = null;
18
11
  stateChangeListeners = [];
19
12
  experienceTracker;
20
- knowledgeDir;
13
+ knowledgeTracker;
21
14
  nextStateId = 1;
22
- constructor() {
23
- this.experienceTracker = new ExperienceTracker();
24
- const configParser = ConfigParser.getInstance();
25
- const config = configParser.getConfig();
26
- const configPath = configParser.getConfigPath();
27
- // Resolve knowledge directory relative to the config file location (project root)
28
- if (configPath) {
29
- const projectRoot = dirname(configPath);
30
- this.knowledgeDir = join(projectRoot, config.dirs?.knowledge || 'knowledge');
31
- }
32
- else {
33
- this.knowledgeDir = config.dirs?.knowledge || 'knowledge';
34
- }
15
+ constructor(experienceTracker, knowledgeTracker) {
16
+ this.experienceTracker = experienceTracker;
17
+ this.knowledgeTracker = knowledgeTracker;
35
18
  }
36
19
  getExperienceTracker() {
37
20
  return this.experienceTracker;
38
21
  }
22
+ getKnowledgeTracker() {
23
+ return this.knowledgeTracker;
24
+ }
39
25
  /**
40
26
  * Subscribe to state change events
41
27
  */
@@ -53,12 +39,6 @@ export class StateManager {
53
39
  * Emit state change event to all listeners
54
40
  */
55
41
  emitStateChange(event) {
56
- // Log HTML content when state changes
57
- if (event.toState.html && event.toState.html !== event.fromState?.html) {
58
- let htmlContent = event?.toState?.html ?? '';
59
- htmlContent = htmlTextSnapshot(htmlContent);
60
- // tag('html').log(`Page HTML for ${event.toState.url}:\n${htmlContent}`);
61
- }
62
42
  this.stateChangeListeners.forEach((listener) => {
63
43
  try {
64
44
  listener(event);
@@ -68,11 +48,6 @@ export class StateManager {
68
48
  }
69
49
  });
70
50
  }
71
- /**
72
- * Extract state path from full URL
73
- * Removes domain, port, protocol
74
- * Keeps path, query, and hash: /path/to/page?tab=users#section
75
- */
76
51
  /**
77
52
  * Update current state from ActionResult and record transition if state changed
78
53
  */
@@ -148,13 +123,7 @@ export class StateManager {
148
123
  if (title) {
149
124
  parts.push(`title_${title}`);
150
125
  }
151
- return parts
152
- .join('_')
153
- .replace(/[^a-zA-Z0-9_]/g, '_')
154
- .replace(/_+/g, '_')
155
- .replace(/^_|_$/g, '')
156
- .toLowerCase()
157
- .substring(0, 200);
126
+ return slugify(parts.join('_')).substring(0, 200);
158
127
  }
159
128
  /**
160
129
  * Get current state
@@ -233,57 +202,14 @@ export class StateManager {
233
202
  getRecentTransitions(count = 5) {
234
203
  return this.stateHistory.slice(-count);
235
204
  }
236
- /**
237
- * Scan knowledge directory for .md files and cache them
238
- */
239
- scanKnowledgeFiles() {
240
- const now = new Date();
241
- // Only rescan every 30 seconds to avoid excessive file I/O
242
- if (this.lastKnowledgeScan && now.getTime() - this.lastKnowledgeScan.getTime() < 30000) {
243
- return;
244
- }
245
- this.knowledgeCache = [];
246
- if (!existsSync(this.knowledgeDir)) {
247
- debugLog(`Knowledge directory not found: ${this.knowledgeDir}`);
248
- return;
249
- }
250
- try {
251
- const files = readdirSync(this.knowledgeDir, { recursive: true })
252
- .filter((file) => typeof file === 'string' && file.endsWith('.md'))
253
- .map((file) => join(this.knowledgeDir, file));
254
- for (const filePath of files) {
255
- try {
256
- const fileContent = readFileSync(filePath, 'utf8');
257
- const parsed = matter(fileContent);
258
- const urlPattern = parsed.data.url || parsed.data.path || '*';
259
- this.knowledgeCache.push({
260
- filePath,
261
- url: urlPattern,
262
- ...parsed.data,
263
- content: parsed.content,
264
- });
265
- debugLog(`Loaded knowledge file: ${filePath} (pattern: ${urlPattern})`);
266
- }
267
- catch (error) {
268
- debugLog(`Failed to load knowledge file ${filePath}:`, error);
269
- }
270
- }
271
- this.lastKnowledgeScan = now;
272
- debugLog(`Scanned ${this.knowledgeCache.length} knowledge files`);
273
- }
274
- catch (error) {
275
- debugLog('Failed to scan knowledge directory:', error);
276
- }
277
- }
278
205
  /**
279
206
  * Get relevant knowledge files for current state
280
207
  */
281
208
  getRelevantKnowledge() {
282
209
  if (!this.currentState)
283
210
  return [];
284
- this.scanKnowledgeFiles();
285
211
  const actionResult = ActionResult.fromState(this.currentState);
286
- return this.knowledgeCache.filter((knowledge) => actionResult.isMatchedBy(knowledge));
212
+ return this.knowledgeTracker.getRelevantKnowledge(actionResult);
287
213
  }
288
214
  /**
289
215
  * Get relevant experience files for current state
@@ -298,17 +224,6 @@ export class StateManager {
298
224
  /**
299
225
  * Get all context for current state (knowledge + experience)
300
226
  */
301
- getCurrentContext() {
302
- if (!this.currentState) {
303
- throw new Error('No current state available');
304
- }
305
- return {
306
- state: this.currentState,
307
- knowledge: this.getRelevantKnowledge(),
308
- experience: this.getRelevantExperience(),
309
- recentTransitions: this.getRecentTransitions(),
310
- };
311
- }
312
227
  /**
313
228
  * Check if we've been in this state before
314
229
  */
@@ -340,41 +255,6 @@ export class StateManager {
340
255
  * If the last transition changed URL, returns the fromState (for URL change detection).
341
256
  * Otherwise returns the most recent toState with content (for diffing).
342
257
  */
343
- getPreviousState() {
344
- if (this.stateHistory.length === 0)
345
- return null;
346
- const lastTransition = this.stateHistory[this.stateHistory.length - 1];
347
- if (lastTransition.fromState?.url !== lastTransition.toState?.url) {
348
- return lastTransition.fromState;
349
- }
350
- for (let i = this.stateHistory.length - 1; i >= 0; i--) {
351
- const toState = this.stateHistory[i].toState;
352
- if (!toState)
353
- continue;
354
- if (toState.id === this.currentState?.id)
355
- continue;
356
- if (toState.html || toState.ariaSnapshot) {
357
- return toState;
358
- }
359
- }
360
- return null;
361
- }
362
- /**
363
- * Load HTML content from file
364
- */
365
- loadHtmlFromFile(htmlFile) {
366
- try {
367
- const filePath = outputPath('states', htmlFile);
368
- if (existsSync(filePath)) {
369
- return readFileSync(filePath, 'utf8');
370
- }
371
- return null;
372
- }
373
- catch (error) {
374
- debugLog('Failed to load HTML from file:', error);
375
- return null;
376
- }
377
- }
378
258
  /**
379
259
  * Clear state history (useful for testing or reset)
380
260
  * Note: This preserves the current state, only clears navigation history
@@ -405,13 +285,7 @@ export class StateManager {
405
285
  this.stateHistory = [];
406
286
  this.allVisitedUrls.clear();
407
287
  this.stateChangeListeners = [];
408
- this.knowledgeCache = [];
409
- this.lastKnowledgeScan = null;
410
288
  this.nextStateId = 1;
411
- // Clean up experience tracker if it has cleanup method
412
- if (this.experienceTracker && typeof this.experienceTracker.cleanup === 'function') {
413
- this.experienceTracker.cleanup();
414
- }
415
289
  debugLog('StateManager cleanup completed');
416
290
  }
417
291
  }
@@ -0,0 +1,24 @@
1
+ interface TokenUsage {
2
+ input: number;
3
+ output: number;
4
+ total: number;
5
+ cached?: number;
6
+ }
7
+ export type ExplorbotMode = 'explore' | 'test' | 'freesail' | 'tui';
8
+ export declare class Stats {
9
+ static startTime: number;
10
+ static sessionName: string;
11
+ static researches: number;
12
+ static tests: number;
13
+ static plans: number;
14
+ static mode?: ExplorbotMode;
15
+ static focus?: string;
16
+ static models: Record<string, TokenUsage>;
17
+ static recordTokens(_agent: string, model: string, usage: TokenUsage): void;
18
+ static getElapsedTime(): string;
19
+ static humanizeTokens(num: number): string;
20
+ static modelsTable(roleModels: Record<string, string>): string;
21
+ static hasActivity(): boolean;
22
+ static sessionLabel(): string;
23
+ }
24
+ export {};
@@ -0,0 +1,24 @@
1
+ export declare class Suite {
2
+ readonly url: string;
3
+ _automatedTests: AutomatedTest[] | null;
4
+ _plannedScenarios: string[] | null;
5
+ constructor(url: string);
6
+ getAutomatedTests(): AutomatedTest[];
7
+ getPlannedScenarios(): string[];
8
+ getActiveScenarioTitles(): Set<string>;
9
+ get automatedTestCount(): number;
10
+ getAutomatedTestNames(): string[];
11
+ getAutomatedTestFiles(): string[];
12
+ loadAutomatedTests(): AutomatedTest[];
13
+ parseTestFile(filePath: string): {
14
+ url: string;
15
+ tests: AutomatedTest[];
16
+ } | null;
17
+ loadPlannedScenarios(): string[];
18
+ }
19
+ interface AutomatedTest {
20
+ title: string;
21
+ pending: boolean;
22
+ file: string;
23
+ }
24
+ export {};
@@ -0,0 +1,166 @@
1
+ import { WebPageState } from './state-manager.js';
2
+ export declare const TestResult: {
3
+ readonly PASSED: "passed";
4
+ readonly FAILED: "failed";
5
+ readonly SKIPPED: "skipped";
6
+ };
7
+ export type TestResultType = (typeof TestResult)[keyof typeof TestResult] | null;
8
+ export declare const TestStatus: {
9
+ readonly PENDING: "pending";
10
+ readonly IN_PROGRESS: "in_progress";
11
+ readonly DONE: "done";
12
+ };
13
+ export type TestStatusType = (typeof TestStatus)[keyof typeof TestStatus];
14
+ export interface Note {
15
+ message: string;
16
+ status?: TestResultType;
17
+ startTime: number;
18
+ endTime: number;
19
+ screenshot?: string;
20
+ log?: string;
21
+ }
22
+ export declare class ActiveNote {
23
+ task: Task;
24
+ startTime: number;
25
+ message: string;
26
+ status?: TestResultType;
27
+ screenshot?: string;
28
+ log?: string;
29
+ constructor(task: Task, message: string, status?: TestResultType);
30
+ commit(finalStatus?: TestResultType): void;
31
+ getMessage(): string;
32
+ getStartTime(): number;
33
+ }
34
+ export interface StepData {
35
+ text: string;
36
+ duration?: number;
37
+ status?: string;
38
+ error?: string;
39
+ log?: string;
40
+ artifacts?: string[];
41
+ noteStartTime?: number;
42
+ }
43
+ export declare class Task {
44
+ id: string;
45
+ description: string;
46
+ notes: Record<string, Note>;
47
+ steps: Record<string, StepData>;
48
+ states: WebPageState[];
49
+ startUrl: string;
50
+ verification?: Verification;
51
+ timestampCounter: number;
52
+ activeNote?: ActiveNote;
53
+ constructor(description: string, startUrl?: string);
54
+ startNote(message: string, status?: TestResultType): ActiveNote;
55
+ finishNote(activeNote: ActiveNote, endTime: number, finalStatus?: TestResultType): void;
56
+ getPrintableNotes(): string[];
57
+ notesToString(): string;
58
+ addNote(message: string, status?: TestResultType, screenshot?: string, log?: string): void;
59
+ addUrlNote(state: UrlNoteState, prevState?: {
60
+ title?: string;
61
+ h1?: string;
62
+ h2?: string;
63
+ }): void;
64
+ addState(state: WebPageState): void;
65
+ addStep(text: string, duration?: number, status?: string, error?: string, log?: string, artifacts?: string[]): void;
66
+ setActiveNoteScreenshot(screenshotFile?: string): void;
67
+ setVerification(message: string, status: TestResultType, state?: UrlNoteState): void;
68
+ addVerificationDetail(detail: string): void;
69
+ getLog(): Array<{
70
+ type: 'step' | 'note' | 'artifact';
71
+ content: string;
72
+ timestamp: number;
73
+ }>;
74
+ getLogString(): string;
75
+ getRunResult(): 'success' | 'partial' | 'failed';
76
+ }
77
+ export declare class Test extends Task {
78
+ scenario: string;
79
+ sessionName?: string;
80
+ status: TestStatusType;
81
+ result: TestResultType;
82
+ priority: 'critical' | 'important' | 'high' | 'normal' | 'low';
83
+ expected: string[];
84
+ plannedSteps: string[];
85
+ plan?: Plan;
86
+ summary: string;
87
+ artifacts: Record<string, string>;
88
+ generatedCode?: string;
89
+ style?: string;
90
+ planIteration: number;
91
+ enabled: boolean;
92
+ startTime?: number;
93
+ endTime?: number;
94
+ resetCount: number;
95
+ constructor(scenario: string, priority: 'critical' | 'important' | 'high' | 'normal' | 'low', expectedOutcome: string | string[], startUrl: string, plannedSteps?: string[]);
96
+ getVisitedUrls({ localOnly }?: {
97
+ localOnly?: boolean;
98
+ }): string[];
99
+ addArtifact(artifact?: string): void;
100
+ get hasFinished(): boolean;
101
+ get isSuccessful(): boolean;
102
+ get hasFailed(): boolean;
103
+ get isSkipped(): boolean;
104
+ getCheckedNotes(): Note[];
105
+ getCheckedExpectations(): string[];
106
+ hasAchievedAny(): boolean;
107
+ getRunResult(): 'success' | 'partial' | 'failed';
108
+ hasAchievedAll(): boolean;
109
+ isComplete(): boolean;
110
+ start(): void;
111
+ finish(result?: TestResultType): void;
112
+ getDurationMs(): number | null;
113
+ getRemainingExpectations(): string[];
114
+ getLog(): Array<{
115
+ type: 'step' | 'note' | 'artifact';
116
+ content: string;
117
+ timestamp: number;
118
+ }>;
119
+ }
120
+ type PlanChangeListener = (tests: Test[]) => void;
121
+ export declare class Plan {
122
+ title: string;
123
+ tests: Test[];
124
+ url?: string;
125
+ iteration: number;
126
+ parentPlan?: Plan;
127
+ changeListeners: PlanChangeListener[];
128
+ constructor(title: string);
129
+ nextIteration(): void;
130
+ addTest(test: Test): void;
131
+ removeTest(test: Test): void;
132
+ onTestsChange(listener: PlanChangeListener): () => void;
133
+ notifyChange(): void;
134
+ getAllTests(): Test[];
135
+ listTests(): Test[];
136
+ getPendingTests(): Test[];
137
+ get isComplete(): boolean;
138
+ get allSuccessful(): boolean;
139
+ get allFailed(): boolean;
140
+ updateStatus(): void;
141
+ static fromMarkdown(filePath: string): Plan;
142
+ saveToMarkdown(filePath: string): void;
143
+ static saveMultipleToMarkdown(plans: Plan[], filePath: string): void;
144
+ getVisitedPages(): WebPageState[];
145
+ merge(otherPlan: Plan): Plan;
146
+ toAiContext(options?: {
147
+ skipSteps?: boolean;
148
+ }): string;
149
+ }
150
+ interface Verification {
151
+ message: string;
152
+ status: TestResultType;
153
+ screenshot?: string;
154
+ url?: string;
155
+ pageLabel?: string;
156
+ details: string[];
157
+ }
158
+ interface UrlNoteState {
159
+ url?: string;
160
+ fullUrl?: string;
161
+ title?: string;
162
+ h1?: string;
163
+ h2?: string;
164
+ screenshotFile?: string;
165
+ }
166
+ export {};