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.
Files changed (75) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +187 -0
  3. package/dist/adapters/base.d.ts +8 -0
  4. package/dist/adapters/base.d.ts.map +1 -0
  5. package/dist/adapters/base.js +2 -0
  6. package/dist/adapters/base.js.map +1 -0
  7. package/dist/adapters/web.d.ts +14 -0
  8. package/dist/adapters/web.d.ts.map +1 -0
  9. package/dist/adapters/web.js +120 -0
  10. package/dist/adapters/web.js.map +1 -0
  11. package/dist/cli/commands/agents.d.ts +3 -0
  12. package/dist/cli/commands/agents.d.ts.map +1 -0
  13. package/dist/cli/commands/agents.js +9 -0
  14. package/dist/cli/commands/agents.js.map +1 -0
  15. package/dist/cli/commands/run.d.ts +3 -0
  16. package/dist/cli/commands/run.d.ts.map +1 -0
  17. package/dist/cli/commands/run.js +49 -0
  18. package/dist/cli/commands/run.js.map +1 -0
  19. package/dist/cli/commands/setup.d.ts +3 -0
  20. package/dist/cli/commands/setup.d.ts.map +1 -0
  21. package/dist/cli/commands/setup.js +93 -0
  22. package/dist/cli/commands/setup.js.map +1 -0
  23. package/dist/cli/index.d.ts +2 -0
  24. package/dist/cli/index.d.ts.map +1 -0
  25. package/dist/cli/index.js +17 -0
  26. package/dist/cli/index.js.map +1 -0
  27. package/dist/core/director.d.ts +14 -0
  28. package/dist/core/director.d.ts.map +1 -0
  29. package/dist/core/director.js +112 -0
  30. package/dist/core/director.js.map +1 -0
  31. package/dist/core/extractor.d.ts +6 -0
  32. package/dist/core/extractor.d.ts.map +1 -0
  33. package/dist/core/extractor.js +42 -0
  34. package/dist/core/extractor.js.map +1 -0
  35. package/dist/core/orchestrator.d.ts +27 -0
  36. package/dist/core/orchestrator.d.ts.map +1 -0
  37. package/dist/core/orchestrator.js +62 -0
  38. package/dist/core/orchestrator.js.map +1 -0
  39. package/dist/core/reporter.d.ts +8 -0
  40. package/dist/core/reporter.d.ts.map +1 -0
  41. package/dist/core/reporter.js +132 -0
  42. package/dist/core/reporter.js.map +1 -0
  43. package/dist/core/runner.d.ts +13 -0
  44. package/dist/core/runner.d.ts.map +1 -0
  45. package/dist/core/runner.js +61 -0
  46. package/dist/core/runner.js.map +1 -0
  47. package/dist/lib/browser.d.ts +4 -0
  48. package/dist/lib/browser.d.ts.map +1 -0
  49. package/dist/lib/browser.js +24 -0
  50. package/dist/lib/browser.js.map +1 -0
  51. package/dist/lib/display.d.ts +7 -0
  52. package/dist/lib/display.d.ts.map +1 -0
  53. package/dist/lib/display.js +80 -0
  54. package/dist/lib/display.js.map +1 -0
  55. package/dist/lib/getConfigs.d.ts +3 -0
  56. package/dist/lib/getConfigs.d.ts.map +1 -0
  57. package/dist/lib/getConfigs.js +12 -0
  58. package/dist/lib/getConfigs.js.map +1 -0
  59. package/dist/llm/index.d.ts +15 -0
  60. package/dist/llm/index.d.ts.map +1 -0
  61. package/dist/llm/index.js +147 -0
  62. package/dist/llm/index.js.map +1 -0
  63. package/dist/personas/index.d.ts +5 -0
  64. package/dist/personas/index.d.ts.map +1 -0
  65. package/dist/personas/index.js +100 -0
  66. package/dist/personas/index.js.map +1 -0
  67. package/dist/personas/loader.d.ts +4 -0
  68. package/dist/personas/loader.d.ts.map +1 -0
  69. package/dist/personas/loader.js +72 -0
  70. package/dist/personas/loader.js.map +1 -0
  71. package/dist/types/index.d.ts +76 -0
  72. package/dist/types/index.d.ts.map +1 -0
  73. package/dist/types/index.js +3 -0
  74. package/dist/types/index.js.map +1 -0
  75. package/package.json +57 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 M.Taqi
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,187 @@
1
+ # 👾 Crawlix
2
+
3
+ > Claw through bugs before your users do.
4
+
5
+ Crawlix is an open-source autonomous QA agent that spawns AI-powered user personas and unleashes them on your product. Each persona navigates independently, makes real decisions, hits dead ends, and finds bugs - without you writing a single test script.
6
+
7
+ ---
8
+
9
+ ## How it works
10
+
11
+ Crawlix spawns multiple AI agents simultaneously. Each one opens your app in a real browser, reads the UI, and navigates toward the goal exactly as that type of user would behave - including their mistakes, impatience, and confusion. When they find something broken, confusing, or unexpected - they report it.
12
+
13
+ ```
14
+ 👾 Crawlix - Claw through bugs before your users do.
15
+
16
+ target → http://localhost:3000/
17
+ goal → Check the landing page is everything working fine
18
+ agents → First-Timer, Impatient, Power User, Adversarial, Non-Native Speaker, Slow Network
19
+
20
+ ✓ First-Timer 2 critical · 3 warnings 18 steps · 12.3s
21
+ ~ Impatient 1 warning 6 steps · 4.1s
22
+ ✓ Power User no findings 22 steps · 15.7s
23
+ ✗ Adversarial 3 critical 14 steps · 9.2s
24
+ ~ Non-Native 106 warnings · 1 info 10 steps · 27.5s
25
+ ~ Slow Network no findings 4 steps · 27.7s
26
+
27
+ ╭──────────────────────────────────────╮
28
+ │ 👾 Crawlix - run complete │
29
+ │ │
30
+ │ 1 critical 106 warnings 1 info │
31
+ │ │
32
+ │ 0 passed 0 stuck 6 incomplete │
33
+ │ │
34
+ │ total time → 539.8s │
35
+ ╰──────────────────────────────────────╯
36
+ ```
37
+
38
+ No test scripts. No selectors. No maintenance.
39
+
40
+ ---
41
+
42
+ ## Install
43
+
44
+ ```bash
45
+ npm install -g crawlix
46
+ ```
47
+
48
+ ---
49
+
50
+ ## Setup
51
+
52
+ Run once. Crawlix asks for your LLM provider and API key - remembers it forever.
53
+
54
+ ```bash
55
+ crawlix setup
56
+ ```
57
+
58
+ Supported providers:
59
+
60
+ - Groq
61
+ - Gemini
62
+ - Cerebras
63
+ - Mistral
64
+ - OpenRouter
65
+ - Ollama
66
+ - OpenAI
67
+ - Anthropic
68
+
69
+ Config is saved to `~/.crawlix/crawlix.config.json`.
70
+
71
+ ---
72
+
73
+ ## Usage
74
+
75
+ ```bash
76
+ # run all agents against your app
77
+ crawlix run --url https://myapp.com --goal "complete the signup flow"
78
+
79
+ # run specific agents only
80
+ crawlix run --url https://myapp.com --goal "login" --agent first-timer,adversarial
81
+
82
+ # run headed - watch agents navigate in real browser
83
+ crawlix run --url https://myapp.com --goal "checkout" --headed
84
+
85
+ # control steps and concurrency
86
+ crawlix run --url https://myapp.com --goal "find pricing" --steps 15 --concurrency 1
87
+
88
+ # list all available agents
89
+ crawlix agents
90
+ ```
91
+
92
+ ---
93
+
94
+ ## Built-in agents
95
+
96
+ | Agent | Behavior |
97
+ |---|---|
98
+ | `first-timer` | Never seen this app. Reads nothing. Clicks whatever looks obvious. |
99
+ | `impatient` | Skips everything. Rage-clicks. Abandons if stuck for more than 2 steps. |
100
+ | `power-user` | Tries every edge case, advanced flow, and keyboard shortcut. |
101
+ | `adversarial` | SQL injection, XSS attempts, wrong inputs, broken sequences. |
102
+ | `non-native` | Misreads labels, confused by idioms. Tests copy clarity ruthlessly. |
103
+ | `slow-network` | Throttled connection. Finds missing loading states and timeouts. |
104
+
105
+ ---
106
+
107
+ ## Custom agents
108
+
109
+ Drop a JSON file into `.crawlix/agents/` in your project root:
110
+
111
+ ```json
112
+ {
113
+ "name": "doctor",
114
+ "description": "Medical professional, time-pressured, technically literate",
115
+ "systemPrompt": "You are a busy doctor with 2 minutes between patients. You know what you want, you don't read instructions, and you get frustrated fast if the UI isn't obvious.",
116
+ "patience": 4,
117
+ "aggression": 3,
118
+ "readingBehavior": "skim"
119
+ }
120
+ ```
121
+
122
+ Crawlix picks it up automatically on the next run. No code, no imports, no build step.
123
+
124
+ Run a specific custom agent:
125
+
126
+ ```bash
127
+ crawlix run --url https://myapp.com --goal "book an appointment" --agent doctor
128
+ ```
129
+
130
+ ---
131
+
132
+ ## Findings
133
+
134
+ Crawlix reports three severity levels:
135
+
136
+ | Severity | Meaning |
137
+ |---|---|
138
+ | `critical` | Broken element, crash, security issue, complete blocker |
139
+ | `warning` | Confusing flow, missing feedback, slow response, unclear copy |
140
+ | `info` | Minor friction, accessibility gap, copy improvement |
141
+
142
+ ---
143
+
144
+ ## Why no test scripts?
145
+
146
+ Traditional QA tools require you to write and maintain selectors, flows, and assertions. They break when your UI changes. They only test paths you already thought of.
147
+
148
+ Crawlix doesn't know your app. That's the point. It finds the paths you didn't think of - the ones your real users will find on their own.
149
+
150
+ ---
151
+
152
+ ## Contributing
153
+
154
+ Contributions are welcome - bug fixes, new agents, adapter improvements, or anything that makes it better.
155
+
156
+ ### Getting started
157
+
158
+ ```bash
159
+ git clone https://github.com/m-taqii/crawlix
160
+ cd crawlix
161
+ pnpm install
162
+ pnpm tsx src/cli/index.ts run --url https://example.com --goal "find the more information link"
163
+ ```
164
+
165
+ ### Ways to contribute
166
+
167
+ - **Add a built-in agent** - add a persona to `src/personas/index.ts` and open a PR
168
+ - **Fix a bug** - open an issue first, then a PR with the fix
169
+ - **Improve element resolution** - `src/adapters/web.ts` `resolve()` method always needs work
170
+ - **Add an adapter** - API testing, mobile, desktop - see `src/adapters/base.ts` for the interface
171
+ - **Improve the report** - `src/core/reporter.ts` - better prompts, better structure
172
+
173
+ ### Before opening a PR
174
+
175
+ - Run `pnpm exec tsc --noEmit` - must be clean
176
+ - Test against a real URL
177
+ - Keep it focused - one thing per PR
178
+
179
+ ### Found a bug?
180
+
181
+ Open an issue with the URL you were testing, the goal you gave, and the error output.
182
+
183
+ ---
184
+
185
+ ## License
186
+
187
+ MIT - see [LICENSE](LICENSE)
@@ -0,0 +1,8 @@
1
+ import type { Action, ActionResult, PageState } from "../types/index.js";
2
+ export interface Adapter {
3
+ open(url: string): Promise<void>;
4
+ getState(): Promise<PageState>;
5
+ execute(action: Action): Promise<ActionResult>;
6
+ close(): Promise<void>;
7
+ }
8
+ //# sourceMappingURL=base.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../src/adapters/base.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAA;AAExE,MAAM,WAAW,OAAO;IACtB,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAChC,QAAQ,IAAI,OAAO,CAAC,SAAS,CAAC,CAAA;IAC9B,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAAA;IAC9C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CACvB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=base.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.js","sourceRoot":"","sources":["../../src/adapters/base.ts"],"names":[],"mappings":""}
@@ -0,0 +1,14 @@
1
+ import type { Adapter } from "./base.js";
2
+ import type { ActionResult, Action, PageState } from "../types/index.js";
3
+ import type { Page } from "playwright";
4
+ export declare class WebAdapter implements Adapter {
5
+ private page;
6
+ private extractor;
7
+ constructor(page: Page);
8
+ open(url: string): Promise<void>;
9
+ getState(): Promise<PageState>;
10
+ private resolve;
11
+ execute(action: Action): Promise<ActionResult>;
12
+ close(): Promise<void>;
13
+ }
14
+ //# sourceMappingURL=web.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web.d.ts","sourceRoot":"","sources":["../../src/adapters/web.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACxC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAA;AACxE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AAEtC,qBAAa,UAAW,YAAW,OAAO;IACtC,OAAO,CAAC,IAAI,CAAM;IAClB,OAAO,CAAC,SAAS,CAAW;gBAEhB,IAAI,EAAE,IAAI;IAKhB,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIhC,QAAQ,IAAI,OAAO,CAAC,SAAS,CAAC;YAItB,OAAO;IA8Bf,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAiF9C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAG/B"}
@@ -0,0 +1,120 @@
1
+ import { Extractor } from "../core/extractor.js";
2
+ export class WebAdapter {
3
+ page;
4
+ extractor;
5
+ constructor(page) {
6
+ this.page = page;
7
+ this.extractor = new Extractor();
8
+ }
9
+ async open(url) {
10
+ await this.page.goto(url, { waitUntil: 'domcontentloaded' });
11
+ }
12
+ async getState() {
13
+ return this.extractor.extract(this.page);
14
+ }
15
+ async resolve(target) {
16
+ const cleaned = target
17
+ .replace(/^\w+:\s*/, '') // remove 'link: ' or 'button: ' prefix
18
+ .replace(/^"|"$/g, '') // remove surrounding quotes
19
+ .trim();
20
+ const strategies = [
21
+ () => this.page.getByRole('button', { name: cleaned, exact: false }).first(),
22
+ () => this.page.getByRole('link', { name: cleaned, exact: false }).first(),
23
+ () => this.page.getByRole('textbox', { name: cleaned, exact: false }).first(),
24
+ () => this.page.getByRole('combobox', { name: cleaned, exact: false }).first(),
25
+ () => this.page.getByRole('checkbox', { name: cleaned, exact: false }).first(),
26
+ () => this.page.getByLabel(cleaned, { exact: false }).first(),
27
+ () => this.page.getByPlaceholder(cleaned, { exact: false }).first(),
28
+ () => this.page.getByText(cleaned, { exact: false }).first(),
29
+ ];
30
+ for (const strategy of strategies) {
31
+ try {
32
+ const el = strategy();
33
+ if (await el.isVisible().catch(() => false)) {
34
+ return el;
35
+ }
36
+ }
37
+ catch {
38
+ }
39
+ }
40
+ return null;
41
+ }
42
+ async execute(action) {
43
+ try {
44
+ switch (action.type) {
45
+ case 'click': {
46
+ // find element by description, click it
47
+ const el = await this.resolve(action.target);
48
+ if (!el)
49
+ return { success: false, error: `Element not found: "${action.target}"` };
50
+ await el.click({ timeout: 5000 });
51
+ // wait for page to settle after click
52
+ await this.page.waitForLoadState('domcontentloaded', { timeout: 5000 }).catch(() => { });
53
+ break;
54
+ }
55
+ case 'type': {
56
+ // find input, fill it with value
57
+ const el = await this.resolve(action.target);
58
+ if (!el)
59
+ return { success: false, error: `Element not found: "${action.target}"` };
60
+ await el.fill(action.value ?? '');
61
+ break;
62
+ }
63
+ case 'scroll': {
64
+ // scroll direction comes in action.value: up/down/left/right
65
+ const directions = {
66
+ up: [0, -500],
67
+ down: [0, 500],
68
+ left: [-500, 0],
69
+ right: [500, 0],
70
+ };
71
+ const [x, y] = directions[action.value ?? 'down'] ?? [0, 500];
72
+ await this.page.mouse.wheel(x, y);
73
+ break;
74
+ }
75
+ case 'select': {
76
+ // dropdown selection
77
+ const el = await this.resolve(action.target);
78
+ if (!el)
79
+ return { success: false, error: `Element not found: "${action.target}"` };
80
+ await el.selectOption(action.value ?? '');
81
+ break;
82
+ }
83
+ case 'hover': {
84
+ const el = await this.resolve(action.target);
85
+ if (!el)
86
+ return { success: false, error: `Element not found: "${action.target}"` };
87
+ await el.hover();
88
+ break;
89
+ }
90
+ case 'press': {
91
+ // keyboard key press - Enter, Tab, Escape, ArrowDown etc
92
+ await this.page.keyboard.press(action.value ?? 'Enter');
93
+ break;
94
+ }
95
+ case 'open': {
96
+ await this.page.goto(action.value ?? '', { waitUntil: 'domcontentloaded', timeout: 15000 });
97
+ break;
98
+ }
99
+ case 'wait': {
100
+ await this.page.waitForLoadState('networkidle', { timeout: 10000 }).catch(() => { });
101
+ break;
102
+ }
103
+ case 'done':
104
+ case 'stuck':
105
+ break;
106
+ }
107
+ return { success: true };
108
+ }
109
+ catch (err) {
110
+ return {
111
+ success: false,
112
+ error: err instanceof Error ? err.message : String(err)
113
+ };
114
+ }
115
+ }
116
+ async close() {
117
+ await this.page.close();
118
+ }
119
+ }
120
+ //# sourceMappingURL=web.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/adapters/web.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare const agentsCommand: Command;
3
+ //# sourceMappingURL=agents.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/agents.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAGnC,eAAO,MAAM,aAAa,SAKpB,CAAA"}
@@ -0,0 +1,9 @@
1
+ import { Command } from 'commander';
2
+ import { listPersonas } from '../../personas/loader.js';
3
+ export const agentsCommand = new Command('agents')
4
+ .description('List available agents')
5
+ .option('--list', 'Show all available agents')
6
+ .action(async () => {
7
+ await listPersonas();
8
+ });
9
+ //# sourceMappingURL=agents.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agents.js","sourceRoot":"","sources":["../../../src/cli/commands/agents.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAEvD,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC;KAC7C,WAAW,CAAC,uBAAuB,CAAC;KACpC,MAAM,CAAC,QAAQ,EAAE,2BAA2B,CAAC;KAC7C,MAAM,CAAC,KAAK,IAAI,EAAE;IACf,MAAM,YAAY,EAAE,CAAA;AACxB,CAAC,CAAC,CAAA"}
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare const runCommand: Command;
3
+ //# sourceMappingURL=run.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/run.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAWpC,eAAO,MAAM,UAAU,SA2CjB,CAAA"}
@@ -0,0 +1,49 @@
1
+ import { Command } from 'commander';
2
+ import ora from 'ora';
3
+ import chalk from 'chalk';
4
+ import { Orchestrator } from '../../core/orchestrator.js';
5
+ import { LLM } from '../../llm/index.js';
6
+ import { loadPersonas } from '../../personas/loader.js';
7
+ import { getConfig } from '../../lib/getConfigs.js';
8
+ import { agentDone, agentStarted, printFinding, printHeader, printSummary } from '../../lib/display.js';
9
+ import { generateReport, saveReport } from "../../core/reporter.js";
10
+ export const runCommand = new Command('run')
11
+ .description('Run AI agents against your app')
12
+ .requiredOption('--url <url>', 'URL to test')
13
+ .requiredOption('--goal <goal>', 'What to achieve')
14
+ .option('--agent <agents>', 'Specific agent(s) to run, comma separated')
15
+ .option('--steps <number>', 'Max steps per agent', '25')
16
+ .option('--concurrency <number>', 'Agents running in parallel', '2')
17
+ .option('--headed', 'Run browser in headed mode')
18
+ .option('--round-robin', 'Spread load across multiple providers to avoid rate limiting')
19
+ .action(async (options) => {
20
+ const config = getConfig();
21
+ if (options.roundRobin && !config.roundRobin?.length) {
22
+ console.warn(chalk.yellow(' ⚠ --round-robin flag used but no round robin providers configured. Run crawlix setup to add them.'));
23
+ }
24
+ const llm = new LLM(config.primary, config.fallback, options.roundRobin ? config.roundRobin : undefined);
25
+ const { url, goal, agent, steps, concurrency, headed } = options;
26
+ const personas = await loadPersonas(agent);
27
+ printHeader(url, goal, personas.map(p => p.name));
28
+ const orchestrator = new Orchestrator({
29
+ url,
30
+ goal,
31
+ llm,
32
+ personas,
33
+ maxSteps: parseInt(steps),
34
+ concurrency: parseInt(concurrency),
35
+ headless: !headed,
36
+ onAgentStart: (name) => agentStarted(name),
37
+ onAgentDone: (result) => {
38
+ agentDone(result);
39
+ result.findings.forEach(f => printFinding(f, result.persona));
40
+ }
41
+ });
42
+ const results = await orchestrator.run();
43
+ printSummary(results);
44
+ const reportSpinner = ora({ text: chalk.gray('generating report...'), spinner: 'dots' }).start();
45
+ const { title, report } = await generateReport(results, url, goal, llm);
46
+ const filepath = saveReport(title, report);
47
+ reportSpinner.stopAndPersist({ symbol: '📋', text: chalk.gray('report saved → ') + chalk.white(filepath) });
48
+ });
49
+ //# sourceMappingURL=run.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.js","sourceRoot":"","sources":["../../../src/cli/commands/run.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare const setupCommand: Command;
3
+ //# sourceMappingURL=setup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/setup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AA0DnC,eAAO,MAAM,YAAY,SAoDnB,CAAA"}
@@ -0,0 +1,93 @@
1
+ import { Command } from 'commander';
2
+ import { select, input, password, confirm } from '@inquirer/prompts';
3
+ import fs from 'fs';
4
+ import os from 'os';
5
+ import path from 'path';
6
+ const DEFAULT_MODELS = {
7
+ groq: 'llama-3.3-70b-versatile',
8
+ openai: 'gpt-4o-mini',
9
+ gemini: 'gemini-2.5-flash',
10
+ anthropic: 'claude-haiku-4-5-20251001',
11
+ openrouter: 'meta-llama/llama-3.3-70b-instruct:free',
12
+ ollama: 'llama3.2',
13
+ cerebras: 'gpt-oss-120b',
14
+ mistral: 'mistral-medium-3-5',
15
+ };
16
+ async function setupProvider(label) {
17
+ const provider = await select({
18
+ message: `Select ${label} provider`,
19
+ choices: [
20
+ { name: 'Groq', value: 'groq' },
21
+ { name: 'Gemini', value: 'gemini' },
22
+ { name: 'Cerebras', value: 'cerebras' },
23
+ { name: 'Mistral', value: 'mistral' },
24
+ { name: 'OpenRouter', value: 'openrouter' },
25
+ { name: 'Ollama', value: 'ollama' },
26
+ { name: 'OpenAI', value: 'openai' },
27
+ { name: 'Anthropic', value: 'anthropic' },
28
+ ]
29
+ });
30
+ let apiKey;
31
+ if (provider === 'ollama') {
32
+ console.log(' ✓ Ollama runs locally — no API key needed');
33
+ }
34
+ else {
35
+ apiKey = await password({
36
+ message: `Enter your ${provider} API key:`,
37
+ validate: v => v.trim().length > 0 ? true : 'API key cannot be empty'
38
+ });
39
+ }
40
+ const defaultModel = DEFAULT_MODELS[provider];
41
+ const customModel = await input({
42
+ message: `Model to use (press enter for default: ${defaultModel}):`,
43
+ });
44
+ const config = {
45
+ provider,
46
+ ...(apiKey && { apiKey }),
47
+ ...(customModel.trim().length > 0 && { model: customModel.trim() }),
48
+ };
49
+ return config;
50
+ }
51
+ export const setupCommand = new Command('setup')
52
+ .description('Configure your LLM provider')
53
+ .action(async () => {
54
+ console.log('\n 👾 crawlix setup\n');
55
+ const primary = await setupProvider('primary');
56
+ const wantsFallback = await confirm({
57
+ message: 'Add a fallback provider?',
58
+ default: false,
59
+ });
60
+ let fallback;
61
+ if (wantsFallback) {
62
+ fallback = await setupProvider('fallback');
63
+ }
64
+ // after fallback setup
65
+ const wantsRoundRobin = await confirm({
66
+ message: 'Add round robin providers to spread load across multiple providers?',
67
+ default: false,
68
+ });
69
+ const roundRobin = [];
70
+ if (wantsRoundRobin) {
71
+ console.log('\n Add providers one by one. Press N when done.\n');
72
+ let addMore = true;
73
+ while (addMore) {
74
+ const provider = await setupProvider(`round robin #${roundRobin.length + 1}`);
75
+ roundRobin.push(provider);
76
+ addMore = await confirm({ message: 'Add another provider?', default: false });
77
+ }
78
+ }
79
+ // build config
80
+ const crawlixConfig = {
81
+ primary,
82
+ ...(fallback && { fallback }),
83
+ ...(roundRobin.length > 0 && { roundRobin }),
84
+ };
85
+ // save to ~/.crawlix/crawlix.config.json
86
+ const configDir = path.join(os.homedir(), '.crawlix');
87
+ const configPath = path.join(configDir, 'crawlix.config.json');
88
+ fs.mkdirSync(configDir, { recursive: true });
89
+ fs.writeFileSync(configPath, JSON.stringify(crawlixConfig, null, 2));
90
+ console.log('\n ✓ Config saved to', configPath);
91
+ console.log(' Run crawlix run --url <url> --goal "<goal>" to start testing\n');
92
+ });
93
+ //# sourceMappingURL=setup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.js","sourceRoot":"","sources":["../../../src/cli/commands/setup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAA;AACpE,OAAO,EAAE,MAAM,IAAI,CAAA;AACnB,OAAO,EAAE,MAAM,IAAI,CAAA;AACnB,OAAO,IAAI,MAAM,MAAM,CAAA;AAGvB,MAAM,cAAc,GAAiC;IACjD,IAAI,EAAE,yBAAyB;IAC/B,MAAM,EAAE,aAAa;IACrB,MAAM,EAAE,kBAAkB;IAC1B,SAAS,EAAE,2BAA2B;IACtC,UAAU,EAAE,wCAAwC;IACpD,MAAM,EAAE,UAAU;IAClB,QAAQ,EAAE,cAAc;IACxB,OAAO,EAAE,oBAAoB;CAChC,CAAA;AAED,KAAK,UAAU,aAAa,CAAC,KAAa;IACtC,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAe;QACxC,OAAO,EAAE,UAAU,KAAK,WAAW;QACnC,OAAO,EAAE;YACL,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE;YAC/B,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE;YACnC,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE;YACvC,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE;YACrC,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,EAAE;YAC3C,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE;YACnC,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE;YACnC,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,EAAE;SAC5C;KACJ,CAAC,CAAA;IAEF,IAAI,MAA0B,CAAA;IAE9B,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACxB,OAAO,CAAC,GAAG,CAAC,6CAA6C,CAAC,CAAA;IAC9D,CAAC;SAAM,CAAC;QACJ,MAAM,GAAG,MAAM,QAAQ,CAAC;YACpB,OAAO,EAAE,cAAc,QAAQ,WAAW;YAC1C,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,yBAAyB;SACxE,CAAC,CAAA;IACN,CAAC;IAED,MAAM,YAAY,GAAW,cAAc,CAAC,QAAQ,CAAC,CAAA;IACrD,MAAM,WAAW,GAAW,MAAM,KAAK,CAAC;QACpC,OAAO,EAAE,0CAA0C,YAAY,IAAI;KACtE,CAAC,CAAA;IAEF,MAAM,MAAM,GAAmB;QAC3B,QAAQ;QACR,GAAG,CAAC,MAAM,IAAI,EAAE,MAAM,EAAE,CAAC;QACzB,GAAG,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,WAAW,CAAC,IAAI,EAAE,EAAE,CAAC;KACtE,CAAA;IAED,OAAO,MAAM,CAAA;AACjB,CAAC;AAED,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC;KAC3C,WAAW,CAAC,6BAA6B,CAAC;KAC1C,MAAM,CAAC,KAAK,IAAI,EAAE;IACf,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAA;IAErC,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,SAAS,CAAC,CAAA;IAE9C,MAAM,aAAa,GAAG,MAAM,OAAO,CAAC;QAChC,OAAO,EAAE,0BAA0B;QACnC,OAAO,EAAE,KAAK;KACjB,CAAC,CAAA;IAEF,IAAI,QAAoC,CAAA;IACxC,IAAI,aAAa,EAAE,CAAC;QAChB,QAAQ,GAAG,MAAM,aAAa,CAAC,UAAU,CAAC,CAAA;IAC9C,CAAC;IAED,uBAAuB;IACvB,MAAM,eAAe,GAAG,MAAM,OAAO,CAAC;QAClC,OAAO,EAAE,qEAAqE;QAC9E,OAAO,EAAE,KAAK;KACjB,CAAC,CAAA;IAEF,MAAM,UAAU,GAAqB,EAAE,CAAA;IAEvC,IAAI,eAAe,EAAE,CAAC;QAClB,OAAO,CAAC,GAAG,CAAC,oDAAoD,CAAC,CAAA;QAEjE,IAAI,OAAO,GAAG,IAAI,CAAA;QAClB,OAAO,OAAO,EAAE,CAAC;YACb,MAAM,QAAQ,GAAG,MAAM,aAAa,CAAC,gBAAgB,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,CAAA;YAC7E,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;YACzB,OAAO,GAAG,MAAM,OAAO,CAAC,EAAE,OAAO,EAAE,uBAAuB,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAA;QACjF,CAAC;IACL,CAAC;IAED,eAAe;IACf,MAAM,aAAa,GAAkB;QACjC,OAAO;QACP,GAAG,CAAC,QAAQ,IAAI,EAAE,QAAQ,EAAE,CAAC;QAC7B,GAAG,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,UAAU,EAAE,CAAC;KAC/C,CAAA;IAED,yCAAyC;IACzC,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,UAAU,CAAC,CAAA;IACrD,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,qBAAqB,CAAC,CAAA;IAE9D,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAC5C,EAAE,CAAC,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAA;IAEpE,OAAO,CAAC,GAAG,CAAC,uBAAuB,EAAE,UAAU,CAAC,CAAA;IAChD,OAAO,CAAC,GAAG,CAAC,kEAAkE,CAAC,CAAA;AACnF,CAAC,CAAC,CAAA"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":""}
@@ -0,0 +1,17 @@
1
+ import { Command } from 'commander';
2
+ import { runCommand } from './commands/run.js';
3
+ import { setupCommand } from './commands/setup.js';
4
+ import { agentsCommand } from './commands/agents.js';
5
+ import { createRequire } from 'module';
6
+ const require = createRequire(import.meta.url);
7
+ const pkg = require('../../package.json');
8
+ const program = new Command();
9
+ program
10
+ .name('crawlix')
11
+ .description('👾 Crawlix: Claw through bugs before your users do.')
12
+ .version(pkg.version);
13
+ program.addCommand(runCommand);
14
+ program.addCommand(setupCommand);
15
+ program.addCommand(agentsCommand);
16
+ program.parse();
17
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAA;AACtC,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AAC9C,MAAM,GAAG,GAAG,OAAO,CAAC,oBAAoB,CAAwB,CAAA;AAChE,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAA;AAE7B,OAAO;KACF,IAAI,CAAC,SAAS,CAAC;KACf,WAAW,CAAC,qDAAqD,CAAC;KAClE,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;AAEzB,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC,CAAA;AAC9B,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,CAAA;AAChC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAA;AAEjC,OAAO,CAAC,KAAK,EAAE,CAAA"}
@@ -0,0 +1,14 @@
1
+ import type { Action, HistoryEntry, PageState, PersonaConfig } from "../types/index.js";
2
+ import { LLM } from "../llm/index.js";
3
+ export declare class Director {
4
+ private persona;
5
+ private llm;
6
+ private goal;
7
+ constructor(persona: PersonaConfig, llm: LLM, goal: string);
8
+ get personaName(): string;
9
+ private buildSystemPrompt;
10
+ private buildUserMessage;
11
+ private parseAction;
12
+ decide(pageState: PageState, history: HistoryEntry[]): Promise<Action>;
13
+ }
14
+ //# sourceMappingURL=director.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"director.d.ts","sourceRoot":"","sources":["../../src/core/director.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAY,SAAS,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClG,OAAO,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAEtC,qBAAa,QAAQ;IACjB,OAAO,CAAC,OAAO,CAAgB;IAC/B,OAAO,CAAC,GAAG,CAAM;IACjB,OAAO,CAAC,IAAI,CAAS;gBAGT,OAAO,EAAE,aAAa,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM;IAM1D,IAAI,WAAW,IAAI,MAAM,CAExB;IAGD,OAAO,CAAC,iBAAiB;IAuCzB,OAAO,CAAC,gBAAgB;IA+BxB,OAAO,CAAC,WAAW;IA0BN,MAAM,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;CAStF"}