imperium-crawl 2.5.2 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -16
- package/dist/batch/job-store.js +1 -1
- package/dist/batch/job-store.js.map +1 -1
- package/dist/brave-api/index.js +1 -1
- package/dist/brave-api/index.js.map +1 -1
- package/dist/cli/config.d.ts +21 -0
- package/dist/cli/config.d.ts.map +1 -0
- package/dist/cli/config.js +51 -0
- package/dist/cli/config.js.map +1 -0
- package/dist/cli/engine.d.ts +17 -0
- package/dist/cli/engine.d.ts.map +1 -0
- package/dist/cli/engine.js +440 -0
- package/dist/cli/engine.js.map +1 -0
- package/dist/cli/explore.d.ts +30 -0
- package/dist/cli/explore.d.ts.map +1 -0
- package/dist/cli/explore.js +427 -0
- package/dist/cli/explore.js.map +1 -0
- package/dist/cli/onboarding.d.ts +10 -0
- package/dist/cli/onboarding.d.ts.map +1 -0
- package/dist/cli/onboarding.js +128 -0
- package/dist/cli/onboarding.js.map +1 -0
- package/dist/cli/recorder.d.ts +44 -0
- package/dist/cli/recorder.d.ts.map +1 -0
- package/dist/cli/recorder.js +67 -0
- package/dist/cli/recorder.js.map +1 -0
- package/dist/cli/tui.d.ts +12 -0
- package/dist/cli/tui.d.ts.map +1 -0
- package/dist/cli/tui.js +945 -0
- package/dist/cli/tui.js.map +1 -0
- package/dist/cli/ui.d.ts +26 -0
- package/dist/cli/ui.d.ts.map +1 -0
- package/dist/cli/ui.js +58 -0
- package/dist/cli/ui.js.map +1 -0
- package/dist/core/action-executor.d.ts +66 -0
- package/dist/core/action-executor.d.ts.map +1 -0
- package/dist/core/action-executor.js +403 -0
- package/dist/core/action-executor.js.map +1 -0
- package/dist/core/config.d.ts +16 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +56 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/constants.d.ts +40 -0
- package/dist/core/constants.d.ts.map +1 -0
- package/dist/core/constants.js +86 -0
- package/dist/core/constants.js.map +1 -0
- package/dist/core/formatters.d.ts +36 -0
- package/dist/core/formatters.d.ts.map +1 -0
- package/dist/core/formatters.js +147 -0
- package/dist/core/formatters.js.map +1 -0
- package/dist/engines/camofox.d.ts +27 -0
- package/dist/engines/camofox.d.ts.map +1 -0
- package/dist/engines/camofox.js +432 -0
- package/dist/engines/camofox.js.map +1 -0
- package/dist/engines/index.d.ts +13 -0
- package/dist/engines/index.d.ts.map +1 -0
- package/dist/engines/index.js +41 -0
- package/dist/engines/index.js.map +1 -0
- package/dist/engines/types.d.ts +63 -0
- package/dist/engines/types.d.ts.map +1 -0
- package/dist/engines/types.js +8 -0
- package/dist/engines/types.js.map +1 -0
- package/dist/flows/engine.js +3 -3
- package/dist/flows/engine.js.map +1 -1
- package/dist/flows/storage.js +1 -1
- package/dist/flows/storage.js.map +1 -1
- package/dist/flows/templates.js +1 -1
- package/dist/flows/templates.js.map +1 -1
- package/dist/flows/types.d.ts +405 -405
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/dist/knowledge/store.js +1 -1
- package/dist/knowledge/store.js.map +1 -1
- package/dist/network/index.d.ts +3 -0
- package/dist/network/index.d.ts.map +1 -0
- package/dist/network/index.js +2 -0
- package/dist/network/index.js.map +1 -0
- package/dist/recipes/data/crypto-websocket.json +11 -0
- package/dist/recipes/data/ecommerce-product.json +25 -0
- package/dist/recipes/data/github-trending.json +19 -0
- package/dist/recipes/data/hn-top-stories.json +22 -0
- package/dist/recipes/data/influencer-competitor-spy.json +14 -0
- package/dist/recipes/data/influencer-content-scout.json +14 -0
- package/dist/recipes/data/influencer-hashtag-scout.json +14 -0
- package/dist/recipes/data/influencer-niche-discovery.json +14 -0
- package/dist/recipes/data/job-listings-greenhouse.json +17 -0
- package/dist/recipes/data/news-article-reader.json +9 -0
- package/dist/recipes/data/product-reviews.json +33 -0
- package/dist/recipes/data/reddit-posts.json +8 -0
- package/dist/recipes/data/seo-page-audit.json +26 -0
- package/dist/recipes/data/social-media-mentions.json +31 -0
- package/dist/recipes/index.d.ts +1 -1
- package/dist/recipes/index.d.ts.map +1 -1
- package/dist/recipes/index.js +14 -14
- package/dist/recipes/index.js.map +1 -1
- package/dist/security/auth-vault.js +1 -1
- package/dist/security/auth-vault.js.map +1 -1
- package/dist/security/index.d.ts +6 -0
- package/dist/security/index.d.ts.map +1 -0
- package/dist/security/index.js +4 -0
- package/dist/security/index.js.map +1 -0
- package/dist/sessions/browser-state.js +1 -1
- package/dist/sessions/browser-state.js.map +1 -1
- package/dist/sessions/encryption.js +1 -1
- package/dist/sessions/encryption.js.map +1 -1
- package/dist/sessions/manager.js +1 -1
- package/dist/sessions/manager.js.map +1 -1
- package/dist/skills/detector.js +1 -1
- package/dist/skills/detector.js.map +1 -1
- package/dist/skills/index.d.ts +9 -0
- package/dist/skills/index.d.ts.map +1 -0
- package/dist/skills/index.js +6 -0
- package/dist/skills/index.js.map +1 -0
- package/dist/skills/manager.js +1 -1
- package/dist/skills/manager.js.map +1 -1
- package/dist/snapshot/store.js +1 -1
- package/dist/snapshot/store.js.map +1 -1
- package/dist/social/index.d.ts +7 -0
- package/dist/social/index.d.ts.map +1 -0
- package/dist/social/index.js +4 -0
- package/dist/social/index.js.map +1 -0
- package/dist/stealth/browser-pool.js +1 -1
- package/dist/stealth/browser-pool.js.map +1 -1
- package/dist/stealth/browser.js +2 -2
- package/dist/stealth/browser.js.map +1 -1
- package/dist/stealth/chrome-profile.js +2 -2
- package/dist/stealth/chrome-profile.js.map +1 -1
- package/dist/stealth/index.js +2 -2
- package/dist/stealth/index.js.map +1 -1
- package/dist/tools/ai-extract.js +1 -1
- package/dist/tools/ai-extract.js.map +1 -1
- package/dist/tools/batch-download.d.ts +1 -1
- package/dist/tools/batch-download.js +1 -1
- package/dist/tools/batch-download.js.map +1 -1
- package/dist/tools/batch-scrape.d.ts +2 -2
- package/dist/tools/batch-scrape.js +1 -1
- package/dist/tools/batch-scrape.js.map +1 -1
- package/dist/tools/browser.d.ts +8 -8
- package/dist/tools/browser.js +4 -4
- package/dist/tools/browser.js.map +1 -1
- package/dist/tools/camofox-status.d.ts +14 -0
- package/dist/tools/camofox-status.d.ts.map +1 -0
- package/dist/tools/camofox-status.js +61 -0
- package/dist/tools/camofox-status.js.map +1 -0
- package/dist/tools/camofox-update.d.ts +29 -0
- package/dist/tools/camofox-update.d.ts.map +1 -0
- package/dist/tools/camofox-update.js +108 -0
- package/dist/tools/camofox-update.js.map +1 -0
- package/dist/tools/crawl.d.ts +2 -2
- package/dist/tools/crawl.js +1 -1
- package/dist/tools/crawl.js.map +1 -1
- package/dist/tools/create-skill.js +3 -3
- package/dist/tools/create-skill.js.map +1 -1
- package/dist/tools/discover-apis.d.ts +1 -1
- package/dist/tools/discover-apis.js +1 -1
- package/dist/tools/discover-apis.js.map +1 -1
- package/dist/tools/download.d.ts +7 -7
- package/dist/tools/download.js +1 -1
- package/dist/tools/download.js.map +1 -1
- package/dist/tools/extract.d.ts +1 -1
- package/dist/tools/extract.js +1 -1
- package/dist/tools/extract.js.map +1 -1
- package/dist/tools/image-search.d.ts +1 -1
- package/dist/tools/image-search.js +2 -2
- package/dist/tools/image-search.js.map +1 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +5 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/instagram.d.ts +1 -1
- package/dist/tools/instagram.js +3 -3
- package/dist/tools/instagram.js.map +1 -1
- package/dist/tools/interact.d.ts +86 -86
- package/dist/tools/interact.js +5 -5
- package/dist/tools/interact.js.map +1 -1
- package/dist/tools/knowledge.js +1 -1
- package/dist/tools/knowledge.js.map +1 -1
- package/dist/tools/list-skills.js +1 -1
- package/dist/tools/list-skills.js.map +1 -1
- package/dist/tools/manifest.d.ts.map +1 -1
- package/dist/tools/manifest.js +9 -0
- package/dist/tools/manifest.js.map +1 -1
- package/dist/tools/map.js +1 -1
- package/dist/tools/map.js.map +1 -1
- package/dist/tools/monitor-websocket.d.ts +1 -1
- package/dist/tools/monitor-websocket.js +1 -1
- package/dist/tools/monitor-websocket.js.map +1 -1
- package/dist/tools/monitor.d.ts +2 -2
- package/dist/tools/news-search.d.ts +1 -1
- package/dist/tools/news-search.js +2 -2
- package/dist/tools/news-search.js.map +1 -1
- package/dist/tools/query-api.d.ts +5 -5
- package/dist/tools/query-api.js +1 -1
- package/dist/tools/query-api.js.map +1 -1
- package/dist/tools/readability.js +1 -1
- package/dist/tools/readability.js.map +1 -1
- package/dist/tools/record-flow.d.ts +2 -2
- package/dist/tools/record-flow.js +3 -3
- package/dist/tools/record-flow.js.map +1 -1
- package/dist/tools/reddit.d.ts +2 -2
- package/dist/tools/reddit.js +3 -3
- package/dist/tools/reddit.js.map +1 -1
- package/dist/tools/rss.js +1 -1
- package/dist/tools/rss.js.map +1 -1
- package/dist/tools/run-flow.d.ts +6 -6
- package/dist/tools/run-skill.d.ts +6 -6
- package/dist/tools/run-skill.js +2 -2
- package/dist/tools/run-skill.js.map +1 -1
- package/dist/tools/scrape.d.ts +4 -4
- package/dist/tools/scrape.js +1 -1
- package/dist/tools/scrape.js.map +1 -1
- package/dist/tools/screenshot.js +1 -1
- package/dist/tools/screenshot.js.map +1 -1
- package/dist/tools/search.d.ts +1 -1
- package/dist/tools/search.js +2 -2
- package/dist/tools/search.js.map +1 -1
- package/dist/tools/snapshot.d.ts +5 -5
- package/dist/tools/snapshot.js +2 -2
- package/dist/tools/snapshot.js.map +1 -1
- package/dist/tools/video-search.d.ts +1 -1
- package/dist/tools/video-search.js +2 -2
- package/dist/tools/video-search.js.map +1 -1
- package/dist/tools/watch.d.ts +2 -2
- package/dist/tools/watch.js +1 -1
- package/dist/tools/watch.js.map +1 -1
- package/dist/tools/youtube.d.ts +1 -1
- package/dist/tools/youtube.js +4 -4
- package/dist/tools/youtube.js.map +1 -1
- package/dist/types.d.ts +14 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/fetcher.js +1 -1
- package/dist/utils/fetcher.js.map +1 -1
- package/dist/utils/robots.js +1 -1
- package/dist/utils/robots.js.map +1 -1
- package/package.json +7 -3
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Explore REPL — interactive browser session with live Playwright.
|
|
3
|
+
*
|
|
4
|
+
* Usage: imperium-crawl explore <url>
|
|
5
|
+
*
|
|
6
|
+
* Opens a headed (visible) browser window and gives the user a readline REPL
|
|
7
|
+
* to execute actions interactively. Every successful action is recorded.
|
|
8
|
+
* At any point, run `save-skill <name>` to export the session as a reusable skill.
|
|
9
|
+
*
|
|
10
|
+
* Commands:
|
|
11
|
+
* navigate <url> Navigate to URL
|
|
12
|
+
* click <selector> Click element
|
|
13
|
+
* type <selector> <text> Fill input field
|
|
14
|
+
* select <selector> <value> Select option
|
|
15
|
+
* wait [ms] Wait N ms (default 1000)
|
|
16
|
+
* screenshot [file] Save screenshot
|
|
17
|
+
* snapshot Show ARIA tree + refs
|
|
18
|
+
* evaluate <script> Run JS in page
|
|
19
|
+
* scroll [up|down] [px] Scroll page
|
|
20
|
+
* hover <selector> Hover element
|
|
21
|
+
* press <key> Press keyboard key
|
|
22
|
+
* save-skill <name> Export recording as skill JSON
|
|
23
|
+
* status Show URL, action count
|
|
24
|
+
* history List recorded actions
|
|
25
|
+
* undo Remove last action
|
|
26
|
+
* help Show command list
|
|
27
|
+
* exit / quit Close browser and exit
|
|
28
|
+
*/
|
|
29
|
+
import readline from "node:readline";
|
|
30
|
+
import fs from "node:fs/promises";
|
|
31
|
+
import { ActionRecorder } from "./recorder.js";
|
|
32
|
+
import { executeAction } from "../core/action-executor.js";
|
|
33
|
+
import { getSessionManager } from "../sessions/index.js";
|
|
34
|
+
import { save as saveSkill } from "../skills/index.js";
|
|
35
|
+
import { getEnhancedSnapshot } from "../snapshot/index.js";
|
|
36
|
+
import { getSnapshotStore } from "../snapshot/index.js";
|
|
37
|
+
import { normalizeUrl } from "../utils/url.js";
|
|
38
|
+
const EXPLORE_TIMEOUT = 30_000;
|
|
39
|
+
// ── ANSI helpers ──
|
|
40
|
+
const C = {
|
|
41
|
+
reset: "\x1b[0m",
|
|
42
|
+
bold: "\x1b[1m",
|
|
43
|
+
dim: "\x1b[2m",
|
|
44
|
+
green: "\x1b[32m",
|
|
45
|
+
red: "\x1b[31m",
|
|
46
|
+
yellow: "\x1b[33m",
|
|
47
|
+
cyan: "\x1b[36m",
|
|
48
|
+
blue: "\x1b[34m",
|
|
49
|
+
magenta: "\x1b[35m",
|
|
50
|
+
};
|
|
51
|
+
function ok(msg) { process.stdout.write(`${C.green}✓${C.reset} ${msg}\n`); }
|
|
52
|
+
function err(msg) { process.stdout.write(`${C.red}✗${C.reset} ${msg}\n`); }
|
|
53
|
+
function info(msg) { process.stdout.write(`${C.cyan}›${C.reset} ${msg}\n`); }
|
|
54
|
+
function dim(msg) { process.stdout.write(`${C.dim}${msg}${C.reset}\n`); }
|
|
55
|
+
// ── Help text ──
|
|
56
|
+
const HELP_TEXT = `
|
|
57
|
+
${C.bold}Explore REPL Commands${C.reset}
|
|
58
|
+
${C.dim}────────────────────────────────────────────────────${C.reset}
|
|
59
|
+
${C.cyan}navigate${C.reset} <url> Navigate to a URL
|
|
60
|
+
${C.cyan}click${C.reset} <selector> Click element (CSS selector or @ref)
|
|
61
|
+
${C.cyan}type${C.reset} <selector> <text> Fill input field
|
|
62
|
+
${C.cyan}select${C.reset} <selector> <value> Select dropdown option
|
|
63
|
+
${C.cyan}hover${C.reset} <selector> Hover over element
|
|
64
|
+
${C.cyan}press${C.reset} <key> Press keyboard key (Enter, Tab, Escape…)
|
|
65
|
+
${C.cyan}scroll${C.reset} [up|down] [px] Scroll page (default: down 500px)
|
|
66
|
+
${C.cyan}wait${C.reset} [ms] Wait N milliseconds (default: 1000)
|
|
67
|
+
${C.cyan}evaluate${C.reset} <js> Run JavaScript in page context
|
|
68
|
+
${C.cyan}screenshot${C.reset} [filename.png] Take screenshot
|
|
69
|
+
${C.cyan}snapshot${C.reset} Show ARIA tree with element refs
|
|
70
|
+
${C.dim}────────────────────────────────────────────────────${C.reset}
|
|
71
|
+
${C.yellow}save-skill${C.reset} <name> Export session as reusable skill
|
|
72
|
+
${C.yellow}history${C.reset} List recorded actions
|
|
73
|
+
${C.yellow}undo${C.reset} Remove last action from recording
|
|
74
|
+
${C.yellow}status${C.reset} Show current URL and action count
|
|
75
|
+
${C.yellow}help${C.reset} Show this help
|
|
76
|
+
${C.yellow}exit${C.reset} / ${C.yellow}quit${C.reset} Close browser and exit
|
|
77
|
+
${C.dim}────────────────────────────────────────────────────${C.reset}
|
|
78
|
+
`;
|
|
79
|
+
// ── Tokenizer ──
|
|
80
|
+
/** Split command line respecting quoted strings */
|
|
81
|
+
function tokenize(line) {
|
|
82
|
+
const tokens = [];
|
|
83
|
+
let current = "";
|
|
84
|
+
let inQuote = false;
|
|
85
|
+
let quoteChar = "";
|
|
86
|
+
for (let i = 0; i < line.length; i++) {
|
|
87
|
+
const ch = line[i];
|
|
88
|
+
if (inQuote) {
|
|
89
|
+
if (ch === quoteChar) {
|
|
90
|
+
inQuote = false;
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
current += ch;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
else if (ch === '"' || ch === "'") {
|
|
97
|
+
inQuote = true;
|
|
98
|
+
quoteChar = ch;
|
|
99
|
+
}
|
|
100
|
+
else if (ch === " " || ch === "\t") {
|
|
101
|
+
if (current) {
|
|
102
|
+
tokens.push(current);
|
|
103
|
+
current = "";
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
current += ch;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if (current)
|
|
111
|
+
tokens.push(current);
|
|
112
|
+
return tokens;
|
|
113
|
+
}
|
|
114
|
+
// ── Session ID for snapshot refs ──
|
|
115
|
+
const EXPLORE_SESSION_ID = `explore-${Date.now()}`;
|
|
116
|
+
// ── Main REPL ──
|
|
117
|
+
export async function runExplore(startUrl, sessionId) {
|
|
118
|
+
const { isPlaywrightAvailable } = await import("../stealth/browser.js");
|
|
119
|
+
if (!(await isPlaywrightAvailable())) {
|
|
120
|
+
err("rebrowser-playwright is required for explore mode.");
|
|
121
|
+
err("Install with: npm i rebrowser-playwright");
|
|
122
|
+
process.exit(1);
|
|
123
|
+
}
|
|
124
|
+
const url = normalizeUrl(startUrl);
|
|
125
|
+
info(`Opening browser → ${C.cyan}${url}${C.reset}`);
|
|
126
|
+
info("Type ${C.bold}help${C.reset} for available commands\n");
|
|
127
|
+
// Launch headed browser
|
|
128
|
+
const { chromium } = await import("rebrowser-playwright");
|
|
129
|
+
const { STEALTH_ARGS } = await import("../core/constants.js");
|
|
130
|
+
const { timeZone, locale } = Intl.DateTimeFormat().resolvedOptions();
|
|
131
|
+
const browser = await chromium.launch({
|
|
132
|
+
headless: false,
|
|
133
|
+
args: STEALTH_ARGS,
|
|
134
|
+
});
|
|
135
|
+
const context = await browser.newContext({ timezoneId: timeZone, locale });
|
|
136
|
+
// Restore session cookies if session_id given
|
|
137
|
+
if (sessionId) {
|
|
138
|
+
const session = await getSessionManager().load(sessionId);
|
|
139
|
+
if (session?.cookies.length) {
|
|
140
|
+
await context.addCookies(session.cookies);
|
|
141
|
+
info(`Restored session: ${C.yellow}${sessionId}${C.reset}`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
const page = await context.newPage();
|
|
145
|
+
// Navigate to starting URL
|
|
146
|
+
try {
|
|
147
|
+
await page.goto(url, { waitUntil: "load", timeout: EXPLORE_TIMEOUT });
|
|
148
|
+
ok(`Navigated to ${page.url()}`);
|
|
149
|
+
}
|
|
150
|
+
catch (e) {
|
|
151
|
+
err(`Navigation failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
152
|
+
}
|
|
153
|
+
const recorder = new ActionRecorder(url);
|
|
154
|
+
const screenshots = [];
|
|
155
|
+
// ── Readline REPL ──
|
|
156
|
+
const rl = readline.createInterface({
|
|
157
|
+
input: process.stdin,
|
|
158
|
+
output: process.stdout,
|
|
159
|
+
prompt: `${C.magenta}explore${C.reset}${C.dim}›${C.reset} `,
|
|
160
|
+
terminal: true,
|
|
161
|
+
});
|
|
162
|
+
rl.prompt();
|
|
163
|
+
const cleanup = async () => {
|
|
164
|
+
// Save session cookies if session_id given
|
|
165
|
+
if (sessionId) {
|
|
166
|
+
try {
|
|
167
|
+
const cookies = await context.cookies();
|
|
168
|
+
const stored = cookies.map((c) => ({
|
|
169
|
+
name: c.name, value: c.value, domain: c.domain, path: c.path,
|
|
170
|
+
expires: c.expires, httpOnly: c.httpOnly, secure: c.secure,
|
|
171
|
+
sameSite: c.sameSite,
|
|
172
|
+
}));
|
|
173
|
+
await getSessionManager().save(sessionId, stored, page.url());
|
|
174
|
+
ok(`Session saved: ${sessionId}`);
|
|
175
|
+
}
|
|
176
|
+
catch { /* non-critical */ }
|
|
177
|
+
}
|
|
178
|
+
await browser.close().catch(() => { });
|
|
179
|
+
rl.close();
|
|
180
|
+
};
|
|
181
|
+
process.on("SIGINT", async () => { await cleanup(); process.exit(0); });
|
|
182
|
+
rl.on("line", async (rawLine) => {
|
|
183
|
+
rl.pause();
|
|
184
|
+
const line = rawLine.trim();
|
|
185
|
+
if (!line) {
|
|
186
|
+
rl.resume();
|
|
187
|
+
rl.prompt();
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
const tokens = tokenize(line);
|
|
191
|
+
const cmd = tokens[0]?.toLowerCase() ?? "";
|
|
192
|
+
const args = tokens.slice(1);
|
|
193
|
+
try {
|
|
194
|
+
switch (cmd) {
|
|
195
|
+
case "navigate": {
|
|
196
|
+
if (!args[0]) {
|
|
197
|
+
err("Usage: navigate <url>");
|
|
198
|
+
break;
|
|
199
|
+
}
|
|
200
|
+
const navUrl = args[0].startsWith("http") ? args[0] : `https://${args[0]}`;
|
|
201
|
+
await page.goto(navUrl, { waitUntil: "load", timeout: EXPLORE_TIMEOUT });
|
|
202
|
+
ok(`Navigated to ${page.url()}`);
|
|
203
|
+
recorder.record({ type: "navigate", url: navUrl }, line, page.url());
|
|
204
|
+
break;
|
|
205
|
+
}
|
|
206
|
+
case "click": {
|
|
207
|
+
if (!args[0]) {
|
|
208
|
+
err("Usage: click <selector>");
|
|
209
|
+
break;
|
|
210
|
+
}
|
|
211
|
+
const action = { type: "click", selector: args[0] };
|
|
212
|
+
const result = await executeAction(page, action, screenshots, EXPLORE_TIMEOUT, EXPLORE_SESSION_ID);
|
|
213
|
+
if (result.success) {
|
|
214
|
+
ok(`Clicked: ${args[0]}`);
|
|
215
|
+
recorder.record(action, line, page.url());
|
|
216
|
+
}
|
|
217
|
+
else
|
|
218
|
+
err(result.error ?? "Click failed");
|
|
219
|
+
break;
|
|
220
|
+
}
|
|
221
|
+
case "type": {
|
|
222
|
+
if (!args[0] || !args[1]) {
|
|
223
|
+
err("Usage: type <selector> <text>");
|
|
224
|
+
break;
|
|
225
|
+
}
|
|
226
|
+
const text = args.slice(1).join(" ");
|
|
227
|
+
const action = { type: "type", selector: args[0], text };
|
|
228
|
+
const result = await executeAction(page, action, screenshots, EXPLORE_TIMEOUT, EXPLORE_SESSION_ID);
|
|
229
|
+
if (result.success) {
|
|
230
|
+
ok(`Typed into: ${args[0]}`);
|
|
231
|
+
recorder.record(action, line, page.url());
|
|
232
|
+
}
|
|
233
|
+
else
|
|
234
|
+
err(result.error ?? "Type failed");
|
|
235
|
+
break;
|
|
236
|
+
}
|
|
237
|
+
case "select": {
|
|
238
|
+
if (!args[0] || !args[1]) {
|
|
239
|
+
err("Usage: select <selector> <value>");
|
|
240
|
+
break;
|
|
241
|
+
}
|
|
242
|
+
const action = { type: "select", selector: args[0], value: args[1] };
|
|
243
|
+
const result = await executeAction(page, action, screenshots, EXPLORE_TIMEOUT, EXPLORE_SESSION_ID);
|
|
244
|
+
if (result.success) {
|
|
245
|
+
ok(`Selected: ${args[1]} in ${args[0]}`);
|
|
246
|
+
recorder.record(action, line, page.url());
|
|
247
|
+
}
|
|
248
|
+
else
|
|
249
|
+
err(result.error ?? "Select failed");
|
|
250
|
+
break;
|
|
251
|
+
}
|
|
252
|
+
case "hover": {
|
|
253
|
+
if (!args[0]) {
|
|
254
|
+
err("Usage: hover <selector>");
|
|
255
|
+
break;
|
|
256
|
+
}
|
|
257
|
+
const action = { type: "hover", selector: args[0] };
|
|
258
|
+
const result = await executeAction(page, action, screenshots, EXPLORE_TIMEOUT, EXPLORE_SESSION_ID);
|
|
259
|
+
if (result.success) {
|
|
260
|
+
ok(`Hovered: ${args[0]}`);
|
|
261
|
+
recorder.record(action, line, page.url());
|
|
262
|
+
}
|
|
263
|
+
else
|
|
264
|
+
err(result.error ?? "Hover failed");
|
|
265
|
+
break;
|
|
266
|
+
}
|
|
267
|
+
case "press": {
|
|
268
|
+
if (!args[0]) {
|
|
269
|
+
err("Usage: press <key> (e.g. Enter, Tab, Escape)");
|
|
270
|
+
break;
|
|
271
|
+
}
|
|
272
|
+
const action = { type: "press", key: args[0] };
|
|
273
|
+
const result = await executeAction(page, action, screenshots, EXPLORE_TIMEOUT, EXPLORE_SESSION_ID);
|
|
274
|
+
if (result.success) {
|
|
275
|
+
ok(`Pressed: ${args[0]}`);
|
|
276
|
+
recorder.record(action, line, page.url());
|
|
277
|
+
}
|
|
278
|
+
else
|
|
279
|
+
err(result.error ?? "Press failed");
|
|
280
|
+
break;
|
|
281
|
+
}
|
|
282
|
+
case "scroll": {
|
|
283
|
+
const direction = args[0]?.toLowerCase() ?? "down";
|
|
284
|
+
const px = parseInt(args[1] ?? "500", 10);
|
|
285
|
+
const y = direction === "up" ? -px : px;
|
|
286
|
+
const action = { type: "scroll", y };
|
|
287
|
+
const result = await executeAction(page, action, screenshots, EXPLORE_TIMEOUT, EXPLORE_SESSION_ID);
|
|
288
|
+
if (result.success) {
|
|
289
|
+
ok(`Scrolled ${direction} ${Math.abs(y)}px`);
|
|
290
|
+
recorder.record(action, line, page.url());
|
|
291
|
+
}
|
|
292
|
+
else
|
|
293
|
+
err(result.error ?? "Scroll failed");
|
|
294
|
+
break;
|
|
295
|
+
}
|
|
296
|
+
case "wait": {
|
|
297
|
+
const ms = parseInt(args[0] ?? "1000", 10);
|
|
298
|
+
const action = { type: "wait", duration: ms };
|
|
299
|
+
await executeAction(page, action, screenshots, EXPLORE_TIMEOUT + ms, EXPLORE_SESSION_ID);
|
|
300
|
+
ok(`Waited ${ms}ms`);
|
|
301
|
+
recorder.record(action, line, page.url());
|
|
302
|
+
break;
|
|
303
|
+
}
|
|
304
|
+
case "screenshot": {
|
|
305
|
+
const filename = args[0] ?? `screenshot-${Date.now()}.png`;
|
|
306
|
+
const buf = await page.screenshot({ fullPage: false });
|
|
307
|
+
await fs.writeFile(filename, buf);
|
|
308
|
+
ok(`Screenshot saved: ${filename}`);
|
|
309
|
+
recorder.record({ type: "screenshot" }, line, page.url());
|
|
310
|
+
break;
|
|
311
|
+
}
|
|
312
|
+
case "snapshot": {
|
|
313
|
+
info("Taking ARIA snapshot...");
|
|
314
|
+
try {
|
|
315
|
+
const snapshot = await getEnhancedSnapshot(page, { interactive: true, compact: true });
|
|
316
|
+
getSnapshotStore().save(EXPLORE_SESSION_ID, snapshot.refs, page.url());
|
|
317
|
+
process.stdout.write("\n" + snapshot.tree + "\n\n");
|
|
318
|
+
info(`${C.dim}${Object.keys(snapshot.refs).length} refs available. Use @ref in commands.${C.reset}`);
|
|
319
|
+
}
|
|
320
|
+
catch (e) {
|
|
321
|
+
err(`Snapshot failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
322
|
+
}
|
|
323
|
+
break;
|
|
324
|
+
}
|
|
325
|
+
case "evaluate": {
|
|
326
|
+
if (!args[0]) {
|
|
327
|
+
err("Usage: evaluate <script>");
|
|
328
|
+
break;
|
|
329
|
+
}
|
|
330
|
+
const script = args.join(" ");
|
|
331
|
+
const action = { type: "evaluate", script };
|
|
332
|
+
const result = await executeAction(page, action, screenshots, EXPLORE_TIMEOUT, EXPLORE_SESSION_ID);
|
|
333
|
+
if (result.success) {
|
|
334
|
+
ok("Evaluated:");
|
|
335
|
+
process.stdout.write(JSON.stringify(result.result, null, 2) + "\n");
|
|
336
|
+
recorder.record(action, line, page.url());
|
|
337
|
+
}
|
|
338
|
+
else {
|
|
339
|
+
err(result.error ?? "Evaluate failed");
|
|
340
|
+
}
|
|
341
|
+
break;
|
|
342
|
+
}
|
|
343
|
+
case "save-skill": {
|
|
344
|
+
if (!args[0]) {
|
|
345
|
+
err("Usage: save-skill <name>");
|
|
346
|
+
break;
|
|
347
|
+
}
|
|
348
|
+
const skillName = args[0];
|
|
349
|
+
if (!/^[a-zA-Z0-9_-]+$/.test(skillName)) {
|
|
350
|
+
err("Skill name may only contain letters, numbers, hyphens, and underscores");
|
|
351
|
+
break;
|
|
352
|
+
}
|
|
353
|
+
if (recorder.count === 0) {
|
|
354
|
+
err("No actions recorded yet. Perform some actions first.");
|
|
355
|
+
break;
|
|
356
|
+
}
|
|
357
|
+
// Auto-detect parameters
|
|
358
|
+
const detectedParams = recorder.detectParameters();
|
|
359
|
+
const paramCount = Object.keys(detectedParams).length;
|
|
360
|
+
const description = `Recorded skill from ${new URL(url).hostname} — ${recorder.count} actions`;
|
|
361
|
+
const config = recorder.toSkillConfig(skillName, description, sessionId, detectedParams);
|
|
362
|
+
await saveSkill(skillName, config);
|
|
363
|
+
ok(`Saved skill: ${C.yellow}${skillName}${C.reset} (${recorder.count} actions${paramCount > 0 ? `, ${paramCount} params detected` : ""})`);
|
|
364
|
+
info(`Run with: ${C.cyan}imperium-crawl run-skill ${skillName}${C.reset}`);
|
|
365
|
+
break;
|
|
366
|
+
}
|
|
367
|
+
case "history": {
|
|
368
|
+
const h = recorder.getHistory();
|
|
369
|
+
if (h.length === 0) {
|
|
370
|
+
info("No actions recorded yet.");
|
|
371
|
+
break;
|
|
372
|
+
}
|
|
373
|
+
process.stdout.write(`\n${C.bold}Recorded actions (${h.length}):${C.reset}\n`);
|
|
374
|
+
h.forEach((r, i) => {
|
|
375
|
+
dim(` ${String(i + 1).padStart(2)}. ${r.rawCommand}`);
|
|
376
|
+
});
|
|
377
|
+
process.stdout.write("\n");
|
|
378
|
+
break;
|
|
379
|
+
}
|
|
380
|
+
case "undo": {
|
|
381
|
+
const undone = recorder.undo();
|
|
382
|
+
if (undone) {
|
|
383
|
+
ok(`Removed: ${undone.rawCommand}`);
|
|
384
|
+
info(`${recorder.count} actions remaining`);
|
|
385
|
+
}
|
|
386
|
+
else {
|
|
387
|
+
info("Nothing to undo");
|
|
388
|
+
}
|
|
389
|
+
break;
|
|
390
|
+
}
|
|
391
|
+
case "status": {
|
|
392
|
+
process.stdout.write(`\n`);
|
|
393
|
+
info(`URL: ${C.cyan}${page.url()}${C.reset}`);
|
|
394
|
+
info(`Actions: ${C.yellow}${recorder.count}${C.reset} recorded`);
|
|
395
|
+
if (sessionId)
|
|
396
|
+
info(`Session: ${C.yellow}${sessionId}${C.reset}`);
|
|
397
|
+
process.stdout.write(`\n`);
|
|
398
|
+
break;
|
|
399
|
+
}
|
|
400
|
+
case "help": {
|
|
401
|
+
process.stdout.write(HELP_TEXT);
|
|
402
|
+
break;
|
|
403
|
+
}
|
|
404
|
+
case "exit":
|
|
405
|
+
case "quit": {
|
|
406
|
+
info("Closing browser...");
|
|
407
|
+
await cleanup();
|
|
408
|
+
process.exit(0);
|
|
409
|
+
break;
|
|
410
|
+
}
|
|
411
|
+
default: {
|
|
412
|
+
err(`Unknown command: ${cmd}. Type ${C.bold}help${C.reset} for available commands.`);
|
|
413
|
+
break;
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
catch (e) {
|
|
418
|
+
err(`Error: ${e instanceof Error ? e.message : String(e)}`);
|
|
419
|
+
}
|
|
420
|
+
rl.resume();
|
|
421
|
+
rl.prompt();
|
|
422
|
+
});
|
|
423
|
+
rl.on("close", async () => {
|
|
424
|
+
await cleanup();
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
//# sourceMappingURL=explore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"explore.js","sourceRoot":"","sources":["../../src/cli/explore.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interactive setup wizard for imperium-crawl CLI.
|
|
3
|
+
*
|
|
4
|
+
* Usage: imperium-crawl setup
|
|
5
|
+
*
|
|
6
|
+
* Guides the user through configuring API keys and saves them to
|
|
7
|
+
* ~/.imperium-crawl/config.json for persistent use.
|
|
8
|
+
*/
|
|
9
|
+
export declare function runSetup(): Promise<void>;
|
|
10
|
+
//# sourceMappingURL=onboarding.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"onboarding.d.ts","sourceRoot":"","sources":["../../src/cli/onboarding.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAeH,wBAAsB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CA2H9C"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interactive setup wizard for imperium-crawl CLI.
|
|
3
|
+
*
|
|
4
|
+
* Usage: imperium-crawl setup
|
|
5
|
+
*
|
|
6
|
+
* Guides the user through configuring API keys and saves them to
|
|
7
|
+
* ~/.imperium-crawl/config.json for persistent use.
|
|
8
|
+
*/
|
|
9
|
+
import chalk from "chalk";
|
|
10
|
+
import { input, select, confirm } from "@inquirer/prompts";
|
|
11
|
+
import { loadCliConfig, saveCliConfig, getCliConfigPath } from "./config.js";
|
|
12
|
+
const BANNER = chalk.cyan(`
|
|
13
|
+
██╗███╗ ███╗██████╗ ███████╗██████╗ ██╗██╗ ██╗███╗ ███╗
|
|
14
|
+
██║████╗ ████║██╔══██╗██╔════╝██╔══██╗██║██║ ██║████╗ ████║
|
|
15
|
+
██║██╔████╔██║██████╔╝█████╗ ██████╔╝██║██║ ██║██╔████╔██║
|
|
16
|
+
██║██║╚██╔╝██║██╔═══╝ ██╔══╝ ██╔══██╗██║██║ ██║██║╚██╔╝██║
|
|
17
|
+
██║██║ ╚═╝ ██║██║ ███████╗██║ ██║██║╚██████╔╝██║ ╚═╝ ██║
|
|
18
|
+
╚═╝╚═╝ ╚═╝╚═╝ ╚══════╝╚═╝ ╚═╝╚═╝ ╚═════╝ ╚═╝ ╚═╝
|
|
19
|
+
`);
|
|
20
|
+
export async function runSetup() {
|
|
21
|
+
console.log(BANNER);
|
|
22
|
+
console.log(chalk.bold(" API Key Setup\n"));
|
|
23
|
+
const existing = loadCliConfig();
|
|
24
|
+
const config = { ...existing };
|
|
25
|
+
// ── Brave Search ──────────────────────────────────────────────────
|
|
26
|
+
const hasBrave = !!(process.env.BRAVE_API_KEY || existing.BRAVE_API_KEY);
|
|
27
|
+
if (hasBrave) {
|
|
28
|
+
console.log(chalk.green(" ✓ BRAVE_API_KEY") +
|
|
29
|
+
chalk.dim(" — already configured (search, news_search, image_search, video_search)"));
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
console.log(chalk.dim(" Brave Search enables 4 search tools. Free tier: https://brave.com/search/api/\n"));
|
|
33
|
+
const braveKey = await input({
|
|
34
|
+
message: "Brave Search API key (press Enter to skip):",
|
|
35
|
+
});
|
|
36
|
+
if (braveKey.trim())
|
|
37
|
+
config.BRAVE_API_KEY = braveKey.trim();
|
|
38
|
+
}
|
|
39
|
+
console.log();
|
|
40
|
+
// ── LLM Provider ─────────────────────────────────────────────────
|
|
41
|
+
const hasLLM = !!(process.env.LLM_API_KEY || existing.LLM_API_KEY);
|
|
42
|
+
if (hasLLM) {
|
|
43
|
+
const currentProvider = process.env.LLM_PROVIDER || existing.LLM_PROVIDER || "anthropic";
|
|
44
|
+
console.log(chalk.green(` ✓ LLM_API_KEY (${currentProvider})`) +
|
|
45
|
+
chalk.dim(" — already configured (ai_extract tool)"));
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
console.log(chalk.dim(" LLM key enables the ai_extract tool — natural language data extraction.\n"));
|
|
49
|
+
const provider = await select({
|
|
50
|
+
message: "LLM provider (for ai_extract tool):",
|
|
51
|
+
choices: [
|
|
52
|
+
{
|
|
53
|
+
name: "Anthropic (Claude Haiku — default)",
|
|
54
|
+
value: "anthropic",
|
|
55
|
+
description: "Fast, affordable. Get key: https://console.anthropic.com",
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
name: "OpenAI (GPT-4o mini — default)",
|
|
59
|
+
value: "openai",
|
|
60
|
+
description: "Widely used. Get key: https://platform.openai.com",
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
name: "MiniMax (M2.5 — 200K context, reasoning)",
|
|
64
|
+
value: "minimax",
|
|
65
|
+
description: "Strong model, OpenAI-compatible API.",
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
name: "Skip for now",
|
|
69
|
+
value: "skip",
|
|
70
|
+
description: "Configure later via env vars or run setup again.",
|
|
71
|
+
},
|
|
72
|
+
],
|
|
73
|
+
});
|
|
74
|
+
if (provider !== "skip") {
|
|
75
|
+
config.LLM_PROVIDER = provider;
|
|
76
|
+
const providerLabel = provider === "anthropic" ? "Anthropic" : provider === "openai" ? "OpenAI" : "MiniMax";
|
|
77
|
+
const llmKey = await input({
|
|
78
|
+
message: `${providerLabel} API key:`,
|
|
79
|
+
});
|
|
80
|
+
if (llmKey.trim())
|
|
81
|
+
config.LLM_API_KEY = llmKey.trim();
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
console.log();
|
|
85
|
+
// ── 2Captcha ─────────────────────────────────────────────────────
|
|
86
|
+
const hasCaptcha = !!(process.env.TWOCAPTCHA_API_KEY ||
|
|
87
|
+
process.env.TWO_CAPTCHA_API_KEY ||
|
|
88
|
+
existing.TWOCAPTCHA_API_KEY);
|
|
89
|
+
if (hasCaptcha) {
|
|
90
|
+
console.log(chalk.green(" ✓ TWOCAPTCHA_API_KEY") +
|
|
91
|
+
chalk.dim(" — already configured (auto CAPTCHA solving in stealth level 3)"));
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
const wantCaptcha = await confirm({
|
|
95
|
+
message: "Configure 2Captcha for automatic CAPTCHA solving? (optional)",
|
|
96
|
+
default: false,
|
|
97
|
+
});
|
|
98
|
+
if (wantCaptcha) {
|
|
99
|
+
const captchaKey = await input({
|
|
100
|
+
message: "2Captcha API key (https://2captcha.com):",
|
|
101
|
+
});
|
|
102
|
+
if (captchaKey.trim())
|
|
103
|
+
config.TWOCAPTCHA_API_KEY = captchaKey.trim();
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// ── Save + Summary ────────────────────────────────────────────────
|
|
107
|
+
saveCliConfig(config);
|
|
108
|
+
console.log("\n" + chalk.bold(" ─────────────────────────────────────────"));
|
|
109
|
+
const enabledTools = [];
|
|
110
|
+
if (config.BRAVE_API_KEY || process.env.BRAVE_API_KEY) {
|
|
111
|
+
enabledTools.push("search, news_search, image_search, video_search");
|
|
112
|
+
}
|
|
113
|
+
if (config.LLM_API_KEY || process.env.LLM_API_KEY) {
|
|
114
|
+
enabledTools.push("ai_extract");
|
|
115
|
+
}
|
|
116
|
+
if (config.TWOCAPTCHA_API_KEY || process.env.TWOCAPTCHA_API_KEY) {
|
|
117
|
+
enabledTools.push("CAPTCHA auto-solve (stealth lvl 3)");
|
|
118
|
+
}
|
|
119
|
+
if (enabledTools.length > 0) {
|
|
120
|
+
console.log(chalk.green(`\n 🚀 Ready! Extra tools enabled: ${enabledTools.join(", ")}`));
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
console.log(chalk.yellow("\n ⚠ No API keys configured.") +
|
|
124
|
+
chalk.dim(" Basic scraping tools work without keys."));
|
|
125
|
+
}
|
|
126
|
+
console.log(chalk.dim(`\n Config saved → ${getCliConfigPath()}\n`));
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=onboarding.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"onboarding.js","sourceRoot":"","sources":["../../src/cli/onboarding.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Action Recorder — captures browser actions during an explore REPL session.
|
|
3
|
+
*
|
|
4
|
+
* Records every action the user performs, supports undo, and can export
|
|
5
|
+
* the captured sequence as an InteractSkillConfig JSON file.
|
|
6
|
+
*
|
|
7
|
+
* Usage: instantiate one per explore session, call record() after each action,
|
|
8
|
+
* call toSkillConfig() at the end to get a saveable skill.
|
|
9
|
+
*/
|
|
10
|
+
import type { ActionInput } from "../core/action-executor.js";
|
|
11
|
+
import type { InteractSkillConfig } from "../skills/index.js";
|
|
12
|
+
import type { SkillParameters } from "../skills/index.js";
|
|
13
|
+
export interface RecordedAction {
|
|
14
|
+
action: ActionInput;
|
|
15
|
+
rawCommand: string;
|
|
16
|
+
pageUrl: string;
|
|
17
|
+
timestamp: number;
|
|
18
|
+
}
|
|
19
|
+
export declare class ActionRecorder {
|
|
20
|
+
private history;
|
|
21
|
+
private startUrl;
|
|
22
|
+
constructor(startUrl: string);
|
|
23
|
+
/** Record an action after it was successfully executed. */
|
|
24
|
+
record(action: ActionInput, rawCommand: string, pageUrl: string): void;
|
|
25
|
+
/** Remove the last recorded action. */
|
|
26
|
+
undo(): RecordedAction | null;
|
|
27
|
+
/** Current number of recorded actions. */
|
|
28
|
+
get count(): number;
|
|
29
|
+
/** List all recorded actions for display. */
|
|
30
|
+
getHistory(): RecordedAction[];
|
|
31
|
+
/** Clear all recorded actions. */
|
|
32
|
+
clear(): void;
|
|
33
|
+
/**
|
|
34
|
+
* Heuristically detect fields that should be parameterized.
|
|
35
|
+
* Returns suggested SkillParameters — user reviews and adjusts.
|
|
36
|
+
*/
|
|
37
|
+
detectParameters(): SkillParameters;
|
|
38
|
+
/**
|
|
39
|
+
* Export recorded session to InteractSkillConfig.
|
|
40
|
+
* Ready to save with skills/manager.ts save().
|
|
41
|
+
*/
|
|
42
|
+
toSkillConfig(name: string, description: string, sessionId?: string, parameters?: SkillParameters): InteractSkillConfig;
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=recorder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recorder.d.ts","sourceRoot":"","sources":["../../src/cli/recorder.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAG1D,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,WAAW,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,OAAO,CAAwB;IACvC,OAAO,CAAC,QAAQ,CAAS;gBAEb,QAAQ,EAAE,MAAM;IAI5B,2DAA2D;IAC3D,MAAM,CAAC,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAStE,uCAAuC;IACvC,IAAI,IAAI,cAAc,GAAG,IAAI;IAI7B,0CAA0C;IAC1C,IAAI,KAAK,IAAI,MAAM,CAElB;IAED,6CAA6C;IAC7C,UAAU,IAAI,cAAc,EAAE;IAI9B,kCAAkC;IAClC,KAAK,IAAI,IAAI;IAIb;;;OAGG;IACH,gBAAgB,IAAI,eAAe;IAKnC;;;OAGG;IACH,aAAa,CACX,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,EACnB,SAAS,CAAC,EAAE,MAAM,EAClB,UAAU,CAAC,EAAE,eAAe,GAC3B,mBAAmB;CAYvB"}
|