quadwork 1.9.0 → 1.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -0
- package/bridges/discord/__pycache__/discord_bridge.cpython-314.pyc +0 -0
- package/bridges/discord/discord_bridge.py +58 -14
- package/out/404.html +1 -1
- package/out/__next.__PAGE__.txt +3 -3
- package/out/__next._full.txt +13 -13
- package/out/__next._head.txt +4 -4
- package/out/__next._index.txt +7 -7
- package/out/__next._tree.txt +2 -2
- package/out/_next/static/chunks/0a4.d381szseh.css +2 -0
- package/out/_next/static/chunks/{0q71bcdksran1.js → 0aldkx8l9xukk.js} +1 -1
- package/out/_next/static/chunks/{04jznxp9-kut_.js → 0gaekhrfy94vz.js} +1 -1
- package/out/_next/static/chunks/{0m439m2ljf2gz.js → 0hirada7763yr.js} +14 -14
- package/out/_next/static/chunks/0rxi-m9onh_sa.js +1 -0
- package/out/_not-found/__next._full.txt +12 -12
- package/out/_not-found/__next._head.txt +4 -4
- package/out/_not-found/__next._index.txt +7 -7
- 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 +2 -2
- package/out/_not-found.html +1 -1
- package/out/_not-found.txt +12 -12
- package/out/app-shell/__next._full.txt +12 -12
- package/out/app-shell/__next._head.txt +4 -4
- package/out/app-shell/__next._index.txt +7 -7
- package/out/app-shell/__next._tree.txt +2 -2
- 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 +12 -12
- package/out/index.html +1 -1
- package/out/index.txt +13 -13
- package/out/project/_/__next._full.txt +13 -13
- package/out/project/_/__next._head.txt +4 -4
- package/out/project/_/__next._index.txt +7 -7
- package/out/project/_/__next._tree.txt +2 -2
- 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/_/queue/__next._full.txt +13 -13
- package/out/project/_/queue/__next._head.txt +4 -4
- package/out/project/_/queue/__next._index.txt +7 -7
- package/out/project/_/queue/__next._tree.txt +2 -2
- 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 +13 -13
- package/out/project/_.html +1 -1
- package/out/project/_.txt +13 -13
- package/out/settings/__next._full.txt +13 -13
- package/out/settings/__next._head.txt +4 -4
- package/out/settings/__next._index.txt +7 -7
- package/out/settings/__next._tree.txt +2 -2
- 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 +13 -13
- package/out/setup/__next._full.txt +13 -13
- package/out/setup/__next._head.txt +4 -4
- package/out/setup/__next._index.txt +7 -7
- package/out/setup/__next._tree.txt +2 -2
- 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 +13 -13
- package/package.json +1 -1
- package/server/index.js +187 -0
- package/server/routes.js +71 -50
- package/out/_next/static/chunks/0d4fb920~o_t9.css +0 -2
- package/out/_next/static/chunks/0yt_bs94icoma.js +0 -1
- /package/out/_next/static/{8W6cFlsHLq6GQp5eCnKNU → MA2-1YByee5M0-bbLgqQD}/_buildManifest.js +0 -0
- /package/out/_next/static/{8W6cFlsHLq6GQp5eCnKNU → MA2-1YByee5M0-bbLgqQD}/_clientMiddlewareManifest.js +0 -0
- /package/out/_next/static/{8W6cFlsHLq6GQp5eCnKNU → MA2-1YByee5M0-bbLgqQD}/_ssgManifest.js +0 -0
package/server/index.js
CHANGED
|
@@ -1298,9 +1298,121 @@ Dev: Work on assigned ticket or address review feedback.
|
|
|
1298
1298
|
RE1/RE2: Review open PRs. If Dev pushed fixes, re-review. Post verdict on PR AND notify here.
|
|
1299
1299
|
ALL: Communicate via this chat by tagging agents. Your terminal is NOT visible.`;
|
|
1300
1300
|
|
|
1301
|
+
// #518: server-side bridge lifecycle helpers. Stop and start Telegram +
|
|
1302
|
+
// Discord bridges so they respond to batch transitions even when the
|
|
1303
|
+
// operator is on a different project page.
|
|
1304
|
+
|
|
1305
|
+
async function autoStopBridges(projectId, project, qwPort) {
|
|
1306
|
+
if (project?.telegram_auto) {
|
|
1307
|
+
try {
|
|
1308
|
+
await fetch(`http://127.0.0.1:${qwPort}/api/telegram?action=stop`, {
|
|
1309
|
+
method: "POST",
|
|
1310
|
+
headers: { "Content-Type": "application/json" },
|
|
1311
|
+
body: JSON.stringify({ project_id: projectId }),
|
|
1312
|
+
signal: AbortSignal.timeout(5000),
|
|
1313
|
+
});
|
|
1314
|
+
console.log(`[auto-bridge] ${projectId}: telegram bridge auto-stopped`);
|
|
1315
|
+
} catch { /* non-fatal */ }
|
|
1316
|
+
}
|
|
1317
|
+
if (project?.discord_auto) {
|
|
1318
|
+
try {
|
|
1319
|
+
await fetch(`http://127.0.0.1:${qwPort}/api/discord?action=stop`, {
|
|
1320
|
+
method: "POST",
|
|
1321
|
+
headers: { "Content-Type": "application/json" },
|
|
1322
|
+
body: JSON.stringify({ project_id: projectId }),
|
|
1323
|
+
signal: AbortSignal.timeout(5000),
|
|
1324
|
+
});
|
|
1325
|
+
console.log(`[auto-bridge] ${projectId}: discord bridge auto-stopped`);
|
|
1326
|
+
} catch { /* non-fatal */ }
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1330
|
+
async function autoStartBridges(projectId, project, qwPort) {
|
|
1331
|
+
if (project?.telegram_auto) {
|
|
1332
|
+
try {
|
|
1333
|
+
// Check if already running before starting
|
|
1334
|
+
const st = await fetch(
|
|
1335
|
+
`http://127.0.0.1:${qwPort}/api/telegram?project=${encodeURIComponent(projectId)}`,
|
|
1336
|
+
{ signal: AbortSignal.timeout(5000) }
|
|
1337
|
+
);
|
|
1338
|
+
if (st.ok) {
|
|
1339
|
+
const data = await st.json();
|
|
1340
|
+
if (data.running) return; // already running
|
|
1341
|
+
if (!data.configured) return; // not configured — can't start
|
|
1342
|
+
}
|
|
1343
|
+
await fetch(`http://127.0.0.1:${qwPort}/api/telegram?action=start`, {
|
|
1344
|
+
method: "POST",
|
|
1345
|
+
headers: { "Content-Type": "application/json" },
|
|
1346
|
+
body: JSON.stringify({ project_id: projectId }),
|
|
1347
|
+
signal: AbortSignal.timeout(10000),
|
|
1348
|
+
});
|
|
1349
|
+
console.log(`[auto-bridge] ${projectId}: telegram bridge auto-started`);
|
|
1350
|
+
} catch { /* non-fatal */ }
|
|
1351
|
+
}
|
|
1352
|
+
if (project?.discord_auto) {
|
|
1353
|
+
try {
|
|
1354
|
+
const st = await fetch(
|
|
1355
|
+
`http://127.0.0.1:${qwPort}/api/discord?project=${encodeURIComponent(projectId)}`,
|
|
1356
|
+
{ signal: AbortSignal.timeout(5000) }
|
|
1357
|
+
);
|
|
1358
|
+
if (st.ok) {
|
|
1359
|
+
const data = await st.json();
|
|
1360
|
+
if (data.running) return;
|
|
1361
|
+
if (!data.configured) return;
|
|
1362
|
+
}
|
|
1363
|
+
await fetch(`http://127.0.0.1:${qwPort}/api/discord?action=start`, {
|
|
1364
|
+
method: "POST",
|
|
1365
|
+
headers: { "Content-Type": "application/json" },
|
|
1366
|
+
body: JSON.stringify({ project_id: projectId }),
|
|
1367
|
+
signal: AbortSignal.timeout(10000),
|
|
1368
|
+
});
|
|
1369
|
+
console.log(`[auto-bridge] ${projectId}: discord bridge auto-started`);
|
|
1370
|
+
} catch { /* non-fatal */ }
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1373
|
+
|
|
1374
|
+
// Track previous batch state per project for bridge auto-start detection
|
|
1375
|
+
const _bridgeBatchPrev = new Map();
|
|
1376
|
+
|
|
1301
1377
|
async function sendTriggerMessage(projectId) {
|
|
1302
1378
|
const cfg = readConfig();
|
|
1303
1379
|
const project = cfg.projects && cfg.projects.find((p) => p.id === projectId);
|
|
1380
|
+
|
|
1381
|
+
// #516: server-side auto-stop — check batch progress before sending.
|
|
1382
|
+
// When trigger_auto is enabled, skip the message and stop the trigger
|
|
1383
|
+
// (plus caffeinate) if the batch is already complete. This covers the
|
|
1384
|
+
// case where the operator is on a different page and the client-side
|
|
1385
|
+
// ScheduledTriggerWidget is not mounted to detect completion.
|
|
1386
|
+
if (project && project.trigger_auto) {
|
|
1387
|
+
const qwPort = cfg.port || 8400;
|
|
1388
|
+
try {
|
|
1389
|
+
const bpRes = await fetch(
|
|
1390
|
+
`http://127.0.0.1:${qwPort}/api/batch-progress?project=${encodeURIComponent(projectId)}`
|
|
1391
|
+
);
|
|
1392
|
+
if (bpRes.ok) {
|
|
1393
|
+
const bp = await bpRes.json();
|
|
1394
|
+
if (bp && bp.complete) {
|
|
1395
|
+
console.log(`[auto-trigger] ${projectId}: batch complete, auto-stopped`);
|
|
1396
|
+
stopTrigger(projectId);
|
|
1397
|
+
// Also stop caffeinate if no other triggers remain running
|
|
1398
|
+
// (#441 companion fix). caffeinateProcess is global (not
|
|
1399
|
+
// project-scoped), so only kill it when all work is done.
|
|
1400
|
+
if (caffeinateProcess.process && triggers.size === 0) {
|
|
1401
|
+
try { caffeinateProcess.process.kill("SIGTERM"); } catch {}
|
|
1402
|
+
caffeinateProcess = { process: null, pid: null, startedAt: null, duration: null };
|
|
1403
|
+
console.log(`[auto-trigger] ${projectId}: caffeinate auto-stopped (no active triggers remain)`);
|
|
1404
|
+
}
|
|
1405
|
+
// #518: also stop bridges when batch completes
|
|
1406
|
+
await autoStopBridges(projectId, project, qwPort);
|
|
1407
|
+
return;
|
|
1408
|
+
}
|
|
1409
|
+
}
|
|
1410
|
+
} catch (err) {
|
|
1411
|
+
// Non-fatal — if batch-progress fails, proceed with the message
|
|
1412
|
+
console.error(`[auto-trigger] ${projectId}: batch-progress check failed:`, err.message);
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1304
1416
|
const message = (project && project.trigger_message) || DEFAULT_MESSAGE;
|
|
1305
1417
|
|
|
1306
1418
|
// #401 / quadwork#277: route trigger sends through the local
|
|
@@ -1721,6 +1833,67 @@ function syncTriggersFromConfig() {
|
|
|
1721
1833
|
}
|
|
1722
1834
|
}
|
|
1723
1835
|
|
|
1836
|
+
// #516: server-side batch-completion poller. Checks every 30s whether
|
|
1837
|
+
// any trigger_auto project's batch is complete, and auto-stops the
|
|
1838
|
+
// trigger (plus caffeinate when no triggers remain). This runs
|
|
1839
|
+
// independently of the trigger tick interval, so completion is
|
|
1840
|
+
// detected within 30s even if the operator is on a different page.
|
|
1841
|
+
// #518: also handles telegram_auto / discord_auto bridge lifecycle
|
|
1842
|
+
// (both start and stop) so bridges respond to batch transitions
|
|
1843
|
+
// even when the operator is viewing a different project page.
|
|
1844
|
+
|
|
1845
|
+
const AUTO_STOP_POLL_INTERVAL_MS = 30_000;
|
|
1846
|
+
|
|
1847
|
+
async function autoStopPollingTick() {
|
|
1848
|
+
const cfg = readConfig();
|
|
1849
|
+
if (!cfg.projects) return;
|
|
1850
|
+
|
|
1851
|
+
for (const project of cfg.projects) {
|
|
1852
|
+
const hasTriggerAuto = project.trigger_auto && triggers.has(project.id);
|
|
1853
|
+
const hasBridgeAuto = project.telegram_auto || project.discord_auto;
|
|
1854
|
+
if (!hasTriggerAuto && !hasBridgeAuto) continue;
|
|
1855
|
+
const qwPort = cfg.port || 8400;
|
|
1856
|
+
try {
|
|
1857
|
+
const res = await fetch(
|
|
1858
|
+
`http://127.0.0.1:${qwPort}/api/batch-progress?project=${encodeURIComponent(project.id)}`
|
|
1859
|
+
);
|
|
1860
|
+
if (!res.ok) continue;
|
|
1861
|
+
const bp = await res.json();
|
|
1862
|
+
const hasItems = bp.items && bp.items.length > 0;
|
|
1863
|
+
const prev = _bridgeBatchPrev.get(project.id);
|
|
1864
|
+
_bridgeBatchPrev.set(project.id, { complete: bp.complete, hasItems });
|
|
1865
|
+
|
|
1866
|
+
if (bp && bp.complete) {
|
|
1867
|
+
if (hasTriggerAuto) {
|
|
1868
|
+
console.log(`[auto-trigger] ${project.id}: batch complete, auto-stopped (poller)`);
|
|
1869
|
+
stopTrigger(project.id);
|
|
1870
|
+
if (caffeinateProcess.process && triggers.size === 0) {
|
|
1871
|
+
try { caffeinateProcess.process.kill("SIGTERM"); } catch {}
|
|
1872
|
+
caffeinateProcess = { process: null, pid: null, startedAt: null, duration: null };
|
|
1873
|
+
console.log(`[auto-trigger] ${project.id}: caffeinate auto-stopped (no active triggers remain)`);
|
|
1874
|
+
}
|
|
1875
|
+
}
|
|
1876
|
+
// #518: also stop bridges when batch completes
|
|
1877
|
+
if (hasBridgeAuto) {
|
|
1878
|
+
await autoStopBridges(project.id, project, qwPort);
|
|
1879
|
+
}
|
|
1880
|
+
}
|
|
1881
|
+
|
|
1882
|
+
// #518: detect batch-start transition → auto-start bridges
|
|
1883
|
+
if (hasBridgeAuto && hasItems && !bp.complete) {
|
|
1884
|
+
const isNewBatch = !prev || prev.complete || !prev.hasItems;
|
|
1885
|
+
if (isNewBatch) {
|
|
1886
|
+
await autoStartBridges(project.id, project, qwPort);
|
|
1887
|
+
}
|
|
1888
|
+
}
|
|
1889
|
+
} catch {
|
|
1890
|
+
// Non-fatal — retry on next tick
|
|
1891
|
+
}
|
|
1892
|
+
}
|
|
1893
|
+
}
|
|
1894
|
+
|
|
1895
|
+
setInterval(autoStopPollingTick, AUTO_STOP_POLL_INTERVAL_MS);
|
|
1896
|
+
|
|
1724
1897
|
// #422 / quadwork#310: auto-continue after loop guard.
|
|
1725
1898
|
//
|
|
1726
1899
|
// Per opted-in project, poll AC's /api/status every 10s. When we see
|
|
@@ -1983,6 +2156,20 @@ server.listen(PORT, "127.0.0.1", () => {
|
|
|
1983
2156
|
}
|
|
1984
2157
|
} catch {}
|
|
1985
2158
|
}
|
|
2159
|
+
// #506: refresh Discord bridge script from the npm package on startup.
|
|
2160
|
+
// The Telegram bridge uses git-fetch + pin, but Discord uses a file-copy
|
|
2161
|
+
// pattern. Without this, upgrading QuadWork leaves a stale on-disk script
|
|
2162
|
+
// missing fixes shipped in newer versions.
|
|
2163
|
+
const DISCORD_BRIDGE_SRC = path.join(__dirname, "..", "bridges", "discord", "discord_bridge.py");
|
|
2164
|
+
const DISCORD_BRIDGE_DEST = path.join(os.homedir(), ".quadwork", "agentchattr-discord", "discord_bridge.py");
|
|
2165
|
+
if (fs.existsSync(DISCORD_BRIDGE_SRC) && fs.existsSync(path.dirname(DISCORD_BRIDGE_DEST))) {
|
|
2166
|
+
try {
|
|
2167
|
+
fs.copyFileSync(DISCORD_BRIDGE_SRC, DISCORD_BRIDGE_DEST);
|
|
2168
|
+
console.log("[bridge-refresh] refreshed Discord bridge script from package");
|
|
2169
|
+
} catch (err) {
|
|
2170
|
+
console.warn(`[bridge-refresh] failed to refresh Discord bridge script: ${err.message || err}`);
|
|
2171
|
+
}
|
|
2172
|
+
}
|
|
1986
2173
|
// #470: patch stale bridge_sender defaults in on-disk bridge scripts.
|
|
1987
2174
|
// The AC config migration (#457) renames the agent sections, but the
|
|
1988
2175
|
// bridge scripts themselves may still have old defaults if the operator
|
package/server/routes.js
CHANGED
|
@@ -1069,17 +1069,17 @@ router.get("/api/uploads/:project/:filename", (req, res) => {
|
|
|
1069
1069
|
|
|
1070
1070
|
// ─── Projects (dashboard aggregation) ──────────────────────────────────────
|
|
1071
1071
|
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
} catch {
|
|
1078
|
-
return [];
|
|
1079
|
-
}
|
|
1080
|
-
}
|
|
1072
|
+
// #512: cache /api/projects results for 60s to eliminate repeated
|
|
1073
|
+
// slow gh CLI calls on every dashboard poll.
|
|
1074
|
+
let _projectsCache = null;
|
|
1075
|
+
let _projectsCacheTs = 0;
|
|
1076
|
+
const PROJECTS_CACHE_TTL = 60_000;
|
|
1081
1077
|
|
|
1082
1078
|
router.get("/api/projects", async (req, res) => {
|
|
1079
|
+
if (_projectsCache && Date.now() - _projectsCacheTs < PROJECTS_CACHE_TTL) {
|
|
1080
|
+
return res.json(_projectsCache);
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
1083
|
const cfg = readConfigFile();
|
|
1084
1084
|
|
|
1085
1085
|
// Fetch active sessions from our own in-memory state (only running PTYs)
|
|
@@ -1113,24 +1113,34 @@ router.get("/api/projects", async (req, res) => {
|
|
|
1113
1113
|
.slice(-10)
|
|
1114
1114
|
.reverse();
|
|
1115
1115
|
|
|
1116
|
-
|
|
1117
|
-
|
|
1116
|
+
// #512: build project-id-to-name map from config and a reverse
|
|
1117
|
+
// lookup from chat message to project name via chatMsgsByProject
|
|
1118
|
+
// (which already knows which AC instance each message came from).
|
|
1119
|
+
// This replaces the expensive allPrs/allIssues gh CLI calls that
|
|
1120
|
+
// were only used for the numberToProject mapping.
|
|
1121
|
+
const projectIdToName = {};
|
|
1122
|
+
for (const p of cfg.projects || []) projectIdToName[p.id] = p.name;
|
|
1123
|
+
const msgToProject = new Map();
|
|
1124
|
+
for (const [pid, msgs] of Object.entries(chatMsgsByProject)) {
|
|
1125
|
+
for (const m of msgs) msgToProject.set(m, projectIdToName[pid]);
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
// #512: parallelize gh CLI calls across projects using async exec.
|
|
1129
|
+
// Only fetch open PR count and most recent PR activity — drop the
|
|
1130
|
+
// allPrs/allIssues calls that were only used for numberToProject.
|
|
1131
|
+
async function fetchProjectGhData(p) {
|
|
1118
1132
|
let openPrs = 0;
|
|
1119
1133
|
let lastActivity = null;
|
|
1120
|
-
|
|
1121
1134
|
if (REPO_RE.test(p.repo)) {
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
const allIssues = ghJson(["issue", "list", "-R", p.repo, "--state", "all", "--json", "number", "--limit", "100"]);
|
|
1131
|
-
for (const issue of allIssues) numberToProject[issue.number] = p.name;
|
|
1135
|
+
try {
|
|
1136
|
+
const [prs, recentPrs] = await Promise.allSettled([
|
|
1137
|
+
ghJsonExecAsync(["pr", "list", "-R", p.repo, "--json", "number", "--limit", "100"]),
|
|
1138
|
+
ghJsonExecAsync(["pr", "list", "-R", p.repo, "--state", "all", "--json", "updatedAt", "--limit", "1"]),
|
|
1139
|
+
]);
|
|
1140
|
+
if (prs.status === "fulfilled") openPrs = prs.value.length;
|
|
1141
|
+
if (recentPrs.status === "fulfilled") lastActivity = recentPrs.value[0]?.updatedAt || null;
|
|
1142
|
+
} catch {}
|
|
1132
1143
|
}
|
|
1133
|
-
|
|
1134
1144
|
const hasAgents = p.agents && Object.keys(p.agents).length > 0;
|
|
1135
1145
|
return {
|
|
1136
1146
|
id: p.id,
|
|
@@ -1141,20 +1151,21 @@ router.get("/api/projects", async (req, res) => {
|
|
|
1141
1151
|
state: hasAgents && activeProjectIds.has(p.id) ? "active" : "idle",
|
|
1142
1152
|
lastActivity,
|
|
1143
1153
|
};
|
|
1144
|
-
}
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
const projectResults = await Promise.all(
|
|
1157
|
+
(cfg.projects || []).map((p) => fetchProjectGhData(p))
|
|
1158
|
+
);
|
|
1145
1159
|
|
|
1146
|
-
// Build activity feed
|
|
1160
|
+
// Build activity feed — use chat-based project association instead
|
|
1161
|
+
// of the dropped numberToProject gh lookup.
|
|
1147
1162
|
const recentEvents = [];
|
|
1148
1163
|
for (const m of workflowMsgs) {
|
|
1164
|
+
// First: try text match against repo/project name
|
|
1149
1165
|
let projectName = (cfg.projects || []).find((p) => m.text.includes(p.repo) || m.text.includes(p.name))?.name;
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
}
|
|
1154
|
-
if (!projectName) {
|
|
1155
|
-
const branchMatch = m.text.match(/task\/(\d+)/);
|
|
1156
|
-
if (branchMatch) projectName = numberToProject[parseInt(branchMatch[1], 10)];
|
|
1157
|
-
}
|
|
1166
|
+
// Second: use the AC instance the message came from
|
|
1167
|
+
if (!projectName) projectName = msgToProject.get(m);
|
|
1168
|
+
// Fallback: single-project installs
|
|
1158
1169
|
if (!projectName && cfg.projects && cfg.projects.length === 1) {
|
|
1159
1170
|
projectName = cfg.projects[0].name;
|
|
1160
1171
|
}
|
|
@@ -1169,7 +1180,10 @@ router.get("/api/projects", async (req, res) => {
|
|
|
1169
1180
|
if (recentEvents.length >= 10) break;
|
|
1170
1181
|
}
|
|
1171
1182
|
|
|
1172
|
-
|
|
1183
|
+
const result = { projects: projectResults, recentEvents };
|
|
1184
|
+
_projectsCache = result;
|
|
1185
|
+
_projectsCacheTs = Date.now();
|
|
1186
|
+
res.json(result);
|
|
1173
1187
|
});
|
|
1174
1188
|
|
|
1175
1189
|
// ─── GitHub Issues / PRs ───────────────────────────────────────────────────
|
|
@@ -2301,7 +2315,7 @@ router.post("/api/rename", (req, res) => {
|
|
|
2301
2315
|
const BRIDGE_DIR = path.join(CONFIG_DIR, "agentchattr-telegram");
|
|
2302
2316
|
// #444: pin agentchattr-telegram to a known commit (same pattern as
|
|
2303
2317
|
// AGENTCHATTR_PIN in bin/quadwork.js for bcurts/agentchattr).
|
|
2304
|
-
const AGENTCHATTR_TELEGRAM_PIN = "
|
|
2318
|
+
const AGENTCHATTR_TELEGRAM_PIN = "045ee18f6d5dbcd0bd45d5ab29f06e2a27382aaf";
|
|
2305
2319
|
|
|
2306
2320
|
function telegramPidFile(projectId) {
|
|
2307
2321
|
return path.join(CONFIG_DIR, `tg-bridge-${projectId}.pid`);
|
|
@@ -2350,7 +2364,8 @@ function buildTelegramBridgeToml(tg, projectId) {
|
|
|
2350
2364
|
`bot_token = "${tg.bot_token}"\n` +
|
|
2351
2365
|
`chat_id = "${tg.chat_id}"\n` +
|
|
2352
2366
|
`agentchattr_url = "${tg.agentchattr_url}"\n` +
|
|
2353
|
-
`cursor_file = "${cursorFile}"\n`
|
|
2367
|
+
`cursor_file = "${cursorFile}"\n` +
|
|
2368
|
+
`project_id = "${projectId}"\n`
|
|
2354
2369
|
);
|
|
2355
2370
|
}
|
|
2356
2371
|
|
|
@@ -2816,6 +2831,9 @@ router.post("/api/telegram", async (req, res) => {
|
|
|
2816
2831
|
if (pid) process.kill(pid, "SIGTERM");
|
|
2817
2832
|
fs.unlinkSync(pf);
|
|
2818
2833
|
}
|
|
2834
|
+
// #522: clear bridge log so last_error doesn't show stale
|
|
2835
|
+
// connection-refused messages after an intentional stop.
|
|
2836
|
+
try { fs.writeFileSync(telegramBridgeLog(projectId), ""); } catch {}
|
|
2819
2837
|
return res.json({ ok: true, running: false });
|
|
2820
2838
|
} catch (err) {
|
|
2821
2839
|
return res.json({ ok: false, error: err.message || "Stop failed" });
|
|
@@ -2909,7 +2927,8 @@ function buildDiscordBridgeToml(dc, projectId) {
|
|
|
2909
2927
|
`bot_token = "${dc.bot_token}"\n` +
|
|
2910
2928
|
`channel_id = "${dc.channel_id}"\n` +
|
|
2911
2929
|
`agentchattr_url = "${dc.agentchattr_url}"\n` +
|
|
2912
|
-
`cursor_file = "${cursorFile}"\n`
|
|
2930
|
+
`cursor_file = "${cursorFile}"\n` +
|
|
2931
|
+
`project_id = "${projectId}"\n`
|
|
2913
2932
|
);
|
|
2914
2933
|
}
|
|
2915
2934
|
|
|
@@ -3066,20 +3085,19 @@ router.post("/api/discord", async (req, res) => {
|
|
|
3066
3085
|
const venvPip = path.join(venvDir, "bin", "pip");
|
|
3067
3086
|
let pipOutput = "";
|
|
3068
3087
|
try {
|
|
3069
|
-
//
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3073
|
-
// On upgrade: overwrite script, keep venv
|
|
3074
|
-
fs.cpSync(
|
|
3075
|
-
path.join(DISCORD_BRIDGE_SRC, "discord_bridge.py"),
|
|
3076
|
-
path.join(DISCORD_BRIDGE_DIR, "discord_bridge.py"),
|
|
3077
|
-
);
|
|
3078
|
-
fs.cpSync(
|
|
3079
|
-
path.join(DISCORD_BRIDGE_SRC, "requirements.txt"),
|
|
3080
|
-
path.join(DISCORD_BRIDGE_DIR, "requirements.txt"),
|
|
3081
|
-
);
|
|
3088
|
+
// #506: always copy bundled bridge files (not just on first install)
|
|
3089
|
+
// so re-installing after a QuadWork upgrade refreshes the script.
|
|
3090
|
+
if (!fs.existsSync(DISCORD_BRIDGE_DIR)) {
|
|
3091
|
+
fs.mkdirSync(DISCORD_BRIDGE_DIR, { recursive: true });
|
|
3082
3092
|
}
|
|
3093
|
+
fs.cpSync(
|
|
3094
|
+
path.join(DISCORD_BRIDGE_SRC, "discord_bridge.py"),
|
|
3095
|
+
path.join(DISCORD_BRIDGE_DIR, "discord_bridge.py"),
|
|
3096
|
+
);
|
|
3097
|
+
fs.cpSync(
|
|
3098
|
+
path.join(DISCORD_BRIDGE_SRC, "requirements.txt"),
|
|
3099
|
+
path.join(DISCORD_BRIDGE_DIR, "requirements.txt"),
|
|
3100
|
+
);
|
|
3083
3101
|
if (!fs.existsSync(venvPython)) {
|
|
3084
3102
|
execFileSync("python3", ["-m", "venv", venvDir], { encoding: "utf-8", timeout: 60000 });
|
|
3085
3103
|
}
|
|
@@ -3225,6 +3243,9 @@ router.post("/api/discord", async (req, res) => {
|
|
|
3225
3243
|
if (pid) process.kill(pid, "SIGTERM");
|
|
3226
3244
|
fs.unlinkSync(pf);
|
|
3227
3245
|
}
|
|
3246
|
+
// #522: clear bridge log so last_error doesn't show stale
|
|
3247
|
+
// connection-refused messages after an intentional stop.
|
|
3248
|
+
try { fs.writeFileSync(discordBridgeLog(projectId), ""); } catch {}
|
|
3228
3249
|
return res.json({ ok: true, running: false });
|
|
3229
3250
|
} catch (err) {
|
|
3230
3251
|
return res.json({ ok: false, error: err.message || "Stop failed" });
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
@font-face{font-family:Geist Mono;font-style:normal;font-weight:100 900;font-display:swap;src:url(../media/4fa387ec64143e14-s.0q3udbd2bu5yp.woff2)format("woff2");unicode-range:U+301,U+400-45F,U+490-491,U+4B0-4B1,U+2116}@font-face{font-family:Geist Mono;font-style:normal;font-weight:100 900;font-display:swap;src:url(../media/bbc41e54d2fcbd21-s.0gw~uztddq1df.woff2)format("woff2");unicode-range:U+100-2BA,U+2BD-2C5,U+2C7-2CC,U+2CE-2D7,U+2DD-2FF,U+304,U+308,U+329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Geist Mono;font-style:normal;font-weight:100 900;font-display:swap;src:url(../media/797e433ab948586e-s.p.0.q-h669a_dqa.woff2)format("woff2");unicode-range:U+??,U+131,U+152-153,U+2BB-2BC,U+2C6,U+2DA,U+2DC,U+304,U+308,U+329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Geist Mono Fallback;src:local(Arial);ascent-override:74.67%;descent-override:21.92%;line-gap-override:0.0%;size-adjust:134.59%}.geist_mono_8d43a2aa-module__8Li5zG__className{font-family:Geist Mono,Geist Mono Fallback;font-style:normal}.geist_mono_8d43a2aa-module__8Li5zG__variable{--font-geist-mono:"Geist Mono", "Geist Mono Fallback"}
|
|
2
|
-
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-space-y-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-duration:initial;--tw-ease:initial}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--color-red-400:#ff6568;--color-red-500:#fb2c36;--color-red-700:#bf000f;--color-red-900:#82181a;--color-amber-200:#fee685;--color-amber-300:#ffd236;--color-amber-400:#fcbb00;--color-amber-500:#f99c00;--color-green-500:#00c758;--color-blue-300:#90c5ff;--color-blue-400:#54a2ff;--color-neutral-200:#e5e5e5;--color-neutral-300:#d4d4d4;--color-neutral-400:#a1a1a1;--color-neutral-500:#737373;--color-neutral-600:#525252;--color-neutral-700:#404040;--color-neutral-900:#171717;--color-neutral-950:#0a0a0a;--color-black:#000;--color-white:#fff;--spacing:.25rem;--container-sm:24rem;--container-md:28rem;--container-lg:32rem;--container-xl:36rem;--container-3xl:48rem;--container-5xl:64rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height:calc(1.5 / 1);--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--font-weight-semibold:600;--font-weight-bold:700;--tracking-tight:-.025em;--tracking-wider:.05em;--tracking-widest:.1em;--leading-tight:1.25;--leading-snug:1.375;--leading-relaxed:1.625;--radius-sm:.25rem;--radius-lg:.5rem;--ease-in-out:cubic-bezier(.4, 0, .2, 1);--animate-ping:ping 1s cubic-bezier(0, 0, .2, 1) infinite;--animate-pulse:pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;--blur-sm:8px;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-geist-mono)}@supports (color:lab(0% 0 0)){:root,:host{--color-red-400:lab(63.7053% 60.745 31.3109);--color-red-500:lab(55.4814% 75.0732 48.8528);--color-red-700:lab(40.4273% 67.2623 53.7441);--color-red-900:lab(28.5139% 44.5539 29.0463);--color-amber-200:lab(91.7203% -.505269 49.9084);--color-amber-300:lab(86.4156% 6.13147 78.3961);--color-amber-400:lab(80.1641% 16.6016 99.2089);--color-amber-500:lab(72.7183% 31.8672 97.9407);--color-green-500:lab(70.5521% -66.5147 45.8073);--color-blue-300:lab(77.5052% -6.4629 -36.42);--color-blue-400:lab(65.0361% -1.42065 -56.9802);--color-neutral-200:lab(90.952% 0 -.0000119209);--color-neutral-300:lab(84.92% 0 -.0000119209);--color-neutral-400:lab(66.128% -.0000298023 .0000119209);--color-neutral-500:lab(48.496% 0 0);--color-neutral-600:lab(34.924% 0 0);--color-neutral-700:lab(27.036% 0 0);--color-neutral-900:lab(7.78201% -.0000149012 0);--color-neutral-950:lab(2.75381% 0 0)}}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.pointer-events-none{pointer-events:none}.invisible{visibility:hidden}.visible{visibility:visible}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.sticky{position:sticky}.inset-0{inset:calc(var(--spacing) * 0)}.start{inset-inline-start:var(--spacing)}.end{inset-inline-end:var(--spacing)}.-top-1{top:calc(var(--spacing) * -1)}.-top-1\.5{top:calc(var(--spacing) * -1.5)}.top-0{top:calc(var(--spacing) * 0)}.top-3{top:calc(var(--spacing) * 3)}.top-4{top:calc(var(--spacing) * 4)}.top-5{top:calc(var(--spacing) * 5)}.top-6{top:calc(var(--spacing) * 6)}.-right-1{right:calc(var(--spacing) * -1)}.-right-1\.5{right:calc(var(--spacing) * -1.5)}.right-0{right:calc(var(--spacing) * 0)}.right-3{right:calc(var(--spacing) * 3)}.bottom-3{bottom:calc(var(--spacing) * 3)}.bottom-5{bottom:calc(var(--spacing) * 5)}.bottom-full{bottom:100%}.left-0{left:calc(var(--spacing) * 0)}.left-16{left:calc(var(--spacing) * 16)}.left-\[14px\]{left:14px}.z-10{z-index:10}.z-20{z-index:20}.z-30{z-index:30}.z-40{z-index:40}.z-50{z-index:50}.col-span-2{grid-column:span 2/span 2}.mx-4{margin-inline:calc(var(--spacing) * 4)}.my-1{margin-block:calc(var(--spacing) * 1)}.my-2{margin-block:calc(var(--spacing) * 2)}.my-4{margin-block:calc(var(--spacing) * 4)}.mt-0\.5{margin-top:calc(var(--spacing) * .5)}.mt-1{margin-top:calc(var(--spacing) * 1)}.mt-1\.5{margin-top:calc(var(--spacing) * 1.5)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mt-5{margin-top:calc(var(--spacing) * 5)}.mr-0{margin-right:calc(var(--spacing) * 0)}.mb-0\.5{margin-bottom:calc(var(--spacing) * .5)}.mb-1{margin-bottom:calc(var(--spacing) * 1)}.mb-1\.5{margin-bottom:calc(var(--spacing) * 1.5)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.mb-6{margin-bottom:calc(var(--spacing) * 6)}.mb-8{margin-bottom:calc(var(--spacing) * 8)}.ml-0\.5{margin-left:calc(var(--spacing) * .5)}.ml-1{margin-left:calc(var(--spacing) * 1)}.ml-1\.5{margin-left:calc(var(--spacing) * 1.5)}.ml-2{margin-left:calc(var(--spacing) * 2)}.ml-3{margin-left:calc(var(--spacing) * 3)}.ml-auto{margin-left:auto}.block{display:block}.contents{display:contents}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.list-item{display:list-item}.table{display:table}.h-1{height:calc(var(--spacing) * 1)}.h-1\.5{height:calc(var(--spacing) * 1.5)}.h-2{height:calc(var(--spacing) * 2)}.h-3{height:calc(var(--spacing) * 3)}.h-3\.5{height:calc(var(--spacing) * 3.5)}.h-4{height:calc(var(--spacing) * 4)}.h-5{height:calc(var(--spacing) * 5)}.h-6{height:calc(var(--spacing) * 6)}.h-7{height:calc(var(--spacing) * 7)}.h-8{height:calc(var(--spacing) * 8)}.h-10{height:calc(var(--spacing) * 10)}.h-12{height:calc(var(--spacing) * 12)}.h-16{height:calc(var(--spacing) * 16)}.h-\[12px\]{height:12px}.h-\[80vh\]{height:80vh}.h-\[calc\(100\%-80px\)\]{height:calc(100% - 80px)}.h-full{height:100%}.h-px{height:1px}.max-h-28{max-height:calc(var(--spacing) * 28)}.max-h-40{max-height:calc(var(--spacing) * 40)}.max-h-48{max-height:calc(var(--spacing) * 48)}.max-h-60{max-height:calc(var(--spacing) * 60)}.max-h-\[90vh\]{max-height:90vh}.max-h-\[150px\]{max-height:150px}.min-h-0{min-height:calc(var(--spacing) * 0)}.min-h-\[88px\]{min-height:88px}.w-1\.5{width:calc(var(--spacing) * 1.5)}.w-2{width:calc(var(--spacing) * 2)}.w-3{width:calc(var(--spacing) * 3)}.w-3\.5{width:calc(var(--spacing) * 3.5)}.w-4{width:calc(var(--spacing) * 4)}.w-5{width:calc(var(--spacing) * 5)}.w-6{width:calc(var(--spacing) * 6)}.w-7{width:calc(var(--spacing) * 7)}.w-8{width:calc(var(--spacing) * 8)}.w-9{width:calc(var(--spacing) * 9)}.w-10{width:calc(var(--spacing) * 10)}.w-12{width:calc(var(--spacing) * 12)}.w-14{width:calc(var(--spacing) * 14)}.w-16{width:calc(var(--spacing) * 16)}.w-44{width:calc(var(--spacing) * 44)}.w-52{width:calc(var(--spacing) * 52)}.w-64{width:calc(var(--spacing) * 64)}.w-72{width:calc(var(--spacing) * 72)}.w-\[1px\]{width:1px}.w-full{width:100%}.w-px{width:1px}.max-w-3xl{max-width:var(--container-3xl)}.max-w-5xl{max-width:var(--container-5xl)}.max-w-\[60\%\]{max-width:60%}.max-w-\[200px\]{max-width:200px}.max-w-\[520px\]{max-width:520px}.max-w-lg{max-width:var(--container-lg)}.max-w-md{max-width:var(--container-md)}.max-w-none{max-width:none}.max-w-sm{max-width:var(--container-sm)}.max-w-xl{max-width:var(--container-xl)}.min-w-0{min-width:calc(var(--spacing) * 0)}.min-w-\[140px\]{min-width:140px}.min-w-\[220px\]{min-width:220px}.min-w-\[280px\]{min-width:280px}.flex-1{flex:1}.shrink-0{flex-shrink:0}.grow{flex-grow:1}.-rotate-90{rotate:-90deg}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.animate-ping{animation:var(--animate-ping)}.animate-pulse{animation:var(--animate-pulse)}.cursor-col-resize{cursor:col-resize}.cursor-move{cursor:move}.cursor-pointer{cursor:pointer}.cursor-row-resize{cursor:row-resize}.resize{resize:both}.resize-none{resize:none}.resize-y{resize:vertical}.list-decimal{list-style-type:decimal}.list-disc{list-style-type:disc}.grid-flow-col{grid-auto-flow:column}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-cols-5{grid-template-columns:repeat(5,minmax(0,1fr))}.grid-rows-2{grid-template-rows:repeat(2,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-baseline{align-items:baseline}.items-center{align-items:center}.items-end{align-items:flex-end}.items-start{align-items:flex-start}.items-stretch{align-items:stretch}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.gap-0{gap:calc(var(--spacing) * 0)}.gap-0\.5{gap:calc(var(--spacing) * .5)}.gap-1{gap:calc(var(--spacing) * 1)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}.gap-6{gap:calc(var(--spacing) * 6)}:where(.space-y-0\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * .5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * .5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 1) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 1) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-1\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 1.5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 1.5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-y-reverse)))}.self-center{align-self:center}.self-end{align-self:flex-end}.self-start{align-self:flex-start}.self-stretch{align-self:stretch}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-sm{border-radius:var(--radius-sm)}.border{border-style:var(--tw-border-style);border-width:1px}.border-2{border-style:var(--tw-border-style);border-width:2px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-l{border-left-style:var(--tw-border-style);border-left-width:1px}.border-dashed{--tw-border-style:dashed;border-style:dashed}.border-\[\#ffcc00\]\/40{border-color:#fc06;border-color:lab(84.7597% 8.24091 84.7906/.4)}.border-accent,.border-accent\/20{border-color:var(--accent)}@supports (color:color-mix(in lab, red, red)){.border-accent\/20{border-color:color-mix(in oklab, var(--accent) 20%, transparent)}}.border-accent\/30{border-color:var(--accent)}@supports (color:color-mix(in lab, red, red)){.border-accent\/30{border-color:color-mix(in oklab, var(--accent) 30%, transparent)}}.border-accent\/40{border-color:var(--accent)}@supports (color:color-mix(in lab, red, red)){.border-accent\/40{border-color:color-mix(in oklab, var(--accent) 40%, transparent)}}.border-accent\/50{border-color:var(--accent)}@supports (color:color-mix(in lab, red, red)){.border-accent\/50{border-color:color-mix(in oklab, var(--accent) 50%, transparent)}}.border-amber-500\/40{border-color:#f99c0066}@supports (color:color-mix(in lab, red, red)){.border-amber-500\/40{border-color:color-mix(in oklab, var(--color-amber-500) 40%, transparent)}}.border-border,.border-border\/30{border-color:var(--border)}@supports (color:color-mix(in lab, red, red)){.border-border\/30{border-color:color-mix(in oklab, var(--border) 30%, transparent)}}.border-border\/40{border-color:var(--border)}@supports (color:color-mix(in lab, red, red)){.border-border\/40{border-color:color-mix(in oklab, var(--border) 40%, transparent)}}.border-border\/50{border-color:var(--border)}@supports (color:color-mix(in lab, red, red)){.border-border\/50{border-color:color-mix(in oklab, var(--border) 50%, transparent)}}.border-border\/60{border-color:var(--border)}@supports (color:color-mix(in lab, red, red)){.border-border\/60{border-color:color-mix(in oklab, var(--border) 60%, transparent)}}.border-error,.border-error\/30{border-color:var(--error)}@supports (color:color-mix(in lab, red, red)){.border-error\/30{border-color:color-mix(in oklab, var(--error) 30%, transparent)}}.border-error\/40{border-color:var(--error)}@supports (color:color-mix(in lab, red, red)){.border-error\/40{border-color:color-mix(in oklab, var(--error) 40%, transparent)}}.border-error\/60{border-color:var(--error)}@supports (color:color-mix(in lab, red, red)){.border-error\/60{border-color:color-mix(in oklab, var(--error) 60%, transparent)}}.border-red-700\/40{border-color:#bf000f66}@supports (color:color-mix(in lab, red, red)){.border-red-700\/40{border-color:color-mix(in oklab, var(--color-red-700) 40%, transparent)}}.border-red-700\/50{border-color:#bf000f80}@supports (color:color-mix(in lab, red, red)){.border-red-700\/50{border-color:color-mix(in oklab, var(--color-red-700) 50%, transparent)}}.border-white\/10{border-color:#ffffff1a}@supports (color:color-mix(in lab, red, red)){.border-white\/10{border-color:color-mix(in oklab, var(--color-white) 10%, transparent)}}.border-white\/15{border-color:#ffffff26}@supports (color:color-mix(in lab, red, red)){.border-white\/15{border-color:color-mix(in oklab, var(--color-white) 15%, transparent)}}.bg-\[\#1a1a1a\]{background-color:#1a1a1a}.bg-\[\#ffcc00\]{background-color:#fc0}.bg-accent,.bg-accent\/5{background-color:var(--accent)}@supports (color:color-mix(in lab, red, red)){.bg-accent\/5{background-color:color-mix(in oklab, var(--accent) 5%, transparent)}}.bg-accent\/10{background-color:var(--accent)}@supports (color:color-mix(in lab, red, red)){.bg-accent\/10{background-color:color-mix(in oklab, var(--accent) 10%, transparent)}}.bg-accent\/30{background-color:var(--accent)}@supports (color:color-mix(in lab, red, red)){.bg-accent\/30{background-color:color-mix(in oklab, var(--accent) 30%, transparent)}}.bg-amber-500\/5{background-color:#f99c000d}@supports (color:color-mix(in lab, red, red)){.bg-amber-500\/5{background-color:color-mix(in oklab, var(--color-amber-500) 5%, transparent)}}.bg-bg{background-color:var(--bg)}.bg-bg-surface,.bg-bg-surface\/50{background-color:var(--bg-surface)}@supports (color:color-mix(in lab, red, red)){.bg-bg-surface\/50{background-color:color-mix(in oklab, var(--bg-surface) 50%, transparent)}}.bg-black\/60{background-color:#0009}@supports (color:color-mix(in lab, red, red)){.bg-black\/60{background-color:color-mix(in oklab, var(--color-black) 60%, transparent)}}.bg-border{background-color:var(--border)}.bg-error,.bg-error\/5{background-color:var(--error)}@supports (color:color-mix(in lab, red, red)){.bg-error\/5{background-color:color-mix(in oklab, var(--error) 5%, transparent)}}.bg-error\/10{background-color:var(--error)}@supports (color:color-mix(in lab, red, red)){.bg-error\/10{background-color:color-mix(in oklab, var(--error) 10%, transparent)}}.bg-green-500{background-color:var(--color-green-500)}.bg-neutral-400{background-color:var(--color-neutral-400)}.bg-neutral-900{background-color:var(--color-neutral-900)}.bg-neutral-950{background-color:var(--color-neutral-950)}.bg-neutral-950\/90{background-color:#0a0a0ae6}@supports (color:color-mix(in lab, red, red)){.bg-neutral-950\/90{background-color:color-mix(in oklab, var(--color-neutral-950) 90%, transparent)}}.bg-red-500{background-color:var(--color-red-500)}.bg-red-900\/20{background-color:#82181a33}@supports (color:color-mix(in lab, red, red)){.bg-red-900\/20{background-color:color-mix(in oklab, var(--color-red-900) 20%, transparent)}}.bg-red-900\/30{background-color:#82181a4d}@supports (color:color-mix(in lab, red, red)){.bg-red-900\/30{background-color:color-mix(in oklab, var(--color-red-900) 30%, transparent)}}.bg-text-muted{background-color:var(--text-muted)}.bg-transparent{background-color:#0000}.bg-white\/5{background-color:#ffffff0d}@supports (color:color-mix(in lab, red, red)){.bg-white\/5{background-color:color-mix(in oklab, var(--color-white) 5%, transparent)}}.object-cover{object-fit:cover}.p-1{padding:calc(var(--spacing) * 1)}.p-1\.5{padding:calc(var(--spacing) * 1.5)}.p-2{padding:calc(var(--spacing) * 2)}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.p-5{padding:calc(var(--spacing) * 5)}.p-6{padding:calc(var(--spacing) * 6)}.px-0\.5{padding-inline:calc(var(--spacing) * .5)}.px-1{padding-inline:calc(var(--spacing) * 1)}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-5{padding-inline:calc(var(--spacing) * 5)}.px-6{padding-inline:calc(var(--spacing) * 6)}.py-0{padding-block:calc(var(--spacing) * 0)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:calc(var(--spacing) * 1)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-8{padding-block:calc(var(--spacing) * 8)}.py-10{padding-block:calc(var(--spacing) * 10)}.py-12{padding-block:calc(var(--spacing) * 12)}.py-\[1px\]{padding-block:1px}.pt-1{padding-top:calc(var(--spacing) * 1)}.pt-1\.5{padding-top:calc(var(--spacing) * 1.5)}.pt-2{padding-top:calc(var(--spacing) * 2)}.pt-6{padding-top:calc(var(--spacing) * 6)}.pb-1{padding-bottom:calc(var(--spacing) * 1)}.pb-2{padding-bottom:calc(var(--spacing) * 2)}.pb-3{padding-bottom:calc(var(--spacing) * 3)}.pb-4{padding-bottom:calc(var(--spacing) * 4)}.pb-5{padding-bottom:calc(var(--spacing) * 5)}.pb-6{padding-bottom:calc(var(--spacing) * 6)}.pl-4{padding-left:calc(var(--spacing) * 4)}.pl-6{padding-left:calc(var(--spacing) * 6)}.pl-10{padding-left:calc(var(--spacing) * 10)}.text-center{text-align:center}.text-left{text-align:left}.text-right{text-align:right}.align-middle{vertical-align:middle}.font-mono{font-family:var(--font-geist-mono)}.font-sans{font-family:var(--font-sans)}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[8px\]{font-size:8px}.text-\[9px\]{font-size:9px}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-\[12px\]{font-size:12px}.text-\[13px\]{font-size:13px}.text-\[16px\]{font-size:16px}.leading-5{--tw-leading:calc(var(--spacing) * 5);line-height:calc(var(--spacing) * 5)}.leading-none{--tw-leading:1;line-height:1}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.leading-snug{--tw-leading:var(--leading-snug);line-height:var(--leading-snug)}.leading-tight{--tw-leading:var(--leading-tight);line-height:var(--leading-tight)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-tight{--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.tracking-widest{--tw-tracking:var(--tracking-widest);letter-spacing:var(--tracking-widest)}.break-words{overflow-wrap:break-word}.break-all{word-break:break-all}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.text-\[\#ffcc00\]{color:#fc0}.text-accent,.text-accent\/70{color:var(--accent)}@supports (color:color-mix(in lab, red, red)){.text-accent\/70{color:color-mix(in oklab, var(--accent) 70%, transparent)}}.text-amber-200\/90{color:#fee685e6}@supports (color:color-mix(in lab, red, red)){.text-amber-200\/90{color:color-mix(in oklab, var(--color-amber-200) 90%, transparent)}}.text-amber-300{color:var(--color-amber-300)}.text-amber-400{color:var(--color-amber-400)}.text-bg{color:var(--bg)}.text-blue-400{color:var(--color-blue-400)}.text-error{color:var(--error)}.text-neutral-200{color:var(--color-neutral-200)}.text-neutral-300{color:var(--color-neutral-300)}.text-neutral-400{color:var(--color-neutral-400)}.text-neutral-500{color:var(--color-neutral-500)}.text-neutral-600{color:var(--color-neutral-600)}.text-neutral-700{color:var(--color-neutral-700)}.text-red-400{color:var(--color-red-400)}.text-text{color:var(--text)}.text-text-muted,.text-text-muted\/60{color:var(--text-muted)}@supports (color:color-mix(in lab, red, red)){.text-text-muted\/60{color:color-mix(in oklab, var(--text-muted) 60%, transparent)}}.text-text-muted\/80{color:var(--text-muted)}@supports (color:color-mix(in lab, red, red)){.text-text-muted\/80{color:color-mix(in oklab, var(--text-muted) 80%, transparent)}}.text-white{color:var(--color-white)}.capitalize{text-transform:capitalize}.uppercase{text-transform:uppercase}.italic{font-style:italic}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.line-through{text-decoration-line:line-through}.underline{text-decoration-line:underline}.underline-offset-2{text-underline-offset:2px}.accent-accent{accent-color:var(--accent)}.opacity-0{opacity:0}.opacity-60{opacity:.6}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-2xl{--tw-shadow:0 25px 50px -12px var(--tw-shadow-color,#00000040);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.blur{--tw-blur:blur(8px);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.backdrop-blur{--tw-backdrop-blur:blur(8px);-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.backdrop-blur-sm{--tw-backdrop-blur:blur(var(--blur-sm));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-\[width\]{transition-property:width;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-150{--tw-duration:.15s;transition-duration:.15s}.duration-200{--tw-duration:.2s;transition-duration:.2s}.ease-in-out{--tw-ease:var(--ease-in-out);transition-timing-function:var(--ease-in-out)}.outline-none{--tw-outline-style:none;outline-style:none}.select-all{-webkit-user-select:all;user-select:all}.select-none{-webkit-user-select:none;user-select:none}@media (hover:hover){.group-hover\:block:is(:where(.group):hover *){display:block}.group-hover\:text-text:is(:where(.group):hover *){color:var(--text)}.group-hover\:opacity-100:is(:where(.group):hover *){opacity:1}}.placeholder\:text-text-muted::placeholder{color:var(--text-muted)}.last\:border-b-0:last-child{border-bottom-style:var(--tw-border-style);border-bottom-width:0}.last\:pb-0:last-child{padding-bottom:calc(var(--spacing) * 0)}@media (hover:hover){.hover\:border-accent:hover,.hover\:border-accent\/40:hover{border-color:var(--accent)}@supports (color:color-mix(in lab, red, red)){.hover\:border-accent\/40:hover{border-color:color-mix(in oklab, var(--accent) 40%, transparent)}}.hover\:border-error\/40:hover{border-color:var(--error)}@supports (color:color-mix(in lab, red, red)){.hover\:border-error\/40:hover{border-color:color-mix(in oklab, var(--error) 40%, transparent)}}.hover\:border-text-muted:hover{border-color:var(--text-muted)}.hover\:border-white\/40:hover{border-color:#fff6}@supports (color:color-mix(in lab, red, red)){.hover\:border-white\/40:hover{border-color:color-mix(in oklab, var(--color-white) 40%, transparent)}}.hover\:bg-\[\#1a1a1a\]:hover{background-color:#1a1a1a}.hover\:bg-accent-dim:hover{background-color:var(--accent-dim)}.hover\:bg-accent\/5:hover{background-color:var(--accent)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-accent\/5:hover{background-color:color-mix(in oklab, var(--accent) 5%, transparent)}}.hover\:bg-accent\/10:hover{background-color:var(--accent)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-accent\/10:hover{background-color:color-mix(in oklab, var(--accent) 10%, transparent)}}.hover\:bg-accent\/20:hover{background-color:var(--accent)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-accent\/20:hover{background-color:color-mix(in oklab, var(--accent) 20%, transparent)}}.hover\:bg-error\/20:hover{background-color:var(--error)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-error\/20:hover{background-color:color-mix(in oklab, var(--error) 20%, transparent)}}.hover\:bg-white\/5:hover{background-color:#ffffff0d}@supports (color:color-mix(in lab, red, red)){.hover\:bg-white\/5:hover{background-color:color-mix(in oklab, var(--color-white) 5%, transparent)}}.hover\:text-accent:hover{color:var(--accent)}.hover\:text-accent-dim:hover{color:var(--accent-dim)}.hover\:text-blue-300:hover{color:var(--color-blue-300)}.hover\:text-blue-400:hover{color:var(--color-blue-400)}.hover\:text-error:hover{color:var(--error)}.hover\:text-text:hover{color:var(--text)}.hover\:text-white:hover{color:var(--color-white)}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-100:hover{opacity:1}}.focus\:border-accent:focus{border-color:var(--accent)}.focus\:opacity-100:focus{opacity:1}.focus\:ring-1:focus{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.focus\:ring-accent:focus{--tw-ring-color:var(--accent)}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-30:disabled{opacity:.3}.disabled\:opacity-40:disabled{opacity:.4}.disabled\:opacity-50:disabled{opacity:.5}@media (min-width:40rem){.sm\:inline{display:inline}.sm\:inline-flex{display:inline-flex}}@media (min-width:48rem){.md\:flex{display:flex}.md\:h-auto{height:auto}.md\:w-px{width:1px}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.md\:flex-row{flex-direction:row}.md\:items-start{align-items:flex-start}.md\:gap-6{gap:calc(var(--spacing) * 6)}.md\:self-stretch{align-self:stretch}.md\:border-t-0{border-top-style:var(--tw-border-style);border-top-width:0}.md\:bg-border{background-color:var(--border)}}@media (min-width:64rem){.lg\:mb-0{margin-bottom:calc(var(--spacing) * 0)}.lg\:block{display:block}.lg\:flex{display:flex}.lg\:grid{display:grid}.lg\:min-h-0{min-height:calc(var(--spacing) * 0)}.lg\:min-w-\[280px\]{min-width:280px}.lg\:flex-1{flex:1}.lg\:grid-cols-\[1fr_340px\]{grid-template-columns:1fr 340px}.lg\:flex-col{flex-direction:column}.lg\:flex-row{flex-direction:row}.lg\:gap-6{gap:calc(var(--spacing) * 6)}.lg\:overflow-hidden{overflow:hidden}.lg\:overflow-y-auto{overflow-y:auto}}@media (min-width:80rem){.xl\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}.\[\&_a\]\:text-accent a{color:var(--accent)}.\[\&_a\]\:underline a{text-decoration-line:underline}.\[\&_blockquote\]\:border-l-2 blockquote{border-left-style:var(--tw-border-style);border-left-width:2px}.\[\&_blockquote\]\:border-border blockquote{border-color:var(--border)}.\[\&_blockquote\]\:pl-2 blockquote{padding-left:calc(var(--spacing) * 2)}.\[\&_blockquote\]\:text-text-muted blockquote{color:var(--text-muted)}.\[\&_code\]\:rounded code{border-radius:.25rem}.\[\&_code\]\:bg-bg-surface code{background-color:var(--bg-surface)}.\[\&_code\]\:px-1 code{padding-inline:calc(var(--spacing) * 1)}.\[\&_code\]\:text-\[11px\] code{font-size:11px}.\[\&_h1\]\:mt-3 h1{margin-top:calc(var(--spacing) * 3)}.\[\&_h1\]\:mb-2 h1{margin-bottom:calc(var(--spacing) * 2)}.\[\&_h1\]\:text-\[14px\] h1{font-size:14px}.\[\&_h1\]\:font-semibold h1{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.\[\&_h2\]\:mt-3 h2{margin-top:calc(var(--spacing) * 3)}.\[\&_h2\]\:mb-1\.5 h2{margin-bottom:calc(var(--spacing) * 1.5)}.\[\&_h2\]\:text-\[13px\] h2{font-size:13px}.\[\&_h2\]\:font-semibold h2{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.\[\&_h3\]\:mt-2 h3{margin-top:calc(var(--spacing) * 2)}.\[\&_h3\]\:mb-1 h3{margin-bottom:calc(var(--spacing) * 1)}.\[\&_h3\]\:text-\[12px\] h3{font-size:12px}.\[\&_h3\]\:font-semibold h3{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.\[\&_hr\]\:my-3 hr{margin-block:calc(var(--spacing) * 3)}.\[\&_hr\]\:border-border hr{border-color:var(--border)}.\[\&_li\]\:my-0\.5 li{margin-block:calc(var(--spacing) * .5)}.\[\&_ol\]\:my-1\.5 ol{margin-block:calc(var(--spacing) * 1.5)}.\[\&_ol\]\:list-decimal ol{list-style-type:decimal}.\[\&_ol\]\:pl-4 ol{padding-left:calc(var(--spacing) * 4)}.\[\&_p\]\:my-1\.5 p{margin-block:calc(var(--spacing) * 1.5)}.\[\&_strong\]\:text-text strong{color:var(--text)}.\[\&_ul\]\:my-1\.5 ul{margin-block:calc(var(--spacing) * 1.5)}.\[\&_ul\]\:list-disc ul{list-style-type:disc}.\[\&_ul\]\:pl-4 ul{padding-left:calc(var(--spacing) * 4)}}:root{--bg:#0a0a0a;--bg-surface:#111;--text:#e0e0e0;--text-muted:#737373;--accent:#0f8;--accent-dim:#00cc6a;--border:#2a2a2a;--error:#f44}::selection{background:var(--accent);color:var(--bg)}body{background:var(--bg);color:var(--text);font-family:var(--font-geist-mono), ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}h1,h2,h3,h4,h5,h6{font-family:var(--font-geist-mono), ui-monospace, monospace;letter-spacing:-.01em}::-webkit-scrollbar{width:6px;height:6px}::-webkit-scrollbar-track{background:var(--bg)}::-webkit-scrollbar-thumb{background:var(--border);border-radius:0}::-webkit-scrollbar-thumb:hover{background:var(--text-muted)}:focus-visible{outline:1px solid var(--accent);outline-offset:1px}@keyframes qw-blink{0%,50%{opacity:1}51%,to{opacity:0}}.animate-qw-blink{animation:1s steps(2,start) infinite qw-blink}@keyframes qw-name-shimmer{0%,to{color:var(--accent)}50%{color:color-mix(in srgb, var(--accent) 55%, #e0e0e0)}}.animate-name-shimmer{animation:1.6s ease-in-out infinite qw-name-shimmer}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}@keyframes ping{75%,to{opacity:0;transform:scale(2)}}@keyframes pulse{50%{opacity:.5}}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,98183,(e,t,r)=>{"use strict";Object.defineProperty(r,"__esModule",{value:!0});var n={assign:function(){return i},searchParamsToUrlQuery:function(){return o},urlQueryToSearchParams:function(){return l}};for(var s in n)Object.defineProperty(r,s,{enumerable:!0,get:n[s]});function o(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 l(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 i(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}},18967,(e,t,r)=>{"use strict";Object.defineProperty(r,"__esModule",{value:!0});var n={DecodeError:function(){return g},MiddlewareNotFoundError:function(){return y},MissingStaticPage:function(){return v},NormalizeError:function(){return b},PageNotFoundError:function(){return j},SP:function(){return x},ST:function(){return m},WEB_VITALS:function(){return o},execOnce:function(){return a},getDisplayName:function(){return d},getLocationOrigin:function(){return c},getURL:function(){return u},isAbsoluteUrl:function(){return i},isResSent:function(){return f},loadGetInitialProps:function(){return p},normalizeRepeatedSlashes:function(){return h},stringifyError:function(){return w}};for(var s in n)Object.defineProperty(r,s,{enumerable:!0,get:n[s]});let o=["CLS","FCP","FID","INP","LCP","TTFB"];function a(e){let t,r=!1;return(...n)=>(r||(r=!0,t=e(...n)),t)}let l=/^[a-zA-Z][a-zA-Z\d+\-.]*?:/,i=e=>l.test(e);function c(){let{protocol:e,hostname:t,port:r}=window.location;return`${e}//${t}${r?":"+r:""}`}function u(){let{href:e}=window.location,t=c();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 v extends Error{constructor(e,t){super(),this.message=`Failed to load static file for page: ${e} ${t}`}}class y 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})}},33525,(e,t,r)=>{"use strict";Object.defineProperty(r,"__esModule",{value:!0}),Object.defineProperty(r,"warnOnce",{enumerable:!0,get:function(){return n}});let n=e=>{}},18566,(e,t,r)=>{t.exports=e.r(76562)},67449,e=>{"use strict";let t=[{value:"soft-chime",label:"Soft Chime"},{value:"warm-bell",label:"Warm Bell"},{value:"click",label:"Click"},{value:"alert-tone",label:"Alert Tone"},{value:"pluck",label:"Pluck"}],r="quadwork_notification_sound",n="quadwork_notification_sound_choice",s="quadwork_notification_sound_background_only";function o(e){try{return window.localStorage.getItem(e)}catch{return null}}function a(e,t){try{window.localStorage.setItem(e,t)}catch{}}function l(){return"off"!==o(r)}function i(){let e=o(n);return e&&t.some(t=>t.value===e)?e:"soft-chime"}function c(){let e=o(s);return null===e||"off"!==e}e.s(["NOTIFICATION_SOUND_OPTIONS",0,t,"getNotificationBackgroundOnly",0,c,"getNotificationChoice",0,i,"getNotificationEnabled",0,l,"playNotificationSound",0,function(){if(!l()||c()&&document.hasFocus())return;let e=i();try{let t=new Audio(`/sounds/${e}.mp3`);t.volume=.6,t.play().catch(()=>{})}catch{}},"setNotificationBackgroundOnly",0,function(e){a(s,e?"on":"off")},"setNotificationChoice",0,function(e){a(n,e)},"setNotificationEnabled",0,function(e){a(r,e?"on":"off")}])},95057,(e,t,r)=>{"use strict";Object.defineProperty(r,"__esModule",{value:!0});var n={formatUrl:function(){return l},formatWithValidation:function(){return c},urlObjectKeys:function(){return i}};for(var s in n)Object.defineProperty(r,s,{enumerable:!0,get:n[s]});let o=e.r(90809)._(e.r(98183)),a=/https?|ftp|gopher|file/;function l(e){let{auth:t,hostname:r}=e,n=e.protocol||"",s=e.pathname||"",l=e.hash||"",i=e.query||"",c=!1;t=t?encodeURIComponent(t).replace(/%3A/i,":")+"@":"",e.host?c=t+e.host:r&&(c=t+(~r.indexOf(":")?`[${r}]`:r),e.port&&(c+=":"+e.port)),i&&"object"==typeof i&&(i=String(o.urlQueryToSearchParams(i)));let u=e.search||i&&`?${i}`||"";return n&&!n.endsWith(":")&&(n+=":"),e.slashes||(!n||a.test(n))&&!1!==c?(c="//"+(c||""),s&&"/"!==s[0]&&(s="/"+s)):c||(c=""),l&&"#"!==l[0]&&(l="#"+l),u&&"?"!==u[0]&&(u="?"+u),s=s.replace(/[?#]/g,encodeURIComponent),u=u.replace("#","%23"),`${n}${c}${s}${u}${l}`}let i=["auth","hash","host","hostname","href","path","pathname","port","protocol","query","search","slashes"];function c(e){return l(e)}},18581,(e,t,r)=>{"use strict";Object.defineProperty(r,"__esModule",{value:!0}),Object.defineProperty(r,"useMergedRef",{enumerable:!0,get:function(){return s}});let n=e.r(71645);function s(e,t){let r=(0,n.useRef)(null),s=(0,n.useRef)(null);return(0,n.useCallback)(n=>{if(null===n){let e=r.current;e&&(r.current=null,e());let t=s.current;t&&(s.current=null,t())}else e&&(r.current=o(e,n)),t&&(s.current=o(t,n))},[e,t])}function o(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)},73668,(e,t,r)=>{"use strict";Object.defineProperty(r,"__esModule",{value:!0}),Object.defineProperty(r,"isLocalURL",{enumerable:!0,get:function(){return o}});let n=e.r(18967),s=e.r(52817);function o(e){if(!(0,n.isAbsoluteUrl)(e))return!0;try{let t=(0,n.getLocationOrigin)(),r=new URL(e,t);return r.origin===t&&(0,s.hasBasePath)(r.pathname)}catch(e){return!1}}},84508,(e,t,r)=>{"use strict";Object.defineProperty(r,"__esModule",{value:!0}),Object.defineProperty(r,"errorOnce",{enumerable:!0,get:function(){return n}});let n=e=>{}},22016,(e,t,r)=>{"use strict";Object.defineProperty(r,"__esModule",{value:!0});var n={default:function(){return g},useLinkStatus:function(){return j}};for(var s in n)Object.defineProperty(r,s,{enumerable:!0,get:n[s]});let o=e.r(90809),a=e.r(43476),l=o._(e.r(71645)),i=e.r(95057),c=e.r(8372),u=e.r(18581),d=e.r(18967),f=e.r(5550);e.r(33525);let h=e.r(88540),p=e.r(91949),x=e.r(73668),m=e.r(9396);function g(t){var r,n;let s,o,g,[j,v]=(0,l.useOptimistic)(p.IDLE_LINK_STATUS),y=(0,l.useRef)(null),{href:w,as:k,children:N,prefetch:C=null,passHref:S,replace:_,shallow:E,scroll:P,onClick:L,onMouseEnter:O,onTouchStart:T,legacyBehavior:I=!1,onNavigate:M,transitionTypes:$,ref:R,unstable_dynamicOnHover:A,...B}=t;s=N,I&&("string"==typeof s||"number"==typeof s)&&(s=(0,a.jsx)("a",{children:s}));let U=l.default.useContext(c.AppRouterContext),F=!1!==C,W=!1!==C?null===(n=C)||"auto"===n?m.FetchStrategy.PPR:m.FetchStrategy.Full:m.FetchStrategy.PPR,z="string"==typeof(r=k||w)?r:(0,i.formatUrl)(r);if(I){if(s?.$$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});o=l.default.Children.only(s)}let q=I?o&&"object"==typeof o&&o.ref:R,D=l.default.useCallback(e=>(null!==U&&(y.current=(0,p.mountLinkInstance)(e,z,U,W,F,v)),()=>{y.current&&((0,p.unmountLinkForCurrentNavigation)(y.current),y.current=null),(0,p.unmountPrefetchableInstance)(e)}),[F,z,U,W,v]),K={ref:(0,u.useMergedRef)(D,q),onClick(t){I||"function"!=typeof L||L(t),I&&o.props&&"function"==typeof o.props.onClick&&o.props.onClick(t),!U||t.defaultPrevented||function(t,r,n,s,o,a,i){if("u">typeof window){let c,{nodeName:u}=t.currentTarget;if("A"===u.toUpperCase()&&((c=t.currentTarget.getAttribute("target"))&&"_self"!==c||t.metaKey||t.ctrlKey||t.shiftKey||t.altKey||t.nativeEvent&&2===t.nativeEvent.which)||t.currentTarget.hasAttribute("download"))return;if(!(0,x.isLocalURL)(r)){s&&(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(99781);l.default.startTransition(()=>{d(r,s?"replace":"push",!1===o?h.ScrollBehavior.NoScroll:h.ScrollBehavior.Default,n.current,i)})}}(t,z,y,_,P,M,$)},onMouseEnter(e){I||"function"!=typeof O||O(e),I&&o.props&&"function"==typeof o.props.onMouseEnter&&o.props.onMouseEnter(e),U&&F&&(0,p.onNavigationIntent)(e.currentTarget,!0===A)},onTouchStart:function(e){I||"function"!=typeof T||T(e),I&&o.props&&"function"==typeof o.props.onTouchStart&&o.props.onTouchStart(e),U&&F&&(0,p.onNavigationIntent)(e.currentTarget,!0===A)}};return(0,d.isAbsoluteUrl)(z)?K.href=z:I&&!S&&("a"!==o.type||"href"in o.props)||(K.href=(0,f.addBasePath)(z)),g=I?l.default.cloneElement(o,K):(0,a.jsx)("a",{...B,...K,children:s}),(0,a.jsx)(b.Provider,{value:j,children:g})}e.r(84508);let b=(0,l.createContext)(p.IDLE_LINK_STATUS),j=()=>(0,l.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)},22140,e=>{"use strict";var t=e.i(43476),r=e.i(22016),n=e.i(18566),s=e.i(71645);function o(){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 l(){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 i(){return(0,t.jsx)("svg",{width:"16",height:"16",viewBox:"0 0 16 16",fill:"none",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round",children:(0,t.jsx)("path",{d:"M10 3L5 8l5 5"})})}function c(){return(0,t.jsx)("svg",{width:"16",height:"16",viewBox:"0 0 16 16",fill:"none",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round",children:(0,t.jsx)("path",{d:"M6 3l5 5-5 5"})})}function u({collapsed:e}){return(0,t.jsx)("svg",{width:"12",height:"12",viewBox:"0 0 12 12",fill:"none",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round",className:`transition-transform duration-150 ${e?"-rotate-90":""}`,children:(0,t.jsx)("path",{d:"M3 4.5l3 3 3-3"})})}function d({size:e=10}){return(0,t.jsxs)("svg",{width:e,height:e,viewBox:"0 0 16 16",fill:"currentColor",stroke:"none",children:[(0,t.jsx)("path",{d:"M10.5 1.5L14.5 5.5L10 7.5L8.5 12.5L3.5 7.5L8.5 6L10.5 1.5Z"}),(0,t.jsx)("path",{d:"M3.5 7.5L1 15L8.5 12.5"})]})}function f({project:e,isActive:n,expanded:o,pinned:a,onContextMenu:l}){let[i,c]=(0,s.useState)(null),u=(0,s.useRef)(null);return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)(r.default,{ref:u,href:`/project/${e.id}`,className:`flex items-center gap-2 ${o?"w-full px-2":""} rounded-sm transition-colors ${!o?"":n?"bg-[#1a1a1a]":"hover:bg-[#1a1a1a]"}`,onMouseEnter:()=>{if(o)return;let e=u.current?.getBoundingClientRect();e&&c({top:e.top+e.height/2})},onMouseLeave:()=>c(null),onContextMenu:t=>l(t,e.id),children:[(0,t.jsxs)("div",{className:"relative shrink-0",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"}`,children:e.name.slice(0,2)||"?"}),a&&!o&&(0,t.jsx)("div",{className:"absolute -top-1 -right-1 text-accent",children:(0,t.jsx)(d,{size:8})})]}),o&&(0,t.jsxs)("span",{className:`text-xs truncate flex items-center gap-1 ${n?"text-accent":"text-text-muted"}`,children:[e.name,a&&(0,t.jsx)(d,{size:10})]})]}),!o&&i&&(0,t.jsxs)("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:i.top,transform:"translateY(-50%)"},children:[a&&"📌 ",e.name]})]})}let h="qw-sidebar-expanded",p="qw-sidebar-collapsed-groups";e.s(["default",0,function(){let e=(0,n.usePathname)(),[d,x]=(0,s.useState)([]),[m,g]=(0,s.useState)([]),[b,j]=(0,s.useState)([]),[v,y]=(0,s.useState)(new Set),[w,k]=(0,s.useState)("online"),[N,C]=(0,s.useState)(!1),[S,_]=(0,s.useState)(null),E=(0,s.useRef)(null);(0,s.useEffect)(()=>{try{if(window.innerWidth>=768){let e=localStorage.getItem(h);"true"===e&&C(!0)}let e=localStorage.getItem(p);e&&y(new Set(JSON.parse(e)))}catch{}},[]),(0,s.useEffect)(()=>{let e=window.matchMedia("(max-width: 767px)"),t=e=>{e.matches&&C(!1)};return e.addEventListener("change",t),()=>e.removeEventListener("change",t)},[]),(0,s.useEffect)(()=>{fetch("/api/config").then(e=>{if(!e.ok)throw Error(`Config fetch failed: ${e.status}`);return e.json()}).then(e=>{E.current=e,x((e.projects||[]).filter(e=>!e.archived)),g(e.pinned_projects||[]),j(e.sidebar_groups||[])}).catch(()=>{})},[]),(0,s.useEffect)(()=>{let e,t=!1,r=async()=>{try{let e=await fetch("/api/health",{signal:AbortSignal.timeout(3e3)});if(t)return;e.ok?k(e=>"offline"===e?"recovering":"online"):k("offline")}catch{if(t)return;k("offline")}t||(e=setTimeout(r,5e3))};return r(),()=>{t=!0,clearTimeout(e)}},[]),(0,s.useEffect)(()=>{if("recovering"===w){let e=setTimeout(()=>k("online"),1500);return()=>clearTimeout(e)}},[w]);let P="/"===e,L="/settings"===e,O=e.startsWith("/project/")?e.split("/")[2]:null,T=(0,s.useCallback)(e=>{g(e),fetch("/api/config").then(e=>e.json()).then(t=>{let r={...t,pinned_projects:e};return E.current=r,fetch("/api/config",{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify(r)})}).catch(()=>{})},[]),I=(0,s.useCallback)(e=>{j(e),fetch("/api/config").then(e=>e.json()).then(t=>{let r={...t,sidebar_groups:e};return E.current=r,fetch("/api/config",{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify(r)})}).catch(()=>{})},[]),M=(e,t)=>{let r=b.map(t=>({...t,projects:t.projects.filter(t=>t!==e)}));if("__ungrouped__"===t)I(r.filter(e=>e.projects.length>0));else{let n=r.find(e=>e.name===t);n?n.projects.push(e):r.push({name:t,projects:[e]}),I(r.filter(e=>e.projects.length>0))}_(null)},$=(e,t)=>{e.preventDefault(),_({x:e.clientX,y:e.clientY,projectId:t})};(0,s.useEffect)(()=>{if(!S)return;let e=()=>_(null);return window.addEventListener("click",e),()=>window.removeEventListener("click",e)},[S]);let R=new Set(m),A=m.map(e=>d.find(t=>t.id===e)).filter(e=>!!e),B=new Set(b.flatMap(e=>e.projects)),U=d.filter(e=>!R.has(e.id)),F=U.filter(e=>!B.has(e.id));return(0,t.jsxs)("aside",{className:`shrink-0 h-full border-r border-border bg-bg-surface flex flex-col py-3 transition-[width] duration-200 ease-in-out overflow-hidden ${N?"w-52 items-stretch px-2":"w-16 items-center"}`,children:[(0,t.jsx)("button",{onClick:()=>{C(e=>{let t=!e;try{localStorage.setItem(h,String(t))}catch{}return t})},className:`hidden md:flex shrink-0 items-center justify-center w-8 h-8 rounded-sm text-text-muted hover:text-text hover:bg-[#1a1a1a] transition-colors ${N?"self-end mr-0":"self-center"}`,title:N?"Collapse sidebar":"Expand sidebar",children:N?(0,t.jsx)(i,{}):(0,t.jsx)(c,{})}),(0,t.jsx)("div",{className:"h-1"}),(0,t.jsxs)(r.default,{href:"/",className:`flex items-center gap-2 rounded-sm transition-colors ${N?"px-2 py-2":"w-10 h-10 justify-center self-center"} ${P?"text-accent":"text-text-muted hover:text-text hover:bg-[#1a1a1a]"}`,title:"Home",children:[(0,t.jsx)(o,{}),N&&(0,t.jsx)("span",{className:"text-xs",children:"Home"})]}),(0,t.jsx)("div",{className:`h-px bg-border my-2 ${N?"":"w-6 self-center"}`}),(0,t.jsxs)("div",{className:`flex-1 flex flex-col gap-2 overflow-y-auto min-h-0 ${N?"":"items-center"}`,children:[A.length>0&&(0,t.jsxs)(t.Fragment,{children:[N&&(0,t.jsx)("span",{className:"text-[10px] uppercase tracking-widest text-text-muted px-2",children:"Pinned"}),A.map(e=>(0,t.jsx)(f,{project:e,isActive:O===e.id,expanded:N,pinned:!0,onContextMenu:$},e.id)),(0,t.jsx)("div",{className:`h-px bg-border ${N?"":"w-6"}`})]}),b.map(e=>{let r=e.projects.map(e=>U.find(t=>t.id===e)).filter(e=>!!e);if(0===r.length)return null;let n=v.has(e.name);return(0,t.jsxs)("div",{className:"flex flex-col gap-1",children:[(0,t.jsx)("button",{onClick:()=>{var t;return t=e.name,void y(e=>{let r=new Set(e);r.has(t)?r.delete(t):r.add(t);try{localStorage.setItem(p,JSON.stringify([...r]))}catch{}return r})},className:`flex items-center gap-1 text-text-muted hover:text-text transition-colors ${N?"px-2 py-0.5":"justify-center w-full"}`,title:`${n?"Expand":"Collapse"} ${e.name}`,children:N?(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(u,{collapsed:n}),(0,t.jsx)("span",{className:"text-[10px] uppercase tracking-widest truncate",children:e.name})]}):(0,t.jsx)("div",{className:`w-6 h-px ${n?"bg-text-muted":"bg-border"}`})}),!n&&r.map(e=>(0,t.jsx)(f,{project:e,isActive:O===e.id,expanded:N,pinned:!1,onContextMenu:$},e.id))]},e.name)}),F.length>0&&b.length>0&&(0,t.jsxs)(t.Fragment,{children:[N&&(0,t.jsx)("span",{className:"text-[10px] uppercase tracking-widest text-text-muted px-2",children:"Ungrouped"}),b.length>0&&!N&&(0,t.jsx)("div",{className:"w-6 h-px bg-border"})]}),F.map(e=>(0,t.jsx)(f,{project:e,isActive:O===e.id,expanded:N,pinned:!1,onContextMenu:$},e.id)),(0,t.jsxs)(r.default,{href:"/setup",className:`flex items-center gap-2 rounded-full transition-colors ${N?"px-2 py-2 border border-dashed border-border text-text-muted hover:text-text hover:bg-[#1a1a1a] rounded-sm":"w-10 h-10 justify-center border border-dashed border-border text-text-muted hover:text-text hover:bg-[#1a1a1a]"}`,title:"Add project",children:[(0,t.jsx)(l,{}),N&&(0,t.jsx)("span",{className:"text-xs text-text-muted",children:"New Project"})]})]}),S&&(0,t.jsxs)("div",{className:"fixed bg-bg-surface border border-border py-1 z-50 text-xs",style:{left:S.x,top:S.y},onClick:e=>e.stopPropagation(),children:[R.has(S.projectId)?(0,t.jsx)("button",{className:"w-full px-3 py-1.5 text-left text-text hover:bg-[#1a1a1a] transition-colors",onClick:()=>{var e;return e=S.projectId,void(T(m.filter(t=>t!==e)),_(null))},children:"Unpin"}):(0,t.jsx)("button",{className:"w-full px-3 py-1.5 text-left text-text hover:bg-[#1a1a1a] transition-colors",onClick:()=>{var e;return e=S.projectId,void(!m.includes(e)&&(T([e,...m]),_(null)))},children:"Pin to top"}),(0,t.jsx)("div",{className:"h-px bg-border my-1"}),S.showGroupMenu?(0,t.jsxs)("div",{className:"flex flex-col",children:[b.map(e=>(0,t.jsx)("button",{className:"w-full px-3 py-1.5 text-left text-text hover:bg-[#1a1a1a] transition-colors",onClick:()=>M(S.projectId,e.name),children:e.name},e.name)),(0,t.jsx)("button",{className:"w-full px-3 py-1.5 text-left text-text hover:bg-[#1a1a1a] transition-colors",onClick:()=>{let e=prompt("New group name:");if(!e?.trim())return;let t=e.trim();b.some(e=>e.name.toLowerCase()===t.toLowerCase())?alert(`Group "${t}" already exists.`):M(S.projectId,t)},children:"+ New group"}),B.has(S.projectId)&&(0,t.jsx)("button",{className:"w-full px-3 py-1.5 text-left text-text-muted hover:bg-[#1a1a1a] transition-colors",onClick:()=>M(S.projectId,"__ungrouped__"),children:"Remove from group"})]}):(0,t.jsx)("button",{className:"w-full px-3 py-1.5 text-left text-text hover:bg-[#1a1a1a] transition-colors",onClick:()=>_({...S,showGroupMenu:!0}),children:"Move to group..."})]}),(0,t.jsx)("div",{className:`h-px bg-border my-2 ${N?"":"w-6 self-center"}`}),"online"!==w&&(0,t.jsxs)("div",{className:`mb-2 relative group ${N?"px-2":"self-center"}`,children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)("div",{className:`w-3 h-3 shrink-0 rounded-full ${"offline"===w?"bg-red-500 animate-pulse":"bg-green-500"}`}),N&&(0,t.jsx)("span",{className:"text-xs text-text-muted",children:"offline"===w?"Backend offline":"Reconnected"})]}),!N&&(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"===w?"Backend offline — run quadwork start":"Backend reconnected"})]}),(0,t.jsxs)(r.default,{href:"/settings",className:`flex items-center gap-2 rounded-sm transition-colors ${N?"px-2 py-2":"w-10 h-10 justify-center self-center"} ${L?"text-accent":"text-text-muted hover:text-text hover:bg-[#1a1a1a]"}`,title:"Settings",children:[(0,t.jsx)(a,{}),N&&(0,t.jsx)("span",{className:"text-xs",children:"Settings"})]})]})}])},26704,e=>{"use strict";var t=e.i(43476),r=e.i(22016),n=e.i(71645);function s({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 o=["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 l(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,i]=(0,n.useState)(!1);(0,n.useEffect)(()=>{i(!0)},[]);let[c,u]=(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,s]=(0,n.useState)(0),[o,a]=(0,n.useState)(""),[l,i]=(0,n.useState)("typing");return(0,n.useEffect)(()=>{let n;if(!t)return;let c=e[r];return"typing"===l?n=o.length<c.length?setTimeout(()=>a(c.slice(0,o.length+1)),70):setTimeout(()=>i("holding"),0):"holding"===l?n=setTimeout(()=>i("deleting"),2e3):o.length>0?n=setTimeout(()=>a(c.slice(0,o.length-1)),35):(s(t=>(t+1)%e.length),i("typing")),()=>clearTimeout(n)},[o,l,r,e,t]),o}(o,x),b=x?g:o[0]||"",[j,v]=(0,n.useState)(!1);(0,n.useEffect)(()=>{if(!x)return void v(!0);let e=setTimeout(()=>v(!0),5e3);return()=>clearTimeout(e)},[x]);let y=(0,n.useRef)(!1);return((0,n.useEffect)(()=>{x&&(g.length>0?y.current=!0:y.current&&v(!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.jsxs)(r.default,{href:"/",className:"flex items-center gap-1.5 text-sm font-bold text-accent hover:text-blue-400 shrink-0",children:[(0,t.jsx)("img",{src:"/icon.svg",alt:"",width:18,height:18,className:"inline-block"}),"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:l(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:l(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:l(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:l(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:l(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:()=>u(!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)(s,{open:c,onClose:()=>u(!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"})}],26704)},43688,e=>{"use strict";var t=e.i(71645),r=e.i(67449);e.s(["default",0,function(){let e=(0,t.useRef)({}),n=(0,t.useRef)("user"),s=(0,t.useRef)([]),o=(0,t.useRef)(!1),a=(0,t.useRef)(new Set),l=(0,t.useCallback)(t=>{null==e.current[t]&&(e.current[t]=0,a.current.add(t))},[]),i=(0,t.useCallback)(()=>{fetch("/api/config").then(e=>e.ok?e.json():null).then(t=>{if(!t)return;"string"==typeof t.operator_name&&t.operator_name&&(n.current=t.operator_name);let r=t.projects||[];for(let e of(s.current=r,r))l(e.id);let a=new Set(r.map(e=>e.id));for(let t of Object.keys(e.current))a.has(t)||delete e.current[t];o.current=!0}).catch(()=>{})},[l]);(0,t.useEffect)(()=>{i();let e=setInterval(i,3e4);return()=>clearInterval(e)},[i]);let c=(0,t.useCallback)(()=>{if(o.current)for(let t of s.current){let s=e.current[t.id];null!=s&&fetch(`/api/chat?path=/api/messages&channel=general&cursor=${s}&project=${encodeURIComponent(t.id)}`).then(e=>e.ok?e.json():null).then(s=>{if(!s)return;let o=Array.isArray(s)?s:s.messages||[];if(0===o.length)return void a.current.delete(t.id);let l=e.current[t.id]??0,i=Math.max(...o.map(e=>e.id));i>l&&(e.current[t.id]=i);let c=n.current;a.current.has(t.id)?a.current.delete(t.id):o.some(e=>e.id>l&&(void 0===e.type||"chat"===e.type)&&"user"!==e.sender&&e.sender!==c&&"system"!==e.sender)&&(0,r.playNotificationSound)()}).catch(()=>{})}},[]);return(0,t.useEffect)(()=>{let e=setInterval(c,3e3);return()=>clearInterval(e)},[c]),null}])}]);
|
|
File without changes
|
|
File without changes
|
|
File without changes
|