qpilot 0.5.3 → 0.7.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/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/app-build-manifest.json +14 -7
- package/.next/standalone/.next/app-path-routes-manifest.json +1 -0
- package/.next/standalone/.next/build-manifest.json +2 -2
- package/.next/standalone/.next/prerender-manifest.json +10 -10
- package/.next/standalone/.next/routes-manifest.json +9 -0
- package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_not-found.html +1 -1
- package/.next/standalone/.next/server/app/_not-found.rsc +3 -3
- package/.next/standalone/.next/server/app/api/run/[id]/answer/route.js +1 -1
- package/.next/standalone/.next/server/app/api/run/[id]/answer/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/run/[id]/pause/route.js +1 -1
- package/.next/standalone/.next/server/app/api/run/[id]/pause/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/run/[id]/shot/[num]/route.js +1 -0
- package/.next/standalone/.next/server/app/api/run/[id]/shot/[num]/route.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/api/run/[id]/shot/[num]/route_client-reference-manifest.js +1 -0
- package/.next/standalone/.next/server/app/api/run/[id]/stream/route.js +2 -2
- package/.next/standalone/.next/server/app/api/run/[id]/stream/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/run/route.js +14 -6
- package/.next/standalone/.next/server/app/api/run/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/index.html +1 -1
- package/.next/standalone/.next/server/app/index.rsc +3 -3
- package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/run/[id]/page.js +1 -1
- package/.next/standalone/.next/server/app/run/[id]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app-paths-manifest.json +1 -0
- package/.next/standalone/.next/server/chunks/960.js +1 -1
- package/.next/standalone/.next/server/functions-config-manifest.json +3 -2
- package/.next/standalone/.next/server/next-font-manifest.js +1 -1
- package/.next/standalone/.next/server/next-font-manifest.json +1 -1
- package/.next/standalone/.next/server/pages/404.html +1 -1
- package/.next/standalone/.next/server/pages/500.html +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/static/chunks/app/api/run/[id]/answer/route-e10dd0bc8788750a.js +1 -0
- package/.next/standalone/.next/static/chunks/app/api/run/[id]/pause/route-e10dd0bc8788750a.js +1 -0
- package/.next/standalone/.next/static/chunks/app/api/run/[id]/shot/[num]/route-e10dd0bc8788750a.js +1 -0
- package/.next/standalone/.next/static/chunks/app/api/run/[id]/stream/route-e10dd0bc8788750a.js +1 -0
- package/.next/standalone/.next/static/chunks/app/api/run/route-e10dd0bc8788750a.js +1 -0
- package/.next/standalone/.next/static/chunks/app/{layout-85e06e327ed56a3c.js → layout-6818616dc0d82320.js} +1 -1
- package/.next/standalone/.next/static/chunks/app/run/[id]/page-3b25ede818499602.js +1 -0
- package/.next/{static/css/4c75ab9da933ec7d.css → standalone/.next/static/css/2e8aee54e9780b29.css} +1 -1
- package/.next/standalone/.next/static/media/013b72fa676f92e0-s.woff2 +0 -0
- package/.next/standalone/.next/static/media/2b5b02fc7e511755-s.woff2 +0 -0
- package/.next/standalone/.next/static/media/65f03d54ccadf4a8-s.woff2 +0 -0
- package/.next/standalone/.next/static/media/7d4881bb7e1bf84d-s.p.woff2 +0 -0
- package/.next/standalone/.next/static/media/b9408752a0c24fb9-s.woff2 +0 -0
- package/.next/standalone/.next/static/media/e038a29029a234f2-s.woff2 +0 -0
- package/.next/standalone/package.json +7 -3
- package/.next/static/chunks/app/api/run/[id]/answer/route-e10dd0bc8788750a.js +1 -0
- package/.next/static/chunks/app/api/run/[id]/pause/route-e10dd0bc8788750a.js +1 -0
- package/.next/static/chunks/app/api/run/[id]/shot/[num]/route-e10dd0bc8788750a.js +1 -0
- package/.next/static/chunks/app/api/run/[id]/stream/route-e10dd0bc8788750a.js +1 -0
- package/.next/static/chunks/app/api/run/route-e10dd0bc8788750a.js +1 -0
- package/.next/static/chunks/app/{layout-85e06e327ed56a3c.js → layout-6818616dc0d82320.js} +1 -1
- package/.next/static/chunks/app/run/[id]/page-3b25ede818499602.js +1 -0
- package/.next/{standalone/.next/static/css/4c75ab9da933ec7d.css → static/css/2e8aee54e9780b29.css} +1 -1
- package/.next/static/media/013b72fa676f92e0-s.woff2 +0 -0
- package/.next/static/media/2b5b02fc7e511755-s.woff2 +0 -0
- package/.next/static/media/65f03d54ccadf4a8-s.woff2 +0 -0
- package/.next/static/media/7d4881bb7e1bf84d-s.p.woff2 +0 -0
- package/.next/static/media/b9408752a0c24fb9-s.woff2 +0 -0
- package/.next/static/media/e038a29029a234f2-s.woff2 +0 -0
- package/README.md +38 -11
- package/bin/qa-agent.js +257 -38
- package/package.json +7 -3
- package/.next/standalone/.next/static/chunks/app/api/run/[id]/answer/route-512bf413c7eb7802.js +0 -1
- package/.next/standalone/.next/static/chunks/app/api/run/[id]/pause/route-512bf413c7eb7802.js +0 -1
- package/.next/standalone/.next/static/chunks/app/api/run/[id]/stream/route-512bf413c7eb7802.js +0 -1
- package/.next/standalone/.next/static/chunks/app/api/run/route-512bf413c7eb7802.js +0 -1
- package/.next/standalone/.next/static/chunks/app/run/[id]/page-a5676bd71f033295.js +0 -1
- package/.next/standalone/.next/static/media/0f1bdadaf30e2d5f-s.woff2 +0 -0
- package/.next/standalone/.next/static/media/2c34d62a75506231-s.woff2 +0 -0
- package/.next/standalone/.next/static/media/601f5c280d60caca-s.woff2 +0 -0
- package/.next/standalone/.next/static/media/a115172161b307bb-s.woff2 +0 -0
- package/.next/standalone/.next/static/media/d100b2a099e34044-s.woff2 +0 -0
- package/.next/standalone/.next/static/media/f5271587012faf78-s.p.woff2 +0 -0
- package/.next/static/chunks/app/api/run/[id]/answer/route-512bf413c7eb7802.js +0 -1
- package/.next/static/chunks/app/api/run/[id]/pause/route-512bf413c7eb7802.js +0 -1
- package/.next/static/chunks/app/api/run/[id]/stream/route-512bf413c7eb7802.js +0 -1
- package/.next/static/chunks/app/api/run/route-512bf413c7eb7802.js +0 -1
- package/.next/static/chunks/app/run/[id]/page-a5676bd71f033295.js +0 -1
- package/.next/static/media/0f1bdadaf30e2d5f-s.woff2 +0 -0
- package/.next/static/media/2c34d62a75506231-s.woff2 +0 -0
- package/.next/static/media/601f5c280d60caca-s.woff2 +0 -0
- package/.next/static/media/a115172161b307bb-s.woff2 +0 -0
- package/.next/static/media/d100b2a099e34044-s.woff2 +0 -0
- package/.next/static/media/f5271587012faf78-s.p.woff2 +0 -0
- /package/.next/standalone/.next/static/{3ynLRpjI9IVS8O8v_Wuds → OTVFCdqWzaakBh2l-H9cW}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{3ynLRpjI9IVS8O8v_Wuds → OTVFCdqWzaakBh2l-H9cW}/_ssgManifest.js +0 -0
- /package/.next/static/{3ynLRpjI9IVS8O8v_Wuds → OTVFCdqWzaakBh2l-H9cW}/_buildManifest.js +0 -0
- /package/.next/static/{3ynLRpjI9IVS8O8v_Wuds → OTVFCdqWzaakBh2l-H9cW}/_ssgManifest.js +0 -0
|
Binary file
|
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/qpilot)
|
|
6
6
|
[](https://github.com/broxhq/qpilot)
|
|
7
|
-

|
|
8
8
|

|
|
9
9
|
|
|
10
10
|
> If qpilot saved you time → **[⭐ Star it on GitHub](https://github.com/broxhq/qpilot)**. It helps more than you'd think.
|
|
@@ -24,42 +24,69 @@ No code. No Selenium. No config files.
|
|
|
24
24
|
|
|
25
25
|
## Quick start
|
|
26
26
|
|
|
27
|
-
**Requirements:** Node.js
|
|
27
|
+
**Requirements:** Node.js 20.12+, Google Chrome, an [Anthropic API key](https://console.anthropic.com) — or any OpenAI-compatible model endpoint (Qwen, vLLM, Ollama, corporate gateway)
|
|
28
28
|
|
|
29
29
|
```bash
|
|
30
30
|
npx qpilot
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
-
That's it.
|
|
33
|
+
That's it. On first run qpilot walks you through a quick provider setup (arrow-key menu), then every launch shows your config and a Start menu.
|
|
34
34
|
|
|
35
35
|
Browser opens automatically at `http://localhost:3847`.
|
|
36
36
|
|
|
37
37
|
---
|
|
38
38
|
|
|
39
|
-
##
|
|
39
|
+
## Models & providers
|
|
40
40
|
|
|
41
|
-
qpilot
|
|
41
|
+
On first run qpilot asks which model to use. You can re-run setup anytime:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npx qpilot config
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Two options:
|
|
48
|
+
|
|
49
|
+
- **Anthropic (Claude)** — enter your `sk-ant-…` key. Default model is `claude-haiku-4-5`.
|
|
50
|
+
Base URL is optional — set it if you reach Claude through a corporate proxy/gateway.
|
|
51
|
+
- **Custom** — any **OpenAI-compatible** endpoint: Qwen, vLLM, Ollama, a corporate
|
|
52
|
+
gateway, OpenRouter, or OpenAI itself. You provide a **base URL**, **API token**
|
|
53
|
+
and **model id**, e.g.:
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
Base URL: https://dashscope-intl.aliyuncs.com/compatible-mode/v1
|
|
57
|
+
Model id: qwen2.5-72b-instruct
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Your choice is saved to `~/.qpilot/config.json` (mode `600`) and reused on every run.
|
|
61
|
+
|
|
62
|
+
> The custom path speaks the OpenAI `/chat/completions` protocol with tool calling —
|
|
63
|
+
> so the model must support function/tool calling for the agent to drive the browser.
|
|
64
|
+
|
|
65
|
+
### API key (Anthropic shortcut)
|
|
66
|
+
|
|
67
|
+
For the Anthropic provider you can skip setup by supplying the key via env:
|
|
42
68
|
|
|
43
69
|
1. `ANTHROPIC_API_KEY` environment variable
|
|
44
70
|
2. `.env.local` file in the current directory
|
|
45
|
-
3. Prompts you to enter it if neither is found
|
|
46
|
-
|
|
47
|
-
To avoid entering it every time:
|
|
48
71
|
|
|
49
72
|
```bash
|
|
50
73
|
echo "ANTHROPIC_API_KEY=sk-ant-..." > .env.local
|
|
51
74
|
```
|
|
52
75
|
|
|
76
|
+
The key is never stored except in `~/.qpilot/config.json` when you run setup.
|
|
77
|
+
|
|
53
78
|
---
|
|
54
79
|
|
|
55
80
|
## Options
|
|
56
81
|
|
|
57
|
-
|
|
|
82
|
+
| Command / flag | Description |
|
|
58
83
|
|------|-------------|
|
|
59
|
-
|
|
|
84
|
+
| `qpilot config` | Re-run provider setup (Anthropic or custom model) |
|
|
85
|
+
| `--visible` | Show the Chrome window while the agent runs (also available in the start menu) |
|
|
60
86
|
|
|
61
87
|
```bash
|
|
62
88
|
npx qpilot --visible
|
|
89
|
+
npx qpilot config
|
|
63
90
|
```
|
|
64
91
|
|
|
65
92
|
---
|
|
@@ -91,6 +118,6 @@ You can paste multiple test cases at once — the agent runs them in order.
|
|
|
91
118
|
|
|
92
119
|
## Notes
|
|
93
120
|
|
|
94
|
-
- API key is
|
|
121
|
+
- API key is stored only in `~/.qpilot/config.json` (file mode `600`) — never sent anywhere except your chosen model provider
|
|
95
122
|
- Runs are in-memory; restarting clears them
|
|
96
123
|
- Powered by [Claude](https://anthropic.com) + [Playwright](https://playwright.dev)
|
package/bin/qa-agent.js
CHANGED
|
@@ -3,14 +3,27 @@
|
|
|
3
3
|
|
|
4
4
|
const { spawn } = require("child_process");
|
|
5
5
|
const { createServer } = require("net");
|
|
6
|
-
const { createInterface } = require("readline");
|
|
7
6
|
const { join } = require("path");
|
|
8
|
-
const {
|
|
7
|
+
const { homedir } = require("os");
|
|
8
|
+
const {
|
|
9
|
+
existsSync,
|
|
10
|
+
readFileSync,
|
|
11
|
+
writeFileSync,
|
|
12
|
+
mkdirSync,
|
|
13
|
+
} = require("fs");
|
|
14
|
+
const pc = require("picocolors");
|
|
9
15
|
|
|
10
16
|
const PKG_DIR = join(__dirname, "..");
|
|
17
|
+
const CONFIG_DIR = join(homedir(), ".qpilot");
|
|
18
|
+
const CONFIG_PATH = join(CONFIG_DIR, "config.json");
|
|
19
|
+
const DEFAULT_ANTHROPIC_MODEL = "claude-haiku-4-5-20251001";
|
|
11
20
|
|
|
12
21
|
const args = process.argv.slice(2);
|
|
13
|
-
|
|
22
|
+
let VISIBLE = args.includes("--visible") || args.includes("-v");
|
|
23
|
+
const WANTS_SETUP =
|
|
24
|
+
args[0] === "config" || args[0] === "setup" || args.includes("--config");
|
|
25
|
+
// menu/prompts only in a real terminal; in scripts start silently
|
|
26
|
+
const INTERACTIVE = Boolean(process.stdout.isTTY && process.stdin.isTTY);
|
|
14
27
|
|
|
15
28
|
function findFreePort(port) {
|
|
16
29
|
return new Promise((resolve) => {
|
|
@@ -28,8 +41,8 @@ function openBrowser(url) {
|
|
|
28
41
|
: process.platform === "win32"
|
|
29
42
|
? "cmd"
|
|
30
43
|
: "xdg-open";
|
|
31
|
-
const
|
|
32
|
-
spawn(cmd,
|
|
44
|
+
const a = process.platform === "win32" ? ["/c", "start", url] : [url];
|
|
45
|
+
spawn(cmd, a, { detached: true, stdio: "ignore" }).unref();
|
|
33
46
|
}
|
|
34
47
|
|
|
35
48
|
function loadEnvFile(filePath) {
|
|
@@ -48,33 +61,218 @@ function loadEnvFile(filePath) {
|
|
|
48
61
|
return env;
|
|
49
62
|
}
|
|
50
63
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
64
|
+
// ── config (~/.qpilot/config.json) ─────────────────────────────────────────
|
|
65
|
+
|
|
66
|
+
function loadConfig() {
|
|
67
|
+
try {
|
|
68
|
+
return JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
|
|
69
|
+
} catch {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
54
73
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
74
|
+
function saveConfig(cfg) {
|
|
75
|
+
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
76
|
+
writeFileSync(CONFIG_PATH, JSON.stringify(cfg, null, 2), { mode: 0o600 });
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Fallback: Anthropic key from env / .env.local (backwards compatibility). */
|
|
80
|
+
function envConfig(fileEnv) {
|
|
81
|
+
const apiKey = process.env.ANTHROPIC_API_KEY || fileEnv.ANTHROPIC_API_KEY;
|
|
82
|
+
if (!apiKey) return null;
|
|
83
|
+
return {
|
|
84
|
+
provider: "anthropic",
|
|
85
|
+
apiKey,
|
|
86
|
+
model: process.env.QPILOT_MODEL || fileEnv.QPILOT_MODEL || "",
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** config → env vars the server understands (lib/provider.ts). */
|
|
91
|
+
function configToEnv(cfg) {
|
|
92
|
+
if (cfg.provider === "custom") {
|
|
93
|
+
return {
|
|
94
|
+
QPILOT_PROVIDER: "custom",
|
|
95
|
+
QPILOT_BASE_URL: cfg.baseURL,
|
|
96
|
+
QPILOT_API_KEY: cfg.apiKey,
|
|
97
|
+
QPILOT_MODEL: cfg.model,
|
|
59
98
|
};
|
|
60
|
-
|
|
99
|
+
}
|
|
100
|
+
return {
|
|
101
|
+
QPILOT_PROVIDER: "anthropic",
|
|
102
|
+
ANTHROPIC_API_KEY: cfg.apiKey,
|
|
103
|
+
...(cfg.model ? { QPILOT_MODEL: cfg.model } : {}),
|
|
104
|
+
...(cfg.baseURL ? { QPILOT_BASE_URL: cfg.baseURL } : {}),
|
|
105
|
+
};
|
|
106
|
+
}
|
|
61
107
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
108
|
+
function describeProvider(cfg) {
|
|
109
|
+
return cfg.provider === "custom"
|
|
110
|
+
? `${cfg.model} @ custom`
|
|
111
|
+
: cfg.model || DEFAULT_ANTHROPIC_MODEL;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function maskKey(key) {
|
|
115
|
+
if (!key) return pc.red("(not set)");
|
|
116
|
+
return key.length > 12 ? `${key.slice(0, 7)}…${key.slice(-4)}` : "••••";
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function configSummary(cfg, source) {
|
|
120
|
+
const row = (label, value) => `${pc.dim(label.padEnd(10))}${value}`;
|
|
121
|
+
const lines = [
|
|
122
|
+
row(
|
|
123
|
+
"Provider",
|
|
124
|
+
cfg.provider === "custom"
|
|
125
|
+
? pc.magenta("Custom (OpenAI-compatible)")
|
|
126
|
+
: pc.magenta("Anthropic (Claude)"),
|
|
127
|
+
),
|
|
128
|
+
row("Model", pc.cyan(cfg.model || DEFAULT_ANTHROPIC_MODEL)),
|
|
129
|
+
];
|
|
130
|
+
if (cfg.baseURL) lines.push(row("Base URL", pc.cyan(cfg.baseURL)));
|
|
131
|
+
lines.push(row("API key", maskKey(cfg.apiKey)));
|
|
132
|
+
lines.push(row("Source", pc.dim(source)));
|
|
133
|
+
return lines.join("\n");
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// ── interactive (@clack/prompts, ESM → dynamic import) ──────────────────────
|
|
137
|
+
|
|
138
|
+
const required = (v) => (v && v.trim() ? undefined : "Required");
|
|
139
|
+
|
|
140
|
+
function bailIfCancel(p, v) {
|
|
141
|
+
if (p.isCancel(v)) {
|
|
142
|
+
p.cancel("Cancelled.");
|
|
143
|
+
process.exit(1);
|
|
144
|
+
}
|
|
145
|
+
return v;
|
|
69
146
|
}
|
|
70
147
|
|
|
71
|
-
function
|
|
148
|
+
async function runSetup(p) {
|
|
149
|
+
const bail = (v) => bailIfCancel(p, v);
|
|
150
|
+
|
|
151
|
+
const provider = bail(
|
|
152
|
+
await p.select({
|
|
153
|
+
message: "Choose your model provider",
|
|
154
|
+
initialValue: "anthropic",
|
|
155
|
+
options: [
|
|
156
|
+
{ value: "anthropic", label: "Anthropic (Claude)", hint: "default" },
|
|
157
|
+
{
|
|
158
|
+
value: "custom",
|
|
159
|
+
label: "Custom — OpenAI-compatible",
|
|
160
|
+
hint: "Qwen, vLLM, Ollama, corp gateway, OpenRouter",
|
|
161
|
+
},
|
|
162
|
+
],
|
|
163
|
+
}),
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
let cfg;
|
|
167
|
+
if (provider === "custom") {
|
|
168
|
+
const baseURL = bail(
|
|
169
|
+
await p.text({
|
|
170
|
+
message: "Base URL",
|
|
171
|
+
placeholder: "https://.../v1",
|
|
172
|
+
validate: (v) =>
|
|
173
|
+
!v || !v.trim()
|
|
174
|
+
? "Required"
|
|
175
|
+
: /^https?:\/\//.test(v.trim())
|
|
176
|
+
? undefined
|
|
177
|
+
: "Must start with http:// or https://",
|
|
178
|
+
}),
|
|
179
|
+
);
|
|
180
|
+
const apiKey = bail(
|
|
181
|
+
await p.password({ message: "API token", validate: required }),
|
|
182
|
+
);
|
|
183
|
+
const model = bail(
|
|
184
|
+
await p.text({
|
|
185
|
+
message: "Model id",
|
|
186
|
+
placeholder: "qwen2.5-72b-instruct",
|
|
187
|
+
validate: required,
|
|
188
|
+
}),
|
|
189
|
+
);
|
|
190
|
+
cfg = {
|
|
191
|
+
provider: "custom",
|
|
192
|
+
baseURL: baseURL.trim(),
|
|
193
|
+
apiKey: apiKey.trim(),
|
|
194
|
+
model: model.trim(),
|
|
195
|
+
};
|
|
196
|
+
} else {
|
|
197
|
+
const apiKey = bail(
|
|
198
|
+
await p.password({
|
|
199
|
+
message: "Anthropic API key (sk-ant-…)",
|
|
200
|
+
validate: required,
|
|
201
|
+
}),
|
|
202
|
+
);
|
|
203
|
+
const model = bail(
|
|
204
|
+
await p.text({
|
|
205
|
+
message: "Model id",
|
|
206
|
+
placeholder: DEFAULT_ANTHROPIC_MODEL,
|
|
207
|
+
defaultValue: DEFAULT_ANTHROPIC_MODEL,
|
|
208
|
+
}),
|
|
209
|
+
);
|
|
210
|
+
const baseURL = bail(
|
|
211
|
+
await p.text({
|
|
212
|
+
message: "Base URL (Enter to use api.anthropic.com)",
|
|
213
|
+
placeholder: "https://api.anthropic.com",
|
|
214
|
+
defaultValue: "",
|
|
215
|
+
validate: (v) =>
|
|
216
|
+
!v || !v.trim() || /^https?:\/\//.test(v.trim())
|
|
217
|
+
? undefined
|
|
218
|
+
: "Must start with http:// or https://",
|
|
219
|
+
}),
|
|
220
|
+
);
|
|
221
|
+
cfg = {
|
|
222
|
+
provider: "anthropic",
|
|
223
|
+
apiKey: apiKey.trim(),
|
|
224
|
+
model: (model || DEFAULT_ANTHROPIC_MODEL).trim(),
|
|
225
|
+
...(baseURL && baseURL.trim() ? { baseURL: baseURL.trim() } : {}),
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
saveConfig(cfg);
|
|
230
|
+
p.log.success(`Saved to ${pc.cyan(CONFIG_PATH)}`);
|
|
231
|
+
return cfg;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/** Config card + menu: Start / Start visible / Change / Exit. */
|
|
235
|
+
async function startMenu(p, cfg, source) {
|
|
236
|
+
for (;;) {
|
|
237
|
+
p.note(configSummary(cfg, source), "Provider");
|
|
238
|
+
const action = bailIfCancel(
|
|
239
|
+
p,
|
|
240
|
+
await p.select({
|
|
241
|
+
message: "Ready to go?",
|
|
242
|
+
initialValue: VISIBLE ? "start-visible" : "start",
|
|
243
|
+
options: [
|
|
244
|
+
{ value: "start", label: "Start", hint: "headless — agent works in background" },
|
|
245
|
+
{
|
|
246
|
+
value: "start-visible",
|
|
247
|
+
label: "Start with visible browser",
|
|
248
|
+
hint: "watch the agent click through pages",
|
|
249
|
+
},
|
|
250
|
+
{ value: "config", label: "Change provider / model" },
|
|
251
|
+
{ value: "exit", label: "Exit" },
|
|
252
|
+
],
|
|
253
|
+
}),
|
|
254
|
+
);
|
|
255
|
+
if (action === "start" || action === "start-visible") {
|
|
256
|
+
VISIBLE = action === "start-visible";
|
|
257
|
+
return cfg;
|
|
258
|
+
}
|
|
259
|
+
if (action === "exit") {
|
|
260
|
+
p.cancel("Bye!");
|
|
261
|
+
process.exit(0);
|
|
262
|
+
}
|
|
263
|
+
cfg = await runSetup(p);
|
|
264
|
+
source = CONFIG_PATH;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// ── server ───────────────────────────────────────────────────────────────────
|
|
269
|
+
|
|
270
|
+
function startServer(serverPath, port, envExtra) {
|
|
72
271
|
return new Promise((resolve, reject) => {
|
|
73
272
|
const child = spawn("node", [serverPath], {
|
|
74
273
|
env: {
|
|
75
274
|
...process.env,
|
|
76
|
-
...
|
|
77
|
-
ANTHROPIC_API_KEY: apiKey,
|
|
275
|
+
...envExtra,
|
|
78
276
|
PORT: String(port),
|
|
79
277
|
HOSTNAME: "127.0.0.1",
|
|
80
278
|
HEADLESS: VISIBLE ? "false" : "true",
|
|
@@ -100,31 +298,50 @@ function startServer(serverPath, port, apiKey, fileEnv) {
|
|
|
100
298
|
async function main() {
|
|
101
299
|
const serverPath = join(PKG_DIR, ".next", "standalone", "server.js");
|
|
102
300
|
if (!existsSync(serverPath)) {
|
|
103
|
-
console.error("App is not built. Run: npm run build");
|
|
301
|
+
console.error(pc.red("App is not built. Run: npm run build"));
|
|
104
302
|
process.exit(1);
|
|
105
303
|
}
|
|
106
304
|
|
|
107
305
|
const fileEnv = loadEnvFile(join(process.cwd(), ".env.local"));
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
if (!
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
306
|
+
|
|
307
|
+
let cfg;
|
|
308
|
+
if (!INTERACTIVE) {
|
|
309
|
+
// scripts/CI: no menu — use saved config or env, else error
|
|
310
|
+
cfg = loadConfig() || envConfig(fileEnv);
|
|
311
|
+
if (WANTS_SETUP || !cfg) {
|
|
312
|
+
console.error(
|
|
313
|
+
"No interactive terminal. Run `qpilot config` in a terminal first, or set ANTHROPIC_API_KEY.",
|
|
314
|
+
);
|
|
116
315
|
process.exit(1);
|
|
117
316
|
}
|
|
317
|
+
} else {
|
|
318
|
+
const p = await import("@clack/prompts");
|
|
319
|
+
p.intro(`${pc.bgCyan(pc.black(" qpilot "))} ${pc.dim("AI agent for manual test cases")}`);
|
|
320
|
+
|
|
321
|
+
if (WANTS_SETUP) {
|
|
322
|
+
cfg = await runSetup(p);
|
|
323
|
+
} else {
|
|
324
|
+
cfg = loadConfig() || envConfig(fileEnv);
|
|
325
|
+
if (!cfg) {
|
|
326
|
+
p.log.warn("No provider configured yet — let's set one up.");
|
|
327
|
+
cfg = await runSetup(p);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
const source = loadConfig() ? CONFIG_PATH : "env / .env.local";
|
|
331
|
+
cfg = await startMenu(p, cfg, source);
|
|
332
|
+
|
|
333
|
+
if (VISIBLE) p.log.info("--visible: browser window will be shown");
|
|
334
|
+
p.outro(pc.dim("Launching…"));
|
|
118
335
|
}
|
|
119
336
|
|
|
120
|
-
|
|
337
|
+
const envExtra = { ...fileEnv, ...configToEnv(cfg) };
|
|
121
338
|
|
|
122
339
|
// try ports until one works
|
|
123
340
|
let port = await findFreePort(3847);
|
|
124
341
|
let child;
|
|
125
342
|
while (true) {
|
|
126
343
|
try {
|
|
127
|
-
child = await startServer(serverPath, port,
|
|
344
|
+
child = await startServer(serverPath, port, envExtra);
|
|
128
345
|
break;
|
|
129
346
|
} catch {
|
|
130
347
|
port = await findFreePort(port + 1);
|
|
@@ -132,15 +349,17 @@ async function main() {
|
|
|
132
349
|
}
|
|
133
350
|
|
|
134
351
|
const url = `http://localhost:${port}`;
|
|
135
|
-
console.log(
|
|
352
|
+
console.log(
|
|
353
|
+
`\n ${pc.bold(pc.cyan("qpilot"))} ${pc.dim("→")} ${pc.underline(pc.cyan(url))} ${pc.dim("·")} ${pc.magenta(describeProvider(cfg))}\n`,
|
|
354
|
+
);
|
|
136
355
|
openBrowser(url);
|
|
137
356
|
|
|
138
357
|
const shutdown = () => {
|
|
139
358
|
child.kill("SIGTERM");
|
|
140
359
|
console.log(
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
360
|
+
`\n ${pc.bold("Thanks for using qpilot!")}` +
|
|
361
|
+
`\n If it saved you time, a ${pc.yellow("⭐")} means a lot:` +
|
|
362
|
+
`\n ${pc.underline(pc.cyan("https://github.com/broxhq/qpilot"))}\n`,
|
|
144
363
|
);
|
|
145
364
|
process.exit(0);
|
|
146
365
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "qpilot",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Run manual test cases with an AI agent in a real browser",
|
|
5
5
|
"bin": {
|
|
6
6
|
"qpilot": "bin/qa-agent.js"
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
],
|
|
31
31
|
"license": "MIT",
|
|
32
32
|
"engines": {
|
|
33
|
-
"node": ">=
|
|
33
|
+
"node": ">=20.12"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@anthropic-ai/sdk": "^0.40.0",
|
|
@@ -55,5 +55,9 @@
|
|
|
55
55
|
"type": "git",
|
|
56
56
|
"url": "https://github.com/broxhq/qpilot.git"
|
|
57
57
|
},
|
|
58
|
-
"homepage": "https://brox.sh"
|
|
58
|
+
"homepage": "https://brox.sh",
|
|
59
|
+
"dependencies": {
|
|
60
|
+
"@clack/prompts": "^1.5.1",
|
|
61
|
+
"picocolors": "^1.1.1"
|
|
62
|
+
}
|
|
59
63
|
}
|
package/.next/standalone/.next/static/chunks/app/api/run/[id]/answer/route-512bf413c7eb7802.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[54,569,774,964],{4441:()=>{}},_=>{_.O(0,[441,255,358],()=>_(_.s=4441)),_N_E=_.O()}]);
|
package/.next/standalone/.next/static/chunks/app/api/run/[id]/pause/route-512bf413c7eb7802.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[54,569,774,964],{4441:()=>{}},_=>{_.O(0,[441,255,358],()=>_(_.s=4441)),_N_E=_.O()}]);
|
package/.next/standalone/.next/static/chunks/app/api/run/[id]/stream/route-512bf413c7eb7802.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[54,569,774,964],{4441:()=>{}},_=>{_.O(0,[441,255,358],()=>_(_.s=4441)),_N_E=_.O()}]);
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[54,569,774,964],{4441:()=>{}},_=>{_.O(0,[441,255,358],()=>_(_.s=4441)),_N_E=_.O()}]);
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[170],{191:(e,t,n)=>{"use strict";n.r(t),n.d(t,{default:()=>U});var r=n(5155),s=n(2115),a=n(2619),i=n.n(a),o=n(3229),l=n(3228),d=n(2638),c=n(3410),u=n(9746),g=n(7274),x=n(8215),m=n(5352),p=n(4788),f=n(7212),b=n(3916),h=n(1083),v=n(2027),j=n(3101),w=n(5016);let N=(0,j.F)("group/badge inline-flex h-5 w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-4xl border border-transparent px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-all focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3!",{variants:{variant:{default:"bg-primary text-primary-foreground [a]:hover:bg-primary/80",secondary:"bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80",destructive:"bg-destructive/10 text-destructive focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:focus-visible:ring-destructive/40 [a]:hover:bg-destructive/20",outline:"border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground",ghost:"hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50",link:"text-primary underline-offset-4 hover:underline"}},defaultVariants:{variant:"default"}});function k(e){let{className:t,variant:n="default",render:r,...s}=e;return(0,v.C)({defaultTagName:"span",props:(0,h.v6)({className:(0,w.cn)(N({variant:n}),t)},s),render:r,state:{slot:"badge",variant:n}})}var y=n(7003),z=n(4036),S=n(5949),A=n(4915),_=n(8502),q=n(8905),E=n(989);function C(e){let{...t}=e;return(0,r.jsx)(z.D,{"data-slot":"dialog",...t})}function F(e){let{...t}=e;return(0,r.jsx)(S.Z,{"data-slot":"dialog-portal",...t})}function O(e){let{className:t,...n}=e;return(0,r.jsx)(A.X,{"data-slot":"dialog-overlay",className:(0,w.cn)("fixed inset-0 isolate z-50 bg-black/10 duration-100 supports-backdrop-filter:backdrop-blur-xs data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0",t),...n})}function P(e){let{className:t,children:n,showCloseButton:s=!0,...a}=e;return(0,r.jsxs)(F,{children:[(0,r.jsx)(O,{}),(0,r.jsxs)(_.h,{"data-slot":"dialog-content",className:(0,w.cn)("fixed top-1/2 left-1/2 z-50 grid w-full max-w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 gap-4 rounded-xl bg-popover p-4 text-sm text-popover-foreground ring-1 ring-foreground/10 duration-100 outline-none sm:max-w-sm data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",t),...a,children:[n,s&&(0,r.jsxs)(q.H,{"data-slot":"dialog-close",render:(0,r.jsx)(y.$,{variant:"ghost",className:"absolute top-2 right-2",size:"icon-sm"}),children:[(0,r.jsx)(p.A,{}),(0,r.jsx)("span",{className:"sr-only",children:"Close"})]})]})]})}function T(e){let{className:t,...n}=e;return(0,r.jsx)("div",{"data-slot":"dialog-header",className:(0,w.cn)("flex flex-col gap-2",t),...n})}function D(e){let{className:t,...n}=e;return(0,r.jsx)(E.L,{"data-slot":"dialog-title",className:(0,w.cn)("font-heading text-base leading-none font-medium",t),...n})}var I=n(2045);function R(e){let{className:t,type:n,...s}=e;return(0,r.jsx)(I.p,{type:n,"data-slot":"input",className:(0,w.cn)("h-8 w-full min-w-0 rounded-lg border border-input bg-transparent px-2.5 py-1 text-base transition-colors outline-none file:inline-flex file:h-6 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 md:text-sm dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40",t),...s})}var W=n(8521),$=n(2577),H=n(1127);function M(e){let{...t}=e;return(0,r.jsx)(W.N,{"data-slot":"collapsible",...t})}function B(e){let{...t}=e;return(0,r.jsx)($.R,{"data-slot":"collapsible-trigger",...t})}function J(e){let{...t}=e;return(0,r.jsx)(H.j,{"data-slot":"collapsible-content",...t})}function U(e){var t,n,a,g,x;let{params:m}=e,{id:p}=(0,s.use)(m),[f,b]=(0,s.useState)(null),[h,v]=(0,s.useState)([]),[j,N]=(0,s.useState)(!1),[k,z]=(0,s.useState)(null),[S,A]=(0,s.useState)(()=>Date.now()),[_,q]=(0,s.useState)(!1),E=(0,s.useRef)(!1);(0,s.useEffect)(()=>{E.current=!1;let e=new EventSource("/api/run/".concat(p,"/stream"));return e.onmessage=e=>{var t,n;let r=JSON.parse(e.data);if("snapshot"===r.kind){if(E.current=!0,b(r.run),v(r.run.events),"running"!==r.run.status&&"waiting"!==r.run.status){let e=r.run.events.at(-1);z(null!=(t=null==e?void 0:e.ts)?t:Date.now())}return}v(e=>[...e,r]),"plan"===r.kind&&r.steps&&b(e=>e?{...e,steps:r.steps}:e),"step"===r.kind&&r.step&&b(e=>{if(!e)return e;let t=e.steps.findIndex(e=>e.num===r.step.num),n=t>=0?e.steps.map((e,n)=>n===t?{...e,...r.step}:e):[...e.steps,r.step];return{...e,steps:n}}),"question"===r.kind&&r.question&&b(e=>e?{...e,status:"waiting",pending:r.question}:e),"answer"===r.kind&&b(e=>e?{...e,status:"running",pending:null}:e),"paused"===r.kind&&b(e=>e?{...e,status:"paused"}:e),"resumed"===r.kind&&b(e=>e?{...e,status:"running"}:e),("done"===r.kind||"error"===r.kind)&&(z(null!=(n=r.ts)?n:Date.now()),b(e=>{var t,n;return e?{...e,status:null!=(t=r.status)?t:"error"===r.kind?"error":"passed",summary:null!=(n=r.summary)?n:r.text,pending:null,steps:e.steps.map(e=>"queued"===e.status?{...e,status:"skipped"}:e)}:e}))},e.onerror=()=>{e.close(),E.current||N(!0)},()=>e.close()},[p]);let F=null!=(n=null==f?void 0:f.status)?n:"running",O=null!=(a=null==f?void 0:f.steps)?a:[],T=O.filter(e=>"pass"===e.status).length,D=O.filter(e=>"fail"===e.status).length,I=O.filter(e=>"warn"===e.status).length,R="running"===F||"waiting"===F,W=R||"paused"===F;async function $(){W&&(q(!0),await fetch("/api/run/".concat(p,"/pause"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({action:"paused"===F?"resume":"pause"})}).catch(()=>{}),q(!1))}let H=R&&null!=(g=null==(t=O.find(e=>"queued"===e.status))?void 0:t.num)?g:null;(0,s.useEffect)(()=>{if(!R)return;let e=setInterval(()=>A(Date.now()),1e3);return()=>clearInterval(e)},[R]),(0,s.useEffect)(()=>{var e;null!=H&&(null==(e=document.getElementById("step-".concat(H)))||e.scrollIntoView({behavior:"smooth",block:"center"}))},[H]);let M=f?(null!=k?k:S)-f.createdAt:0,B=O.filter(e=>"queued"!==e.status).length,J=O.length?B/O.length*100:0,U=[];for(let e of O){let t=U[U.length-1];t&&t.title===e.group?t.steps.push(e):U.push({title:e.group,steps:[e]})}return j?(0,r.jsxs)("main",{className:"flex flex-col items-center justify-center min-h-screen px-6 text-center",children:[(0,r.jsx)("p",{className:"text-6xl font-semibold text-muted-foreground/20 mb-4",children:"404"}),(0,r.jsx)("p",{className:"text-sm text-muted-foreground mb-6",children:"Run not found — it may have finished and been cleared from memory."}),(0,r.jsxs)(i(),{href:"/",className:"inline-flex items-center gap-1.5 text-sm text-foreground/70 hover:text-foreground transition-colors",children:[(0,r.jsx)(o.A,{className:"size-3.5"}),"New run"]})]}):(0,r.jsxs)("main",{className:"mx-auto max-w-2xl px-6 pt-10 pb-24",children:[(0,r.jsxs)(i(),{href:"/",className:"inline-flex items-center gap-1.5 text-xs text-muted-foreground hover:text-foreground transition-colors mb-8",children:[(0,r.jsx)(o.A,{className:"size-3.5"}),"new run"]}),(0,r.jsxs)("section",{className:"mb-8",children:[(0,r.jsx)(G,{status:F}),(0,r.jsx)("h1",{className:"text-lg font-semibold tracking-tight mt-5 break-words text-foreground/90",children:null!=(x=null==f?void 0:f.title)?x:p}),f&&(0,r.jsxs)("div",{className:"flex items-center justify-between gap-3 mt-1.5",children:[(0,r.jsx)("p",{className:"text-xs text-muted-foreground font-mono",children:O.length>0?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsxs)("span",{className:"text-foreground/60",children:[B,"/",O.length," steps"]}),T>0&&(0,r.jsxs)("span",{className:"text-success ml-2",children:["\xb7 ",T," passed"]}),I>0&&(0,r.jsxs)("span",{className:"text-warning ml-2",children:["\xb7 ",I," warn"]}),D>0&&(0,r.jsxs)("span",{className:"text-destructive ml-2",children:["\xb7 ",D," failed"]})]}):(0,r.jsx)("span",{className:"text-muted-foreground/50",children:"waiting for plan…"})}),(0,r.jsxs)("div",{className:"flex items-center gap-2 shrink-0",children:[W&&(0,r.jsx)(y.$,{variant:"ghost",size:"sm",onClick:$,disabled:_||"waiting"===F,className:"h-7 px-2 text-muted-foreground/60 hover:text-foreground",children:"paused"===F?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(l.A,{className:"size-3.5 mr-1"}),"Resume"]}):(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(d.A,{className:"size-3.5 mr-1"}),"Pause"]})}),(0,r.jsxs)("span",{className:"inline-flex items-center gap-1 text-xs text-muted-foreground/60 font-mono tabular-nums",children:[(0,r.jsx)(c.A,{className:"size-3"}),function(e){let t=Math.max(0,Math.floor(e/1e3));return"".concat(Math.floor(t/60),":").concat(String(t%60).padStart(2,"0"))}(M)]})]})]}),O.length>0&&(0,r.jsx)("div",{className:"relative mt-3 h-[3px] rounded-full bg-white/5 overflow-hidden",children:(0,r.jsx)("div",{className:(0,w.cn)("absolute inset-y-0 left-0 rounded-full transition-all duration-700 ease-out","failed"===F||"error"===F?"bg-destructive":"bg-success"),style:{width:"".concat(J,"%")}})})]}),(0,r.jsxs)("section",{className:"space-y-2",children:[0===O.length&&(0,r.jsxs)("div",{className:"flex flex-col items-center justify-center py-16 text-center",children:[(0,r.jsx)(u.A,{className:"size-5 text-muted-foreground/30 animate-spin mb-3"}),(0,r.jsx)("p",{className:"text-sm text-muted-foreground/50",children:"waiting for agent to start…"})]}),U.map((e,t)=>(0,r.jsxs)("div",{className:"space-y-2",children:[e.title&&(0,r.jsx)("div",{className:"pt-4 first:pt-0 text-[10.5px] font-semibold uppercase tracking-widest text-muted-foreground/40",children:e.title}),e.steps.map((e,t)=>(0,r.jsx)("div",{id:"step-".concat(e.num),className:"scroll-mt-6",children:(0,r.jsx)(K,{step:e,displayNum:t+1,active:e.num===H,events:h.filter(t=>t.stepNum===e.num)})},e.num))]},t))]}),(null==f?void 0:f.summary)&&(0,r.jsxs)("div",{className:"mt-6 rounded-xl border border-white/7 bg-card/60 px-4 py-3",children:[(0,r.jsx)("div",{className:"text-[10px] font-semibold uppercase tracking-widest text-muted-foreground/40 mb-1.5",children:"Summary"}),(0,r.jsx)("div",{className:"text-sm leading-relaxed text-foreground/80",children:f.summary})]}),("passed"===F||"failed"===F)&&(0,r.jsx)(V,{}),(0,r.jsx)(C,{open:!!(null==f?void 0:f.pending),children:(0,r.jsx)(P,{showCloseButton:!1,children:(null==f?void 0:f.pending)&&(0,r.jsx)(ee,{runId:p,question:f.pending})})})]})}function V(){return(0,r.jsxs)("a",{href:"https://github.com/broxhq/qpilot",target:"_blank",rel:"noreferrer",className:"group mt-6 flex items-center gap-3 rounded-xl border border-white/7 bg-card/60 px-4 py-3 transition-colors hover:border-warning/30 hover:bg-warning/[0.03]",children:[(0,r.jsx)(g.A,{className:"size-4 shrink-0 text-muted-foreground/50 transition-colors group-hover:text-warning group-hover:fill-warning"}),(0,r.jsxs)("div",{className:"min-w-0",children:[(0,r.jsxs)("div",{className:"text-sm text-foreground/80",children:["Did qpilot save you time?"," ",(0,r.jsx)("span",{className:"text-foreground/95 group-hover:text-warning transition-colors",children:"Star it on GitHub"})]}),(0,r.jsx)("div",{className:"text-xs text-muted-foreground/50",children:"A ⭐ helps more people find it — takes two seconds."})]})]})}let L={running:{label:"Running",sub:"agent is executing steps",icon:(0,r.jsx)(u.A,{className:"size-4 animate-spin"}),color:"text-foreground/70",bg:"bg-white/5",border:"border-white/10"},waiting:{label:"Waiting",sub:"agent needs your input",icon:(0,r.jsx)(x.A,{className:"size-4"}),color:"text-warning",bg:"bg-warning/10",border:"border-warning/20"},paused:{label:"Paused",sub:"run is paused",icon:(0,r.jsx)(d.A,{className:"size-4"}),color:"text-foreground/50",bg:"bg-white/5",border:"border-white/10"},passed:{label:"Passed",sub:"all steps passed",icon:(0,r.jsx)(m.A,{className:"size-4",strokeWidth:2.5}),color:"text-success",bg:"bg-success/10",border:"border-success/20"},failed:{label:"Failed",sub:"some steps failed",icon:(0,r.jsx)(p.A,{className:"size-4",strokeWidth:2.5}),color:"text-destructive",bg:"bg-destructive/10",border:"border-destructive/20"},error:{label:"Error",sub:"agent crashed",icon:(0,r.jsx)(x.A,{className:"size-4"}),color:"text-destructive",bg:"bg-destructive/10",border:"border-destructive/20"}};function G(e){var t;let{status:n}=e,s=null!=(t=L[n])?t:L.running;return(0,r.jsxs)("div",{className:"flex items-center gap-3",children:[(0,r.jsx)("div",{className:(0,w.cn)("flex items-center justify-center size-9 rounded-xl border transition-colors",s.bg,s.border,s.color),children:s.icon}),(0,r.jsxs)("div",{children:[(0,r.jsx)("div",{className:(0,w.cn)("text-sm font-semibold tracking-tight",s.color),children:s.label}),(0,r.jsx)("div",{className:"text-xs text-muted-foreground/60",children:s.sub})]})]})}let Q={queued:{border:"border-l-white/8",badge:"bg-white/5 text-muted-foreground/50",bg:"",label:"queued"},pass:{border:"border-l-success/60",badge:"bg-success/10 text-success",bg:"",label:"pass"},warn:{border:"border-l-warning/60",badge:"bg-warning/10 text-warning",bg:"",label:"warn"},fail:{border:"border-l-destructive/60",badge:"bg-destructive/10 text-destructive",bg:"bg-destructive/[0.03]",label:"fail"},skipped:{border:"border-l-white/8",badge:"bg-white/4 text-muted-foreground/30",bg:"",label:"skipped"}},X={border:"border-l-warning/80",badge:"bg-warning/10 text-warning",bg:"bg-warning/[0.03]"};function Z(e){if("action"===e.kind&&("report_step"===e.toolName||"finish"===e.toolName))return!1;if("observation"===e.kind){var t;let n=null!=(t=e.text)?t:"";return n.startsWith("Error:")||n.startsWith("[debug]")}return!0}function K(e){var t;let{step:n,events:a,active:i,displayNum:o}=e,l=null!=(t=Q[n.status])?t:Q.queued,d=i?{...l,...X}:l,c=a.filter(Z),g=i||"fail"===n.status,[x,m]=(0,s.useState)(g);return(0,s.useEffect)(()=>m(g),[g]),(0,r.jsx)(M,{open:x,onOpenChange:m,children:(0,r.jsxs)("div",{className:(0,w.cn)("rounded-xl border border-white/7 border-l-2 overflow-hidden transition-colors",d.border,d.bg),children:[(0,r.jsxs)(B,{className:"group w-full flex items-center gap-3 px-4 py-3 text-left hover:bg-white/[0.02] transition-colors",children:[(0,r.jsx)(k,{className:(0,w.cn)("border-0 text-[9.5px] tracking-widest font-semibold shrink-0 gap-1 uppercase rounded-md px-1.5",d.badge),children:i?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(u.A,{className:"size-2.5 animate-spin"}),"running"]}):l.label}),(0,r.jsxs)("span",{className:"flex-1 min-w-0 text-[13px] text-foreground/80",children:[(0,r.jsx)("span",{className:"text-muted-foreground/40 mr-2 font-mono text-[11px]",children:String(null!=o?o:n.num).padStart(2,"0")}),n.description]}),(0,r.jsx)(f.A,{className:"size-3.5 text-muted-foreground/30 shrink-0 group-data-open:hidden"}),(0,r.jsx)(b.A,{className:"size-3.5 text-muted-foreground/30 shrink-0 hidden group-data-open:inline"})]}),n.evidence&&(0,r.jsx)("div",{className:"px-4 pb-3 -mt-0.5 text-[11.5px] text-muted-foreground/60 leading-relaxed font-mono",children:n.evidence}),(0,r.jsx)(J,{children:(0,r.jsxs)("div",{className:"px-4 pb-4 pt-3 space-y-3 border-t border-white/5",children:[n.screenshot&&(0,r.jsx)("a",{href:n.screenshot,target:"_blank",rel:"noreferrer",className:"block rounded-lg overflow-hidden border border-white/8 hover:border-white/15 transition-colors",children:(0,r.jsx)("img",{src:n.screenshot,alt:"screenshot step ".concat(n.num),className:"max-h-64 w-full object-contain bg-black/20"})}),c.length>0?(0,r.jsx)("div",{className:"space-y-0.5",children:c.map((e,t)=>(0,r.jsx)(Y,{event:e},t))}):(0,r.jsx)("div",{className:"text-[11px] text-muted-foreground/30",children:"no events for this step"})]})})]})})}function Y(e){let{event:t}=e,{icon:n,text:s,cls:a}=function(e){var t,n,r,s,a,i,o,l,d;switch(e.kind){case"action":return{icon:"→",text:function(e,t){var n,r,s,a,i,o,l,d;let c=null!=t?t:{};switch(e){case"navigate":return"Opening ".concat(null!=(n=c.url)?n:"");case"snapshot":return c.near?'Reading "'.concat(c.near,'" block'):"Reading page";case"click":return c.name?'Clicking "'.concat(c.name,'"'):"Clicking element";case"fill":return c.name?'Filling "'.concat(c.name,'" → "').concat(null!=(r=c.value)?r:"",'"'):'Filling "'.concat(null!=(s=c.value)?s:"",'"');case"select":return c.name?'Selecting "'.concat(null!=(a=c.value)?a:"",'" in "').concat(c.name,'"'):'Selecting "'.concat(null!=(i=c.value)?i:"",'"');case"hover":return c.name?'Hovering "'.concat(c.name,'"'):"Hovering element";case"scroll_to":return"Scrolling to ".concat(c.text?'"'.concat(c.text,'"'):null!=(o=c.ref)?o:"element");case"scroll":{let e=[Number(c.y)?"".concat(Number(c.y)>0?"down":"up"," ").concat(Math.abs(Number(c.y)),"px"):"",Number(c.x)?"".concat(Number(c.x)>0?"right":"left"," ").concat(Math.abs(Number(c.x)),"px"):""].filter(Boolean).join(", "),t=c.ref?" inside ".concat(c.ref):"";return"Scrolling ".concat(e||"0px").concat(t)}case"press":return"Pressing ".concat(null!=(l=c.key)?l:"");case"wait":return"Waiting ".concat(null!=(d=c.ms)?d:""," ms");case"ask_user":return"Asking user";default:return null!=e?e:"action"}}(e.toolName,e.toolInput),cls:"text-foreground/70"};case"step":{let s=null!=(r=null==(t=e.step)?void 0:t.status)?r:"",a="pass"===s?"text-success":"fail"===s?"text-destructive":"text-warning";return{icon:"pass"===s?"✓":"fail"===s?"✗":"!",text:"Step ".concat(null==(n=e.step)?void 0:n.num," — ").concat(s.toUpperCase()),cls:a}}case"observation":{let t=null!=(s=e.text)?s:"";if(t.startsWith("Error:"))return{icon:"✗",text:t,cls:"text-destructive"};return{icon:"\xb7",text:t,cls:"text-muted-foreground/40"}}case"question":return{icon:"?",text:"Asking: ".concat(null!=(i=null==(a=e.question)?void 0:a.prompt)?i:""),cls:"text-warning"};case"answer":return{icon:"✎",text:"User answered",cls:"text-foreground/50"};case"thought":return{icon:"›",text:null!=(o=e.text)?o:"",cls:"text-muted-foreground/40 italic"};case"done":return{icon:"■",text:"Run finished — ".concat(null!=(l=e.status)?l:""),cls:"text-foreground/60"};case"error":return{icon:"✗",text:null!=(d=e.text)?d:"",cls:"text-destructive"};default:return{icon:"\xb7",text:"",cls:"text-muted-foreground/30"}}}(t),i=new Date(t.ts).toLocaleTimeString("en-US",{hour12:!1});return(0,r.jsxs)("div",{className:"flex gap-2.5 text-[11.5px] leading-relaxed items-baseline font-mono",children:[(0,r.jsx)("span",{className:"shrink-0 tabular-nums text-muted-foreground/25 text-[10px]",children:i}),(0,r.jsx)("span",{className:(0,w.cn)("shrink-0 w-3.5 text-center",a),children:n}),(0,r.jsx)("span",{className:(0,w.cn)("min-w-0 break-words",a),children:s})]})}function ee(e){let{runId:t,question:n}=e,[a,i]=(0,s.useState)(""),[o,l]=(0,s.useState)(!1),[d,c]=(0,s.useState)(null);async function u(e){if(e.preventDefault(),a){l(!0),c(null);try{let e=await fetch("/api/run/".concat(t,"/answer"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({questionId:n.id,answer:a})});if(!e.ok){let t=await e.json().catch(()=>({}));throw Error(t.error||"HTTP ".concat(e.status))}i("")}catch(e){c(e instanceof Error?e.message:String(e)),l(!1)}}}return(0,r.jsxs)("form",{onSubmit:u,className:"space-y-4",children:[(0,r.jsx)(T,{children:(0,r.jsxs)(D,{className:"flex items-center gap-2 text-base",children:[(0,r.jsx)(x.A,{className:"size-4 text-warning shrink-0"}),"Agent needs input"]})}),(0,r.jsx)("p",{className:"text-sm text-muted-foreground leading-relaxed",children:n.prompt}),(0,r.jsx)(R,{autoFocus:!0,type:n.secret?"password":"text",value:a,onChange:e=>i(e.target.value),placeholder:n.secret?"OTP / password":"answer",className:"font-mono"}),d&&(0,r.jsx)("p",{className:"text-destructive text-xs",children:d}),(0,r.jsx)(y.$,{type:"submit",disabled:!a||o,className:"w-full",children:o?"Sending…":"Submit"})]})}},5016:(e,t,n)=>{"use strict";n.d(t,{cn:()=>a});var r=n(2821),s=n(5889);function a(){for(var e=arguments.length,t=Array(e),n=0;n<e;n++)t[n]=arguments[n];return(0,s.QP)((0,r.$)(t))}},7003:(e,t,n)=>{"use strict";n.d(t,{$:()=>l});var r=n(5155),s=n(9574),a=n(3101),i=n(5016);let o=(0,a.F)("group/button inline-flex shrink-0 items-center justify-center rounded-lg border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",{variants:{variant:{default:"bg-primary text-primary-foreground [a]:hover:bg-primary/80",outline:"border-border bg-background hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50",secondary:"bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",ghost:"hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50",destructive:"bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40",link:"text-primary underline-offset-4 hover:underline"},size:{default:"h-8 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",xs:"h-6 gap-1 rounded-[min(var(--radius-md),10px)] px-2 text-xs in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3",sm:"h-7 gap-1 rounded-[min(var(--radius-md),12px)] px-2.5 text-[0.8rem] in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5",lg:"h-9 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",icon:"size-8","icon-xs":"size-6 rounded-[min(var(--radius-md),10px)] in-data-[slot=button-group]:rounded-lg [&_svg:not([class*='size-'])]:size-3","icon-sm":"size-7 rounded-[min(var(--radius-md),12px)] in-data-[slot=button-group]:rounded-lg","icon-lg":"size-9"}},defaultVariants:{variant:"default",size:"default"}});function l(e){let{className:t,variant:n="default",size:a="default",...l}=e;return(0,r.jsx)(s.$,{"data-slot":"button",className:(0,i.cn)(o({variant:n,size:a,className:t})),...l})}},9578:(e,t,n)=>{Promise.resolve().then(n.bind(n,191))}},e=>{e.O(0,[248,532,441,255,358],()=>e(e.s=9578)),_N_E=e.O()}]);
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[54,569,774,964],{4441:()=>{}},_=>{_.O(0,[441,255,358],()=>_(_.s=4441)),_N_E=_.O()}]);
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[54,569,774,964],{4441:()=>{}},_=>{_.O(0,[441,255,358],()=>_(_.s=4441)),_N_E=_.O()}]);
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[54,569,774,964],{4441:()=>{}},_=>{_.O(0,[441,255,358],()=>_(_.s=4441)),_N_E=_.O()}]);
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[54,569,774,964],{4441:()=>{}},_=>{_.O(0,[441,255,358],()=>_(_.s=4441)),_N_E=_.O()}]);
|