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,5 +1,5 @@
|
|
|
1
1
|
import { ActionResult } from './action-result.js';
|
|
2
|
-
interface Knowledge {
|
|
2
|
+
export interface Knowledge {
|
|
3
3
|
filePath: string;
|
|
4
4
|
url: string;
|
|
5
5
|
content: string;
|
|
@@ -12,6 +12,7 @@ export declare class KnowledgeTracker {
|
|
|
12
12
|
constructor();
|
|
13
13
|
loadKnowledgeFiles(): void;
|
|
14
14
|
getRelevantKnowledge(state: ActionResult): Knowledge[];
|
|
15
|
+
renderRelevantKnowledge(state: ActionResult): string;
|
|
15
16
|
addKnowledge(urlPattern: string, description: string): {
|
|
16
17
|
filename: string;
|
|
17
18
|
filePath: string;
|
|
@@ -30,4 +31,3 @@ export declare class KnowledgeTracker {
|
|
|
30
31
|
normalizeUrl(url: string): string;
|
|
31
32
|
getStateParameters(state: ActionResult, keys: string[]): Record<string, any>;
|
|
32
33
|
}
|
|
33
|
-
export {};
|
|
@@ -1,11 +1,15 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, readFileSync,
|
|
2
|
-
import {
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import dedent from 'dedent';
|
|
3
4
|
import matter from 'gray-matter';
|
|
4
5
|
import { ActionResult } from './action-result.js';
|
|
5
6
|
import { ConfigParser } from './config.js';
|
|
6
7
|
import { getCliName } from "./utils/cli-name.js";
|
|
7
|
-
import { createDebug } from './utils/logger.js';
|
|
8
|
+
import { createDebug, pluralize, tag } from './utils/logger.js';
|
|
9
|
+
import { loadMarkdownFiles } from './utils/markdown-files.js';
|
|
10
|
+
import { mdq } from './utils/markdown-query.js';
|
|
8
11
|
import { isSecretName, registerSecret } from './utils/secrets.js';
|
|
12
|
+
import { slugify } from './utils/strings.js';
|
|
9
13
|
const debugLog = createDebug('explorbot:knowledge-tracker');
|
|
10
14
|
export class KnowledgeTracker {
|
|
11
15
|
knowledgeDir;
|
|
@@ -14,14 +18,7 @@ export class KnowledgeTracker {
|
|
|
14
18
|
constructor() {
|
|
15
19
|
const configParser = ConfigParser.getInstance();
|
|
16
20
|
const config = configParser.getConfig();
|
|
17
|
-
|
|
18
|
-
if (configPath) {
|
|
19
|
-
const projectRoot = dirname(configPath);
|
|
20
|
-
this.knowledgeDir = join(projectRoot, config.dirs?.knowledge || 'knowledge');
|
|
21
|
-
}
|
|
22
|
-
else {
|
|
23
|
-
this.knowledgeDir = config.dirs?.knowledge || 'knowledge';
|
|
24
|
-
}
|
|
21
|
+
this.knowledgeDir = configParser.resolveProjectDir(config.dirs?.knowledge || 'knowledge');
|
|
25
22
|
if (!existsSync(this.knowledgeDir)) {
|
|
26
23
|
mkdirSync(this.knowledgeDir, { recursive: true });
|
|
27
24
|
}
|
|
@@ -30,27 +27,13 @@ export class KnowledgeTracker {
|
|
|
30
27
|
if (this.isLoaded)
|
|
31
28
|
return;
|
|
32
29
|
this.knowledgeFiles = [];
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
try {
|
|
41
|
-
const fileContent = readFileSync(filePath, 'utf8');
|
|
42
|
-
const parsed = matter(fileContent);
|
|
43
|
-
const urlPattern = parsed.data.url || parsed.data.path || '*';
|
|
44
|
-
this.knowledgeFiles.push({
|
|
45
|
-
filePath,
|
|
46
|
-
url: urlPattern,
|
|
47
|
-
content: this.interpolateVars(parsed.content),
|
|
48
|
-
...parsed.data,
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
catch (error) {
|
|
52
|
-
// Skip invalid files
|
|
53
|
-
}
|
|
30
|
+
for (const entry of loadMarkdownFiles(this.knowledgeDir, { recursive: true })) {
|
|
31
|
+
this.knowledgeFiles.push({
|
|
32
|
+
filePath: entry.filePath,
|
|
33
|
+
url: entry.data.url || entry.data.path || '*',
|
|
34
|
+
content: this.interpolateVars(entry.content),
|
|
35
|
+
...entry.data,
|
|
36
|
+
});
|
|
54
37
|
}
|
|
55
38
|
this.isLoaded = true;
|
|
56
39
|
}
|
|
@@ -60,21 +43,35 @@ export class KnowledgeTracker {
|
|
|
60
43
|
return state.isMatchedBy(knowledge);
|
|
61
44
|
});
|
|
62
45
|
}
|
|
46
|
+
renderRelevantKnowledge(state) {
|
|
47
|
+
const knowledgeFiles = this.getRelevantKnowledge(state);
|
|
48
|
+
if (knowledgeFiles.length === 0)
|
|
49
|
+
return '';
|
|
50
|
+
const knowledgeContent = knowledgeFiles
|
|
51
|
+
.map((k) => k.content)
|
|
52
|
+
.filter((k) => !!k)
|
|
53
|
+
.join('\n\n');
|
|
54
|
+
tag('operation').log(`Found ${knowledgeFiles.length} relevant knowledge ${pluralize(knowledgeFiles.length, 'file')}`);
|
|
55
|
+
return dedent `
|
|
56
|
+
<knowledge>
|
|
57
|
+
Here is relevant knowledge for this page:
|
|
58
|
+
|
|
59
|
+
${knowledgeContent}
|
|
60
|
+
</knowledge>
|
|
61
|
+
`;
|
|
62
|
+
}
|
|
63
63
|
addKnowledge(urlPattern, description) {
|
|
64
64
|
const configParser = ConfigParser.getInstance();
|
|
65
|
-
const config = configParser.getConfig();
|
|
66
65
|
const configPath = configParser.getConfigPath();
|
|
67
66
|
if (!configPath) {
|
|
68
67
|
throw new Error(`No explorbot configuration found. Please run "${getCliName()} init" first.`);
|
|
69
68
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
if (!existsSync(knowledgeDir)) {
|
|
73
|
-
mkdirSync(knowledgeDir, { recursive: true });
|
|
69
|
+
if (!existsSync(this.knowledgeDir)) {
|
|
70
|
+
mkdirSync(this.knowledgeDir, { recursive: true });
|
|
74
71
|
}
|
|
75
72
|
const normalizedUrl = this.normalizeUrl(urlPattern);
|
|
76
73
|
const filename = this.generateFilename(normalizedUrl);
|
|
77
|
-
const filePath = join(knowledgeDir, filename);
|
|
74
|
+
const filePath = join(this.knowledgeDir, filename);
|
|
78
75
|
const isNewFile = !existsSync(filePath);
|
|
79
76
|
if (isNewFile) {
|
|
80
77
|
const frontmatter = {
|
|
@@ -101,6 +98,7 @@ export class KnowledgeTracker {
|
|
|
101
98
|
const fileContent = matter.stringify(newContent, frontmatter);
|
|
102
99
|
writeFileSync(filePath, fileContent, 'utf8');
|
|
103
100
|
}
|
|
101
|
+
this.isLoaded = false;
|
|
104
102
|
return { filename, filePath, isNewFile };
|
|
105
103
|
}
|
|
106
104
|
interpolateVars(content) {
|
|
@@ -129,12 +127,7 @@ export class KnowledgeTracker {
|
|
|
129
127
|
});
|
|
130
128
|
}
|
|
131
129
|
generateFilename(url) {
|
|
132
|
-
let filename = url
|
|
133
|
-
.replace(/https?:\/\//g, '')
|
|
134
|
-
.replace(/[^a-zA-Z0-9_]/g, '_')
|
|
135
|
-
.replace(/_+/g, '_')
|
|
136
|
-
.replace(/^_|_$/g, '')
|
|
137
|
-
.toLowerCase();
|
|
130
|
+
let filename = slugify(url.replace(/https?:\/\//g, ''));
|
|
138
131
|
if (!filename || filename === '*') {
|
|
139
132
|
filename = 'general';
|
|
140
133
|
}
|
|
@@ -156,7 +149,7 @@ export class KnowledgeTracker {
|
|
|
156
149
|
this.loadKnowledgeFiles();
|
|
157
150
|
return this.knowledgeFiles.map((knowledge) => {
|
|
158
151
|
const content = knowledge.content.trim();
|
|
159
|
-
const firstLine = content.split('\n')[0]?.trim() || '';
|
|
152
|
+
const firstLine = mdq(content).meta()[0]?.text.split('\n')[0]?.trim() || '';
|
|
160
153
|
return {
|
|
161
154
|
url: knowledge.url,
|
|
162
155
|
firstLine,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ActionResult } from './action-result.js';
|
|
2
|
-
import { ExperienceTracker } from './experience-tracker.js';
|
|
2
|
+
import type { ExperienceTracker } from './experience-tracker.js';
|
|
3
|
+
import type { Knowledge, KnowledgeTracker } from './knowledge-tracker.js';
|
|
3
4
|
export interface Link {
|
|
4
5
|
title: string;
|
|
5
6
|
url: string;
|
|
@@ -54,24 +55,23 @@ export interface StateTransition {
|
|
|
54
55
|
trigger: 'manual' | 'navigation' | 'automatic';
|
|
55
56
|
}
|
|
56
57
|
export type StateChangeListener = (event: StateTransition) => void;
|
|
57
|
-
export interface
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
/** Markdown content */
|
|
61
|
-
content: string;
|
|
58
|
+
export interface TabInfo {
|
|
59
|
+
url: string;
|
|
60
|
+
title: string;
|
|
62
61
|
}
|
|
62
|
+
export type { Knowledge };
|
|
63
63
|
export declare class StateManager {
|
|
64
|
+
otherTabs: TabInfo[];
|
|
64
65
|
currentState: WebPageState | null;
|
|
65
66
|
stateHistory: StateTransition[];
|
|
66
67
|
allVisitedUrls: Set<string>;
|
|
67
|
-
knowledgeCache: Knowledge[];
|
|
68
|
-
lastKnowledgeScan: Date | null;
|
|
69
68
|
stateChangeListeners: StateChangeListener[];
|
|
70
69
|
experienceTracker: ExperienceTracker;
|
|
71
|
-
|
|
70
|
+
knowledgeTracker: KnowledgeTracker;
|
|
72
71
|
nextStateId: number;
|
|
73
|
-
constructor();
|
|
72
|
+
constructor(experienceTracker: ExperienceTracker, knowledgeTracker: KnowledgeTracker);
|
|
74
73
|
getExperienceTracker(): ExperienceTracker;
|
|
74
|
+
getKnowledgeTracker(): KnowledgeTracker;
|
|
75
75
|
/**
|
|
76
76
|
* Subscribe to state change events
|
|
77
77
|
*/
|
|
@@ -80,11 +80,6 @@ export declare class StateManager {
|
|
|
80
80
|
* Emit state change event to all listeners
|
|
81
81
|
*/
|
|
82
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
83
|
/**
|
|
89
84
|
* Update current state from ActionResult and record transition if state changed
|
|
90
85
|
*/
|
|
@@ -119,10 +114,6 @@ export declare class StateManager {
|
|
|
119
114
|
* Get the last N transitions
|
|
120
115
|
*/
|
|
121
116
|
getRecentTransitions(count?: number): StateTransition[];
|
|
122
|
-
/**
|
|
123
|
-
* Scan knowledge directory for .md files and cache them
|
|
124
|
-
*/
|
|
125
|
-
scanKnowledgeFiles(): void;
|
|
126
117
|
/**
|
|
127
118
|
* Get relevant knowledge files for current state
|
|
128
119
|
*/
|
|
@@ -134,12 +125,6 @@ export declare class StateManager {
|
|
|
134
125
|
/**
|
|
135
126
|
* Get all context for current state (knowledge + experience)
|
|
136
127
|
*/
|
|
137
|
-
getCurrentContext(): {
|
|
138
|
-
state: WebPageState;
|
|
139
|
-
knowledge: Knowledge[];
|
|
140
|
-
experience: string[];
|
|
141
|
-
recentTransitions: StateTransition[];
|
|
142
|
-
};
|
|
143
128
|
/**
|
|
144
129
|
* Check if we've been in this state before
|
|
145
130
|
*/
|
|
@@ -158,11 +143,6 @@ export declare class StateManager {
|
|
|
158
143
|
* If the last transition changed URL, returns the fromState (for URL change detection).
|
|
159
144
|
* Otherwise returns the most recent toState with content (for diffing).
|
|
160
145
|
*/
|
|
161
|
-
getPreviousState(): WebPageState | null;
|
|
162
|
-
/**
|
|
163
|
-
* Load HTML content from file
|
|
164
|
-
*/
|
|
165
|
-
loadHtmlFromFile(htmlFile: string): string | null;
|
|
166
146
|
/**
|
|
167
147
|
* Clear state history (useful for testing or reset)
|
|
168
148
|
* Note: This preserves the current state, only clears navigation history
|
|
@@ -1,40 +1,28 @@
|
|
|
1
|
-
import { existsSync, readFileSync, readdirSync } from 'node:fs';
|
|
2
|
-
import { dirname, join } from 'node:path';
|
|
3
|
-
import matter from 'gray-matter';
|
|
4
1
|
import { ActionResult } from './action-result.js';
|
|
5
|
-
import { ConfigParser, outputPath } from './config.js';
|
|
6
|
-
import { ExperienceTracker } from './experience-tracker.js';
|
|
7
2
|
import { detectFocusArea } from './utils/aria.js';
|
|
8
3
|
import { createDebug } from './utils/logger.js';
|
|
4
|
+
import { slugify } from './utils/strings.js';
|
|
9
5
|
import { extractStatePath } from './utils/url-matcher.js';
|
|
10
6
|
const debugLog = createDebug('explorbot:state');
|
|
11
7
|
export class StateManager {
|
|
8
|
+
otherTabs = [];
|
|
12
9
|
currentState = null;
|
|
13
10
|
stateHistory = [];
|
|
14
11
|
allVisitedUrls = new Set();
|
|
15
|
-
knowledgeCache = [];
|
|
16
|
-
lastKnowledgeScan = null;
|
|
17
12
|
stateChangeListeners = [];
|
|
18
13
|
experienceTracker;
|
|
19
|
-
|
|
14
|
+
knowledgeTracker;
|
|
20
15
|
nextStateId = 1;
|
|
21
|
-
constructor() {
|
|
22
|
-
this.experienceTracker =
|
|
23
|
-
|
|
24
|
-
const config = configParser.getConfig();
|
|
25
|
-
const configPath = configParser.getConfigPath();
|
|
26
|
-
// Resolve knowledge directory relative to the config file location (project root)
|
|
27
|
-
if (configPath) {
|
|
28
|
-
const projectRoot = dirname(configPath);
|
|
29
|
-
this.knowledgeDir = join(projectRoot, config.dirs?.knowledge || 'knowledge');
|
|
30
|
-
}
|
|
31
|
-
else {
|
|
32
|
-
this.knowledgeDir = config.dirs?.knowledge || 'knowledge';
|
|
33
|
-
}
|
|
16
|
+
constructor(experienceTracker, knowledgeTracker) {
|
|
17
|
+
this.experienceTracker = experienceTracker;
|
|
18
|
+
this.knowledgeTracker = knowledgeTracker;
|
|
34
19
|
}
|
|
35
20
|
getExperienceTracker() {
|
|
36
21
|
return this.experienceTracker;
|
|
37
22
|
}
|
|
23
|
+
getKnowledgeTracker() {
|
|
24
|
+
return this.knowledgeTracker;
|
|
25
|
+
}
|
|
38
26
|
/**
|
|
39
27
|
* Subscribe to state change events
|
|
40
28
|
*/
|
|
@@ -61,11 +49,6 @@ export class StateManager {
|
|
|
61
49
|
}
|
|
62
50
|
});
|
|
63
51
|
}
|
|
64
|
-
/**
|
|
65
|
-
* Extract state path from full URL
|
|
66
|
-
* Removes domain, port, protocol
|
|
67
|
-
* Keeps path, query, and hash: /path/to/page?tab=users#section
|
|
68
|
-
*/
|
|
69
52
|
/**
|
|
70
53
|
* Update current state from ActionResult and record transition if state changed
|
|
71
54
|
*/
|
|
@@ -141,13 +124,7 @@ export class StateManager {
|
|
|
141
124
|
if (title) {
|
|
142
125
|
parts.push(`title_${title}`);
|
|
143
126
|
}
|
|
144
|
-
return parts
|
|
145
|
-
.join('_')
|
|
146
|
-
.replace(/[^a-zA-Z0-9_]/g, '_')
|
|
147
|
-
.replace(/_+/g, '_')
|
|
148
|
-
.replace(/^_|_$/g, '')
|
|
149
|
-
.toLowerCase()
|
|
150
|
-
.substring(0, 200);
|
|
127
|
+
return slugify(parts.join('_')).substring(0, 200);
|
|
151
128
|
}
|
|
152
129
|
/**
|
|
153
130
|
* Get current state
|
|
@@ -226,57 +203,14 @@ export class StateManager {
|
|
|
226
203
|
getRecentTransitions(count = 5) {
|
|
227
204
|
return this.stateHistory.slice(-count);
|
|
228
205
|
}
|
|
229
|
-
/**
|
|
230
|
-
* Scan knowledge directory for .md files and cache them
|
|
231
|
-
*/
|
|
232
|
-
scanKnowledgeFiles() {
|
|
233
|
-
const now = new Date();
|
|
234
|
-
// Only rescan every 30 seconds to avoid excessive file I/O
|
|
235
|
-
if (this.lastKnowledgeScan && now.getTime() - this.lastKnowledgeScan.getTime() < 30000) {
|
|
236
|
-
return;
|
|
237
|
-
}
|
|
238
|
-
this.knowledgeCache = [];
|
|
239
|
-
if (!existsSync(this.knowledgeDir)) {
|
|
240
|
-
debugLog(`Knowledge directory not found: ${this.knowledgeDir}`);
|
|
241
|
-
return;
|
|
242
|
-
}
|
|
243
|
-
try {
|
|
244
|
-
const files = readdirSync(this.knowledgeDir, { recursive: true })
|
|
245
|
-
.filter((file) => typeof file === 'string' && file.endsWith('.md'))
|
|
246
|
-
.map((file) => join(this.knowledgeDir, file));
|
|
247
|
-
for (const filePath of files) {
|
|
248
|
-
try {
|
|
249
|
-
const fileContent = readFileSync(filePath, 'utf8');
|
|
250
|
-
const parsed = matter(fileContent);
|
|
251
|
-
const urlPattern = parsed.data.url || parsed.data.path || '*';
|
|
252
|
-
this.knowledgeCache.push({
|
|
253
|
-
filePath,
|
|
254
|
-
url: urlPattern,
|
|
255
|
-
...parsed.data,
|
|
256
|
-
content: parsed.content,
|
|
257
|
-
});
|
|
258
|
-
debugLog(`Loaded knowledge file: ${filePath} (pattern: ${urlPattern})`);
|
|
259
|
-
}
|
|
260
|
-
catch (error) {
|
|
261
|
-
debugLog(`Failed to load knowledge file ${filePath}:`, error);
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
this.lastKnowledgeScan = now;
|
|
265
|
-
debugLog(`Scanned ${this.knowledgeCache.length} knowledge files`);
|
|
266
|
-
}
|
|
267
|
-
catch (error) {
|
|
268
|
-
debugLog('Failed to scan knowledge directory:', error);
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
206
|
/**
|
|
272
207
|
* Get relevant knowledge files for current state
|
|
273
208
|
*/
|
|
274
209
|
getRelevantKnowledge() {
|
|
275
210
|
if (!this.currentState)
|
|
276
211
|
return [];
|
|
277
|
-
this.scanKnowledgeFiles();
|
|
278
212
|
const actionResult = ActionResult.fromState(this.currentState);
|
|
279
|
-
return this.
|
|
213
|
+
return this.knowledgeTracker.getRelevantKnowledge(actionResult);
|
|
280
214
|
}
|
|
281
215
|
/**
|
|
282
216
|
* Get relevant experience files for current state
|
|
@@ -291,17 +225,6 @@ export class StateManager {
|
|
|
291
225
|
/**
|
|
292
226
|
* Get all context for current state (knowledge + experience)
|
|
293
227
|
*/
|
|
294
|
-
getCurrentContext() {
|
|
295
|
-
if (!this.currentState) {
|
|
296
|
-
throw new Error('No current state available');
|
|
297
|
-
}
|
|
298
|
-
return {
|
|
299
|
-
state: this.currentState,
|
|
300
|
-
knowledge: this.getRelevantKnowledge(),
|
|
301
|
-
experience: this.getRelevantExperience(),
|
|
302
|
-
recentTransitions: this.getRecentTransitions(),
|
|
303
|
-
};
|
|
304
|
-
}
|
|
305
228
|
/**
|
|
306
229
|
* Check if we've been in this state before
|
|
307
230
|
*/
|
|
@@ -333,41 +256,6 @@ export class StateManager {
|
|
|
333
256
|
* If the last transition changed URL, returns the fromState (for URL change detection).
|
|
334
257
|
* Otherwise returns the most recent toState with content (for diffing).
|
|
335
258
|
*/
|
|
336
|
-
getPreviousState() {
|
|
337
|
-
if (this.stateHistory.length === 0)
|
|
338
|
-
return null;
|
|
339
|
-
const lastTransition = this.stateHistory[this.stateHistory.length - 1];
|
|
340
|
-
if (lastTransition.fromState?.url !== lastTransition.toState?.url) {
|
|
341
|
-
return lastTransition.fromState;
|
|
342
|
-
}
|
|
343
|
-
for (let i = this.stateHistory.length - 1; i >= 0; i--) {
|
|
344
|
-
const toState = this.stateHistory[i].toState;
|
|
345
|
-
if (!toState)
|
|
346
|
-
continue;
|
|
347
|
-
if (toState.id === this.currentState?.id)
|
|
348
|
-
continue;
|
|
349
|
-
if (toState.html || toState.ariaSnapshot) {
|
|
350
|
-
return toState;
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
return null;
|
|
354
|
-
}
|
|
355
|
-
/**
|
|
356
|
-
* Load HTML content from file
|
|
357
|
-
*/
|
|
358
|
-
loadHtmlFromFile(htmlFile) {
|
|
359
|
-
try {
|
|
360
|
-
const filePath = outputPath('states', htmlFile);
|
|
361
|
-
if (existsSync(filePath)) {
|
|
362
|
-
return readFileSync(filePath, 'utf8');
|
|
363
|
-
}
|
|
364
|
-
return null;
|
|
365
|
-
}
|
|
366
|
-
catch (error) {
|
|
367
|
-
debugLog('Failed to load HTML from file:', error);
|
|
368
|
-
return null;
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
259
|
/**
|
|
372
260
|
* Clear state history (useful for testing or reset)
|
|
373
261
|
* Note: This preserves the current state, only clears navigation history
|
|
@@ -398,13 +286,7 @@ export class StateManager {
|
|
|
398
286
|
this.stateHistory = [];
|
|
399
287
|
this.allVisitedUrls.clear();
|
|
400
288
|
this.stateChangeListeners = [];
|
|
401
|
-
this.knowledgeCache = [];
|
|
402
|
-
this.lastKnowledgeScan = null;
|
|
403
289
|
this.nextStateId = 1;
|
|
404
|
-
// Clean up experience tracker if it has cleanup method
|
|
405
|
-
if (this.experienceTracker && typeof this.experienceTracker.cleanup === 'function') {
|
|
406
|
-
this.experienceTracker.cleanup();
|
|
407
|
-
}
|
|
408
290
|
debugLog('StateManager cleanup completed');
|
|
409
291
|
}
|
|
410
292
|
}
|
package/dist/src/utils/aria.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ export interface FocusAreaResult {
|
|
|
4
4
|
name: string | null;
|
|
5
5
|
}
|
|
6
6
|
export declare const compactAriaSnapshot: (snapshot: string | null, keepNamed?: boolean) => string;
|
|
7
|
-
export declare const diffAriaSnapshots: (previous: string | null, current: string | null) =>
|
|
7
|
+
export declare const diffAriaSnapshots: (previous: string | null, current: string | null) => AriaDiff;
|
|
8
8
|
export declare const detectFocusArea: (snapshot: string | null) => FocusAreaResult;
|
|
9
9
|
export declare const collectInteractiveNodes: (snapshot: string | null) => Array<Record<string, unknown>>;
|
|
10
10
|
export interface FocusedElementInfo {
|
|
@@ -18,3 +18,8 @@ export declare function parseAriaLocator(ariaStr: string): {
|
|
|
18
18
|
role: string;
|
|
19
19
|
text: string;
|
|
20
20
|
} | null;
|
|
21
|
+
export declare const LARGE_ARIA_CHANGE_THRESHOLD = 50;
|
|
22
|
+
export interface AriaDiff {
|
|
23
|
+
text: string | null;
|
|
24
|
+
count: number;
|
|
25
|
+
}
|
package/dist/src/utils/aria.js
CHANGED
|
@@ -490,7 +490,9 @@ export const diffAriaSnapshots = (previous, current) => {
|
|
|
490
490
|
const currTotals = countBy(curr.map((e) => e.summary));
|
|
491
491
|
const byCount = diffByCount(prevTotals, currTotals);
|
|
492
492
|
const renames = detectRenames(prev, curr, prevTotals, currTotals);
|
|
493
|
-
|
|
493
|
+
const added = [...byCount.added, ...renames.added];
|
|
494
|
+
const removed = [...byCount.removed, ...renames.removed];
|
|
495
|
+
return { text: formatDiff(added, removed, toggled), count: added.length + removed.length + toggled.length };
|
|
494
496
|
};
|
|
495
497
|
export const detectFocusArea = (snapshot) => {
|
|
496
498
|
let tree = parseSnapshot(snapshot);
|
|
@@ -543,3 +545,4 @@ export function parseAriaLocator(ariaStr) {
|
|
|
543
545
|
return null;
|
|
544
546
|
return { role: match[1], text: match[2] };
|
|
545
547
|
}
|
|
548
|
+
export const LARGE_ARIA_CHANGE_THRESHOLD = 50;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare class TTLCache<T> {
|
|
2
|
+
store: Map<string, CacheEntry<T>>;
|
|
3
|
+
ttlMs: number;
|
|
4
|
+
constructor(ttlMs?: number);
|
|
5
|
+
get(key: string): T | undefined;
|
|
6
|
+
set(key: string, value: T): void;
|
|
7
|
+
fetch(key: string, compute: () => Promise<T>): Promise<T>;
|
|
8
|
+
delete(key: string): void;
|
|
9
|
+
clear(): void;
|
|
10
|
+
}
|
|
11
|
+
type CacheEntry<T> = {
|
|
12
|
+
value: T;
|
|
13
|
+
at: number;
|
|
14
|
+
};
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export class TTLCache {
|
|
2
|
+
store = new Map();
|
|
3
|
+
ttlMs;
|
|
4
|
+
constructor(ttlMs = Number.POSITIVE_INFINITY) {
|
|
5
|
+
this.ttlMs = ttlMs;
|
|
6
|
+
}
|
|
7
|
+
get(key) {
|
|
8
|
+
const entry = this.store.get(key);
|
|
9
|
+
if (!entry)
|
|
10
|
+
return undefined;
|
|
11
|
+
if (Date.now() - entry.at > this.ttlMs) {
|
|
12
|
+
this.store.delete(key);
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
return entry.value;
|
|
16
|
+
}
|
|
17
|
+
set(key, value) {
|
|
18
|
+
this.store.set(key, { value, at: Date.now() });
|
|
19
|
+
}
|
|
20
|
+
async fetch(key, compute) {
|
|
21
|
+
const cached = this.get(key);
|
|
22
|
+
if (cached !== undefined)
|
|
23
|
+
return cached;
|
|
24
|
+
const value = await compute();
|
|
25
|
+
this.set(key, value);
|
|
26
|
+
return value;
|
|
27
|
+
}
|
|
28
|
+
delete(key) {
|
|
29
|
+
this.store.delete(key);
|
|
30
|
+
}
|
|
31
|
+
clear() {
|
|
32
|
+
this.store.clear();
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -21,5 +21,11 @@ export interface ContextData {
|
|
|
21
21
|
combinedHtml?: string;
|
|
22
22
|
research?: string;
|
|
23
23
|
}
|
|
24
|
+
export declare function formatHeadings(headings: {
|
|
25
|
+
h1?: string;
|
|
26
|
+
h2?: string;
|
|
27
|
+
h3?: string;
|
|
28
|
+
h4?: string;
|
|
29
|
+
}): string[];
|
|
24
30
|
export type ContextMode = 'attached' | 'compact' | 'full';
|
|
25
31
|
export declare function formatContextSummary(data: ContextData, mode?: ContextMode): string;
|
|
@@ -10,6 +10,18 @@ function indent(text) {
|
|
|
10
10
|
.map((line) => chalk.gray(` ${line}`))
|
|
11
11
|
.join('\n');
|
|
12
12
|
}
|
|
13
|
+
export function formatHeadings(headings) {
|
|
14
|
+
const lines = [];
|
|
15
|
+
if (headings.h1)
|
|
16
|
+
lines.push(`H1: ${headings.h1}`);
|
|
17
|
+
if (headings.h2)
|
|
18
|
+
lines.push(`H2: ${headings.h2}`);
|
|
19
|
+
if (headings.h3)
|
|
20
|
+
lines.push(`H3: ${headings.h3}`);
|
|
21
|
+
if (headings.h4)
|
|
22
|
+
lines.push(`H4: ${headings.h4}`);
|
|
23
|
+
return lines;
|
|
24
|
+
}
|
|
13
25
|
export function formatContextSummary(data, mode = 'compact') {
|
|
14
26
|
if (mode === 'full') {
|
|
15
27
|
return formatContextFull(data);
|
|
@@ -27,15 +39,7 @@ function formatContextAttached(data) {
|
|
|
27
39
|
lines.push(indent(data.title));
|
|
28
40
|
}
|
|
29
41
|
lines.push('');
|
|
30
|
-
const headingLines =
|
|
31
|
-
if (data.headings.h1)
|
|
32
|
-
headingLines.push(`H1: ${data.headings.h1}`);
|
|
33
|
-
if (data.headings.h2)
|
|
34
|
-
headingLines.push(`H2: ${data.headings.h2}`);
|
|
35
|
-
if (data.headings.h3)
|
|
36
|
-
headingLines.push(`H3: ${data.headings.h3}`);
|
|
37
|
-
if (data.headings.h4)
|
|
38
|
-
headingLines.push(`H4: ${data.headings.h4}`);
|
|
42
|
+
const headingLines = formatHeadings(data.headings);
|
|
39
43
|
if (headingLines.length > 0) {
|
|
40
44
|
lines.push(section('HEADINGS') + chalk.gray(' (Auto-attached)'));
|
|
41
45
|
lines.push(indent(headingLines.join('\n')));
|
|
@@ -88,15 +92,7 @@ function formatContextCompact(data) {
|
|
|
88
92
|
lines.push(indent(data.title));
|
|
89
93
|
}
|
|
90
94
|
lines.push('');
|
|
91
|
-
const headingLines =
|
|
92
|
-
if (data.headings.h1)
|
|
93
|
-
headingLines.push(`H1: ${data.headings.h1}`);
|
|
94
|
-
if (data.headings.h2)
|
|
95
|
-
headingLines.push(`H2: ${data.headings.h2}`);
|
|
96
|
-
if (data.headings.h3)
|
|
97
|
-
headingLines.push(`H3: ${data.headings.h3}`);
|
|
98
|
-
if (data.headings.h4)
|
|
99
|
-
headingLines.push(`H4: ${data.headings.h4}`);
|
|
95
|
+
const headingLines = formatHeadings(data.headings);
|
|
100
96
|
if (headingLines.length > 0) {
|
|
101
97
|
lines.push(section('HEADINGS') + chalk.gray(' (Auto-attached)'));
|
|
102
98
|
lines.push(indent(headingLines.join('\n')));
|
|
@@ -144,15 +140,7 @@ function formatContextFull(data) {
|
|
|
144
140
|
lines.push(indent(data.title));
|
|
145
141
|
}
|
|
146
142
|
lines.push('');
|
|
147
|
-
const headingLines =
|
|
148
|
-
if (data.headings.h1)
|
|
149
|
-
headingLines.push(`H1: ${data.headings.h1}`);
|
|
150
|
-
if (data.headings.h2)
|
|
151
|
-
headingLines.push(`H2: ${data.headings.h2}`);
|
|
152
|
-
if (data.headings.h3)
|
|
153
|
-
headingLines.push(`H3: ${data.headings.h3}`);
|
|
154
|
-
if (data.headings.h4)
|
|
155
|
-
headingLines.push(`H4: ${data.headings.h4}`);
|
|
143
|
+
const headingLines = formatHeadings(data.headings);
|
|
156
144
|
if (headingLines.length > 0) {
|
|
157
145
|
lines.push(section('HEADINGS') + chalk.gray(' (Auto-attached)'));
|
|
158
146
|
lines.push(indent(headingLines.join('\n')));
|
|
@@ -49,12 +49,10 @@ export class HooksRunner {
|
|
|
49
49
|
async executeHook(hook, url) {
|
|
50
50
|
try {
|
|
51
51
|
if (hook.type === 'playwright') {
|
|
52
|
-
|
|
53
|
-
await hook.hook({ page, url });
|
|
52
|
+
await this.explorer.withPage(async (page) => hook.hook({ page, url }));
|
|
54
53
|
}
|
|
55
54
|
else {
|
|
56
|
-
|
|
57
|
-
await hook.hook({ I, url });
|
|
55
|
+
await hook.hook({ I: this.explorer.actor, url });
|
|
58
56
|
}
|
|
59
57
|
}
|
|
60
58
|
catch (error) {
|
package/dist/src/utils/html.d.ts
CHANGED
|
@@ -2,8 +2,10 @@ import type * as parse5TreeAdapter from 'parse5/lib/tree-adapters/default';
|
|
|
2
2
|
import type { HtmlConfig } from '../config.js';
|
|
3
3
|
export declare const EXPLORBOT_ATTRS: {
|
|
4
4
|
readonly area: "data-explorbot-area";
|
|
5
|
+
readonly coveredBy: "data-explorbot-covered-by";
|
|
5
6
|
readonly context: "data-explorbot-context";
|
|
6
7
|
readonly eidx: "data-explorbot-eidx";
|
|
8
|
+
readonly hit: "data-explorbot-hit";
|
|
7
9
|
readonly variant: "data-explorbot-variant";
|
|
8
10
|
};
|
|
9
11
|
export declare const HTML_SELECTORS: {
|
|
@@ -41,8 +43,10 @@ export declare function inferHtmlRole(data: {
|
|
|
41
43
|
export declare const ELEMENT_EXTRACTION_CONFIG: {
|
|
42
44
|
readonly attrs: {
|
|
43
45
|
readonly area: "data-explorbot-area";
|
|
46
|
+
readonly coveredBy: "data-explorbot-covered-by";
|
|
44
47
|
readonly context: "data-explorbot-context";
|
|
45
48
|
readonly eidx: "data-explorbot-eidx";
|
|
49
|
+
readonly hit: "data-explorbot-hit";
|
|
46
50
|
readonly variant: "data-explorbot-variant";
|
|
47
51
|
};
|
|
48
52
|
readonly codeEditorMarkers: readonly ["monaco", "codemirror", "ace", "ace_editor", "code"];
|
|
@@ -70,6 +74,7 @@ export type ComponentScopeExtractionConfig = {
|
|
|
70
74
|
interactiveControlSelector: string;
|
|
71
75
|
limits: typeof HTML_EXTRACTION_LIMITS;
|
|
72
76
|
};
|
|
77
|
+
export declare function captureHtmlForSnapshot(): string;
|
|
73
78
|
export declare function extractElementData(el: Element, config?: ElementExtractionConfig): {
|
|
74
79
|
tag: string;
|
|
75
80
|
text: string;
|