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.
- package/README.md +14 -14
- package/bin/explorbot-cli.ts +4 -3
- package/boat/doc-collector/src/ai/documentarian.ts +22 -27
- package/boat/doc-collector/src/ai/tools.ts +67 -10
- package/boat/doc-collector/src/docbot.ts +28 -7
- package/boat/doc-collector/src/docs-renderer.ts +19 -24
- package/boat/doc-collector/src/screenshots.ts +33 -1
- package/boat/doc-collector/src/state-diagram.ts +281 -0
- package/dist/bin/explorbot-cli.js +3 -3
- package/dist/boat/doc-collector/src/ai/documentarian.js +16 -6
- package/dist/boat/doc-collector/src/ai/tools.js +47 -10
- package/dist/boat/doc-collector/src/docbot.js +25 -6
- package/dist/boat/doc-collector/src/docs-renderer.js +18 -3
- package/dist/boat/doc-collector/src/screenshots.js +29 -0
- package/dist/boat/doc-collector/src/state-diagram.js +200 -0
- package/dist/package.json +8 -6
- package/dist/src/action-result.d.ts +131 -0
- package/dist/src/action-result.js +82 -159
- package/dist/src/action.d.ts +43 -0
- package/dist/src/action.js +18 -106
- package/dist/src/activity.d.ts +26 -0
- package/dist/src/ai/agent.d.ts +3 -0
- package/dist/src/ai/captain/file-tools.d.ts +28 -0
- package/dist/src/ai/captain/idle-mode.d.ts +11 -0
- package/dist/src/ai/captain/mixin.d.ts +10 -0
- package/dist/src/ai/captain/test-mode.d.ts +13 -0
- package/dist/src/ai/captain/web-mode.d.ts +13 -0
- package/dist/src/ai/captain/web-mode.js +0 -7
- package/dist/src/ai/captain.d.ts +141 -0
- package/dist/src/ai/captain.js +4 -19
- package/dist/src/ai/conversation.d.ts +28 -0
- package/dist/src/ai/conversation.js +9 -28
- package/dist/src/ai/driller.d.ts +157 -0
- package/dist/src/ai/driller.js +3 -12
- package/dist/src/ai/experience-compactor.d.ts +53 -0
- package/dist/src/ai/experience-compactor.js +16 -33
- package/dist/src/ai/fisherman-tools.d.ts +90 -0
- package/dist/src/ai/fisherman-tools.js +1 -1
- package/dist/src/ai/fisherman.d.ts +29 -0
- package/dist/src/ai/fisherman.js +0 -3
- package/dist/src/ai/historian/codeceptjs.d.ts +17 -0
- package/dist/src/ai/historian/codeceptjs.js +3 -2
- package/dist/src/ai/historian/experience.d.ts +40 -0
- package/dist/src/ai/historian/mixin.d.ts +2 -0
- package/dist/src/ai/historian/playwright.d.ts +22 -0
- package/dist/src/ai/historian/playwright.js +3 -2
- package/dist/src/ai/historian/screencast.d.ts +32 -0
- package/dist/src/ai/historian/utils.d.ts +3 -0
- package/dist/src/ai/historian/utils.js +0 -1
- package/dist/src/ai/historian.d.ts +109 -0
- package/dist/src/ai/historian.js +1 -5
- package/dist/src/ai/navigator.d.ts +54 -0
- package/dist/src/ai/navigator.js +11 -46
- package/dist/src/ai/pilot.d.ts +81 -0
- package/dist/src/ai/pilot.js +6 -17
- package/dist/src/ai/planner/session-dedup.d.ts +12 -0
- package/dist/src/ai/planner/styles.d.ts +6 -0
- package/dist/src/ai/planner/subpages.d.ts +35 -0
- package/dist/src/ai/planner.d.ts +79 -0
- package/dist/src/ai/planner.js +49 -37
- package/dist/src/ai/provider.d.ts +53 -0
- package/dist/src/ai/provider.js +78 -130
- package/dist/src/ai/quartermaster.d.ts +56 -0
- package/dist/src/ai/quartermaster.js +4 -10
- package/dist/src/ai/rerunner.d.ts +48 -0
- package/dist/src/ai/rerunner.js +14 -22
- package/dist/src/ai/researcher/cache.d.ts +6 -0
- package/dist/src/ai/researcher/cache.js +11 -18
- package/dist/src/ai/researcher/coordinates.d.ts +56 -0
- package/dist/src/ai/researcher/deep-analysis.d.ts +74 -0
- package/dist/src/ai/researcher/deep-analysis.js +3 -6
- package/dist/src/ai/researcher/fingerprint-worker.d.ts +1 -0
- package/dist/src/ai/researcher/focus.d.ts +8 -0
- package/dist/src/ai/researcher/locators.d.ts +36 -0
- package/dist/src/ai/researcher/mixin.d.ts +2 -0
- package/dist/src/ai/researcher/parser.d.ts +35 -0
- package/dist/src/ai/researcher/parser.js +1 -1
- package/dist/src/ai/researcher/research-result.d.ts +15 -0
- package/dist/src/ai/researcher/research-result.js +0 -19
- package/dist/src/ai/researcher/sections.d.ts +19 -0
- package/dist/src/ai/researcher/sections.js +5 -1
- package/dist/src/ai/researcher.js +12 -53
- package/dist/src/ai/rules.d.ts +16 -0
- package/dist/src/ai/rules.js +22 -15
- package/dist/src/ai/session-analyst.d.ts +11 -0
- package/dist/src/ai/session-analyst.js +8 -5
- package/dist/src/ai/task-agent.d.ts +28 -0
- package/dist/src/ai/task-agent.js +2 -27
- package/dist/src/ai/tester.d.ts +101 -0
- package/dist/src/ai/tester.js +10 -61
- package/dist/src/ai/tools.d.ts +52 -0
- package/dist/src/ai/tools.js +119 -101
- package/dist/src/api/api-client.d.ts +17 -0
- package/dist/src/api/request-result.d.ts +44 -0
- package/dist/src/api/request-store.d.ts +29 -0
- package/dist/src/api/spec-reader.d.ts +5 -0
- package/dist/src/api/xhr-capture.d.ts +10 -0
- package/dist/src/browser-server.d.ts +10 -0
- package/dist/src/command-handler.d.ts +68 -0
- package/dist/src/commands/add-rule-command.d.ts +11 -0
- package/dist/src/commands/base-command.d.ts +26 -0
- package/dist/src/commands/clean-command.d.ts +12 -0
- package/dist/src/commands/compact-command.d.ts +20 -0
- package/dist/src/commands/compact-command.js +6 -6
- package/dist/src/commands/context-aria-command.d.ts +6 -0
- package/dist/src/commands/context-command.d.ts +11 -0
- package/dist/src/commands/context-command.js +1 -1
- package/dist/src/commands/context-data-command.d.ts +6 -0
- package/dist/src/commands/context-experience-command.d.ts +6 -0
- package/dist/src/commands/context-html-command.d.ts +6 -0
- package/dist/src/commands/context-knowledge-command.d.ts +6 -0
- package/dist/src/commands/context-knowledge-command.js +1 -1
- package/dist/src/commands/debug-command.d.ts +6 -0
- package/dist/src/commands/drill-command.d.ts +10 -0
- package/dist/src/commands/exit-command.d.ts +7 -0
- package/dist/src/commands/experience-command.d.ts +15 -0
- package/dist/src/commands/experience-command.js +1 -1
- package/dist/src/commands/explore-command.d.ts +51 -0
- package/dist/src/commands/freesail-command.d.ts +12 -0
- package/dist/src/commands/help-command.d.ts +6 -0
- package/dist/src/commands/index.d.ts +4 -0
- package/dist/src/commands/init-command.d.ts +7 -0
- package/dist/src/commands/knows-command.d.ts +10 -0
- package/dist/src/commands/knows-command.js +1 -1
- package/dist/src/commands/learn-command.d.ts +7 -0
- package/dist/src/commands/learn-command.js +3 -1
- package/dist/src/commands/navigate-command.d.ts +7 -0
- package/dist/src/commands/path-command.d.ts +10 -0
- package/dist/src/commands/plan-clear-command.d.ts +7 -0
- package/dist/src/commands/plan-command.d.ts +14 -0
- package/dist/src/commands/plan-edit-command.d.ts +7 -0
- package/dist/src/commands/plan-load-command.d.ts +7 -0
- package/dist/src/commands/plan-reload-command.d.ts +7 -0
- package/dist/src/commands/plan-save-command.d.ts +7 -0
- package/dist/src/commands/plans-command.d.ts +21 -0
- package/dist/src/commands/rerun-command.d.ts +7 -0
- package/dist/src/commands/research-command.d.ts +11 -0
- package/dist/src/commands/runs-command.d.ts +7 -0
- package/dist/src/commands/start-command.d.ts +7 -0
- package/dist/src/commands/status-command.d.ts +6 -0
- package/dist/src/commands/test-command.d.ts +11 -0
- package/dist/src/components/ActivityPane.d.ts +6 -0
- package/dist/src/components/AddKnowledge.d.ts +10 -0
- package/dist/src/components/AddKnowledge.js +3 -7
- package/dist/src/components/AddRule.d.ts +9 -0
- package/dist/src/components/App.d.ts +9 -0
- package/dist/src/components/App.js +2 -2
- package/dist/src/components/Autocomplete.d.ts +3 -0
- package/dist/src/components/InputPane.d.ts +13 -0
- package/dist/src/components/InputReadline.d.ts +17 -0
- package/dist/src/components/LogPane.d.ts +6 -0
- package/dist/src/components/PlanEditor.d.ts +9 -0
- package/dist/src/components/PlanPane.d.ts +13 -0
- package/dist/src/components/SessionTimer.d.ts +6 -0
- package/dist/src/components/StateTransitionPane.d.ts +8 -0
- package/dist/src/components/StatusPane.d.ts +4 -0
- package/dist/src/components/TaskPane.d.ts +9 -0
- package/dist/src/components/Welcome.d.ts +3 -0
- package/dist/src/components/WelcomeChecklist.d.ts +9 -0
- package/dist/src/components/WelcomeCommands.d.ts +6 -0
- package/dist/src/components/autocomplete-store.d.ts +10 -0
- package/dist/src/components/parse-keypress.d.ts +12 -0
- package/dist/src/config.d.ts +253 -0
- package/dist/src/config.js +12 -0
- package/dist/src/execution-controller.d.ts +25 -0
- package/dist/src/experience-tracker.d.ts +112 -0
- package/dist/src/experience-tracker.js +83 -155
- package/dist/src/explorbot.d.ts +106 -0
- package/dist/src/explorbot.js +17 -51
- package/dist/src/explorer.d.ts +129 -0
- package/dist/src/explorer.js +31 -77
- package/dist/src/index.d.ts +6 -0
- package/dist/src/index.js +2 -55
- package/dist/src/knowledge-tracker.d.ts +33 -0
- package/dist/src/knowledge-tracker.js +47 -47
- package/dist/src/observability.d.ts +13 -0
- package/dist/src/observability.js +2 -1
- package/dist/src/playwright-recorder.d.ts +31 -0
- package/dist/src/reporter.d.ts +34 -0
- package/dist/src/state-manager.d.ts +160 -0
- package/dist/src/state-manager.js +10 -136
- package/dist/src/stats.d.ts +24 -0
- package/dist/src/suite.d.ts +24 -0
- package/dist/src/test-plan.d.ts +166 -0
- package/dist/src/utils/aria.d.ts +25 -0
- package/dist/src/utils/aria.js +4 -1
- package/dist/src/utils/browser-errors.d.ts +8 -0
- package/dist/src/utils/cache.d.ts +15 -0
- package/dist/src/utils/cache.js +34 -0
- package/dist/src/utils/cli-name.d.ts +1 -0
- package/dist/src/utils/code-extractor.d.ts +1 -0
- package/dist/src/utils/context-formatter.d.ts +31 -0
- package/dist/src/utils/context-formatter.js +15 -27
- package/dist/src/utils/error-page.d.ts +12 -0
- package/dist/src/utils/expandable.d.ts +4 -0
- package/dist/src/utils/hooks-runner.d.ts +15 -0
- package/dist/src/utils/html-diff.d.ts +19 -0
- package/dist/src/utils/html.d.ts +129 -0
- package/dist/src/utils/html.js +71 -0
- package/dist/src/utils/log-filters.d.ts +6 -0
- package/dist/src/utils/logger.d.ts +35 -0
- package/dist/src/utils/loop.d.ts +35 -0
- package/dist/src/utils/markdown-files.d.ts +10 -0
- package/dist/src/utils/markdown-files.js +21 -0
- package/dist/src/utils/markdown-parser.d.ts +17 -0
- package/dist/src/utils/markdown-query.d.ts +46 -0
- package/dist/src/utils/markdown-query.js +14 -1
- package/dist/src/utils/markdown-terminal.d.ts +1 -0
- package/dist/src/utils/next-steps.d.ts +11 -0
- package/dist/src/utils/page-readiness.d.ts +7 -0
- package/dist/src/utils/page-readiness.js +1 -1
- package/dist/src/utils/research-parser.d.ts +1 -0
- package/dist/src/utils/retry.d.ts +8 -0
- package/dist/src/utils/rules-loader.d.ts +12 -0
- package/dist/src/utils/secrets.d.ts +4 -0
- package/dist/src/utils/secrets.js +28 -0
- package/dist/src/utils/step-analyzer.d.ts +11 -0
- package/dist/src/utils/strings.d.ts +5 -0
- package/dist/src/utils/strings.js +10 -0
- package/dist/src/utils/test-files.d.ts +3 -0
- package/dist/src/utils/test-plan-markdown.d.ts +9 -0
- package/dist/src/utils/throttle.d.ts +2 -0
- package/dist/src/utils/unique-names.d.ts +2 -0
- package/dist/src/utils/url-matcher.d.ts +6 -0
- package/dist/src/utils/web-element.d.ts +45 -0
- package/dist/src/utils/web-element.js +3 -0
- package/dist/src/utils/web-sandbox.d.ts +4 -0
- package/dist/src/utils/web-sandbox.js +37 -0
- package/dist/src/utils/xpath.d.ts +17 -0
- package/package.json +8 -6
- package/src/action-result.ts +80 -168
- package/src/action.ts +16 -123
- package/src/ai/captain/web-mode.ts +0 -7
- package/src/ai/captain.ts +5 -17
- package/src/ai/conversation.ts +9 -32
- package/src/ai/driller.ts +3 -16
- package/src/ai/experience-compactor.ts +16 -35
- package/src/ai/fisherman-tools.ts +1 -1
- package/src/ai/fisherman.ts +0 -4
- package/src/ai/historian/codeceptjs.ts +4 -2
- package/src/ai/historian/playwright.ts +4 -2
- package/src/ai/historian/utils.ts +0 -1
- package/src/ai/historian.ts +4 -7
- package/src/ai/navigator.ts +13 -49
- package/src/ai/pilot.ts +6 -16
- package/src/ai/planner.ts +56 -44
- package/src/ai/provider.ts +86 -139
- package/src/ai/quartermaster.ts +34 -41
- package/src/ai/rerunner.ts +17 -21
- package/src/ai/researcher/cache.ts +10 -16
- package/src/ai/researcher/deep-analysis.ts +3 -6
- package/src/ai/researcher/parser.ts +1 -1
- package/src/ai/researcher/research-result.ts +0 -18
- package/src/ai/researcher/sections.ts +5 -1
- package/src/ai/researcher.ts +11 -59
- package/src/ai/rules.ts +24 -13
- package/src/ai/session-analyst.ts +8 -5
- package/src/ai/task-agent.ts +3 -30
- package/src/ai/tester.ts +12 -73
- package/src/ai/tools.ts +119 -106
- package/src/commands/compact-command.ts +7 -8
- package/src/commands/context-command.ts +1 -1
- package/src/commands/context-knowledge-command.ts +1 -1
- package/src/commands/experience-command.ts +1 -1
- package/src/commands/knows-command.ts +1 -1
- package/src/commands/learn-command.ts +3 -1
- package/src/components/AddKnowledge.tsx +5 -7
- package/src/components/App.tsx +2 -2
- package/src/config.ts +12 -0
- package/src/experience-tracker.ts +90 -152
- package/src/explorbot.ts +17 -51
- package/src/explorer.ts +34 -81
- package/src/index.ts +9 -0
- package/src/knowledge-tracker.ts +49 -50
- package/src/observability.ts +2 -1
- package/src/state-manager.ts +15 -164
- package/src/utils/aria.ts +11 -2
- package/src/utils/cache.ts +40 -0
- package/src/utils/context-formatter.ts +12 -15
- package/src/utils/html.ts +79 -0
- package/src/utils/markdown-files.ts +30 -0
- package/src/utils/markdown-query.ts +15 -1
- package/src/utils/page-readiness.ts +1 -1
- package/src/utils/secrets.ts +28 -0
- package/src/utils/strings.ts +12 -0
- package/src/utils/web-element.ts +4 -0
- package/src/utils/web-sandbox.ts +43 -0
- package/src/index.tsx +0 -62
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { mkdirSync, writeFileSync } from 'node:fs';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import { z } from 'zod';
|
|
4
|
-
import {
|
|
4
|
+
import { outputPath } from "../config.js";
|
|
5
5
|
import { createDebug, tag } from "../utils/logger.js";
|
|
6
6
|
import { isCodeceptToolName } from "../utils/step-analyzer.js";
|
|
7
7
|
const debugLog = createDebug('explorbot:quartermaster');
|
|
@@ -16,12 +16,11 @@ export class Quartermaster {
|
|
|
16
16
|
constructor(provider, options) {
|
|
17
17
|
this.provider = provider;
|
|
18
18
|
this.model = options?.model;
|
|
19
|
-
|
|
20
|
-
this.outputDir = join(configParser.getOutputDir(), 'a11y');
|
|
19
|
+
this.outputDir = outputPath('a11y');
|
|
21
20
|
}
|
|
22
21
|
start(playwrightHelper, stateManager) {
|
|
23
22
|
this.playwrightHelper = playwrightHelper;
|
|
24
|
-
this.
|
|
23
|
+
mkdirSync(this.outputDir, { recursive: true });
|
|
25
24
|
this.unsubscribe = stateManager.onStateChange((event) => {
|
|
26
25
|
this.onPageChange(event);
|
|
27
26
|
});
|
|
@@ -34,11 +33,6 @@ export class Quartermaster {
|
|
|
34
33
|
}
|
|
35
34
|
debugLog('Quartermaster stopped');
|
|
36
35
|
}
|
|
37
|
-
ensureDirectory() {
|
|
38
|
-
if (!existsSync(this.outputDir)) {
|
|
39
|
-
mkdirSync(this.outputDir, { recursive: true });
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
36
|
onPageChange(event) {
|
|
43
37
|
const state = event.toState;
|
|
44
38
|
if (!state?.hash)
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { ExperienceTracker } from '../experience-tracker.js';
|
|
2
|
+
import type Explorer from '../explorer.js';
|
|
3
|
+
import type { KnowledgeTracker } from '../knowledge-tracker.js';
|
|
4
|
+
import { Test } from '../test-plan.js';
|
|
5
|
+
import type { Agent } from './agent.js';
|
|
6
|
+
import type { Navigator } from './navigator.js';
|
|
7
|
+
import { Provider } from './provider.js';
|
|
8
|
+
import { TaskAgent } from './task-agent.js';
|
|
9
|
+
export declare class Rerunner extends TaskAgent implements Agent {
|
|
10
|
+
readonly ACTION_TOOLS: string[];
|
|
11
|
+
emoji: string;
|
|
12
|
+
explorer: Explorer;
|
|
13
|
+
provider: Provider;
|
|
14
|
+
agentTools: any;
|
|
15
|
+
healedSteps: Array<{
|
|
16
|
+
original: string;
|
|
17
|
+
healed: string;
|
|
18
|
+
}>;
|
|
19
|
+
traceDir: string;
|
|
20
|
+
static pluginsWired: boolean;
|
|
21
|
+
constructor(explorer: Explorer, provider: Provider, agentTools?: any);
|
|
22
|
+
getNavigator(): Navigator;
|
|
23
|
+
getExperienceTracker(): ExperienceTracker;
|
|
24
|
+
getKnowledgeTracker(): KnowledgeTracker;
|
|
25
|
+
getProvider(): Provider;
|
|
26
|
+
get rerunnerConfig(): Record<string, any>;
|
|
27
|
+
get healLimit(): number;
|
|
28
|
+
get healMaxIterations(): number;
|
|
29
|
+
rerun(filePath: string, options?: {
|
|
30
|
+
testIndices?: number[];
|
|
31
|
+
}): Promise<RerunResult>;
|
|
32
|
+
getCurrentTask(testMap: Map<string, Test>): Test | undefined;
|
|
33
|
+
setupPlugins(): void;
|
|
34
|
+
teardownHealing(): void;
|
|
35
|
+
healStep(step: any, error: Error): Promise<((deps: {
|
|
36
|
+
I: any;
|
|
37
|
+
}) => Promise<void>) | null>;
|
|
38
|
+
getHealSystemPrompt(): string;
|
|
39
|
+
getHealUserPrompt(failedCode: string, error: Error): string;
|
|
40
|
+
printResults(result: RerunResult): void;
|
|
41
|
+
}
|
|
42
|
+
interface RerunResult {
|
|
43
|
+
total: number;
|
|
44
|
+
passed: number;
|
|
45
|
+
failed: number;
|
|
46
|
+
healed: number;
|
|
47
|
+
}
|
|
48
|
+
export {};
|
package/dist/src/ai/rerunner.js
CHANGED
|
@@ -14,10 +14,10 @@ import { ActionResult } from "../action-result.js";
|
|
|
14
14
|
import { setActivity } from "../activity.js";
|
|
15
15
|
import { Stats } from "../stats.js";
|
|
16
16
|
import { Task, Test, TestResult } from "../test-plan.js";
|
|
17
|
+
import { formatHeadings } from "../utils/context-formatter.js";
|
|
17
18
|
import { createDebug, tag } from "../utils/logger.js";
|
|
18
19
|
import { loop } from "../utils/loop.js";
|
|
19
20
|
import { RulesLoader } from "../utils/rules-loader.js";
|
|
20
|
-
import { loadTestSuites, printTestList } from "../utils/test-files.js";
|
|
21
21
|
import { toolExecutionLabel } from "./conversation.js";
|
|
22
22
|
import { actionRule, locatorRule, sectionContextRule } from "./rules.js";
|
|
23
23
|
import { TaskAgent } from "./task-agent.js";
|
|
@@ -31,6 +31,7 @@ export class Rerunner extends TaskAgent {
|
|
|
31
31
|
agentTools;
|
|
32
32
|
healedSteps = [];
|
|
33
33
|
traceDir = '';
|
|
34
|
+
static pluginsWired = false;
|
|
34
35
|
constructor(explorer, provider, agentTools) {
|
|
35
36
|
super();
|
|
36
37
|
this.explorer = explorer;
|
|
@@ -58,9 +59,6 @@ export class Rerunner extends TaskAgent {
|
|
|
58
59
|
get healMaxIterations() {
|
|
59
60
|
return this.rerunnerConfig.healMaxIterations ?? 3;
|
|
60
61
|
}
|
|
61
|
-
listTests(testsDir) {
|
|
62
|
-
printTestList(loadTestSuites(testsDir));
|
|
63
|
-
}
|
|
64
62
|
async rerun(filePath, options) {
|
|
65
63
|
const absPath = resolve(filePath);
|
|
66
64
|
if (!existsSync(absPath)) {
|
|
@@ -191,7 +189,6 @@ export class Rerunner extends TaskAgent {
|
|
|
191
189
|
}
|
|
192
190
|
setupPlugins() {
|
|
193
191
|
const healMod = heal.default || heal;
|
|
194
|
-
healMod.connectToEvents();
|
|
195
192
|
healMod.addRecipe('explorbot-ai-healer', {
|
|
196
193
|
priority: 10,
|
|
197
194
|
fn: async (context) => {
|
|
@@ -202,20 +199,26 @@ export class Rerunner extends TaskAgent {
|
|
|
202
199
|
for (const [name, recipe] of Object.entries(userRecipes)) {
|
|
203
200
|
healMod.addRecipe(name, recipe);
|
|
204
201
|
}
|
|
202
|
+
const outputDir = global.output_dir || 'output';
|
|
203
|
+
this.traceDir = `${outputDir}/rerun-traces`;
|
|
204
|
+
if (Rerunner.pluginsWired)
|
|
205
|
+
return;
|
|
206
|
+
Rerunner.pluginsWired = true;
|
|
207
|
+
healMod.connectToEvents();
|
|
205
208
|
let currentTest = null;
|
|
206
209
|
let healTries = 0;
|
|
207
210
|
let isHealing = false;
|
|
208
211
|
let caughtError = null;
|
|
209
|
-
const healLimit = this.healLimit;
|
|
210
212
|
codeceptjs.event.dispatcher.on('test.before', (test) => {
|
|
211
213
|
currentTest = test;
|
|
212
214
|
healTries = 0;
|
|
213
215
|
caughtError = null;
|
|
216
|
+
isHealing = false;
|
|
214
217
|
});
|
|
215
218
|
codeceptjs.event.dispatcher.on('step.after', (step) => {
|
|
216
219
|
if (isHealing)
|
|
217
220
|
return;
|
|
218
|
-
if (healTries >= healLimit)
|
|
221
|
+
if (healTries >= this.healLimit)
|
|
219
222
|
return;
|
|
220
223
|
if (!healMod.hasCorrespondingRecipes(step))
|
|
221
224
|
return;
|
|
@@ -249,9 +252,6 @@ export class Rerunner extends TaskAgent {
|
|
|
249
252
|
maxTimeout: 5000,
|
|
250
253
|
factor: 1.5,
|
|
251
254
|
});
|
|
252
|
-
const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
|
|
253
|
-
const outputDir = global.output_dir || 'output';
|
|
254
|
-
this.traceDir = `${outputDir}/rerun_${timestamp}`;
|
|
255
255
|
const aiTrace = aiTracePlugin.default || aiTracePlugin;
|
|
256
256
|
aiTrace(this.rerunnerConfig.aiTrace || { output: this.traceDir });
|
|
257
257
|
import('@testomatio/reporter/codecept')
|
|
@@ -263,9 +263,9 @@ export class Rerunner extends TaskAgent {
|
|
|
263
263
|
}
|
|
264
264
|
teardownHealing() {
|
|
265
265
|
const healMod = heal.default || heal;
|
|
266
|
-
healMod.recipes
|
|
266
|
+
Reflect.deleteProperty(healMod.recipes, 'explorbot-ai-healer');
|
|
267
267
|
for (const name of Object.keys(this.rerunnerConfig.recipes || {})) {
|
|
268
|
-
healMod.recipes
|
|
268
|
+
Reflect.deleteProperty(healMod.recipes, name);
|
|
269
269
|
}
|
|
270
270
|
}
|
|
271
271
|
async healStep(step, error) {
|
|
@@ -378,7 +378,7 @@ export class Rerunner extends TaskAgent {
|
|
|
378
378
|
if (!healed) {
|
|
379
379
|
throw new Error(`Could not heal: ${failedCode}`);
|
|
380
380
|
}
|
|
381
|
-
this.healedSteps.push({
|
|
381
|
+
this.healedSteps.push({ original: failedCode, healed: healedCommand });
|
|
382
382
|
console.log(chalk.green(` ${figureSet.tick} Healed: ${healedCommand}`));
|
|
383
383
|
};
|
|
384
384
|
}
|
|
@@ -419,15 +419,7 @@ export class Rerunner extends TaskAgent {
|
|
|
419
419
|
getHealUserPrompt(failedCode, error) {
|
|
420
420
|
const state = this.explorer.getStateManager().getCurrentState();
|
|
421
421
|
const actionResult = state ? ActionResult.fromState(state) : null;
|
|
422
|
-
const headings =
|
|
423
|
-
if (state?.h1)
|
|
424
|
-
headings.push(`H1: ${state.h1}`);
|
|
425
|
-
if (state?.h2)
|
|
426
|
-
headings.push(`H2: ${state.h2}`);
|
|
427
|
-
if (state?.h3)
|
|
428
|
-
headings.push(`H3: ${state.h3}`);
|
|
429
|
-
if (state?.h4)
|
|
430
|
-
headings.push(`H4: ${state.h4}`);
|
|
422
|
+
const headings = formatHeadings(state || {});
|
|
431
423
|
return dedent `
|
|
432
424
|
A test step failed and needs healing.
|
|
433
425
|
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare function clearResearchCache(): void;
|
|
2
|
+
export declare function getCachedResearch(hash: string): string;
|
|
3
|
+
export declare function getPreviousResearch(hash: string): string;
|
|
4
|
+
export declare function saveResearch(hash: string, text: string, combinedHtml?: string): string;
|
|
5
|
+
export declare function findSimilarResearch(combinedHtml: string): Promise<string | null>;
|
|
6
|
+
export declare function findSimilarStateHash(combinedHtml: string): Promise<string | null>;
|
|
@@ -2,14 +2,14 @@ import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from 'no
|
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import { Worker } from 'node:worker_threads';
|
|
4
4
|
import { outputPath } from "../../config.js";
|
|
5
|
+
import { TTLCache } from "../../utils/cache.js";
|
|
5
6
|
import { computeHtmlFingerprint } from "../../utils/html-diff.js";
|
|
6
7
|
import { debugLog } from "./mixin.js";
|
|
7
8
|
const CACHE_TTL_MS = 6 * 60 * 60 * 1000; // 6 hours
|
|
8
9
|
const FINGERPRINT_MAX_AGE_MS = 60 * 60 * 1000; // 1 hour
|
|
9
10
|
const FINGERPRINT_WORKER_TIMEOUT_MS = 10_000;
|
|
10
11
|
const SIMILARITY_THRESHOLD = 90;
|
|
11
|
-
const memoryCache =
|
|
12
|
-
const memoryCacheTimestamps = {};
|
|
12
|
+
const memoryCache = new TTLCache(CACHE_TTL_MS);
|
|
13
13
|
let fingerprintWorker = null;
|
|
14
14
|
function getStatesDir() {
|
|
15
15
|
return outputPath('states');
|
|
@@ -22,29 +22,23 @@ function getFingerprintWorker() {
|
|
|
22
22
|
return fingerprintWorker;
|
|
23
23
|
}
|
|
24
24
|
export function clearResearchCache() {
|
|
25
|
-
|
|
26
|
-
delete memoryCache[key];
|
|
27
|
-
for (const key of Object.keys(memoryCacheTimestamps))
|
|
28
|
-
delete memoryCacheTimestamps[key];
|
|
25
|
+
memoryCache.clear();
|
|
29
26
|
}
|
|
30
27
|
export function getCachedResearch(hash) {
|
|
31
28
|
if (!hash)
|
|
32
29
|
return '';
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
return memoryCache[hash] || '';
|
|
37
|
-
}
|
|
30
|
+
const cached = memoryCache.get(hash);
|
|
31
|
+
if (cached !== undefined)
|
|
32
|
+
return cached;
|
|
38
33
|
const researchFile = outputPath('research', `${hash}.md`);
|
|
39
34
|
if (!existsSync(researchFile))
|
|
40
35
|
return '';
|
|
41
36
|
const stats = statSync(researchFile);
|
|
42
|
-
if (now - stats.mtimeMs > CACHE_TTL_MS)
|
|
37
|
+
if (Date.now() - stats.mtimeMs > CACHE_TTL_MS)
|
|
43
38
|
return '';
|
|
44
|
-
const
|
|
45
|
-
memoryCache
|
|
46
|
-
|
|
47
|
-
return cached;
|
|
39
|
+
const fromDisk = readFileSync(researchFile, 'utf8');
|
|
40
|
+
memoryCache.set(hash, fromDisk);
|
|
41
|
+
return fromDisk;
|
|
48
42
|
}
|
|
49
43
|
export function getPreviousResearch(hash) {
|
|
50
44
|
if (!hash)
|
|
@@ -60,8 +54,7 @@ export function saveResearch(hash, text, combinedHtml) {
|
|
|
60
54
|
if (!existsSync(researchDir))
|
|
61
55
|
mkdirSync(researchDir, { recursive: true });
|
|
62
56
|
writeFileSync(researchFile, text);
|
|
63
|
-
memoryCache
|
|
64
|
-
memoryCacheTimestamps[hash] = Date.now();
|
|
57
|
+
memoryCache.set(hash, text);
|
|
65
58
|
debugLog(`Research saved to ${researchFile}`);
|
|
66
59
|
if (combinedHtml) {
|
|
67
60
|
const statesDir = getStatesDir();
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { Page } from 'playwright';
|
|
2
|
+
import type { ActionResult } from '../../action-result.js';
|
|
3
|
+
import type Explorer from '../../explorer.js';
|
|
4
|
+
import type { Provider } from '../provider.js';
|
|
5
|
+
import { type Constructor } from './mixin.js';
|
|
6
|
+
import type { ResearchResult } from './research-result.js';
|
|
7
|
+
export declare function visuallyAnnotateContainers(page: Page, containers: Array<{
|
|
8
|
+
css: string;
|
|
9
|
+
label: string;
|
|
10
|
+
}>): Promise<number>;
|
|
11
|
+
export declare function WithCoordinates<T extends Constructor>(Base: T): {
|
|
12
|
+
new (...args: any[]): {
|
|
13
|
+
explorer: Explorer;
|
|
14
|
+
provider: Provider;
|
|
15
|
+
actionResult: ActionResult | undefined;
|
|
16
|
+
analyzeScreenshotForVisualProps(): Promise<VisualAnalysisResult>;
|
|
17
|
+
visuallyAnnotateElements(opts?: {
|
|
18
|
+
containers?: Array<{
|
|
19
|
+
css: string;
|
|
20
|
+
label: string;
|
|
21
|
+
}>;
|
|
22
|
+
}): Promise<number>;
|
|
23
|
+
_analyzeScreenshotForVisualProps(): Promise<VisualAnalysisResult>;
|
|
24
|
+
mergeVisualData(result: ResearchResult, visualData: Map<string, {
|
|
25
|
+
coordinates: string | null;
|
|
26
|
+
color: string | null;
|
|
27
|
+
icon: string | null;
|
|
28
|
+
}>): Promise<void>;
|
|
29
|
+
backfillCoordinates(result: ResearchResult): Promise<void>;
|
|
30
|
+
};
|
|
31
|
+
} & T;
|
|
32
|
+
export interface VisualAnalysisResult {
|
|
33
|
+
elements: Map<string, {
|
|
34
|
+
coordinates: string | null;
|
|
35
|
+
color: string | null;
|
|
36
|
+
icon: string | null;
|
|
37
|
+
}>;
|
|
38
|
+
pagePurpose: string | null;
|
|
39
|
+
primaryActions: string[] | null;
|
|
40
|
+
focusedSection: string | null;
|
|
41
|
+
}
|
|
42
|
+
export interface CoordinateMethods {
|
|
43
|
+
analyzeScreenshotForVisualProps(): Promise<VisualAnalysisResult>;
|
|
44
|
+
mergeVisualData(result: ResearchResult, visualData: Map<string, {
|
|
45
|
+
coordinates: string | null;
|
|
46
|
+
color: string | null;
|
|
47
|
+
icon: string | null;
|
|
48
|
+
}>): Promise<void>;
|
|
49
|
+
backfillCoordinates(result: ResearchResult): Promise<void>;
|
|
50
|
+
visuallyAnnotateElements(opts?: {
|
|
51
|
+
containers?: Array<{
|
|
52
|
+
css: string;
|
|
53
|
+
label: string;
|
|
54
|
+
}>;
|
|
55
|
+
}): Promise<number>;
|
|
56
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { ActionResult, type Diff } from '../../action-result.js';
|
|
2
|
+
import type Explorer from '../../explorer.js';
|
|
3
|
+
import type { StateManager } from '../../state-manager.js';
|
|
4
|
+
import { WebPageState } from '../../state-manager.js';
|
|
5
|
+
import type { Provider } from '../provider.js';
|
|
6
|
+
import { type Constructor } from './mixin.js';
|
|
7
|
+
import { type ResearchElement } from './parser.js';
|
|
8
|
+
import type { ResearchResult } from './research-result.js';
|
|
9
|
+
export declare function WithDeepAnalysis<T extends Constructor>(Base: T): {
|
|
10
|
+
new (...args: any[]): {
|
|
11
|
+
explorer: Explorer;
|
|
12
|
+
provider: Provider;
|
|
13
|
+
stateManager: StateManager;
|
|
14
|
+
actionResult: ActionResult | undefined;
|
|
15
|
+
performDeepAnalysis(state: WebPageState, result: ResearchResult): Promise<void>;
|
|
16
|
+
researchOverlay(current: ActionResult, previous: ActionResult, pageStateHash: string): Promise<string | null>;
|
|
17
|
+
_loadPreviousExtendedSections(hash: string): PreviousSection[];
|
|
18
|
+
_replayPreviousSections(state: WebPageState, prevSections: PreviousSection[], maxClicks: number): Promise<{
|
|
19
|
+
verified: string[];
|
|
20
|
+
verifiedCodes: string[];
|
|
21
|
+
missing: PreviousSection[];
|
|
22
|
+
}>;
|
|
23
|
+
_appendExtendedResearch(result: ResearchResult, expandedSections: string[], navigationLinks: Array<{
|
|
24
|
+
code: string;
|
|
25
|
+
url: string;
|
|
26
|
+
}>): void;
|
|
27
|
+
_discoverExpandables(researchText: string, missing?: PreviousSection[], verifiedCodes?: string[]): Promise<ExpandableElement[]>;
|
|
28
|
+
_buildClickCommands(el: ExpandableElement): string[];
|
|
29
|
+
_selectExpandables(expandables: ExpandableElement[], url: string, maxClicks: number): Promise<ExpandableElement[]>;
|
|
30
|
+
_clickExpandableElements(elements: Array<{
|
|
31
|
+
commands: string[];
|
|
32
|
+
description: string;
|
|
33
|
+
}>, state: WebPageState, expandedSections: string[], navigationLinks: Array<{
|
|
34
|
+
code: string;
|
|
35
|
+
url: string;
|
|
36
|
+
}>): Promise<void>;
|
|
37
|
+
_executeAndAnalyze(commands: string[], description: string, state: WebPageState, originalAria: string, alreadyExpanded: string[]): Promise<ExpansionOutcome>;
|
|
38
|
+
_restorePageState(url: string, originalAria: string): Promise<void>;
|
|
39
|
+
_analyzeExpandedAction(code: string, description: string, diff: Diff, alreadyExpanded: string[]): Promise<string | null>;
|
|
40
|
+
_deduplicateExpandedSections(sections: string[]): string[];
|
|
41
|
+
_summarizeExpanded(expandedSections: string[]): string[];
|
|
42
|
+
_sectionFingerprint(sectionMarkdown: string): string | null;
|
|
43
|
+
_parseSectionKeys(sectionMarkdown: string): {
|
|
44
|
+
name: string;
|
|
45
|
+
keys: string[];
|
|
46
|
+
} | null;
|
|
47
|
+
};
|
|
48
|
+
} & T;
|
|
49
|
+
interface ExpandableElement extends ResearchElement {
|
|
50
|
+
container: string | null;
|
|
51
|
+
}
|
|
52
|
+
interface PreviousSection {
|
|
53
|
+
name: string;
|
|
54
|
+
code: string;
|
|
55
|
+
}
|
|
56
|
+
type ExpansionOutcome = {
|
|
57
|
+
status: 'revealed';
|
|
58
|
+
code: string;
|
|
59
|
+
sectionMarkdown: string;
|
|
60
|
+
} | {
|
|
61
|
+
status: 'navigated';
|
|
62
|
+
code: string;
|
|
63
|
+
url: string;
|
|
64
|
+
} | {
|
|
65
|
+
status: 'none';
|
|
66
|
+
code: string;
|
|
67
|
+
} | {
|
|
68
|
+
status: 'failed';
|
|
69
|
+
};
|
|
70
|
+
export interface DeepAnalysisMethods {
|
|
71
|
+
performDeepAnalysis(state: WebPageState, result: ResearchResult): Promise<void>;
|
|
72
|
+
researchOverlay(current: ActionResult, previous: ActionResult, pageStateHash: string): Promise<string | null>;
|
|
73
|
+
}
|
|
74
|
+
export {};
|
|
@@ -74,7 +74,6 @@ export function WithDeepAnalysis(Base) {
|
|
|
74
74
|
return null;
|
|
75
75
|
}
|
|
76
76
|
const diff = await current.diff(previous);
|
|
77
|
-
await diff.calculate();
|
|
78
77
|
if (!diff.ariaChanged && diff.htmlParts.length === 0) {
|
|
79
78
|
debugLog(`No diff between current and previous state for overlay "${focusArea.name}"`);
|
|
80
79
|
return null;
|
|
@@ -312,12 +311,11 @@ export function WithDeepAnalysis(Base) {
|
|
|
312
311
|
const isCoordinateClick = el.commands[0].startsWith('I.clickXY(');
|
|
313
312
|
if (!isCoordinateClick) {
|
|
314
313
|
const hoverCmd = el.commands[0].replace('I.click(', 'I.moveCursorTo(');
|
|
315
|
-
await this.explorer.attemptAction(hoverCmd, undefined
|
|
314
|
+
await this.explorer.attemptAction(hoverCmd, undefined);
|
|
316
315
|
await new Promise((r) => setTimeout(r, 500));
|
|
317
316
|
await this.explorer.capturePageState();
|
|
318
317
|
const hoverAR = ActionResult.fromState(this.stateManager.getCurrentState());
|
|
319
318
|
const hoverDiff = await hoverAR.diff(previousState);
|
|
320
|
-
await hoverDiff.calculate();
|
|
321
319
|
const hoverHtmlSize = hoverDiff.htmlParts.reduce((sum, p) => sum + p.subtree.length, 0);
|
|
322
320
|
const hoverRevealed = hoverDiff.ariaChanged && hoverHtmlSize > 500;
|
|
323
321
|
if (hoverRevealed) {
|
|
@@ -355,7 +353,7 @@ export function WithDeepAnalysis(Base) {
|
|
|
355
353
|
let clickCode = null;
|
|
356
354
|
const action = this.explorer.createAction();
|
|
357
355
|
for (const cmd of commands) {
|
|
358
|
-
if (await action.attempt(cmd, undefined
|
|
356
|
+
if (await action.attempt(cmd, undefined)) {
|
|
359
357
|
clickCode = cmd;
|
|
360
358
|
break;
|
|
361
359
|
}
|
|
@@ -370,7 +368,6 @@ export function WithDeepAnalysis(Base) {
|
|
|
370
368
|
await this.explorer.createAction().capturePageState();
|
|
371
369
|
const currAR = ActionResult.fromState(this.stateManager.getCurrentState());
|
|
372
370
|
diff = await currAR.diff(previousState);
|
|
373
|
-
await diff.calculate();
|
|
374
371
|
}
|
|
375
372
|
catch (err) {
|
|
376
373
|
tag('warning').log(`State capture failed after click: ${err instanceof Error ? err.message : err}`);
|
|
@@ -399,7 +396,7 @@ export function WithDeepAnalysis(Base) {
|
|
|
399
396
|
await this.cancelInUi();
|
|
400
397
|
await this.explorer.capturePageState();
|
|
401
398
|
const currentAria = this.stateManager.getCurrentState()?.ariaSnapshot || '';
|
|
402
|
-
if (!diffAriaSnapshots(originalAria, currentAria))
|
|
399
|
+
if (!diffAriaSnapshots(originalAria, currentAria).text)
|
|
403
400
|
return;
|
|
404
401
|
}
|
|
405
402
|
catch (err) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Page } from 'playwright';
|
|
2
|
+
import type { ResearchSection } from './parser.js';
|
|
3
|
+
import type { ResearchResult } from './research-result.js';
|
|
4
|
+
export declare const FOCUSED_MARKER = "> **Focused**";
|
|
5
|
+
export declare function hasFocusedSection(text: string): boolean;
|
|
6
|
+
export declare function detectFocusedSection(page: Page, sections: ResearchSection[]): Promise<string | null>;
|
|
7
|
+
export declare function markSectionAsFocused(result: ResearchResult, sectionName: string): void;
|
|
8
|
+
export declare function pickDefaultFocusedSection(sections: ResearchSection[]): string | null;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { ActionResult } from '../../action-result.js';
|
|
2
|
+
import type Explorer from '../../explorer.js';
|
|
3
|
+
import type { Conversation } from '../conversation.js';
|
|
4
|
+
import type { Provider } from '../provider.js';
|
|
5
|
+
import { type Constructor } from './mixin.js';
|
|
6
|
+
import { parseResearchSections } from './parser.js';
|
|
7
|
+
import type { ResearchResult } from './research-result.js';
|
|
8
|
+
export declare const DYNAMIC_ID_PATTERN: RegExp;
|
|
9
|
+
export declare const isForbiddenLocator: (s: string) => boolean;
|
|
10
|
+
export declare function WithLocators<T extends Constructor>(Base: T): {
|
|
11
|
+
new (...args: any[]): {
|
|
12
|
+
explorer: Explorer;
|
|
13
|
+
provider: Provider;
|
|
14
|
+
actionResult: ActionResult | undefined;
|
|
15
|
+
testLocators(locators: Locator[]): Promise<void>;
|
|
16
|
+
fixBrokenSections(result: ResearchResult, conversation: Conversation): Promise<void>;
|
|
17
|
+
backfillBrokenLocators(result: ResearchResult): Promise<void>;
|
|
18
|
+
validateContainers(result: ResearchResult): Promise<void>;
|
|
19
|
+
updateSectionContainer(result: ResearchResult, section: ReturnType<typeof parseResearchSections>[0], newCss: string | null): void;
|
|
20
|
+
};
|
|
21
|
+
} & T;
|
|
22
|
+
export interface Locator {
|
|
23
|
+
section: string;
|
|
24
|
+
container: string | null;
|
|
25
|
+
element: string;
|
|
26
|
+
type: 'css' | 'xpath' | 'aria';
|
|
27
|
+
locator: string;
|
|
28
|
+
valid: boolean | null;
|
|
29
|
+
error: string | null;
|
|
30
|
+
pwLocator: string | null;
|
|
31
|
+
}
|
|
32
|
+
export interface LocatorMethods {
|
|
33
|
+
testLocators(locators: Locator[]): Promise<void>;
|
|
34
|
+
fixBrokenSections(result: ResearchResult, conversation: Conversation): Promise<void>;
|
|
35
|
+
backfillBrokenLocators(result: ResearchResult): Promise<void>;
|
|
36
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export interface ResearchElement {
|
|
2
|
+
name: string;
|
|
3
|
+
type: string | null;
|
|
4
|
+
aria: {
|
|
5
|
+
role: string;
|
|
6
|
+
text: string;
|
|
7
|
+
} | null;
|
|
8
|
+
css: string | null;
|
|
9
|
+
xpath: string | null;
|
|
10
|
+
coordinates: string | null;
|
|
11
|
+
color: string | null;
|
|
12
|
+
icon: string | null;
|
|
13
|
+
eidx: string | null;
|
|
14
|
+
}
|
|
15
|
+
export interface ResearchSection {
|
|
16
|
+
name: string;
|
|
17
|
+
containerCss: string | null;
|
|
18
|
+
elements: ResearchElement[];
|
|
19
|
+
rawMarkdown: string;
|
|
20
|
+
isExtended: boolean;
|
|
21
|
+
}
|
|
22
|
+
export declare const RESEARCH_COLUMN_ORDER: string[];
|
|
23
|
+
export declare function mapRowToElement(row: Record<string, string>): ResearchElement | null;
|
|
24
|
+
export declare function extractContainerFromBlockquote(sectionMarkdown: string): string | null;
|
|
25
|
+
export declare function parseResearchSections(markdown: string): ResearchSection[];
|
|
26
|
+
export declare function extractValidContainers(researchText: string, opts?: {
|
|
27
|
+
exclude?: string[];
|
|
28
|
+
}): Array<{
|
|
29
|
+
css: string;
|
|
30
|
+
label: string;
|
|
31
|
+
}>;
|
|
32
|
+
export declare function rebuildSectionMarkdown(section: ResearchSection): string;
|
|
33
|
+
export declare function formatResearchSummary(text: string, opts?: {
|
|
34
|
+
visionUsed?: boolean;
|
|
35
|
+
}): string;
|
|
@@ -69,7 +69,7 @@ export function extractContainerFromBlockquote(sectionMarkdown) {
|
|
|
69
69
|
return css;
|
|
70
70
|
}
|
|
71
71
|
export function parseResearchSections(markdown) {
|
|
72
|
-
const hasExtendedResearch = markdown.
|
|
72
|
+
const hasExtendedResearch = mdq(markdown).query('section1(~"Extended Research")').count() > 0;
|
|
73
73
|
return parseSections(markdown)
|
|
74
74
|
.filter((s) => !SKIP_SECTIONS.has(s.name.toLowerCase()) && !s.name.toLowerCase().includes('data:'))
|
|
75
75
|
.map((section) => {
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Locator } from './locators.js';
|
|
2
|
+
import { type ResearchSection } from './parser.js';
|
|
3
|
+
export declare class ResearchResult {
|
|
4
|
+
text: string;
|
|
5
|
+
url: string;
|
|
6
|
+
createdAt: Date;
|
|
7
|
+
locators: Locator[];
|
|
8
|
+
constructor(text: string, url: string);
|
|
9
|
+
parseLocators(): void;
|
|
10
|
+
get containers(): string[];
|
|
11
|
+
get containerLocators(): Locator[];
|
|
12
|
+
rebuildSectionInText(section: ResearchSection): void;
|
|
13
|
+
cleanup(): void;
|
|
14
|
+
reorderColumns(columns: string[]): string[];
|
|
15
|
+
}
|
|
@@ -42,25 +42,6 @@ export class ResearchResult {
|
|
|
42
42
|
pwLocator: null,
|
|
43
43
|
}));
|
|
44
44
|
}
|
|
45
|
-
updateSection(sectionName, locators) {
|
|
46
|
-
const sections = parseResearchSections(this.text);
|
|
47
|
-
const section = sections.find((s) => s.name === sectionName);
|
|
48
|
-
if (!section)
|
|
49
|
-
return;
|
|
50
|
-
for (const el of section.elements) {
|
|
51
|
-
const elLocators = locators.filter((l) => l.element === el.name);
|
|
52
|
-
for (const loc of elLocators) {
|
|
53
|
-
const value = loc.valid === false ? null : loc.locator || null;
|
|
54
|
-
if (loc.type === 'css')
|
|
55
|
-
el.css = value;
|
|
56
|
-
if (loc.type === 'xpath')
|
|
57
|
-
el.xpath = value;
|
|
58
|
-
if (loc.type === 'aria')
|
|
59
|
-
el.aria = value ? parseAriaLocator(value) : null;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
this.rebuildSectionInText(section);
|
|
63
|
-
}
|
|
64
45
|
rebuildSectionInText(section) {
|
|
65
46
|
if (section.elements.length === 0)
|
|
66
47
|
return;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ActionResult } from '../../action-result.js';
|
|
2
|
+
import type Explorer from '../../explorer.js';
|
|
3
|
+
import type { StateManager } from '../../state-manager.js';
|
|
4
|
+
import type { Provider } from '../provider.js';
|
|
5
|
+
import type { Constructor } from './mixin.js';
|
|
6
|
+
export interface SectionMethods {
|
|
7
|
+
researchBySections(): Promise<string>;
|
|
8
|
+
}
|
|
9
|
+
export declare function WithSections<T extends Constructor>(Base: T): {
|
|
10
|
+
new (...args: any[]): {
|
|
11
|
+
explorer: Explorer;
|
|
12
|
+
provider: Provider;
|
|
13
|
+
stateManager: StateManager;
|
|
14
|
+
actionResult: ActionResult | undefined;
|
|
15
|
+
researchBySections(): Promise<string>;
|
|
16
|
+
_detectFocusCss(): Promise<string | null>;
|
|
17
|
+
_researchSingleSection(name: string, description: string, ariaSnapshot: string, focusCss: string | null): Promise<string>;
|
|
18
|
+
};
|
|
19
|
+
} & T;
|
|
@@ -89,9 +89,13 @@ export function WithSections(Base) {
|
|
|
89
89
|
</section_format>
|
|
90
90
|
|
|
91
91
|
<rules>
|
|
92
|
-
-
|
|
92
|
+
- List only elements physically inside this section's declared container.
|
|
93
|
+
- Do not copy global toolbar, navigation, list, or detail elements into this section unless they are descendants of this section container.
|
|
94
|
+
- Every element with eidx inside this section's container MUST appear in the table.
|
|
93
95
|
- Every row needs CSS; ARIA may be "-" for icon-only buttons.
|
|
94
96
|
- ARIA locator JSON uses keys "role" and "text" (NOT "name").
|
|
97
|
+
- Elements marked data-explorbot-hit="covered" or "offscreen" are not directly actionable; describe the covering or focused UI first.
|
|
98
|
+
- In split-pane pages, entity detail panels are active detail context; include close/back/pin controls in the detail panel section when present.
|
|
95
99
|
</rules>
|
|
96
100
|
|
|
97
101
|
${generalLocatorRuleText}
|