explorbot 0.1.30 → 0.1.32-beta.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/dist/boat/api-tester/example/apibot.config.js +30 -0
- package/dist/package.json +11 -26
- package/dist/src/action-result.d.ts +133 -0
- package/dist/src/action-result.js +22 -7
- package/dist/src/action.d.ts +50 -0
- package/dist/src/action.js +10 -5
- 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.d.ts +143 -0
- package/dist/src/ai/conversation.d.ts +31 -0
- package/dist/src/ai/conversation.js +1 -1
- package/dist/src/ai/driller.d.ts +161 -0
- package/dist/src/ai/experience-compactor.d.ts +53 -0
- package/dist/src/ai/fisherman-tools.d.ts +90 -0
- package/dist/src/ai/fisherman.d.ts +30 -0
- package/dist/src/ai/historian/codeceptjs.d.ts +15 -0
- 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 +20 -0
- package/dist/src/ai/historian/screencast.d.ts +32 -0
- package/dist/src/ai/historian/utils.d.ts +4 -0
- package/dist/src/ai/historian.d.ts +108 -0
- package/dist/src/ai/navigator.d.ts +56 -0
- package/dist/src/ai/pilot.d.ts +83 -0
- 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/provider.d.ts +50 -0
- package/dist/src/ai/provider.js +13 -5
- package/dist/src/ai/quartermaster.d.ts +57 -0
- package/dist/src/ai/rerunner.d.ts +49 -0
- package/dist/src/ai/researcher/cache.d.ts +6 -0
- 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/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/research-result.d.ts +16 -0
- package/dist/src/ai/researcher/sections.d.ts +19 -0
- package/dist/src/ai/rules.d.ts +15 -0
- package/dist/src/ai/session-analyst.d.ts +11 -0
- package/dist/src/ai/task-agent.d.ts +28 -0
- package/dist/src/ai/tester.d.ts +103 -0
- package/dist/src/ai/tools.d.ts +41 -0
- 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/context-aria-command.d.ts +6 -0
- package/dist/src/commands/context-command.d.ts +11 -0
- 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/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/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/learn-command.d.ts +7 -0
- 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 +8 -0
- package/dist/src/components/AddRule.d.ts +9 -0
- package/dist/src/components/App.d.ts +9 -0
- 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 +251 -0
- package/dist/src/execution-controller.d.ts +25 -0
- package/dist/src/experience-tracker.d.ts +107 -0
- package/dist/src/experience-tracker.js +2 -1
- package/dist/src/explorbot.d.ts +107 -0
- package/dist/src/explorer.d.ts +140 -0
- package/dist/src/explorer.js +13 -9
- 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 +9 -2
- 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 +185 -0
- package/dist/src/state-manager.js +0 -7
- 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 +20 -0
- package/dist/src/utils/browser-errors.d.ts +8 -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 +25 -0
- 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 +124 -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-parser.d.ts +17 -0
- package/dist/src/utils/markdown-query.d.ts +40 -0
- 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 +6 -0
- 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 +3 -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 +44 -0
- package/dist/src/utils/xpath.d.ts +17 -0
- package/package.json +11 -26
- package/src/action-result.ts +22 -7
- package/src/action.ts +12 -5
- package/src/ai/conversation.ts +1 -1
- package/src/ai/provider.ts +13 -5
- package/src/experience-tracker.ts +2 -1
- package/src/explorer.ts +14 -9
- package/src/index.ts +9 -0
- package/src/knowledge-tracker.ts +7 -1
- package/src/observability.ts +2 -1
- package/src/state-manager.ts +0 -8
- package/src/utils/secrets.ts +29 -0
- package/src/index.tsx +0 -62
package/dist/src/index.js
CHANGED
|
@@ -1,55 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import { addKnowledgeCommand } from './commands/add-knowledge.js';
|
|
4
|
-
import { cleanCommand } from './commands/clean.js';
|
|
5
|
-
import { exploreCommand } from './commands/explore.js';
|
|
6
|
-
import { initCommand } from './commands/init.js';
|
|
7
|
-
const program = new Command();
|
|
8
|
-
program
|
|
9
|
-
.name('explorbot')
|
|
10
|
-
.description('AI-powered web exploration tool')
|
|
11
|
-
.option('-f, --from <url>', 'Start exploration from a specific URL')
|
|
12
|
-
.option('-v, --verbose', 'Enable verbose logging')
|
|
13
|
-
.option('--debug', 'Enable debug logging (same as --verbose)')
|
|
14
|
-
.option('-c, --config <path>', 'Path to configuration file')
|
|
15
|
-
.option('-p, --path <path>', 'Working directory path')
|
|
16
|
-
.helpOption('-h, --help', 'Show this help message');
|
|
17
|
-
program
|
|
18
|
-
.command('clean')
|
|
19
|
-
.description('Clean up artifacts or experience folders')
|
|
20
|
-
.option('-t, --type <type>', 'Type of cleanup (artifacts|experience|all)', 'artifacts')
|
|
21
|
-
.option('-p, --path <path>', 'Custom path to clean')
|
|
22
|
-
.action(async (options, command) => {
|
|
23
|
-
const globalOptions = command.parent.opts();
|
|
24
|
-
const allOptions = { ...globalOptions, ...options };
|
|
25
|
-
await cleanCommand(allOptions);
|
|
26
|
-
});
|
|
27
|
-
program
|
|
28
|
-
.command('init')
|
|
29
|
-
.description('Initialize a new project with configuration')
|
|
30
|
-
.option('-c, --config-path <path>', 'Path for the config file', './explorbot.config.js')
|
|
31
|
-
.option('-f, --force', 'Overwrite existing config file', false)
|
|
32
|
-
.option('-p, --path <path>', 'Working directory for initialization')
|
|
33
|
-
.action(async (options, command) => {
|
|
34
|
-
const globalOptions = command.parent.opts();
|
|
35
|
-
const allOptions = { ...globalOptions, ...options };
|
|
36
|
-
await initCommand(allOptions);
|
|
37
|
-
});
|
|
38
|
-
program
|
|
39
|
-
.command('add-knowledge')
|
|
40
|
-
.alias('learn')
|
|
41
|
-
.description('Add knowledge for specific URLs')
|
|
42
|
-
.option('-p, --path <path>', 'Knowledge directory path')
|
|
43
|
-
.action(async (options) => {
|
|
44
|
-
await addKnowledgeCommand(options);
|
|
45
|
-
});
|
|
46
|
-
program.parse();
|
|
47
|
-
const options = program.opts();
|
|
48
|
-
const command = program.args[0];
|
|
49
|
-
if (command === 'clean' || command === 'init' || command === 'add-knowledge' || command === 'learn') {
|
|
50
|
-
// These commands are handled by their respective actions
|
|
51
|
-
}
|
|
52
|
-
else {
|
|
53
|
-
// Default to explore command
|
|
54
|
-
exploreCommand(options);
|
|
55
|
-
}
|
|
1
|
+
export { ExplorBot } from "./explorbot.js";
|
|
2
|
+
export { Plan, Test, TestResult, TestStatus } from "./test-plan.js";
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { ActionResult } from './action-result.js';
|
|
2
|
+
interface Knowledge {
|
|
3
|
+
filePath: string;
|
|
4
|
+
url: string;
|
|
5
|
+
content: string;
|
|
6
|
+
[key: string]: any;
|
|
7
|
+
}
|
|
8
|
+
export declare class KnowledgeTracker {
|
|
9
|
+
knowledgeDir: string;
|
|
10
|
+
knowledgeFiles: Knowledge[];
|
|
11
|
+
isLoaded: boolean;
|
|
12
|
+
constructor();
|
|
13
|
+
loadKnowledgeFiles(): void;
|
|
14
|
+
getRelevantKnowledge(state: ActionResult): Knowledge[];
|
|
15
|
+
addKnowledge(urlPattern: string, description: string): {
|
|
16
|
+
filename: string;
|
|
17
|
+
filePath: string;
|
|
18
|
+
isNewFile: boolean;
|
|
19
|
+
};
|
|
20
|
+
interpolateVars(content: string): string;
|
|
21
|
+
generateFilename(url: string): string;
|
|
22
|
+
getExistingUrls(): string[];
|
|
23
|
+
getKnowledgeForUrl(urlPattern: string): string[];
|
|
24
|
+
listAllKnowledge(): Array<{
|
|
25
|
+
url: string;
|
|
26
|
+
firstLine: string;
|
|
27
|
+
filePath: string;
|
|
28
|
+
}>;
|
|
29
|
+
getMatchingKnowledge(url: string): Knowledge[];
|
|
30
|
+
normalizeUrl(url: string): string;
|
|
31
|
+
getStateParameters(state: ActionResult, keys: string[]): Record<string, any>;
|
|
32
|
+
}
|
|
33
|
+
export {};
|
|
@@ -5,6 +5,7 @@ import { ActionResult } from './action-result.js';
|
|
|
5
5
|
import { ConfigParser } from './config.js';
|
|
6
6
|
import { getCliName } from "./utils/cli-name.js";
|
|
7
7
|
import { createDebug } from './utils/logger.js';
|
|
8
|
+
import { isSecretName, registerSecret } from './utils/secrets.js';
|
|
8
9
|
const debugLog = createDebug('explorbot:knowledge-tracker');
|
|
9
10
|
export class KnowledgeTracker {
|
|
10
11
|
knowledgeDir;
|
|
@@ -109,9 +110,15 @@ export class KnowledgeTracker {
|
|
|
109
110
|
return match;
|
|
110
111
|
const namespace = expr.slice(0, dotIndex);
|
|
111
112
|
const key = expr.slice(dotIndex + 1);
|
|
112
|
-
if (namespace === 'env')
|
|
113
|
-
|
|
113
|
+
if (namespace === 'env') {
|
|
114
|
+
const value = process.env[key] ?? '';
|
|
115
|
+
if (isSecretName(key))
|
|
116
|
+
registerSecret(value);
|
|
117
|
+
return value;
|
|
118
|
+
}
|
|
114
119
|
if (namespace === 'config') {
|
|
120
|
+
if (isSecretName(key))
|
|
121
|
+
return '';
|
|
115
122
|
const config = ConfigParser.getInstance().getConfig();
|
|
116
123
|
const value = key.split('.').reduce((obj, k) => obj?.[k], config);
|
|
117
124
|
if (value !== undefined && typeof value !== 'object')
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type Span } from '@opentelemetry/api';
|
|
2
|
+
type TelemetryMetadata = Record<string, unknown>;
|
|
3
|
+
export declare const Observability: {
|
|
4
|
+
run<T>(name: string, metadata: TelemetryMetadata, fn: () => Promise<T>): Promise<T>;
|
|
5
|
+
getTelemetry(): {
|
|
6
|
+
isEnabled: boolean;
|
|
7
|
+
functionId: string;
|
|
8
|
+
metadata: Record<string, unknown>;
|
|
9
|
+
};
|
|
10
|
+
isTracing(): boolean;
|
|
11
|
+
getSpan(): Span;
|
|
12
|
+
};
|
|
13
|
+
export {};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { trace } from '@opentelemetry/api';
|
|
2
|
+
import { redactSecrets } from './utils/secrets.js';
|
|
2
3
|
let current = null;
|
|
3
4
|
export const Observability = {
|
|
4
5
|
async run(name, metadata, fn) {
|
|
@@ -70,7 +71,7 @@ function buildRootSpanAttributes(name, metadata) {
|
|
|
70
71
|
attributes['langfuse.trace.tags'] = metadata.tags;
|
|
71
72
|
}
|
|
72
73
|
if (metadata.input !== undefined) {
|
|
73
|
-
attributes['langfuse.trace.input'] = JSON.stringify(metadata.input);
|
|
74
|
+
attributes['langfuse.trace.input'] = redactSecrets(JSON.stringify(metadata.input));
|
|
74
75
|
}
|
|
75
76
|
return attributes;
|
|
76
77
|
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export interface TraceCall {
|
|
2
|
+
class: string;
|
|
3
|
+
method: string;
|
|
4
|
+
params: Record<string, any>;
|
|
5
|
+
}
|
|
6
|
+
export interface VerificationStep {
|
|
7
|
+
name: string;
|
|
8
|
+
args: any[];
|
|
9
|
+
}
|
|
10
|
+
export declare class PlaywrightRecorder {
|
|
11
|
+
context: any;
|
|
12
|
+
tracing: any;
|
|
13
|
+
active: boolean;
|
|
14
|
+
nextGroupId: number;
|
|
15
|
+
verifications: VerificationStep[];
|
|
16
|
+
recordVerification(steps: VerificationStep[]): void;
|
|
17
|
+
drainVerifications(): VerificationStep[];
|
|
18
|
+
start(browserContext: any): Promise<void>;
|
|
19
|
+
beginAction(title: string): Promise<string | null>;
|
|
20
|
+
endAction(): Promise<void>;
|
|
21
|
+
exportChunk(): Promise<Map<string, TraceCall[]>>;
|
|
22
|
+
stop(): Promise<void>;
|
|
23
|
+
isActive(): boolean;
|
|
24
|
+
}
|
|
25
|
+
declare function parseTrace(ndjson: string): Map<string, TraceCall[]>;
|
|
26
|
+
export declare function renderCall(call: TraceCall): string;
|
|
27
|
+
export declare function renderAssertion(assertion: {
|
|
28
|
+
name: string;
|
|
29
|
+
args: any[];
|
|
30
|
+
}): string;
|
|
31
|
+
export { parseTrace };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Client } from '@testomatio/reporter';
|
|
2
|
+
import type { Step } from '@testomatio/reporter/types/types.js';
|
|
3
|
+
import type { ReporterConfig } from './config.js';
|
|
4
|
+
import type { StateManager } from './state-manager.js';
|
|
5
|
+
import { Test } from './test-plan.js';
|
|
6
|
+
export type ReporterMeta = Record<string, string | undefined>;
|
|
7
|
+
export interface ReporterStep {
|
|
8
|
+
title: string;
|
|
9
|
+
status: 'passed' | 'failed';
|
|
10
|
+
code: string[];
|
|
11
|
+
discovery?: string;
|
|
12
|
+
}
|
|
13
|
+
export declare class Reporter {
|
|
14
|
+
client: Client;
|
|
15
|
+
isRunStarted: boolean;
|
|
16
|
+
reporterEnabled: boolean;
|
|
17
|
+
stateManager?: StateManager;
|
|
18
|
+
constructor(config?: ReporterConfig, stateManager?: StateManager);
|
|
19
|
+
buildTitle(): string;
|
|
20
|
+
static resolveEnabled(config?: ReporterConfig): boolean;
|
|
21
|
+
configureHtmlPipe(): void;
|
|
22
|
+
configureMarkdownPipe(): void;
|
|
23
|
+
configureRunGroup(runGroup: string | null | undefined): void;
|
|
24
|
+
startRun(): Promise<void>;
|
|
25
|
+
reportTestStart(test: Test): Promise<void>;
|
|
26
|
+
combineStepsAndNotes(test: Test, lastScreenshotFile?: string): Step[];
|
|
27
|
+
buildVerificationStep(test: Test, lastScreenshotFile?: string): Step | undefined;
|
|
28
|
+
reportTest(test: Test, meta?: ReporterMeta): Promise<void>;
|
|
29
|
+
finishRun(): Promise<void>;
|
|
30
|
+
isEnabled(): boolean;
|
|
31
|
+
setRunDescription(text: string): Promise<void>;
|
|
32
|
+
extractLastNoteMessage(test: Test): string;
|
|
33
|
+
reportSteps(test: Test, steps: ReporterStep[]): Promise<void>;
|
|
34
|
+
}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { ActionResult } from './action-result.js';
|
|
2
|
+
import { ExperienceTracker } from './experience-tracker.js';
|
|
3
|
+
export interface Link {
|
|
4
|
+
title: string;
|
|
5
|
+
url: string;
|
|
6
|
+
visible?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export interface WebPageState {
|
|
9
|
+
/** Unique incremental state identifier */
|
|
10
|
+
id?: number;
|
|
11
|
+
/** URL path without domain, including hash: /path/to/page#section */
|
|
12
|
+
url: string;
|
|
13
|
+
/** Page title */
|
|
14
|
+
title?: string;
|
|
15
|
+
/** HTTP status of the main document navigation */
|
|
16
|
+
httpStatus?: number;
|
|
17
|
+
/** Full URL for reference */
|
|
18
|
+
fullUrl?: string;
|
|
19
|
+
/** Timestamp when state was captured */
|
|
20
|
+
timestamp?: Date;
|
|
21
|
+
/** Hash of the state for unique identification */
|
|
22
|
+
hash?: string;
|
|
23
|
+
/** HTML file path */
|
|
24
|
+
htmlFile?: string;
|
|
25
|
+
/** Screenshot file path */
|
|
26
|
+
screenshotFile?: string;
|
|
27
|
+
/** Log file path */
|
|
28
|
+
logFile?: string;
|
|
29
|
+
/** HTML content */
|
|
30
|
+
html?: string;
|
|
31
|
+
notes?: string[];
|
|
32
|
+
/** Page headings */
|
|
33
|
+
h1?: string;
|
|
34
|
+
h2?: string;
|
|
35
|
+
h3?: string;
|
|
36
|
+
h4?: string;
|
|
37
|
+
ariaSnapshot?: string | null;
|
|
38
|
+
ariaSnapshotFile?: string;
|
|
39
|
+
links?: Link[];
|
|
40
|
+
verifications?: Record<string, boolean>;
|
|
41
|
+
}
|
|
42
|
+
export interface StateTransition {
|
|
43
|
+
/** Previous state (null if this is the first state) */
|
|
44
|
+
fromState: WebPageState | null;
|
|
45
|
+
/** Current state */
|
|
46
|
+
toState: WebPageState;
|
|
47
|
+
/** Code block that caused the transition */
|
|
48
|
+
codeBlock: string;
|
|
49
|
+
/** Timestamp of the transition */
|
|
50
|
+
timestamp: Date;
|
|
51
|
+
/** Any error that occurred during transition */
|
|
52
|
+
error?: string;
|
|
53
|
+
/** What triggered the state change */
|
|
54
|
+
trigger: 'manual' | 'navigation' | 'automatic';
|
|
55
|
+
}
|
|
56
|
+
export type StateChangeListener = (event: StateTransition) => void;
|
|
57
|
+
export interface Knowledge extends WebPageState {
|
|
58
|
+
/** File path */
|
|
59
|
+
filePath: string;
|
|
60
|
+
/** Markdown content */
|
|
61
|
+
content: string;
|
|
62
|
+
}
|
|
63
|
+
export declare class StateManager {
|
|
64
|
+
currentState: WebPageState | null;
|
|
65
|
+
stateHistory: StateTransition[];
|
|
66
|
+
allVisitedUrls: Set<string>;
|
|
67
|
+
knowledgeCache: Knowledge[];
|
|
68
|
+
lastKnowledgeScan: Date | null;
|
|
69
|
+
stateChangeListeners: StateChangeListener[];
|
|
70
|
+
experienceTracker: ExperienceTracker;
|
|
71
|
+
knowledgeDir: string;
|
|
72
|
+
nextStateId: number;
|
|
73
|
+
constructor();
|
|
74
|
+
getExperienceTracker(): ExperienceTracker;
|
|
75
|
+
/**
|
|
76
|
+
* Subscribe to state change events
|
|
77
|
+
*/
|
|
78
|
+
onStateChange(listener: StateChangeListener): () => void;
|
|
79
|
+
/**
|
|
80
|
+
* Emit state change event to all listeners
|
|
81
|
+
*/
|
|
82
|
+
emitStateChange(event: StateTransition): void;
|
|
83
|
+
/**
|
|
84
|
+
* Extract state path from full URL
|
|
85
|
+
* Removes domain, port, protocol
|
|
86
|
+
* Keeps path, query, and hash: /path/to/page?tab=users#section
|
|
87
|
+
*/
|
|
88
|
+
/**
|
|
89
|
+
* Update current state from ActionResult and record transition if state changed
|
|
90
|
+
*/
|
|
91
|
+
updateState(actionResult: ActionResult, codeBlock?: string, trigger?: 'manual' | 'navigation' | 'automatic'): WebPageState;
|
|
92
|
+
/**
|
|
93
|
+
* Update state from basic data (for navigation events)
|
|
94
|
+
*/
|
|
95
|
+
updateStateFromBasic(url: string, title?: string, trigger?: 'manual' | 'navigation' | 'automatic'): WebPageState;
|
|
96
|
+
hasDialogAppeared(previousState: WebPageState | null, newState: WebPageState): boolean;
|
|
97
|
+
/**
|
|
98
|
+
* Generate a basic hash for state comparison
|
|
99
|
+
*/
|
|
100
|
+
generateBasicHash(url: string, title?: string): string;
|
|
101
|
+
/**
|
|
102
|
+
* Get current state
|
|
103
|
+
*/
|
|
104
|
+
getCurrentState(): WebPageState | null;
|
|
105
|
+
/**
|
|
106
|
+
* Check if state has changed since a given state
|
|
107
|
+
*/
|
|
108
|
+
hasStateChanged(previousState: WebPageState | null): boolean;
|
|
109
|
+
/**
|
|
110
|
+
* Compare two states by their hash
|
|
111
|
+
*/
|
|
112
|
+
statesEqual(state1: WebPageState | null, state2: WebPageState | null): boolean;
|
|
113
|
+
/**
|
|
114
|
+
* Get state history
|
|
115
|
+
*/
|
|
116
|
+
getStateHistory(): StateTransition[];
|
|
117
|
+
isInDeadLoop(): boolean;
|
|
118
|
+
/**
|
|
119
|
+
* Get the last N transitions
|
|
120
|
+
*/
|
|
121
|
+
getRecentTransitions(count?: number): StateTransition[];
|
|
122
|
+
/**
|
|
123
|
+
* Scan knowledge directory for .md files and cache them
|
|
124
|
+
*/
|
|
125
|
+
scanKnowledgeFiles(): void;
|
|
126
|
+
/**
|
|
127
|
+
* Get relevant knowledge files for current state
|
|
128
|
+
*/
|
|
129
|
+
getRelevantKnowledge(): Knowledge[];
|
|
130
|
+
/**
|
|
131
|
+
* Get relevant experience files for current state
|
|
132
|
+
*/
|
|
133
|
+
getRelevantExperience(): string[];
|
|
134
|
+
/**
|
|
135
|
+
* Get all context for current state (knowledge + experience)
|
|
136
|
+
*/
|
|
137
|
+
getCurrentContext(): {
|
|
138
|
+
state: WebPageState;
|
|
139
|
+
knowledge: Knowledge[];
|
|
140
|
+
experience: string[];
|
|
141
|
+
recentTransitions: StateTransition[];
|
|
142
|
+
};
|
|
143
|
+
/**
|
|
144
|
+
* Check if we've been in this state before
|
|
145
|
+
*/
|
|
146
|
+
hasVisitedState(path: string): boolean;
|
|
147
|
+
getAllVisitedUrls(): Set<string>;
|
|
148
|
+
/**
|
|
149
|
+
* Get how many times we've visited a specific path
|
|
150
|
+
*/
|
|
151
|
+
getVisitCount(path: string): number;
|
|
152
|
+
/**
|
|
153
|
+
* Find the most recent transition to a specific path
|
|
154
|
+
*/
|
|
155
|
+
getLastVisitToPath(path: string): StateTransition | null;
|
|
156
|
+
/**
|
|
157
|
+
* Get previous state from history for comparison.
|
|
158
|
+
* If the last transition changed URL, returns the fromState (for URL change detection).
|
|
159
|
+
* Otherwise returns the most recent toState with content (for diffing).
|
|
160
|
+
*/
|
|
161
|
+
getPreviousState(): WebPageState | null;
|
|
162
|
+
/**
|
|
163
|
+
* Load HTML content from file
|
|
164
|
+
*/
|
|
165
|
+
loadHtmlFromFile(htmlFile: string): string | null;
|
|
166
|
+
/**
|
|
167
|
+
* Clear state history (useful for testing or reset)
|
|
168
|
+
* Note: This preserves the current state, only clears navigation history
|
|
169
|
+
*/
|
|
170
|
+
clearHistory(): void;
|
|
171
|
+
/**
|
|
172
|
+
* Get the number of active state change listeners
|
|
173
|
+
*/
|
|
174
|
+
getListenerCount(): number;
|
|
175
|
+
/**
|
|
176
|
+
* Clear all state change listeners
|
|
177
|
+
*/
|
|
178
|
+
clearListeners(): void;
|
|
179
|
+
/**
|
|
180
|
+
* Complete cleanup of the StateManager instance
|
|
181
|
+
* Clears all state, history, listeners, and caches
|
|
182
|
+
*/
|
|
183
|
+
cleanup(): void;
|
|
184
|
+
}
|
|
185
|
+
export declare function normalizeUrl(url: string): string;
|
|
@@ -5,7 +5,6 @@ import { ActionResult } from './action-result.js';
|
|
|
5
5
|
import { ConfigParser, outputPath } from './config.js';
|
|
6
6
|
import { ExperienceTracker } from './experience-tracker.js';
|
|
7
7
|
import { detectFocusArea } from './utils/aria.js';
|
|
8
|
-
import { htmlTextSnapshot } from './utils/html.js';
|
|
9
8
|
import { createDebug } from './utils/logger.js';
|
|
10
9
|
import { extractStatePath } from './utils/url-matcher.js';
|
|
11
10
|
const debugLog = createDebug('explorbot:state');
|
|
@@ -53,12 +52,6 @@ export class StateManager {
|
|
|
53
52
|
* Emit state change event to all listeners
|
|
54
53
|
*/
|
|
55
54
|
emitStateChange(event) {
|
|
56
|
-
// Log HTML content when state changes
|
|
57
|
-
if (event.toState.html && event.toState.html !== event.fromState?.html) {
|
|
58
|
-
let htmlContent = event?.toState?.html ?? '';
|
|
59
|
-
htmlContent = htmlTextSnapshot(htmlContent);
|
|
60
|
-
// tag('html').log(`Page HTML for ${event.toState.url}:\n${htmlContent}`);
|
|
61
|
-
}
|
|
62
55
|
this.stateChangeListeners.forEach((listener) => {
|
|
63
56
|
try {
|
|
64
57
|
listener(event);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
interface TokenUsage {
|
|
2
|
+
input: number;
|
|
3
|
+
output: number;
|
|
4
|
+
total: number;
|
|
5
|
+
cached?: number;
|
|
6
|
+
}
|
|
7
|
+
export type ExplorbotMode = 'explore' | 'test' | 'freesail' | 'tui';
|
|
8
|
+
export declare class Stats {
|
|
9
|
+
static startTime: number;
|
|
10
|
+
static sessionName: string;
|
|
11
|
+
static researches: number;
|
|
12
|
+
static tests: number;
|
|
13
|
+
static plans: number;
|
|
14
|
+
static mode?: ExplorbotMode;
|
|
15
|
+
static focus?: string;
|
|
16
|
+
static models: Record<string, TokenUsage>;
|
|
17
|
+
static recordTokens(_agent: string, model: string, usage: TokenUsage): void;
|
|
18
|
+
static getElapsedTime(): string;
|
|
19
|
+
static humanizeTokens(num: number): string;
|
|
20
|
+
static modelsTable(roleModels: Record<string, string>): string;
|
|
21
|
+
static hasActivity(): boolean;
|
|
22
|
+
static sessionLabel(): string;
|
|
23
|
+
}
|
|
24
|
+
export {};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export declare class Suite {
|
|
2
|
+
readonly url: string;
|
|
3
|
+
_automatedTests: AutomatedTest[] | null;
|
|
4
|
+
_plannedScenarios: string[] | null;
|
|
5
|
+
constructor(url: string);
|
|
6
|
+
getAutomatedTests(): AutomatedTest[];
|
|
7
|
+
getPlannedScenarios(): string[];
|
|
8
|
+
getActiveScenarioTitles(): Set<string>;
|
|
9
|
+
get automatedTestCount(): number;
|
|
10
|
+
getAutomatedTestNames(): string[];
|
|
11
|
+
getAutomatedTestFiles(): string[];
|
|
12
|
+
loadAutomatedTests(): AutomatedTest[];
|
|
13
|
+
parseTestFile(filePath: string): {
|
|
14
|
+
url: string;
|
|
15
|
+
tests: AutomatedTest[];
|
|
16
|
+
} | null;
|
|
17
|
+
loadPlannedScenarios(): string[];
|
|
18
|
+
}
|
|
19
|
+
interface AutomatedTest {
|
|
20
|
+
title: string;
|
|
21
|
+
pending: boolean;
|
|
22
|
+
file: string;
|
|
23
|
+
}
|
|
24
|
+
export {};
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { WebPageState } from './state-manager.js';
|
|
2
|
+
export declare const TestResult: {
|
|
3
|
+
readonly PASSED: "passed";
|
|
4
|
+
readonly FAILED: "failed";
|
|
5
|
+
readonly SKIPPED: "skipped";
|
|
6
|
+
};
|
|
7
|
+
export type TestResultType = (typeof TestResult)[keyof typeof TestResult] | null;
|
|
8
|
+
export declare const TestStatus: {
|
|
9
|
+
readonly PENDING: "pending";
|
|
10
|
+
readonly IN_PROGRESS: "in_progress";
|
|
11
|
+
readonly DONE: "done";
|
|
12
|
+
};
|
|
13
|
+
export type TestStatusType = (typeof TestStatus)[keyof typeof TestStatus];
|
|
14
|
+
export interface Note {
|
|
15
|
+
message: string;
|
|
16
|
+
status?: TestResultType;
|
|
17
|
+
startTime: number;
|
|
18
|
+
endTime: number;
|
|
19
|
+
screenshot?: string;
|
|
20
|
+
log?: string;
|
|
21
|
+
}
|
|
22
|
+
export declare class ActiveNote {
|
|
23
|
+
task: Task;
|
|
24
|
+
startTime: number;
|
|
25
|
+
message: string;
|
|
26
|
+
status?: TestResultType;
|
|
27
|
+
screenshot?: string;
|
|
28
|
+
log?: string;
|
|
29
|
+
constructor(task: Task, message: string, status?: TestResultType);
|
|
30
|
+
commit(finalStatus?: TestResultType): void;
|
|
31
|
+
getMessage(): string;
|
|
32
|
+
getStartTime(): number;
|
|
33
|
+
}
|
|
34
|
+
export interface StepData {
|
|
35
|
+
text: string;
|
|
36
|
+
duration?: number;
|
|
37
|
+
status?: string;
|
|
38
|
+
error?: string;
|
|
39
|
+
log?: string;
|
|
40
|
+
artifacts?: string[];
|
|
41
|
+
noteStartTime?: number;
|
|
42
|
+
}
|
|
43
|
+
export declare class Task {
|
|
44
|
+
id: string;
|
|
45
|
+
description: string;
|
|
46
|
+
notes: Record<string, Note>;
|
|
47
|
+
steps: Record<string, StepData>;
|
|
48
|
+
states: WebPageState[];
|
|
49
|
+
startUrl: string;
|
|
50
|
+
verification?: Verification;
|
|
51
|
+
timestampCounter: number;
|
|
52
|
+
activeNote?: ActiveNote;
|
|
53
|
+
constructor(description: string, startUrl?: string);
|
|
54
|
+
startNote(message: string, status?: TestResultType): ActiveNote;
|
|
55
|
+
finishNote(activeNote: ActiveNote, endTime: number, finalStatus?: TestResultType): void;
|
|
56
|
+
getPrintableNotes(): string[];
|
|
57
|
+
notesToString(): string;
|
|
58
|
+
addNote(message: string, status?: TestResultType, screenshot?: string, log?: string): void;
|
|
59
|
+
addUrlNote(state: UrlNoteState, prevState?: {
|
|
60
|
+
title?: string;
|
|
61
|
+
h1?: string;
|
|
62
|
+
h2?: string;
|
|
63
|
+
}): void;
|
|
64
|
+
addState(state: WebPageState): void;
|
|
65
|
+
addStep(text: string, duration?: number, status?: string, error?: string, log?: string, artifacts?: string[]): void;
|
|
66
|
+
setActiveNoteScreenshot(screenshotFile?: string): void;
|
|
67
|
+
setVerification(message: string, status: TestResultType, state?: UrlNoteState): void;
|
|
68
|
+
addVerificationDetail(detail: string): void;
|
|
69
|
+
getLog(): Array<{
|
|
70
|
+
type: 'step' | 'note' | 'artifact';
|
|
71
|
+
content: string;
|
|
72
|
+
timestamp: number;
|
|
73
|
+
}>;
|
|
74
|
+
getLogString(): string;
|
|
75
|
+
getRunResult(): 'success' | 'partial' | 'failed';
|
|
76
|
+
}
|
|
77
|
+
export declare class Test extends Task {
|
|
78
|
+
scenario: string;
|
|
79
|
+
sessionName?: string;
|
|
80
|
+
status: TestStatusType;
|
|
81
|
+
result: TestResultType;
|
|
82
|
+
priority: 'critical' | 'important' | 'high' | 'normal' | 'low';
|
|
83
|
+
expected: string[];
|
|
84
|
+
plannedSteps: string[];
|
|
85
|
+
plan?: Plan;
|
|
86
|
+
summary: string;
|
|
87
|
+
artifacts: Record<string, string>;
|
|
88
|
+
generatedCode?: string;
|
|
89
|
+
style?: string;
|
|
90
|
+
planIteration: number;
|
|
91
|
+
enabled: boolean;
|
|
92
|
+
startTime?: number;
|
|
93
|
+
endTime?: number;
|
|
94
|
+
resetCount: number;
|
|
95
|
+
constructor(scenario: string, priority: 'critical' | 'important' | 'high' | 'normal' | 'low', expectedOutcome: string | string[], startUrl: string, plannedSteps?: string[]);
|
|
96
|
+
getVisitedUrls({ localOnly }?: {
|
|
97
|
+
localOnly?: boolean;
|
|
98
|
+
}): string[];
|
|
99
|
+
addArtifact(artifact?: string): void;
|
|
100
|
+
get hasFinished(): boolean;
|
|
101
|
+
get isSuccessful(): boolean;
|
|
102
|
+
get hasFailed(): boolean;
|
|
103
|
+
get isSkipped(): boolean;
|
|
104
|
+
getCheckedNotes(): Note[];
|
|
105
|
+
getCheckedExpectations(): string[];
|
|
106
|
+
hasAchievedAny(): boolean;
|
|
107
|
+
getRunResult(): 'success' | 'partial' | 'failed';
|
|
108
|
+
hasAchievedAll(): boolean;
|
|
109
|
+
isComplete(): boolean;
|
|
110
|
+
start(): void;
|
|
111
|
+
finish(result?: TestResultType): void;
|
|
112
|
+
getDurationMs(): number | null;
|
|
113
|
+
getRemainingExpectations(): string[];
|
|
114
|
+
getLog(): Array<{
|
|
115
|
+
type: 'step' | 'note' | 'artifact';
|
|
116
|
+
content: string;
|
|
117
|
+
timestamp: number;
|
|
118
|
+
}>;
|
|
119
|
+
}
|
|
120
|
+
type PlanChangeListener = (tests: Test[]) => void;
|
|
121
|
+
export declare class Plan {
|
|
122
|
+
title: string;
|
|
123
|
+
tests: Test[];
|
|
124
|
+
url?: string;
|
|
125
|
+
iteration: number;
|
|
126
|
+
parentPlan?: Plan;
|
|
127
|
+
changeListeners: PlanChangeListener[];
|
|
128
|
+
constructor(title: string);
|
|
129
|
+
nextIteration(): void;
|
|
130
|
+
addTest(test: Test): void;
|
|
131
|
+
removeTest(test: Test): void;
|
|
132
|
+
onTestsChange(listener: PlanChangeListener): () => void;
|
|
133
|
+
notifyChange(): void;
|
|
134
|
+
getAllTests(): Test[];
|
|
135
|
+
listTests(): Test[];
|
|
136
|
+
getPendingTests(): Test[];
|
|
137
|
+
get isComplete(): boolean;
|
|
138
|
+
get allSuccessful(): boolean;
|
|
139
|
+
get allFailed(): boolean;
|
|
140
|
+
updateStatus(): void;
|
|
141
|
+
static fromMarkdown(filePath: string): Plan;
|
|
142
|
+
saveToMarkdown(filePath: string): void;
|
|
143
|
+
static saveMultipleToMarkdown(plans: Plan[], filePath: string): void;
|
|
144
|
+
getVisitedPages(): WebPageState[];
|
|
145
|
+
merge(otherPlan: Plan): Plan;
|
|
146
|
+
toAiContext(options?: {
|
|
147
|
+
skipSteps?: boolean;
|
|
148
|
+
}): string;
|
|
149
|
+
}
|
|
150
|
+
interface Verification {
|
|
151
|
+
message: string;
|
|
152
|
+
status: TestResultType;
|
|
153
|
+
screenshot?: string;
|
|
154
|
+
url?: string;
|
|
155
|
+
pageLabel?: string;
|
|
156
|
+
details: string[];
|
|
157
|
+
}
|
|
158
|
+
interface UrlNoteState {
|
|
159
|
+
url?: string;
|
|
160
|
+
fullUrl?: string;
|
|
161
|
+
title?: string;
|
|
162
|
+
h1?: string;
|
|
163
|
+
h2?: string;
|
|
164
|
+
screenshotFile?: string;
|
|
165
|
+
}
|
|
166
|
+
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface FocusAreaResult {
|
|
2
|
+
detected: boolean;
|
|
3
|
+
type: 'dialog' | 'modal' | null;
|
|
4
|
+
name: string | null;
|
|
5
|
+
}
|
|
6
|
+
export declare const compactAriaSnapshot: (snapshot: string | null, keepNamed?: boolean) => string;
|
|
7
|
+
export declare const diffAriaSnapshots: (previous: string | null, current: string | null) => string | null;
|
|
8
|
+
export declare const detectFocusArea: (snapshot: string | null) => FocusAreaResult;
|
|
9
|
+
export declare const collectInteractiveNodes: (snapshot: string | null) => Array<Record<string, unknown>>;
|
|
10
|
+
export interface FocusedElementInfo {
|
|
11
|
+
role: string;
|
|
12
|
+
name: string;
|
|
13
|
+
value?: string;
|
|
14
|
+
attributes?: string[];
|
|
15
|
+
}
|
|
16
|
+
export declare function extractFocusedElement(ariaSnapshot: string | null): FocusedElementInfo | null;
|
|
17
|
+
export declare function parseAriaLocator(ariaStr: string): {
|
|
18
|
+
role: string;
|
|
19
|
+
text: string;
|
|
20
|
+
} | null;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare class BrowserRecoveryError extends Error {
|
|
2
|
+
originalError: unknown;
|
|
3
|
+
recovered: boolean;
|
|
4
|
+
constructor(label: string, originalError: unknown, recovered: boolean);
|
|
5
|
+
}
|
|
6
|
+
export declare function isFatalBrowserError(error: unknown): boolean;
|
|
7
|
+
export declare function isNavigationTransitionError(error: unknown): boolean;
|
|
8
|
+
export declare function browserErrorMessage(error: unknown): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function getCliName(): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function extractCodeBlocks(aiResponse: string): string[];
|