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
@@ -0,0 +1,157 @@
1
+ import { ActionResult } from '../action-result.js';
2
+ import type { ExperienceTracker } from '../experience-tracker.js';
3
+ import type Explorer from '../explorer.js';
4
+ import type { KnowledgeTracker } from '../knowledge-tracker.js';
5
+ import { Plan, Test } from '../test-plan.js';
6
+ import { HooksRunner } from '../utils/hooks-runner.js';
7
+ import { WebElement } from '../utils/web-element.js';
8
+ import type { Agent } from './agent.js';
9
+ import type { Navigator } from './navigator.js';
10
+ import type { Provider } from './provider.js';
11
+ import { TaskAgent } from './task-agent.js';
12
+ interface ComponentInfo {
13
+ id: string;
14
+ name: string;
15
+ role: string;
16
+ locator: string;
17
+ preferredCode: string;
18
+ eidx: string;
19
+ description: string;
20
+ html: string;
21
+ text: string;
22
+ tag: string;
23
+ classes: string[];
24
+ attrs: Record<string, string>;
25
+ context: string;
26
+ variant: string;
27
+ placeholder: string;
28
+ disabled: boolean;
29
+ ariaMatches: string[];
30
+ }
31
+ interface InteractionResult {
32
+ componentId: string;
33
+ component: string;
34
+ action: string;
35
+ result: 'success' | 'failed' | 'unknown';
36
+ description: string;
37
+ code?: string;
38
+ }
39
+ interface ComponentTest extends Test {
40
+ component?: ComponentInfo;
41
+ interactions?: InteractionResult[];
42
+ }
43
+ interface DrillOptions {
44
+ knowledgePath?: string;
45
+ maxComponents?: number;
46
+ interactive?: boolean;
47
+ }
48
+ export declare class Driller extends TaskAgent implements Agent {
49
+ readonly ACTION_TOOLS: string[];
50
+ emoji: string;
51
+ explorer: Explorer;
52
+ provider: Provider;
53
+ navigator: Navigator;
54
+ hooksRunner: HooksRunner;
55
+ currentPlan?: Plan;
56
+ allResults: InteractionResult[];
57
+ verifiedAction: {
58
+ componentId: string;
59
+ toolName: string;
60
+ code?: string;
61
+ canonicalCode?: string;
62
+ } | null;
63
+ pendingNestedContext: string | null;
64
+ MAX_COMPONENT_ITERATIONS: number;
65
+ constructor(explorer: Explorer, provider: Provider, navigator: Navigator);
66
+ getNavigator(): Navigator;
67
+ getExperienceTracker(): ExperienceTracker;
68
+ getKnowledgeTracker(): KnowledgeTracker;
69
+ getProvider(): Provider;
70
+ getSystemMessage(component?: ComponentInfo): string;
71
+ drill(opts?: DrillOptions): Promise<Plan>;
72
+ captureAnnotatedState(): Promise<ActionResult>;
73
+ collectComponents(state: ActionResult, maxComponents: number): Promise<ComponentInfo[]>;
74
+ toComponentInfo(element: WebElement, ariaNodes: Array<Record<string, unknown>>): ComponentInfo;
75
+ drillComponent(test: ComponentTest, originalState: ActionResult, interactive: boolean): Promise<void>;
76
+ buildComponentPrompt(originalState: ActionResult, component: ComponentInfo): Promise<string>;
77
+ buildContextUpdate(currentState: ActionResult, component: ComponentInfo): Promise<string>;
78
+ createDrillFlowTools(originalState: ActionResult, test: ComponentTest, interactive: boolean): {
79
+ drill_record: import("@ai-sdk/provider-utils").ExecutableTool<import("ai").Tool<{
80
+ action: any;
81
+ result: any;
82
+ code: any;
83
+ }, {
84
+ success: boolean;
85
+ message: string;
86
+ recorded?: undefined;
87
+ } | {
88
+ success: boolean;
89
+ recorded: string;
90
+ message?: undefined;
91
+ }, import("@ai-sdk/provider-utils").Context>>;
92
+ drill_done: import("@ai-sdk/provider-utils").ExecutableTool<import("ai").Tool<{
93
+ summary: any;
94
+ }, {
95
+ success: boolean;
96
+ message: string;
97
+ summary?: undefined;
98
+ recorded?: undefined;
99
+ } | {
100
+ success: boolean;
101
+ summary: any;
102
+ recorded: number;
103
+ message?: undefined;
104
+ }, import("@ai-sdk/provider-utils").Context>>;
105
+ drill_skip: import("@ai-sdk/provider-utils").ExecutableTool<import("ai").Tool<{
106
+ reason: any;
107
+ }, {
108
+ success: boolean;
109
+ message: string;
110
+ skipped?: undefined;
111
+ } | {
112
+ success: boolean;
113
+ skipped: string;
114
+ message?: undefined;
115
+ }, import("@ai-sdk/provider-utils").Context>>;
116
+ drill_restore: import("@ai-sdk/provider-utils").ExecutableTool<import("ai").Tool<{
117
+ reason: any;
118
+ }, {
119
+ success: boolean;
120
+ url: string;
121
+ }, import("@ai-sdk/provider-utils").Context>>;
122
+ drill_ask: import("@ai-sdk/provider-utils").ExecutableTool<import("ai").Tool<{
123
+ question: any;
124
+ }, {
125
+ success: boolean;
126
+ message: string;
127
+ skipped?: undefined;
128
+ userSuggestion?: undefined;
129
+ instruction?: undefined;
130
+ } | {
131
+ success: boolean;
132
+ skipped: boolean;
133
+ message?: undefined;
134
+ userSuggestion?: undefined;
135
+ instruction?: undefined;
136
+ } | {
137
+ success: boolean;
138
+ userSuggestion: string;
139
+ instruction: string;
140
+ message?: undefined;
141
+ skipped?: undefined;
142
+ }, import("@ai-sdk/provider-utils").Context>>;
143
+ };
144
+ restoreOriginalState(originalState: ActionResult, reason: string): Promise<void>;
145
+ saveToExperience(state: ActionResult, results: InteractionResult[]): Promise<void>;
146
+ createVerifiedActionTools(baseTools: Record<string, any>, component: ComponentInfo): Record<string, any>;
147
+ hasVerifiedAction(componentId: string): boolean;
148
+ detectNestedOverlayContext(component: ComponentInfo, result: any): Promise<string | null>;
149
+ getVisibleOverlayHtml(): Promise<string>;
150
+ getComponentScopeHtml(component: ComponentInfo, originalState: ActionResult): Promise<string>;
151
+ saveToKnowledge(knowledgePath: string, state: ActionResult, results: InteractionResult[]): Promise<void>;
152
+ generateKnowledgeContent(state: ActionResult, interactions: InteractionResult[]): string;
153
+ logSummary(): void;
154
+ }
155
+ export declare function buildCanonicalClickCode(component: ComponentInfo): string;
156
+ export declare function formatExperienceTitle(interaction: InteractionResult): string;
157
+ export {};
@@ -11,7 +11,7 @@ import { EXPLORBOT_ATTRS, HTML_COMPOSITE_AREA_HINTS, HTML_COMPOSITE_TARGET_ROLES
11
11
  import { createDebug, tag } from "../utils/logger.js";
12
12
  import { loop, pause } from "../utils/loop.js";
13
13
  import { WebElement } from "../utils/web-element.js";
14
- import { locatorRule } from "./rules.js";
14
+ import { drillLocatorRule } from "./rules.js";
15
15
  import { TaskAgent, isInteractive } from "./task-agent.js";
16
16
  import { createCodeceptJSTools } from "./tools.js";
17
17
  const debugLog = createDebug('explorbot:driller');
@@ -23,7 +23,6 @@ export class Driller extends TaskAgent {
23
23
  navigator;
24
24
  hooksRunner;
25
25
  currentPlan;
26
- currentConversation = null;
27
26
  allResults = [];
28
27
  verifiedAction = null;
29
28
  pendingNestedContext = null;
@@ -245,7 +244,6 @@ export class Driller extends TaskAgent {
245
244
  this.verifiedAction = null;
246
245
  this.pendingNestedContext = null;
247
246
  const conversation = this.provider.startConversation(this.getSystemMessage(component), 'driller');
248
- this.currentConversation = conversation;
249
247
  conversation.addUserText(await this.buildComponentPrompt(originalState, component));
250
248
  let finished = false;
251
249
  const actionTools = this.createVerifiedActionTools(createCodeceptJSTools(this.explorer, test), component);
@@ -506,10 +504,10 @@ export class Driller extends TaskAgent {
506
504
  const targetUrl = originalState.fullUrl || originalState.url;
507
505
  const action = this.explorer.createAction();
508
506
  if (currentState?.url !== originalState.url) {
509
- await action.attempt(`I.amOnPage(${JSON.stringify(targetUrl)})`, `${reason} (restore URL)`, false);
507
+ await action.attempt(`I.amOnPage(${JSON.stringify(targetUrl)})`, `${reason} (restore URL)`);
510
508
  return;
511
509
  }
512
- await action.attempt('I.pressKey("Escape")', `${reason} (restore state)`, false);
510
+ await action.attempt('I.pressKey("Escape")', `${reason} (restore state)`);
513
511
  }
514
512
  async saveToExperience(state, results) {
515
513
  const experienceTracker = this.getExperienceTracker();
@@ -667,12 +665,6 @@ export class Driller extends TaskAgent {
667
665
  tag('step').log(` ${status} ${componentTest.component?.name || test.scenario}`);
668
666
  }
669
667
  }
670
- getCurrentPlan() {
671
- return this.currentPlan;
672
- }
673
- getConversation() {
674
- return this.currentConversation;
675
- }
676
668
  }
677
669
  function formatAriaNode(node) {
678
670
  const role = typeof node.role === 'string' ? node.role : 'unknown';
@@ -1105,4 +1097,3 @@ function isInteractiveElement(element) {
1105
1097
  return true;
1106
1098
  return false;
1107
1099
  }
1108
- const drillLocatorRule = locatorRule.replace(/<context_simplification>[\s\S]*?<\/context_simplification>/, '').trim();
@@ -0,0 +1,53 @@
1
+ import { type ExperienceFile, type ExperienceTracker } from '../experience-tracker.js';
2
+ import type { Agent } from './agent.js';
3
+ import type { Provider } from './provider.js';
4
+ export declare const COMPACT_MAX_LENGTH = 5000;
5
+ interface MergeGroup {
6
+ pattern: string;
7
+ files: ExperienceFile[];
8
+ }
9
+ export declare class ExperienceCompactor implements Agent {
10
+ emoji: string;
11
+ provider: Provider;
12
+ experienceTracker: ExperienceTracker;
13
+ constructor(provider: Provider, experienceTracker: ExperienceTracker);
14
+ compactExperience(experience: string): Promise<string>;
15
+ stripNonUsefulEntries(content: string): string;
16
+ isRecent(file: ExperienceFile): boolean;
17
+ reviewExperienceQuality(content: string, context: {
18
+ url?: string;
19
+ title?: string;
20
+ }): Promise<string>;
21
+ compactAllExperiences(): Promise<{
22
+ merged: number;
23
+ compacted: number;
24
+ }>;
25
+ autocompact(): Promise<{
26
+ merged: number;
27
+ compacted: number;
28
+ }>;
29
+ generalizeDynamicUrls(): number;
30
+ compactFiles(files: ExperienceFile[], options?: {
31
+ skipSmall?: boolean;
32
+ }): Promise<number>;
33
+ mergeSimilarExperiences(options?: {
34
+ onlyDynamic?: boolean;
35
+ }): Promise<number>;
36
+ identifyMergeGroups(files: ExperienceFile[]): Promise<MergeGroup[]>;
37
+ askAiForMergeDecisions(urls: string[]): Promise<{
38
+ urls: string[];
39
+ pattern: string;
40
+ }[]>;
41
+ buildMergePrompt(urls: string[]): string;
42
+ mergeExperienceGroup(group: MergeGroup): Promise<void>;
43
+ getSystemPrompt(): string;
44
+ buildCompactionPrompt(content: string): string;
45
+ buildReviewPrompt(sections: Array<{
46
+ title: string;
47
+ raw: string;
48
+ }>, context: {
49
+ url?: string;
50
+ title?: string;
51
+ }): string;
52
+ }
53
+ export {};
@@ -1,25 +1,26 @@
1
1
  import { unlinkSync } from 'node:fs';
2
+ import { basename } from 'node:path';
2
3
  import dedent from 'dedent';
3
- import { marked } from 'marked';
4
4
  import { z } from 'zod';
5
5
  import { RECENT_WINDOW_DAYS } from '../experience-tracker.js';
6
6
  import { Observability } from '../observability.js';
7
7
  import { createDebug, log, tag } from '../utils/logger.js';
8
8
  import { mdq } from '../utils/markdown-query.js';
9
+ import { isNonReusableCode } from '../utils/step-analyzer.js';
9
10
  import { generalizeUrl, hasDynamicUrlSegment } from '../utils/url-matcher.js';
10
11
  const debugLog = createDebug('explorbot:experience-compactor');
12
+ export const COMPACT_MAX_LENGTH = 5000;
11
13
  export class ExperienceCompactor {
12
14
  emoji = '🗜️';
13
15
  provider;
14
16
  experienceTracker;
15
- MAX_LENGTH = 5000;
16
17
  constructor(provider, experienceTracker) {
17
18
  this.provider = provider;
18
19
  this.experienceTracker = experienceTracker;
19
20
  }
20
21
  async compactExperience(experience) {
21
22
  const stripped = this.stripNonUsefulEntries(experience);
22
- if (stripped.length < this.MAX_LENGTH) {
23
+ if (stripped.length < COMPACT_MAX_LENGTH) {
23
24
  return stripped;
24
25
  }
25
26
  const prompt = this.buildCompactionPrompt(stripped);
@@ -101,7 +102,7 @@ export class ExperienceCompactor {
101
102
  const generalized = generalizeUrl(url);
102
103
  if (generalized === url)
103
104
  continue;
104
- const stateHash = file.filePath.split('/').pop()?.replace('.md', '') || '';
105
+ const stateHash = basename(file.filePath, '.md');
105
106
  const newData = { ...file.data, url: `~${generalized}~`, mergedFrom: [url] };
106
107
  this.experienceTracker.writeExperienceFile(stateHash, file.content, newData);
107
108
  tag('substep').log(`Generalized URL: ${url} → ~${generalized}~`);
@@ -110,7 +111,7 @@ export class ExperienceCompactor {
110
111
  return count;
111
112
  }
112
113
  async compactFiles(files, options) {
113
- const workingSet = options?.skipSmall ? files.filter((f) => f.content.length >= this.MAX_LENGTH) : files;
114
+ const workingSet = options?.skipSmall ? files.filter((f) => f.content.length >= COMPACT_MAX_LENGTH) : files;
114
115
  let compactedCount = 0;
115
116
  const total = workingSet.length;
116
117
  const aiReviewCount = workingSet.filter((f) => this.isRecent(f)).length;
@@ -119,7 +120,7 @@ export class ExperienceCompactor {
119
120
  }
120
121
  for (let i = 0; i < workingSet.length; i++) {
121
122
  const experience = workingSet[i];
122
- const shortName = experience.filePath.split('/').pop() || experience.filePath;
123
+ const shortName = basename(experience.filePath);
123
124
  const willReview = this.isRecent(experience);
124
125
  if (total > 1 && willReview) {
125
126
  tag('substep').log(`[${i + 1}/${total}] reviewing ${shortName}`);
@@ -128,9 +129,9 @@ export class ExperienceCompactor {
128
129
  if (willReview) {
129
130
  content = await this.reviewExperienceQuality(content, experience.data);
130
131
  }
131
- if (content.length >= this.MAX_LENGTH) {
132
+ if (content.length >= COMPACT_MAX_LENGTH) {
132
133
  if (total > 1)
133
- tag('substep').log(`[${i + 1}/${total}] compacting ${shortName} (over ${this.MAX_LENGTH} chars)`);
134
+ tag('substep').log(`[${i + 1}/${total}] compacting ${shortName} (over ${COMPACT_MAX_LENGTH} chars)`);
134
135
  const prompt = this.buildCompactionPrompt(content);
135
136
  const model = this.provider.getModelForAgent('experience-compactor');
136
137
  const response = await this.provider.chat([
@@ -141,7 +142,7 @@ export class ExperienceCompactor {
141
142
  }
142
143
  if (content === experience.content)
143
144
  continue;
144
- const stateHash = experience.filePath.split('/').pop()?.replace('.md', '') || '';
145
+ const stateHash = basename(experience.filePath, '.md');
145
146
  this.experienceTracker.writeExperienceFile(stateHash, content, experience.data);
146
147
  debugLog('Experience file compacted:', experience.filePath);
147
148
  compactedCount++;
@@ -250,7 +251,7 @@ export class ExperienceCompactor {
250
251
  async mergeExperienceGroup(group) {
251
252
  const [targetFile, ...sourceFiles] = group.files;
252
253
  const combinedContent = group.files.map((f) => f.content).join('\n\n---\n\n');
253
- const targetStateHash = targetFile.filePath.split('/').pop()?.replace('.md', '') || '';
254
+ const targetStateHash = basename(targetFile.filePath, '.md');
254
255
  const newFrontmatter = {
255
256
  ...targetFile.data,
256
257
  url: group.pattern,
@@ -283,7 +284,7 @@ export class ExperienceCompactor {
283
284
  <rules>
284
285
  - Use markdown h2 headers only (##) - NO XML tags or wrappers in output
285
286
  - Merge similar flows to remove duplicates
286
- - Keep output under ${this.MAX_LENGTH} characters
287
+ - Keep output under ${COMPACT_MAX_LENGTH} characters
287
288
  - Be explicit and short - no proposals or explanations
288
289
 
289
290
  KEEP only:
@@ -368,27 +369,9 @@ export class ExperienceCompactor {
368
369
  }
369
370
  }
370
371
  function listSections(content) {
371
- const tokens = marked.lexer(content);
372
- const sections = [];
373
- let currentHeading = null;
374
- let currentRaw = '';
375
- const flush = () => {
376
- if (currentHeading !== null)
377
- sections.push({ title: currentHeading, raw: currentRaw });
378
- };
379
- for (const token of tokens) {
380
- const raw = token.raw || '';
381
- if (token.type === 'heading' && token.depth === 2) {
382
- flush();
383
- currentHeading = token.text.trim();
384
- currentRaw = raw;
385
- continue;
386
- }
387
- if (currentHeading !== null)
388
- currentRaw += raw;
389
- }
390
- flush();
391
- return sections;
372
+ const sections = mdq(content).query('section2').each();
373
+ const metas = mdq(content).query('section2').meta();
374
+ return sections.map((q, i) => ({ title: metas[i].text.trim(), raw: q.text() }));
392
375
  }
393
376
  function dropEmptySections(content) {
394
377
  let result = content;
@@ -408,7 +391,7 @@ function dropNonReusableSections(content) {
408
391
  const sections = [...mdq(result).query('section2(~"FLOW:")').each(), ...mdq(result).query('section2(~"ACTION:")').each()];
409
392
  for (const section of sections) {
410
393
  const raw = section.text();
411
- if (!/\bI\.clickXY\s*\(/.test(raw))
394
+ if (!isNonReusableCode(raw))
412
395
  continue;
413
396
  result = result.replace(raw, '');
414
397
  }
@@ -0,0 +1,90 @@
1
+ import type { ApiClient } from '../api/api-client.js';
2
+ import type { RequestStore } from '../api/request-store.js';
3
+ export declare function createFishermanTools(apiClient: ApiClient, requestStore: RequestStore, opts: {
4
+ spec?: any;
5
+ baseEndpoint?: string;
6
+ }): {
7
+ tools: {
8
+ getEndpointSpec: import("@ai-sdk/provider-utils").ExecutableTool<import("ai").Tool<{
9
+ method: any;
10
+ path: any;
11
+ }, {
12
+ source: string;
13
+ method: string;
14
+ path: string;
15
+ status: number;
16
+ requestBody: any;
17
+ definition?: undefined;
18
+ error?: undefined;
19
+ } | {
20
+ source: string;
21
+ definition: string;
22
+ method?: undefined;
23
+ path?: undefined;
24
+ status?: undefined;
25
+ requestBody?: undefined;
26
+ error?: undefined;
27
+ } | {
28
+ source: string;
29
+ error: any;
30
+ method?: undefined;
31
+ path?: undefined;
32
+ status?: undefined;
33
+ requestBody?: undefined;
34
+ definition?: undefined;
35
+ }, import("@ai-sdk/provider-utils").Context>>;
36
+ request: import("@ai-sdk/provider-utils").ExecutableTool<import("ai").Tool<any, {
37
+ success: boolean;
38
+ error: string;
39
+ status?: undefined;
40
+ statusText?: undefined;
41
+ errorPreview?: undefined;
42
+ } | {
43
+ success: boolean;
44
+ status: number;
45
+ statusText: string;
46
+ errorPreview: string;
47
+ error?: undefined;
48
+ } | {
49
+ success: boolean;
50
+ status: number;
51
+ error?: undefined;
52
+ statusText?: undefined;
53
+ errorPreview?: undefined;
54
+ }, import("@ai-sdk/provider-utils").Context>>;
55
+ finish: import("@ai-sdk/provider-utils").ExecutableTool<import("ai").Tool<{
56
+ summary: string;
57
+ created: {
58
+ type: string;
59
+ id?: string | number;
60
+ title?: string;
61
+ }[];
62
+ failed?: {
63
+ type: string;
64
+ reason: string;
65
+ }[];
66
+ }, {
67
+ finished: boolean;
68
+ }, import("@ai-sdk/provider-utils").Context>>;
69
+ stop: import("@ai-sdk/provider-utils").ExecutableTool<import("ai").Tool<{
70
+ reason: any;
71
+ }, {
72
+ stopped: boolean;
73
+ }, import("@ai-sdk/provider-utils").Context>>;
74
+ };
75
+ getResult: () => FishermanResult;
76
+ isFinished: () => boolean;
77
+ };
78
+ export interface FishermanResult {
79
+ success: boolean;
80
+ summary: string;
81
+ created: Array<{
82
+ type: string;
83
+ id?: string | number;
84
+ title?: string;
85
+ }>;
86
+ failed: Array<{
87
+ type: string;
88
+ reason: string;
89
+ }>;
90
+ }
@@ -136,7 +136,7 @@ function extractKeyFields(body, result = {}, depth = 0) {
136
136
  return result;
137
137
  }
138
138
  for (const [key, value] of Object.entries(body)) {
139
- if (value === null || value === undefined)
139
+ if (value == null)
140
140
  continue;
141
141
  if (typeof value === 'object') {
142
142
  extractKeyFields(value, result, depth + 1);
@@ -0,0 +1,29 @@
1
+ import type { ApiClient } from '../api/api-client.js';
2
+ import type { RequestStore } from '../api/request-store.js';
3
+ import type { Agent } from './agent.js';
4
+ import { type FishermanResult } from './fisherman-tools.js';
5
+ import type { Provider } from './provider.js';
6
+ export declare class Fisherman implements Agent {
7
+ emoji: string;
8
+ provider: Provider;
9
+ apiClient: ApiClient;
10
+ requestStore: RequestStore;
11
+ specLoader: () => Promise<any | null>;
12
+ cookieProvider: () => Promise<Record<string, string>>;
13
+ configHeaders: Record<string, string>;
14
+ sessionName?: string;
15
+ baseEndpoint: string;
16
+ spec: any | null;
17
+ mode: 'replicate' | 'achieve' | 'disabled';
18
+ hasApiConfig: boolean;
19
+ constructor(provider: Provider, apiClient: ApiClient, requestStore: RequestStore, specLoader: () => Promise<any | null>, baseEndpoint: string, cookieProvider: () => Promise<Record<string, string>>, configHeaders?: Record<string, string>, hasApiConfig?: boolean);
20
+ isAvailable(): boolean;
21
+ ensureReady(scopeUrl?: string): Promise<void>;
22
+ getEndpointList(scopeUrl?: string): string;
23
+ prepareData(instructions: string, scopeUrl?: string, sessionName?: string): Promise<FishermanResult>;
24
+ detectMode(scopeUrl?: string): Promise<void>;
25
+ refreshAuth(): Promise<void>;
26
+ buildEndpointList(scopeUrl?: string): string;
27
+ buildSystemPrompt(endpointList: string, toolNames: string[], scopeUrl?: string): string;
28
+ buildTaskPrompt(instructions: string): string;
29
+ }
@@ -34,9 +34,6 @@ export class Fisherman {
34
34
  isAvailable() {
35
35
  return this.mode !== 'disabled';
36
36
  }
37
- getMode() {
38
- return this.mode;
39
- }
40
37
  async ensureReady(scopeUrl) {
41
38
  await this.detectMode(scopeUrl);
42
39
  this.spec ??= await this.specLoader();
@@ -0,0 +1,17 @@
1
+ import type { StateManager } from '../../state-manager.js';
2
+ import type { Plan } from '../../test-plan.js';
3
+ import type { Conversation } from '../conversation.js';
4
+ import type { Constructor } from './mixin.js';
5
+ export interface CodeceptJSMethods {
6
+ toCode(conversation: Conversation, scenario: string): string;
7
+ saveCodeceptPlanToFile(plan: Plan): string;
8
+ }
9
+ export declare function WithCodeceptJS<T extends Constructor>(Base: T): {
10
+ new (...args: any[]): {
11
+ savedFiles: Set<string>;
12
+ stateManager?: StateManager;
13
+ toCode(conversation: Conversation, scenario: string): string;
14
+ saveCodeceptPlanToFile(plan: Plan): string;
15
+ getKnowledgeLines(url: string, indent?: string): string[];
16
+ };
17
+ } & T;
@@ -2,7 +2,6 @@ import { mkdirSync, writeFileSync } from 'node:fs';
2
2
  import { join } from 'node:path';
3
3
  import { ActionResult } from "../../action-result.js";
4
4
  import { ConfigParser } from "../../config.js";
5
- import { KnowledgeTracker } from "../../knowledge-tracker.js";
6
5
  import { tag } from "../../utils/logger.js";
7
6
  import { relativeToCwd } from "../../utils/next-steps.js";
8
7
  import { safeFilename } from "../../utils/strings.js";
@@ -87,7 +86,9 @@ export function WithCodeceptJS(Base) {
87
86
  return filePath;
88
87
  }
89
88
  getKnowledgeLines(url, indent = ' ') {
90
- const knowledgeTracker = new KnowledgeTracker();
89
+ const knowledgeTracker = this.stateManager?.getKnowledgeTracker();
90
+ if (!knowledgeTracker)
91
+ return [];
91
92
  const state = new ActionResult({ url });
92
93
  const { wait, waitForElement, code } = knowledgeTracker.getStateParameters(state, ['wait', 'waitForElement', 'code']);
93
94
  const lines = [];
@@ -0,0 +1,40 @@
1
+ import { ActionResult } from '../../action-result.js';
2
+ import { ExperienceTracker, type SessionStep } from '../../experience-tracker.js';
3
+ import type { Reporter } from '../../reporter.js';
4
+ import type { StateManager } from '../../state-manager.js';
5
+ import { type Task, Test } from '../../test-plan.js';
6
+ import type { Conversation, ToolExecution } from '../conversation.js';
7
+ import type { Provider } from '../provider.js';
8
+ import { type Constructor } from './mixin.js';
9
+ export interface ExperienceMethods {
10
+ saveSession(task: Task, initialState: ActionResult, conversation: Conversation): Promise<void>;
11
+ }
12
+ export declare function WithExperience<T extends Constructor>(Base: T): {
13
+ new (...args: any[]): {
14
+ provider: Provider;
15
+ experienceTracker: ExperienceTracker;
16
+ reporter: Reporter | undefined;
17
+ stateManager: StateManager | undefined;
18
+ isPlaywrightFramework: () => boolean;
19
+ toCode: (conversation: Conversation, scenario: string) => string;
20
+ toPlaywrightCode: (conversation: Conversation, scenario: string) => Promise<string>;
21
+ stopScreencast: () => Promise<void>;
22
+ saveSession(task: Task, initialState: ActionResult, conversation: Conversation): Promise<void>;
23
+ reportSession(test: Test, steps: SessionStep[]): Promise<void>;
24
+ extractSteps(toolExecutions: ToolExecution[]): Promise<SessionStep[]>;
25
+ hasRelevantFlowExperience(state: ActionResult): boolean;
26
+ extractPassedCodeceptSteps(task: Task): SessionStep[];
27
+ curateFlow(steps: SessionStep[], task: Task, initialState: ActionResult): Promise<string>;
28
+ renderFlowFromSuccessfulSteps(steps: SessionStep[], task: Task): string;
29
+ detectRetryPatterns(toolExecutions: ToolExecution[], initialState: ActionResult): Promise<void>;
30
+ analyzeDiscoveries(stepsWithDiffs: Array<{
31
+ step: SessionStep;
32
+ ariaDiff: string | null;
33
+ }>): Promise<void>;
34
+ buildDiscoveryPrompt(stepsWithDiffs: Array<{
35
+ step: SessionStep;
36
+ ariaDiff: string | null;
37
+ }>): string;
38
+ extractVisitedUrls(toolExecutions: ToolExecution[], initialUrl: string): string[];
39
+ };
40
+ } & T;
@@ -0,0 +1,2 @@
1
+ export type Constructor<T = object> = new (...args: any[]) => T;
2
+ export declare const debugLog: (...args: any[]) => void;
@@ -0,0 +1,22 @@
1
+ import type { StateManager } from '../../state-manager.js';
2
+ import { type PlaywrightRecorder } from '../../playwright-recorder.js';
3
+ import type { Plan } from '../../test-plan.js';
4
+ import type { Conversation } from '../conversation.js';
5
+ import type { Constructor } from './mixin.js';
6
+ export interface PlaywrightMethods {
7
+ toPlaywrightCode(conversation: Conversation, scenario: string): Promise<string>;
8
+ savePlaywrightPlanToFile(plan: Plan): string;
9
+ }
10
+ export declare function WithPlaywright<T extends Constructor>(Base: T): {
11
+ new (...args: any[]): {
12
+ playwright: {
13
+ recorder: PlaywrightRecorder;
14
+ helper: any;
15
+ } | undefined;
16
+ savedFiles: Set<string>;
17
+ stateManager?: StateManager;
18
+ toPlaywrightCode(conversation: Conversation, scenario: string): Promise<string>;
19
+ savePlaywrightPlanToFile(plan: Plan): string;
20
+ getPlaywrightKnowledgeLines(url: string, indent?: string): string[];
21
+ };
22
+ } & T;
@@ -2,7 +2,6 @@ import { mkdirSync, writeFileSync } from 'node:fs';
2
2
  import { join } from 'node:path';
3
3
  import { ActionResult } from "../../action-result.js";
4
4
  import { ConfigParser } from "../../config.js";
5
- import { KnowledgeTracker } from "../../knowledge-tracker.js";
6
5
  import { renderAssertion, renderCall } from "../../playwright-recorder.js";
7
6
  import { tag } from "../../utils/logger.js";
8
7
  import { relativeToCwd } from "../../utils/next-steps.js";
@@ -124,7 +123,9 @@ export function WithPlaywright(Base) {
124
123
  return filePath;
125
124
  }
126
125
  getPlaywrightKnowledgeLines(url, indent = ' ') {
127
- const knowledgeTracker = new KnowledgeTracker();
126
+ const knowledgeTracker = this.stateManager?.getKnowledgeTracker();
127
+ if (!knowledgeTracker)
128
+ return [];
128
129
  const state = new ActionResult({ url });
129
130
  const { wait, waitForElement } = knowledgeTracker.getStateParameters(state, ['wait', 'waitForElement']);
130
131
  const lines = [];