explorbot 0.1.32-beta.1 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -19
- package/bin/explorbot-cli.ts +33 -10
- package/boat/api-tester/src/config.ts +45 -3
- package/boat/doc-collector/src/ai/documentarian.ts +26 -28
- package/boat/doc-collector/src/ai/tools.ts +74 -16
- package/boat/doc-collector/src/cli.ts +1 -6
- package/boat/doc-collector/src/docbot.ts +30 -9
- package/boat/doc-collector/src/docs-renderer.ts +19 -24
- package/boat/doc-collector/src/screenshots.ts +34 -2
- package/boat/doc-collector/src/state-diagram.ts +281 -0
- package/dist/bin/explorbot-cli.js +29 -9
- package/dist/boat/api-tester/src/config.js +43 -4
- package/dist/boat/doc-collector/src/ai/documentarian.js +19 -7
- package/dist/boat/doc-collector/src/ai/tools.js +53 -16
- package/dist/boat/doc-collector/src/cli.js +1 -5
- package/dist/boat/doc-collector/src/docbot.js +27 -8
- package/dist/boat/doc-collector/src/docs-renderer.js +18 -3
- package/dist/boat/doc-collector/src/screenshots.js +30 -1
- package/dist/boat/doc-collector/src/state-diagram.js +200 -0
- package/dist/models.json +30 -0
- package/dist/package.json +23 -3
- package/dist/src/action-result.d.ts +8 -10
- package/dist/src/action-result.js +72 -164
- package/dist/src/action.d.ts +13 -12
- package/dist/src/action.js +37 -113
- package/dist/src/ai/agent.d.ts +17 -0
- package/dist/src/ai/captain/idle-mode.js +1 -1
- package/dist/src/ai/captain/test-mode.js +1 -1
- package/dist/src/ai/captain/web-mode.js +18 -29
- package/dist/src/ai/captain.d.ts +1 -3
- package/dist/src/ai/captain.js +17 -45
- package/dist/src/ai/conversation.d.ts +2 -5
- package/dist/src/ai/conversation.js +9 -28
- package/dist/src/ai/driller.d.ts +2 -17
- package/dist/src/ai/driller.js +26 -50
- package/dist/src/ai/experience-compactor.d.ts +2 -2
- package/dist/src/ai/experience-compactor.js +16 -33
- package/dist/src/ai/fisherman-tools.js +1 -1
- package/dist/src/ai/fisherman.d.ts +0 -1
- package/dist/src/ai/fisherman.js +0 -3
- package/dist/src/ai/historian/codeceptjs.d.ts +2 -0
- package/dist/src/ai/historian/codeceptjs.js +4 -3
- package/dist/src/ai/historian/playwright.d.ts +4 -1
- package/dist/src/ai/historian/playwright.js +4 -3
- package/dist/src/ai/historian/screencast.d.ts +2 -1
- package/dist/src/ai/historian/screencast.js +2 -2
- package/dist/src/ai/historian/utils.d.ts +0 -1
- package/dist/src/ai/historian/utils.js +0 -1
- package/dist/src/ai/historian.d.ts +10 -8
- package/dist/src/ai/historian.js +1 -5
- package/dist/src/ai/navigator.d.ts +8 -6
- package/dist/src/ai/navigator.js +34 -65
- package/dist/src/ai/pilot.d.ts +13 -8
- package/dist/src/ai/pilot.js +53 -59
- package/dist/src/ai/planner.d.ts +5 -4
- package/dist/src/ai/planner.js +66 -52
- package/dist/src/ai/provider.d.ts +4 -1
- package/dist/src/ai/provider.js +77 -137
- package/dist/src/ai/quartermaster.d.ts +22 -22
- package/dist/src/ai/quartermaster.js +8 -14
- package/dist/src/ai/rerunner.d.ts +3 -13
- package/dist/src/ai/rerunner.js +23 -44
- package/dist/src/ai/researcher/cache.js +11 -18
- package/dist/src/ai/researcher/coordinates.js +4 -3
- package/dist/src/ai/researcher/deep-analysis.d.ts +2 -0
- package/dist/src/ai/researcher/deep-analysis.js +8 -11
- package/dist/src/ai/researcher/locators.d.ts +9 -2
- package/dist/src/ai/researcher/locators.js +65 -8
- package/dist/src/ai/researcher/parser.js +1 -1
- package/dist/src/ai/researcher/research-result.d.ts +0 -1
- package/dist/src/ai/researcher/research-result.js +0 -19
- package/dist/src/ai/researcher/sections.d.ts +2 -0
- package/dist/src/ai/researcher/sections.js +7 -3
- package/dist/src/ai/researcher.js +40 -106
- package/dist/src/ai/rules.d.ts +1 -0
- package/dist/src/ai/rules.js +22 -15
- package/dist/src/ai/session-analyst.js +8 -5
- package/dist/src/ai/task-agent.d.ts +19 -6
- package/dist/src/ai/task-agent.js +37 -33
- package/dist/src/ai/tester.d.ts +6 -14
- package/dist/src/ai/tester.js +46 -111
- package/dist/src/ai/tools.d.ts +26 -14
- package/dist/src/ai/tools.js +138 -132
- package/dist/src/command-handler.js +1 -1
- package/dist/src/commands/compact-command.d.ts +1 -1
- package/dist/src/commands/compact-command.js +6 -6
- package/dist/src/commands/context-aria-command.js +1 -1
- package/dist/src/commands/context-command.js +8 -6
- package/dist/src/commands/context-data-command.js +2 -2
- package/dist/src/commands/context-experience-command.js +2 -2
- package/dist/src/commands/context-html-command.js +2 -2
- package/dist/src/commands/context-knowledge-command.js +2 -2
- package/dist/src/commands/drill-command.js +1 -1
- package/dist/src/commands/experience-command.js +1 -1
- package/dist/src/commands/explore-command.js +4 -3
- package/dist/src/commands/freesail-command.js +2 -2
- package/dist/src/commands/knows-command.js +1 -1
- package/dist/src/commands/learn-command.js +5 -3
- package/dist/src/commands/path-command.js +1 -1
- package/dist/src/commands/research-command.js +1 -1
- package/dist/src/commands/test-command.js +1 -1
- package/dist/src/components/AddKnowledge.d.ts +2 -0
- package/dist/src/components/AddKnowledge.js +3 -7
- package/dist/src/components/App.js +3 -3
- package/dist/src/config.d.ts +19 -0
- package/dist/src/config.js +156 -10
- package/dist/src/experience-tracker.d.ts +11 -6
- package/dist/src/experience-tracker.js +82 -155
- package/dist/src/explorbot.d.ts +21 -13
- package/dist/src/explorbot.js +84 -80
- package/dist/src/explorer.d.ts +66 -102
- package/dist/src/explorer.js +332 -623
- package/dist/src/knowledge-tracker.d.ts +2 -2
- package/dist/src/knowledge-tracker.js +38 -45
- package/dist/src/state-manager.d.ts +10 -30
- package/dist/src/state-manager.js +11 -129
- package/dist/src/utils/aria.d.ts +6 -1
- package/dist/src/utils/aria.js +4 -1
- package/dist/src/utils/cache.d.ts +15 -0
- package/dist/src/utils/cache.js +34 -0
- package/dist/src/utils/context-formatter.d.ts +6 -0
- package/dist/src/utils/context-formatter.js +15 -27
- package/dist/src/utils/hooks-runner.js +2 -4
- package/dist/src/utils/html.d.ts +5 -0
- package/dist/src/utils/html.js +71 -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-query.d.ts +6 -0
- package/dist/src/utils/markdown-query.js +14 -1
- package/dist/src/utils/page-readiness.d.ts +1 -0
- package/dist/src/utils/page-readiness.js +1 -1
- package/dist/src/utils/secrets.js +2 -2
- package/dist/src/utils/strings.d.ts +2 -0
- package/dist/src/utils/strings.js +10 -0
- package/dist/src/utils/test-files.js +1 -1
- package/dist/src/utils/web-annotate.d.ts +5 -0
- package/dist/src/utils/web-annotate.js +58 -0
- package/dist/src/utils/web-eidx.d.ts +2 -0
- package/dist/src/utils/web-eidx.js +20 -0
- package/dist/src/utils/web-element.d.ts +3 -1
- package/dist/src/utils/web-element.js +32 -0
- package/dist/src/utils/web-sandbox.d.ts +4 -0
- package/dist/src/utils/web-sandbox.js +37 -0
- package/models.json +30 -0
- package/package.json +23 -3
- package/src/action-result.ts +70 -173
- package/src/action.ts +38 -132
- package/src/ai/agent.ts +20 -0
- package/src/ai/captain/idle-mode.ts +1 -1
- package/src/ai/captain/test-mode.ts +1 -1
- package/src/ai/captain/web-mode.ts +18 -30
- package/src/ai/captain.ts +17 -42
- package/src/ai/conversation.ts +9 -32
- package/src/ai/driller.ts +53 -83
- 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 +5 -3
- package/src/ai/historian/playwright.ts +7 -4
- package/src/ai/historian/screencast.ts +4 -3
- package/src/ai/historian/utils.ts +0 -1
- package/src/ai/historian.ts +6 -8
- package/src/ai/navigator.ts +39 -70
- package/src/ai/pilot.ts +59 -61
- package/src/ai/planner.ts +76 -62
- package/src/ai/provider.ts +85 -146
- package/src/ai/quartermaster.ts +39 -45
- package/src/ai/rerunner.ts +27 -50
- package/src/ai/researcher/cache.ts +10 -16
- package/src/ai/researcher/coordinates.ts +4 -3
- package/src/ai/researcher/deep-analysis.ts +10 -11
- package/src/ai/researcher/locators.ts +66 -9
- package/src/ai/researcher/parser.ts +1 -1
- package/src/ai/researcher/research-result.ts +0 -18
- package/src/ai/researcher/sections.ts +9 -3
- package/src/ai/researcher.ts +42 -119
- package/src/ai/rules.ts +24 -13
- package/src/ai/session-analyst.ts +8 -5
- package/src/ai/task-agent.ts +45 -38
- package/src/ai/tester.ts +51 -129
- package/src/ai/tools.ts +145 -153
- package/src/command-handler.ts +1 -1
- package/src/commands/compact-command.ts +7 -8
- package/src/commands/context-aria-command.ts +1 -1
- package/src/commands/context-command.ts +8 -6
- package/src/commands/context-data-command.ts +2 -2
- package/src/commands/context-experience-command.ts +2 -2
- package/src/commands/context-html-command.ts +2 -2
- package/src/commands/context-knowledge-command.ts +2 -2
- package/src/commands/drill-command.ts +1 -1
- package/src/commands/experience-command.ts +1 -1
- package/src/commands/explore-command.ts +4 -3
- package/src/commands/freesail-command.ts +2 -2
- package/src/commands/knows-command.ts +1 -1
- package/src/commands/learn-command.ts +5 -3
- package/src/commands/path-command.ts +1 -1
- package/src/commands/research-command.ts +1 -1
- package/src/commands/test-command.ts +1 -1
- package/src/components/AddKnowledge.tsx +5 -7
- package/src/components/App.tsx +3 -3
- package/src/config.ts +185 -11
- package/src/experience-tracker.ts +89 -152
- package/src/explorbot.ts +88 -83
- package/src/explorer.ts +402 -693
- package/src/knowledge-tracker.ts +42 -49
- package/src/state-manager.ts +20 -155
- 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/hooks-runner.ts +2 -4
- 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 +2 -3
- package/src/utils/strings.ts +12 -0
- package/src/utils/test-files.ts +1 -1
- package/src/utils/web-annotate.ts +64 -0
- package/src/utils/web-eidx.ts +21 -0
- package/src/utils/web-element.ts +34 -0
- package/src/utils/web-sandbox.ts +43 -0
- package/dist/boat/api-tester/example/apibot.config.js +0 -30
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { basename } from 'node:path';
|
|
2
2
|
import chalk from 'chalk';
|
|
3
|
+
import { COMPACT_MAX_LENGTH } from '../ai/experience-compactor.js';
|
|
3
4
|
import { tag } from '../utils/logger.js';
|
|
4
5
|
import { BaseCommand } from './base-command.js';
|
|
5
|
-
const COMPACT_THRESHOLD = 5000;
|
|
6
6
|
export class CompactCommand extends BaseCommand {
|
|
7
7
|
name = 'compact';
|
|
8
8
|
description = 'Compact stored experience files; optionally filtered by filename or URL substring';
|
|
@@ -16,7 +16,7 @@ export class CompactCommand extends BaseCommand {
|
|
|
16
16
|
const target = remaining[0];
|
|
17
17
|
const dryRun = !!opts.dryRun;
|
|
18
18
|
const merge = opts.merge !== false;
|
|
19
|
-
const tracker = this.explorBot.
|
|
19
|
+
const tracker = this.explorBot.experienceTracker();
|
|
20
20
|
const files = this.resolveTarget(tracker, target);
|
|
21
21
|
if (files === null) {
|
|
22
22
|
tag('info').log('No experience files found.');
|
|
@@ -51,7 +51,7 @@ export class CompactCommand extends BaseCommand {
|
|
|
51
51
|
buildDryRunSuggestions(compactor, files, target) {
|
|
52
52
|
const wouldTouch = files.filter((f) => {
|
|
53
53
|
const stripped = compactor.stripNonUsefulEntries(f.content);
|
|
54
|
-
return stripped !== f.content || stripped.length >=
|
|
54
|
+
return stripped !== f.content || stripped.length >= COMPACT_MAX_LENGTH || compactor.isRecent(f);
|
|
55
55
|
});
|
|
56
56
|
if (wouldTouch.length === 0)
|
|
57
57
|
return [];
|
|
@@ -62,7 +62,7 @@ export class CompactCommand extends BaseCommand {
|
|
|
62
62
|
async runFullSweep(compactor, merge) {
|
|
63
63
|
if (!merge) {
|
|
64
64
|
tag('info').log('Compacting all experience files (merge skipped)…');
|
|
65
|
-
const compacted = await compactor.compactFiles(this.explorBot.
|
|
65
|
+
const compacted = await compactor.compactFiles(this.explorBot.experienceTracker().getAllExperience());
|
|
66
66
|
return { merged: 0, compacted };
|
|
67
67
|
}
|
|
68
68
|
tag('info').log('Merging experience files with similar URLs, then compacting all…');
|
|
@@ -101,7 +101,7 @@ export class CompactCommand extends BaseCommand {
|
|
|
101
101
|
const charsRemoved = chars - strippedChars;
|
|
102
102
|
const willStrip = stripped !== file.content;
|
|
103
103
|
const willReview = compactor.isRecent(file);
|
|
104
|
-
const willAi = strippedChars >=
|
|
104
|
+
const willAi = strippedChars >= COMPACT_MAX_LENGTH;
|
|
105
105
|
if (willStrip)
|
|
106
106
|
wouldStrip++;
|
|
107
107
|
if (willReview)
|
|
@@ -131,7 +131,7 @@ export class CompactCommand extends BaseCommand {
|
|
|
131
131
|
lines.push(` ${chalk.dim('Files matched:')} ${chalk.bold(String(files.length))}`);
|
|
132
132
|
lines.push(` ${chalk.dim('Would strip:')} ${chalk.bold(String(wouldStrip))} ${chalk.dim('(remove legacy / FAILED / Visual click, rename to FLOW/ACTION)')}`);
|
|
133
133
|
lines.push(` ${chalk.dim('Would ai-review:')} ${chalk.bold(String(wouldAiReview))} ${chalk.dim('(recent files ≤30d — quality/reusability check)')}`);
|
|
134
|
-
lines.push(` ${chalk.dim('Would ai-compact:')} ${chalk.bold(String(wouldAiCompact))} ${chalk.dim(`(over ${
|
|
134
|
+
lines.push(` ${chalk.dim('Would ai-compact:')} ${chalk.bold(String(wouldAiCompact))} ${chalk.dim(`(over ${COMPACT_MAX_LENGTH} chars after strip)`)}`);
|
|
135
135
|
lines.push(` ${chalk.dim('Total chars:')} ${chalk.bold(String(totalChars))}`);
|
|
136
136
|
tag('info').log(lines.join('\n'));
|
|
137
137
|
}
|
|
@@ -4,7 +4,7 @@ export class ContextAriaCommand extends BaseCommand {
|
|
|
4
4
|
name = 'context:aria';
|
|
5
5
|
description = 'Print full ARIA snapshot for current page';
|
|
6
6
|
async execute(_args) {
|
|
7
|
-
const state = this.explorBot.
|
|
7
|
+
const state = this.explorBot.stateManager().getCurrentState();
|
|
8
8
|
if (!state) {
|
|
9
9
|
throw new Error('No active page to snapshot');
|
|
10
10
|
}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { Researcher } from '../ai/researcher.js';
|
|
2
|
+
import { visuallyAnnotateContainers } from '../ai/researcher/coordinates.js';
|
|
2
3
|
import { outputPath } from '../config.js';
|
|
3
4
|
import { formatContextSummary } from '../utils/context-formatter.js';
|
|
4
5
|
import { tag } from '../utils/logger.js';
|
|
5
6
|
import { extractValidContainers } from '../utils/research-parser.js';
|
|
7
|
+
import { annotatePageElements } from '../utils/web-annotate.js';
|
|
6
8
|
import { BaseCommand } from './base-command.js';
|
|
7
9
|
export class ContextCommand extends BaseCommand {
|
|
8
10
|
name = 'context';
|
|
@@ -22,21 +24,21 @@ export class ContextCommand extends BaseCommand {
|
|
|
22
24
|
];
|
|
23
25
|
async execute(args) {
|
|
24
26
|
const explorer = this.explorBot.getExplorer();
|
|
25
|
-
const state =
|
|
27
|
+
const state = this.explorBot.stateManager().getCurrentState();
|
|
26
28
|
if (!state) {
|
|
27
29
|
throw new Error('No active page to show context for');
|
|
28
30
|
}
|
|
29
31
|
const { opts } = this.parseArgs(args);
|
|
30
32
|
const isVisual = !!(opts.visual || opts.screenshot);
|
|
31
|
-
await explorer.
|
|
33
|
+
await explorer.withPage(annotatePageElements);
|
|
32
34
|
if (isVisual) {
|
|
33
35
|
const cachedResearch = Researcher.getCachedResearch(state);
|
|
34
36
|
const containers = cachedResearch ? extractValidContainers(cachedResearch) : [];
|
|
35
|
-
await explorer.
|
|
37
|
+
await explorer.withPage((page) => visuallyAnnotateContainers(page, containers));
|
|
36
38
|
}
|
|
37
|
-
const actionResult = await explorer.
|
|
38
|
-
const experienceTracker =
|
|
39
|
-
const knowledgeTracker = this.explorBot.
|
|
39
|
+
const actionResult = await explorer.capture({ screenshot: isVisual });
|
|
40
|
+
const experienceTracker = this.explorBot.experienceTracker();
|
|
41
|
+
const knowledgeTracker = this.explorBot.knowledgeTracker();
|
|
40
42
|
let mode = 'compact';
|
|
41
43
|
if (opts.full) {
|
|
42
44
|
mode = 'full';
|
|
@@ -6,14 +6,14 @@ export class ContextDataCommand extends BaseCommand {
|
|
|
6
6
|
description = 'Extract structured data from current page';
|
|
7
7
|
async execute(_args) {
|
|
8
8
|
const explorer = this.explorBot.getExplorer();
|
|
9
|
-
const state =
|
|
9
|
+
const state = this.explorBot.stateManager().getCurrentState();
|
|
10
10
|
if (!state) {
|
|
11
11
|
throw new Error('No active page to extract data from');
|
|
12
12
|
}
|
|
13
13
|
const actionResult = ActionResult.fromState(state);
|
|
14
14
|
if (!actionResult.html || actionResult.html.trim().length < 100) {
|
|
15
15
|
tag('info').log('Capturing fresh page content...');
|
|
16
|
-
const freshResult = await explorer.
|
|
16
|
+
const freshResult = await explorer.capture();
|
|
17
17
|
const table = await this.explorBot.agentResearcher().extractData(freshResult);
|
|
18
18
|
tag('multiline').log(table);
|
|
19
19
|
return;
|
|
@@ -8,12 +8,12 @@ export class ContextExperienceCommand extends BaseCommand {
|
|
|
8
8
|
description = 'Print all matching experience for current page';
|
|
9
9
|
async execute(_args) {
|
|
10
10
|
const explorer = this.explorBot.getExplorer();
|
|
11
|
-
const state =
|
|
11
|
+
const state = this.explorBot.stateManager().getCurrentState();
|
|
12
12
|
if (!state) {
|
|
13
13
|
throw new Error('No active page');
|
|
14
14
|
}
|
|
15
15
|
const actionResult = ActionResult.fromState(state);
|
|
16
|
-
const experienceTracker =
|
|
16
|
+
const experienceTracker = this.explorBot.experienceTracker();
|
|
17
17
|
const experience = experienceTracker.getRelevantExperience(actionResult);
|
|
18
18
|
if (experience.length === 0) {
|
|
19
19
|
tag('info').log(`No experience found for: ${actionResult.url}`);
|
|
@@ -6,7 +6,7 @@ export class ContextHtmlCommand extends BaseCommand {
|
|
|
6
6
|
description = 'Print combined HTML snapshot for current page';
|
|
7
7
|
async execute(_args) {
|
|
8
8
|
const explorer = this.explorBot.getExplorer();
|
|
9
|
-
const manager =
|
|
9
|
+
const manager = this.explorBot.stateManager();
|
|
10
10
|
const state = manager.getCurrentState();
|
|
11
11
|
if (!state) {
|
|
12
12
|
throw new Error('No active page to snapshot');
|
|
@@ -14,7 +14,7 @@ export class ContextHtmlCommand extends BaseCommand {
|
|
|
14
14
|
let actionResult = ActionResult.fromState(state);
|
|
15
15
|
if (!actionResult.html || actionResult.html.trim().length < 100) {
|
|
16
16
|
tag('info').log('Capturing fresh page content...');
|
|
17
|
-
actionResult = await explorer.
|
|
17
|
+
actionResult = await explorer.capture();
|
|
18
18
|
}
|
|
19
19
|
const html = await actionResult.combinedHtml();
|
|
20
20
|
if (!html) {
|
|
@@ -8,12 +8,12 @@ export class ContextKnowledgeCommand extends BaseCommand {
|
|
|
8
8
|
description = 'Print all matching knowledge for current page';
|
|
9
9
|
async execute(_args) {
|
|
10
10
|
const explorer = this.explorBot.getExplorer();
|
|
11
|
-
const state =
|
|
11
|
+
const state = this.explorBot.stateManager().getCurrentState();
|
|
12
12
|
if (!state) {
|
|
13
13
|
throw new Error('No active page');
|
|
14
14
|
}
|
|
15
15
|
const actionResult = ActionResult.fromState(state);
|
|
16
|
-
const knowledgeTracker = this.explorBot.
|
|
16
|
+
const knowledgeTracker = this.explorBot.knowledgeTracker();
|
|
17
17
|
const knowledge = knowledgeTracker.getRelevantKnowledge(actionResult);
|
|
18
18
|
if (knowledge.length === 0) {
|
|
19
19
|
tag('info').log(`No knowledge found for: ${actionResult.url}`);
|
|
@@ -10,7 +10,7 @@ export class DrillCommand extends BaseCommand {
|
|
|
10
10
|
async execute(args) {
|
|
11
11
|
const knowledgePath = this.parseKnowledgeArg(args);
|
|
12
12
|
const maxComponents = this.parseMaxArg(args);
|
|
13
|
-
const state = this.explorBot.
|
|
13
|
+
const state = this.explorBot.stateManager().getCurrentState();
|
|
14
14
|
if (!state) {
|
|
15
15
|
throw new Error('No active page to drill');
|
|
16
16
|
}
|
|
@@ -16,7 +16,7 @@ export class ExperienceCommand extends BaseCommand {
|
|
|
16
16
|
return;
|
|
17
17
|
}
|
|
18
18
|
const recency = opts.recent ? 'recent' : opts.old ? 'old' : undefined;
|
|
19
|
-
const tracker = this.explorBot.
|
|
19
|
+
const tracker = this.explorBot.experienceTracker();
|
|
20
20
|
const [first, second] = remaining;
|
|
21
21
|
const combinedRef = first?.match(/^([A-Z]+)[.\-]?(\d+)$/i);
|
|
22
22
|
if (combinedRef) {
|
|
@@ -4,6 +4,7 @@ import { outputPath } from '../config.js';
|
|
|
4
4
|
import { normalizeUrl } from '../state-manager.js';
|
|
5
5
|
import { Stats } from '../stats.js';
|
|
6
6
|
import { TestResult } from '../test-plan.js';
|
|
7
|
+
import { browserErrorMessage } from "../utils/browser-errors.js";
|
|
7
8
|
import { getCliName } from "../utils/cli-name.js";
|
|
8
9
|
import { ErrorPageError, getStateErrorPageError } from "../utils/error-page.js";
|
|
9
10
|
import { tag } from '../utils/logger.js';
|
|
@@ -34,7 +35,7 @@ export class ExploreCommand extends BaseCommand {
|
|
|
34
35
|
oldTestRefs = new Set();
|
|
35
36
|
priorityFilter;
|
|
36
37
|
getCurrentPageUrl() {
|
|
37
|
-
const state = this.explorBot.
|
|
38
|
+
const state = this.explorBot.stateManager().getCurrentState();
|
|
38
39
|
return state?.fullUrl || state?.url;
|
|
39
40
|
}
|
|
40
41
|
async execute(args) {
|
|
@@ -53,7 +54,7 @@ export class ExploreCommand extends BaseCommand {
|
|
|
53
54
|
Stats.mode ??= 'explore';
|
|
54
55
|
Stats.focus ??= feature;
|
|
55
56
|
const mainUrl = this.getCurrentPageUrl();
|
|
56
|
-
const error = getStateErrorPageError(this.explorBot.
|
|
57
|
+
const error = getStateErrorPageError(this.explorBot.stateManager().getCurrentState());
|
|
57
58
|
if (error) {
|
|
58
59
|
tag('warning').log(error.message);
|
|
59
60
|
return;
|
|
@@ -72,7 +73,7 @@ export class ExploreCommand extends BaseCommand {
|
|
|
72
73
|
return;
|
|
73
74
|
}
|
|
74
75
|
if (mainUrl)
|
|
75
|
-
await this.explorBot.visit(mainUrl);
|
|
76
|
+
await this.explorBot.visit(mainUrl).catch((err) => tag('warning').log(`Could not return to ${mainUrl}: ${browserErrorMessage(err)}`));
|
|
76
77
|
const savedPath = this.explorBot.savePlans(this.completedPlans);
|
|
77
78
|
this.printResults();
|
|
78
79
|
await this.explorBot.printSessionAnalysis();
|
|
@@ -31,7 +31,7 @@ export class FreesailCommand extends BaseCommand {
|
|
|
31
31
|
await loop(async (ctx) => {
|
|
32
32
|
if (maxTests != null && testsRun >= maxTests)
|
|
33
33
|
ctx.stop();
|
|
34
|
-
const stateManager = this.explorBot.
|
|
34
|
+
const stateManager = this.explorBot.stateManager();
|
|
35
35
|
const state = stateManager.getCurrentState();
|
|
36
36
|
if (state && !Researcher.getCachedResearch(state)) {
|
|
37
37
|
await this.explorBot.agentResearcher().research(state, { deep: true, screenshot: true });
|
|
@@ -63,7 +63,7 @@ export class FreesailCommand extends BaseCommand {
|
|
|
63
63
|
return;
|
|
64
64
|
}
|
|
65
65
|
tag('info').log(`Navigating to: ${suggestion.target} - ${suggestion.reason}`);
|
|
66
|
-
await this.explorBot.
|
|
66
|
+
await this.explorBot.openTab();
|
|
67
67
|
await this.explorBot.visit(suggestion.target);
|
|
68
68
|
this.explorBot.clearPlan();
|
|
69
69
|
}, { maxAttempts: Number.POSITIVE_INFINITY });
|
|
@@ -17,7 +17,7 @@ export class KnowsCommand extends BaseCommand {
|
|
|
17
17
|
description = 'List all knowledge URLs or show matching knowledge for a URL';
|
|
18
18
|
async execute(args, limit = 0) {
|
|
19
19
|
const url = args.trim();
|
|
20
|
-
const tracker = this.explorBot.
|
|
20
|
+
const tracker = this.explorBot.knowledgeTracker();
|
|
21
21
|
if (!url) {
|
|
22
22
|
const allKnowledge = tracker.listAllKnowledge();
|
|
23
23
|
if (allKnowledge.length === 0) {
|
|
@@ -10,10 +10,12 @@ export class LearnCommand extends BaseCommand {
|
|
|
10
10
|
const note = args.trim();
|
|
11
11
|
if (!note) {
|
|
12
12
|
const AddKnowledge = (await import('../components/AddKnowledge.js')).default;
|
|
13
|
-
const
|
|
13
|
+
const explorer = this.explorBot.getExplorer();
|
|
14
|
+
const state = this.explorBot.stateManager().getCurrentState();
|
|
14
15
|
const initialUrl = state?.url || '';
|
|
15
16
|
const { unmount } = render(React.createElement(AddKnowledge, {
|
|
16
17
|
initialUrl,
|
|
18
|
+
knowledgeTracker: this.explorBot.knowledgeTracker(),
|
|
17
19
|
onComplete: () => unmount(),
|
|
18
20
|
onCancel: () => unmount(),
|
|
19
21
|
}), {
|
|
@@ -23,12 +25,12 @@ export class LearnCommand extends BaseCommand {
|
|
|
23
25
|
return;
|
|
24
26
|
}
|
|
25
27
|
const explorer = this.explorBot.getExplorer();
|
|
26
|
-
const state =
|
|
28
|
+
const state = this.explorBot.stateManager().getCurrentState();
|
|
27
29
|
if (!state) {
|
|
28
30
|
throw new Error('No active page to attach knowledge');
|
|
29
31
|
}
|
|
30
32
|
const targetUrl = state.url || state.fullUrl || '/';
|
|
31
|
-
|
|
33
|
+
this.explorBot.knowledgeTracker().addKnowledge(targetUrl, note);
|
|
32
34
|
tag('success').log('Knowledge saved for current page');
|
|
33
35
|
}
|
|
34
36
|
}
|
|
@@ -7,7 +7,7 @@ export class PathCommand extends BaseCommand {
|
|
|
7
7
|
async execute(args) {
|
|
8
8
|
const { opts } = this.parseArgs(args);
|
|
9
9
|
const showLinks = !!opts.links;
|
|
10
|
-
const stateManager = this.explorBot.
|
|
10
|
+
const stateManager = this.explorBot.stateManager();
|
|
11
11
|
const history = stateManager.getStateHistory();
|
|
12
12
|
if (history.length === 0) {
|
|
13
13
|
tag('multiline').log('No navigation history yet.');
|
|
@@ -23,7 +23,7 @@ export class ResearchCommand extends BaseCommand {
|
|
|
23
23
|
if (target) {
|
|
24
24
|
await this.explorBot.agentNavigator().visit(target);
|
|
25
25
|
}
|
|
26
|
-
const state = this.explorBot.
|
|
26
|
+
const state = this.explorBot.stateManager().getCurrentState();
|
|
27
27
|
if (!state) {
|
|
28
28
|
throw new Error('No active page to research');
|
|
29
29
|
}
|
|
@@ -48,7 +48,7 @@ export class TestCommand extends BaseCommand {
|
|
|
48
48
|
toExecute.push(...matching);
|
|
49
49
|
}
|
|
50
50
|
else {
|
|
51
|
-
const state = this.explorBot.
|
|
51
|
+
const state = this.explorBot.stateManager().getCurrentState();
|
|
52
52
|
if (!state) {
|
|
53
53
|
throw new Error('No page loaded. Please navigate to a page first.');
|
|
54
54
|
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { Box, Text, useInput } from 'ink';
|
|
2
2
|
import React, { useEffect, useState } from 'react';
|
|
3
|
-
import { KnowledgeTracker } from '../knowledge-tracker.js';
|
|
4
3
|
import InputReadline from './InputReadline.js';
|
|
5
|
-
const AddKnowledge = ({ initialUrl = '', onComplete, onCancel }) => {
|
|
4
|
+
const AddKnowledge = ({ initialUrl = '', knowledgeTracker, onComplete, onCancel }) => {
|
|
6
5
|
const [urlPattern, setUrlPattern] = useState(initialUrl);
|
|
7
6
|
const [description, setDescription] = useState('');
|
|
8
7
|
const [activeField, setActiveField] = useState(initialUrl ? 'description' : 'url');
|
|
@@ -11,18 +10,16 @@ const AddKnowledge = ({ initialUrl = '', onComplete, onCancel }) => {
|
|
|
11
10
|
const isStandalone = !onComplete;
|
|
12
11
|
useEffect(() => {
|
|
13
12
|
try {
|
|
14
|
-
const knowledgeTracker = new KnowledgeTracker();
|
|
15
13
|
const urls = knowledgeTracker.getExistingUrls();
|
|
16
14
|
setSuggestedUrls(urls);
|
|
17
15
|
}
|
|
18
16
|
catch (error) {
|
|
19
17
|
console.error('Failed to load suggestions:', error);
|
|
20
18
|
}
|
|
21
|
-
}, []);
|
|
19
|
+
}, [knowledgeTracker]);
|
|
22
20
|
useEffect(() => {
|
|
23
21
|
if (urlPattern.trim()) {
|
|
24
22
|
try {
|
|
25
|
-
const knowledgeTracker = new KnowledgeTracker();
|
|
26
23
|
const knowledge = knowledgeTracker.getKnowledgeForUrl(urlPattern);
|
|
27
24
|
setExistingKnowledge(knowledge);
|
|
28
25
|
}
|
|
@@ -34,13 +31,12 @@ const AddKnowledge = ({ initialUrl = '', onComplete, onCancel }) => {
|
|
|
34
31
|
else {
|
|
35
32
|
setExistingKnowledge([]);
|
|
36
33
|
}
|
|
37
|
-
}, [urlPattern]);
|
|
34
|
+
}, [urlPattern, knowledgeTracker]);
|
|
38
35
|
const handleSave = () => {
|
|
39
36
|
if (!urlPattern.trim() || !description.trim()) {
|
|
40
37
|
return;
|
|
41
38
|
}
|
|
42
39
|
try {
|
|
43
|
-
const knowledgeTracker = new KnowledgeTracker();
|
|
44
40
|
const result = knowledgeTracker.addKnowledge(urlPattern.trim(), description.trim());
|
|
45
41
|
const action = result.isNewFile ? 'Created' : 'Updated';
|
|
46
42
|
console.log(`\nKnowledge ${action} in: ${result.filename}`);
|
|
@@ -47,7 +47,7 @@ export function App({ explorBot, initialShowInput = false, exitOnEmptyInput = fa
|
|
|
47
47
|
userInputPromiseRef.current = { resolve, reject };
|
|
48
48
|
});
|
|
49
49
|
});
|
|
50
|
-
const manager = explorBot.
|
|
50
|
+
const manager = explorBot.stateManager();
|
|
51
51
|
unsubscribe = manager.onStateChange((transition) => {
|
|
52
52
|
if (mounted) {
|
|
53
53
|
setLastTransition(transition);
|
|
@@ -111,7 +111,7 @@ export function App({ explorBot, initialShowInput = false, exitOnEmptyInput = fa
|
|
|
111
111
|
return;
|
|
112
112
|
setChecklistData({
|
|
113
113
|
config: explorBot.getConfig(),
|
|
114
|
-
knowledgeTracker: explorBot.
|
|
114
|
+
knowledgeTracker: explorBot.knowledgeTracker(),
|
|
115
115
|
});
|
|
116
116
|
setShowWelcome(true);
|
|
117
117
|
setShowInput(true);
|
|
@@ -283,7 +283,7 @@ export function App({ explorBot, initialShowInput = false, exitOnEmptyInput = fa
|
|
|
283
283
|
React.createElement(Box, { height: 3, flexDirection: "row", justifyContent: "space-between", alignItems: "center", paddingX: 1 },
|
|
284
284
|
React.createElement(ActivityPane, { isInputVisible: showInput }),
|
|
285
285
|
showSessionTimer && React.createElement(SessionTimer, { startedAt: sessionStartedAtRef.current })),
|
|
286
|
-
showWelcome && React.createElement(WelcomeCommands, { hasKnowledge: explorBot.
|
|
286
|
+
showWelcome && React.createElement(WelcomeCommands, { hasKnowledge: explorBot.knowledgeTracker().listAllKnowledge().length > 0 }),
|
|
287
287
|
showInput && React.createElement(Box, { height: 1 }),
|
|
288
288
|
interruptPrompt && showInput && (React.createElement(Box, { paddingX: 1 },
|
|
289
289
|
React.createElement(Text, { color: "yellow" }, interruptPrompt))),
|
package/dist/src/config.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export declare const PROVIDERS: Record<string, () => Promise<(modelId: string) => any>>;
|
|
1
2
|
interface PlaywrightConfig {
|
|
2
3
|
browser: 'chromium' | 'firefox' | 'webkit';
|
|
3
4
|
url: string;
|
|
@@ -204,6 +205,7 @@ interface ExplorbotConfig {
|
|
|
204
205
|
};
|
|
205
206
|
experience?: {
|
|
206
207
|
maxReadLines?: number;
|
|
208
|
+
disabled?: boolean;
|
|
207
209
|
};
|
|
208
210
|
reporter?: ReporterConfig;
|
|
209
211
|
api?: ApiConfig;
|
|
@@ -213,14 +215,17 @@ interface ExplorbotConfig {
|
|
|
213
215
|
}
|
|
214
216
|
type RuleEntry = string | Record<string, string>;
|
|
215
217
|
export declare const EXPLORBOT_CONFIG_PATHS: string[];
|
|
218
|
+
export declare const EXPLORBOT_ENV_VARS: EnvVar[];
|
|
216
219
|
export type { ExplorbotConfig, PlaywrightConfig, AIConfig, HtmlConfig, ActionConfig, AgentConfig, AgentsConfig, HistorianAgentConfig, ResearcherAgentConfig, NavigatorAgentConfig, PlannerAgentConfig, RerunnerAgentConfig, HealRecipe, Hook, HookConfig, HooksConfig, PlaywrightHook, CodeceptJSHook, HookPatternMap, RuleEntry, ReporterConfig, ApiConfig, WebConfig, ApiHookFn, };
|
|
217
220
|
export declare class ConfigParser {
|
|
218
221
|
static instance: ConfigParser;
|
|
222
|
+
static recommended: Record<string, Record<string, string>> | null;
|
|
219
223
|
config: ExplorbotConfig | null;
|
|
220
224
|
configPath: string | null;
|
|
221
225
|
runtimeBaseUrlOverride: string | null;
|
|
222
226
|
constructor();
|
|
223
227
|
static loadEnv(filePath: string): void;
|
|
228
|
+
static recommendedModels(): Record<string, Record<string, string>>;
|
|
224
229
|
static getInstance(): ConfigParser;
|
|
225
230
|
loadConfig(options?: {
|
|
226
231
|
config?: string;
|
|
@@ -230,6 +235,8 @@ export declare class ConfigParser {
|
|
|
230
235
|
getConfig(): ExplorbotConfig;
|
|
231
236
|
getConfigPath(): string | null;
|
|
232
237
|
getOutputDir(): string;
|
|
238
|
+
getProjectRoot(): string;
|
|
239
|
+
resolveProjectDir(relativeDir: string): string;
|
|
233
240
|
getStatesDir(): string;
|
|
234
241
|
getPlansDir(): string;
|
|
235
242
|
getTestsDir(): string;
|
|
@@ -237,6 +244,7 @@ export declare class ConfigParser {
|
|
|
237
244
|
static setupTestConfig(): void;
|
|
238
245
|
static getTestDirectories(): string[];
|
|
239
246
|
static cleanupAllTestDirectories(): void;
|
|
247
|
+
buildEnvConfig(baseUrl: string | undefined, outputRoot: string): Promise<ExplorbotConfig>;
|
|
240
248
|
findConfigFile(): string | null;
|
|
241
249
|
loadConfigModule(configPath: string): Promise<any>;
|
|
242
250
|
resolveConfig(config: ExplorbotConfig, options?: {
|
|
@@ -249,3 +257,14 @@ export declare class ConfigParser {
|
|
|
249
257
|
ensureDirectory(path: string): void;
|
|
250
258
|
}
|
|
251
259
|
export declare function outputPath(...segments: string[]): string;
|
|
260
|
+
export declare function resolveModel(spec: string, role?: ModelRole): Promise<any>;
|
|
261
|
+
export declare function resolveOutputRoot(): string;
|
|
262
|
+
export declare function materializeKnowledge(outputRoot: string): void;
|
|
263
|
+
export declare function createModel(provider: string, modelId: string): Promise<any>;
|
|
264
|
+
type ModelRole = 'model' | 'visionModel' | 'agenticModel';
|
|
265
|
+
interface EnvVar {
|
|
266
|
+
name: string;
|
|
267
|
+
description: string;
|
|
268
|
+
required?: boolean;
|
|
269
|
+
}
|
|
270
|
+
export type { ModelRole, EnvVar };
|