crawlix 0.1.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/LICENSE +21 -0
- package/README.md +187 -0
- package/dist/adapters/base.d.ts +8 -0
- package/dist/adapters/base.d.ts.map +1 -0
- package/dist/adapters/base.js +2 -0
- package/dist/adapters/base.js.map +1 -0
- package/dist/adapters/web.d.ts +14 -0
- package/dist/adapters/web.d.ts.map +1 -0
- package/dist/adapters/web.js +120 -0
- package/dist/adapters/web.js.map +1 -0
- package/dist/cli/commands/agents.d.ts +3 -0
- package/dist/cli/commands/agents.d.ts.map +1 -0
- package/dist/cli/commands/agents.js +9 -0
- package/dist/cli/commands/agents.js.map +1 -0
- package/dist/cli/commands/run.d.ts +3 -0
- package/dist/cli/commands/run.d.ts.map +1 -0
- package/dist/cli/commands/run.js +49 -0
- package/dist/cli/commands/run.js.map +1 -0
- package/dist/cli/commands/setup.d.ts +3 -0
- package/dist/cli/commands/setup.d.ts.map +1 -0
- package/dist/cli/commands/setup.js +93 -0
- package/dist/cli/commands/setup.js.map +1 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +17 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/core/director.d.ts +14 -0
- package/dist/core/director.d.ts.map +1 -0
- package/dist/core/director.js +112 -0
- package/dist/core/director.js.map +1 -0
- package/dist/core/extractor.d.ts +6 -0
- package/dist/core/extractor.d.ts.map +1 -0
- package/dist/core/extractor.js +42 -0
- package/dist/core/extractor.js.map +1 -0
- package/dist/core/orchestrator.d.ts +27 -0
- package/dist/core/orchestrator.d.ts.map +1 -0
- package/dist/core/orchestrator.js +62 -0
- package/dist/core/orchestrator.js.map +1 -0
- package/dist/core/reporter.d.ts +8 -0
- package/dist/core/reporter.d.ts.map +1 -0
- package/dist/core/reporter.js +132 -0
- package/dist/core/reporter.js.map +1 -0
- package/dist/core/runner.d.ts +13 -0
- package/dist/core/runner.d.ts.map +1 -0
- package/dist/core/runner.js +61 -0
- package/dist/core/runner.js.map +1 -0
- package/dist/lib/browser.d.ts +4 -0
- package/dist/lib/browser.d.ts.map +1 -0
- package/dist/lib/browser.js +24 -0
- package/dist/lib/browser.js.map +1 -0
- package/dist/lib/display.d.ts +7 -0
- package/dist/lib/display.d.ts.map +1 -0
- package/dist/lib/display.js +80 -0
- package/dist/lib/display.js.map +1 -0
- package/dist/lib/getConfigs.d.ts +3 -0
- package/dist/lib/getConfigs.d.ts.map +1 -0
- package/dist/lib/getConfigs.js +12 -0
- package/dist/lib/getConfigs.js.map +1 -0
- package/dist/llm/index.d.ts +15 -0
- package/dist/llm/index.d.ts.map +1 -0
- package/dist/llm/index.js +147 -0
- package/dist/llm/index.js.map +1 -0
- package/dist/personas/index.d.ts +5 -0
- package/dist/personas/index.d.ts.map +1 -0
- package/dist/personas/index.js +100 -0
- package/dist/personas/index.js.map +1 -0
- package/dist/personas/loader.d.ts +4 -0
- package/dist/personas/loader.d.ts.map +1 -0
- package/dist/personas/loader.js +72 -0
- package/dist/personas/loader.js.map +1 -0
- package/dist/types/index.d.ts +76 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +3 -0
- package/dist/types/index.js.map +1 -0
- package/package.json +57 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import ora, {} from 'ora';
|
|
3
|
+
import boxen from 'boxen';
|
|
4
|
+
const spinners = new Map();
|
|
5
|
+
export function agentStarted(personaName) {
|
|
6
|
+
const spinner = ora({
|
|
7
|
+
text: chalk.gray(`${personaName} — running...`),
|
|
8
|
+
spinner: 'dots',
|
|
9
|
+
}).start();
|
|
10
|
+
spinners.set(personaName, spinner);
|
|
11
|
+
}
|
|
12
|
+
export function agentDone(result) {
|
|
13
|
+
const spinner = spinners.get(result.persona);
|
|
14
|
+
if (!spinner)
|
|
15
|
+
return;
|
|
16
|
+
const critical = result.findings.filter(f => f.severity === 'critical').length;
|
|
17
|
+
const warnings = result.findings.filter(f => f.severity === 'warning').length;
|
|
18
|
+
const info = result.findings.filter(f => f.severity === 'info').length;
|
|
19
|
+
const duration = (result.duration / 1000).toFixed(1);
|
|
20
|
+
const findings = result.findings.length === 0
|
|
21
|
+
? chalk.green('no findings')
|
|
22
|
+
: [
|
|
23
|
+
critical > 0 ? chalk.red(`${critical} critical`) : null,
|
|
24
|
+
warnings > 0 ? chalk.yellow(`${warnings} warnings`) : null,
|
|
25
|
+
info > 0 ? chalk.gray(`${info} info`) : null,
|
|
26
|
+
].filter(Boolean).join(chalk.gray(' · '));
|
|
27
|
+
const status = result.goalReached
|
|
28
|
+
? chalk.green('✓')
|
|
29
|
+
: result.stuck
|
|
30
|
+
? chalk.red('✗')
|
|
31
|
+
: chalk.yellow('~');
|
|
32
|
+
spinner.stopAndPersist({
|
|
33
|
+
symbol: status,
|
|
34
|
+
text: `${chalk.white(result.persona.padEnd(16))} ${findings} ${chalk.gray(`${result.steps} steps · ${duration}s`)}`,
|
|
35
|
+
});
|
|
36
|
+
spinners.delete(result.persona);
|
|
37
|
+
}
|
|
38
|
+
export function printFinding(finding, persona) {
|
|
39
|
+
const icon = finding.severity === 'critical'
|
|
40
|
+
? chalk.red('⚠ critical')
|
|
41
|
+
: finding.severity === 'warning'
|
|
42
|
+
? chalk.yellow('⚠ warning')
|
|
43
|
+
: chalk.gray('ℹ info');
|
|
44
|
+
console.log(` ${icon} ${chalk.gray(`[${persona}]`)} ${finding.description}`);
|
|
45
|
+
if (finding.element) {
|
|
46
|
+
console.log(` ${chalk.gray('element:')} ${finding.element}`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
export function printSummary(results) {
|
|
50
|
+
const allFindings = results.flatMap(r => r.findings);
|
|
51
|
+
const critical = allFindings.filter(f => f.severity === 'critical').length;
|
|
52
|
+
const warnings = allFindings.filter(f => f.severity === 'warning').length;
|
|
53
|
+
const info = allFindings.filter(f => f.severity === 'info').length;
|
|
54
|
+
const passed = results.filter(r => r.goalReached).length;
|
|
55
|
+
const stuck = results.filter(r => r.stuck).length;
|
|
56
|
+
const totalTime = results.reduce((acc, r) => acc + r.duration, 0);
|
|
57
|
+
const lines = [
|
|
58
|
+
chalk.bold.white('👾 Crawlix — run complete'),
|
|
59
|
+
'',
|
|
60
|
+
` ${chalk.red(`${critical} critical`)} ${chalk.yellow(`${warnings} warnings`)} ${chalk.gray(`${info} info`)}`,
|
|
61
|
+
'',
|
|
62
|
+
` ${chalk.green(`${passed} passed`)} ${chalk.red(`${stuck} stuck`)} ${chalk.gray(`${results.length - passed - stuck} incomplete`)}`,
|
|
63
|
+
'',
|
|
64
|
+
chalk.gray(` total time → ${(totalTime / 1000).toFixed(1)}s`),
|
|
65
|
+
].join('\n');
|
|
66
|
+
console.log('\n' + boxen(lines, {
|
|
67
|
+
padding: 1,
|
|
68
|
+
borderColor: 'magenta',
|
|
69
|
+
borderStyle: 'round',
|
|
70
|
+
dimBorder: false,
|
|
71
|
+
}));
|
|
72
|
+
}
|
|
73
|
+
export function printHeader(url, goal, personas) {
|
|
74
|
+
console.log('\n' + chalk.bold.white(' 👾 Crawlix - Claw through bugs before your users do.'));
|
|
75
|
+
console.log(chalk.gray(` target → `) + chalk.white(url));
|
|
76
|
+
console.log(chalk.gray(` goal → `) + chalk.white(goal));
|
|
77
|
+
console.log(chalk.gray(` agents → `) + chalk.white(personas.join(', ')));
|
|
78
|
+
console.log();
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=display.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"display.js","sourceRoot":"","sources":["../../src/lib/display.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,GAAG,EAAE,EAAY,MAAM,KAAK,CAAA;AACnC,OAAO,KAAK,MAAM,OAAO,CAAA;AAGzB,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAe,CAAA;AAEvC,MAAM,UAAU,YAAY,CAAC,WAAmB;IAC9C,MAAM,OAAO,GAAG,GAAG,CAAC;QAClB,IAAI,EAAK,KAAK,CAAC,IAAI,CAAC,GAAG,WAAW,eAAe,CAAC;QAClD,OAAO,EAAE,MAAM;KAChB,CAAC,CAAC,KAAK,EAAE,CAAA;IACV,QAAQ,CAAC,GAAG,CAAC,WAAW,EAAE,OAAO,CAAC,CAAA;AACpC,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,MAAiB;IACzC,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;IAC5C,IAAI,CAAC,OAAO;QAAE,OAAM;IAEpB,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,UAAU,CAAC,CAAC,MAAM,CAAA;IAC9E,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,MAAM,CAAA;IAC7E,MAAM,IAAI,GAAO,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC,MAAM,CAAA;IAC1E,MAAM,QAAQ,GAAG,CAAC,MAAM,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;IAEpD,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC;QAC3C,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,aAAa,CAAC;QAC5B,CAAC,CAAC;YACE,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,QAAQ,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI;YACvD,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,QAAQ,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI;YAC1D,IAAI,GAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,CAAU,CAAC,CAAC,IAAI;SAC1D,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAA;IAE7C,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW;QAC/B,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;QAClB,CAAC,CAAC,MAAM,CAAC,KAAK;YACZ,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC;YAChB,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;IAEvB,OAAO,CAAC,cAAc,CAAC;QACrB,MAAM,EAAE,MAAM;QACd,IAAI,EAAI,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,QAAQ,KAAK,KAAK,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,KAAK,YAAY,QAAQ,GAAG,CAAC,EAAE;KACvH,CAAC,CAAA;IAEF,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;AACjC,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,OAAgB,EAAE,OAAe;IAC5D,MAAM,IAAI,GAAG,OAAO,CAAC,QAAQ,KAAK,UAAU;QAC1C,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC;QACzB,CAAC,CAAC,OAAO,CAAC,QAAQ,KAAK,SAAS;YAC9B,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC;YAC3B,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;IAE1B,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,KAAK,KAAK,CAAC,IAAI,CAAC,IAAI,OAAO,GAAG,CAAC,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC,CAAA;IAC9E,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;QACpB,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC,CAAA;IAC/D,CAAC;AACH,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,OAAoB;IAC/C,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAA;IACpD,MAAM,QAAQ,GAAM,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,UAAU,CAAC,CAAC,MAAM,CAAA;IAC7E,MAAM,QAAQ,GAAM,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,MAAM,CAAA;IAC5E,MAAM,IAAI,GAAU,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC,MAAM,CAAA;IACzE,MAAM,MAAM,GAAQ,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,MAAM,CAAA;IAC7D,MAAM,KAAK,GAAS,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAA;IACvD,MAAM,SAAS,GAAK,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAA;IAEnE,MAAM,KAAK,GAAG;QACZ,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,2BAA2B,CAAC;QAC7C,EAAE;QACF,KAAK,KAAK,CAAC,GAAG,CAAC,GAAG,QAAQ,WAAW,CAAC,KAAK,KAAK,CAAC,MAAM,CAAC,GAAG,QAAQ,WAAW,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,EAAE;QAChH,EAAE;QACF,KAAK,KAAK,CAAC,KAAK,CAAC,GAAG,MAAM,SAAS,CAAC,KAAK,KAAK,CAAC,GAAG,CAAC,GAAG,KAAK,QAAQ,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,MAAM,GAAG,MAAM,GAAG,KAAK,aAAa,CAAC,EAAE;QACtI,EAAE;QACF,KAAK,CAAC,IAAI,CAAC,kBAAkB,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;KAC/D,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAEZ,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,KAAK,CAAC,KAAK,EAAE;QAC9B,OAAO,EAAM,CAAC;QACd,WAAW,EAAE,SAAS;QACtB,WAAW,EAAE,OAAO;QACpB,SAAS,EAAI,KAAK;KACnB,CAAC,CAAC,CAAA;AACL,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,GAAW,EAAE,IAAY,EAAE,QAAkB;IACvE,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,wDAAwD,CAAC,CAAC,CAAA;IAC9F,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAA;IAC3D,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAA;IAC5D,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IAC3E,OAAO,CAAC,GAAG,EAAE,CAAA;AACf,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getConfigs.d.ts","sourceRoot":"","sources":["../../src/lib/getConfigs.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEvD,wBAAgB,SAAS,IAAI,aAAa,CAOzC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import os from 'os';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
export function getConfig() {
|
|
5
|
+
const configPath = path.join(os.homedir(), '.crawlix', 'crawlix.config.json');
|
|
6
|
+
if (!fs.existsSync(configPath)) {
|
|
7
|
+
throw new Error("Config file not found. Run 'crawlix setup' to create one.");
|
|
8
|
+
}
|
|
9
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
10
|
+
return config;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=getConfigs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getConfigs.js","sourceRoot":"","sources":["../../src/lib/getConfigs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAA;AACnB,OAAO,EAAE,MAAM,IAAI,CAAA;AACnB,OAAO,IAAI,MAAM,MAAM,CAAA;AAGvB,MAAM,UAAU,SAAS;IACrB,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,UAAU,EAAE,qBAAqB,CAAC,CAAC;IAC9E,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,2DAA2D,CAAC,CAAC;IACjF,CAAC;IACD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC;IAChE,OAAO,MAAM,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ProviderConfig, LLMInput, LLMOutput } from "../types/index.js";
|
|
2
|
+
export declare class LLM {
|
|
3
|
+
private primaryConfig;
|
|
4
|
+
private fallbackConfig?;
|
|
5
|
+
private client;
|
|
6
|
+
private fallbackClient?;
|
|
7
|
+
private roundRobinProviders;
|
|
8
|
+
private roundRobinClients;
|
|
9
|
+
private roundRobinIndex;
|
|
10
|
+
private useRoundRobin;
|
|
11
|
+
constructor(primaryConfig: ProviderConfig, fallbackConfig?: ProviderConfig, roundRobin?: ProviderConfig[]);
|
|
12
|
+
complete(input: LLMInput): Promise<LLMOutput>;
|
|
13
|
+
private callProvider;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/llm/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,SAAS,EAAgB,MAAM,mBAAmB,CAAC;AAoC3F,qBAAa,GAAG;IACZ,OAAO,CAAC,aAAa,CAAiB;IACtC,OAAO,CAAC,cAAc,CAAC,CAA6B;IAEpD,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,cAAc,CAAC,CAAiC;IACxD,OAAO,CAAC,mBAAmB,CAAwB;IACnD,OAAO,CAAC,iBAAiB,CAA8B;IACvD,OAAO,CAAC,eAAe,CAAa;IACpC,OAAO,CAAC,aAAa,CAAkB;gBAE3B,aAAa,EAAE,cAAc,EAAE,cAAc,CAAC,EAAE,cAAc,EAAE,UAAU,CAAC,EAAE,cAAc,EAAE;IAcnG,QAAQ,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC,SAAS,CAAC;YAsDrC,YAAY;CA2D7B"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import Anthropic from "@anthropic-ai/sdk";
|
|
2
|
+
import OpenAI from "openai";
|
|
3
|
+
// Default baseURLs per provider
|
|
4
|
+
const BASE_URLS = {
|
|
5
|
+
groq: 'https://api.groq.com/openai/v1',
|
|
6
|
+
gemini: 'https://generativelanguage.googleapis.com/v1beta/openai',
|
|
7
|
+
openrouter: 'https://openrouter.ai/api/v1',
|
|
8
|
+
ollama: 'http://localhost:11434/v1',
|
|
9
|
+
cerebras: 'https://api.cerebras.ai/v1',
|
|
10
|
+
mistral: 'https://api.mistral.ai/v1',
|
|
11
|
+
};
|
|
12
|
+
const DEFAULT_MODELS = {
|
|
13
|
+
groq: 'llama-3.3-70b-versatile',
|
|
14
|
+
openai: 'gpt-4o-mini',
|
|
15
|
+
gemini: 'gemini-2.5-flash',
|
|
16
|
+
anthropic: 'claude-haiku-4-5-20251001',
|
|
17
|
+
openrouter: 'meta-llama/llama-3.3-70b-instruct:free',
|
|
18
|
+
ollama: 'llama3.2',
|
|
19
|
+
cerebras: 'gpt-oss-120b',
|
|
20
|
+
mistral: 'mistral-medium-3-5',
|
|
21
|
+
};
|
|
22
|
+
// Client factory
|
|
23
|
+
function createClient(config) {
|
|
24
|
+
if (config.provider === 'anthropic') {
|
|
25
|
+
return new Anthropic({ apiKey: config.apiKey });
|
|
26
|
+
}
|
|
27
|
+
return new OpenAI({
|
|
28
|
+
apiKey: config.apiKey ?? 'no-key-needed', // ollama doesn't need a key
|
|
29
|
+
baseURL: config.baseURL ?? BASE_URLS[config.provider],
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
// LLM
|
|
33
|
+
export class LLM {
|
|
34
|
+
primaryConfig;
|
|
35
|
+
fallbackConfig;
|
|
36
|
+
client;
|
|
37
|
+
fallbackClient;
|
|
38
|
+
roundRobinProviders = [];
|
|
39
|
+
roundRobinClients = [];
|
|
40
|
+
roundRobinIndex = 0;
|
|
41
|
+
useRoundRobin = false;
|
|
42
|
+
constructor(primaryConfig, fallbackConfig, roundRobin) {
|
|
43
|
+
this.primaryConfig = primaryConfig;
|
|
44
|
+
this.fallbackConfig = fallbackConfig;
|
|
45
|
+
if (roundRobin && roundRobin.length > 0) {
|
|
46
|
+
this.useRoundRobin = true;
|
|
47
|
+
this.roundRobinProviders = roundRobin;
|
|
48
|
+
this.roundRobinClients = roundRobin.map(c => createClient(c));
|
|
49
|
+
}
|
|
50
|
+
this.client = createClient(primaryConfig);
|
|
51
|
+
if (fallbackConfig) {
|
|
52
|
+
this.fallbackClient = createClient(fallbackConfig);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
async complete(input) {
|
|
56
|
+
if (this.useRoundRobin && this.roundRobinProviders.length > 0) {
|
|
57
|
+
// try current provider
|
|
58
|
+
const index = this.roundRobinIndex % this.roundRobinProviders.length;
|
|
59
|
+
const config = this.roundRobinProviders[index];
|
|
60
|
+
const client = this.roundRobinClients[index];
|
|
61
|
+
this.roundRobinIndex++;
|
|
62
|
+
try {
|
|
63
|
+
return await this.callProvider(client, config, input);
|
|
64
|
+
}
|
|
65
|
+
catch (err) {
|
|
66
|
+
const isRateLimit = err?.status === 429 ||
|
|
67
|
+
String(err).toLowerCase().includes('rate');
|
|
68
|
+
if (isRateLimit) {
|
|
69
|
+
// remove current provider from available pool temporarily
|
|
70
|
+
const available = this.roundRobinProviders
|
|
71
|
+
.map((p, i) => ({ p, i }))
|
|
72
|
+
.filter(({ i }) => i !== index);
|
|
73
|
+
if (available.length === 0)
|
|
74
|
+
throw err;
|
|
75
|
+
// pick randomly from remaining
|
|
76
|
+
const random = available[Math.floor(Math.random() * available.length)];
|
|
77
|
+
console.warn(`👾 ${config.provider} rate limited — randomly switching to ${this.roundRobinProviders[random.i].provider}`);
|
|
78
|
+
return await this.callProvider(this.roundRobinClients[random.i], this.roundRobinProviders[random.i], input);
|
|
79
|
+
}
|
|
80
|
+
throw err;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
try {
|
|
84
|
+
return await this.callProvider(this.client, this.primaryConfig, input);
|
|
85
|
+
}
|
|
86
|
+
catch (err) {
|
|
87
|
+
const isRateLimit = err?.status === 429 ||
|
|
88
|
+
String(err).toLowerCase().includes('rate');
|
|
89
|
+
if (isRateLimit && this.fallbackClient && this.fallbackConfig) {
|
|
90
|
+
console.warn(`👾 ${this.primaryConfig.provider} rate limited — falling back to ${this.fallbackConfig.provider}`);
|
|
91
|
+
return await this.callProvider(this.fallbackClient, this.fallbackConfig, input);
|
|
92
|
+
}
|
|
93
|
+
throw err;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
async callProvider(client, config, input) {
|
|
97
|
+
const model = config.model ?? DEFAULT_MODELS[config.provider];
|
|
98
|
+
// Anthropic
|
|
99
|
+
if (client instanceof Anthropic) {
|
|
100
|
+
const res = await client.messages.create({
|
|
101
|
+
model,
|
|
102
|
+
max_tokens: 2048,
|
|
103
|
+
system: [{
|
|
104
|
+
type: 'text',
|
|
105
|
+
text: input.system,
|
|
106
|
+
cache_control: { type: 'ephemeral' }
|
|
107
|
+
}],
|
|
108
|
+
messages: input.messages.map(m => ({
|
|
109
|
+
role: m.role,
|
|
110
|
+
content: m.content,
|
|
111
|
+
})),
|
|
112
|
+
});
|
|
113
|
+
const block = res.content[0];
|
|
114
|
+
if (!block || block.type !== 'text') {
|
|
115
|
+
throw new Error('Anthropic returned empty response');
|
|
116
|
+
}
|
|
117
|
+
return {
|
|
118
|
+
content: block.text,
|
|
119
|
+
provider: config.provider,
|
|
120
|
+
model,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
// OpenAI-compatible (Groq, Gemini, etc.)
|
|
124
|
+
const res = await client.chat.completions.create({
|
|
125
|
+
model,
|
|
126
|
+
temperature: 0.2,
|
|
127
|
+
max_tokens: 2048,
|
|
128
|
+
response_format: { type: 'json_object' },
|
|
129
|
+
messages: [
|
|
130
|
+
{ role: 'system', content: input.system },
|
|
131
|
+
...input.messages.map(m => ({
|
|
132
|
+
role: m.role,
|
|
133
|
+
content: m.content,
|
|
134
|
+
})),
|
|
135
|
+
],
|
|
136
|
+
});
|
|
137
|
+
const content = res.choices[0]?.message?.content;
|
|
138
|
+
if (!content)
|
|
139
|
+
throw new Error(`${config.provider} returned empty response`);
|
|
140
|
+
return {
|
|
141
|
+
content,
|
|
142
|
+
provider: config.provider,
|
|
143
|
+
model,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/llm/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { PersonaConfig } from '../types/index.js';
|
|
2
|
+
export declare const PERSONAS: Record<string, PersonaConfig>;
|
|
3
|
+
export declare function resolvePersona(input: PersonaConfig | string): PersonaConfig;
|
|
4
|
+
export declare const PERSONA_NAMES: Array<keyof typeof PERSONAS>;
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/personas/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAGtD,eAAO,MAAM,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAwFlD,CAAA;AAID,wBAAgB,cAAc,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,GAAG,aAAa,CAa3E;AAID,eAAO,MAAM,aAAa,EAA4B,KAAK,CAAC,MAAM,OAAO,QAAQ,CAAC,CAAA"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
// Persona Definitions
|
|
2
|
+
export const PERSONAS = {
|
|
3
|
+
'first-timer': {
|
|
4
|
+
name: 'First-Timer',
|
|
5
|
+
description: 'A new user encountering this product for the first time',
|
|
6
|
+
patience: 7,
|
|
7
|
+
aggression: 1,
|
|
8
|
+
readingBehavior: 'thorough',
|
|
9
|
+
systemPrompt: `You are a first-time user of this application. You have no prior knowledge
|
|
10
|
+
of how it works. You read everything carefully before clicking. You get lost easily
|
|
11
|
+
and click whatever looks most obvious. You notice when labels are confusing or when
|
|
12
|
+
the UI doesn't explain what it does. You try the happy path but may misread instructions.
|
|
13
|
+
You stop and re-read if something doesn't work. You sometimes click the wrong button
|
|
14
|
+
by accident. You never use keyboard shortcuts.`,
|
|
15
|
+
},
|
|
16
|
+
'impatient': {
|
|
17
|
+
name: 'Impatient',
|
|
18
|
+
description: 'A busy user who skims and clicks fast without reading',
|
|
19
|
+
patience: 3,
|
|
20
|
+
aggression: 4,
|
|
21
|
+
readingBehavior: 'skip',
|
|
22
|
+
systemPrompt: `You are a busy, impatient user. You skip reading instructions entirely.
|
|
23
|
+
You click the first thing that looks right. You submit forms immediately without
|
|
24
|
+
filling all fields. You abandon flows quickly if they take more than 2 steps.
|
|
25
|
+
You double-click buttons. You spam the submit button if nothing happens immediately.
|
|
26
|
+
You get frustrated by loading states and try to click through them. You ignore
|
|
27
|
+
confirmation dialogs and click the default option.`,
|
|
28
|
+
},
|
|
29
|
+
'power-user': {
|
|
30
|
+
name: 'Power User',
|
|
31
|
+
description: 'An experienced user who uses advanced features and shortcuts',
|
|
32
|
+
patience: 9,
|
|
33
|
+
aggression: 3,
|
|
34
|
+
readingBehavior: 'skim',
|
|
35
|
+
systemPrompt: `You are an experienced power user. You use keyboard shortcuts whenever
|
|
36
|
+
possible. You try edge cases deliberately: very long inputs, special characters,
|
|
37
|
+
emoji in text fields, extreme values in number fields. You try to navigate directly
|
|
38
|
+
to deep URLs. You open multiple flows. You look for admin or settings panels.
|
|
39
|
+
You test the absolute limits of the application. You notice missing features and
|
|
40
|
+
document them as findings. You move fast but methodically.`,
|
|
41
|
+
},
|
|
42
|
+
'adversarial': {
|
|
43
|
+
name: 'Adversarial',
|
|
44
|
+
description: 'A malicious user probing for security issues and broken flows',
|
|
45
|
+
patience: 8,
|
|
46
|
+
aggression: 10,
|
|
47
|
+
readingBehavior: 'skim',
|
|
48
|
+
systemPrompt: `You are a malicious user deliberately trying to break the application
|
|
49
|
+
and find security vulnerabilities. You inject script tags into input fields: <script>alert(1)</script>.
|
|
50
|
+
You try SQL injection: ' OR 1=1 --. You enter extremely long strings (500+ characters).
|
|
51
|
+
You try to access other users' data by modifying IDs in URLs. You submit forms
|
|
52
|
+
with missing required fields. You try to upload malicious file types. You look for
|
|
53
|
+
exposed API keys or tokens in the page source. You test every boundary condition.
|
|
54
|
+
You document every vulnerability as a critical finding.`,
|
|
55
|
+
},
|
|
56
|
+
'non-native': {
|
|
57
|
+
name: 'Non-Native Speaker',
|
|
58
|
+
description: 'A user who reads English as a second language and gets confused by jargon',
|
|
59
|
+
patience: 6,
|
|
60
|
+
aggression: 1,
|
|
61
|
+
readingBehavior: 'thorough',
|
|
62
|
+
systemPrompt: `You are a user for whom English is not your first language. You read
|
|
63
|
+
carefully but misunderstand idioms and technical jargon. You get confused by
|
|
64
|
+
abbreviations and acronyms that aren't explained. You misread instructions when
|
|
65
|
+
they use complex sentence structures. You sometimes click the wrong option because
|
|
66
|
+
labels use synonyms you don't recognize. You note when UI copy is unclear or uses
|
|
67
|
+
unexplained terminology. You are patient and try multiple times before giving up.`,
|
|
68
|
+
},
|
|
69
|
+
'slow-network': {
|
|
70
|
+
name: 'Slow Network',
|
|
71
|
+
description: 'A user on a throttled connection who encounters loading and timeout issues',
|
|
72
|
+
patience: 5,
|
|
73
|
+
aggression: 2,
|
|
74
|
+
readingBehavior: 'skim',
|
|
75
|
+
systemPrompt: `You are using this application on a very slow mobile network connection.
|
|
76
|
+
Pages take a long time to load. You notice when content loads without a visible
|
|
77
|
+
loading indicator. You record it as a warning whenever you're left staring at
|
|
78
|
+
a blank screen with no feedback. You sometimes click buttons multiple times because
|
|
79
|
+
you think the first click didn't register. You notice layout shifts when content
|
|
80
|
+
loads in. You look for missing skeleton screens and loading states. You document
|
|
81
|
+
every slow response as at least a warning-level finding.`,
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
// Resolver
|
|
85
|
+
// Accepts either a persona name string or a full PersonaConfig
|
|
86
|
+
export function resolvePersona(input) {
|
|
87
|
+
if (typeof input === 'string') {
|
|
88
|
+
const persona = PERSONAS[input.toLowerCase()];
|
|
89
|
+
if (!persona) {
|
|
90
|
+
const available = Object.keys(PERSONAS).join(', ');
|
|
91
|
+
throw new Error(`Unknown persona "${input}". Available: ${available}\n` +
|
|
92
|
+
`Or pass a full PersonaConfig object.`);
|
|
93
|
+
}
|
|
94
|
+
return persona;
|
|
95
|
+
}
|
|
96
|
+
return input;
|
|
97
|
+
}
|
|
98
|
+
// All persona names
|
|
99
|
+
export const PERSONA_NAMES = Object.keys(PERSONAS);
|
|
100
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/personas/index.ts"],"names":[],"mappings":"AAEA,uBAAuB;AACvB,MAAM,CAAC,MAAM,QAAQ,GAAkC;IAErD,aAAa,EAAE;QACb,IAAI,EAAa,aAAa;QAC9B,WAAW,EAAM,yDAAyD;QAC1E,QAAQ,EAAS,CAAC;QAClB,UAAU,EAAO,CAAC;QAClB,eAAe,EAAE,UAAU;QAC3B,YAAY,EAAE;;;;;+CAK6B;KAC5C;IAED,WAAW,EAAE;QACX,IAAI,EAAa,WAAW;QAC5B,WAAW,EAAM,uDAAuD;QACxE,QAAQ,EAAS,CAAC;QAClB,UAAU,EAAO,CAAC;QAClB,eAAe,EAAE,MAAM;QACvB,YAAY,EAAE;;;;;mDAKiC;KAChD;IAED,YAAY,EAAE;QACZ,IAAI,EAAa,YAAY;QAC7B,WAAW,EAAM,8DAA8D;QAC/E,QAAQ,EAAS,CAAC;QAClB,UAAU,EAAO,CAAC;QAClB,eAAe,EAAE,MAAM;QACvB,YAAY,EAAE;;;;;2DAKyC;KACxD;IAED,aAAa,EAAE;QACb,IAAI,EAAa,aAAa;QAC9B,WAAW,EAAM,+DAA+D;QAChF,QAAQ,EAAS,CAAC;QAClB,UAAU,EAAO,EAAE;QACnB,eAAe,EAAE,MAAM;QACvB,YAAY,EAAE;;;;;;wDAMsC;KACrD;IAED,YAAY,EAAE;QACZ,IAAI,EAAa,oBAAoB;QACrC,WAAW,EAAM,2EAA2E;QAC5F,QAAQ,EAAS,CAAC;QAClB,UAAU,EAAO,CAAC;QAClB,eAAe,EAAE,UAAU;QAC3B,YAAY,EAAE;;;;;kFAKgE;KAC/E;IAED,cAAc,EAAE;QACd,IAAI,EAAa,cAAc;QAC/B,WAAW,EAAM,4EAA4E;QAC7F,QAAQ,EAAS,CAAC;QAClB,UAAU,EAAO,CAAC;QAClB,eAAe,EAAE,MAAM;QACvB,YAAY,EAAE;;;;;;yDAMuC;KACtD;CAEF,CAAA;AAED,YAAY;AACZ,+DAA+D;AAC/D,MAAM,UAAU,cAAc,CAAC,KAA6B;IAC1D,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAA;QAC7C,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YAClD,MAAM,IAAI,KAAK,CACb,oBAAoB,KAAK,iBAAiB,SAAS,IAAI;gBACvD,sCAAsC,CACvC,CAAA;QACH,CAAC;QACD,OAAO,OAAO,CAAA;IAChB,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED,qBAAqB;AAErB,MAAM,CAAC,MAAM,aAAa,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAiC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/personas/loader.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAyCtD,wBAAsB,YAAY,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CA0B/E;AAED,wBAAsB,YAAY,kBAmBjC"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { PERSONAS } from './index.js';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
function isValidPersona(config) {
|
|
5
|
+
const c = config;
|
|
6
|
+
return (typeof c.name === 'string' &&
|
|
7
|
+
typeof c.description === 'string' &&
|
|
8
|
+
typeof c.systemPrompt === 'string' &&
|
|
9
|
+
typeof c.patience === 'number' &&
|
|
10
|
+
typeof c.aggression === 'number' &&
|
|
11
|
+
['thorough', 'skim', 'skip'].includes(c.readingBehavior));
|
|
12
|
+
}
|
|
13
|
+
async function loadCustomPersonas() {
|
|
14
|
+
const dir = path.resolve(process.cwd(), '.crawlix/agents/');
|
|
15
|
+
if (!fs.existsSync(dir))
|
|
16
|
+
return [];
|
|
17
|
+
const result = [];
|
|
18
|
+
const files = fs.readdirSync(dir).filter(f => f.endsWith('.json'));
|
|
19
|
+
for (const file of files) {
|
|
20
|
+
try {
|
|
21
|
+
const content = fs.readFileSync(path.join(dir, file), 'utf-8');
|
|
22
|
+
const config = JSON.parse(content);
|
|
23
|
+
if (isValidPersona(config)) {
|
|
24
|
+
result.push(config);
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
console.warn(`👾 skipping ${file} — missing or invalid fields`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
console.warn(`👾 skipping ${file} — invalid JSON`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return result;
|
|
35
|
+
}
|
|
36
|
+
export async function loadPersonas(agentFlag) {
|
|
37
|
+
const builtIns = Object.values(PERSONAS);
|
|
38
|
+
// if --agent is specified, only load those
|
|
39
|
+
if (agentFlag) {
|
|
40
|
+
const requested = agentFlag.split(',').map(a => a.trim().toLowerCase());
|
|
41
|
+
const customs = await loadCustomPersonas();
|
|
42
|
+
const allPersonas = [
|
|
43
|
+
...Object.values(PERSONAS),
|
|
44
|
+
...customs
|
|
45
|
+
];
|
|
46
|
+
return requested.map(name => {
|
|
47
|
+
const found = allPersonas.find(p => p.name.toLowerCase() === name);
|
|
48
|
+
if (!found)
|
|
49
|
+
throw new Error(`Unknown agent "${name}". Run 'crawlix agents --list' to see available agents.`);
|
|
50
|
+
return found;
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
const customs = await loadCustomPersonas();
|
|
54
|
+
return [...builtIns, ...customs];
|
|
55
|
+
}
|
|
56
|
+
export async function listPersonas() {
|
|
57
|
+
const builtIns = Object.values(PERSONAS);
|
|
58
|
+
const customs = await loadCustomPersonas();
|
|
59
|
+
console.log('\n 👾 available agents\n');
|
|
60
|
+
console.log(' built-in:');
|
|
61
|
+
builtIns.forEach(p => {
|
|
62
|
+
console.log(` ${p.name.padEnd(16)} ${p.description}`);
|
|
63
|
+
});
|
|
64
|
+
if (customs.length > 0) {
|
|
65
|
+
console.log('\n custom:');
|
|
66
|
+
customs.forEach(p => {
|
|
67
|
+
console.log(` ${p.name.padEnd(16)} ${p.description}`);
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
console.log();
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/personas/loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
export type ActionType = 'open' | 'click' | 'type' | 'scroll' | 'select' | 'hover' | 'press' | 'wait' | 'done' | 'stuck';
|
|
2
|
+
export interface Action {
|
|
3
|
+
type: ActionType;
|
|
4
|
+
target?: string;
|
|
5
|
+
value?: string;
|
|
6
|
+
reasoning: string;
|
|
7
|
+
finding?: Finding;
|
|
8
|
+
}
|
|
9
|
+
export interface ActionResult {
|
|
10
|
+
success: boolean;
|
|
11
|
+
error?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface Finding {
|
|
14
|
+
severity: 'critical' | 'warning' | 'info';
|
|
15
|
+
description: string;
|
|
16
|
+
element?: string | undefined;
|
|
17
|
+
screenshot?: string;
|
|
18
|
+
step?: number;
|
|
19
|
+
}
|
|
20
|
+
export interface PageState {
|
|
21
|
+
url?: string;
|
|
22
|
+
title?: string | undefined;
|
|
23
|
+
tree: string;
|
|
24
|
+
timestamp: number;
|
|
25
|
+
}
|
|
26
|
+
export interface HistoryEntry {
|
|
27
|
+
step: number;
|
|
28
|
+
pageState: PageState;
|
|
29
|
+
action: Action;
|
|
30
|
+
}
|
|
31
|
+
export interface PersonaConfig {
|
|
32
|
+
name: string;
|
|
33
|
+
description: string;
|
|
34
|
+
systemPrompt: string;
|
|
35
|
+
patience: number;
|
|
36
|
+
aggression: number;
|
|
37
|
+
readingBehavior: 'thorough' | 'skim' | 'skip';
|
|
38
|
+
maxSteps?: number;
|
|
39
|
+
}
|
|
40
|
+
export type ProviderName = 'groq' | 'openai' | 'anthropic' | 'gemini' | 'openrouter' | 'ollama' | 'cerebras' | 'mistral';
|
|
41
|
+
export interface ProviderConfig {
|
|
42
|
+
provider: ProviderName;
|
|
43
|
+
apiKey?: string;
|
|
44
|
+
model?: string;
|
|
45
|
+
baseURL?: string;
|
|
46
|
+
}
|
|
47
|
+
export interface LLMInput {
|
|
48
|
+
system: string;
|
|
49
|
+
messages: LLMMessage[];
|
|
50
|
+
}
|
|
51
|
+
export interface LLMMessage {
|
|
52
|
+
role: 'user' | 'assistant';
|
|
53
|
+
content: string;
|
|
54
|
+
}
|
|
55
|
+
export interface LLMOutput {
|
|
56
|
+
content: string;
|
|
57
|
+
provider: ProviderName;
|
|
58
|
+
model: string;
|
|
59
|
+
}
|
|
60
|
+
export interface CrawlixConfig {
|
|
61
|
+
primary: ProviderConfig;
|
|
62
|
+
fallback?: ProviderConfig;
|
|
63
|
+
roundRobin?: ProviderConfig[];
|
|
64
|
+
}
|
|
65
|
+
export interface RunResult {
|
|
66
|
+
persona: string;
|
|
67
|
+
url: string;
|
|
68
|
+
goal: string;
|
|
69
|
+
steps: number;
|
|
70
|
+
findings: Finding[];
|
|
71
|
+
goalReached: boolean;
|
|
72
|
+
stuck: boolean;
|
|
73
|
+
duration: number;
|
|
74
|
+
history: HistoryEntry[];
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,UAAU,GAAK,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,GAAG,QAAQ,GAAG,OAAO,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAA;AAE1H,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,UAAU,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAGD,MAAM,WAAW,OAAO;IACtB,QAAQ,EAAE,UAAU,GAAG,SAAS,GAAG,MAAM,CAAA;IACzC,WAAW,EAAE,MAAM,CAAA;IACnB,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAGD,MAAM,WAAW,SAAS;IACxB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;CAClB;AAGD,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,SAAS,CAAA;IACpB,MAAM,EAAE,MAAM,CAAA;CACf;AAGD,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,YAAY,EAAE,MAAM,CAAA;IACpB,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;IAClB,eAAe,EAAE,UAAU,GAAG,MAAM,GAAG,MAAM,CAAA;IAC7C,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAGD,MAAM,MAAM,YAAY,GAAK,MAAM,GAAG,QAAQ,GAAG,WAAW,GAAG,QAAQ,GAAG,YAAY,GAAG,QAAQ,GAAG,UAAU,GAAG,SAAS,CAAC;AAE3H,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,YAAY,CAAA;IACtB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,UAAU,EAAE,CAAA;CACvB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,GAAG,WAAW,CAAA;IAC1B,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,YAAY,CAAA;IACtB,KAAK,EAAE,MAAM,CAAA;CACd;AAGD,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,cAAc,CAAA;IACvB,QAAQ,CAAC,EAAE,cAAc,CAAA;IACzB,UAAU,CAAC,EAAE,cAAc,EAAE,CAAA;CAC9B;AAGD,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAA;IACf,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,OAAO,EAAE,CAAA;IACnB,WAAW,EAAE,OAAO,CAAA;IACpB,KAAK,EAAE,OAAO,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,YAAY,EAAE,CAAA;CACxB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,mBAAmB"}
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "crawlix",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "AI testers that think like users. Your users will break it anyway. Crawlix finds it first.",
|
|
5
|
+
"main": "./dist/cli/index.js",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": "./dist/cli/index.js"
|
|
8
|
+
},
|
|
9
|
+
"keywords": [
|
|
10
|
+
"ai",
|
|
11
|
+
"testing",
|
|
12
|
+
"qa",
|
|
13
|
+
"automation",
|
|
14
|
+
"playwright",
|
|
15
|
+
"agents",
|
|
16
|
+
"llm"
|
|
17
|
+
],
|
|
18
|
+
"author": "Muhammad Taqi",
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"devEngines": {
|
|
21
|
+
"packageManager": {
|
|
22
|
+
"name": "pnpm",
|
|
23
|
+
"version": "^11.2.2",
|
|
24
|
+
"onFail": "download"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"type": "module",
|
|
28
|
+
"bin": {
|
|
29
|
+
"crawlix": "./dist/cli/index.js"
|
|
30
|
+
},
|
|
31
|
+
"files": [
|
|
32
|
+
"dist",
|
|
33
|
+
"README.md",
|
|
34
|
+
"LICENSE"
|
|
35
|
+
],
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"@anthropic-ai/sdk": "^0.98.0",
|
|
38
|
+
"@inquirer/prompts": "^8.5.0",
|
|
39
|
+
"boxen": "^8.0.1",
|
|
40
|
+
"chalk": "^5.6.2",
|
|
41
|
+
"commander": "^14.0.3",
|
|
42
|
+
"openai": "^6.39.0",
|
|
43
|
+
"ora": "^9.4.0",
|
|
44
|
+
"playwright": "^1.60.0"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@types/node": "^25.9.1",
|
|
48
|
+
"tsx": "^4.22.3",
|
|
49
|
+
"typescript": "^6.0.3"
|
|
50
|
+
},
|
|
51
|
+
"scripts": {
|
|
52
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
53
|
+
"dev": "tsx src/cli/index.ts",
|
|
54
|
+
"build": "tsc",
|
|
55
|
+
"typecheck": "tsc --noEmit"
|
|
56
|
+
}
|
|
57
|
+
}
|