quadwork 1.5.2 → 1.5.4
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/bin/quadwork.js +16 -1
- package/out/404.html +1 -1
- package/out/__next.__PAGE__.txt +3 -3
- package/out/__next._full.txt +11 -11
- package/out/__next._head.txt +4 -4
- package/out/__next._index.txt +5 -5
- package/out/__next._tree.txt +1 -1
- package/out/_next/static/chunks/0.bbxho1vnxin.js +1 -0
- package/out/_next/static/chunks/{0m83k84.midd1.js → 0.fo6qk3ltnbn.js} +3 -3
- package/out/_next/static/chunks/00n1ppi~-l_sv.js +1 -0
- package/out/_next/static/chunks/{0.57eg262w~qg.js → 01xlw8hd842-c.js} +1 -1
- package/out/_next/static/chunks/{135rms05ismy4.js → 0656i.-.r7.a9.js} +2 -2
- package/out/_next/static/chunks/09elx026_5z7..js +1 -0
- package/out/_next/static/chunks/0d3shmwh5_nmn.js +1 -0
- package/out/_next/static/chunks/0fkhi51bdw9~~.js +1 -0
- package/out/_next/static/chunks/0fpg8z.yd2xb7.js +1 -0
- package/out/_next/static/chunks/0iwycgwby2dd_.js +1 -0
- package/out/_next/static/chunks/0mtmv-f5qymoi.js +1 -0
- package/out/_next/static/chunks/0pqt~8bl3ukh4.js +4 -0
- package/out/_next/static/chunks/0ze4gu236oq96.js +31 -0
- package/out/_next/static/chunks/0zfotsowwll1x.js +2 -0
- package/out/_next/static/chunks/0~xrqi87fqraz.js +1 -0
- package/out/_next/static/chunks/11v7tu7pto6_x.js +1 -0
- package/out/_next/static/chunks/{0dmi9pk2bd712.js → 12i404gkhv7q..js} +2 -2
- package/out/_next/static/chunks/16g.ca89g7fib.js +1 -0
- package/out/_next/static/chunks/{turbopack-0wh29ykoy-rb5.js → turbopack-0lcwh84lrj9gi.js} +1 -1
- package/out/_not-found/__next._full.txt +10 -10
- package/out/_not-found/__next._head.txt +4 -4
- package/out/_not-found/__next._index.txt +5 -5
- package/out/_not-found/__next._not-found.__PAGE__.txt +2 -2
- package/out/_not-found/__next._not-found.txt +3 -3
- package/out/_not-found/__next._tree.txt +1 -1
- package/out/_not-found.html +1 -1
- package/out/_not-found.txt +10 -10
- package/out/app-shell/__next._full.txt +10 -10
- package/out/app-shell/__next._head.txt +4 -4
- package/out/app-shell/__next._index.txt +5 -5
- package/out/app-shell/__next._tree.txt +1 -1
- package/out/app-shell/__next.app-shell.__PAGE__.txt +2 -2
- package/out/app-shell/__next.app-shell.txt +3 -3
- package/out/app-shell.html +1 -1
- package/out/app-shell.txt +10 -10
- package/out/index.html +1 -1
- package/out/index.txt +11 -11
- package/out/project/_/__next._full.txt +11 -11
- package/out/project/_/__next._head.txt +4 -4
- package/out/project/_/__next._index.txt +5 -5
- package/out/project/_/__next._tree.txt +1 -1
- package/out/project/_/__next.project.$d$id.__PAGE__.txt +3 -3
- package/out/project/_/__next.project.$d$id.txt +3 -3
- package/out/project/_/__next.project.txt +3 -3
- package/out/project/_/memory/__next._full.txt +11 -11
- package/out/project/_/memory/__next._head.txt +4 -4
- package/out/project/_/memory/__next._index.txt +5 -5
- package/out/project/_/memory/__next._tree.txt +1 -1
- package/out/project/_/memory/__next.project.$d$id.memory.__PAGE__.txt +3 -3
- package/out/project/_/memory/__next.project.$d$id.memory.txt +3 -3
- package/out/project/_/memory/__next.project.$d$id.txt +3 -3
- package/out/project/_/memory/__next.project.txt +3 -3
- package/out/project/_/memory.html +1 -1
- package/out/project/_/memory.txt +11 -11
- package/out/project/_/queue/__next._full.txt +11 -11
- package/out/project/_/queue/__next._head.txt +4 -4
- package/out/project/_/queue/__next._index.txt +5 -5
- package/out/project/_/queue/__next._tree.txt +1 -1
- package/out/project/_/queue/__next.project.$d$id.queue.__PAGE__.txt +3 -3
- package/out/project/_/queue/__next.project.$d$id.queue.txt +3 -3
- package/out/project/_/queue/__next.project.$d$id.txt +3 -3
- package/out/project/_/queue/__next.project.txt +3 -3
- package/out/project/_/queue.html +1 -1
- package/out/project/_/queue.txt +11 -11
- package/out/project/_.html +1 -1
- package/out/project/_.txt +11 -11
- package/out/settings/__next._full.txt +11 -11
- package/out/settings/__next._head.txt +4 -4
- package/out/settings/__next._index.txt +5 -5
- package/out/settings/__next._tree.txt +1 -1
- package/out/settings/__next.settings.__PAGE__.txt +3 -3
- package/out/settings/__next.settings.txt +3 -3
- package/out/settings.html +1 -1
- package/out/settings.txt +11 -11
- package/out/setup/__next._full.txt +11 -11
- package/out/setup/__next._head.txt +4 -4
- package/out/setup/__next._index.txt +5 -5
- package/out/setup/__next._tree.txt +1 -1
- package/out/setup/__next.setup.__PAGE__.txt +3 -3
- package/out/setup/__next.setup.txt +3 -3
- package/out/setup.html +1 -1
- package/out/setup.txt +11 -11
- package/package.json +1 -1
- package/server/index.js +130 -41
- package/server/install-agentchattr.js +53 -0
- package/server/routes.js +122 -3
- package/server/routes.telegramBridge.test.js +100 -2
- package/templates/CLAUDE.md +2 -1
- package/templates/config.toml +8 -0
- package/templates/seeds/dev.AGENTS.md +2 -0
- package/templates/seeds/head.AGENTS.md +2 -0
- package/templates/seeds/reviewer1.AGENTS.md +3 -1
- package/templates/seeds/reviewer2.AGENTS.md +3 -1
- package/out/_next/static/chunks/0-7v31f-nsgw-.js +0 -1
- package/out/_next/static/chunks/04_t39bv8y9pe.js +0 -1
- package/out/_next/static/chunks/084lff9v4p_vh.js +0 -1
- package/out/_next/static/chunks/0e.ktwt1nyj...js +0 -1
- package/out/_next/static/chunks/0excsn2a_5qsb.js +0 -4
- package/out/_next/static/chunks/0ezniz80psxr6.js +0 -1
- package/out/_next/static/chunks/0g-nq4.uckan-.js +0 -1
- package/out/_next/static/chunks/0ox7p_szjhn69.js +0 -1
- package/out/_next/static/chunks/0r7t_sj_sejq9.js +0 -1
- package/out/_next/static/chunks/0r_tb4lmfa_yb.js +0 -1
- package/out/_next/static/chunks/0whtwwbpg72ar.js +0 -1
- package/out/_next/static/chunks/0z~0.4hivi.f2.js +0 -31
- package/out/_next/static/chunks/15i5_ay.0ap.6.js +0 -2
- package/out/_next/static/chunks/17y2walb2um9w.js +0 -1
- /package/out/_next/static/{yMYfZ4LAn8Fy22suFUnOy → XCVQTR6dRg8tK75W8jDzw}/_buildManifest.js +0 -0
- /package/out/_next/static/{yMYfZ4LAn8Fy22suFUnOy → XCVQTR6dRg8tK75W8jDzw}/_clientMiddlewareManifest.js +0 -0
- /package/out/_next/static/{yMYfZ4LAn8Fy22suFUnOy → XCVQTR6dRg8tK75W8jDzw}/_ssgManifest.js +0 -0
package/server/routes.js
CHANGED
|
@@ -2385,6 +2385,70 @@ function telegramConfigToml(projectId) {
|
|
|
2385
2385
|
return path.join(CONFIG_DIR, `telegram-${projectId}.toml`);
|
|
2386
2386
|
}
|
|
2387
2387
|
|
|
2388
|
+
// #383: path to a project's AgentChattr config.toml. The install
|
|
2389
|
+
// handler patches this file to declare the `telegram-bridge` agent
|
|
2390
|
+
// so AC's registry accepts the bridge's register call.
|
|
2391
|
+
function projectAgentchattrConfigPath(projectId) {
|
|
2392
|
+
return path.join(CONFIG_DIR, projectId, "agentchattr", "config.toml");
|
|
2393
|
+
}
|
|
2394
|
+
|
|
2395
|
+
// #383 Bug 1: prefer the per-project agentchattr_url. Every project
|
|
2396
|
+
// after the first uses a distinct port (8301, 8302, ...), so reading
|
|
2397
|
+
// the global default silently routed bridge traffic to the wrong AC
|
|
2398
|
+
// instance.
|
|
2399
|
+
function resolveProjectAgentchattrUrl(cfg, project) {
|
|
2400
|
+
return (
|
|
2401
|
+
(project && project.agentchattr_url) ||
|
|
2402
|
+
(cfg && cfg.agentchattr_url) ||
|
|
2403
|
+
"http://127.0.0.1:8300"
|
|
2404
|
+
);
|
|
2405
|
+
}
|
|
2406
|
+
|
|
2407
|
+
// #383 Bug 2: the upstream bridge only reads `agentchattr_url` from
|
|
2408
|
+
// inside `[telegram]`. A separate `[agentchattr]` section is silently
|
|
2409
|
+
// ignored and the bridge falls back to its hardcoded :8300 default.
|
|
2410
|
+
// #404: accept projectId so we can write a per-project cursor_file
|
|
2411
|
+
// path. Without this, multiple project bridges share the same default
|
|
2412
|
+
// cursor and clobber each other's position — the project with higher
|
|
2413
|
+
// AC message IDs advances the cursor past the other project's range,
|
|
2414
|
+
// silently killing AC→TG forwarding for that project.
|
|
2415
|
+
function buildTelegramBridgeToml(tg, projectId) {
|
|
2416
|
+
const cursorFile = path.join(CONFIG_DIR, `telegram-bridge-cursor-${projectId}.json`);
|
|
2417
|
+
return (
|
|
2418
|
+
`[telegram]\n` +
|
|
2419
|
+
`bot_token = "${tg.bot_token}"\n` +
|
|
2420
|
+
`chat_id = "${tg.chat_id}"\n` +
|
|
2421
|
+
`agentchattr_url = "${tg.agentchattr_url}"\n` +
|
|
2422
|
+
`cursor_file = "${cursorFile}"\n`
|
|
2423
|
+
);
|
|
2424
|
+
}
|
|
2425
|
+
|
|
2426
|
+
// #383 Bug 3: AC's registry rejects any base name not pre-declared
|
|
2427
|
+
// in config.toml with `400 unknown base`. The bridge registers as
|
|
2428
|
+
// `telegram-bridge`, so every per-project AC config must declare it.
|
|
2429
|
+
// Idempotent: only appends if the section is not already present.
|
|
2430
|
+
function patchAgentchattrConfigForTelegramBridge(tomlText) {
|
|
2431
|
+
if (/^\[agents\.telegram-bridge\]\s*$/m.test(tomlText)) {
|
|
2432
|
+
return { text: tomlText, changed: false };
|
|
2433
|
+
}
|
|
2434
|
+
const sep = tomlText.length === 0 || tomlText.endsWith("\n") ? "" : "\n";
|
|
2435
|
+
const block = `\n[agents.telegram-bridge]\nlabel = "Telegram Bridge"\n`;
|
|
2436
|
+
return { text: tomlText + sep + block, changed: true };
|
|
2437
|
+
}
|
|
2438
|
+
|
|
2439
|
+
// #383 Bug 4: the upstream bridge treats env vars as higher
|
|
2440
|
+
// precedence than TOML values. If the parent shell exported
|
|
2441
|
+
// TELEGRAM_BOT_TOKEN for a different bot, the bridge silently ran
|
|
2442
|
+
// as the wrong identity. Scrub those keys from the child's env so
|
|
2443
|
+
// the TOML is the single source of truth.
|
|
2444
|
+
function buildTelegramBridgeSpawnEnv(parentEnv) {
|
|
2445
|
+
const env = { ...parentEnv };
|
|
2446
|
+
delete env.TELEGRAM_BOT_TOKEN;
|
|
2447
|
+
delete env.TELEGRAM_CHAT_ID;
|
|
2448
|
+
delete env.AGENTCHATTR_URL;
|
|
2449
|
+
return env;
|
|
2450
|
+
}
|
|
2451
|
+
|
|
2388
2452
|
// #353: per-project log file for the bridge subprocess. The start
|
|
2389
2453
|
// handler redirects stdout + stderr here so crashes (ImportError,
|
|
2390
2454
|
// config parse, auth failure) are recoverable instead of
|
|
@@ -2502,7 +2566,8 @@ function getProjectTelegram(projectId) {
|
|
|
2502
2566
|
return {
|
|
2503
2567
|
bot_token: resolveToken(project.telegram.bot_token || ""),
|
|
2504
2568
|
chat_id: project.telegram.chat_id || "",
|
|
2505
|
-
|
|
2569
|
+
// #383 Bug 1: prefer per-project URL over the global default.
|
|
2570
|
+
agentchattr_url: resolveProjectAgentchattrUrl(cfg, project),
|
|
2506
2571
|
};
|
|
2507
2572
|
} catch {
|
|
2508
2573
|
return null;
|
|
@@ -2638,7 +2703,31 @@ router.post("/api/telegram", async (req, res) => {
|
|
|
2638
2703
|
`pip output tail:\n${pipOutput.split("\n").slice(-10).join("\n")}`,
|
|
2639
2704
|
});
|
|
2640
2705
|
}
|
|
2641
|
-
|
|
2706
|
+
// #383 Bug 3: ensure every known project's AC config declares
|
|
2707
|
+
// the `telegram-bridge` agent. Without this, AC's registry
|
|
2708
|
+
// rejects the bridge's register call with `400 unknown base`
|
|
2709
|
+
// and the bridge enters an infinite re-register loop.
|
|
2710
|
+
// Idempotent — append-only, skips configs that already have
|
|
2711
|
+
// the section. Does NOT restart AC servers; the operator
|
|
2712
|
+
// must click SERVER → Restart to load the new agent slug.
|
|
2713
|
+
const patched = [];
|
|
2714
|
+
try {
|
|
2715
|
+
const cfgAll = JSON.parse(fs.readFileSync(CONFIG_PATH, "utf-8"));
|
|
2716
|
+
for (const proj of cfgAll.projects || []) {
|
|
2717
|
+
if (!proj || !proj.id) continue;
|
|
2718
|
+
const acPath = projectAgentchattrConfigPath(proj.id);
|
|
2719
|
+
if (!fs.existsSync(acPath)) continue;
|
|
2720
|
+
try {
|
|
2721
|
+
const before = fs.readFileSync(acPath, "utf-8");
|
|
2722
|
+
const { text, changed } = patchAgentchattrConfigForTelegramBridge(before);
|
|
2723
|
+
if (changed) {
|
|
2724
|
+
fs.writeFileSync(acPath, text);
|
|
2725
|
+
patched.push(proj.id);
|
|
2726
|
+
}
|
|
2727
|
+
} catch {}
|
|
2728
|
+
}
|
|
2729
|
+
} catch {}
|
|
2730
|
+
return res.json({ ok: true, patched_projects: patched });
|
|
2642
2731
|
}
|
|
2643
2732
|
case "start": {
|
|
2644
2733
|
const projectId = body.project_id;
|
|
@@ -2661,7 +2750,9 @@ router.post("/api/telegram", async (req, res) => {
|
|
|
2661
2750
|
const tg = getProjectTelegram(projectId);
|
|
2662
2751
|
if (!tg || !tg.bot_token || !tg.chat_id) return res.json({ ok: false, error: "Save bot_token and chat_id in project settings first." });
|
|
2663
2752
|
const tomlPath = telegramConfigToml(projectId);
|
|
2664
|
-
|
|
2753
|
+
// #383 Bug 2: write agentchattr_url inside [telegram]; the
|
|
2754
|
+
// bridge's load_config only reads from that section.
|
|
2755
|
+
const tomlContent = buildTelegramBridgeToml(tg, projectId);
|
|
2665
2756
|
fs.writeFileSync(tomlPath, tomlContent, { mode: 0o600 });
|
|
2666
2757
|
fs.chmodSync(tomlPath, 0o600);
|
|
2667
2758
|
// #353: pre-flight import check so a fresh install with no
|
|
@@ -2710,9 +2801,15 @@ router.post("/api/telegram", async (req, res) => {
|
|
|
2710
2801
|
}
|
|
2711
2802
|
let child;
|
|
2712
2803
|
try {
|
|
2804
|
+
// #383 Bug 4: scrub TELEGRAM_*/AGENTCHATTR_URL from the child
|
|
2805
|
+
// env so an operator shell that exports a different bot's
|
|
2806
|
+
// token (common on machines running AC2) can't silently
|
|
2807
|
+
// override the TOML. Makes the TOML the single source of
|
|
2808
|
+
// truth for the bridge's identity.
|
|
2713
2809
|
child = spawn(venvPython, [bridgeScript, "--config", tomlPath], {
|
|
2714
2810
|
detached: true,
|
|
2715
2811
|
stdio: ["ignore", outFd, errFd],
|
|
2812
|
+
env: buildTelegramBridgeSpawnEnv(process.env),
|
|
2716
2813
|
});
|
|
2717
2814
|
child.unref();
|
|
2718
2815
|
if (child.pid) fs.writeFileSync(telegramPidFile(projectId), String(child.pid));
|
|
@@ -2747,6 +2844,21 @@ router.post("/api/telegram", async (req, res) => {
|
|
|
2747
2844
|
case "stop": {
|
|
2748
2845
|
const projectId = body.project_id;
|
|
2749
2846
|
if (!projectId) return res.json({ ok: false, error: "Missing project_id" });
|
|
2847
|
+
// #388: deregister the bridge from AC before killing so the slot
|
|
2848
|
+
// clears immediately instead of lingering for 60s as a stale -2/-3.
|
|
2849
|
+
// Awaited so a fast stop→start cycle doesn't race the deregister.
|
|
2850
|
+
try {
|
|
2851
|
+
const cfg = JSON.parse(fs.readFileSync(CONFIG_PATH, "utf-8"));
|
|
2852
|
+
const project = cfg.projects?.find((p) => p.id === projectId);
|
|
2853
|
+
const acUrl = resolveProjectAgentchattrUrl(cfg, project);
|
|
2854
|
+
if (acUrl) {
|
|
2855
|
+
const acPort = new URL(acUrl).port || "8300";
|
|
2856
|
+
await fetch(`http://127.0.0.1:${acPort}/api/deregister/telegram-bridge`, {
|
|
2857
|
+
method: "POST",
|
|
2858
|
+
signal: AbortSignal.timeout(3000),
|
|
2859
|
+
}).catch(() => {});
|
|
2860
|
+
}
|
|
2861
|
+
} catch {}
|
|
2750
2862
|
try {
|
|
2751
2863
|
const pf = telegramPidFile(projectId);
|
|
2752
2864
|
if (fs.existsSync(pf)) {
|
|
@@ -2898,6 +3010,13 @@ module.exports.readLastLines = readLastLines;
|
|
|
2898
3010
|
// #380: expose checkTelegramBridgePythonDeps so the bridge test can
|
|
2899
3011
|
// exercise the venv-path interpreter argument round trip.
|
|
2900
3012
|
module.exports.checkTelegramBridgePythonDeps = checkTelegramBridgePythonDeps;
|
|
3013
|
+
// #383: pure helpers exposed for unit tests in
|
|
3014
|
+
// routes.telegramBridge.test.js. No production callers outside
|
|
3015
|
+
// this file.
|
|
3016
|
+
module.exports.resolveProjectAgentchattrUrl = resolveProjectAgentchattrUrl;
|
|
3017
|
+
module.exports.buildTelegramBridgeToml = buildTelegramBridgeToml;
|
|
3018
|
+
module.exports.patchAgentchattrConfigForTelegramBridge = patchAgentchattrConfigForTelegramBridge;
|
|
3019
|
+
module.exports.buildTelegramBridgeSpawnEnv = buildTelegramBridgeSpawnEnv;
|
|
2901
3020
|
// #236: expose sendViaWebSocket so the chat-ws-send regression test
|
|
2902
3021
|
// can verify the ack/body/error paths against a fake AC ws server.
|
|
2903
3022
|
module.exports.sendViaWebSocket = sendViaWebSocket;
|
|
@@ -11,7 +11,14 @@ const fs = require("node:fs");
|
|
|
11
11
|
const os = require("node:os");
|
|
12
12
|
const path = require("node:path");
|
|
13
13
|
const { execFileSync } = require("node:child_process");
|
|
14
|
-
const {
|
|
14
|
+
const {
|
|
15
|
+
readLastLines,
|
|
16
|
+
checkTelegramBridgePythonDeps,
|
|
17
|
+
resolveProjectAgentchattrUrl,
|
|
18
|
+
buildTelegramBridgeToml,
|
|
19
|
+
patchAgentchattrConfigForTelegramBridge,
|
|
20
|
+
buildTelegramBridgeSpawnEnv,
|
|
21
|
+
} = require("./routes");
|
|
15
22
|
|
|
16
23
|
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "qw-bridge-log-"));
|
|
17
24
|
function write(name, content) {
|
|
@@ -133,8 +140,99 @@ try {
|
|
|
133
140
|
venvSkipped = true;
|
|
134
141
|
}
|
|
135
142
|
|
|
143
|
+
// 12) #383 Bug 1: resolveProjectAgentchattrUrl prefers the
|
|
144
|
+
// per-project URL over the global default. Every project
|
|
145
|
+
// after the first uses a distinct port, so silently reading
|
|
146
|
+
// the global default routed bridge traffic to the wrong AC
|
|
147
|
+
// instance.
|
|
148
|
+
assert.equal(
|
|
149
|
+
resolveProjectAgentchattrUrl(
|
|
150
|
+
{ agentchattr_url: "http://127.0.0.1:8300" },
|
|
151
|
+
{ id: "quadwork", agentchattr_url: "http://127.0.0.1:8301" },
|
|
152
|
+
),
|
|
153
|
+
"http://127.0.0.1:8301",
|
|
154
|
+
);
|
|
155
|
+
// Falls back to global default when the project has no URL of
|
|
156
|
+
// its own (legacy single-project installs).
|
|
157
|
+
assert.equal(
|
|
158
|
+
resolveProjectAgentchattrUrl(
|
|
159
|
+
{ agentchattr_url: "http://127.0.0.1:8300" },
|
|
160
|
+
{ id: "legacy" },
|
|
161
|
+
),
|
|
162
|
+
"http://127.0.0.1:8300",
|
|
163
|
+
);
|
|
164
|
+
// Hard-coded fallback when neither is set.
|
|
165
|
+
assert.equal(
|
|
166
|
+
resolveProjectAgentchattrUrl({}, {}),
|
|
167
|
+
"http://127.0.0.1:8300",
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
// 13) #383 Bug 2: buildTelegramBridgeToml writes agentchattr_url
|
|
171
|
+
// inside [telegram]. The upstream bridge's load_config only
|
|
172
|
+
// reads from that section — a separate [agentchattr] section
|
|
173
|
+
// is silently ignored and the bridge falls back to its
|
|
174
|
+
// hardcoded :8300 default.
|
|
175
|
+
const toml13 = buildTelegramBridgeToml({
|
|
176
|
+
bot_token: "123:abc",
|
|
177
|
+
chat_id: "-42",
|
|
178
|
+
agentchattr_url: "http://127.0.0.1:8301",
|
|
179
|
+
}, "testproject");
|
|
180
|
+
assert.match(toml13, /^\[telegram\]/);
|
|
181
|
+
assert.match(toml13, /bot_token = "123:abc"/);
|
|
182
|
+
assert.match(toml13, /chat_id = "-42"/);
|
|
183
|
+
assert.match(toml13, /agentchattr_url = "http:\/\/127\.0\.0\.1:8301"/);
|
|
184
|
+
// #404: cursor_file must be per-project so multiple bridges
|
|
185
|
+
// don't clobber each other's position.
|
|
186
|
+
assert.match(toml13, /cursor_file = ".*telegram-bridge-cursor-testproject\.json"/);
|
|
187
|
+
// Must NOT emit a separate [agentchattr] section — the bridge
|
|
188
|
+
// would silently ignore it.
|
|
189
|
+
assert.equal(toml13.includes("\n[agentchattr]\n"), false);
|
|
190
|
+
|
|
191
|
+
// 14) #383 Bug 3: patchAgentchattrConfigForTelegramBridge is
|
|
192
|
+
// idempotent. The Install Bridge migration may run multiple
|
|
193
|
+
// times; it must not duplicate the section or corrupt the
|
|
194
|
+
// file.
|
|
195
|
+
const baseConfig =
|
|
196
|
+
"[agents.head]\nlabel = \"Head\"\n\n[agents.dev]\nlabel = \"Dev\"\n";
|
|
197
|
+
const first = patchAgentchattrConfigForTelegramBridge(baseConfig);
|
|
198
|
+
assert.equal(first.changed, true);
|
|
199
|
+
assert.match(first.text, /^\[agents\.telegram-bridge\]$/m);
|
|
200
|
+
assert.match(first.text, /label = "Telegram Bridge"/);
|
|
201
|
+
// Running a second time is a no-op.
|
|
202
|
+
const second = patchAgentchattrConfigForTelegramBridge(first.text);
|
|
203
|
+
assert.equal(second.changed, false);
|
|
204
|
+
assert.equal(second.text, first.text);
|
|
205
|
+
// A config that was hand-patched during diagnosis is recognized
|
|
206
|
+
// as already-correct — do not clobber the operator's edit.
|
|
207
|
+
const handPatched =
|
|
208
|
+
baseConfig + "\n[agents.telegram-bridge]\nlabel = \"Telegram Bridge\"\n";
|
|
209
|
+
const third = patchAgentchattrConfigForTelegramBridge(handPatched);
|
|
210
|
+
assert.equal(third.changed, false);
|
|
211
|
+
assert.equal(third.text, handPatched);
|
|
212
|
+
|
|
213
|
+
// 15) #383 Bug 4: buildTelegramBridgeSpawnEnv strips the three
|
|
214
|
+
// env vars the upstream bridge treats as higher-precedence
|
|
215
|
+
// than TOML. Without this, an operator shell that exported a
|
|
216
|
+
// different bot's token (common on machines running AC2)
|
|
217
|
+
// silently overrode the QuadWork-written TOML and the bridge
|
|
218
|
+
// ran as the wrong identity.
|
|
219
|
+
const scrubbed = buildTelegramBridgeSpawnEnv({
|
|
220
|
+
PATH: "/usr/bin",
|
|
221
|
+
HOME: "/home/op",
|
|
222
|
+
TELEGRAM_BOT_TOKEN: "wrong-token",
|
|
223
|
+
TELEGRAM_CHAT_ID: "-999",
|
|
224
|
+
AGENTCHATTR_URL: "http://127.0.0.1:9999",
|
|
225
|
+
});
|
|
226
|
+
assert.equal(scrubbed.TELEGRAM_BOT_TOKEN, undefined);
|
|
227
|
+
assert.equal(scrubbed.TELEGRAM_CHAT_ID, undefined);
|
|
228
|
+
assert.equal(scrubbed.AGENTCHATTR_URL, undefined);
|
|
229
|
+
// Non-telegram keys must pass through untouched — the bridge
|
|
230
|
+
// still needs PATH/HOME/etc. to find python and open files.
|
|
231
|
+
assert.equal(scrubbed.PATH, "/usr/bin");
|
|
232
|
+
assert.equal(scrubbed.HOME, "/home/op");
|
|
233
|
+
|
|
136
234
|
console.log(
|
|
137
|
-
"routes.telegramBridge.test.js: all assertions passed (
|
|
235
|
+
"routes.telegramBridge.test.js: all assertions passed (15 cases" +
|
|
138
236
|
(venvSkipped ? ", case 11 pip step skipped" : "") +
|
|
139
237
|
")",
|
|
140
238
|
);
|
package/templates/CLAUDE.md
CHANGED
|
@@ -33,7 +33,8 @@ Branch naming (strict): `task/<issue-number>-<short-slug>`
|
|
|
33
33
|
|
|
34
34
|
## Communication Rules
|
|
35
35
|
|
|
36
|
-
- **
|
|
36
|
+
- **Always reply to the operator** — when the operator (sender: "user") addresses you in chat, you MUST reply via `chat_send`. The operator's terminal is invisible; if you don't `chat_send`, your response does not exist.
|
|
37
|
+
- **No acknowledgment messages between agents** — don't send "on it", "noted", "standing by" to other agents. This rule does NOT apply to operator messages — always reply to the operator.
|
|
37
38
|
- **No status updates to Head** — Dev works silently until PR is ready
|
|
38
39
|
- **Strict routing**: Dev→Reviewer1/Reviewer2 (review) → Dev→Head (merge request) → Head→Dev (merged)
|
|
39
40
|
- **Post-merge silence**: Head sends ONE "merged" message. No further replies from anyone.
|
package/templates/config.toml
CHANGED
|
@@ -37,6 +37,14 @@ cwd = "{{dev_cwd}}"
|
|
|
37
37
|
color = "#da7756"
|
|
38
38
|
label = "Dev Builder"
|
|
39
39
|
|
|
40
|
+
# #383: AC's registry rejects bases not declared in config.toml.
|
|
41
|
+
# The Telegram bridge registers as `telegram-bridge`, so every
|
|
42
|
+
# per-project AC config must declare it. The bridge has no
|
|
43
|
+
# command/cwd of its own — it is a long-running external client
|
|
44
|
+
# that posts to AC's HTTP API.
|
|
45
|
+
[agents.telegram-bridge]
|
|
46
|
+
label = "Telegram Bridge"
|
|
47
|
+
|
|
40
48
|
[routing]
|
|
41
49
|
default = "none"
|
|
42
50
|
max_agent_hops = 30
|
|
@@ -85,5 +85,7 @@ Head owns this file — do not edit it. Read it when you need context on the bat
|
|
|
85
85
|
- After BOTH Reviewer1 AND Reviewer2 approve → ONLY THEN message **@head** to request merge.
|
|
86
86
|
- Always include issue/PR numbers in messages
|
|
87
87
|
- Report blockers to @head immediately
|
|
88
|
+
- **Always reply to the operator**: when the operator (sender: "user") sends a message that mentions you or is addressed to you, you MUST reply via `chat_send`. If it's a question, answer it. If it's an instruction, confirm what you will do, then do it. If it's not actionable for your role, reply explaining that and suggest which agent should handle it. The operator's terminal is invisible — if you don't `chat_send`, your response does not exist.
|
|
89
|
+
- **No acknowledgment messages between agents** — don't send "on it", "noted", "standing by" to other agents. This rule does NOT apply to operator messages — always reply to the operator.
|
|
88
90
|
- **Do NOT send ANY message to @head between assignment and merge request** — no acks, no status updates.
|
|
89
91
|
- **After merge confirmation from Head**: do NOT reply. The loop is COMPLETE — silence is required.
|
|
@@ -97,5 +97,7 @@ When the operator asks you in chat to start a task or batch:
|
|
|
97
97
|
- **ALWAYS @mention the next agent** — never @user or @human
|
|
98
98
|
- Route: you → @dev for task assignments. You do NOT message @reviewer1 or @reviewer2 directly.
|
|
99
99
|
- Include issue/PR numbers in all messages
|
|
100
|
+
- **Always reply to the operator**: when the operator (sender: "user") sends a message that mentions you or is addressed to you, you MUST reply via `chat_send`. If it's a question, answer it. If it's an instruction, confirm what you will do, then do it. If it's not actionable for your role, reply explaining that and suggest which agent should handle it. The operator's terminal is invisible — if you don't `chat_send`, your response does not exist.
|
|
101
|
+
- **No acknowledgment messages between agents** — don't send "on it", "noted", "standing by" to other agents. This rule does NOT apply to operator messages — always reply to the operator.
|
|
100
102
|
- **Do NOT reply to acknowledgments** — if Dev says "on it" or similar, do NOT respond. Wait silently for the PR.
|
|
101
103
|
- **After merge**: send ONE message: "@dev PR #<number> merged. Issue #<number> closed." — no further replies needed.
|
|
@@ -101,5 +101,7 @@ Run this once at the start of each session.
|
|
|
101
101
|
- **After BLOCK**: send message to @head AND @dev — Head decides whether to reassign or close
|
|
102
102
|
- Always include PR number in messages
|
|
103
103
|
- Tag specific findings with file:line references
|
|
104
|
-
- **
|
|
104
|
+
- **Always reply to the operator**: when the operator (sender: "user") sends a message that mentions you or is addressed to you, you MUST reply via `chat_send`. If it's a question, answer it. If it's an instruction, confirm what you will do, then do it. If it's not actionable for your role, reply explaining that and suggest which agent should handle it. The operator's terminal is invisible — if you don't `chat_send`, your response does not exist.
|
|
105
|
+
- **No acknowledgment messages between agents** — don't send "on it", "noted", "standing by" to other agents. This rule does NOT apply to operator messages — always reply to the operator.
|
|
106
|
+
- Only send unsolicited messages when delivering a completed review verdict. But ALWAYS reply when the operator addresses you directly — even if the message is not a review request. The operator may be asking about your status, giving instructions, or testing connectivity.
|
|
105
107
|
- **After merge confirmation from Head**: do NOT reply. The loop is complete — no acknowledgment needed.
|
|
@@ -101,5 +101,7 @@ Run this once at the start of each session.
|
|
|
101
101
|
- **After BLOCK**: send message to @head AND @dev — Head decides whether to reassign or close
|
|
102
102
|
- Always include PR number in messages
|
|
103
103
|
- Tag specific findings with file:line references
|
|
104
|
-
- **
|
|
104
|
+
- **Always reply to the operator**: when the operator (sender: "user") sends a message that mentions you or is addressed to you, you MUST reply via `chat_send`. If it's a question, answer it. If it's an instruction, confirm what you will do, then do it. If it's not actionable for your role, reply explaining that and suggest which agent should handle it. The operator's terminal is invisible — if you don't `chat_send`, your response does not exist.
|
|
105
|
+
- **No acknowledgment messages between agents** — don't send "on it", "noted", "standing by" to other agents. This rule does NOT apply to operator messages — always reply to the operator.
|
|
106
|
+
- Only send unsolicited messages when delivering a completed review verdict. But ALWAYS reply when the operator addresses you directly — even if the message is not a review request. The operator may be asking about your status, giving instructions, or testing connectivity.
|
|
105
107
|
- **After merge confirmation from Head**: do NOT reply. The loop is complete — no acknowledgment needed.
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,15352,(e,t,n)=>{"use strict";Object.defineProperty(n,"__esModule",{value:!0}),Object.defineProperty(n,"BailoutToCSR",{enumerable:!0,get:function(){return l}});let r=e.r(17071);function l({reason:e,children:t}){if("u"<typeof window)throw Object.defineProperty(new r.BailoutToCSRError(e),"__NEXT_ERROR_CODE",{value:"E394",enumerable:!1,configurable:!0});return t}},87083,(e,t,n)=>{"use strict";function r(e){return e.split("/").map(e=>encodeURIComponent(e)).join("/")}Object.defineProperty(n,"__esModule",{value:!0}),Object.defineProperty(n,"encodeURIPath",{enumerable:!0,get:function(){return r}})},48021,(e,t,n)=>{"use strict";Object.defineProperty(n,"__esModule",{value:!0}),Object.defineProperty(n,"PreloadChunks",{enumerable:!0,get:function(){return a}});let r=e.r(85899),l=e.r(90184),u=e.r(27807),o=e.r(87083),s=e.r(7866);function a({moduleIds:e}){if("u">typeof window)return null;let t=u.workAsyncStorage.getStore();if(void 0===t)return null;let n=[];if(t.reactLoadableManifest&&e){let r=t.reactLoadableManifest;for(let t of e){if(!r[t])continue;let e=r[t].files;n.push(...e)}}if(0===n.length)return null;let i=(0,s.getAssetTokenQuery)();return(0,r.jsx)(r.Fragment,{children:n.map(e=>{let n=`${t.assetPrefix}/_next/${(0,o.encodeURIPath)(e)}${i}`;return e.endsWith(".css")?(0,r.jsx)("link",{precedence:"dynamic",href:n,rel:"stylesheet",as:"style",nonce:t.nonce},e):((0,l.preload)(n,{as:"script",fetchPriority:"low",nonce:t.nonce}),null)})})}},82525,(e,t,n)=>{"use strict";Object.defineProperty(n,"__esModule",{value:!0}),Object.defineProperty(n,"default",{enumerable:!0,get:function(){return i}});let r=e.r(85899),l=e.r(4232),u=e.r(15352),o=e.r(48021);function s(e){return{default:e&&"default"in e?e.default:e}}let a={loader:()=>Promise.resolve(s(()=>null)),loading:null,ssr:!0},i=function(e){let t={...a,...e},n=(0,l.lazy)(()=>t.loader().then(s)),i=t.loading;function d(e){let s=i?(0,r.jsx)(i,{isLoading:!0,pastDelay:!0,error:null}):null,a=!t.ssr||!!t.loading,d=a?l.Suspense:l.Fragment,c=t.ssr?(0,r.jsxs)(r.Fragment,{children:["u"<typeof window?(0,r.jsx)(o.PreloadChunks,{moduleIds:t.modules}):null,(0,r.jsx)(n,{...e})]}):(0,r.jsx)(u.BailoutToCSR,{reason:"next/dynamic",children:(0,r.jsx)(n,{...e})});return(0,r.jsx)(d,{...a?{fallback:s}:{},children:c})}return d.displayName="LoadableComponent",d}},52279,(e,t,n)=>{"use strict";Object.defineProperty(n,"__esModule",{value:!0}),Object.defineProperty(n,"default",{enumerable:!0,get:function(){return l}});let r=e.r(5581)._(e.r(82525));function l(e,t){let n={};"function"==typeof e&&(n.loader=e);let l={...n,...t};return(0,r.default)({...l,modules:l.loadableGenerated?.modules})}("function"==typeof n.default||"object"==typeof n.default&&null!==n.default)&&void 0===n.default.__esModule&&(Object.defineProperty(n.default,"__esModule",{value:!0}),Object.assign(n.default,n),t.exports=n.default)},66610,e=>{"use strict";var t=e.i(85899),n=e.i(52279),r=e.i(16353);let l=(0,n.default)(()=>e.A(34183),{loadableGenerated:{modules:[71714]},ssr:!1});e.s(["default",0,function(){let e=(0,r.usePathname)().split("/")[2]||"";return e&&"_"!==e?(0,t.jsx)("div",{className:"w-full h-full",children:(0,t.jsx)(l,{projectId:e})}):null}])},34183,e=>{e.v(t=>Promise.all(["static/chunks/0whtwwbpg72ar.js","static/chunks/0m83k84.midd1.js","static/chunks/17oc2l.ekcs8b.css"].map(t=>e.l(t))).then(()=>t(71714)))}]);
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,62206,(e,t,r)=>{"use strict";Object.defineProperty(r,"__esModule",{value:!0});var n={assign:function(){return l},searchParamsToUrlQuery:function(){return s},urlQueryToSearchParams:function(){return i}};for(var o in n)Object.defineProperty(r,o,{enumerable:!0,get:n[o]});function s(e){let t={};for(let[r,n]of e.entries()){let e=t[r];void 0===e?t[r]=n:Array.isArray(e)?e.push(n):t[r]=[e,n]}return t}function a(e){return"string"==typeof e?e:("number"!=typeof e||isNaN(e))&&"boolean"!=typeof e?"":String(e)}function i(e){let t=new URLSearchParams;for(let[r,n]of Object.entries(e))if(Array.isArray(n))for(let e of n)t.append(r,a(e));else t.set(r,a(n));return t}function l(e,...t){for(let r of t){for(let t of r.keys())e.delete(t);for(let[t,n]of r.entries())e.append(t,n)}return e}},71281,(e,t,r)=>{"use strict";Object.defineProperty(r,"__esModule",{value:!0});var n={DecodeError:function(){return g},MiddlewareNotFoundError:function(){return v},MissingStaticPage:function(){return y},NormalizeError:function(){return b},PageNotFoundError:function(){return j},SP:function(){return x},ST:function(){return m},WEB_VITALS:function(){return s},execOnce:function(){return a},getDisplayName:function(){return d},getLocationOrigin:function(){return u},getURL:function(){return c},isAbsoluteUrl:function(){return l},isResSent:function(){return f},loadGetInitialProps:function(){return p},normalizeRepeatedSlashes:function(){return h},stringifyError:function(){return w}};for(var o in n)Object.defineProperty(r,o,{enumerable:!0,get:n[o]});let s=["CLS","FCP","FID","INP","LCP","TTFB"];function a(e){let t,r=!1;return(...n)=>(r||(r=!0,t=e(...n)),t)}let i=/^[a-zA-Z][a-zA-Z\d+\-.]*?:/,l=e=>i.test(e);function u(){let{protocol:e,hostname:t,port:r}=window.location;return`${e}//${t}${r?":"+r:""}`}function c(){let{href:e}=window.location,t=u();return e.substring(t.length)}function d(e){return"string"==typeof e?e:e.displayName||e.name||"Unknown"}function f(e){return e.finished||e.headersSent}function h(e){let t=e.split("?");return t[0].replace(/\\/g,"/").replace(/\/\/+/g,"/")+(t[1]?`?${t.slice(1).join("?")}`:"")}async function p(e,t){let r=t.res||t.ctx&&t.ctx.res;if(!e.getInitialProps)return t.ctx&&t.Component?{pageProps:await p(t.Component,t.ctx)}:{};let n=await e.getInitialProps(t);if(r&&f(r))return n;if(!n)throw Object.defineProperty(Error(`"${d(e)}.getInitialProps()" should resolve to an object. But found "${n}" instead.`),"__NEXT_ERROR_CODE",{value:"E1025",enumerable:!1,configurable:!0});return n}let x="u">typeof performance,m=x&&["mark","measure","getEntriesByName"].every(e=>"function"==typeof performance[e]);class g extends Error{}class b extends Error{}class j extends Error{constructor(e){super(),this.code="ENOENT",this.name="PageNotFoundError",this.message=`Cannot find module for page: ${e}`}}class y extends Error{constructor(e,t){super(),this.message=`Failed to load static file for page: ${e} ${t}`}}class v extends Error{constructor(){super(),this.code="ENOENT",this.message="Cannot find the middleware module"}}function w(e){return JSON.stringify({message:e.message,stack:e.stack})}},11938,(e,t,r)=>{"use strict";Object.defineProperty(r,"__esModule",{value:!0}),Object.defineProperty(r,"warnOnce",{enumerable:!0,get:function(){return n}});let n=e=>{}},16353,(e,t,r)=>{t.exports=e.r(89093)},56749,(e,t,r)=>{"use strict";Object.defineProperty(r,"__esModule",{value:!0});var n={formatUrl:function(){return i},formatWithValidation:function(){return u},urlObjectKeys:function(){return l}};for(var o in n)Object.defineProperty(r,o,{enumerable:!0,get:n[o]});let s=e.r(60224)._(e.r(62206)),a=/https?|ftp|gopher|file/;function i(e){let{auth:t,hostname:r}=e,n=e.protocol||"",o=e.pathname||"",i=e.hash||"",l=e.query||"",u=!1;t=t?encodeURIComponent(t).replace(/%3A/i,":")+"@":"",e.host?u=t+e.host:r&&(u=t+(~r.indexOf(":")?`[${r}]`:r),e.port&&(u+=":"+e.port)),l&&"object"==typeof l&&(l=String(s.urlQueryToSearchParams(l)));let c=e.search||l&&`?${l}`||"";return n&&!n.endsWith(":")&&(n+=":"),e.slashes||(!n||a.test(n))&&!1!==u?(u="//"+(u||""),o&&"/"!==o[0]&&(o="/"+o)):u||(u=""),i&&"#"!==i[0]&&(i="#"+i),c&&"?"!==c[0]&&(c="?"+c),o=o.replace(/[?#]/g,encodeURIComponent),c=c.replace("#","%23"),`${n}${u}${o}${c}${i}`}let l=["auth","hash","host","hostname","href","path","pathname","port","protocol","query","search","slashes"];function u(e){return i(e)}},88173,(e,t,r)=>{"use strict";Object.defineProperty(r,"__esModule",{value:!0}),Object.defineProperty(r,"useMergedRef",{enumerable:!0,get:function(){return o}});let n=e.r(4232);function o(e,t){let r=(0,n.useRef)(null),o=(0,n.useRef)(null);return(0,n.useCallback)(n=>{if(null===n){let e=r.current;e&&(r.current=null,e());let t=o.current;t&&(o.current=null,t())}else e&&(r.current=s(e,n)),t&&(o.current=s(t,n))},[e,t])}function s(e,t){if("function"!=typeof e)return e.current=t,()=>{e.current=null};{let r=e(t);return"function"==typeof r?r:()=>e(null)}}("function"==typeof r.default||"object"==typeof r.default&&null!==r.default)&&void 0===r.default.__esModule&&(Object.defineProperty(r.default,"__esModule",{value:!0}),Object.assign(r.default,r),t.exports=r.default)},47244,(e,t,r)=>{"use strict";Object.defineProperty(r,"__esModule",{value:!0}),Object.defineProperty(r,"isLocalURL",{enumerable:!0,get:function(){return s}});let n=e.r(71281),o=e.r(17608);function s(e){if(!(0,n.isAbsoluteUrl)(e))return!0;try{let t=(0,n.getLocationOrigin)(),r=new URL(e,t);return r.origin===t&&(0,o.hasBasePath)(r.pathname)}catch(e){return!1}}},33010,(e,t,r)=>{"use strict";Object.defineProperty(r,"__esModule",{value:!0}),Object.defineProperty(r,"errorOnce",{enumerable:!0,get:function(){return n}});let n=e=>{}},2270,(e,t,r)=>{"use strict";Object.defineProperty(r,"__esModule",{value:!0});var n={default:function(){return g},useLinkStatus:function(){return j}};for(var o in n)Object.defineProperty(r,o,{enumerable:!0,get:n[o]});let s=e.r(60224),a=e.r(85899),i=s._(e.r(4232)),l=e.r(56749),u=e.r(4340),c=e.r(88173),d=e.r(71281),f=e.r(93614);e.r(11938);let h=e.r(77710),p=e.r(97991),x=e.r(47244),m=e.r(44367);function g(t){var r,n;let o,s,g,[j,y]=(0,i.useOptimistic)(p.IDLE_LINK_STATUS),v=(0,i.useRef)(null),{href:w,as:k,children:N,prefetch:E=null,passHref:P,replace:S,shallow:C,scroll:_,onClick:O,onMouseEnter:T,onTouchStart:L,legacyBehavior:R=!1,onNavigate:M,transitionTypes:A,ref:I,unstable_dynamicOnHover:$,...B}=t;o=N,R&&("string"==typeof o||"number"==typeof o)&&(o=(0,a.jsx)("a",{children:o}));let U=i.default.useContext(u.AppRouterContext),F=!1!==E,W=!1!==E?null===(n=E)||"auto"===n?m.FetchStrategy.PPR:m.FetchStrategy.Full:m.FetchStrategy.PPR,z="string"==typeof(r=k||w)?r:(0,l.formatUrl)(r);if(R){if(o?.$$typeof===Symbol.for("react.lazy"))throw Object.defineProperty(Error("`<Link legacyBehavior>` received a direct child that is either a Server Component, or JSX that was loaded with React.lazy(). This is not supported. Either remove legacyBehavior, or make the direct child a Client Component that renders the Link's `<a>` tag."),"__NEXT_ERROR_CODE",{value:"E863",enumerable:!1,configurable:!0});s=i.default.Children.only(o)}let D=R?s&&"object"==typeof s&&s.ref:I,q=i.default.useCallback(e=>(null!==U&&(v.current=(0,p.mountLinkInstance)(e,z,U,W,F,y)),()=>{v.current&&((0,p.unmountLinkForCurrentNavigation)(v.current),v.current=null),(0,p.unmountPrefetchableInstance)(e)}),[F,z,U,W,y]),K={ref:(0,c.useMergedRef)(q,D),onClick(t){R||"function"!=typeof O||O(t),R&&s.props&&"function"==typeof s.props.onClick&&s.props.onClick(t),!U||t.defaultPrevented||function(t,r,n,o,s,a,l){if("u">typeof window){let u,{nodeName:c}=t.currentTarget;if("A"===c.toUpperCase()&&((u=t.currentTarget.getAttribute("target"))&&"_self"!==u||t.metaKey||t.ctrlKey||t.shiftKey||t.altKey||t.nativeEvent&&2===t.nativeEvent.which)||t.currentTarget.hasAttribute("download"))return;if(!(0,x.isLocalURL)(r)){o&&(t.preventDefault(),location.replace(r));return}if(t.preventDefault(),a){let e=!1;if(a({preventDefault:()=>{e=!0}}),e)return}let{dispatchNavigateAction:d}=e.r(93845);i.default.startTransition(()=>{d(r,o?"replace":"push",!1===s?h.ScrollBehavior.NoScroll:h.ScrollBehavior.Default,n.current,l)})}}(t,z,v,S,_,M,A)},onMouseEnter(e){R||"function"!=typeof T||T(e),R&&s.props&&"function"==typeof s.props.onMouseEnter&&s.props.onMouseEnter(e),U&&F&&(0,p.onNavigationIntent)(e.currentTarget,!0===$)},onTouchStart:function(e){R||"function"!=typeof L||L(e),R&&s.props&&"function"==typeof s.props.onTouchStart&&s.props.onTouchStart(e),U&&F&&(0,p.onNavigationIntent)(e.currentTarget,!0===$)}};return(0,d.isAbsoluteUrl)(z)?K.href=z:R&&!P&&("a"!==s.type||"href"in s.props)||(K.href=(0,f.addBasePath)(z)),g=R?i.default.cloneElement(s,K):(0,a.jsx)("a",{...B,...K,children:o}),(0,a.jsx)(b.Provider,{value:j,children:g})}e.r(33010);let b=(0,i.createContext)(p.IDLE_LINK_STATUS),j=()=>(0,i.useContext)(b);("function"==typeof r.default||"object"==typeof r.default&&null!==r.default)&&void 0===r.default.__esModule&&(Object.defineProperty(r.default,"__esModule",{value:!0}),Object.assign(r.default,r),t.exports=r.default)},86081,e=>{"use strict";var t=e.i(85899),r=e.i(2270),n=e.i(16353),o=e.i(4232);function s(){return(0,t.jsxs)("svg",{width:"20",height:"20",viewBox:"0 0 20 20",fill:"none",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round",children:[(0,t.jsx)("path",{d:"M3 10L10 3l7 7"}),(0,t.jsx)("path",{d:"M5 8.5V16h3.5v-4h3v4H15V8.5"})]})}function a(){return(0,t.jsxs)("svg",{width:"18",height:"18",viewBox:"0 0 18 18",fill:"none",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round",children:[(0,t.jsx)("circle",{cx:"9",cy:"9",r:"2.5"}),(0,t.jsx)("path",{d:"M7.5 1.5h3l.4 2.1a5.5 5.5 0 011.3.7l2-.8 1.5 2.6-1.6 1.3a5.5 5.5 0 010 1.5l1.6 1.3-1.5 2.6-2-.8a5.5 5.5 0 01-1.3.7l-.4 2.1h-3l-.4-2.1a5.5 5.5 0 01-1.3-.7l-2 .8-1.5-2.6 1.6-1.3a5.5 5.5 0 010-1.5L2.3 6.1l1.5-2.6 2 .8a5.5 5.5 0 011.3-.7z"})]})}function i(){return(0,t.jsx)("svg",{width:"16",height:"16",viewBox:"0 0 16 16",fill:"none",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",children:(0,t.jsx)("path",{d:"M8 3v10M3 8h10"})})}function l({project:e,isActive:n}){let[s,a]=(0,o.useState)(null),i=(0,o.useRef)(null);return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(r.default,{ref:i,href:`/project/${e.id}`,onMouseEnter:()=>{let e=i.current?.getBoundingClientRect();e&&a({top:e.top+e.height/2})},onMouseLeave:()=>a(null),children:(0,t.jsx)("div",{className:`w-10 h-10 flex items-center justify-center rounded-full text-[11px] font-semibold uppercase tracking-tight transition-colors ${n?"border-2 border-accent text-accent":"border border-border text-text-muted hover:text-text hover:bg-[#1a1a1a]"}`,children:e.name.slice(0,2)||"?"})}),s&&(0,t.jsx)("div",{className:"fixed px-2 py-1 bg-bg-surface border border-border text-text text-xs whitespace-nowrap pointer-events-none z-50",style:{left:72,top:s.top,transform:"translateY(-50%)"},children:e.name})]})}e.s(["default",0,function(){let e=(0,n.usePathname)(),[u,c]=(0,o.useState)([]),[d,f]=(0,o.useState)("online");(0,o.useEffect)(()=>{fetch("/api/config").then(e=>{if(!e.ok)throw Error(`Config fetch failed: ${e.status}`);return e.json()}).then(e=>c((e.projects||[]).filter(e=>!e.archived))).catch(()=>{})},[]),(0,o.useEffect)(()=>{let e,t=!1,r=async()=>{try{let e=await fetch("/api/health",{signal:AbortSignal.timeout(3e3)});if(t)return;e.ok?f(e=>"offline"===e?"recovering":"online"):f("offline")}catch{if(t)return;f("offline")}t||(e=setTimeout(r,5e3))};return r(),()=>{t=!0,clearTimeout(e)}},[]),(0,o.useEffect)(()=>{if("recovering"===d){let e=setTimeout(()=>f("online"),1500);return()=>clearTimeout(e)}},[d]);let h="/"===e,p="/settings"===e,x=e.startsWith("/project/")?e.split("/")[2]:null;return(0,t.jsxs)("aside",{className:"w-16 shrink-0 h-full border-r border-border bg-bg-surface flex flex-col items-center py-3",children:[(0,t.jsx)(r.default,{href:"/",className:`w-10 h-10 flex items-center justify-center rounded-sm transition-colors ${h?"text-accent":"text-text-muted hover:text-text hover:bg-[#1a1a1a]"}`,title:"Home",children:(0,t.jsx)(s,{})}),(0,t.jsx)("div",{className:"w-6 h-px bg-border my-2"}),(0,t.jsxs)("div",{className:"flex-1 flex flex-col items-center gap-2 overflow-y-auto min-h-0",children:[u.map(e=>{let r=x===e.id;return(0,t.jsx)(l,{project:e,isActive:r},e.id)}),(0,t.jsx)(r.default,{href:"/setup",className:"w-10 h-10 flex items-center justify-center rounded-full border border-dashed border-border text-text-muted hover:text-text hover:bg-[#1a1a1a] transition-colors",title:"Add project",children:(0,t.jsx)(i,{})})]}),(0,t.jsx)("div",{className:"w-6 h-px bg-border my-2"}),"online"!==d&&(0,t.jsxs)("div",{className:"mb-2 relative group",children:[(0,t.jsx)("div",{className:`w-3 h-3 rounded-full ${"offline"===d?"bg-red-500 animate-pulse":"bg-green-500"}`}),(0,t.jsx)("div",{className:"fixed left-16 ml-2 px-2 py-1 bg-bg-surface border border-border text-xs whitespace-nowrap z-50 hidden group-hover:block",style:{transform:"translateY(-50%)",top:"auto"},children:"offline"===d?"Backend offline — run quadwork start":"Backend reconnected"})]}),(0,t.jsx)(r.default,{href:"/settings",className:`w-10 h-10 flex items-center justify-center rounded-sm transition-colors ${p?"text-accent":"text-text-muted hover:text-text hover:bg-[#1a1a1a]"}`,title:"Settings",children:(0,t.jsx)(a,{})})]})}])},34852,e=>{"use strict";var t=e.i(85899),r=e.i(2270),n=e.i(4232);function o({open:e,onClose:r}){return((0,n.useEffect)(()=>{if(!e)return;let t=e=>{"Escape"===e.key&&r()};return window.addEventListener("keydown",t),()=>window.removeEventListener("keydown",t)},[e,r]),e)?(0,t.jsx)("div",{className:"fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-sm",onClick:r,role:"dialog","aria-modal":"true","aria-labelledby":"about-title",children:(0,t.jsxs)("div",{className:"relative mx-4 max-w-lg w-full rounded-lg border border-white/10 bg-neutral-950 p-6 shadow-2xl",onClick:e=>e.stopPropagation(),children:[(0,t.jsx)("button",{type:"button",onClick:r,"aria-label":"Close",className:"absolute right-3 top-3 rounded p-1 text-neutral-400 hover:bg-white/5 hover:text-white",children:(0,t.jsx)("svg",{width:"18",height:"18",viewBox:"0 0 20 20",fill:"none",stroke:"currentColor",strokeWidth:"1.8",children:(0,t.jsx)("path",{d:"M4 4l12 12M16 4L4 16",strokeLinecap:"round"})})}),(0,t.jsx)("h2",{id:"about-title",className:"text-lg font-semibold text-white",children:"What is QuadWork?"}),(0,t.jsx)("p",{className:"mt-3 text-sm leading-relaxed text-neutral-300",children:"QuadWork is a local dashboard that runs a team of 4 AI agents — Head, Dev, and two Reviewers — that code, review, and ship while you sleep."}),(0,t.jsx)("p",{className:"mt-3 text-sm leading-relaxed text-neutral-300",children:"Every task follows a strict GitHub workflow: Issue → Branch → Pull Request → 2 Reviews → Merge. Branch protection ensures no agent can skip the process."}),(0,t.jsx)("h3",{className:"mt-5 text-sm font-semibold text-white",children:"Why QuadWork?"}),(0,t.jsxs)("ul",{className:"mt-2 space-y-1.5 text-sm text-neutral-300",children:[(0,t.jsxs)("li",{children:["🤖 ",(0,t.jsx)("b",{children:"Run 24/7"})," — agents work overnight while you rest"]}),(0,t.jsxs)("li",{children:["🛡️ ",(0,t.jsx)("b",{children:"Always reviewed"})," — every PR needs 2 independent approvals"]}),(0,t.jsxs)("li",{children:["🔒 ",(0,t.jsx)("b",{children:"Local-first"})," — runs entirely on your machine, no data leaves"]}),(0,t.jsxs)("li",{children:["🧰 ",(0,t.jsx)("b",{children:"Bring your own CLI"})," — works with Claude Code, Codex, or both"]}),(0,t.jsxs)("li",{children:["📦 ",(0,t.jsx)("b",{children:"One install"})," — ",(0,t.jsx)("code",{className:"rounded bg-white/5 px-1 py-0.5 text-[12px]",children:"npx quadwork init"})," and you're set"]})]}),(0,t.jsx)("div",{className:"mt-5",children:(0,t.jsx)("a",{href:"https://github.com/realproject7/quadwork",target:"_blank",rel:"noopener noreferrer",className:"inline-flex items-center gap-1 text-sm text-blue-400 hover:text-blue-300",children:"Read the full docs on GitHub →"})})]})}):null}let s=["sleep.","eat.","enjoy life.","touch grass.","spend time with people.","watch a movie.","take a vacation.","go for a run."],a="quadwork_tagline_animation";function i(e){return!Number.isFinite(e)||e<=0?"0h":e<1?`${(60*e).toFixed(0)}m`:`${e.toFixed(1)}h`}e.s(["default",0,function(){let[e,l]=(0,n.useState)(!1);(0,n.useEffect)(()=>{l(!0)},[]);let[u,c]=(0,n.useState)(!1),[d,f]=(0,n.useState)(null),[h,p]=(0,n.useState)(!1);(0,n.useEffect)(()=>{let e=!1,t=()=>{fetch("/api/activity/stats").then(e=>e.ok?e.json():null).then(t=>{!e&&t&&f(t)}).catch(()=>{})};t();let r=setInterval(t,6e4);return()=>{e=!0,clearInterval(r)}},[]);let[x,m]=(0,n.useState)(!0);(0,n.useEffect)(()=>{try{let e=window.localStorage.getItem(a);"off"===e&&m(!1)}catch{}},[]);let g=function(e,t){let[r,o]=(0,n.useState)(0),[s,a]=(0,n.useState)(""),[i,l]=(0,n.useState)("typing");return(0,n.useEffect)(()=>{let n;if(!t)return;let u=e[r];return"typing"===i?n=s.length<u.length?setTimeout(()=>a(u.slice(0,s.length+1)),70):setTimeout(()=>l("holding"),0):"holding"===i?n=setTimeout(()=>l("deleting"),2e3):s.length>0?n=setTimeout(()=>a(u.slice(0,s.length-1)),35):(o(t=>(t+1)%e.length),l("typing")),()=>clearTimeout(n)},[s,i,r,e,t]),s}(s,x),b=x?g:s[0]||"",[j,y]=(0,n.useState)(!1);(0,n.useEffect)(()=>{if(!x)return void y(!0);let e=setTimeout(()=>y(!0),5e3);return()=>clearTimeout(e)},[x]);let v=(0,n.useRef)(!1);return((0,n.useEffect)(()=>{x&&(g.length>0?v.current=!0:v.current&&y(!0))},[x,g]),e)?(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)("header",{className:"sticky top-0 z-40 flex h-12 items-center justify-between border-b border-white/10 bg-neutral-950/90 px-4 backdrop-blur",children:[(0,t.jsxs)("div",{className:"flex items-center gap-3 min-w-0",children:[(0,t.jsx)(r.default,{href:"/",className:"text-sm font-bold text-white hover:text-blue-400 shrink-0",children:"QuadWork"}),(0,t.jsx)("span",{className:"hidden sm:inline text-neutral-600",children:"|"}),(0,t.jsxs)("span",{className:"hidden sm:inline text-[13px] text-neutral-400 truncate",children:["Your AI dev team while you"," ",(0,t.jsx)("span",{className:"text-neutral-200",children:b}),x&&(0,t.jsx)("span",{className:"ml-0.5 inline-block w-[1px] h-[12px] align-middle bg-neutral-400 animate-qw-blink"})]}),j&&(0,t.jsx)("button",{type:"button",onClick:()=>{m(e=>{let t=!e;try{window.localStorage.setItem(a,t?"on":"off")}catch{}return t})},"aria-label":x?"Pause tagline animation":"Resume tagline animation","aria-pressed":x,title:x?"Pause tagline animation":"Resume tagline animation",className:"hidden sm:inline-flex items-center justify-center w-3.5 h-3.5 ml-1 rounded-full border border-white/15 text-neutral-500 hover:text-white hover:border-white/40 transition-colors text-[8px]",children:x?"❚❚":"▶"})]}),(0,t.jsxs)("div",{className:"flex items-center gap-3 shrink-0",children:[d&&(0,t.jsxs)("div",{className:"relative hidden md:flex items-center gap-2 text-[10px] text-neutral-500",onMouseEnter:()=>p(!0),onMouseLeave:()=>p(!1),onFocus:()=>p(!0),onBlur:()=>p(!1),tabIndex:0,children:[(0,t.jsx)("span",{className:"text-neutral-200",children:"Your AI team worked:"}),(0,t.jsxs)("span",{children:["Today ",(0,t.jsx)("span",{className:"text-neutral-200",children:i(d.today)})]}),(0,t.jsx)("span",{className:"text-neutral-700",children:"·"}),(0,t.jsxs)("span",{children:["Week ",(0,t.jsx)("span",{className:"text-neutral-200",children:i(d.week)})]}),(0,t.jsx)("span",{className:"text-neutral-700",children:"·"}),(0,t.jsxs)("span",{children:["Month ",(0,t.jsx)("span",{className:"text-neutral-200",children:i(d.month)})]}),h&&(0,t.jsxs)("div",{className:"absolute top-6 right-0 z-50 min-w-[220px] p-2 text-[10px] leading-snug text-neutral-200 bg-neutral-900 border border-white/15 rounded shadow-lg",children:[(0,t.jsx)("div",{className:"mb-1 text-neutral-400 uppercase tracking-wider text-[9px]",children:"Per project"}),0===Object.entries(d.by_project).length&&(0,t.jsx)("div",{className:"text-neutral-500",children:"No activity logged yet"}),Object.entries(d.by_project).map(([e,r])=>(0,t.jsxs)("div",{className:"flex items-baseline gap-2",children:[(0,t.jsx)("span",{className:"text-neutral-400 truncate flex-1",children:e}),(0,t.jsx)("span",{className:"tabular-nums text-neutral-200",children:i(r.month)}),(0,t.jsx)("span",{className:"text-neutral-600 text-[9px]",children:"/ mo"})]},e)),(0,t.jsxs)("div",{className:"mt-1 pt-1 border-t border-white/10 text-neutral-500",children:["Lifetime: ",(0,t.jsx)("span",{className:"text-neutral-200",children:i(d.total)})]}),(0,t.jsx)("div",{className:"mt-1 pt-1 border-t border-white/10 text-neutral-500 leading-snug",children:"ⓘ Stats are best-effort. Server restarts may undercount in-flight sessions."})]})]}),(0,t.jsx)("button",{type:"button",onClick:()=>c(!0),"aria-label":"About QuadWork",className:"rounded p-1 text-neutral-400 hover:bg-white/5 hover:text-white",children:(0,t.jsxs)("svg",{width:"18",height:"18",viewBox:"0 0 20 20",fill:"none",stroke:"currentColor",strokeWidth:"1.5",children:[(0,t.jsx)("circle",{cx:"10",cy:"10",r:"8"}),(0,t.jsx)("path",{d:"M10 9v5",strokeLinecap:"round"}),(0,t.jsx)("circle",{cx:"10",cy:"6.5",r:"0.8",fill:"currentColor"})]})}),(0,t.jsx)("a",{href:"https://github.com/realproject7/quadwork",target:"_blank",rel:"noopener noreferrer",className:"text-[12px] text-neutral-400 hover:text-white",children:"QuadWork github"})]})]}),(0,t.jsx)(o,{open:u,onClose:()=>c(!1)})]}):(0,t.jsx)("header",{className:"sticky top-0 z-40 flex h-12 items-center justify-between border-b border-white/10 bg-neutral-950/90 px-4 backdrop-blur","aria-hidden":"true"})}],34852)}]);
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,64618,e=>{"use strict";var t=e.i(24046),s=e.i(85899),a=e.i(4232),r=e.i(16353);let c=[{id:"name",label:"Project Name",subtitle:"Name your project",status:"active"},{id:"repo",label:"GitHub Repo",subtitle:"Connect a repository",status:"pending"},{id:"models",label:"Agent Models",subtitle:"Configure CLI backends",status:"pending"},{id:"workdir",label:"Working Directory",subtitle:"Set the local path",status:"pending"},{id:"workspaces",label:"Create Workspaces",subtitle:"Worktrees + seed files",status:"pending"},{id:"launch",label:"Ready to Launch",subtitle:"Review & start",status:"pending"}],n=[{value:"claude",label:"Claude Code"},{value:"codex",label:"Codex"}],o=[{key:"head",label:"T1 — Head",role:"Owner / Final Guard",desc:"Merges PRs, makes final calls"},{key:"reviewer1",label:"T2a — Reviewer 1",role:"Design Reviewer",desc:"Reviews architecture & design"},{key:"reviewer2",label:"T2b — Reviewer 2",role:"Code Reviewer",desc:"Reviews implementation quality"},{key:"dev",label:"T3 — Developer",role:"Full-Stack Builder",desc:"Implements features & fixes"}];function l({repo:e,workingDir:t,setWorkingDir:r,error:c,onNext:n}){let[o,i]=(0,a.useState)(!0),[x,d]=(0,a.useState)(null),[p,m]=(0,a.useState)(!1),u=e?e.split("/")[1]:"project";return(0,a.useEffect)(()=>{e?fetch(`/api/setup/detect-clone?repo=${encodeURIComponent(e)}`).then(e=>e.ok?e.json():null).then(e=>{d(e),e?.found&&e.path?r(e.path):e?.suggested&&r(e.suggested),i(!1)}).catch(()=>i(!1)):i(!1)},[e,r]),(0,s.jsxs)("div",{children:[(0,s.jsx)("h2",{className:"text-sm font-semibold text-text mb-1",children:"Where is your project?"}),(0,s.jsx)("p",{className:"text-[11px] text-text-muted mb-3",children:"Your project's git repository on your local machine. QuadWork will create 4 agent workspaces next to this directory."}),o&&(0,s.jsx)("p",{className:"text-[11px] text-text-muted mb-3",children:"Scanning for existing clone..."}),!o&&x?.found&&(0,s.jsxs)("div",{className:"border border-accent/30 bg-accent/5 p-3 mb-4 text-[11px]",children:[(0,s.jsx)("p",{className:"text-accent font-semibold mb-1",children:"Found existing clone"}),(0,s.jsx)("p",{className:"text-text font-mono",children:x.path}),(0,s.jsxs)("div",{className:"flex gap-2 mt-2",children:[(0,s.jsx)("button",{onClick:n,className:"px-3 py-1 bg-accent text-bg text-[11px] font-semibold hover:bg-accent-dim transition-colors",children:"Use this"}),(0,s.jsx)("button",{onClick:()=>{m(!0),r("")},className:"px-3 py-1 text-[11px] text-text-muted border border-border hover:text-text transition-colors",children:"Choose different path"})]})]}),!o&&!x?.found&&!p&&(0,s.jsxs)("div",{className:"border border-border bg-bg-surface p-3 mb-4 text-[11px]",children:[(0,s.jsxs)("p",{className:"text-text-muted mb-1",children:["No local clone found for ",(0,s.jsx)("span",{className:"text-accent",children:e})]}),(0,s.jsx)("p",{className:"text-text-muted mb-2",children:"Setup will clone it to:"}),(0,s.jsx)("p",{className:"text-text font-mono mb-2",children:x?.suggested||`~/Projects/${u}`}),(0,s.jsxs)("div",{className:"flex gap-2",children:[(0,s.jsx)("button",{onClick:n,disabled:!t.trim(),className:"px-3 py-1 bg-accent text-bg text-[11px] font-semibold hover:bg-accent-dim transition-colors disabled:opacity-50",children:"Clone here & continue"}),(0,s.jsx)("button",{onClick:()=>m(!0),className:"px-3 py-1 text-[11px] text-text-muted border border-border hover:text-text transition-colors",children:"Choose different path"})]})]}),(p||!o&&!x)&&(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)("input",{value:t,onChange:e=>r(e.target.value),placeholder:`~/Projects/${u}`,className:"w-full bg-transparent border border-border px-2 py-1.5 text-[12px] text-text outline-none focus:border-accent mb-2"}),(0,s.jsx)("button",{onClick:n,disabled:!t.trim(),className:"px-4 py-1.5 bg-accent text-bg text-[12px] font-semibold hover:bg-accent-dim transition-colors disabled:opacity-50",children:"Next"})]}),c&&(0,s.jsx)("p",{className:"text-[11px] text-error mt-2",children:c}),(0,s.jsxs)("div",{className:"border border-border bg-bg-surface p-3 mt-4 text-[11px] text-text-muted font-mono space-y-0.5",children:[(0,s.jsx)("p",{className:"text-[10px] uppercase tracking-wider text-text-muted mb-1 font-sans",children:"Workspace layout"}),(0,s.jsxs)("p",{className:"text-accent",children:[u,"/ ← your repo"]}),(0,s.jsxs)("p",{children:[u,"-head/ ← Head agent"]}),(0,s.jsxs)("p",{children:[u,"-dev/ ← Dev agent"]}),(0,s.jsxs)("p",{children:[u,"-reviewer1/ ← Reviewer1"]}),(0,s.jsxs)("p",{children:[u,"-reviewer2/ ← Reviewer2"]})]})]})}e.s(["default",0,function(){let e=(0,r.useRouter)(),[i,x]=(0,a.useState)(c),[d,p]=(0,a.useState)(0),[m,u]=(0,a.useState)(""),[h,b]=(0,a.useState)(""),[g,j]=(0,a.useState)(""),[f,v]=(0,a.useState)([]),[N,k]=(0,a.useState)(!1),[y,w]=(0,a.useState)(!1),[C,S]=(0,a.useState)(""),[_,R]=(0,a.useState)(!1),[T,H]=(0,a.useState)({head:"claude",reviewer1:"claude",reviewer2:"claude",dev:"claude"}),[P,$]=(0,a.useState)(!0),[q,A]=(0,a.useState)(!1),[I,L]=(0,a.useState)(""),[E,F]=(0,a.useState)("paste"),[U,W]=(0,a.useState)(""),[D,G]=(0,a.useState)("~/.quadwork/reviewer-token"),[O,B]=(0,a.useState)(""),[M,Y]=(0,a.useState)({}),[z,J]=(0,a.useState)(!1),[K,V]=(0,a.useState)([]),[X,Q]=(0,a.useState)("idle"),[Z,ee]=(0,a.useState)(!1),[et,es]=(0,a.useState)({chattr:0,mcpHttp:0,mcpSse:0}),[ea,er]=(0,a.useState)({chattr:"",mcpHttp:"",mcpSse:""}),ec=e=>{let t=parseInt(ea[e],10),s=Number.isFinite(t)&&t>0&&t<=65535?t:0;es(t=>({...t,[e]:s})),er(t=>({...t,[e]:s?String(s):""}))},[en,eo]=(0,a.useState)({chattr:0,mcpHttp:0,mcpSse:0}),[el,ei]=(0,a.useState)(null);(0,a.useEffect)(()=>{fetch("/api/cli-status").then(e=>e.json()).then(e=>{ei(e);let t=e.claude&&!e.codex?"claude":!e.claude&&e.codex?"codex":null;t?H({head:t,reviewer1:t,reviewer2:t,dev:t}):e.claude&&e.codex&&H({head:"codex",dev:"claude",reviewer1:"codex",reviewer2:"claude"})}).catch(()=>{})},[]),(0,a.useEffect)(()=>{fetch("/api/github/user").then(e=>e.json()).then(e=>{e.login&&S(e.login)}).catch(()=>{})},[]),(0,a.useEffect)(()=>{C&&(k(!0),fetch(`/api/github/repos?owner=${encodeURIComponent(C)}`).then(e=>e.json()).then(e=>{Array.isArray(e)&&v(e)}).catch(()=>{}).finally(()=>k(!1)))},[C]);let ex=(0,a.useCallback)((e,t)=>{x(s=>s.map((s,a)=>a===e?{...s,...t}:s))},[]),ed=(0,a.useCallback)(()=>{x(e=>e.map((e,t)=>t===d?{...e,status:"done"}:t===d+1?{...e,status:"active"}:e)),p(e=>e+1)},[d]),ep=async(e,t)=>{J(!0);try{let s=await fetch(`/api/setup?step=${e}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)}),a=await s.json();return J(!1),a}catch{return J(!1),{ok:!1,error:"Request failed"}}},em=async()=>{let e=await ep("verify-repo",{repo:h});e.ok?ed():ex(d,{status:"error",error:e.error})},eu=async()=>{if(J(!0),V([]),q&&"paste"===E&&U){V(e=>[...e,"Saving reviewer token..."]);try{let e=await fetch("/api/setup/save-token",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({token:U})}),t=await e.json();t.ok&&V(e=>[...e,`Token saved to ${t.path}`])}catch{}}V(e=>[...e,"Creating worktrees..."]);let e=await ep("create-worktrees",{workingDir:O,repo:h});if(!e.ok){V(t=>[...t,`Error: ${e.errors?.join(", ")||e.error}`]),ex(d,{status:"error",error:e.errors?.join(", ")||e.error}),J(!1);return}V(e=>[...e,"Worktrees created."]),V(e=>[...e,"Writing seed files..."]);let t=q?"file"===E?D:"~/.quadwork/reviewer-token":"",s=await ep("seed-files",{workingDir:O,projectName:m,repo:h,reviewerUser:q?I:"",reviewerTokenPath:t});if(!s.ok){V(e=>[...e,`Error: ${s.error}`]),ex(d,{status:"error",error:s.error}),J(!1);return}V(e=>[...e,"Seed files written."]),V(e=>[...e,"Done."]),J(!1),ed()},eh=async()=>{let t,s,a;ec("chattr"),ec("mcpHttp"),ec("mcpSse");let r=e=>{let t=ea[e];if(""!==t){let e=parseInt(t,10);return Number.isFinite(e)&&e>0&&e<=65535?e:0}return et[e]},c={chattr:r("chattr"),mcpHttp:r("mcpHttp"),mcpSse:r("mcpSse")};if(Q("running"),Z&&c.chattr>0){t=c.chattr,s=c.mcpHttp||c.chattr-100,a=c.mcpSse||s+1;let e=[t,s,a];try{let t=(await Promise.all(e.map(e=>fetch(`/api/port-check?port=${e}`).then(e=>e.json())))).filter(e=>!e.free).map(e=>e.port);if(t.length>0){Q("error"),ex(d,{status:"error",error:`Port${t.length>1?"s":""} ${t.join(", ")} already in use`});return}}catch{}}else if(en.chattr)t=en.chattr,s=en.mcpHttp,a=en.mcpSse;else try{let e=await fetch("/api/port-check/auto?start=8300&count=1"),r=await e.json(),c=await fetch("/api/port-check/auto?start=8200&count=2"),n=await c.json();t=r.ports?.[0]||8300,s=n.ports?.[0]||8200,a=n.ports?.[1]||8201}catch{t=8300,s=8200,a=8201}let n=await ep("agentchattr-config",{workingDir:O,projectName:m,repo:h,backends:T,agentchattr_port:t,mcp_http_port:s,mcp_sse_port:a});n.ok&&Y({agentchattr_token:n.agentchattr_token,agentchattr_port:n.agentchattr_port,mcp_http_port:n.mcp_http_port,mcp_sse_port:n.mcp_sse_port});let o=O.split("/").pop()||m.toLowerCase().replace(/\s+/g,"-").replace(/[^a-z0-9-]/g,""),l=await ep("add-config",{id:o,name:m,repo:h,workingDir:O,backends:T,auto_approve:P,...n.ok?{agentchattr_token:n.agentchattr_token,agentchattr_port:n.agentchattr_port,mcp_http_port:n.mcp_http_port,mcp_sse_port:n.mcp_sse_port}:M});l.ok?(Q("done"),ex(d,{status:"done"}),setTimeout(()=>e.push(`/project/${o}`),1200)):(Q("error"),ex(d,{status:"error",error:l.error}))};(0,a.useEffect)(()=>{i[d]?.id==="launch"&&(async()=>{try{let e=await fetch("/api/port-check/auto?start=8300&count=1"),t=await e.json(),s=await fetch("/api/port-check/auto?start=8200&count=2"),a=await s.json(),r={chattr:t.ports?.[0]||8300,mcpHttp:a.ports?.[0]||8200,mcpSse:a.ports?.[1]||8201};eo(r),et.chattr||(es(r),er({chattr:String(r.chattr),mcpHttp:String(r.mcpHttp),mcpSse:String(r.mcpSse)}))}catch{}})()},[d,i]);let eb=f.filter(e=>e.name.toLowerCase().includes(g.toLowerCase())),eg=i[d];return(0,s.jsxs)("div",{className:"h-full overflow-y-auto",children:[(0,s.jsxs)("div",{className:"px-6 pt-6 pb-4 border-b border-border",children:[(0,s.jsx)("h1",{className:"text-lg font-semibold text-text tracking-tight",children:"Set Up Your AI Dev Team"}),(0,s.jsx)("p",{className:"text-[11px] text-text-muted mt-1",children:"Configure agents, connect your repo, and launch a multi-agent development workflow in minutes."})]}),(0,s.jsxs)("div",{className:"flex h-[calc(100%-80px)]",children:[(0,s.jsxs)("div",{className:"flex-1 flex gap-6 p-6 overflow-y-auto",children:[(0,s.jsx)("div",{className:"w-44 shrink-0",children:i.map((e,t)=>(0,s.jsxs)("div",{className:"flex items-start gap-2 py-2",children:[(0,s.jsx)("span",{className:`w-5 h-5 flex items-center justify-center text-[10px] border shrink-0 mt-0.5 ${"done"===e.status?"border-accent text-accent":"error"===e.status?"border-error text-error":"active"===e.status?"border-accent text-accent bg-accent/10":"skipped"===e.status?"border-border text-text-muted line-through":"border-border text-text-muted"}`,children:"done"===e.status?"✓":"error"===e.status?"!":t+1}),(0,s.jsxs)("div",{children:[(0,s.jsx)("span",{className:`text-[11px] block leading-tight ${"active"===e.status?"text-text font-semibold":"done"===e.status?"text-accent":"text-text-muted"}`,children:e.label}),(0,s.jsx)("span",{className:"text-[10px] text-text-muted block",children:e.subtitle})]})]},e.id))}),(0,s.jsxs)("div",{className:"flex-1 border border-border p-5 min-h-0",children:[eg?.id==="name"&&(0,s.jsxs)("div",{children:[(0,s.jsx)("h2",{className:"text-sm font-semibold text-text mb-1",children:"Name your project"}),(0,s.jsx)("p",{className:"text-[11px] text-text-muted mb-4",children:"This name identifies your project in the dashboard and agent configs."}),(0,s.jsx)("input",{value:m,onChange:e=>u(e.target.value),placeholder:"e.g. My DeFi App",className:"w-full bg-transparent border border-border px-2 py-1.5 text-[12px] text-text outline-none focus:border-accent mb-4",autoFocus:!0}),(0,s.jsx)("button",{onClick:ed,disabled:!m.trim(),className:"px-4 py-1.5 bg-accent text-bg text-[12px] font-semibold hover:bg-accent-dim transition-colors disabled:opacity-50",children:"Next"})]}),eg?.id==="repo"&&(0,s.jsxs)("div",{children:[(0,s.jsx)("h2",{className:"text-sm font-semibold text-text mb-1",children:"Connect a GitHub repository"}),(0,s.jsx)("p",{className:"text-[11px] text-text-muted mb-4",children:"Select an existing repo or enter one manually. Agents will work within this repo."}),!y&&(0,s.jsxs)(s.Fragment,{children:[C&&(0,s.jsxs)("p",{className:"text-[11px] text-text-muted mb-2",children:["Showing repos for ",(0,s.jsx)("span",{className:"text-accent",children:C})]}),(0,s.jsx)("input",{value:g,onChange:e=>j(e.target.value),placeholder:"Search repos...",className:"w-full bg-transparent border border-border px-2 py-1.5 text-[12px] text-text outline-none focus:border-accent mb-2"}),N&&(0,s.jsx)("p",{className:"text-[11px] text-text-muted mb-2",children:"Loading..."}),(0,s.jsxs)("div",{className:"max-h-40 overflow-y-auto border border-border mb-3",children:[eb.map(e=>(0,s.jsxs)("button",{onClick:()=>b(`${C}/${e.name}`),className:`w-full text-left px-3 py-1.5 text-[11px] border-b border-border/50 last:border-b-0 hover:bg-accent/5 transition-colors ${h===`${C}/${e.name}`?"bg-accent/10 text-accent":"text-text"}`,children:[(0,s.jsx)("span",{className:"font-semibold",children:e.name}),e.isPrivate&&(0,s.jsx)("span",{className:"text-[10px] text-text-muted ml-2",children:"private"}),e.description&&(0,s.jsx)("span",{className:"text-[10px] text-text-muted ml-2",children:e.description})]},e.name)),!N&&0===eb.length&&(0,s.jsx)("p",{className:"px-3 py-2 text-[11px] text-text-muted",children:"No repos found."})]}),(0,s.jsx)("button",{onClick:()=>w(!0),className:"text-[11px] text-text-muted hover:text-accent transition-colors mb-3 block",children:"Enter manually instead"})]}),y&&(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)("input",{value:h,onChange:e=>b(e.target.value),placeholder:"owner/repo",className:"w-full bg-transparent border border-border px-2 py-1.5 text-[12px] text-text outline-none focus:border-accent mb-2"}),(0,s.jsx)("button",{onClick:()=>w(!1),className:"text-[11px] text-text-muted hover:text-accent transition-colors mb-3 block",children:"Back to repo list"})]}),(0,s.jsxs)("label",{className:"flex items-center gap-2 mb-4 cursor-pointer",children:[(0,s.jsx)("input",{type:"checkbox",checked:_,onChange:e=>R(e.target.checked),className:"accent-accent"}),(0,s.jsxs)("span",{className:"text-[11px] text-text-muted",children:["Enable branch protection on ",(0,s.jsx)("code",{className:"text-accent",children:"main"})]})]}),_&&(0,s.jsxs)("div",{className:"border border-border bg-bg-surface p-3 mb-4 text-[11px] space-y-2",children:[(0,s.jsx)("p",{className:"text-text-muted",children:"Run this after setup, or configure in GitHub UI:"}),(0,s.jsxs)("div",{className:"flex items-center gap-2",children:[(0,s.jsx)("code",{className:"text-accent flex-1 select-all text-[10px] break-all",children:`gh api repos/${h||"owner/repo"}/branches/main/protection -X PUT -f "required_pull_request_reviews[required_approving_review_count]=1" -f "enforce_admins=false" -f "required_status_checks=null" -f "restrictions=null"`}),(0,s.jsx)("button",{onClick:()=>navigator.clipboard.writeText(`gh api repos/${h}/branches/main/protection -X PUT -f "required_pull_request_reviews[required_approving_review_count]=1" -f "enforce_admins=false" -f "required_status_checks=null" -f "restrictions=null"`),className:"text-[10px] text-text-muted hover:text-accent shrink-0",children:"copy"})]})]}),eg.error&&(0,s.jsx)("p",{className:"text-[11px] text-error mb-2",children:eg.error}),(0,s.jsx)("button",{onClick:em,disabled:!h||z,className:"px-4 py-1.5 bg-accent text-bg text-[12px] font-semibold hover:bg-accent-dim transition-colors disabled:opacity-50",children:z?"Verifying...":"Verify & Continue"})]}),eg?.id==="models"&&(0,s.jsxs)("div",{children:[(0,s.jsx)("h2",{className:"text-sm font-semibold text-text mb-1",children:"Configure agent CLI backends"}),(0,s.jsx)("p",{className:"text-[11px] text-text-muted mb-4",children:"Each agent runs its own CLI instance. Pick the backend for each role."}),el&&!el.claude&&el.codex&&(0,s.jsxs)("div",{className:"border border-accent/20 bg-accent/5 p-3 mb-4 text-[11px]",children:[(0,s.jsx)("p",{className:"text-text",children:"You have Codex CLI installed — great! All 4 agents will use Codex."}),(0,s.jsx)("p",{className:"text-text-muted mt-1.5",children:"Tip: Installing Claude Code too gives your team different AI perspectives, which can improve code review quality. You can add it anytime:"}),(0,s.jsx)("p",{className:"text-accent mt-1 font-mono text-[10px]",children:"npm install -g @anthropic-ai/claude-code"}),(0,s.jsx)("p",{className:"text-text-muted mt-1.5",children:"For now, Codex CLI handles everything perfectly. Let's continue!"})]}),el&&el.claude&&!el.codex&&(0,s.jsxs)("div",{className:"border border-accent/20 bg-accent/5 p-3 mb-4 text-[11px]",children:[(0,s.jsx)("p",{className:"text-text",children:"You have Claude Code installed — great! All 4 agents will use Claude."}),(0,s.jsx)("p",{className:"text-text-muted mt-1.5",children:"Tip: Installing Codex CLI too gives your team different AI perspectives, which can improve code review quality. You can add it anytime:"}),(0,s.jsx)("p",{className:"text-accent mt-1 font-mono text-[10px]",children:"npm install -g codex"}),(0,s.jsx)("p",{className:"text-text-muted mt-1.5",children:"For now, Claude Code handles everything perfectly. Let's continue!"})]}),(0,s.jsx)("div",{className:"border border-border mb-4",children:o.map(e=>(0,s.jsxs)("div",{className:"flex items-center justify-between px-3 py-2 border-b border-border/50 last:border-b-0",children:[(0,s.jsxs)("div",{className:"flex-1 min-w-0",children:[(0,s.jsx)("span",{className:"text-[11px] text-text font-semibold block",children:e.label}),(0,s.jsx)("span",{className:"text-[10px] text-text-muted",children:e.desc})]}),(0,s.jsx)("select",{value:T[e.key],onChange:t=>H({...T,[e.key]:t.target.value}),className:"bg-transparent border border-border px-2 py-0.5 text-[11px] text-text outline-none focus:border-accent cursor-pointer ml-3",children:n.map(e=>(0,s.jsxs)("option",{value:e.value,className:"bg-bg-surface",disabled:!!el&&!el[e.value],children:[e.label,el&&!el[e.value]?" (not installed)":""]},e.value))})]},e.key))}),(0,s.jsxs)("label",{className:"flex items-center gap-2 mb-3 cursor-pointer",title:"Enable permission bypass flags so agents can work autonomously without prompting for approval on every action",children:[(0,s.jsx)("input",{type:"checkbox",checked:P,onChange:e=>$(e.target.checked),className:"accent-accent"}),(0,s.jsx)("span",{className:"text-[11px] text-text",children:"Auto-approve agent actions"}),(0,s.jsx)("span",{className:"text-[10px] text-text-muted",children:"(required for autonomous work)"})]}),(0,s.jsxs)("label",{className:"flex items-center gap-2 mb-3 cursor-pointer",children:[(0,s.jsx)("input",{type:"checkbox",checked:q,onChange:e=>A(e.target.checked),className:"accent-accent"}),(0,s.jsx)("span",{className:"text-[11px] text-text-muted",children:"Configure reviewer credentials (for GitHub PR reviews)"})]}),q&&(0,s.jsxs)("div",{className:"border border-border p-3 mb-4 space-y-3",children:[(0,s.jsxs)("div",{children:[(0,s.jsx)("label",{className:"text-[11px] text-text-muted block mb-1",children:"Reviewer GitHub username"}),(0,s.jsx)("input",{value:I,onChange:e=>L(e.target.value),placeholder:"github-username",className:"w-full bg-transparent border border-border px-2 py-1.5 text-[12px] text-text outline-none focus:border-accent"})]}),(0,s.jsxs)("div",{children:[(0,s.jsx)("label",{className:"text-[11px] text-text-muted block mb-2",children:"Token source"}),(0,s.jsxs)("div",{className:"flex gap-4 mb-2",children:[(0,s.jsxs)("label",{className:"flex items-center gap-1.5 cursor-pointer",children:[(0,s.jsx)("input",{type:"radio",name:"tokenMode",checked:"paste"===E,onChange:()=>F("paste"),className:"accent-accent"}),(0,s.jsx)("span",{className:"text-[11px] text-text",children:"Paste token"})]}),(0,s.jsxs)("label",{className:"flex items-center gap-1.5 cursor-pointer",children:[(0,s.jsx)("input",{type:"radio",name:"tokenMode",checked:"file"===E,onChange:()=>F("file"),className:"accent-accent"}),(0,s.jsx)("span",{className:"text-[11px] text-text",children:"Use existing file"})]})]}),"paste"===E?(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)("input",{value:U,onChange:e=>W(e.target.value),placeholder:"ghp_xxxxxxxxxxxxxxxxxxxx",type:"password",className:"w-full bg-transparent border border-border px-2 py-1.5 text-[12px] text-text outline-none focus:border-accent"}),(0,s.jsxs)("div",{className:"mt-2 text-[10px] text-text-muted leading-relaxed",children:[(0,s.jsxs)("p",{children:["Paste a GitHub ",(0,s.jsx)("span",{className:"text-text",children:"Personal Access Token (classic)"}),"."]}),(0,s.jsxs)("p",{className:"mt-1",children:["Create one at"," ",(0,s.jsx)("a",{href:"https://github.com/settings/tokens",target:"_blank",rel:"noopener noreferrer",className:"text-accent hover:underline",children:"github.com/settings/tokens"})," ","→ Generate new token (classic)"]}),(0,s.jsxs)("p",{className:"mt-1",children:["Required permission: ",(0,s.jsx)("span",{className:"text-accent",children:"repo"})," (Full control of private repositories)",(0,s.jsx)("br",{}),(0,s.jsx)("span",{className:"text-text-muted",children:"Needed for reading PRs, posting reviews, and approving/requesting changes"})]})]})]}):(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)("input",{value:D,onChange:e=>G(e.target.value),placeholder:"~/.quadwork/reviewer-token",className:"w-full bg-transparent border border-border px-2 py-1.5 text-[12px] text-text outline-none focus:border-accent"}),D&&!D.startsWith("~/.quadwork")&&!D.startsWith(String.raw`${t.default.env.HOME}/.quadwork`)&&(0,s.jsx)("p",{className:"text-[10px] text-[#ffcc00] mt-1",children:"This path may be inside a git repository. Consider using the default ~/.quadwork/ location to avoid accidentally committing tokens."})]})]})]}),(0,s.jsx)("button",{onClick:ed,className:"px-4 py-1.5 bg-accent text-bg text-[12px] font-semibold hover:bg-accent-dim transition-colors",children:"Next"})]}),eg?.id==="workdir"&&(0,s.jsx)(l,{repo:h,workingDir:O,setWorkingDir:B,error:eg.error,onNext:ed}),eg?.id==="workspaces"&&(0,s.jsxs)("div",{children:[(0,s.jsx)("h2",{className:"text-sm font-semibold text-text mb-1",children:"Create workspaces"}),(0,s.jsx)("p",{className:"text-[11px] text-text-muted mb-4",children:"This creates git worktrees for each agent and writes seed configuration files (AGENTS.md, CLAUDE.md) into each workspace."}),eg.error&&(0,s.jsx)("p",{className:"text-[11px] text-error mb-2",children:eg.error}),K.length>0&&(0,s.jsx)("div",{className:"border border-border bg-bg-surface p-3 mb-4 text-[11px] text-text-muted space-y-0.5 font-mono",children:K.map((e,t)=>(0,s.jsx)("p",{children:e},t))}),(0,s.jsx)("button",{onClick:eu,disabled:z,className:"px-4 py-1.5 bg-accent text-bg text-[12px] font-semibold hover:bg-accent-dim transition-colors disabled:opacity-50",children:z?"Creating...":"Create Worktrees & Seed Files"})]}),eg?.id==="launch"&&(0,s.jsxs)("div",{children:[(0,s.jsx)("h2",{className:"text-sm font-semibold text-text mb-1",children:"Ready to launch"}),(0,s.jsx)("p",{className:"text-[11px] text-text-muted mb-4",children:"Everything is configured. Review the summary and launch your AI dev team."}),(0,s.jsxs)("div",{className:"border border-border mb-4",children:[(0,s.jsx)("div",{className:"px-3 py-1.5 border-b border-border bg-bg-surface",children:(0,s.jsx)("span",{className:"text-[11px] text-text font-semibold",children:"Team Roster"})}),o.map(e=>(0,s.jsxs)("div",{className:"flex items-center justify-between px-3 py-1.5 border-b border-border/50 last:border-b-0",children:[(0,s.jsx)("span",{className:"text-[11px] text-text font-semibold",children:e.label}),(0,s.jsx)("span",{className:"text-[10px] text-text-muted",children:e.role}),(0,s.jsx)("span",{className:"text-[11px] text-accent",children:"claude"===T[e.key]?"Claude Code":"Codex"})]},e.key))]}),(0,s.jsxs)("div",{className:"mb-4",children:[(0,s.jsxs)("label",{className:"flex items-center gap-2 cursor-pointer mb-2",children:[(0,s.jsx)("input",{type:"checkbox",checked:Z,onChange:e=>ee(e.target.checked),className:"accent-accent"}),(0,s.jsx)("span",{className:"text-[11px] text-text-muted",children:"Custom ports"})]}),Z&&(0,s.jsx)("div",{className:"border border-border p-3 space-y-2",children:(0,s.jsxs)("div",{className:"grid grid-cols-3 gap-3",children:[(0,s.jsxs)("div",{className:"flex flex-col gap-1",children:[(0,s.jsx)("label",{className:"text-[10px] text-text-muted uppercase tracking-wider",children:"AgentChattr port"}),(0,s.jsx)("input",{type:"number",value:ea.chattr,onChange:e=>er({...ea,chattr:e.target.value}),onBlur:()=>ec("chattr"),placeholder:String(en.chattr||8300),className:"bg-transparent border border-border px-2 py-1 text-[11px] text-text outline-none focus:border-accent"}),en.chattr>0&&(0,s.jsxs)("span",{className:"text-[10px] text-text-muted",children:["auto-detected: ",en.chattr]})]}),(0,s.jsxs)("div",{className:"flex flex-col gap-1",children:[(0,s.jsx)("label",{className:"text-[10px] text-text-muted uppercase tracking-wider",children:"MCP HTTP port"}),(0,s.jsx)("input",{type:"number",value:ea.mcpHttp,onChange:e=>er({...ea,mcpHttp:e.target.value}),onBlur:()=>ec("mcpHttp"),placeholder:String(en.mcpHttp||8200),className:"bg-transparent border border-border px-2 py-1 text-[11px] text-text outline-none focus:border-accent"}),en.mcpHttp>0&&(0,s.jsxs)("span",{className:"text-[10px] text-text-muted",children:["auto-detected: ",en.mcpHttp]})]}),(0,s.jsxs)("div",{className:"flex flex-col gap-1",children:[(0,s.jsx)("label",{className:"text-[10px] text-text-muted uppercase tracking-wider",children:"MCP SSE port"}),(0,s.jsx)("input",{type:"number",value:ea.mcpSse,onChange:e=>er({...ea,mcpSse:e.target.value}),onBlur:()=>ec("mcpSse"),placeholder:String(en.mcpSse||8201),className:"bg-transparent border border-border px-2 py-1 text-[11px] text-text outline-none focus:border-accent"}),en.mcpSse>0&&(0,s.jsxs)("span",{className:"text-[10px] text-text-muted",children:["auto-detected: ",en.mcpSse]})]})]})})]}),eg.error&&(0,s.jsx)("p",{className:"text-[11px] text-error mb-2",children:eg.error}),"done"===X&&(0,s.jsx)("p",{className:"text-[11px] text-accent mb-2",children:"Project saved. Redirecting to dashboard..."}),(0,s.jsx)("button",{onClick:eh,disabled:"running"===X||"done"===X,className:"px-5 py-2 bg-accent text-bg text-[12px] font-semibold hover:bg-accent-dim transition-colors disabled:opacity-50",children:"running"===X?"Launching...":"done"===X?"Launched!":"Launch Project"})]}),d>=i.length&&(0,s.jsxs)("div",{className:"text-center py-8",children:[(0,s.jsx)("p",{className:"text-accent text-sm font-semibold",children:"Setup complete!"}),(0,s.jsx)("p",{className:"text-[11px] text-text-muted mt-2",children:"Redirecting to project dashboard..."})]})]})]}),(0,s.jsxs)("div",{className:"w-64 shrink-0 border-l border-border p-4 overflow-y-auto bg-bg-surface/50",children:[(0,s.jsx)("h3",{className:"text-[11px] font-semibold text-text-muted uppercase tracking-wider mb-3",children:"Configuration Preview"}),(0,s.jsxs)("div",{className:"space-y-3 text-[11px]",children:[(0,s.jsxs)("div",{children:[(0,s.jsx)("span",{className:"text-text-muted block mb-0.5",children:"Project"}),(0,s.jsx)("span",{className:"text-text",children:m||"—"})]}),(0,s.jsxs)("div",{children:[(0,s.jsx)("span",{className:"text-text-muted block mb-0.5",children:"Repository"}),(0,s.jsx)("span",{className:"text-text",children:h||"—"}),_&&(0,s.jsx)("span",{className:"text-[10px] text-accent block",children:"+ branch protection"})]}),(0,s.jsxs)("div",{children:[(0,s.jsx)("span",{className:"text-text-muted block mb-0.5",children:"Backends"}),Object.entries(T).map(([e,t])=>(0,s.jsxs)("div",{className:"flex justify-between",children:[(0,s.jsx)("span",{className:"text-text capitalize",children:e}),(0,s.jsx)("span",{className:"text-accent",children:t})]},e))]}),q&&I&&(0,s.jsxs)("div",{children:[(0,s.jsx)("span",{className:"text-text-muted block mb-0.5",children:"Reviewer"}),(0,s.jsxs)("span",{className:"text-text",children:["@",I]})]}),(0,s.jsxs)("div",{children:[(0,s.jsx)("span",{className:"text-text-muted block mb-0.5",children:"Directory"}),(0,s.jsx)("span",{className:"text-text font-mono text-[10px]",children:O||"—"})]}),(0,s.jsxs)("div",{children:[(0,s.jsx)("span",{className:"text-text-muted block mb-0.5",children:"Status"}),(0,s.jsx)("div",{className:"space-y-0.5",children:i.map(e=>(0,s.jsxs)("div",{className:"flex items-center gap-1.5",children:[(0,s.jsx)("span",{className:`text-[10px] ${"done"===e.status?"text-accent":"error"===e.status?"text-error":"active"===e.status?"text-text":"text-text-muted"}`,children:"done"===e.status?"✓":"error"===e.status?"✗":"active"===e.status?"●":"○"}),(0,s.jsx)("span",{className:`text-[10px] ${"active"===e.status?"text-text":"text-text-muted"}`,children:e.label})]},e.id))})]})]})]})]})]})}])}]);
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,18540,e=>{"use strict";var t=e.i(85899),r=e.i(4232);let s=[{title:"You assign a task in the chat",body:"Tell @head what to build. Be as specific or as vague as you like."},{title:"Head creates a GitHub issue",body:"Head opens an issue, adds it to the queue, and waits for your trigger."},{title:"Dev writes the code",body:"Dev clones a branch, implements the change, and opens a pull request."},{title:"Reviewers check the work",body:"Reviewer1 and Reviewer2 each review the PR independently. Both must approve before the PR is mergeable."},{title:"Head merges and continues",body:"Head merges the approved PR and assigns the next ticket from the queue. The cycle continues all night while you sleep."}];e.s(["default",0,function({open:e,onClose:a}){return((0,r.useEffect)(()=>{if(!e)return;let t=e=>{"Escape"===e.key&&a()};return window.addEventListener("keydown",t),()=>window.removeEventListener("keydown",t)},[e,a]),e)?(0,t.jsx)("div",{className:"fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-sm",onClick:a,role:"dialog","aria-modal":"true","aria-labelledby":"how-to-work-title",children:(0,t.jsxs)("div",{className:"relative mx-4 max-w-xl w-full max-h-[90vh] overflow-auto rounded-lg border border-white/10 bg-neutral-950 p-6 shadow-2xl",onClick:e=>e.stopPropagation(),children:[(0,t.jsx)("button",{type:"button",onClick:a,"aria-label":"Close",className:"absolute right-3 top-3 rounded p-1 text-neutral-400 hover:bg-white/5 hover:text-white",children:(0,t.jsx)("svg",{width:"18",height:"18",viewBox:"0 0 20 20",fill:"none",stroke:"currentColor",strokeWidth:"1.8",children:(0,t.jsx)("path",{d:"M4 4l12 12M16 4L4 16",strokeLinecap:"round"})})}),(0,t.jsx)("h2",{id:"how-to-work-title",className:"text-base font-semibold text-white",children:"How QuadWork builds your code"}),(0,t.jsx)("p",{className:"mt-2 text-[12px] text-neutral-400",children:"Five steps from your one-line request to a merged pull request."}),(0,t.jsxs)("ol",{className:"mt-5 relative",children:[(0,t.jsx)("span",{"aria-hidden":!0,className:"absolute left-[14px] top-3 bottom-3 w-px bg-accent/30"}),s.map((e,r)=>(0,t.jsxs)("li",{className:"relative pl-10 pb-5 last:pb-0",children:[(0,t.jsx)("span",{className:"absolute left-0 top-0 inline-flex items-center justify-center w-7 h-7 rounded-full border border-accent bg-neutral-950 text-accent text-[12px] font-semibold tabular-nums","aria-hidden":!0,children:r+1}),(0,t.jsx)("div",{className:"text-[13px] font-semibold text-white",children:e.title}),(0,t.jsx)("div",{className:"mt-1 text-[12px] leading-relaxed text-neutral-400",children:e.body})]},r))]})]})}):null}])},16348,e=>{"use strict";var t=e.i(85899),r=e.i(4232),s=e.i(2270),a=e.i(18540);function i({hasProjects:e}){let[l,o]=(0,r.useState)(!1);return(0,t.jsxs)("div",{className:"flex flex-col items-center justify-center text-center px-6 py-12 border border-border bg-bg-surface",children:[(0,t.jsxs)("svg",{width:"64",height:"64",viewBox:"0 0 64 64",fill:"none","aria-hidden":!0,className:"text-accent",children:[(0,t.jsx)("rect",{x:"6",y:"14",width:"18",height:"22",rx:"2",stroke:"currentColor",strokeWidth:"2"}),(0,t.jsx)("rect",{x:"40",y:"14",width:"18",height:"22",rx:"2",stroke:"currentColor",strokeWidth:"2"}),(0,t.jsx)("rect",{x:"6",y:"42",width:"18",height:"14",rx:"2",stroke:"currentColor",strokeWidth:"2"}),(0,t.jsx)("rect",{x:"40",y:"42",width:"18",height:"14",rx:"2",stroke:"currentColor",strokeWidth:"2"}),(0,t.jsx)("circle",{cx:"15",cy:"25",r:"2",fill:"currentColor"}),(0,t.jsx)("circle",{cx:"49",cy:"25",r:"2",fill:"currentColor"}),(0,t.jsx)("circle",{cx:"15",cy:"49",r:"2",fill:"currentColor"}),(0,t.jsx)("circle",{cx:"49",cy:"49",r:"2",fill:"currentColor"}),(0,t.jsx)("path",{d:"M24 25 L40 25 M24 49 L40 49 M15 36 L15 42 M49 36 L49 42",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round"})]}),(0,t.jsx)("h1",{className:"mt-5 text-lg font-semibold text-text max-w-md",children:e?"Pick a project from the sidebar to start working":"Welcome to QuadWork — let's set up your first AI dev team"}),(0,t.jsx)("p",{className:"mt-2 text-[12px] text-text-muted leading-relaxed max-w-md",children:e?"Each project has its own 4-agent team and chat. Click any chip in the left sidebar to open one.":"QuadWork runs Head, Dev, and two Reviewers as a team. They open issues, write code, review PRs, and merge — while you sleep."}),(0,t.jsxs)("div",{className:"mt-5 flex items-center gap-3",children:[e?(0,t.jsx)("span",{className:"text-[11px] text-text-muted italic",children:"← look at the left sidebar"}):(0,t.jsx)(s.default,{href:"/setup",className:"px-4 py-2 text-[12px] font-semibold text-bg bg-accent hover:bg-accent-dim transition-colors",children:"Add Your First Project →"}),(0,t.jsx)("button",{type:"button",onClick:()=>o(!0),className:"px-4 py-2 text-[12px] text-text-muted border border-border hover:text-text hover:border-text-muted transition-colors",children:"How to Work"})]}),(0,t.jsx)(a.default,{open:l,onClose:()=>o(!1)})]})}e.s(["default",0,function(){let[e,a]=(0,r.useState)([]),[l,o]=(0,r.useState)([]),[c,n]=(0,r.useState)("loading");return(0,r.useEffect)(()=>{fetch("/api/projects").then(e=>{if(!e.ok)throw Error(`${e.status}`);return e.json()}).then(e=>{e.projects&&Array.isArray(e.projects)&&a(e.projects.filter(e=>!e.archived)),e.recentEvents&&Array.isArray(e.recentEvents)&&o(e.recentEvents),n("loaded")}).catch(()=>{n("error")})},[]),(0,t.jsxs)("div",{className:"h-full overflow-y-auto p-6",children:["loaded"===c&&(0,t.jsx)("div",{className:"mb-6",children:(0,t.jsx)(i,{hasProjects:e.length>0})}),"error"===c&&(0,t.jsx)("div",{className:"mb-6 border border-error/30 bg-error/5 text-error text-[11px] px-3 py-2",children:"Could not load projects from /api/projects. The dashboard may be out of date — check the server logs and reload."}),(0,t.jsxs)("div",{className:"mb-6",children:[(0,t.jsx)("h1",{className:"text-lg font-semibold text-text tracking-tight",children:"Projects"}),(0,t.jsxs)("p",{className:"text-xs text-text-muted mt-1",children:[e.length," configured project",1!==e.length?"s":""]})]}),(0,t.jsxs)("div",{className:"grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-3 mb-8",children:[e.map(e=>(0,t.jsxs)(s.default,{href:`/project/${e.id}`,className:"block border border-border bg-bg-surface p-4 hover:bg-[#1a1a1a] transition-colors group",children:[(0,t.jsxs)("div",{className:"flex items-center justify-between mb-3",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)("span",{className:`w-1.5 h-1.5 rounded-full ${"active"===e.state?"bg-accent":"bg-text-muted"}`}),(0,t.jsx)("span",{className:"text-sm font-semibold text-text",children:e.name}),(0,t.jsx)("span",{className:"text-[10px] text-text-muted",children:e.state})]}),(0,t.jsx)("span",{className:"text-[10px] text-text-muted opacity-0 group-hover:opacity-100 transition-opacity",children:"open →"})]}),(0,t.jsxs)("div",{className:"flex gap-4 text-[11px] mb-2",children:[(0,t.jsxs)("div",{children:[(0,t.jsx)("span",{className:"text-text-muted",children:"agents"}),(0,t.jsx)("span",{className:"ml-1.5 text-text",children:e.agentCount})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)("span",{className:"text-text-muted",children:"PRs"}),(0,t.jsx)("span",{className:"ml-1.5 text-text",children:e.openPrs})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)("span",{className:"text-text-muted",children:"repo"}),(0,t.jsx)("span",{className:"ml-1.5 text-text",children:e.repo})]})]}),e.lastActivity&&(0,t.jsxs)("div",{className:"text-[10px] text-text-muted",children:["last activity: ",function(e){let t=Math.floor((Date.now()-new Date(e).getTime())/6e4);if(t<1)return"just now";if(t<60)return`${t}m ago`;let r=Math.floor(t/60);if(r<24)return`${r}h ago`;let s=Math.floor(r/24);return`${s}d ago`}(e.lastActivity)]})]},e.id)),(0,t.jsx)(s.default,{href:"/setup",className:"border border-dashed border-border p-4 flex items-center justify-center text-text-muted hover:text-text hover:border-text-muted transition-colors min-h-[88px]",children:(0,t.jsx)("span",{className:"text-sm",children:"+ New Project"})})]}),(0,t.jsxs)("div",{className:"mb-6",children:[(0,t.jsx)("h2",{className:"text-xs text-text-muted uppercase tracking-wider mb-3",children:"Recent Activity"}),(0,t.jsxs)("div",{className:"border border-border bg-bg-surface",children:[0===l.length&&(0,t.jsx)("div",{className:"px-3 py-3 text-[11px] text-text-muted",children:"No recent activity"}),l.map((e,r)=>(0,t.jsxs)("div",{className:"flex gap-3 px-3 py-1.5 border-b border-border/50 last:border-b-0 text-[11px]",children:[(0,t.jsx)("span",{className:"text-text-muted shrink-0 w-10 text-right tabular-nums",children:e.time?.slice(0,5)||""}),(0,t.jsx)("span",{className:"text-accent shrink-0 font-semibold w-12",children:e.projectName}),(0,t.jsx)("span",{className:"text-[#ffcc00] shrink-0 font-semibold w-12",children:"reviewer1"===e.actor?"RE1":"reviewer2"===e.actor?"RE2":e.actor}),(0,t.jsx)("span",{className:"text-text truncate min-w-0",children:e.text})]},`${e.time}-${r}`))]})]})]})}],16348)}]);
|