copilot-agent 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +539 -1
- package/dist/index.js.map +1 -1
- package/package.json +26 -7
package/dist/index.js
CHANGED
|
@@ -1331,14 +1331,552 @@ function renderReport(r) {
|
|
|
1331
1331
|
log("");
|
|
1332
1332
|
}
|
|
1333
1333
|
|
|
1334
|
+
// src/commands/dashboard.ts
|
|
1335
|
+
var ESC = "\x1B";
|
|
1336
|
+
var CLEAR = `${ESC}[2J${ESC}[H`;
|
|
1337
|
+
var HIDE_CURSOR = `${ESC}[?25l`;
|
|
1338
|
+
var SHOW_CURSOR = `${ESC}[?25h`;
|
|
1339
|
+
var SAVE_CURSOR = `${ESC}7`;
|
|
1340
|
+
var RESTORE_CURSOR = `${ESC}8`;
|
|
1341
|
+
function registerDashboardCommand(program2) {
|
|
1342
|
+
program2.command("dashboard").alias("tui").description("Real-time terminal dashboard for copilot sessions").option("-r, --refresh <n>", "Refresh interval in seconds", "5").option("-l, --limit <n>", "Number of sessions to show", "8").action((opts) => {
|
|
1343
|
+
runDashboard(parseInt(opts.refresh, 10), parseInt(opts.limit, 10));
|
|
1344
|
+
});
|
|
1345
|
+
}
|
|
1346
|
+
function runDashboard(refreshSec, limit) {
|
|
1347
|
+
process.stdout.write(HIDE_CURSOR);
|
|
1348
|
+
const cleanup = () => {
|
|
1349
|
+
process.stdout.write(SHOW_CURSOR);
|
|
1350
|
+
process.stdout.write(CLEAR);
|
|
1351
|
+
process.exit(0);
|
|
1352
|
+
};
|
|
1353
|
+
process.on("SIGINT", cleanup);
|
|
1354
|
+
process.on("SIGTERM", cleanup);
|
|
1355
|
+
const render = () => {
|
|
1356
|
+
try {
|
|
1357
|
+
const output = buildScreen(limit);
|
|
1358
|
+
process.stdout.write(CLEAR + output);
|
|
1359
|
+
} catch {
|
|
1360
|
+
}
|
|
1361
|
+
};
|
|
1362
|
+
render();
|
|
1363
|
+
const timer = setInterval(render, refreshSec * 1e3);
|
|
1364
|
+
process.stdout.on("resize", render);
|
|
1365
|
+
process.stdin.setRawMode?.(true);
|
|
1366
|
+
process.stdin.resume();
|
|
1367
|
+
process.stdin.on("data", (data) => {
|
|
1368
|
+
const key = data.toString();
|
|
1369
|
+
if (key === "q" || key === "") {
|
|
1370
|
+
clearInterval(timer);
|
|
1371
|
+
cleanup();
|
|
1372
|
+
}
|
|
1373
|
+
if (key === "r") render();
|
|
1374
|
+
});
|
|
1375
|
+
}
|
|
1376
|
+
function buildScreen(limit) {
|
|
1377
|
+
const cols = process.stdout.columns || 80;
|
|
1378
|
+
const rows = process.stdout.rows || 40;
|
|
1379
|
+
const lines = [];
|
|
1380
|
+
const now = /* @__PURE__ */ new Date();
|
|
1381
|
+
const timeStr = now.toLocaleTimeString("en-GB");
|
|
1382
|
+
lines.push("");
|
|
1383
|
+
lines.push(` ${BOLD}${CYAN}\u250C${"\u2500".repeat(cols - 6)}\u2510${RESET}`);
|
|
1384
|
+
lines.push(` ${BOLD}${CYAN}\u2502${RESET} \u{1F916} ${BOLD}Copilot Agent Dashboard${RESET}${" ".repeat(Math.max(0, cols - 37 - timeStr.length))}${DIM}${timeStr}${RESET} ${BOLD}${CYAN}\u2502${RESET}`);
|
|
1385
|
+
lines.push(` ${BOLD}${CYAN}\u2514${"\u2500".repeat(cols - 6)}\u2518${RESET}`);
|
|
1386
|
+
lines.push("");
|
|
1387
|
+
const procs = findCopilotProcesses();
|
|
1388
|
+
lines.push(` ${BOLD}${GREEN}\u25CF Active Processes (${procs.length})${RESET}`);
|
|
1389
|
+
lines.push(` ${"\u2500".repeat(Math.min(cols - 4, 70))}`);
|
|
1390
|
+
if (procs.length === 0) {
|
|
1391
|
+
lines.push(` ${DIM}No copilot processes running${RESET}`);
|
|
1392
|
+
} else {
|
|
1393
|
+
for (const p of procs) {
|
|
1394
|
+
const sid = p.sessionId ? p.sessionId.slice(0, 8) + "\u2026" : "\u2014";
|
|
1395
|
+
const cwdShort = p.cwd ? "~/" + p.cwd.split("/").slice(-2).join("/") : "\u2014";
|
|
1396
|
+
lines.push(` ${GREEN}\u2B24${RESET} PID ${BOLD}${p.pid}${RESET} ${CYAN}${sid}${RESET} ${DIM}${cwdShort}${RESET}`);
|
|
1397
|
+
}
|
|
1398
|
+
}
|
|
1399
|
+
lines.push("");
|
|
1400
|
+
const sessions = listSessions(limit);
|
|
1401
|
+
lines.push(` ${BOLD}${CYAN}\u25CF Recent Sessions (${sessions.length})${RESET}`);
|
|
1402
|
+
lines.push(` ${"\u2500".repeat(Math.min(cols - 4, 70))}`);
|
|
1403
|
+
const headerCols = [
|
|
1404
|
+
pad("Status", 10),
|
|
1405
|
+
pad("Premium", 8),
|
|
1406
|
+
pad("Duration", 10),
|
|
1407
|
+
pad("Project", 18),
|
|
1408
|
+
pad("Last Activity", 20)
|
|
1409
|
+
];
|
|
1410
|
+
lines.push(` ${DIM}${headerCols.join(" ")}${RESET}`);
|
|
1411
|
+
for (const s of sessions) {
|
|
1412
|
+
const report = getSessionReport(s.id);
|
|
1413
|
+
const statusIcon = s.complete ? `${GREEN}\u2714 done ${RESET}` : `${YELLOW}\u23F8 stop ${RESET}`;
|
|
1414
|
+
const premium = pad(String(s.premiumRequests), 8);
|
|
1415
|
+
const duration = report ? pad(formatDuration2(report.durationMs), 10) : pad("\u2014", 10);
|
|
1416
|
+
const project = pad(s.cwd.split("/").pop() ?? "\u2014", 18);
|
|
1417
|
+
const lastAct = pad(formatTimeAgo(s.mtime), 20);
|
|
1418
|
+
lines.push(` ${statusIcon}${premium}${duration}${project}${lastAct}`);
|
|
1419
|
+
}
|
|
1420
|
+
lines.push("");
|
|
1421
|
+
if (sessions.length > 0) {
|
|
1422
|
+
const latest = getSessionReport(sessions[0].id);
|
|
1423
|
+
if (latest) {
|
|
1424
|
+
lines.push(` ${BOLD}${CYAN}\u25CF Latest Session Detail${RESET} ${DIM}${latest.id.slice(0, 8)}\u2026${RESET}`);
|
|
1425
|
+
lines.push(` ${"\u2500".repeat(Math.min(cols - 4, 70))}`);
|
|
1426
|
+
lines.push(` Turns: ${BOLD}${latest.assistantTurns}${RESET} Tokens: ${BOLD}${latest.outputTokens.toLocaleString()}${RESET} Premium: ${BOLD}${latest.premiumRequests}${RESET} Commits: ${BOLD}${latest.gitCommits.length}${RESET} Files: ${BOLD}${latest.filesEdited.length}${RESET} edited, ${BOLD}${latest.filesCreated.length}${RESET} created`);
|
|
1427
|
+
lines.push("");
|
|
1428
|
+
const toolEntries = Object.entries(latest.toolUsage).sort((a, b) => b[1] - a[1]).slice(0, 5);
|
|
1429
|
+
if (toolEntries.length > 0) {
|
|
1430
|
+
const maxVal = toolEntries[0][1];
|
|
1431
|
+
const barW = Math.min(20, Math.floor((cols - 30) / 2));
|
|
1432
|
+
lines.push(` ${DIM}Tools:${RESET}`);
|
|
1433
|
+
for (const [tool, count] of toolEntries) {
|
|
1434
|
+
const filled = Math.round(count / maxVal * barW);
|
|
1435
|
+
const b = `${CYAN}${"\u2588".repeat(filled)}${DIM}${"\u2591".repeat(barW - filled)}${RESET}`;
|
|
1436
|
+
lines.push(` ${b} ${String(count).padStart(4)} ${tool}`);
|
|
1437
|
+
}
|
|
1438
|
+
lines.push("");
|
|
1439
|
+
}
|
|
1440
|
+
if (latest.gitCommits.length > 0) {
|
|
1441
|
+
const maxCommits = Math.min(3, latest.gitCommits.length);
|
|
1442
|
+
lines.push(` ${DIM}Recent commits:${RESET}`);
|
|
1443
|
+
for (let i = 0; i < maxCommits; i++) {
|
|
1444
|
+
const msg = latest.gitCommits[i].split("\n")[0].slice(0, cols - 10);
|
|
1445
|
+
lines.push(` ${GREEN}\u25CF${RESET} ${msg}`);
|
|
1446
|
+
}
|
|
1447
|
+
if (latest.gitCommits.length > maxCommits) {
|
|
1448
|
+
lines.push(` ${DIM} \u2026 +${latest.gitCommits.length - maxCommits} more${RESET}`);
|
|
1449
|
+
}
|
|
1450
|
+
lines.push("");
|
|
1451
|
+
}
|
|
1452
|
+
if (latest.taskCompletions.length > 0) {
|
|
1453
|
+
const maxTasks = Math.min(3, latest.taskCompletions.length);
|
|
1454
|
+
lines.push(` ${DIM}Completed tasks:${RESET}`);
|
|
1455
|
+
for (let i = 0; i < maxTasks; i++) {
|
|
1456
|
+
const msg = latest.taskCompletions[i].split("\n")[0].slice(0, cols - 10);
|
|
1457
|
+
lines.push(` ${GREEN}\u2714${RESET} ${msg}`);
|
|
1458
|
+
}
|
|
1459
|
+
if (latest.taskCompletions.length > maxTasks) {
|
|
1460
|
+
lines.push(` ${DIM} \u2026 +${latest.taskCompletions.length - maxTasks} more${RESET}`);
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
lines.push("");
|
|
1466
|
+
lines.push(` ${DIM}Press ${BOLD}q${RESET}${DIM} to quit, ${BOLD}r${RESET}${DIM} to refresh${RESET}`);
|
|
1467
|
+
return lines.join("\n");
|
|
1468
|
+
}
|
|
1469
|
+
function pad(s, n) {
|
|
1470
|
+
if (s.length >= n) return s.slice(0, n);
|
|
1471
|
+
return s + " ".repeat(n - s.length);
|
|
1472
|
+
}
|
|
1473
|
+
function formatDuration2(ms) {
|
|
1474
|
+
if (ms < 6e4) return `${Math.round(ms / 1e3)}s`;
|
|
1475
|
+
if (ms < 36e5) return `${Math.round(ms / 6e4)}m`;
|
|
1476
|
+
const h = Math.floor(ms / 36e5);
|
|
1477
|
+
const m = Math.round(ms % 36e5 / 6e4);
|
|
1478
|
+
return `${h}h ${m}m`;
|
|
1479
|
+
}
|
|
1480
|
+
function formatTimeAgo(mtimeMs) {
|
|
1481
|
+
const diff = Date.now() - mtimeMs;
|
|
1482
|
+
if (diff < 6e4) return "just now";
|
|
1483
|
+
if (diff < 36e5) return `${Math.round(diff / 6e4)}m ago`;
|
|
1484
|
+
if (diff < 864e5) return `${Math.round(diff / 36e5)}h ago`;
|
|
1485
|
+
return `${Math.round(diff / 864e5)}d ago`;
|
|
1486
|
+
}
|
|
1487
|
+
|
|
1488
|
+
// src/commands/web.ts
|
|
1489
|
+
import { Hono } from "hono";
|
|
1490
|
+
import { streamSSE } from "hono/streaming";
|
|
1491
|
+
import { serve } from "@hono/node-server";
|
|
1492
|
+
import { spawn as spawn2 } from "child_process";
|
|
1493
|
+
|
|
1494
|
+
// src/web/layout.ts
|
|
1495
|
+
var cssStyles = `
|
|
1496
|
+
*{margin:0;padding:0;box-sizing:border-box}
|
|
1497
|
+
:root{
|
|
1498
|
+
--bg:#0d1117;--bg2:#161b22;--bg3:#21262d;--bg4:#292e36;
|
|
1499
|
+
--border:#30363d;--border2:#3d444d;
|
|
1500
|
+
--text:#e6edf3;--text2:#8b949e;--text3:#484f58;
|
|
1501
|
+
--cyan:#58a6ff;--green:#3fb950;--yellow:#d29922;--red:#f85149;--purple:#bc8cff;--orange:#f0883e;
|
|
1502
|
+
--font-sans:'Inter',system-ui,sans-serif;
|
|
1503
|
+
--font-mono:'JetBrains Mono','SF Mono',monospace;
|
|
1504
|
+
--radius:8px;
|
|
1505
|
+
}
|
|
1506
|
+
body{background:var(--bg);color:var(--text);font-family:var(--font-sans);font-size:14px;line-height:1.5;-webkit-font-smoothing:antialiased}
|
|
1507
|
+
.header{background:var(--bg2);border-bottom:1px solid var(--border);padding:12px 24px;display:flex;align-items:center;justify-content:space-between;position:sticky;top:0;z-index:10;backdrop-filter:blur(12px)}
|
|
1508
|
+
.header-left{display:flex;align-items:center;gap:10px}
|
|
1509
|
+
.header-left h1{font-size:16px;font-weight:600}
|
|
1510
|
+
.header-left h1 span{color:var(--cyan)}
|
|
1511
|
+
.live-badge{display:flex;align-items:center;gap:6px;font-size:12px;color:var(--green);background:rgba(63,185,80,.1);padding:3px 10px;border-radius:12px;font-weight:500}
|
|
1512
|
+
.live-dot{width:6px;height:6px;border-radius:50%;background:var(--green);animation:pulse 2s infinite}
|
|
1513
|
+
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.3}}
|
|
1514
|
+
.clock{font-family:var(--font-mono);font-size:13px;color:var(--text2)}
|
|
1515
|
+
.container{max-width:1280px;margin:0 auto;padding:16px 20px}
|
|
1516
|
+
.stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:10px;margin-bottom:16px}
|
|
1517
|
+
.stat{background:var(--bg2);border:1px solid var(--border);border-radius:var(--radius);padding:14px 16px;transition:border-color .2s}
|
|
1518
|
+
.stat:hover{border-color:var(--border2)}
|
|
1519
|
+
.stat-label{font-size:11px;font-weight:500;color:var(--text2);text-transform:uppercase;letter-spacing:.4px}
|
|
1520
|
+
.stat-value{font-size:22px;font-weight:700;font-family:var(--font-mono);margin-top:2px}
|
|
1521
|
+
.stat-value.green{color:var(--green)}.stat-value.cyan{color:var(--cyan)}
|
|
1522
|
+
.stat-value.yellow{color:var(--yellow)}.stat-value.purple{color:var(--purple)}
|
|
1523
|
+
.procs{background:var(--bg2);border:1px solid var(--border);border-radius:var(--radius);margin-bottom:16px;overflow:hidden}
|
|
1524
|
+
.procs-header{padding:10px 16px;font-size:13px;font-weight:600;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:8px}
|
|
1525
|
+
.procs-body{padding:4px 0}
|
|
1526
|
+
.proc{padding:6px 16px;display:flex;align-items:center;gap:10px;font-size:13px}
|
|
1527
|
+
.proc-dot{width:6px;height:6px;border-radius:50%;background:var(--green);flex-shrink:0}
|
|
1528
|
+
.proc-pid{font-family:var(--font-mono);color:var(--cyan);font-weight:500;min-width:70px}
|
|
1529
|
+
.proc-sid{color:var(--text2);font-family:var(--font-mono);font-size:12px}
|
|
1530
|
+
.proc-cwd{color:var(--text3);font-size:12px}
|
|
1531
|
+
.empty{padding:14px 16px;color:var(--text3);font-size:13px}
|
|
1532
|
+
.main{display:grid;grid-template-columns:360px 1fr;gap:0;background:var(--bg2);border:1px solid var(--border);border-radius:var(--radius);overflow:hidden;min-height:calc(100vh - 260px)}
|
|
1533
|
+
.sidebar{border-right:1px solid var(--border);overflow-y:auto}
|
|
1534
|
+
.sidebar-header{padding:10px 16px;font-size:13px;font-weight:600;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:8px;position:sticky;top:0;background:var(--bg2);z-index:2}
|
|
1535
|
+
.count{background:var(--bg3);color:var(--text2);font-size:11px;padding:1px 7px;border-radius:10px;font-weight:500}
|
|
1536
|
+
.s-item{padding:10px 16px;border-bottom:1px solid var(--border);cursor:pointer;transition:background .15s}
|
|
1537
|
+
.s-item:last-child{border-bottom:none}
|
|
1538
|
+
.s-item:hover{background:var(--bg3)}
|
|
1539
|
+
.s-item.active{background:rgba(88,166,255,.06);border-left:3px solid var(--cyan);padding-left:13px}
|
|
1540
|
+
.s-row{display:flex;align-items:center;gap:10px}
|
|
1541
|
+
.s-icon{font-size:14px;flex-shrink:0}
|
|
1542
|
+
.s-info{flex:1;min-width:0}
|
|
1543
|
+
.s-title{font-size:13px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
1544
|
+
.s-meta{font-size:11px;color:var(--text2);display:flex;gap:10px;margin-top:2px;flex-wrap:wrap}
|
|
1545
|
+
.badge{font-size:10px;padding:1px 6px;border-radius:4px;font-weight:600;font-family:var(--font-mono);text-transform:uppercase}
|
|
1546
|
+
.badge-done{background:rgba(63,185,80,.12);color:var(--green)}
|
|
1547
|
+
.badge-stop{background:rgba(210,153,34,.12);color:var(--yellow)}
|
|
1548
|
+
.detail{padding:20px;overflow-y:auto}
|
|
1549
|
+
.detail-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:16px}
|
|
1550
|
+
.detail-title{font-size:18px;font-weight:700}
|
|
1551
|
+
.detail-id{font-family:var(--font-mono);font-size:11px;color:var(--text3);background:var(--bg);padding:3px 8px;border-radius:4px}
|
|
1552
|
+
.detail-time{font-size:12px;color:var(--text2);margin-bottom:16px}
|
|
1553
|
+
.detail-stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:8px;margin-bottom:20px}
|
|
1554
|
+
.d-stat{background:var(--bg);border-radius:6px;padding:10px}
|
|
1555
|
+
.d-stat-label{font-size:10px;color:var(--text2);text-transform:uppercase;letter-spacing:.3px}
|
|
1556
|
+
.d-stat-val{font-size:16px;font-weight:700;font-family:var(--font-mono);margin-top:1px}
|
|
1557
|
+
.sub{margin-top:20px}
|
|
1558
|
+
.sub-title{font-size:12px;font-weight:600;color:var(--text2);text-transform:uppercase;letter-spacing:.5px;margin-bottom:8px;display:flex;align-items:center;gap:6px}
|
|
1559
|
+
.tool-row{display:flex;align-items:center;gap:8px;padding:3px 0;font-size:12px}
|
|
1560
|
+
.tool-name{color:var(--text2);min-width:110px;text-align:right;font-family:var(--font-mono);font-size:11px}
|
|
1561
|
+
.tool-bar-bg{flex:1;background:var(--bg);border-radius:3px;height:14px;overflow:hidden}
|
|
1562
|
+
.tool-bar{height:100%;border-radius:3px;background:linear-gradient(90deg,var(--cyan),var(--purple));opacity:.7;transition:width .4s ease}
|
|
1563
|
+
.tool-count{font-family:var(--font-mono);color:var(--text2);min-width:40px;font-size:11px}
|
|
1564
|
+
.commit-list,.task-list,.file-list,.error-list{list-style:none}
|
|
1565
|
+
.commit-list li,.task-list li{padding:5px 0;font-size:13px;display:flex;align-items:flex-start;gap:6px;border-bottom:1px solid var(--border)}
|
|
1566
|
+
.commit-list li:last-child,.task-list li:last-child{border-bottom:none}
|
|
1567
|
+
.c-dot{color:var(--green);flex-shrink:0;margin-top:2px}
|
|
1568
|
+
.t-check{color:var(--green);flex-shrink:0;margin-top:2px}
|
|
1569
|
+
.file-list li{padding:2px 0;font-size:11px;font-family:var(--font-mono)}
|
|
1570
|
+
.file-created{color:var(--green)}
|
|
1571
|
+
.file-edited{color:var(--yellow)}
|
|
1572
|
+
.error-list li{padding:5px 0;font-size:12px;color:var(--red)}
|
|
1573
|
+
.more{font-size:11px;color:var(--text3);padding:4px 0}
|
|
1574
|
+
.empty-detail{display:flex;align-items:center;justify-content:center;height:100%;color:var(--text3)}
|
|
1575
|
+
.htmx-settling{opacity:0}
|
|
1576
|
+
.htmx-added{opacity:0;transition:opacity .3s ease}
|
|
1577
|
+
@media(max-width:768px){.main{grid-template-columns:1fr}.stats{grid-template-columns:repeat(2,1fr)}}
|
|
1578
|
+
`;
|
|
1579
|
+
var layoutHead = `<!DOCTYPE html>
|
|
1580
|
+
<html lang="en">
|
|
1581
|
+
<head>
|
|
1582
|
+
<meta charset="utf-8">
|
|
1583
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
1584
|
+
<title>Copilot Agent Dashboard</title>
|
|
1585
|
+
<script src="https://unpkg.com/htmx.org@2.0.4" integrity="sha384-HGfztofotfshcF7+8n44JQL2oJmowVChPTg48S+jvZoztPfvwD79OC/LTtG6dMp+" crossorigin="anonymous"></script>
|
|
1586
|
+
<script src="https://unpkg.com/htmx-ext-sse@2.2.2/sse.js"></script>
|
|
1587
|
+
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
|
|
1588
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
1589
|
+
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
|
|
1590
|
+
<style>
|
|
1591
|
+
${cssStyles}
|
|
1592
|
+
</style>
|
|
1593
|
+
</head>`;
|
|
1594
|
+
var layoutFoot = `</html>`;
|
|
1595
|
+
|
|
1596
|
+
// src/web/views.ts
|
|
1597
|
+
function esc(s) {
|
|
1598
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
1599
|
+
}
|
|
1600
|
+
function fmt(n) {
|
|
1601
|
+
return n.toLocaleString();
|
|
1602
|
+
}
|
|
1603
|
+
function fmtDur(ms) {
|
|
1604
|
+
if (!ms) return "\u2014";
|
|
1605
|
+
if (ms < 6e4) return `${Math.round(ms / 1e3)}s`;
|
|
1606
|
+
if (ms < 36e5) return `${Math.round(ms / 6e4)}m`;
|
|
1607
|
+
const h = Math.floor(ms / 36e5);
|
|
1608
|
+
const m = Math.round(ms % 36e5 / 6e4);
|
|
1609
|
+
return `${h}h ${m}m`;
|
|
1610
|
+
}
|
|
1611
|
+
function fmtTime(iso) {
|
|
1612
|
+
if (!iso) return "\u2014";
|
|
1613
|
+
return new Date(iso).toLocaleString("en-GB", { month: "short", day: "numeric", hour: "2-digit", minute: "2-digit" });
|
|
1614
|
+
}
|
|
1615
|
+
function fmtAgo(iso) {
|
|
1616
|
+
if (!iso) return "\u2014";
|
|
1617
|
+
const diff = Date.now() - new Date(iso).getTime();
|
|
1618
|
+
if (diff < 6e4) return "just now";
|
|
1619
|
+
if (diff < 36e5) return `${Math.round(diff / 6e4)}m ago`;
|
|
1620
|
+
if (diff < 864e5) return `${Math.round(diff / 36e5)}h ago`;
|
|
1621
|
+
return `${Math.round(diff / 864e5)}d ago`;
|
|
1622
|
+
}
|
|
1623
|
+
function shortPath(p, proj) {
|
|
1624
|
+
if (proj && p.includes(proj + "/")) return p.split(proj + "/").pop() ?? p;
|
|
1625
|
+
return p.split("/").slice(-3).join("/");
|
|
1626
|
+
}
|
|
1627
|
+
function renderStats(sessions) {
|
|
1628
|
+
const totalPremium = sessions.reduce((a, s) => a + (s.premiumRequests ?? 0), 0);
|
|
1629
|
+
const totalTokens = sessions.reduce((a, s) => a + (s.outputTokens ?? 0), 0);
|
|
1630
|
+
const totalCommits = sessions.reduce((a, s) => a + (s.gitCommits?.length ?? 0), 0);
|
|
1631
|
+
const totalTasks = sessions.reduce((a, s) => a + (s.taskCompletions?.length ?? 0), 0);
|
|
1632
|
+
const completed = sessions.filter((s) => s.complete).length;
|
|
1633
|
+
const items = [
|
|
1634
|
+
{ label: "Sessions", value: String(sessions.length), cls: "cyan" },
|
|
1635
|
+
{ label: "Completed", value: `${completed}/${sessions.length}`, cls: "green" },
|
|
1636
|
+
{ label: "Premium", value: fmt(totalPremium), cls: "yellow" },
|
|
1637
|
+
{ label: "Tokens", value: fmt(totalTokens), cls: "purple" },
|
|
1638
|
+
{ label: "Commits", value: String(totalCommits), cls: "green" },
|
|
1639
|
+
{ label: "Tasks Done", value: String(totalTasks), cls: "cyan" }
|
|
1640
|
+
];
|
|
1641
|
+
return items.map(
|
|
1642
|
+
(i) => `<div class="stat"><div class="stat-label">${i.label}</div><div class="stat-value ${i.cls}">${i.value}</div></div>`
|
|
1643
|
+
).join("");
|
|
1644
|
+
}
|
|
1645
|
+
function renderProcesses(procs) {
|
|
1646
|
+
if (procs.length === 0) return '<div class="empty">No active copilot processes</div>';
|
|
1647
|
+
return procs.map((p) => {
|
|
1648
|
+
const sid = p.sessionId ? p.sessionId.slice(0, 8) + "\u2026" : "\u2014";
|
|
1649
|
+
return `<div class="proc">
|
|
1650
|
+
<div class="proc-dot"></div>
|
|
1651
|
+
<span class="proc-pid">PID ${p.pid}</span>
|
|
1652
|
+
<span class="proc-sid">${esc(sid)}</span>
|
|
1653
|
+
<span class="proc-cwd">${esc(p.cwd ?? "")}</span>
|
|
1654
|
+
</div>`;
|
|
1655
|
+
}).join("");
|
|
1656
|
+
}
|
|
1657
|
+
function renderSessionList(sessions, selectedId) {
|
|
1658
|
+
return sessions.map((s) => {
|
|
1659
|
+
const proj = (s.cwd ?? "").split("/").pop() ?? "\u2014";
|
|
1660
|
+
const isActive = s.id === selectedId;
|
|
1661
|
+
return `<div class="s-item${isActive ? " active" : ""}"
|
|
1662
|
+
hx-get="/partial/detail/${s.id}" hx-target="#detail" hx-swap="innerHTML"
|
|
1663
|
+
onclick="document.querySelectorAll('.s-item').forEach(e=>e.classList.remove('active'));this.classList.add('active')">
|
|
1664
|
+
<div class="s-row">
|
|
1665
|
+
<span class="s-icon">${s.complete ? "\u2705" : "\u23F8\uFE0F"}</span>
|
|
1666
|
+
<div class="s-info">
|
|
1667
|
+
<div class="s-title">${esc(proj)} \u2014 ${esc(s.summary || "(no summary)")}</div>
|
|
1668
|
+
<div class="s-meta">
|
|
1669
|
+
<span>${fmtDur(s.durationMs)}</span>
|
|
1670
|
+
<span>${fmt(s.premiumRequests)} premium</span>
|
|
1671
|
+
<span>${fmtAgo(s.endTime)}</span>
|
|
1672
|
+
<span class="badge ${s.complete ? "badge-done" : "badge-stop"}">${s.complete ? "done" : "stopped"}</span>
|
|
1673
|
+
</div>
|
|
1674
|
+
</div>
|
|
1675
|
+
</div>
|
|
1676
|
+
</div>`;
|
|
1677
|
+
}).join("");
|
|
1678
|
+
}
|
|
1679
|
+
function renderDetail(s) {
|
|
1680
|
+
const proj = (s.cwd ?? "").split("/").pop() ?? "\u2014";
|
|
1681
|
+
const totalTools = Object.values(s.toolUsage ?? {}).reduce((a, b) => a + b, 0);
|
|
1682
|
+
const toolEntries = Object.entries(s.toolUsage ?? {}).sort((a, b) => b[1] - a[1]);
|
|
1683
|
+
const maxTool = toolEntries[0]?.[1] ?? 1;
|
|
1684
|
+
let html = "";
|
|
1685
|
+
html += `<div class="detail-head">
|
|
1686
|
+
<div class="detail-title">${esc(proj)}</div>
|
|
1687
|
+
<div class="detail-id">${s.id}</div>
|
|
1688
|
+
</div>`;
|
|
1689
|
+
html += `<div class="detail-time">${fmtTime(s.startTime)} \u2192 ${fmtTime(s.endTime)}</div>`;
|
|
1690
|
+
html += `<div class="detail-stats">
|
|
1691
|
+
<div class="d-stat"><div class="d-stat-label">Duration</div><div class="d-stat-val">${fmtDur(s.durationMs)}</div></div>
|
|
1692
|
+
<div class="d-stat"><div class="d-stat-label">User Msgs</div><div class="d-stat-val">${s.userMessages}</div></div>
|
|
1693
|
+
<div class="d-stat"><div class="d-stat-label">Turns</div><div class="d-stat-val">${fmt(s.assistantTurns)}</div></div>
|
|
1694
|
+
<div class="d-stat"><div class="d-stat-label">Tokens</div><div class="d-stat-val">${fmt(s.outputTokens)}</div></div>
|
|
1695
|
+
<div class="d-stat"><div class="d-stat-label">Premium</div><div class="d-stat-val">${fmt(s.premiumRequests)}</div></div>
|
|
1696
|
+
<div class="d-stat"><div class="d-stat-label">Tool Calls</div><div class="d-stat-val">${fmt(totalTools)}</div></div>
|
|
1697
|
+
</div>`;
|
|
1698
|
+
if (toolEntries.length > 0) {
|
|
1699
|
+
html += `<div class="sub"><div class="sub-title">\u{1F527} Tools Used</div>`;
|
|
1700
|
+
for (const [tool, count] of toolEntries.slice(0, 12)) {
|
|
1701
|
+
const pct = Math.round(count / maxTool * 100);
|
|
1702
|
+
html += `<div class="tool-row">
|
|
1703
|
+
<span class="tool-name">${esc(tool)}</span>
|
|
1704
|
+
<div class="tool-bar-bg"><div class="tool-bar" style="width:${pct}%"></div></div>
|
|
1705
|
+
<span class="tool-count">${count}</span>
|
|
1706
|
+
</div>`;
|
|
1707
|
+
}
|
|
1708
|
+
if (toolEntries.length > 12) html += `<div class="more">\u2026 +${toolEntries.length - 12} more</div>`;
|
|
1709
|
+
html += `</div>`;
|
|
1710
|
+
}
|
|
1711
|
+
if (s.gitCommits.length > 0) {
|
|
1712
|
+
html += `<div class="sub"><div class="sub-title">\u{1F500} Git Commits <span class="count">${s.gitCommits.length}</span></div><ul class="commit-list">`;
|
|
1713
|
+
for (const msg of s.gitCommits.slice(0, 12)) {
|
|
1714
|
+
const first = msg.split("\n")[0].slice(0, 80);
|
|
1715
|
+
html += `<li><span class="c-dot">\u25CF</span><span>${esc(first)}</span></li>`;
|
|
1716
|
+
}
|
|
1717
|
+
if (s.gitCommits.length > 12) html += `<li class="more">\u2026 +${s.gitCommits.length - 12} more</li>`;
|
|
1718
|
+
html += `</ul></div>`;
|
|
1719
|
+
}
|
|
1720
|
+
const files = [
|
|
1721
|
+
...s.filesCreated.map((f) => ({ path: f, type: "created" })),
|
|
1722
|
+
...s.filesEdited.map((f) => ({ path: f, type: "edited" }))
|
|
1723
|
+
];
|
|
1724
|
+
if (files.length > 0) {
|
|
1725
|
+
html += `<div class="sub"><div class="sub-title">\u{1F4C1} Files Changed <span class="count">${files.length}</span></div><ul class="file-list">`;
|
|
1726
|
+
for (const f of files.slice(0, 25)) {
|
|
1727
|
+
const cls = f.type === "created" ? "file-created" : "file-edited";
|
|
1728
|
+
const icon = f.type === "created" ? "+" : "~";
|
|
1729
|
+
html += `<li><span class="${cls}">${icon}</span> ${esc(shortPath(f.path, proj))}</li>`;
|
|
1730
|
+
}
|
|
1731
|
+
if (files.length > 25) html += `<li class="more">\u2026 +${files.length - 25} more</li>`;
|
|
1732
|
+
html += `</ul></div>`;
|
|
1733
|
+
}
|
|
1734
|
+
if (s.taskCompletions.length > 0) {
|
|
1735
|
+
html += `<div class="sub"><div class="sub-title">\u2705 Tasks Completed <span class="count">${s.taskCompletions.length}</span></div><ul class="task-list">`;
|
|
1736
|
+
for (const t of s.taskCompletions.slice(0, 10)) {
|
|
1737
|
+
const first = t.split("\n")[0].slice(0, 80);
|
|
1738
|
+
html += `<li><span class="t-check">\u2714</span><span>${esc(first)}</span></li>`;
|
|
1739
|
+
}
|
|
1740
|
+
if (s.taskCompletions.length > 10) html += `<li class="more">\u2026 +${s.taskCompletions.length - 10} more</li>`;
|
|
1741
|
+
html += `</ul></div>`;
|
|
1742
|
+
}
|
|
1743
|
+
if (s.errors.length > 0) {
|
|
1744
|
+
html += `<div class="sub"><div class="sub-title" style="color:var(--red)">\u26A0\uFE0F Errors <span class="count">${s.errors.length}</span></div><ul class="error-list">`;
|
|
1745
|
+
for (const e of s.errors.slice(0, 5)) {
|
|
1746
|
+
html += `<li>${esc(e.slice(0, 100))}</li>`;
|
|
1747
|
+
}
|
|
1748
|
+
if (s.errors.length > 5) html += `<li class="more">\u2026 +${s.errors.length - 5} more</li>`;
|
|
1749
|
+
html += `</ul></div>`;
|
|
1750
|
+
}
|
|
1751
|
+
return html;
|
|
1752
|
+
}
|
|
1753
|
+
|
|
1754
|
+
// src/commands/web.ts
|
|
1755
|
+
function registerWebCommand(program2) {
|
|
1756
|
+
program2.command("web").description("Launch web dashboard in browser").option("-p, --port <n>", "Port number", "3847").option("--no-open", "Do not auto-open browser").action((opts) => {
|
|
1757
|
+
startWebServer(parseInt(opts.port, 10), opts.open !== false);
|
|
1758
|
+
});
|
|
1759
|
+
}
|
|
1760
|
+
function getData() {
|
|
1761
|
+
const sessions = listSessions(20);
|
|
1762
|
+
const reports = sessions.map((s) => getSessionReport(s.id)).filter((r) => r !== null);
|
|
1763
|
+
const processes = findCopilotProcesses();
|
|
1764
|
+
return { sessions: reports, processes };
|
|
1765
|
+
}
|
|
1766
|
+
function startWebServer(port, autoOpen) {
|
|
1767
|
+
const app = new Hono();
|
|
1768
|
+
app.get("/api/sessions", (c) => c.json(getData()));
|
|
1769
|
+
app.get("/api/session/:id", (c) => {
|
|
1770
|
+
const report = getSessionReport(c.req.param("id"));
|
|
1771
|
+
if (!report) return c.json({ error: "Not found" }, 404);
|
|
1772
|
+
return c.json(report);
|
|
1773
|
+
});
|
|
1774
|
+
app.get("/events", (c) => {
|
|
1775
|
+
return streamSSE(c, async (stream) => {
|
|
1776
|
+
while (true) {
|
|
1777
|
+
const { sessions, processes } = getData();
|
|
1778
|
+
await stream.writeSSE({
|
|
1779
|
+
event: "stats",
|
|
1780
|
+
data: renderStats(sessions)
|
|
1781
|
+
});
|
|
1782
|
+
await stream.writeSSE({
|
|
1783
|
+
event: "procs",
|
|
1784
|
+
data: renderProcesses(processes)
|
|
1785
|
+
});
|
|
1786
|
+
await stream.writeSSE({
|
|
1787
|
+
event: "proc-count",
|
|
1788
|
+
data: String(processes.length)
|
|
1789
|
+
});
|
|
1790
|
+
await stream.sleep(5e3);
|
|
1791
|
+
}
|
|
1792
|
+
});
|
|
1793
|
+
});
|
|
1794
|
+
app.get("/partial/detail/:id", (c) => {
|
|
1795
|
+
const report = getSessionReport(c.req.param("id"));
|
|
1796
|
+
if (!report) return c.html('<div class="empty-detail">Session not found</div>');
|
|
1797
|
+
return c.html(renderDetail(report));
|
|
1798
|
+
});
|
|
1799
|
+
app.get("/", (c) => {
|
|
1800
|
+
const { sessions, processes } = getData();
|
|
1801
|
+
const firstId = sessions[0]?.id;
|
|
1802
|
+
return c.html(`${layoutHead}
|
|
1803
|
+
<body>
|
|
1804
|
+
<div class="header">
|
|
1805
|
+
<div class="header-left">
|
|
1806
|
+
<h1>\u{1F916} <span>Copilot Agent</span></h1>
|
|
1807
|
+
<div class="live-badge"><div class="live-dot"></div> Live</div>
|
|
1808
|
+
</div>
|
|
1809
|
+
<div class="clock" id="clock"></div>
|
|
1810
|
+
</div>
|
|
1811
|
+
|
|
1812
|
+
<div class="container"
|
|
1813
|
+
hx-ext="sse"
|
|
1814
|
+
sse-connect="/events">
|
|
1815
|
+
|
|
1816
|
+
<div class="stats"
|
|
1817
|
+
sse-swap="stats"
|
|
1818
|
+
hx-swap="innerHTML">
|
|
1819
|
+
${renderStats(sessions)}
|
|
1820
|
+
</div>
|
|
1821
|
+
|
|
1822
|
+
<div class="procs">
|
|
1823
|
+
<div class="procs-header">
|
|
1824
|
+
\u2B24 Active Processes <span class="count" sse-swap="proc-count" hx-swap="innerHTML">${processes.length}</span>
|
|
1825
|
+
</div>
|
|
1826
|
+
<div class="procs-body"
|
|
1827
|
+
sse-swap="procs"
|
|
1828
|
+
hx-swap="innerHTML">
|
|
1829
|
+
${renderProcesses(processes)}
|
|
1830
|
+
</div>
|
|
1831
|
+
</div>
|
|
1832
|
+
|
|
1833
|
+
<div class="main">
|
|
1834
|
+
<div class="sidebar">
|
|
1835
|
+
<div class="sidebar-header">
|
|
1836
|
+
\u{1F4CB} Sessions <span class="count">${sessions.length}</span>
|
|
1837
|
+
</div>
|
|
1838
|
+
${renderSessionList(sessions, firstId)}
|
|
1839
|
+
</div>
|
|
1840
|
+
<div class="detail" id="detail">
|
|
1841
|
+
${firstId ? renderDetail(sessions[0]) : '<div class="empty-detail">No sessions</div>'}
|
|
1842
|
+
</div>
|
|
1843
|
+
</div>
|
|
1844
|
+
</div>
|
|
1845
|
+
|
|
1846
|
+
<script>
|
|
1847
|
+
setInterval(() => {
|
|
1848
|
+
document.getElementById('clock').textContent = new Date().toLocaleTimeString('en-GB');
|
|
1849
|
+
}, 1000);
|
|
1850
|
+
document.getElementById('clock').textContent = new Date().toLocaleTimeString('en-GB');
|
|
1851
|
+
</script>
|
|
1852
|
+
</body>
|
|
1853
|
+
${layoutFoot}`);
|
|
1854
|
+
});
|
|
1855
|
+
try {
|
|
1856
|
+
serve({ fetch: app.fetch, port }, () => {
|
|
1857
|
+
const url = `http://localhost:${port}`;
|
|
1858
|
+
ok(`Web dashboard \u2192 ${url}`);
|
|
1859
|
+
info("Press Ctrl+C to stop");
|
|
1860
|
+
if (autoOpen) {
|
|
1861
|
+
spawn2("open", [url], { detached: true, stdio: "ignore" }).unref();
|
|
1862
|
+
}
|
|
1863
|
+
});
|
|
1864
|
+
} catch (err) {
|
|
1865
|
+
fail(`Server error: ${err instanceof Error ? err.message : err}`);
|
|
1866
|
+
process.exit(1);
|
|
1867
|
+
}
|
|
1868
|
+
}
|
|
1869
|
+
|
|
1334
1870
|
// src/index.ts
|
|
1335
1871
|
var program = new Command();
|
|
1336
|
-
program.name("copilot-agent").version("0.
|
|
1872
|
+
program.name("copilot-agent").version("0.7.0").description("Autonomous GitHub Copilot CLI agent \u2014 auto-resume, task discovery, overnight runs");
|
|
1337
1873
|
registerStatusCommand(program);
|
|
1338
1874
|
registerWatchCommand(program);
|
|
1339
1875
|
registerRunCommand(program);
|
|
1340
1876
|
registerOvernightCommand(program);
|
|
1341
1877
|
registerResearchCommand(program);
|
|
1342
1878
|
registerReportCommand(program);
|
|
1879
|
+
registerDashboardCommand(program);
|
|
1880
|
+
registerWebCommand(program);
|
|
1343
1881
|
program.parse();
|
|
1344
1882
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/lib/session.ts","../src/lib/process.ts","../src/lib/logger.ts","../src/lib/colors.ts","../src/commands/status.ts","../src/commands/watch.ts","../src/lib/detect.ts","../src/lib/tasks.ts","../src/lib/lock.ts","../src/lib/git.ts","../src/commands/run.ts","../src/commands/overnight.ts","../src/commands/research.ts","../src/commands/report.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { registerStatusCommand } from './commands/status.js';\nimport { registerWatchCommand } from './commands/watch.js';\nimport { registerRunCommand } from './commands/run.js';\nimport { registerOvernightCommand } from './commands/overnight.js';\nimport { registerResearchCommand } from './commands/research.js';\nimport { registerReportCommand } from './commands/report.js';\n\nconst program = new Command();\n\nprogram\n .name('copilot-agent')\n .version('0.6.0')\n .description('Autonomous GitHub Copilot CLI agent — auto-resume, task discovery, overnight runs');\n\nregisterStatusCommand(program);\nregisterWatchCommand(program);\nregisterRunCommand(program);\nregisterOvernightCommand(program);\nregisterResearchCommand(program);\nregisterReportCommand(program);\n\nprogram.parse();\n","import {\n existsSync,\n readdirSync,\n readFileSync,\n statSync,\n} from 'node:fs';\nimport { join, resolve } from 'node:path';\nimport { homedir } from 'node:os';\n\nexport interface Session {\n id: string;\n dir: string;\n mtime: number;\n lastEvent: string;\n premiumRequests: number;\n summary: string;\n cwd: string;\n complete: boolean;\n}\n\nexport interface SessionReport {\n id: string;\n cwd: string;\n summary: string;\n startTime: string;\n endTime: string;\n durationMs: number;\n complete: boolean;\n userMessages: number;\n assistantTurns: number;\n outputTokens: number;\n premiumRequests: number;\n toolUsage: Record<string, number>;\n gitCommits: string[];\n filesCreated: string[];\n filesEdited: string[];\n errors: string[];\n taskCompletions: string[];\n}\n\nconst SESSION_DIR = join(homedir(), '.copilot', 'session-state');\n\nexport function getSessionDir(): string {\n return SESSION_DIR;\n}\n\nexport function validateSession(sid: string): boolean {\n const events = join(SESSION_DIR, sid, 'events.jsonl');\n try {\n return existsSync(events) && statSync(events).size > 0;\n } catch {\n return false;\n }\n}\n\nexport function listSessions(limit = 20): Session[] {\n if (!existsSync(SESSION_DIR)) return [];\n\n const entries = readdirSync(SESSION_DIR, { withFileTypes: true })\n .filter(d => d.isDirectory());\n\n const dirs: { id: string; dir: string; mtime: number }[] = [];\n for (const entry of entries) {\n const dirPath = join(SESSION_DIR, entry.name);\n if (!existsSync(join(dirPath, 'events.jsonl'))) continue;\n try {\n const stat = statSync(dirPath);\n dirs.push({ id: entry.name, dir: dirPath, mtime: stat.mtimeMs });\n } catch { /* skip */ }\n }\n\n dirs.sort((a, b) => b.mtime - a.mtime);\n\n return dirs.slice(0, limit).map(s => ({\n id: s.id,\n dir: s.dir,\n mtime: s.mtime,\n lastEvent: getLastEvent(s.id),\n premiumRequests: getSessionPremium(s.id),\n summary: getSessionSummary(s.id),\n cwd: getSessionCwd(s.id),\n complete: hasTaskComplete(s.id),\n }));\n}\n\nexport function getLatestSessionId(): string | null {\n if (!existsSync(SESSION_DIR)) return null;\n\n const entries = readdirSync(SESSION_DIR, { withFileTypes: true })\n .filter(d => d.isDirectory());\n\n let latest: { id: string; mtime: number } | null = null;\n for (const entry of entries) {\n try {\n const stat = statSync(join(SESSION_DIR, entry.name));\n if (!latest || stat.mtimeMs > latest.mtime) {\n latest = { id: entry.name, mtime: stat.mtimeMs };\n }\n } catch { /* skip */ }\n }\n return latest?.id ?? null;\n}\n\nexport function hasTaskComplete(sid: string): boolean {\n if (!validateSession(sid)) return false;\n try {\n const content = readFileSync(join(SESSION_DIR, sid, 'events.jsonl'), 'utf-8');\n return content.includes('\"session.task_complete\"');\n } catch {\n return false;\n }\n}\n\nexport function getLastEvent(sid: string): string {\n if (!validateSession(sid)) return 'invalid';\n try {\n const lines = readFileSync(join(SESSION_DIR, sid, 'events.jsonl'), 'utf-8')\n .trimEnd()\n .split('\\n');\n const last = JSON.parse(lines[lines.length - 1]);\n return last.type ?? 'unknown';\n } catch {\n return 'corrupted';\n }\n}\n\nexport function getSessionPremium(sid: string): number {\n if (!validateSession(sid)) return 0;\n try {\n const content = readFileSync(join(SESSION_DIR, sid, 'events.jsonl'), 'utf-8');\n const lines = content.trimEnd().split('\\n');\n for (let i = lines.length - 1; i >= 0; i--) {\n try {\n const event = JSON.parse(lines[i]);\n if (event.type === 'session.shutdown' && event.data?.totalPremiumRequests != null) {\n return event.data.totalPremiumRequests;\n }\n } catch { /* skip malformed line */ }\n }\n return 0;\n } catch {\n return 0;\n }\n}\n\nfunction parseSimpleYaml(content: string): Record<string, string> {\n const result: Record<string, string> = {};\n for (const line of content.split('\\n')) {\n const idx = line.indexOf(': ');\n if (idx === -1) continue;\n const key = line.substring(0, idx).trim();\n const value = line.substring(idx + 2).trim();\n if (key) result[key] = value;\n }\n return result;\n}\n\nfunction readWorkspace(sid: string): Record<string, string> {\n const wsPath = join(SESSION_DIR, sid, 'workspace.yaml');\n if (!existsSync(wsPath)) return {};\n try {\n return parseSimpleYaml(readFileSync(wsPath, 'utf-8'));\n } catch {\n return {};\n }\n}\n\nexport function getSessionSummary(sid: string): string {\n return readWorkspace(sid).summary ?? '';\n}\n\nexport function getSessionCwd(sid: string): string {\n return readWorkspace(sid).cwd ?? '';\n}\n\nexport function findSessionForProject(projectPath: string): string | null {\n const resolved = resolve(projectPath);\n const sessions = listSessions(50);\n for (const s of sessions) {\n if (s.cwd && resolve(s.cwd) === resolved) return s.id;\n }\n return null;\n}\n\nexport function findLatestIncomplete(): string | null {\n const sessions = listSessions(50);\n for (const s of sessions) {\n if (!s.complete) return s.id;\n }\n return null;\n}\n\nexport function getSessionReport(sid: string): SessionReport | null {\n if (!validateSession(sid)) return null;\n\n const ws = readWorkspace(sid);\n let lines: string[];\n try {\n lines = readFileSync(join(SESSION_DIR, sid, 'events.jsonl'), 'utf-8')\n .trimEnd()\n .split('\\n');\n } catch {\n return null;\n }\n\n const report: SessionReport = {\n id: sid,\n cwd: ws.cwd ?? '',\n summary: ws.summary ?? '',\n startTime: '',\n endTime: '',\n durationMs: 0,\n complete: false,\n userMessages: 0,\n assistantTurns: 0,\n outputTokens: 0,\n premiumRequests: 0,\n toolUsage: {},\n gitCommits: [],\n filesCreated: [],\n filesEdited: [],\n errors: [],\n taskCompletions: [],\n };\n\n for (const line of lines) {\n let event: Record<string, unknown>;\n try {\n event = JSON.parse(line);\n } catch {\n continue;\n }\n\n const type = event.type as string;\n const ts = event.timestamp as string | undefined;\n const data = (event.data ?? {}) as Record<string, unknown>;\n\n if (ts && !report.startTime) report.startTime = ts;\n if (ts) report.endTime = ts;\n\n switch (type) {\n case 'user.message':\n report.userMessages++;\n break;\n\n case 'assistant.message':\n report.assistantTurns++;\n report.outputTokens += (data.outputTokens as number) ?? 0;\n break;\n\n case 'tool.execution_start': {\n const toolName = data.toolName as string;\n if (toolName) {\n report.toolUsage[toolName] = (report.toolUsage[toolName] ?? 0) + 1;\n }\n // Track git commits\n if (toolName === 'bash') {\n const args = data.arguments as Record<string, string> | undefined;\n const cmd = args?.command ?? '';\n if (cmd.includes('git') && cmd.includes('commit') && cmd.includes('-m')) {\n const msgMatch = cmd.match(/-m\\s+\"([^\"]{1,120})/);\n if (msgMatch) report.gitCommits.push(msgMatch[1]);\n }\n }\n // Track file creates/edits\n if (toolName === 'create') {\n const args = data.arguments as Record<string, string> | undefined;\n if (args?.path) report.filesCreated.push(args.path);\n }\n if (toolName === 'edit') {\n const args = data.arguments as Record<string, string> | undefined;\n if (args?.path && !report.filesEdited.includes(args.path)) {\n report.filesEdited.push(args.path);\n }\n }\n break;\n }\n\n case 'session.task_complete': {\n const summary = data.summary as string | undefined;\n report.taskCompletions.push(summary ?? '(task completed)');\n report.complete = true;\n break;\n }\n\n case 'session.error': {\n const msg = data.message as string | undefined;\n if (msg) report.errors.push(msg);\n break;\n }\n\n case 'session.shutdown': {\n const premium = data.totalPremiumRequests as number | undefined;\n if (premium != null) report.premiumRequests = premium;\n break;\n }\n }\n }\n\n if (report.startTime && report.endTime) {\n report.durationMs = new Date(report.endTime).getTime() - new Date(report.startTime).getTime();\n }\n\n return report;\n}\n","import { execSync, spawn } from 'node:child_process';\nimport { resolve } from 'node:path';\nimport { getLatestSessionId, getSessionPremium, getSessionCwd } from './session.js';\nimport { log, warn, fail } from './logger.js';\n\nexport interface CopilotProcess {\n pid: number;\n command: string;\n sessionId?: string;\n cwd?: string;\n}\n\nexport interface CopilotResult {\n exitCode: number;\n sessionId: string | null;\n premium: number;\n}\n\nexport function isCopilotInstalled(): boolean {\n try {\n execSync('which copilot', { stdio: 'pipe', encoding: 'utf-8' });\n return true;\n } catch {\n return false;\n }\n}\n\nexport function assertCopilot(): void {\n if (!isCopilotInstalled()) {\n fail('copilot CLI not found. Install with: npm i -g @githubnext/copilot');\n process.exit(1);\n }\n}\n\nexport function findCopilotProcesses(): CopilotProcess[] {\n try {\n const output = execSync('ps -eo pid,command', { encoding: 'utf-8' });\n const results: CopilotProcess[] = [];\n const myPid = process.pid;\n const parentPid = process.ppid;\n for (const line of output.split('\\n')) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n if (\n (trimmed.includes('copilot') || trimmed.includes('@githubnext/copilot')) &&\n !trimmed.includes('ps -eo') &&\n !trimmed.includes('copilot-agent') &&\n !trimmed.includes('grep')\n ) {\n const match = trimmed.match(/^(\\d+)\\s+(.+)$/);\n if (match) {\n const pid = parseInt(match[1], 10);\n // Exclude our own process tree\n if (pid === myPid || pid === parentPid) continue;\n const cmd = match[2];\n const sidMatch = cmd.match(/resume[= ]+([a-f0-9-]{36})/);\n // Try to get cwd of the process\n let cwd: string | undefined;\n try {\n cwd = execSync(`lsof -p ${pid} -Fn 2>/dev/null | grep '^n/' | head -1`, {\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n }).trim().slice(1) || undefined;\n } catch { /* best effort */ }\n // Fallback: get cwd from session if we know the session\n const sid = sidMatch?.[1];\n if (!cwd && sid) {\n cwd = getSessionCwd(sid) || undefined;\n }\n results.push({ pid, command: cmd, sessionId: sid, cwd });\n }\n }\n }\n return results;\n } catch {\n return [];\n }\n}\n\nexport function findPidForSession(sid: string): number | null {\n const procs = findCopilotProcesses();\n const matching = procs\n .filter(p => p.command.includes(sid))\n .sort((a, b) => b.pid - a.pid);\n return matching[0]?.pid ?? null;\n}\n\n/**\n * SAFETY: Wait until no copilot is running in the SAME directory.\n * Copilot in different directories/worktrees can run in parallel.\n */\nexport async function waitForCopilotInDir(\n dir: string,\n timeoutMs = 14_400_000,\n pollMs = 10_000,\n): Promise<void> {\n const targetDir = resolve(dir);\n const start = Date.now();\n let warned = false;\n while (Date.now() - start < timeoutMs) {\n const procs = findCopilotProcesses();\n const conflicting = procs.filter(p => {\n if (!p.cwd) return false;\n return resolve(p.cwd) === targetDir;\n });\n if (conflicting.length === 0) return;\n if (!warned) {\n warn(`Waiting for copilot in ${targetDir} to finish...`);\n for (const p of conflicting) {\n log(` PID ${p.pid}: ${p.command.slice(0, 80)}`);\n }\n warned = true;\n }\n await sleep(pollMs);\n }\n warn('Timeout waiting for copilot to finish in directory');\n}\n\n/**\n * SAFETY: Check if a session already has a running copilot process.\n * If so, refuse to spawn another one to prevent corruption.\n */\nexport function assertSessionNotRunning(sid: string): void {\n const pid = findPidForSession(sid);\n if (pid) {\n fail(`Session ${sid.slice(0, 8)}… already has copilot running (PID ${pid}). Cannot resume — would corrupt the session.`);\n process.exit(1);\n }\n}\n\nexport async function waitForExit(pid: number, timeoutMs = 14_400_000): Promise<boolean> {\n const start = Date.now();\n while (Date.now() - start < timeoutMs) {\n try {\n process.kill(pid, 0);\n await sleep(5000);\n } catch {\n return true; // process exited\n }\n }\n return false; // timeout\n}\n\nexport async function runCopilot(\n args: string[],\n options?: { cwd?: string; useWorktree?: boolean },\n): Promise<CopilotResult> {\n const dir = options?.cwd ?? process.cwd();\n\n if (options?.useWorktree) {\n // Worktree mode: create separate worktree, no waiting needed\n // (caller is responsible for creating worktree and passing its path)\n } else {\n // Default: wait for copilot in same directory to finish\n await waitForCopilotInDir(dir);\n }\n\n return new Promise((resolve) => {\n const child = spawn('copilot', args, {\n cwd: options?.cwd,\n stdio: 'inherit',\n env: { ...process.env },\n });\n\n child.on('close', async (code) => {\n await sleep(3000); // let events flush\n const sid = getLatestSessionId();\n const premium = sid ? getSessionPremium(sid) : 0;\n resolve({\n exitCode: code ?? 1,\n sessionId: sid,\n premium,\n });\n });\n\n child.on('error', () => {\n resolve({ exitCode: 1, sessionId: null, premium: 0 });\n });\n });\n}\n\nexport function runCopilotResume(\n sid: string,\n steps: number,\n message?: string,\n cwd?: string,\n): Promise<CopilotResult> {\n // SAFETY: Refuse if session already running\n assertSessionNotRunning(sid);\n\n const args = [\n `--resume=${sid}`,\n '--autopilot',\n '--allow-all',\n '--max-autopilot-continues',\n String(steps),\n '--no-ask-user',\n ];\n if (message) args.push('-p', message);\n return runCopilot(args, { cwd });\n}\n\nexport function runCopilotTask(\n prompt: string,\n steps: number,\n cwd?: string,\n useWorktree?: boolean,\n): Promise<CopilotResult> {\n return runCopilot([\n '-p', prompt,\n '--autopilot',\n '--allow-all',\n '--max-autopilot-continues', String(steps),\n '--no-ask-user',\n ], { cwd, useWorktree });\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise(r => setTimeout(r, ms));\n}\n","import { appendFileSync, mkdirSync } from 'node:fs';\nimport { dirname } from 'node:path';\nimport { execSync } from 'node:child_process';\nimport { RED, GREEN, YELLOW, CYAN, DIM, RESET } from './colors.js';\n\nlet logFilePath: string | null = null;\n\nconst ANSI_RE =\n /[\\u001b\\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g;\n\nfunction stripAnsi(s: string): string {\n return s.replace(ANSI_RE, '');\n}\n\nfunction writeToFile(msg: string): void {\n if (!logFilePath) return;\n try {\n appendFileSync(logFilePath, stripAnsi(msg) + '\\n');\n } catch { /* ignore file write errors */ }\n}\n\nexport function setLogFile(path: string): void {\n mkdirSync(dirname(path), { recursive: true });\n logFilePath = path;\n}\n\nexport function log(msg: string): void {\n console.log(msg);\n writeToFile(msg);\n}\n\nexport function warn(msg: string): void {\n const out = `${YELLOW}⚠ ${msg}${RESET}`;\n console.log(out);\n writeToFile(`⚠ ${msg}`);\n}\n\nexport function ok(msg: string): void {\n const out = `${GREEN}✔ ${msg}${RESET}`;\n console.log(out);\n writeToFile(`✔ ${msg}`);\n}\n\nexport function fail(msg: string): void {\n const out = `${RED}✖ ${msg}${RESET}`;\n console.error(out);\n writeToFile(`✖ ${msg}`);\n}\n\nexport function info(msg: string): void {\n const out = `${CYAN}ℹ ${msg}${RESET}`;\n console.log(out);\n writeToFile(`ℹ ${msg}`);\n}\n\nexport function dim(msg: string): void {\n const out = `${DIM}${msg}${RESET}`;\n console.log(out);\n writeToFile(msg);\n}\n\nexport function notify(message: string, title = 'copilot-agent'): void {\n try {\n if (process.platform === 'darwin') {\n execSync(\n `osascript -e 'display notification \"${message.replace(/\"/g, '\\\\\"')}\" with title \"${title.replace(/\"/g, '\\\\\"')}\"'`,\n { stdio: 'ignore' },\n );\n } else {\n try {\n execSync('which notify-send', { stdio: 'pipe' });\n execSync(\n `notify-send \"${title}\" \"${message.replace(/\"/g, '\\\\\"')}\"`,\n { stdio: 'ignore' },\n );\n } catch { /* notify-send not available */ }\n }\n } catch { /* notification not available */ }\n}\n","export const RED = '\\x1b[31m';\nexport const GREEN = '\\x1b[32m';\nexport const YELLOW = '\\x1b[33m';\nexport const BLUE = '\\x1b[34m';\nexport const CYAN = '\\x1b[36m';\nexport const DIM = '\\x1b[2m';\nexport const BOLD = '\\x1b[1m';\nexport const RESET = '\\x1b[0m';\n","import type { Command } from 'commander';\nimport {\n listSessions,\n hasTaskComplete,\n getLastEvent,\n getSessionPremium,\n} from '../lib/session.js';\nimport { findCopilotProcesses } from '../lib/process.js';\nimport { log } from '../lib/logger.js';\nimport { BOLD, CYAN, DIM, GREEN, YELLOW, RESET } from '../lib/colors.js';\n\nexport function registerStatusCommand(program: Command): void {\n program\n .command('status')\n .description('Show copilot session status')\n .option('-l, --limit <n>', 'Number of sessions to show', '10')\n .option('-a, --active', 'Show only active (running) processes')\n .option('-i, --incomplete', 'Only show incomplete sessions')\n .action((opts) => {\n if (opts.active) {\n showActive();\n } else {\n showRecent(parseInt(opts.limit, 10), opts.incomplete ?? false);\n }\n });\n}\n\nfunction showActive(): void {\n const procs = findCopilotProcesses();\n if (procs.length === 0) {\n log(`${DIM}No active copilot processes.${RESET}`);\n return;\n }\n\n log(`\\n${BOLD}${'PID'.padEnd(8)} ${'Session'.padEnd(40)} Command${RESET}`);\n log('─'.repeat(108));\n\n for (const p of procs) {\n log(\n `${CYAN}${String(p.pid).padEnd(8)}${RESET} ${(p.sessionId ?? '—').padEnd(40)} ${truncate(p.command, 58)}`,\n );\n }\n log('');\n}\n\nfunction showRecent(limit: number, incompleteOnly: boolean): void {\n let sessions = listSessions(limit);\n if (incompleteOnly) {\n sessions = sessions.filter(s => !s.complete);\n }\n\n if (sessions.length === 0) {\n log(`${DIM}No sessions found.${RESET}`);\n return;\n }\n\n log(\n `\\n${BOLD}${'Status'.padEnd(10)} ${'Premium'.padEnd(10)} ${'Last Event'.padEnd(25)} ${'Summary'.padEnd(40)} ID${RESET}`,\n );\n log('─'.repeat(120));\n\n for (const s of sessions) {\n const status = s.complete\n ? `${GREEN}✔ done${RESET}`\n : `${YELLOW}⏸ stop${RESET}`;\n const premium = String(s.premiumRequests);\n const summary = truncate(s.summary || '—', 38);\n\n log(\n `${status.padEnd(10 + 9)} ${premium.padEnd(10)} ${s.lastEvent.padEnd(25)} ${summary.padEnd(40)} ${DIM}${s.id}${RESET}`,\n );\n }\n log(`\\n${DIM}Total: ${sessions.length} session(s)${RESET}`);\n}\n\nfunction truncate(s: string, max: number): string {\n if (s.length <= max) return s;\n return s.substring(0, max - 1) + '…';\n}\n","import type { Command } from 'commander';\nimport {\n validateSession,\n hasTaskComplete,\n getSessionSummary,\n getLastEvent,\n findLatestIncomplete,\n getSessionCwd,\n} from '../lib/session.js';\nimport {\n findPidForSession,\n waitForExit,\n runCopilotResume,\n assertCopilot,\n} from '../lib/process.js';\nimport { log, ok, warn, fail, info, notify } from '../lib/logger.js';\nimport { CYAN, RESET } from '../lib/colors.js';\n\nexport function registerWatchCommand(program: Command): void {\n program\n .command('watch [session-id]')\n .description('Watch a session and auto-resume when it stops')\n .option('-s, --steps <n>', 'Max autopilot continues per resume', '30')\n .option('-r, --max-resumes <n>', 'Max number of resumes', '10')\n .option('-c, --cooldown <n>', 'Seconds between resumes', '10')\n .option('-m, --message <msg>', 'Message to send on resume')\n .action(async (sid: string | undefined, opts) => {\n try {\n await watchCommand(sid, {\n steps: parseInt(opts.steps, 10),\n maxResumes: parseInt(opts.maxResumes, 10),\n cooldown: parseInt(opts.cooldown, 10),\n message: opts.message,\n });\n } catch (err) {\n fail(`Watch error: ${err instanceof Error ? err.message : err}`);\n process.exit(1);\n }\n });\n}\n\ninterface WatchOptions {\n steps: number;\n maxResumes: number;\n cooldown: number;\n message?: string;\n}\n\nasync function watchCommand(sid: string | undefined, opts: WatchOptions): Promise<void> {\n assertCopilot();\n\n if (!sid) {\n sid = findLatestIncomplete() ?? undefined;\n if (!sid) {\n fail('No incomplete session found.');\n process.exit(1);\n }\n info(`Auto-detected incomplete session: ${CYAN}${sid}${RESET}`);\n }\n\n if (!validateSession(sid)) {\n fail(`Invalid session: ${sid}`);\n process.exit(1);\n }\n\n if (hasTaskComplete(sid)) {\n ok(`Session ${sid} already completed.`);\n return;\n }\n\n let resumes = 0;\n\n while (resumes < opts.maxResumes) {\n const pid = findPidForSession(sid);\n\n if (pid) {\n info(`Watching PID ${pid} for session ${CYAN}${sid.slice(0, 8)}${RESET}…`);\n const exited = await waitForExit(pid);\n\n if (!exited) {\n warn('Timeout waiting for process exit.');\n break;\n }\n }\n\n // Small delay for events to flush\n await sleep(3000);\n\n if (hasTaskComplete(sid)) {\n ok(`Task complete! Summary: ${getSessionSummary(sid) || 'none'}`);\n notify('Task completed!', `Session ${sid.slice(0, 8)}`);\n return;\n }\n\n // Interrupted — resume\n resumes++;\n log(`Session interrupted (${getLastEvent(sid)}). Resume ${resumes}/${opts.maxResumes}…`);\n\n if (opts.cooldown > 0 && resumes > 1) {\n info(`Cooldown ${opts.cooldown}s...`);\n await sleep(opts.cooldown * 1000);\n }\n\n const cwd = getSessionCwd(sid) || undefined;\n const result = await runCopilotResume(\n sid,\n opts.steps,\n opts.message ?? 'Continue remaining work. Pick up where you left off and complete the task.',\n cwd,\n );\n\n if (result.sessionId && result.sessionId !== sid) {\n info(`New session created: ${CYAN}${result.sessionId}${RESET}`);\n sid = result.sessionId;\n }\n }\n\n warn(`Max resumes (${opts.maxResumes}) reached.`);\n notify('Max resumes reached', `Session ${sid.slice(0, 8)}`);\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise(r => setTimeout(r, ms));\n}\n","import { existsSync, readFileSync, readdirSync } from 'node:fs';\nimport { join, basename, resolve } from 'node:path';\nimport { execSync } from 'node:child_process';\n\nexport type ProjectType =\n | 'kmp' | 'kotlin' | 'java'\n | 'node' | 'typescript' | 'react' | 'next'\n | 'python' | 'rust' | 'swift' | 'go' | 'flutter'\n | 'unknown';\n\nexport function detectProjectType(dir: string): ProjectType {\n const exists = (f: string) => existsSync(join(dir, f));\n\n if (exists('build.gradle.kts') || exists('build.gradle')) {\n if (exists('composeApp') || exists('gradle.properties')) {\n try {\n const gradle = readFileSync(join(dir, 'build.gradle.kts'), 'utf-8');\n if (gradle.includes('multiplatform') || gradle.includes('KotlinMultiplatform')) return 'kmp';\n } catch { /* ignore */ }\n }\n if (exists('pom.xml')) return 'java';\n return 'kotlin';\n }\n if (exists('pubspec.yaml')) return 'flutter';\n if (exists('Package.swift')) return 'swift';\n try {\n const entries = readdirSync(dir);\n if (entries.some(e => e.endsWith('.xcodeproj'))) return 'swift';\n } catch { /* ignore */ }\n if (exists('Cargo.toml')) return 'rust';\n if (exists('go.mod')) return 'go';\n if (exists('pyproject.toml') || exists('setup.py') || exists('requirements.txt')) return 'python';\n if (exists('package.json')) {\n try {\n const pkg = JSON.parse(readFileSync(join(dir, 'package.json'), 'utf-8'));\n const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };\n if (allDeps['next']) return 'next';\n if (allDeps['react']) return 'react';\n if (allDeps['typescript'] || exists('tsconfig.json')) return 'typescript';\n } catch { /* ignore */ }\n return 'node';\n }\n if (exists('pom.xml')) return 'java';\n return 'unknown';\n}\n\nexport function detectProjectName(dir: string): string {\n try {\n const pkg = JSON.parse(readFileSync(join(dir, 'package.json'), 'utf-8'));\n if (pkg.name) return pkg.name;\n } catch { /* ignore */ }\n return basename(resolve(dir));\n}\n\nexport function detectMainBranch(dir: string): string {\n try {\n const ref = execSync('git symbolic-ref refs/remotes/origin/HEAD', {\n cwd: dir,\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n }).trim();\n return ref.split('/').pop() ?? 'main';\n } catch { /* ignore */ }\n\n try {\n const branch = execSync('git branch --show-current', {\n cwd: dir,\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n }).trim();\n if (branch) return branch;\n } catch { /* ignore */ }\n\n return 'main';\n}\n","import type { ProjectType } from \"./detect.js\";\n\ninterface TaskPrompt {\n title: string;\n prompt: string;\n priority: number;\n}\n\nconst COMMON_TASKS: TaskPrompt[] = [\n {\n title: \"Fix TODOs\",\n prompt:\n \"Scan for TODO, FIXME, HACK comments. Fix the most impactful ones. Run tests to verify.\",\n priority: 1,\n },\n {\n title: \"Update dependencies\",\n prompt:\n \"Check for outdated dependencies. Update patch/minor versions that are safe. Run tests after updating.\",\n priority: 2,\n },\n {\n title: \"Improve test coverage\",\n prompt:\n \"Find untested public functions. Write tests for the most critical ones. Target 80%+ coverage.\",\n priority: 3,\n },\n {\n title: \"Fix lint warnings\",\n prompt:\n \"Run the project linter. Fix all warnings without changing behavior. Run tests.\",\n priority: 4,\n },\n {\n title: \"Improve documentation\",\n prompt:\n \"Review README and code docs. Add missing JSDoc/KDoc for public APIs. Update outdated sections.\",\n priority: 5,\n },\n {\n title: \"Security audit\",\n prompt:\n \"Check for common security issues: hardcoded secrets, SQL injection, XSS, insecure defaults. Fix any found.\",\n priority: 6,\n },\n];\n\nconst TYPE_TASKS: Partial<Record<ProjectType, TaskPrompt[]>> = {\n kmp: [\n {\n title: \"KMP: Optimize Compose\",\n prompt:\n \"Review Compose UI code for recomposition issues. Add @Stable/@Immutable where needed. Check remember usage.\",\n priority: 2,\n },\n {\n title: \"KMP: Check expect/actual\",\n prompt:\n \"Review expect/actual declarations. Ensure all platforms have proper implementations. Check for missing iOS/Desktop actuals.\",\n priority: 3,\n },\n {\n title: \"KMP: Room migrations\",\n prompt:\n \"Check Room database schema. Ensure migrations are defined for schema changes. Add missing migration tests.\",\n priority: 4,\n },\n ],\n typescript: [\n {\n title: \"TS: Strict type safety\",\n prompt:\n \"Find `any` types and loose assertions. Replace with proper types. Enable stricter tsconfig options if safe.\",\n priority: 2,\n },\n ],\n react: [\n {\n title: \"React: Performance\",\n prompt:\n \"Find unnecessary re-renders. Add React.memo, useMemo, useCallback where beneficial. Check bundle size.\",\n priority: 2,\n },\n ],\n python: [\n {\n title: \"Python: Type hints\",\n prompt:\n \"Add type hints to public functions. Run mypy to check type safety. Fix any type errors.\",\n priority: 2,\n },\n ],\n node: [\n {\n title: \"Node: Error handling\",\n prompt:\n \"Review async error handling. Add try/catch for unhandled promises. Check for missing error middleware.\",\n priority: 2,\n },\n ],\n};\n\nexport function getTasksForProject(type: ProjectType): TaskPrompt[] {\n const specific = TYPE_TASKS[type] ?? [];\n return [...specific, ...COMMON_TASKS].sort(\n (a, b) => a.priority - b.priority,\n );\n}\n","import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\n\nconst LOCK_BASE = join(homedir(), '.copilot', 'locks');\n\nfunction lockDir(name: string): string {\n return join(LOCK_BASE, `${name}.lock`);\n}\n\nfunction isPidAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n\nexport function acquireLock(name: string, timeoutMs = 30_000): boolean {\n mkdirSync(LOCK_BASE, { recursive: true });\n const dir = lockDir(name);\n const deadline = Date.now() + timeoutMs;\n\n while (Date.now() < deadline) {\n try {\n mkdirSync(dir);\n // Lock acquired — write metadata\n writeFileSync(join(dir, 'pid'), String(process.pid));\n writeFileSync(join(dir, 'acquired'), new Date().toISOString());\n return true;\n } catch {\n // Lock dir exists — check if holder is still alive\n try {\n const holderPid = parseInt(readFileSync(join(dir, 'pid'), 'utf-8').trim(), 10);\n if (!isPidAlive(holderPid)) {\n // Stale lock — break it\n rmSync(dir, { recursive: true, force: true });\n continue;\n }\n } catch {\n // Can't read pid file — try breaking\n rmSync(dir, { recursive: true, force: true });\n continue;\n }\n // Holder is alive — wait and retry\n const waitMs = Math.min(500, deadline - Date.now());\n if (waitMs > 0) {\n const start = Date.now();\n while (Date.now() - start < waitMs) { /* spin wait */ }\n }\n }\n }\n return false;\n}\n\nexport function releaseLock(name: string): void {\n const dir = lockDir(name);\n try {\n rmSync(dir, { recursive: true, force: true });\n } catch { /* already released */ }\n}\n\nexport async function withLock<T>(name: string, fn: () => T | Promise<T>): Promise<T> {\n if (!acquireLock(name)) {\n throw new Error(`Failed to acquire lock: ${name}`);\n }\n try {\n return await fn();\n } finally {\n releaseLock(name);\n }\n}\n","import { existsSync, rmSync } from 'node:fs';\nimport { join, resolve } from 'node:path';\nimport { execSync } from 'node:child_process';\n\nfunction gitExec(dir: string, cmd: string): string | null {\n try {\n return execSync(cmd, {\n cwd: dir,\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n }).trim();\n } catch {\n return null;\n }\n}\n\nexport function isGitRepo(dir: string): boolean {\n return existsSync(join(dir, '.git'));\n}\n\nexport function gitCurrentBranch(dir: string): string | null {\n return gitExec(dir, 'git branch --show-current');\n}\n\nexport function gitStash(dir: string): boolean {\n return gitExec(dir, 'git stash -q') !== null;\n}\n\nexport function gitStashPop(dir: string): boolean {\n return gitExec(dir, 'git stash pop -q') !== null;\n}\n\nexport function gitCheckout(dir: string, branch: string): boolean {\n return gitExec(dir, `git checkout ${branch} -q`) !== null;\n}\n\nexport function gitCreateBranch(dir: string, branch: string): boolean {\n return gitExec(dir, `git checkout -b ${branch}`) !== null;\n}\n\nexport function gitCountCommits(dir: string, from: string, to: string): number {\n const result = gitExec(dir, `git log ${from}..${to} --oneline`);\n if (!result) return 0;\n return result.split('\\n').filter(l => l.trim()).length;\n}\n\nexport function gitStatus(dir: string): string {\n return gitExec(dir, 'git status --porcelain') ?? '';\n}\n\nexport function gitRoot(dir: string): string | null {\n return gitExec(dir, 'git rev-parse --show-toplevel');\n}\n\n// ── Worktree support ──\n\nexport function listWorktrees(dir: string): { path: string; branch: string; bare: boolean }[] {\n const raw = gitExec(dir, 'git worktree list --porcelain');\n if (!raw) return [];\n const trees: { path: string; branch: string; bare: boolean }[] = [];\n let current: { path: string; branch: string; bare: boolean } = { path: '', branch: '', bare: false };\n for (const line of raw.split('\\n')) {\n if (line.startsWith('worktree ')) {\n if (current.path) trees.push(current);\n current = { path: line.slice(9), branch: '', bare: false };\n } else if (line.startsWith('branch ')) {\n current.branch = line.slice(7).replace('refs/heads/', '');\n } else if (line === 'bare') {\n current.bare = true;\n }\n }\n if (current.path) trees.push(current);\n return trees;\n}\n\n/**\n * Create a git worktree for parallel copilot work.\n * Returns the worktree path or null on failure.\n */\nexport function createWorktree(repoDir: string, branch: string): string | null {\n const safeBranch = branch.replace(/[^a-zA-Z0-9._/-]/g, '-');\n const worktreePath = resolve(repoDir, '..', `${resolve(repoDir).split('/').pop()}-wt-${safeBranch}`);\n\n if (existsSync(worktreePath)) {\n return worktreePath; // already exists\n }\n\n // Create branch if it doesn't exist, then add worktree\n const branchExists = gitExec(repoDir, `git rev-parse --verify ${safeBranch}`) !== null;\n const cmd = branchExists\n ? `git worktree add \"${worktreePath}\" ${safeBranch}`\n : `git worktree add -b ${safeBranch} \"${worktreePath}\"`;\n\n if (gitExec(repoDir, cmd) !== null) {\n return worktreePath;\n }\n return null;\n}\n\n/**\n * Remove a worktree (prune).\n */\nexport function removeWorktree(repoDir: string, worktreePath: string): boolean {\n const result = gitExec(repoDir, `git worktree remove \"${worktreePath}\" --force`);\n return result !== null;\n}\n\n/**\n * Clean up all copilot-agent worktrees.\n */\nexport function cleanupWorktrees(repoDir: string): number {\n const trees = listWorktrees(repoDir);\n let cleaned = 0;\n for (const t of trees) {\n if (t.path.includes('-wt-')) {\n if (removeWorktree(repoDir, t.path)) cleaned++;\n }\n }\n gitExec(repoDir, 'git worktree prune');\n return cleaned;\n}\n","import type { Command } from 'commander';\nimport { detectProjectType, detectProjectName, detectMainBranch } from '../lib/detect.js';\nimport { getTasksForProject } from '../lib/tasks.js';\nimport { runCopilotTask, assertCopilot } from '../lib/process.js';\nimport { withLock } from '../lib/lock.js';\nimport { isGitRepo, gitCurrentBranch, gitStatus, gitStash, gitCheckout, gitCreateBranch, gitCountCommits, createWorktree, removeWorktree } from '../lib/git.js';\nimport { log, ok, warn, fail, info, notify } from '../lib/logger.js';\nimport { BOLD, CYAN, DIM, GREEN, RESET, YELLOW } from '../lib/colors.js';\n\nexport function registerRunCommand(program: Command): void {\n program\n .command('run [dir]')\n .description('Discover and fix issues in a project')\n .option('-s, --steps <n>', 'Max autopilot continues per task', '30')\n .option('-t, --max-tasks <n>', 'Max number of tasks to run', '5')\n .option('-p, --max-premium <n>', 'Max total premium requests', '50')\n .option('--dry-run', 'Show tasks without executing')\n .option('--worktree', 'Use git worktree for parallel execution (default: wait for idle)')\n .action(async (dir: string | undefined, opts) => {\n try {\n await runCommand(dir ?? process.cwd(), {\n steps: parseInt(opts.steps, 10),\n maxTasks: parseInt(opts.maxTasks, 10),\n maxPremium: parseInt(opts.maxPremium, 10),\n dryRun: opts.dryRun ?? false,\n useWorktree: opts.worktree ?? false,\n });\n } catch (err) {\n fail(`Run error: ${err instanceof Error ? err.message : err}`);\n process.exit(1);\n }\n });\n}\n\ninterface RunOptions {\n steps: number;\n maxTasks: number;\n maxPremium: number;\n dryRun: boolean;\n useWorktree: boolean;\n}\n\nasync function runCommand(dir: string, opts: RunOptions): Promise<void> {\n assertCopilot();\n\n const projectType = detectProjectType(dir);\n const name = detectProjectName(dir);\n const mainBranch = isGitRepo(dir) ? detectMainBranch(dir) : null;\n\n info(`Project: ${CYAN}${name}${RESET} (${projectType})`);\n if (mainBranch) info(`Main branch: ${mainBranch}`);\n\n const tasks = getTasksForProject(projectType).slice(0, opts.maxTasks);\n\n if (tasks.length === 0) {\n warn('No tasks found for this project type.');\n return;\n }\n\n log(`Found ${tasks.length} tasks:`);\n for (const t of tasks) {\n log(` ${DIM}•${RESET} ${t.title}`);\n }\n\n if (opts.dryRun) {\n log(`${DIM}(dry-run — not executing)${RESET}`);\n return;\n }\n\n const originalBranch = isGitRepo(dir) ? gitCurrentBranch(dir) : null;\n let completed = 0;\n let premiumTotal = 0;\n\n for (const task of tasks) {\n if (premiumTotal >= opts.maxPremium) {\n warn(`Premium request limit reached (${premiumTotal}/${opts.maxPremium}).`);\n break;\n }\n\n log(`\\n${'═'.repeat(60)}`);\n log(`${BOLD}${CYAN}Task: ${task.title}${RESET}`);\n log(`${'═'.repeat(60)}`);\n\n const timestamp = Date.now().toString(36);\n const random = Math.random().toString(36).substring(2, 6);\n const branchName = `agent/fix-${completed + 1}-${timestamp}-${random}`;\n\n if (mainBranch && isGitRepo(dir)) {\n if (gitStatus(dir)) gitStash(dir);\n gitCheckout(dir, mainBranch);\n if (!gitCreateBranch(dir, branchName)) {\n warn(`Could not create branch ${branchName}, continuing on current.`);\n }\n }\n\n info(`Running: ${task.title}…`);\n\n let taskDir = dir;\n let worktreeCreated = false;\n\n if (opts.useWorktree && isGitRepo(dir)) {\n try {\n taskDir = createWorktree(dir, branchName, mainBranch ?? undefined);\n worktreeCreated = true;\n info(`Created worktree: ${taskDir}`);\n } catch (err) {\n warn(`Worktree creation failed, falling back to main dir: ${err}`);\n taskDir = dir;\n }\n }\n\n const result = await withLock('copilot-run', () =>\n runCopilotTask(task.prompt, opts.steps, taskDir, opts.useWorktree),\n );\n\n const commitRef = worktreeCreated ? taskDir : dir;\n const commits = mainBranch ? gitCountCommits(commitRef, mainBranch, 'HEAD') : 0;\n premiumTotal += result.premium;\n completed++;\n ok(`${task.title} — ${commits} commit(s), ${result.premium} premium`);\n\n if (worktreeCreated) {\n try {\n removeWorktree(dir, taskDir);\n } catch (err) {\n warn(`Worktree cleanup failed: ${err}`);\n }\n }\n\n if (!worktreeCreated && originalBranch && isGitRepo(dir)) {\n gitCheckout(dir, mainBranch ?? originalBranch);\n }\n }\n\n log(`\\n${BOLD}═══ Run Summary ═══${RESET}`);\n log(`Completed ${completed}/${tasks.length} tasks. Total premium: ${premiumTotal}`);\n notify(`Completed ${completed} tasks`, name);\n}\n","import type { Command } from 'commander';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport { detectProjectType, detectProjectName, detectMainBranch } from '../lib/detect.js';\nimport { getTasksForProject } from '../lib/tasks.js';\nimport { runCopilotTask, assertCopilot, findPidForSession, findCopilotProcesses, waitForExit, waitForCopilotInDir, runCopilotResume } from '../lib/process.js';\nimport { withLock } from '../lib/lock.js';\nimport { isGitRepo, gitCurrentBranch, gitStash, gitCheckout, gitCreateBranch, gitCountCommits, createWorktree, removeWorktree } from '../lib/git.js';\nimport { findLatestIncomplete, validateSession, hasTaskComplete, getSessionCwd } from '../lib/session.js';\nimport { log, ok, warn, fail, info, setLogFile, notify } from '../lib/logger.js';\nimport { BOLD, CYAN, DIM, RESET } from '../lib/colors.js';\n\nexport function registerOvernightCommand(program: Command): void {\n program\n .command('overnight [dir]')\n .description('Run tasks continuously until a deadline')\n .option('-u, --until <HH>', 'Stop at this hour (24h format)', '07')\n .option('-s, --steps <n>', 'Max autopilot continues per task', '50')\n .option('-c, --cooldown <n>', 'Seconds between tasks', '15')\n .option('-p, --max-premium <n>', 'Max premium requests budget', '300')\n .option('--dry-run', 'Show plan without executing')\n .option('--worktree', 'Use git worktree for parallel execution (default: wait for idle)')\n .action(async (dir: string | undefined, opts) => {\n try {\n await overnightCommand(dir ?? process.cwd(), {\n until: parseInt(opts.until, 10),\n steps: parseInt(opts.steps, 10),\n cooldown: parseInt(opts.cooldown, 10),\n maxPremium: parseInt(opts.maxPremium, 10),\n dryRun: opts.dryRun ?? false,\n useWorktree: opts.worktree ?? false,\n });\n } catch (err) {\n fail(`Overnight error: ${err instanceof Error ? err.message : err}`);\n process.exit(1);\n }\n });\n}\n\ninterface OvernightOptions {\n until: number;\n steps: number;\n cooldown: number;\n maxPremium: number;\n dryRun: boolean;\n useWorktree: boolean;\n}\n\nfunction isPastDeadline(untilHour: number): boolean {\n const hour = new Date().getHours();\n return hour >= untilHour && hour < 20;\n}\n\nasync function overnightCommand(dir: string, opts: OvernightOptions): Promise<void> {\n assertCopilot();\n\n const ts = new Date().toISOString().replace(/[:.]/g, '').slice(0, 15);\n const logPath = join(homedir(), '.copilot', 'auto-resume-logs', `overnight-${ts}.log`);\n setLogFile(logPath);\n\n const name = detectProjectName(dir);\n const projectType = detectProjectType(dir);\n const mainBranch = isGitRepo(dir) ? detectMainBranch(dir) : null;\n\n info(`Overnight runner for ${CYAN}${name}${RESET} (${projectType})`);\n info(`Deadline: ${String(opts.until).padStart(2, '0')}:00`);\n info(`Max premium: ${opts.maxPremium}, Steps: ${opts.steps}`);\n info(`Log: ${logPath}`);\n\n const tasks = getTasksForProject(projectType);\n\n if (opts.dryRun) {\n log(`\\nWould run ${tasks.length} tasks:`);\n for (const t of tasks) log(` ${DIM}•${RESET} ${t.title}`);\n return;\n }\n\n // Phase 1: Resume existing incomplete session\n const existingSession = findLatestIncomplete();\n if (existingSession && validateSession(existingSession)) {\n info(`Found incomplete session: ${existingSession}`);\n const pid = findPidForSession(existingSession);\n if (pid) {\n info(`Waiting for running copilot (PID ${pid})...`);\n await waitForExit(pid);\n }\n\n if (!hasTaskComplete(existingSession) && !isPastDeadline(opts.until)) {\n info('Resuming incomplete session...');\n const cwd = getSessionCwd(existingSession) || dir;\n await runCopilotResume(\n existingSession,\n opts.steps,\n 'Continue remaining work. Complete the task.',\n cwd,\n );\n }\n }\n\n // Phase 2: Loop tasks until deadline\n const originalBranch = isGitRepo(dir) ? gitCurrentBranch(dir) : null;\n let taskIdx = 0;\n let totalPremium = 0;\n let totalCommits = 0;\n\n while (!isPastDeadline(opts.until) && taskIdx < tasks.length) {\n if (totalPremium >= opts.maxPremium) {\n warn(`Premium budget exhausted: ${totalPremium}/${opts.maxPremium}`);\n break;\n }\n\n const task = tasks[taskIdx % tasks.length];\n taskIdx++;\n\n log(`\\n${'═'.repeat(60)}`);\n log(`${BOLD}${CYAN}[${new Date().toLocaleTimeString()}] Task ${taskIdx}: ${task.title}${RESET}`);\n log(`${DIM}Premium: ${totalPremium}/${opts.maxPremium}${RESET}`);\n log(`${'═'.repeat(60)}`);\n\n const timestamp = Date.now().toString(36);\n const random = Math.random().toString(36).substring(2, 6);\n const branchName = `agent/overnight-${taskIdx}-${timestamp}-${random}`;\n\n if (mainBranch && isGitRepo(dir)) {\n gitStash(dir);\n gitCheckout(dir, mainBranch);\n gitCreateBranch(dir, branchName);\n }\n\n info(`Running: ${task.title}…`);\n\n let taskDir = dir;\n let worktreeCreated = false;\n\n if (opts.useWorktree && isGitRepo(dir)) {\n try {\n taskDir = createWorktree(dir, branchName, mainBranch ?? undefined);\n worktreeCreated = true;\n info(`Created worktree: ${taskDir}`);\n } catch (err) {\n warn(`Worktree creation failed, falling back to main dir: ${err}`);\n taskDir = dir;\n }\n }\n\n try {\n const result = await withLock('copilot-overnight', () =>\n runCopilotTask(task.prompt, opts.steps, taskDir, opts.useWorktree),\n );\n\n const commitRef = worktreeCreated ? taskDir : dir;\n const commits = mainBranch ? gitCountCommits(commitRef, mainBranch, 'HEAD') : 0;\n totalPremium += result.premium;\n totalCommits += commits;\n\n if (commits > 0) {\n ok(`${commits} commit(s) on ${branchName}`);\n } else {\n log(`${DIM}No commits on ${branchName}${RESET}`);\n }\n } catch (err) {\n fail(`Task failed: ${err}`);\n }\n\n // Cleanup worktree if we created one\n if (worktreeCreated) {\n try {\n removeWorktree(dir, taskDir);\n info(`Removed worktree: ${taskDir}`);\n } catch (err) {\n warn(`Worktree cleanup failed: ${err}`);\n }\n }\n\n if (!worktreeCreated && mainBranch && isGitRepo(dir)) {\n gitCheckout(dir, mainBranch);\n }\n\n if (!isPastDeadline(opts.until)) {\n info(`Cooldown ${opts.cooldown}s…`);\n await sleep(opts.cooldown * 1000);\n }\n }\n\n if (originalBranch && isGitRepo(dir)) {\n gitCheckout(dir, originalBranch);\n }\n\n const summary = `Overnight done — ${taskIdx} tasks, ${totalCommits} commits, ${totalPremium} premium.`;\n ok(summary);\n notify(summary, name);\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise(r => setTimeout(r, ms));\n}\n","import type { Command } from 'commander';\nimport { existsSync, copyFileSync, mkdirSync } from 'node:fs';\nimport { join, resolve } from 'node:path';\nimport { homedir } from 'node:os';\nimport { detectProjectType, detectProjectName } from '../lib/detect.js';\nimport { runCopilotTask, assertCopilot } from '../lib/process.js';\nimport { withLock } from '../lib/lock.js';\nimport { log, ok, warn, fail, info, notify } from '../lib/logger.js';\nimport { CYAN, RESET } from '../lib/colors.js';\n\nexport function registerResearchCommand(program: Command): void {\n program\n .command('research [project]')\n .description('Research improvements or a specific topic')\n .option('-s, --steps <n>', 'Max autopilot continues', '50')\n .action(async (project: string | undefined, opts) => {\n try {\n await researchCommand(project ?? process.cwd(), {\n steps: parseInt(opts.steps, 10),\n });\n } catch (err) {\n fail(`Research error: ${err instanceof Error ? err.message : err}`);\n process.exit(1);\n }\n });\n}\n\ninterface ResearchOptions {\n steps: number;\n}\n\nfunction buildResearchPrompt(projectType: string, projectName: string): string {\n return `You are a senior software architect. Analyze this ${projectType} project \"${projectName}\" thoroughly.\n\nResearch and produce a file called RESEARCH-PROPOSALS.md with:\n\n1. **Architecture Assessment** — Current architecture, patterns used, strengths and weaknesses\n2. **Code Quality Report** — Common issues, anti-patterns, technical debt areas\n3. **Security Audit** — Potential vulnerabilities, dependency risks, configuration issues\n4. **Performance Analysis** — Bottlenecks, optimization opportunities, resource usage\n5. **Testing Gap Analysis** — Untested areas, test quality, coverage recommendations\n6. **Improvement Proposals** — Prioritized list of actionable improvements with effort estimates\n\nFor each proposal, include:\n- Priority (P0/P1/P2)\n- Estimated effort (hours)\n- Impact description\n- Suggested implementation approach\n\nWrite RESEARCH-PROPOSALS.md in the project root.`;\n}\n\nasync function researchCommand(dir: string, opts: ResearchOptions): Promise<void> {\n assertCopilot();\n\n const projectDir = resolve(dir);\n const projectType = detectProjectType(projectDir);\n const projectName = detectProjectName(projectDir);\n\n info(`Researching: ${CYAN}${projectName}${RESET} (${projectType})`);\n\n const prompt = buildResearchPrompt(projectType, projectName);\n\n const result = await withLock('copilot-research', () =>\n runCopilotTask(prompt, opts.steps, projectDir),\n );\n\n log(`Copilot exited with code ${result.exitCode}`);\n\n // Check for output file\n const proposalsFile = join(projectDir, 'RESEARCH-PROPOSALS.md');\n if (existsSync(proposalsFile)) {\n ok('RESEARCH-PROPOSALS.md generated.');\n\n // Backup to ~/.copilot/research-reports/\n const backupDir = join(homedir(), '.copilot', 'research-reports');\n mkdirSync(backupDir, { recursive: true });\n const timestamp = new Date().toISOString().replace(/[:.]/g, '-');\n const backupFile = join(backupDir, `${projectName}-${timestamp}.md`);\n copyFileSync(proposalsFile, backupFile);\n ok(`Backup saved: ${backupFile}`);\n } else {\n warn('RESEARCH-PROPOSALS.md was not generated. Check copilot output.');\n }\n\n notify('Research complete', projectName);\n}\n","import type { Command } from 'commander';\nimport { resolve } from 'node:path';\nimport {\n listSessions,\n getSessionReport,\n type SessionReport,\n} from '../lib/session.js';\nimport { log, warn, fail } from '../lib/logger.js';\nimport { BOLD, CYAN, DIM, GREEN, YELLOW, RED, RESET } from '../lib/colors.js';\n\nexport function registerReportCommand(program: Command): void {\n program\n .command('report [session-id]')\n .description('Show what copilot did — timeline, tools, commits, files changed')\n .option('-l, --limit <n>', 'Number of recent sessions to report (when no ID given)', '1')\n .option('--project <dir>', 'Filter sessions by project directory')\n .option('--json', 'Output raw JSON')\n .action((sessionId: string | undefined, opts) => {\n try {\n if (sessionId) {\n reportSingle(sessionId, opts.json ?? false);\n } else {\n reportRecent(parseInt(opts.limit, 10), opts.project, opts.json ?? false);\n }\n } catch (err) {\n fail(`Report error: ${err instanceof Error ? err.message : err}`);\n process.exit(1);\n }\n });\n}\n\nfunction reportRecent(limit: number, projectDir?: string, json = false): void {\n let sessions = listSessions(limit * 3); // fetch extra to filter\n if (projectDir) {\n const target = resolve(projectDir);\n sessions = sessions.filter(s => s.cwd && resolve(s.cwd) === target);\n }\n sessions = sessions.slice(0, limit);\n\n if (sessions.length === 0) {\n warn('No sessions found.');\n return;\n }\n\n for (const s of sessions) {\n reportSingle(s.id, json);\n }\n}\n\nfunction reportSingle(sid: string, json = false): void {\n const report = getSessionReport(sid);\n if (!report) {\n warn(`Session ${sid} not found or invalid.`);\n return;\n }\n\n if (json) {\n log(JSON.stringify(report, null, 2));\n return;\n }\n\n renderReport(report);\n}\n\nfunction formatDuration(ms: number): string {\n if (ms < 60_000) return `${Math.round(ms / 1000)}s`;\n if (ms < 3_600_000) return `${Math.round(ms / 60_000)}m`;\n const h = Math.floor(ms / 3_600_000);\n const m = Math.round((ms % 3_600_000) / 60_000);\n return `${h}h ${m}m`;\n}\n\nfunction formatTime(iso: string): string {\n if (!iso) return '—';\n const d = new Date(iso);\n return d.toLocaleString('en-GB', {\n month: 'short',\n day: 'numeric',\n hour: '2-digit',\n minute: '2-digit',\n });\n}\n\nfunction bar(value: number, max: number, width = 20): string {\n const filled = Math.round((value / Math.max(max, 1)) * width);\n return '█'.repeat(filled) + '░'.repeat(width - filled);\n}\n\nfunction renderReport(r: SessionReport): void {\n const status = r.complete\n ? `${GREEN}✔ Completed${RESET}`\n : `${YELLOW}⏸ Interrupted${RESET}`;\n\n const projectName = r.cwd.split('/').pop() ?? r.cwd;\n\n log('');\n log(`${BOLD}╔${'═'.repeat(62)}╗${RESET}`);\n log(`${BOLD}║${RESET} 📋 Session Report: ${CYAN}${r.id.slice(0, 8)}…${RESET}${' '.repeat(62 - 28 - r.id.slice(0, 8).length)}${BOLD}║${RESET}`);\n log(`${BOLD}╚${'═'.repeat(62)}╝${RESET}`);\n\n // Overview\n log('');\n log(`${BOLD} Overview${RESET}`);\n log(` ${'─'.repeat(58)}`);\n log(` Project: ${CYAN}${projectName}${RESET} ${DIM}${r.cwd}${RESET}`);\n log(` Status: ${status}`);\n log(` Duration: ${BOLD}${formatDuration(r.durationMs)}${RESET} ${DIM}(${formatTime(r.startTime)} → ${formatTime(r.endTime)})${RESET}`);\n log(` Summary: ${r.summary || DIM + '(none)' + RESET}`);\n\n // Stats\n log('');\n log(`${BOLD} Activity${RESET}`);\n log(` ${'─'.repeat(58)}`);\n log(` User messages: ${BOLD}${r.userMessages}${RESET}`);\n log(` Assistant turns: ${BOLD}${r.assistantTurns}${RESET}`);\n log(` Output tokens: ${BOLD}${r.outputTokens.toLocaleString()}${RESET}`);\n log(` Premium requests: ${BOLD}${r.premiumRequests}${RESET}`);\n log(` Tool calls: ${BOLD}${Object.values(r.toolUsage).reduce((a, b) => a + b, 0)}${RESET}`);\n\n // Tools breakdown\n const toolEntries = Object.entries(r.toolUsage).sort((a, b) => b[1] - a[1]);\n if (toolEntries.length > 0) {\n const maxCount = toolEntries[0][1];\n log('');\n log(`${BOLD} Tools Used${RESET}`);\n log(` ${'─'.repeat(58)}`);\n for (const [tool, count] of toolEntries.slice(0, 10)) {\n const barStr = bar(count, maxCount, 15);\n log(` ${DIM}${barStr}${RESET} ${String(count).padStart(5)} ${tool}`);\n }\n if (toolEntries.length > 10) {\n log(` ${DIM} … and ${toolEntries.length - 10} more tools${RESET}`);\n }\n }\n\n // Git commits\n if (r.gitCommits.length > 0) {\n log('');\n log(`${BOLD} Git Commits (${r.gitCommits.length})${RESET}`);\n log(` ${'─'.repeat(58)}`);\n for (const msg of r.gitCommits) {\n log(` ${GREEN}●${RESET} ${msg.slice(0, 70)}${msg.length > 70 ? '…' : ''}`);\n }\n }\n\n // Files created\n if (r.filesCreated.length > 0) {\n log('');\n log(`${BOLD} Files Created (${r.filesCreated.length})${RESET}`);\n log(` ${'─'.repeat(58)}`);\n for (const f of r.filesCreated.slice(0, 15)) {\n const short = f.includes(projectName) ? f.split(projectName + '/')[1] ?? f : f;\n log(` ${GREEN}+${RESET} ${short}`);\n }\n if (r.filesCreated.length > 15) {\n log(` ${DIM} … and ${r.filesCreated.length - 15} more${RESET}`);\n }\n }\n\n // Files edited\n if (r.filesEdited.length > 0) {\n log('');\n log(`${BOLD} Files Edited (${r.filesEdited.length})${RESET}`);\n log(` ${'─'.repeat(58)}`);\n for (const f of r.filesEdited.slice(0, 15)) {\n const short = f.includes(projectName) ? f.split(projectName + '/')[1] ?? f : f;\n log(` ${YELLOW}~${RESET} ${short}`);\n }\n if (r.filesEdited.length > 15) {\n log(` ${DIM} … and ${r.filesEdited.length - 15} more${RESET}`);\n }\n }\n\n // Task completions\n if (r.taskCompletions.length > 0) {\n log('');\n log(`${BOLD} Tasks Completed (${r.taskCompletions.length})${RESET}`);\n log(` ${'─'.repeat(58)}`);\n for (const t of r.taskCompletions) {\n const lines = t.split('\\n');\n const first = lines[0].slice(0, 70);\n log(` ${GREEN}✔${RESET} ${first}${first.length < lines[0].length ? '…' : ''}`);\n }\n }\n\n // Errors\n if (r.errors.length > 0) {\n log('');\n log(`${BOLD} Errors (${r.errors.length})${RESET}`);\n log(` ${'─'.repeat(58)}`);\n for (const e of r.errors.slice(0, 5)) {\n log(` ${RED}✖${RESET} ${e.slice(0, 70)}`);\n }\n if (r.errors.length > 5) {\n log(` ${DIM} … and ${r.errors.length - 5} more${RESET}`);\n }\n }\n\n log('');\n}\n"],"mappings":"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","names":["execSync","resolve","execSync","resolve","program","program","sleep","existsSync","readFileSync","readdirSync","join","resolve","execSync","mkdirSync","readFileSync","join","homedir","existsSync","join","resolve","execSync","resolve","existsSync","program","join","homedir","program","join","homedir","sleep","existsSync","mkdirSync","join","resolve","homedir","program","resolve","join","existsSync","homedir","mkdirSync","resolve","program","resolve"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/lib/session.ts","../src/lib/process.ts","../src/lib/logger.ts","../src/lib/colors.ts","../src/commands/status.ts","../src/commands/watch.ts","../src/lib/detect.ts","../src/lib/tasks.ts","../src/lib/lock.ts","../src/lib/git.ts","../src/commands/run.ts","../src/commands/overnight.ts","../src/commands/research.ts","../src/commands/report.ts","../src/commands/dashboard.ts","../src/commands/web.ts","../src/web/layout.ts","../src/web/views.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { registerStatusCommand } from './commands/status.js';\nimport { registerWatchCommand } from './commands/watch.js';\nimport { registerRunCommand } from './commands/run.js';\nimport { registerOvernightCommand } from './commands/overnight.js';\nimport { registerResearchCommand } from './commands/research.js';\nimport { registerReportCommand } from './commands/report.js';\nimport { registerDashboardCommand } from './commands/dashboard.js';\nimport { registerWebCommand } from './commands/web.js';\n\nconst program = new Command();\n\nprogram\n .name('copilot-agent')\n .version('0.7.0')\n .description('Autonomous GitHub Copilot CLI agent — auto-resume, task discovery, overnight runs');\n\nregisterStatusCommand(program);\nregisterWatchCommand(program);\nregisterRunCommand(program);\nregisterOvernightCommand(program);\nregisterResearchCommand(program);\nregisterReportCommand(program);\nregisterDashboardCommand(program);\nregisterWebCommand(program);\n\nprogram.parse();\n","import {\n existsSync,\n readdirSync,\n readFileSync,\n statSync,\n} from 'node:fs';\nimport { join, resolve } from 'node:path';\nimport { homedir } from 'node:os';\n\nexport interface Session {\n id: string;\n dir: string;\n mtime: number;\n lastEvent: string;\n premiumRequests: number;\n summary: string;\n cwd: string;\n complete: boolean;\n}\n\nexport interface SessionReport {\n id: string;\n cwd: string;\n summary: string;\n startTime: string;\n endTime: string;\n durationMs: number;\n complete: boolean;\n userMessages: number;\n assistantTurns: number;\n outputTokens: number;\n premiumRequests: number;\n toolUsage: Record<string, number>;\n gitCommits: string[];\n filesCreated: string[];\n filesEdited: string[];\n errors: string[];\n taskCompletions: string[];\n}\n\nconst SESSION_DIR = join(homedir(), '.copilot', 'session-state');\n\nexport function getSessionDir(): string {\n return SESSION_DIR;\n}\n\nexport function validateSession(sid: string): boolean {\n const events = join(SESSION_DIR, sid, 'events.jsonl');\n try {\n return existsSync(events) && statSync(events).size > 0;\n } catch {\n return false;\n }\n}\n\nexport function listSessions(limit = 20): Session[] {\n if (!existsSync(SESSION_DIR)) return [];\n\n const entries = readdirSync(SESSION_DIR, { withFileTypes: true })\n .filter(d => d.isDirectory());\n\n const dirs: { id: string; dir: string; mtime: number }[] = [];\n for (const entry of entries) {\n const dirPath = join(SESSION_DIR, entry.name);\n if (!existsSync(join(dirPath, 'events.jsonl'))) continue;\n try {\n const stat = statSync(dirPath);\n dirs.push({ id: entry.name, dir: dirPath, mtime: stat.mtimeMs });\n } catch { /* skip */ }\n }\n\n dirs.sort((a, b) => b.mtime - a.mtime);\n\n return dirs.slice(0, limit).map(s => ({\n id: s.id,\n dir: s.dir,\n mtime: s.mtime,\n lastEvent: getLastEvent(s.id),\n premiumRequests: getSessionPremium(s.id),\n summary: getSessionSummary(s.id),\n cwd: getSessionCwd(s.id),\n complete: hasTaskComplete(s.id),\n }));\n}\n\nexport function getLatestSessionId(): string | null {\n if (!existsSync(SESSION_DIR)) return null;\n\n const entries = readdirSync(SESSION_DIR, { withFileTypes: true })\n .filter(d => d.isDirectory());\n\n let latest: { id: string; mtime: number } | null = null;\n for (const entry of entries) {\n try {\n const stat = statSync(join(SESSION_DIR, entry.name));\n if (!latest || stat.mtimeMs > latest.mtime) {\n latest = { id: entry.name, mtime: stat.mtimeMs };\n }\n } catch { /* skip */ }\n }\n return latest?.id ?? null;\n}\n\nexport function hasTaskComplete(sid: string): boolean {\n if (!validateSession(sid)) return false;\n try {\n const content = readFileSync(join(SESSION_DIR, sid, 'events.jsonl'), 'utf-8');\n return content.includes('\"session.task_complete\"');\n } catch {\n return false;\n }\n}\n\nexport function getLastEvent(sid: string): string {\n if (!validateSession(sid)) return 'invalid';\n try {\n const lines = readFileSync(join(SESSION_DIR, sid, 'events.jsonl'), 'utf-8')\n .trimEnd()\n .split('\\n');\n const last = JSON.parse(lines[lines.length - 1]);\n return last.type ?? 'unknown';\n } catch {\n return 'corrupted';\n }\n}\n\nexport function getSessionPremium(sid: string): number {\n if (!validateSession(sid)) return 0;\n try {\n const content = readFileSync(join(SESSION_DIR, sid, 'events.jsonl'), 'utf-8');\n const lines = content.trimEnd().split('\\n');\n for (let i = lines.length - 1; i >= 0; i--) {\n try {\n const event = JSON.parse(lines[i]);\n if (event.type === 'session.shutdown' && event.data?.totalPremiumRequests != null) {\n return event.data.totalPremiumRequests;\n }\n } catch { /* skip malformed line */ }\n }\n return 0;\n } catch {\n return 0;\n }\n}\n\nfunction parseSimpleYaml(content: string): Record<string, string> {\n const result: Record<string, string> = {};\n for (const line of content.split('\\n')) {\n const idx = line.indexOf(': ');\n if (idx === -1) continue;\n const key = line.substring(0, idx).trim();\n const value = line.substring(idx + 2).trim();\n if (key) result[key] = value;\n }\n return result;\n}\n\nfunction readWorkspace(sid: string): Record<string, string> {\n const wsPath = join(SESSION_DIR, sid, 'workspace.yaml');\n if (!existsSync(wsPath)) return {};\n try {\n return parseSimpleYaml(readFileSync(wsPath, 'utf-8'));\n } catch {\n return {};\n }\n}\n\nexport function getSessionSummary(sid: string): string {\n return readWorkspace(sid).summary ?? '';\n}\n\nexport function getSessionCwd(sid: string): string {\n return readWorkspace(sid).cwd ?? '';\n}\n\nexport function findSessionForProject(projectPath: string): string | null {\n const resolved = resolve(projectPath);\n const sessions = listSessions(50);\n for (const s of sessions) {\n if (s.cwd && resolve(s.cwd) === resolved) return s.id;\n }\n return null;\n}\n\nexport function findLatestIncomplete(): string | null {\n const sessions = listSessions(50);\n for (const s of sessions) {\n if (!s.complete) return s.id;\n }\n return null;\n}\n\nexport function getSessionReport(sid: string): SessionReport | null {\n if (!validateSession(sid)) return null;\n\n const ws = readWorkspace(sid);\n let lines: string[];\n try {\n lines = readFileSync(join(SESSION_DIR, sid, 'events.jsonl'), 'utf-8')\n .trimEnd()\n .split('\\n');\n } catch {\n return null;\n }\n\n const report: SessionReport = {\n id: sid,\n cwd: ws.cwd ?? '',\n summary: ws.summary ?? '',\n startTime: '',\n endTime: '',\n durationMs: 0,\n complete: false,\n userMessages: 0,\n assistantTurns: 0,\n outputTokens: 0,\n premiumRequests: 0,\n toolUsage: {},\n gitCommits: [],\n filesCreated: [],\n filesEdited: [],\n errors: [],\n taskCompletions: [],\n };\n\n for (const line of lines) {\n let event: Record<string, unknown>;\n try {\n event = JSON.parse(line);\n } catch {\n continue;\n }\n\n const type = event.type as string;\n const ts = event.timestamp as string | undefined;\n const data = (event.data ?? {}) as Record<string, unknown>;\n\n if (ts && !report.startTime) report.startTime = ts;\n if (ts) report.endTime = ts;\n\n switch (type) {\n case 'user.message':\n report.userMessages++;\n break;\n\n case 'assistant.message':\n report.assistantTurns++;\n report.outputTokens += (data.outputTokens as number) ?? 0;\n break;\n\n case 'tool.execution_start': {\n const toolName = data.toolName as string;\n if (toolName) {\n report.toolUsage[toolName] = (report.toolUsage[toolName] ?? 0) + 1;\n }\n // Track git commits\n if (toolName === 'bash') {\n const args = data.arguments as Record<string, string> | undefined;\n const cmd = args?.command ?? '';\n if (cmd.includes('git') && cmd.includes('commit') && cmd.includes('-m')) {\n const msgMatch = cmd.match(/-m\\s+\"([^\"]{1,120})/);\n if (msgMatch) report.gitCommits.push(msgMatch[1]);\n }\n }\n // Track file creates/edits\n if (toolName === 'create') {\n const args = data.arguments as Record<string, string> | undefined;\n if (args?.path) report.filesCreated.push(args.path);\n }\n if (toolName === 'edit') {\n const args = data.arguments as Record<string, string> | undefined;\n if (args?.path && !report.filesEdited.includes(args.path)) {\n report.filesEdited.push(args.path);\n }\n }\n break;\n }\n\n case 'session.task_complete': {\n const summary = data.summary as string | undefined;\n report.taskCompletions.push(summary ?? '(task completed)');\n report.complete = true;\n break;\n }\n\n case 'session.error': {\n const msg = data.message as string | undefined;\n if (msg) report.errors.push(msg);\n break;\n }\n\n case 'session.shutdown': {\n const premium = data.totalPremiumRequests as number | undefined;\n if (premium != null) report.premiumRequests = premium;\n break;\n }\n }\n }\n\n if (report.startTime && report.endTime) {\n report.durationMs = new Date(report.endTime).getTime() - new Date(report.startTime).getTime();\n }\n\n return report;\n}\n","import { execSync, spawn } from 'node:child_process';\nimport { resolve } from 'node:path';\nimport { getLatestSessionId, getSessionPremium, getSessionCwd } from './session.js';\nimport { log, warn, fail } from './logger.js';\n\nexport interface CopilotProcess {\n pid: number;\n command: string;\n sessionId?: string;\n cwd?: string;\n}\n\nexport interface CopilotResult {\n exitCode: number;\n sessionId: string | null;\n premium: number;\n}\n\nexport function isCopilotInstalled(): boolean {\n try {\n execSync('which copilot', { stdio: 'pipe', encoding: 'utf-8' });\n return true;\n } catch {\n return false;\n }\n}\n\nexport function assertCopilot(): void {\n if (!isCopilotInstalled()) {\n fail('copilot CLI not found. Install with: npm i -g @githubnext/copilot');\n process.exit(1);\n }\n}\n\nexport function findCopilotProcesses(): CopilotProcess[] {\n try {\n const output = execSync('ps -eo pid,command', { encoding: 'utf-8' });\n const results: CopilotProcess[] = [];\n const myPid = process.pid;\n const parentPid = process.ppid;\n for (const line of output.split('\\n')) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n if (\n (trimmed.includes('copilot') || trimmed.includes('@githubnext/copilot')) &&\n !trimmed.includes('ps -eo') &&\n !trimmed.includes('copilot-agent') &&\n !trimmed.includes('grep')\n ) {\n const match = trimmed.match(/^(\\d+)\\s+(.+)$/);\n if (match) {\n const pid = parseInt(match[1], 10);\n // Exclude our own process tree\n if (pid === myPid || pid === parentPid) continue;\n const cmd = match[2];\n const sidMatch = cmd.match(/resume[= ]+([a-f0-9-]{36})/);\n // Try to get cwd of the process\n let cwd: string | undefined;\n try {\n cwd = execSync(`lsof -p ${pid} -Fn 2>/dev/null | grep '^n/' | head -1`, {\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n }).trim().slice(1) || undefined;\n } catch { /* best effort */ }\n // Fallback: get cwd from session if we know the session\n const sid = sidMatch?.[1];\n if (!cwd && sid) {\n cwd = getSessionCwd(sid) || undefined;\n }\n results.push({ pid, command: cmd, sessionId: sid, cwd });\n }\n }\n }\n return results;\n } catch {\n return [];\n }\n}\n\nexport function findPidForSession(sid: string): number | null {\n const procs = findCopilotProcesses();\n const matching = procs\n .filter(p => p.command.includes(sid))\n .sort((a, b) => b.pid - a.pid);\n return matching[0]?.pid ?? null;\n}\n\n/**\n * SAFETY: Wait until no copilot is running in the SAME directory.\n * Copilot in different directories/worktrees can run in parallel.\n */\nexport async function waitForCopilotInDir(\n dir: string,\n timeoutMs = 14_400_000,\n pollMs = 10_000,\n): Promise<void> {\n const targetDir = resolve(dir);\n const start = Date.now();\n let warned = false;\n while (Date.now() - start < timeoutMs) {\n const procs = findCopilotProcesses();\n const conflicting = procs.filter(p => {\n if (!p.cwd) return false;\n return resolve(p.cwd) === targetDir;\n });\n if (conflicting.length === 0) return;\n if (!warned) {\n warn(`Waiting for copilot in ${targetDir} to finish...`);\n for (const p of conflicting) {\n log(` PID ${p.pid}: ${p.command.slice(0, 80)}`);\n }\n warned = true;\n }\n await sleep(pollMs);\n }\n warn('Timeout waiting for copilot to finish in directory');\n}\n\n/**\n * SAFETY: Check if a session already has a running copilot process.\n * If so, refuse to spawn another one to prevent corruption.\n */\nexport function assertSessionNotRunning(sid: string): void {\n const pid = findPidForSession(sid);\n if (pid) {\n fail(`Session ${sid.slice(0, 8)}… already has copilot running (PID ${pid}). Cannot resume — would corrupt the session.`);\n process.exit(1);\n }\n}\n\nexport async function waitForExit(pid: number, timeoutMs = 14_400_000): Promise<boolean> {\n const start = Date.now();\n while (Date.now() - start < timeoutMs) {\n try {\n process.kill(pid, 0);\n await sleep(5000);\n } catch {\n return true; // process exited\n }\n }\n return false; // timeout\n}\n\nexport async function runCopilot(\n args: string[],\n options?: { cwd?: string; useWorktree?: boolean },\n): Promise<CopilotResult> {\n const dir = options?.cwd ?? process.cwd();\n\n if (options?.useWorktree) {\n // Worktree mode: create separate worktree, no waiting needed\n // (caller is responsible for creating worktree and passing its path)\n } else {\n // Default: wait for copilot in same directory to finish\n await waitForCopilotInDir(dir);\n }\n\n return new Promise((resolve) => {\n const child = spawn('copilot', args, {\n cwd: options?.cwd,\n stdio: 'inherit',\n env: { ...process.env },\n });\n\n child.on('close', async (code) => {\n await sleep(3000); // let events flush\n const sid = getLatestSessionId();\n const premium = sid ? getSessionPremium(sid) : 0;\n resolve({\n exitCode: code ?? 1,\n sessionId: sid,\n premium,\n });\n });\n\n child.on('error', () => {\n resolve({ exitCode: 1, sessionId: null, premium: 0 });\n });\n });\n}\n\nexport function runCopilotResume(\n sid: string,\n steps: number,\n message?: string,\n cwd?: string,\n): Promise<CopilotResult> {\n // SAFETY: Refuse if session already running\n assertSessionNotRunning(sid);\n\n const args = [\n `--resume=${sid}`,\n '--autopilot',\n '--allow-all',\n '--max-autopilot-continues',\n String(steps),\n '--no-ask-user',\n ];\n if (message) args.push('-p', message);\n return runCopilot(args, { cwd });\n}\n\nexport function runCopilotTask(\n prompt: string,\n steps: number,\n cwd?: string,\n useWorktree?: boolean,\n): Promise<CopilotResult> {\n return runCopilot([\n '-p', prompt,\n '--autopilot',\n '--allow-all',\n '--max-autopilot-continues', String(steps),\n '--no-ask-user',\n ], { cwd, useWorktree });\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise(r => setTimeout(r, ms));\n}\n","import { appendFileSync, mkdirSync } from 'node:fs';\nimport { dirname } from 'node:path';\nimport { execSync } from 'node:child_process';\nimport { RED, GREEN, YELLOW, CYAN, DIM, RESET } from './colors.js';\n\nlet logFilePath: string | null = null;\n\nconst ANSI_RE =\n /[\\u001b\\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g;\n\nfunction stripAnsi(s: string): string {\n return s.replace(ANSI_RE, '');\n}\n\nfunction writeToFile(msg: string): void {\n if (!logFilePath) return;\n try {\n appendFileSync(logFilePath, stripAnsi(msg) + '\\n');\n } catch { /* ignore file write errors */ }\n}\n\nexport function setLogFile(path: string): void {\n mkdirSync(dirname(path), { recursive: true });\n logFilePath = path;\n}\n\nexport function log(msg: string): void {\n console.log(msg);\n writeToFile(msg);\n}\n\nexport function warn(msg: string): void {\n const out = `${YELLOW}⚠ ${msg}${RESET}`;\n console.log(out);\n writeToFile(`⚠ ${msg}`);\n}\n\nexport function ok(msg: string): void {\n const out = `${GREEN}✔ ${msg}${RESET}`;\n console.log(out);\n writeToFile(`✔ ${msg}`);\n}\n\nexport function fail(msg: string): void {\n const out = `${RED}✖ ${msg}${RESET}`;\n console.error(out);\n writeToFile(`✖ ${msg}`);\n}\n\nexport function info(msg: string): void {\n const out = `${CYAN}ℹ ${msg}${RESET}`;\n console.log(out);\n writeToFile(`ℹ ${msg}`);\n}\n\nexport function dim(msg: string): void {\n const out = `${DIM}${msg}${RESET}`;\n console.log(out);\n writeToFile(msg);\n}\n\nexport function notify(message: string, title = 'copilot-agent'): void {\n try {\n if (process.platform === 'darwin') {\n execSync(\n `osascript -e 'display notification \"${message.replace(/\"/g, '\\\\\"')}\" with title \"${title.replace(/\"/g, '\\\\\"')}\"'`,\n { stdio: 'ignore' },\n );\n } else {\n try {\n execSync('which notify-send', { stdio: 'pipe' });\n execSync(\n `notify-send \"${title}\" \"${message.replace(/\"/g, '\\\\\"')}\"`,\n { stdio: 'ignore' },\n );\n } catch { /* notify-send not available */ }\n }\n } catch { /* notification not available */ }\n}\n","export const RED = '\\x1b[31m';\nexport const GREEN = '\\x1b[32m';\nexport const YELLOW = '\\x1b[33m';\nexport const BLUE = '\\x1b[34m';\nexport const CYAN = '\\x1b[36m';\nexport const DIM = '\\x1b[2m';\nexport const BOLD = '\\x1b[1m';\nexport const RESET = '\\x1b[0m';\n","import type { Command } from 'commander';\nimport {\n listSessions,\n hasTaskComplete,\n getLastEvent,\n getSessionPremium,\n} from '../lib/session.js';\nimport { findCopilotProcesses } from '../lib/process.js';\nimport { log } from '../lib/logger.js';\nimport { BOLD, CYAN, DIM, GREEN, YELLOW, RESET } from '../lib/colors.js';\n\nexport function registerStatusCommand(program: Command): void {\n program\n .command('status')\n .description('Show copilot session status')\n .option('-l, --limit <n>', 'Number of sessions to show', '10')\n .option('-a, --active', 'Show only active (running) processes')\n .option('-i, --incomplete', 'Only show incomplete sessions')\n .action((opts) => {\n if (opts.active) {\n showActive();\n } else {\n showRecent(parseInt(opts.limit, 10), opts.incomplete ?? false);\n }\n });\n}\n\nfunction showActive(): void {\n const procs = findCopilotProcesses();\n if (procs.length === 0) {\n log(`${DIM}No active copilot processes.${RESET}`);\n return;\n }\n\n log(`\\n${BOLD}${'PID'.padEnd(8)} ${'Session'.padEnd(40)} Command${RESET}`);\n log('─'.repeat(108));\n\n for (const p of procs) {\n log(\n `${CYAN}${String(p.pid).padEnd(8)}${RESET} ${(p.sessionId ?? '—').padEnd(40)} ${truncate(p.command, 58)}`,\n );\n }\n log('');\n}\n\nfunction showRecent(limit: number, incompleteOnly: boolean): void {\n let sessions = listSessions(limit);\n if (incompleteOnly) {\n sessions = sessions.filter(s => !s.complete);\n }\n\n if (sessions.length === 0) {\n log(`${DIM}No sessions found.${RESET}`);\n return;\n }\n\n log(\n `\\n${BOLD}${'Status'.padEnd(10)} ${'Premium'.padEnd(10)} ${'Last Event'.padEnd(25)} ${'Summary'.padEnd(40)} ID${RESET}`,\n );\n log('─'.repeat(120));\n\n for (const s of sessions) {\n const status = s.complete\n ? `${GREEN}✔ done${RESET}`\n : `${YELLOW}⏸ stop${RESET}`;\n const premium = String(s.premiumRequests);\n const summary = truncate(s.summary || '—', 38);\n\n log(\n `${status.padEnd(10 + 9)} ${premium.padEnd(10)} ${s.lastEvent.padEnd(25)} ${summary.padEnd(40)} ${DIM}${s.id}${RESET}`,\n );\n }\n log(`\\n${DIM}Total: ${sessions.length} session(s)${RESET}`);\n}\n\nfunction truncate(s: string, max: number): string {\n if (s.length <= max) return s;\n return s.substring(0, max - 1) + '…';\n}\n","import type { Command } from 'commander';\nimport {\n validateSession,\n hasTaskComplete,\n getSessionSummary,\n getLastEvent,\n findLatestIncomplete,\n getSessionCwd,\n} from '../lib/session.js';\nimport {\n findPidForSession,\n waitForExit,\n runCopilotResume,\n assertCopilot,\n} from '../lib/process.js';\nimport { log, ok, warn, fail, info, notify } from '../lib/logger.js';\nimport { CYAN, RESET } from '../lib/colors.js';\n\nexport function registerWatchCommand(program: Command): void {\n program\n .command('watch [session-id]')\n .description('Watch a session and auto-resume when it stops')\n .option('-s, --steps <n>', 'Max autopilot continues per resume', '30')\n .option('-r, --max-resumes <n>', 'Max number of resumes', '10')\n .option('-c, --cooldown <n>', 'Seconds between resumes', '10')\n .option('-m, --message <msg>', 'Message to send on resume')\n .action(async (sid: string | undefined, opts) => {\n try {\n await watchCommand(sid, {\n steps: parseInt(opts.steps, 10),\n maxResumes: parseInt(opts.maxResumes, 10),\n cooldown: parseInt(opts.cooldown, 10),\n message: opts.message,\n });\n } catch (err) {\n fail(`Watch error: ${err instanceof Error ? err.message : err}`);\n process.exit(1);\n }\n });\n}\n\ninterface WatchOptions {\n steps: number;\n maxResumes: number;\n cooldown: number;\n message?: string;\n}\n\nasync function watchCommand(sid: string | undefined, opts: WatchOptions): Promise<void> {\n assertCopilot();\n\n if (!sid) {\n sid = findLatestIncomplete() ?? undefined;\n if (!sid) {\n fail('No incomplete session found.');\n process.exit(1);\n }\n info(`Auto-detected incomplete session: ${CYAN}${sid}${RESET}`);\n }\n\n if (!validateSession(sid)) {\n fail(`Invalid session: ${sid}`);\n process.exit(1);\n }\n\n if (hasTaskComplete(sid)) {\n ok(`Session ${sid} already completed.`);\n return;\n }\n\n let resumes = 0;\n\n while (resumes < opts.maxResumes) {\n const pid = findPidForSession(sid);\n\n if (pid) {\n info(`Watching PID ${pid} for session ${CYAN}${sid.slice(0, 8)}${RESET}…`);\n const exited = await waitForExit(pid);\n\n if (!exited) {\n warn('Timeout waiting for process exit.');\n break;\n }\n }\n\n // Small delay for events to flush\n await sleep(3000);\n\n if (hasTaskComplete(sid)) {\n ok(`Task complete! Summary: ${getSessionSummary(sid) || 'none'}`);\n notify('Task completed!', `Session ${sid.slice(0, 8)}`);\n return;\n }\n\n // Interrupted — resume\n resumes++;\n log(`Session interrupted (${getLastEvent(sid)}). Resume ${resumes}/${opts.maxResumes}…`);\n\n if (opts.cooldown > 0 && resumes > 1) {\n info(`Cooldown ${opts.cooldown}s...`);\n await sleep(opts.cooldown * 1000);\n }\n\n const cwd = getSessionCwd(sid) || undefined;\n const result = await runCopilotResume(\n sid,\n opts.steps,\n opts.message ?? 'Continue remaining work. Pick up where you left off and complete the task.',\n cwd,\n );\n\n if (result.sessionId && result.sessionId !== sid) {\n info(`New session created: ${CYAN}${result.sessionId}${RESET}`);\n sid = result.sessionId;\n }\n }\n\n warn(`Max resumes (${opts.maxResumes}) reached.`);\n notify('Max resumes reached', `Session ${sid.slice(0, 8)}`);\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise(r => setTimeout(r, ms));\n}\n","import { existsSync, readFileSync, readdirSync } from 'node:fs';\nimport { join, basename, resolve } from 'node:path';\nimport { execSync } from 'node:child_process';\n\nexport type ProjectType =\n | 'kmp' | 'kotlin' | 'java'\n | 'node' | 'typescript' | 'react' | 'next'\n | 'python' | 'rust' | 'swift' | 'go' | 'flutter'\n | 'unknown';\n\nexport function detectProjectType(dir: string): ProjectType {\n const exists = (f: string) => existsSync(join(dir, f));\n\n if (exists('build.gradle.kts') || exists('build.gradle')) {\n if (exists('composeApp') || exists('gradle.properties')) {\n try {\n const gradle = readFileSync(join(dir, 'build.gradle.kts'), 'utf-8');\n if (gradle.includes('multiplatform') || gradle.includes('KotlinMultiplatform')) return 'kmp';\n } catch { /* ignore */ }\n }\n if (exists('pom.xml')) return 'java';\n return 'kotlin';\n }\n if (exists('pubspec.yaml')) return 'flutter';\n if (exists('Package.swift')) return 'swift';\n try {\n const entries = readdirSync(dir);\n if (entries.some(e => e.endsWith('.xcodeproj'))) return 'swift';\n } catch { /* ignore */ }\n if (exists('Cargo.toml')) return 'rust';\n if (exists('go.mod')) return 'go';\n if (exists('pyproject.toml') || exists('setup.py') || exists('requirements.txt')) return 'python';\n if (exists('package.json')) {\n try {\n const pkg = JSON.parse(readFileSync(join(dir, 'package.json'), 'utf-8'));\n const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };\n if (allDeps['next']) return 'next';\n if (allDeps['react']) return 'react';\n if (allDeps['typescript'] || exists('tsconfig.json')) return 'typescript';\n } catch { /* ignore */ }\n return 'node';\n }\n if (exists('pom.xml')) return 'java';\n return 'unknown';\n}\n\nexport function detectProjectName(dir: string): string {\n try {\n const pkg = JSON.parse(readFileSync(join(dir, 'package.json'), 'utf-8'));\n if (pkg.name) return pkg.name;\n } catch { /* ignore */ }\n return basename(resolve(dir));\n}\n\nexport function detectMainBranch(dir: string): string {\n try {\n const ref = execSync('git symbolic-ref refs/remotes/origin/HEAD', {\n cwd: dir,\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n }).trim();\n return ref.split('/').pop() ?? 'main';\n } catch { /* ignore */ }\n\n try {\n const branch = execSync('git branch --show-current', {\n cwd: dir,\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n }).trim();\n if (branch) return branch;\n } catch { /* ignore */ }\n\n return 'main';\n}\n","import type { ProjectType } from \"./detect.js\";\n\ninterface TaskPrompt {\n title: string;\n prompt: string;\n priority: number;\n}\n\nconst COMMON_TASKS: TaskPrompt[] = [\n {\n title: \"Fix TODOs\",\n prompt:\n \"Scan for TODO, FIXME, HACK comments. Fix the most impactful ones. Run tests to verify.\",\n priority: 1,\n },\n {\n title: \"Update dependencies\",\n prompt:\n \"Check for outdated dependencies. Update patch/minor versions that are safe. Run tests after updating.\",\n priority: 2,\n },\n {\n title: \"Improve test coverage\",\n prompt:\n \"Find untested public functions. Write tests for the most critical ones. Target 80%+ coverage.\",\n priority: 3,\n },\n {\n title: \"Fix lint warnings\",\n prompt:\n \"Run the project linter. Fix all warnings without changing behavior. Run tests.\",\n priority: 4,\n },\n {\n title: \"Improve documentation\",\n prompt:\n \"Review README and code docs. Add missing JSDoc/KDoc for public APIs. Update outdated sections.\",\n priority: 5,\n },\n {\n title: \"Security audit\",\n prompt:\n \"Check for common security issues: hardcoded secrets, SQL injection, XSS, insecure defaults. Fix any found.\",\n priority: 6,\n },\n];\n\nconst TYPE_TASKS: Partial<Record<ProjectType, TaskPrompt[]>> = {\n kmp: [\n {\n title: \"KMP: Optimize Compose\",\n prompt:\n \"Review Compose UI code for recomposition issues. Add @Stable/@Immutable where needed. Check remember usage.\",\n priority: 2,\n },\n {\n title: \"KMP: Check expect/actual\",\n prompt:\n \"Review expect/actual declarations. Ensure all platforms have proper implementations. Check for missing iOS/Desktop actuals.\",\n priority: 3,\n },\n {\n title: \"KMP: Room migrations\",\n prompt:\n \"Check Room database schema. Ensure migrations are defined for schema changes. Add missing migration tests.\",\n priority: 4,\n },\n ],\n typescript: [\n {\n title: \"TS: Strict type safety\",\n prompt:\n \"Find `any` types and loose assertions. Replace with proper types. Enable stricter tsconfig options if safe.\",\n priority: 2,\n },\n ],\n react: [\n {\n title: \"React: Performance\",\n prompt:\n \"Find unnecessary re-renders. Add React.memo, useMemo, useCallback where beneficial. Check bundle size.\",\n priority: 2,\n },\n ],\n python: [\n {\n title: \"Python: Type hints\",\n prompt:\n \"Add type hints to public functions. Run mypy to check type safety. Fix any type errors.\",\n priority: 2,\n },\n ],\n node: [\n {\n title: \"Node: Error handling\",\n prompt:\n \"Review async error handling. Add try/catch for unhandled promises. Check for missing error middleware.\",\n priority: 2,\n },\n ],\n};\n\nexport function getTasksForProject(type: ProjectType): TaskPrompt[] {\n const specific = TYPE_TASKS[type] ?? [];\n return [...specific, ...COMMON_TASKS].sort(\n (a, b) => a.priority - b.priority,\n );\n}\n","import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\n\nconst LOCK_BASE = join(homedir(), '.copilot', 'locks');\n\nfunction lockDir(name: string): string {\n return join(LOCK_BASE, `${name}.lock`);\n}\n\nfunction isPidAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n\nexport function acquireLock(name: string, timeoutMs = 30_000): boolean {\n mkdirSync(LOCK_BASE, { recursive: true });\n const dir = lockDir(name);\n const deadline = Date.now() + timeoutMs;\n\n while (Date.now() < deadline) {\n try {\n mkdirSync(dir);\n // Lock acquired — write metadata\n writeFileSync(join(dir, 'pid'), String(process.pid));\n writeFileSync(join(dir, 'acquired'), new Date().toISOString());\n return true;\n } catch {\n // Lock dir exists — check if holder is still alive\n try {\n const holderPid = parseInt(readFileSync(join(dir, 'pid'), 'utf-8').trim(), 10);\n if (!isPidAlive(holderPid)) {\n // Stale lock — break it\n rmSync(dir, { recursive: true, force: true });\n continue;\n }\n } catch {\n // Can't read pid file — try breaking\n rmSync(dir, { recursive: true, force: true });\n continue;\n }\n // Holder is alive — wait and retry\n const waitMs = Math.min(500, deadline - Date.now());\n if (waitMs > 0) {\n const start = Date.now();\n while (Date.now() - start < waitMs) { /* spin wait */ }\n }\n }\n }\n return false;\n}\n\nexport function releaseLock(name: string): void {\n const dir = lockDir(name);\n try {\n rmSync(dir, { recursive: true, force: true });\n } catch { /* already released */ }\n}\n\nexport async function withLock<T>(name: string, fn: () => T | Promise<T>): Promise<T> {\n if (!acquireLock(name)) {\n throw new Error(`Failed to acquire lock: ${name}`);\n }\n try {\n return await fn();\n } finally {\n releaseLock(name);\n }\n}\n","import { existsSync, rmSync } from 'node:fs';\nimport { join, resolve } from 'node:path';\nimport { execSync } from 'node:child_process';\n\nfunction gitExec(dir: string, cmd: string): string | null {\n try {\n return execSync(cmd, {\n cwd: dir,\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n }).trim();\n } catch {\n return null;\n }\n}\n\nexport function isGitRepo(dir: string): boolean {\n return existsSync(join(dir, '.git'));\n}\n\nexport function gitCurrentBranch(dir: string): string | null {\n return gitExec(dir, 'git branch --show-current');\n}\n\nexport function gitStash(dir: string): boolean {\n return gitExec(dir, 'git stash -q') !== null;\n}\n\nexport function gitStashPop(dir: string): boolean {\n return gitExec(dir, 'git stash pop -q') !== null;\n}\n\nexport function gitCheckout(dir: string, branch: string): boolean {\n return gitExec(dir, `git checkout ${branch} -q`) !== null;\n}\n\nexport function gitCreateBranch(dir: string, branch: string): boolean {\n return gitExec(dir, `git checkout -b ${branch}`) !== null;\n}\n\nexport function gitCountCommits(dir: string, from: string, to: string): number {\n const result = gitExec(dir, `git log ${from}..${to} --oneline`);\n if (!result) return 0;\n return result.split('\\n').filter(l => l.trim()).length;\n}\n\nexport function gitStatus(dir: string): string {\n return gitExec(dir, 'git status --porcelain') ?? '';\n}\n\nexport function gitRoot(dir: string): string | null {\n return gitExec(dir, 'git rev-parse --show-toplevel');\n}\n\n// ── Worktree support ──\n\nexport function listWorktrees(dir: string): { path: string; branch: string; bare: boolean }[] {\n const raw = gitExec(dir, 'git worktree list --porcelain');\n if (!raw) return [];\n const trees: { path: string; branch: string; bare: boolean }[] = [];\n let current: { path: string; branch: string; bare: boolean } = { path: '', branch: '', bare: false };\n for (const line of raw.split('\\n')) {\n if (line.startsWith('worktree ')) {\n if (current.path) trees.push(current);\n current = { path: line.slice(9), branch: '', bare: false };\n } else if (line.startsWith('branch ')) {\n current.branch = line.slice(7).replace('refs/heads/', '');\n } else if (line === 'bare') {\n current.bare = true;\n }\n }\n if (current.path) trees.push(current);\n return trees;\n}\n\n/**\n * Create a git worktree for parallel copilot work.\n * Returns the worktree path or null on failure.\n */\nexport function createWorktree(repoDir: string, branch: string): string | null {\n const safeBranch = branch.replace(/[^a-zA-Z0-9._/-]/g, '-');\n const worktreePath = resolve(repoDir, '..', `${resolve(repoDir).split('/').pop()}-wt-${safeBranch}`);\n\n if (existsSync(worktreePath)) {\n return worktreePath; // already exists\n }\n\n // Create branch if it doesn't exist, then add worktree\n const branchExists = gitExec(repoDir, `git rev-parse --verify ${safeBranch}`) !== null;\n const cmd = branchExists\n ? `git worktree add \"${worktreePath}\" ${safeBranch}`\n : `git worktree add -b ${safeBranch} \"${worktreePath}\"`;\n\n if (gitExec(repoDir, cmd) !== null) {\n return worktreePath;\n }\n return null;\n}\n\n/**\n * Remove a worktree (prune).\n */\nexport function removeWorktree(repoDir: string, worktreePath: string): boolean {\n const result = gitExec(repoDir, `git worktree remove \"${worktreePath}\" --force`);\n return result !== null;\n}\n\n/**\n * Clean up all copilot-agent worktrees.\n */\nexport function cleanupWorktrees(repoDir: string): number {\n const trees = listWorktrees(repoDir);\n let cleaned = 0;\n for (const t of trees) {\n if (t.path.includes('-wt-')) {\n if (removeWorktree(repoDir, t.path)) cleaned++;\n }\n }\n gitExec(repoDir, 'git worktree prune');\n return cleaned;\n}\n","import type { Command } from 'commander';\nimport { detectProjectType, detectProjectName, detectMainBranch } from '../lib/detect.js';\nimport { getTasksForProject } from '../lib/tasks.js';\nimport { runCopilotTask, assertCopilot } from '../lib/process.js';\nimport { withLock } from '../lib/lock.js';\nimport { isGitRepo, gitCurrentBranch, gitStatus, gitStash, gitCheckout, gitCreateBranch, gitCountCommits, createWorktree, removeWorktree } from '../lib/git.js';\nimport { log, ok, warn, fail, info, notify } from '../lib/logger.js';\nimport { BOLD, CYAN, DIM, GREEN, RESET, YELLOW } from '../lib/colors.js';\n\nexport function registerRunCommand(program: Command): void {\n program\n .command('run [dir]')\n .description('Discover and fix issues in a project')\n .option('-s, --steps <n>', 'Max autopilot continues per task', '30')\n .option('-t, --max-tasks <n>', 'Max number of tasks to run', '5')\n .option('-p, --max-premium <n>', 'Max total premium requests', '50')\n .option('--dry-run', 'Show tasks without executing')\n .option('--worktree', 'Use git worktree for parallel execution (default: wait for idle)')\n .action(async (dir: string | undefined, opts) => {\n try {\n await runCommand(dir ?? process.cwd(), {\n steps: parseInt(opts.steps, 10),\n maxTasks: parseInt(opts.maxTasks, 10),\n maxPremium: parseInt(opts.maxPremium, 10),\n dryRun: opts.dryRun ?? false,\n useWorktree: opts.worktree ?? false,\n });\n } catch (err) {\n fail(`Run error: ${err instanceof Error ? err.message : err}`);\n process.exit(1);\n }\n });\n}\n\ninterface RunOptions {\n steps: number;\n maxTasks: number;\n maxPremium: number;\n dryRun: boolean;\n useWorktree: boolean;\n}\n\nasync function runCommand(dir: string, opts: RunOptions): Promise<void> {\n assertCopilot();\n\n const projectType = detectProjectType(dir);\n const name = detectProjectName(dir);\n const mainBranch = isGitRepo(dir) ? detectMainBranch(dir) : null;\n\n info(`Project: ${CYAN}${name}${RESET} (${projectType})`);\n if (mainBranch) info(`Main branch: ${mainBranch}`);\n\n const tasks = getTasksForProject(projectType).slice(0, opts.maxTasks);\n\n if (tasks.length === 0) {\n warn('No tasks found for this project type.');\n return;\n }\n\n log(`Found ${tasks.length} tasks:`);\n for (const t of tasks) {\n log(` ${DIM}•${RESET} ${t.title}`);\n }\n\n if (opts.dryRun) {\n log(`${DIM}(dry-run — not executing)${RESET}`);\n return;\n }\n\n const originalBranch = isGitRepo(dir) ? gitCurrentBranch(dir) : null;\n let completed = 0;\n let premiumTotal = 0;\n\n for (const task of tasks) {\n if (premiumTotal >= opts.maxPremium) {\n warn(`Premium request limit reached (${premiumTotal}/${opts.maxPremium}).`);\n break;\n }\n\n log(`\\n${'═'.repeat(60)}`);\n log(`${BOLD}${CYAN}Task: ${task.title}${RESET}`);\n log(`${'═'.repeat(60)}`);\n\n const timestamp = Date.now().toString(36);\n const random = Math.random().toString(36).substring(2, 6);\n const branchName = `agent/fix-${completed + 1}-${timestamp}-${random}`;\n\n if (mainBranch && isGitRepo(dir)) {\n if (gitStatus(dir)) gitStash(dir);\n gitCheckout(dir, mainBranch);\n if (!gitCreateBranch(dir, branchName)) {\n warn(`Could not create branch ${branchName}, continuing on current.`);\n }\n }\n\n info(`Running: ${task.title}…`);\n\n let taskDir = dir;\n let worktreeCreated = false;\n\n if (opts.useWorktree && isGitRepo(dir)) {\n try {\n taskDir = createWorktree(dir, branchName, mainBranch ?? undefined);\n worktreeCreated = true;\n info(`Created worktree: ${taskDir}`);\n } catch (err) {\n warn(`Worktree creation failed, falling back to main dir: ${err}`);\n taskDir = dir;\n }\n }\n\n const result = await withLock('copilot-run', () =>\n runCopilotTask(task.prompt, opts.steps, taskDir, opts.useWorktree),\n );\n\n const commitRef = worktreeCreated ? taskDir : dir;\n const commits = mainBranch ? gitCountCommits(commitRef, mainBranch, 'HEAD') : 0;\n premiumTotal += result.premium;\n completed++;\n ok(`${task.title} — ${commits} commit(s), ${result.premium} premium`);\n\n if (worktreeCreated) {\n try {\n removeWorktree(dir, taskDir);\n } catch (err) {\n warn(`Worktree cleanup failed: ${err}`);\n }\n }\n\n if (!worktreeCreated && originalBranch && isGitRepo(dir)) {\n gitCheckout(dir, mainBranch ?? originalBranch);\n }\n }\n\n log(`\\n${BOLD}═══ Run Summary ═══${RESET}`);\n log(`Completed ${completed}/${tasks.length} tasks. Total premium: ${premiumTotal}`);\n notify(`Completed ${completed} tasks`, name);\n}\n","import type { Command } from 'commander';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport { detectProjectType, detectProjectName, detectMainBranch } from '../lib/detect.js';\nimport { getTasksForProject } from '../lib/tasks.js';\nimport { runCopilotTask, assertCopilot, findPidForSession, findCopilotProcesses, waitForExit, waitForCopilotInDir, runCopilotResume } from '../lib/process.js';\nimport { withLock } from '../lib/lock.js';\nimport { isGitRepo, gitCurrentBranch, gitStash, gitCheckout, gitCreateBranch, gitCountCommits, createWorktree, removeWorktree } from '../lib/git.js';\nimport { findLatestIncomplete, validateSession, hasTaskComplete, getSessionCwd } from '../lib/session.js';\nimport { log, ok, warn, fail, info, setLogFile, notify } from '../lib/logger.js';\nimport { BOLD, CYAN, DIM, RESET } from '../lib/colors.js';\n\nexport function registerOvernightCommand(program: Command): void {\n program\n .command('overnight [dir]')\n .description('Run tasks continuously until a deadline')\n .option('-u, --until <HH>', 'Stop at this hour (24h format)', '07')\n .option('-s, --steps <n>', 'Max autopilot continues per task', '50')\n .option('-c, --cooldown <n>', 'Seconds between tasks', '15')\n .option('-p, --max-premium <n>', 'Max premium requests budget', '300')\n .option('--dry-run', 'Show plan without executing')\n .option('--worktree', 'Use git worktree for parallel execution (default: wait for idle)')\n .action(async (dir: string | undefined, opts) => {\n try {\n await overnightCommand(dir ?? process.cwd(), {\n until: parseInt(opts.until, 10),\n steps: parseInt(opts.steps, 10),\n cooldown: parseInt(opts.cooldown, 10),\n maxPremium: parseInt(opts.maxPremium, 10),\n dryRun: opts.dryRun ?? false,\n useWorktree: opts.worktree ?? false,\n });\n } catch (err) {\n fail(`Overnight error: ${err instanceof Error ? err.message : err}`);\n process.exit(1);\n }\n });\n}\n\ninterface OvernightOptions {\n until: number;\n steps: number;\n cooldown: number;\n maxPremium: number;\n dryRun: boolean;\n useWorktree: boolean;\n}\n\nfunction isPastDeadline(untilHour: number): boolean {\n const hour = new Date().getHours();\n return hour >= untilHour && hour < 20;\n}\n\nasync function overnightCommand(dir: string, opts: OvernightOptions): Promise<void> {\n assertCopilot();\n\n const ts = new Date().toISOString().replace(/[:.]/g, '').slice(0, 15);\n const logPath = join(homedir(), '.copilot', 'auto-resume-logs', `overnight-${ts}.log`);\n setLogFile(logPath);\n\n const name = detectProjectName(dir);\n const projectType = detectProjectType(dir);\n const mainBranch = isGitRepo(dir) ? detectMainBranch(dir) : null;\n\n info(`Overnight runner for ${CYAN}${name}${RESET} (${projectType})`);\n info(`Deadline: ${String(opts.until).padStart(2, '0')}:00`);\n info(`Max premium: ${opts.maxPremium}, Steps: ${opts.steps}`);\n info(`Log: ${logPath}`);\n\n const tasks = getTasksForProject(projectType);\n\n if (opts.dryRun) {\n log(`\\nWould run ${tasks.length} tasks:`);\n for (const t of tasks) log(` ${DIM}•${RESET} ${t.title}`);\n return;\n }\n\n // Phase 1: Resume existing incomplete session\n const existingSession = findLatestIncomplete();\n if (existingSession && validateSession(existingSession)) {\n info(`Found incomplete session: ${existingSession}`);\n const pid = findPidForSession(existingSession);\n if (pid) {\n info(`Waiting for running copilot (PID ${pid})...`);\n await waitForExit(pid);\n }\n\n if (!hasTaskComplete(existingSession) && !isPastDeadline(opts.until)) {\n info('Resuming incomplete session...');\n const cwd = getSessionCwd(existingSession) || dir;\n await runCopilotResume(\n existingSession,\n opts.steps,\n 'Continue remaining work. Complete the task.',\n cwd,\n );\n }\n }\n\n // Phase 2: Loop tasks until deadline\n const originalBranch = isGitRepo(dir) ? gitCurrentBranch(dir) : null;\n let taskIdx = 0;\n let totalPremium = 0;\n let totalCommits = 0;\n\n while (!isPastDeadline(opts.until) && taskIdx < tasks.length) {\n if (totalPremium >= opts.maxPremium) {\n warn(`Premium budget exhausted: ${totalPremium}/${opts.maxPremium}`);\n break;\n }\n\n const task = tasks[taskIdx % tasks.length];\n taskIdx++;\n\n log(`\\n${'═'.repeat(60)}`);\n log(`${BOLD}${CYAN}[${new Date().toLocaleTimeString()}] Task ${taskIdx}: ${task.title}${RESET}`);\n log(`${DIM}Premium: ${totalPremium}/${opts.maxPremium}${RESET}`);\n log(`${'═'.repeat(60)}`);\n\n const timestamp = Date.now().toString(36);\n const random = Math.random().toString(36).substring(2, 6);\n const branchName = `agent/overnight-${taskIdx}-${timestamp}-${random}`;\n\n if (mainBranch && isGitRepo(dir)) {\n gitStash(dir);\n gitCheckout(dir, mainBranch);\n gitCreateBranch(dir, branchName);\n }\n\n info(`Running: ${task.title}…`);\n\n let taskDir = dir;\n let worktreeCreated = false;\n\n if (opts.useWorktree && isGitRepo(dir)) {\n try {\n taskDir = createWorktree(dir, branchName, mainBranch ?? undefined);\n worktreeCreated = true;\n info(`Created worktree: ${taskDir}`);\n } catch (err) {\n warn(`Worktree creation failed, falling back to main dir: ${err}`);\n taskDir = dir;\n }\n }\n\n try {\n const result = await withLock('copilot-overnight', () =>\n runCopilotTask(task.prompt, opts.steps, taskDir, opts.useWorktree),\n );\n\n const commitRef = worktreeCreated ? taskDir : dir;\n const commits = mainBranch ? gitCountCommits(commitRef, mainBranch, 'HEAD') : 0;\n totalPremium += result.premium;\n totalCommits += commits;\n\n if (commits > 0) {\n ok(`${commits} commit(s) on ${branchName}`);\n } else {\n log(`${DIM}No commits on ${branchName}${RESET}`);\n }\n } catch (err) {\n fail(`Task failed: ${err}`);\n }\n\n // Cleanup worktree if we created one\n if (worktreeCreated) {\n try {\n removeWorktree(dir, taskDir);\n info(`Removed worktree: ${taskDir}`);\n } catch (err) {\n warn(`Worktree cleanup failed: ${err}`);\n }\n }\n\n if (!worktreeCreated && mainBranch && isGitRepo(dir)) {\n gitCheckout(dir, mainBranch);\n }\n\n if (!isPastDeadline(opts.until)) {\n info(`Cooldown ${opts.cooldown}s…`);\n await sleep(opts.cooldown * 1000);\n }\n }\n\n if (originalBranch && isGitRepo(dir)) {\n gitCheckout(dir, originalBranch);\n }\n\n const summary = `Overnight done — ${taskIdx} tasks, ${totalCommits} commits, ${totalPremium} premium.`;\n ok(summary);\n notify(summary, name);\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise(r => setTimeout(r, ms));\n}\n","import type { Command } from 'commander';\nimport { existsSync, copyFileSync, mkdirSync } from 'node:fs';\nimport { join, resolve } from 'node:path';\nimport { homedir } from 'node:os';\nimport { detectProjectType, detectProjectName } from '../lib/detect.js';\nimport { runCopilotTask, assertCopilot } from '../lib/process.js';\nimport { withLock } from '../lib/lock.js';\nimport { log, ok, warn, fail, info, notify } from '../lib/logger.js';\nimport { CYAN, RESET } from '../lib/colors.js';\n\nexport function registerResearchCommand(program: Command): void {\n program\n .command('research [project]')\n .description('Research improvements or a specific topic')\n .option('-s, --steps <n>', 'Max autopilot continues', '50')\n .action(async (project: string | undefined, opts) => {\n try {\n await researchCommand(project ?? process.cwd(), {\n steps: parseInt(opts.steps, 10),\n });\n } catch (err) {\n fail(`Research error: ${err instanceof Error ? err.message : err}`);\n process.exit(1);\n }\n });\n}\n\ninterface ResearchOptions {\n steps: number;\n}\n\nfunction buildResearchPrompt(projectType: string, projectName: string): string {\n return `You are a senior software architect. Analyze this ${projectType} project \"${projectName}\" thoroughly.\n\nResearch and produce a file called RESEARCH-PROPOSALS.md with:\n\n1. **Architecture Assessment** — Current architecture, patterns used, strengths and weaknesses\n2. **Code Quality Report** — Common issues, anti-patterns, technical debt areas\n3. **Security Audit** — Potential vulnerabilities, dependency risks, configuration issues\n4. **Performance Analysis** — Bottlenecks, optimization opportunities, resource usage\n5. **Testing Gap Analysis** — Untested areas, test quality, coverage recommendations\n6. **Improvement Proposals** — Prioritized list of actionable improvements with effort estimates\n\nFor each proposal, include:\n- Priority (P0/P1/P2)\n- Estimated effort (hours)\n- Impact description\n- Suggested implementation approach\n\nWrite RESEARCH-PROPOSALS.md in the project root.`;\n}\n\nasync function researchCommand(dir: string, opts: ResearchOptions): Promise<void> {\n assertCopilot();\n\n const projectDir = resolve(dir);\n const projectType = detectProjectType(projectDir);\n const projectName = detectProjectName(projectDir);\n\n info(`Researching: ${CYAN}${projectName}${RESET} (${projectType})`);\n\n const prompt = buildResearchPrompt(projectType, projectName);\n\n const result = await withLock('copilot-research', () =>\n runCopilotTask(prompt, opts.steps, projectDir),\n );\n\n log(`Copilot exited with code ${result.exitCode}`);\n\n // Check for output file\n const proposalsFile = join(projectDir, 'RESEARCH-PROPOSALS.md');\n if (existsSync(proposalsFile)) {\n ok('RESEARCH-PROPOSALS.md generated.');\n\n // Backup to ~/.copilot/research-reports/\n const backupDir = join(homedir(), '.copilot', 'research-reports');\n mkdirSync(backupDir, { recursive: true });\n const timestamp = new Date().toISOString().replace(/[:.]/g, '-');\n const backupFile = join(backupDir, `${projectName}-${timestamp}.md`);\n copyFileSync(proposalsFile, backupFile);\n ok(`Backup saved: ${backupFile}`);\n } else {\n warn('RESEARCH-PROPOSALS.md was not generated. Check copilot output.');\n }\n\n notify('Research complete', projectName);\n}\n","import type { Command } from 'commander';\nimport { resolve } from 'node:path';\nimport {\n listSessions,\n getSessionReport,\n type SessionReport,\n} from '../lib/session.js';\nimport { log, warn, fail } from '../lib/logger.js';\nimport { BOLD, CYAN, DIM, GREEN, YELLOW, RED, RESET } from '../lib/colors.js';\n\nexport function registerReportCommand(program: Command): void {\n program\n .command('report [session-id]')\n .description('Show what copilot did — timeline, tools, commits, files changed')\n .option('-l, --limit <n>', 'Number of recent sessions to report (when no ID given)', '1')\n .option('--project <dir>', 'Filter sessions by project directory')\n .option('--json', 'Output raw JSON')\n .action((sessionId: string | undefined, opts) => {\n try {\n if (sessionId) {\n reportSingle(sessionId, opts.json ?? false);\n } else {\n reportRecent(parseInt(opts.limit, 10), opts.project, opts.json ?? false);\n }\n } catch (err) {\n fail(`Report error: ${err instanceof Error ? err.message : err}`);\n process.exit(1);\n }\n });\n}\n\nfunction reportRecent(limit: number, projectDir?: string, json = false): void {\n let sessions = listSessions(limit * 3); // fetch extra to filter\n if (projectDir) {\n const target = resolve(projectDir);\n sessions = sessions.filter(s => s.cwd && resolve(s.cwd) === target);\n }\n sessions = sessions.slice(0, limit);\n\n if (sessions.length === 0) {\n warn('No sessions found.');\n return;\n }\n\n for (const s of sessions) {\n reportSingle(s.id, json);\n }\n}\n\nfunction reportSingle(sid: string, json = false): void {\n const report = getSessionReport(sid);\n if (!report) {\n warn(`Session ${sid} not found or invalid.`);\n return;\n }\n\n if (json) {\n log(JSON.stringify(report, null, 2));\n return;\n }\n\n renderReport(report);\n}\n\nfunction formatDuration(ms: number): string {\n if (ms < 60_000) return `${Math.round(ms / 1000)}s`;\n if (ms < 3_600_000) return `${Math.round(ms / 60_000)}m`;\n const h = Math.floor(ms / 3_600_000);\n const m = Math.round((ms % 3_600_000) / 60_000);\n return `${h}h ${m}m`;\n}\n\nfunction formatTime(iso: string): string {\n if (!iso) return '—';\n const d = new Date(iso);\n return d.toLocaleString('en-GB', {\n month: 'short',\n day: 'numeric',\n hour: '2-digit',\n minute: '2-digit',\n });\n}\n\nfunction bar(value: number, max: number, width = 20): string {\n const filled = Math.round((value / Math.max(max, 1)) * width);\n return '█'.repeat(filled) + '░'.repeat(width - filled);\n}\n\nfunction renderReport(r: SessionReport): void {\n const status = r.complete\n ? `${GREEN}✔ Completed${RESET}`\n : `${YELLOW}⏸ Interrupted${RESET}`;\n\n const projectName = r.cwd.split('/').pop() ?? r.cwd;\n\n log('');\n log(`${BOLD}╔${'═'.repeat(62)}╗${RESET}`);\n log(`${BOLD}║${RESET} 📋 Session Report: ${CYAN}${r.id.slice(0, 8)}…${RESET}${' '.repeat(62 - 28 - r.id.slice(0, 8).length)}${BOLD}║${RESET}`);\n log(`${BOLD}╚${'═'.repeat(62)}╝${RESET}`);\n\n // Overview\n log('');\n log(`${BOLD} Overview${RESET}`);\n log(` ${'─'.repeat(58)}`);\n log(` Project: ${CYAN}${projectName}${RESET} ${DIM}${r.cwd}${RESET}`);\n log(` Status: ${status}`);\n log(` Duration: ${BOLD}${formatDuration(r.durationMs)}${RESET} ${DIM}(${formatTime(r.startTime)} → ${formatTime(r.endTime)})${RESET}`);\n log(` Summary: ${r.summary || DIM + '(none)' + RESET}`);\n\n // Stats\n log('');\n log(`${BOLD} Activity${RESET}`);\n log(` ${'─'.repeat(58)}`);\n log(` User messages: ${BOLD}${r.userMessages}${RESET}`);\n log(` Assistant turns: ${BOLD}${r.assistantTurns}${RESET}`);\n log(` Output tokens: ${BOLD}${r.outputTokens.toLocaleString()}${RESET}`);\n log(` Premium requests: ${BOLD}${r.premiumRequests}${RESET}`);\n log(` Tool calls: ${BOLD}${Object.values(r.toolUsage).reduce((a, b) => a + b, 0)}${RESET}`);\n\n // Tools breakdown\n const toolEntries = Object.entries(r.toolUsage).sort((a, b) => b[1] - a[1]);\n if (toolEntries.length > 0) {\n const maxCount = toolEntries[0][1];\n log('');\n log(`${BOLD} Tools Used${RESET}`);\n log(` ${'─'.repeat(58)}`);\n for (const [tool, count] of toolEntries.slice(0, 10)) {\n const barStr = bar(count, maxCount, 15);\n log(` ${DIM}${barStr}${RESET} ${String(count).padStart(5)} ${tool}`);\n }\n if (toolEntries.length > 10) {\n log(` ${DIM} … and ${toolEntries.length - 10} more tools${RESET}`);\n }\n }\n\n // Git commits\n if (r.gitCommits.length > 0) {\n log('');\n log(`${BOLD} Git Commits (${r.gitCommits.length})${RESET}`);\n log(` ${'─'.repeat(58)}`);\n for (const msg of r.gitCommits) {\n log(` ${GREEN}●${RESET} ${msg.slice(0, 70)}${msg.length > 70 ? '…' : ''}`);\n }\n }\n\n // Files created\n if (r.filesCreated.length > 0) {\n log('');\n log(`${BOLD} Files Created (${r.filesCreated.length})${RESET}`);\n log(` ${'─'.repeat(58)}`);\n for (const f of r.filesCreated.slice(0, 15)) {\n const short = f.includes(projectName) ? f.split(projectName + '/')[1] ?? f : f;\n log(` ${GREEN}+${RESET} ${short}`);\n }\n if (r.filesCreated.length > 15) {\n log(` ${DIM} … and ${r.filesCreated.length - 15} more${RESET}`);\n }\n }\n\n // Files edited\n if (r.filesEdited.length > 0) {\n log('');\n log(`${BOLD} Files Edited (${r.filesEdited.length})${RESET}`);\n log(` ${'─'.repeat(58)}`);\n for (const f of r.filesEdited.slice(0, 15)) {\n const short = f.includes(projectName) ? f.split(projectName + '/')[1] ?? f : f;\n log(` ${YELLOW}~${RESET} ${short}`);\n }\n if (r.filesEdited.length > 15) {\n log(` ${DIM} … and ${r.filesEdited.length - 15} more${RESET}`);\n }\n }\n\n // Task completions\n if (r.taskCompletions.length > 0) {\n log('');\n log(`${BOLD} Tasks Completed (${r.taskCompletions.length})${RESET}`);\n log(` ${'─'.repeat(58)}`);\n for (const t of r.taskCompletions) {\n const lines = t.split('\\n');\n const first = lines[0].slice(0, 70);\n log(` ${GREEN}✔${RESET} ${first}${first.length < lines[0].length ? '…' : ''}`);\n }\n }\n\n // Errors\n if (r.errors.length > 0) {\n log('');\n log(`${BOLD} Errors (${r.errors.length})${RESET}`);\n log(` ${'─'.repeat(58)}`);\n for (const e of r.errors.slice(0, 5)) {\n log(` ${RED}✖${RESET} ${e.slice(0, 70)}`);\n }\n if (r.errors.length > 5) {\n log(` ${DIM} … and ${r.errors.length - 5} more${RESET}`);\n }\n }\n\n log('');\n}\n","import type { Command } from 'commander';\nimport { listSessions, getSessionReport, type SessionReport, type Session } from '../lib/session.js';\nimport { findCopilotProcesses, type CopilotProcess } from '../lib/process.js';\nimport { BOLD, CYAN, DIM, GREEN, YELLOW, RED, RESET } from '../lib/colors.js';\n\nconst ESC = '\\x1b';\nconst CLEAR = `${ESC}[2J${ESC}[H`;\nconst HIDE_CURSOR = `${ESC}[?25l`;\nconst SHOW_CURSOR = `${ESC}[?25h`;\nconst SAVE_CURSOR = `${ESC}7`;\nconst RESTORE_CURSOR = `${ESC}8`;\n\nexport function registerDashboardCommand(program: Command): void {\n program\n .command('dashboard')\n .alias('tui')\n .description('Real-time terminal dashboard for copilot sessions')\n .option('-r, --refresh <n>', 'Refresh interval in seconds', '5')\n .option('-l, --limit <n>', 'Number of sessions to show', '8')\n .action((opts) => {\n runDashboard(parseInt(opts.refresh, 10), parseInt(opts.limit, 10));\n });\n}\n\nfunction runDashboard(refreshSec: number, limit: number): void {\n process.stdout.write(HIDE_CURSOR);\n\n const cleanup = () => {\n process.stdout.write(SHOW_CURSOR);\n process.stdout.write(CLEAR);\n process.exit(0);\n };\n\n process.on('SIGINT', cleanup);\n process.on('SIGTERM', cleanup);\n\n const render = () => {\n try {\n const output = buildScreen(limit);\n process.stdout.write(CLEAR + output);\n } catch {\n // ignore render errors\n }\n };\n\n render();\n const timer = setInterval(render, refreshSec * 1000);\n\n // Handle terminal resize\n process.stdout.on('resize', render);\n\n // Keep alive\n process.stdin.setRawMode?.(true);\n process.stdin.resume();\n process.stdin.on('data', (data) => {\n const key = data.toString();\n if (key === 'q' || key === '\\x03') {\n clearInterval(timer);\n cleanup();\n }\n if (key === 'r') render();\n });\n}\n\nfunction buildScreen(limit: number): string {\n const cols = process.stdout.columns || 80;\n const rows = process.stdout.rows || 40;\n const lines: string[] = [];\n\n const now = new Date();\n const timeStr = now.toLocaleTimeString('en-GB');\n\n // Header\n lines.push('');\n lines.push(` ${BOLD}${CYAN}┌${'─'.repeat(cols - 6)}┐${RESET}`);\n lines.push(` ${BOLD}${CYAN}│${RESET} 🤖 ${BOLD}Copilot Agent Dashboard${RESET}${' '.repeat(Math.max(0, cols - 37 - timeStr.length))}${DIM}${timeStr}${RESET} ${BOLD}${CYAN}│${RESET}`);\n lines.push(` ${BOLD}${CYAN}└${'─'.repeat(cols - 6)}┘${RESET}`);\n lines.push('');\n\n // Active processes\n const procs = findCopilotProcesses();\n lines.push(` ${BOLD}${GREEN}● Active Processes (${procs.length})${RESET}`);\n lines.push(` ${'─'.repeat(Math.min(cols - 4, 70))}`);\n\n if (procs.length === 0) {\n lines.push(` ${DIM}No copilot processes running${RESET}`);\n } else {\n for (const p of procs) {\n const sid = p.sessionId ? p.sessionId.slice(0, 8) + '…' : '—';\n const cwdShort = p.cwd ? '~/' + p.cwd.split('/').slice(-2).join('/') : '—';\n lines.push(` ${GREEN}⬤${RESET} PID ${BOLD}${p.pid}${RESET} ${CYAN}${sid}${RESET} ${DIM}${cwdShort}${RESET}`);\n }\n }\n lines.push('');\n\n // Recent sessions\n const sessions = listSessions(limit);\n lines.push(` ${BOLD}${CYAN}● Recent Sessions (${sessions.length})${RESET}`);\n lines.push(` ${'─'.repeat(Math.min(cols - 4, 70))}`);\n\n // Table header\n const headerCols = [\n pad('Status', 10),\n pad('Premium', 8),\n pad('Duration', 10),\n pad('Project', 18),\n pad('Last Activity', 20),\n ];\n lines.push(` ${DIM}${headerCols.join(' ')}${RESET}`);\n\n for (const s of sessions) {\n const report = getSessionReport(s.id);\n const statusIcon = s.complete\n ? `${GREEN}✔ done ${RESET}`\n : `${YELLOW}⏸ stop ${RESET}`;\n const premium = pad(String(s.premiumRequests), 8);\n const duration = report ? pad(formatDuration(report.durationMs), 10) : pad('—', 10);\n const project = pad(s.cwd.split('/').pop() ?? '—', 18);\n const lastAct = pad(formatTimeAgo(s.mtime), 20);\n\n lines.push(` ${statusIcon}${premium}${duration}${project}${lastAct}`);\n }\n lines.push('');\n\n // Latest session detail panel\n if (sessions.length > 0) {\n const latest = getSessionReport(sessions[0].id);\n if (latest) {\n lines.push(` ${BOLD}${CYAN}● Latest Session Detail${RESET} ${DIM}${latest.id.slice(0, 8)}…${RESET}`);\n lines.push(` ${'─'.repeat(Math.min(cols - 4, 70))}`);\n\n // Mini stats row\n lines.push(` Turns: ${BOLD}${latest.assistantTurns}${RESET} Tokens: ${BOLD}${latest.outputTokens.toLocaleString()}${RESET} Premium: ${BOLD}${latest.premiumRequests}${RESET} Commits: ${BOLD}${latest.gitCommits.length}${RESET} Files: ${BOLD}${latest.filesEdited.length}${RESET} edited, ${BOLD}${latest.filesCreated.length}${RESET} created`);\n lines.push('');\n\n // Top tools mini chart\n const toolEntries = Object.entries(latest.toolUsage).sort((a, b) => b[1] - a[1]).slice(0, 5);\n if (toolEntries.length > 0) {\n const maxVal = toolEntries[0][1];\n const barW = Math.min(20, Math.floor((cols - 30) / 2));\n lines.push(` ${DIM}Tools:${RESET}`);\n for (const [tool, count] of toolEntries) {\n const filled = Math.round((count / maxVal) * barW);\n const b = `${CYAN}${'█'.repeat(filled)}${DIM}${'░'.repeat(barW - filled)}${RESET}`;\n lines.push(` ${b} ${String(count).padStart(4)} ${tool}`);\n }\n lines.push('');\n }\n\n // Recent commits\n if (latest.gitCommits.length > 0) {\n const maxCommits = Math.min(3, latest.gitCommits.length);\n lines.push(` ${DIM}Recent commits:${RESET}`);\n for (let i = 0; i < maxCommits; i++) {\n const msg = latest.gitCommits[i].split('\\n')[0].slice(0, cols - 10);\n lines.push(` ${GREEN}●${RESET} ${msg}`);\n }\n if (latest.gitCommits.length > maxCommits) {\n lines.push(` ${DIM} … +${latest.gitCommits.length - maxCommits} more${RESET}`);\n }\n lines.push('');\n }\n\n // Recent task completions\n if (latest.taskCompletions.length > 0) {\n const maxTasks = Math.min(3, latest.taskCompletions.length);\n lines.push(` ${DIM}Completed tasks:${RESET}`);\n for (let i = 0; i < maxTasks; i++) {\n const msg = latest.taskCompletions[i].split('\\n')[0].slice(0, cols - 10);\n lines.push(` ${GREEN}✔${RESET} ${msg}`);\n }\n if (latest.taskCompletions.length > maxTasks) {\n lines.push(` ${DIM} … +${latest.taskCompletions.length - maxTasks} more${RESET}`);\n }\n }\n }\n }\n\n // Footer\n lines.push('');\n lines.push(` ${DIM}Press ${BOLD}q${RESET}${DIM} to quit, ${BOLD}r${RESET}${DIM} to refresh${RESET}`);\n\n return lines.join('\\n');\n}\n\nfunction pad(s: string, n: number): string {\n if (s.length >= n) return s.slice(0, n);\n return s + ' '.repeat(n - s.length);\n}\n\nfunction formatDuration(ms: number): string {\n if (ms < 60_000) return `${Math.round(ms / 1000)}s`;\n if (ms < 3_600_000) return `${Math.round(ms / 60_000)}m`;\n const h = Math.floor(ms / 3_600_000);\n const m = Math.round((ms % 3_600_000) / 60_000);\n return `${h}h ${m}m`;\n}\n\nfunction formatTimeAgo(mtimeMs: number): string {\n const diff = Date.now() - mtimeMs;\n if (diff < 60_000) return 'just now';\n if (diff < 3_600_000) return `${Math.round(diff / 60_000)}m ago`;\n if (diff < 86_400_000) return `${Math.round(diff / 3_600_000)}h ago`;\n return `${Math.round(diff / 86_400_000)}d ago`;\n}\n","import type { Command } from 'commander';\nimport { Hono } from 'hono';\nimport { streamSSE } from 'hono/streaming';\nimport { serve } from '@hono/node-server';\nimport { spawn } from 'node:child_process';\nimport { listSessions, getSessionReport } from '../lib/session.js';\nimport { findCopilotProcesses } from '../lib/process.js';\nimport { ok, info, fail } from '../lib/logger.js';\nimport { layoutHead, layoutFoot } from '../web/layout.js';\nimport { renderStats, renderProcesses, renderSessionList, renderDetail } from '../web/views.js';\n\nexport function registerWebCommand(program: Command): void {\n program\n .command('web')\n .description('Launch web dashboard in browser')\n .option('-p, --port <n>', 'Port number', '3847')\n .option('--no-open', 'Do not auto-open browser')\n .action((opts) => {\n startWebServer(parseInt(opts.port, 10), opts.open !== false);\n });\n}\n\nfunction getData() {\n const sessions = listSessions(20);\n const reports = sessions.map(s => getSessionReport(s.id)).filter(r => r !== null);\n const processes = findCopilotProcesses();\n return { sessions: reports, processes };\n}\n\nfunction startWebServer(port: number, autoOpen: boolean): void {\n const app = new Hono();\n\n // ─── JSON API ────────────────────────────────────────\n app.get('/api/sessions', (c) => c.json(getData()));\n\n app.get('/api/session/:id', (c) => {\n const report = getSessionReport(c.req.param('id'));\n if (!report) return c.json({ error: 'Not found' }, 404);\n return c.json(report);\n });\n\n // ─── SSE for live updates ────────────────────────────\n app.get('/events', (c) => {\n return streamSSE(c, async (stream) => {\n while (true) {\n const { sessions, processes } = getData();\n // Push partial HTML fragments for htmx to swap\n await stream.writeSSE({\n event: 'stats',\n data: renderStats(sessions),\n });\n await stream.writeSSE({\n event: 'procs',\n data: renderProcesses(processes),\n });\n await stream.writeSSE({\n event: 'proc-count',\n data: String(processes.length),\n });\n await stream.sleep(5000);\n }\n });\n });\n\n // ─── htmx Partials ──────────────────────────────────\n app.get('/partial/detail/:id', (c) => {\n const report = getSessionReport(c.req.param('id'));\n if (!report) return c.html('<div class=\"empty-detail\">Session not found</div>');\n return c.html(renderDetail(report));\n });\n\n // ─── Main page ──────────────────────────────────────\n app.get('/', (c) => {\n const { sessions, processes } = getData();\n const firstId = sessions[0]?.id;\n\n return c.html(`${layoutHead}\n<body>\n <div class=\"header\">\n <div class=\"header-left\">\n <h1>🤖 <span>Copilot Agent</span></h1>\n <div class=\"live-badge\"><div class=\"live-dot\"></div> Live</div>\n </div>\n <div class=\"clock\" id=\"clock\"></div>\n </div>\n\n <div class=\"container\"\n hx-ext=\"sse\"\n sse-connect=\"/events\">\n\n <div class=\"stats\"\n sse-swap=\"stats\"\n hx-swap=\"innerHTML\">\n ${renderStats(sessions)}\n </div>\n\n <div class=\"procs\">\n <div class=\"procs-header\">\n ⬤ Active Processes <span class=\"count\" sse-swap=\"proc-count\" hx-swap=\"innerHTML\">${processes.length}</span>\n </div>\n <div class=\"procs-body\"\n sse-swap=\"procs\"\n hx-swap=\"innerHTML\">\n ${renderProcesses(processes)}\n </div>\n </div>\n\n <div class=\"main\">\n <div class=\"sidebar\">\n <div class=\"sidebar-header\">\n 📋 Sessions <span class=\"count\">${sessions.length}</span>\n </div>\n ${renderSessionList(sessions, firstId)}\n </div>\n <div class=\"detail\" id=\"detail\">\n ${firstId ? renderDetail(sessions[0]) : '<div class=\"empty-detail\">No sessions</div>'}\n </div>\n </div>\n </div>\n\n <script>\n setInterval(() => {\n document.getElementById('clock').textContent = new Date().toLocaleTimeString('en-GB');\n }, 1000);\n document.getElementById('clock').textContent = new Date().toLocaleTimeString('en-GB');\n </script>\n</body>\n${layoutFoot}`);\n });\n\n // ─── Start server ───────────────────────────────────\n try {\n serve({ fetch: app.fetch, port }, () => {\n const url = `http://localhost:${port}`;\n ok(`Web dashboard → ${url}`);\n info('Press Ctrl+C to stop');\n if (autoOpen) {\n spawn('open', [url], { detached: true, stdio: 'ignore' }).unref();\n }\n });\n } catch (err) {\n fail(`Server error: ${err instanceof Error ? err.message : err}`);\n process.exit(1);\n }\n}\n","const cssStyles = `\n*{margin:0;padding:0;box-sizing:border-box}\n:root{\n --bg:#0d1117;--bg2:#161b22;--bg3:#21262d;--bg4:#292e36;\n --border:#30363d;--border2:#3d444d;\n --text:#e6edf3;--text2:#8b949e;--text3:#484f58;\n --cyan:#58a6ff;--green:#3fb950;--yellow:#d29922;--red:#f85149;--purple:#bc8cff;--orange:#f0883e;\n --font-sans:'Inter',system-ui,sans-serif;\n --font-mono:'JetBrains Mono','SF Mono',monospace;\n --radius:8px;\n}\nbody{background:var(--bg);color:var(--text);font-family:var(--font-sans);font-size:14px;line-height:1.5;-webkit-font-smoothing:antialiased}\n.header{background:var(--bg2);border-bottom:1px solid var(--border);padding:12px 24px;display:flex;align-items:center;justify-content:space-between;position:sticky;top:0;z-index:10;backdrop-filter:blur(12px)}\n.header-left{display:flex;align-items:center;gap:10px}\n.header-left h1{font-size:16px;font-weight:600}\n.header-left h1 span{color:var(--cyan)}\n.live-badge{display:flex;align-items:center;gap:6px;font-size:12px;color:var(--green);background:rgba(63,185,80,.1);padding:3px 10px;border-radius:12px;font-weight:500}\n.live-dot{width:6px;height:6px;border-radius:50%;background:var(--green);animation:pulse 2s infinite}\n@keyframes pulse{0%,100%{opacity:1}50%{opacity:.3}}\n.clock{font-family:var(--font-mono);font-size:13px;color:var(--text2)}\n.container{max-width:1280px;margin:0 auto;padding:16px 20px}\n.stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:10px;margin-bottom:16px}\n.stat{background:var(--bg2);border:1px solid var(--border);border-radius:var(--radius);padding:14px 16px;transition:border-color .2s}\n.stat:hover{border-color:var(--border2)}\n.stat-label{font-size:11px;font-weight:500;color:var(--text2);text-transform:uppercase;letter-spacing:.4px}\n.stat-value{font-size:22px;font-weight:700;font-family:var(--font-mono);margin-top:2px}\n.stat-value.green{color:var(--green)}.stat-value.cyan{color:var(--cyan)}\n.stat-value.yellow{color:var(--yellow)}.stat-value.purple{color:var(--purple)}\n.procs{background:var(--bg2);border:1px solid var(--border);border-radius:var(--radius);margin-bottom:16px;overflow:hidden}\n.procs-header{padding:10px 16px;font-size:13px;font-weight:600;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:8px}\n.procs-body{padding:4px 0}\n.proc{padding:6px 16px;display:flex;align-items:center;gap:10px;font-size:13px}\n.proc-dot{width:6px;height:6px;border-radius:50%;background:var(--green);flex-shrink:0}\n.proc-pid{font-family:var(--font-mono);color:var(--cyan);font-weight:500;min-width:70px}\n.proc-sid{color:var(--text2);font-family:var(--font-mono);font-size:12px}\n.proc-cwd{color:var(--text3);font-size:12px}\n.empty{padding:14px 16px;color:var(--text3);font-size:13px}\n.main{display:grid;grid-template-columns:360px 1fr;gap:0;background:var(--bg2);border:1px solid var(--border);border-radius:var(--radius);overflow:hidden;min-height:calc(100vh - 260px)}\n.sidebar{border-right:1px solid var(--border);overflow-y:auto}\n.sidebar-header{padding:10px 16px;font-size:13px;font-weight:600;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:8px;position:sticky;top:0;background:var(--bg2);z-index:2}\n.count{background:var(--bg3);color:var(--text2);font-size:11px;padding:1px 7px;border-radius:10px;font-weight:500}\n.s-item{padding:10px 16px;border-bottom:1px solid var(--border);cursor:pointer;transition:background .15s}\n.s-item:last-child{border-bottom:none}\n.s-item:hover{background:var(--bg3)}\n.s-item.active{background:rgba(88,166,255,.06);border-left:3px solid var(--cyan);padding-left:13px}\n.s-row{display:flex;align-items:center;gap:10px}\n.s-icon{font-size:14px;flex-shrink:0}\n.s-info{flex:1;min-width:0}\n.s-title{font-size:13px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.s-meta{font-size:11px;color:var(--text2);display:flex;gap:10px;margin-top:2px;flex-wrap:wrap}\n.badge{font-size:10px;padding:1px 6px;border-radius:4px;font-weight:600;font-family:var(--font-mono);text-transform:uppercase}\n.badge-done{background:rgba(63,185,80,.12);color:var(--green)}\n.badge-stop{background:rgba(210,153,34,.12);color:var(--yellow)}\n.detail{padding:20px;overflow-y:auto}\n.detail-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:16px}\n.detail-title{font-size:18px;font-weight:700}\n.detail-id{font-family:var(--font-mono);font-size:11px;color:var(--text3);background:var(--bg);padding:3px 8px;border-radius:4px}\n.detail-time{font-size:12px;color:var(--text2);margin-bottom:16px}\n.detail-stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:8px;margin-bottom:20px}\n.d-stat{background:var(--bg);border-radius:6px;padding:10px}\n.d-stat-label{font-size:10px;color:var(--text2);text-transform:uppercase;letter-spacing:.3px}\n.d-stat-val{font-size:16px;font-weight:700;font-family:var(--font-mono);margin-top:1px}\n.sub{margin-top:20px}\n.sub-title{font-size:12px;font-weight:600;color:var(--text2);text-transform:uppercase;letter-spacing:.5px;margin-bottom:8px;display:flex;align-items:center;gap:6px}\n.tool-row{display:flex;align-items:center;gap:8px;padding:3px 0;font-size:12px}\n.tool-name{color:var(--text2);min-width:110px;text-align:right;font-family:var(--font-mono);font-size:11px}\n.tool-bar-bg{flex:1;background:var(--bg);border-radius:3px;height:14px;overflow:hidden}\n.tool-bar{height:100%;border-radius:3px;background:linear-gradient(90deg,var(--cyan),var(--purple));opacity:.7;transition:width .4s ease}\n.tool-count{font-family:var(--font-mono);color:var(--text2);min-width:40px;font-size:11px}\n.commit-list,.task-list,.file-list,.error-list{list-style:none}\n.commit-list li,.task-list li{padding:5px 0;font-size:13px;display:flex;align-items:flex-start;gap:6px;border-bottom:1px solid var(--border)}\n.commit-list li:last-child,.task-list li:last-child{border-bottom:none}\n.c-dot{color:var(--green);flex-shrink:0;margin-top:2px}\n.t-check{color:var(--green);flex-shrink:0;margin-top:2px}\n.file-list li{padding:2px 0;font-size:11px;font-family:var(--font-mono)}\n.file-created{color:var(--green)}\n.file-edited{color:var(--yellow)}\n.error-list li{padding:5px 0;font-size:12px;color:var(--red)}\n.more{font-size:11px;color:var(--text3);padding:4px 0}\n.empty-detail{display:flex;align-items:center;justify-content:center;height:100%;color:var(--text3)}\n.htmx-settling{opacity:0}\n.htmx-added{opacity:0;transition:opacity .3s ease}\n@media(max-width:768px){.main{grid-template-columns:1fr}.stats{grid-template-columns:repeat(2,1fr)}}\n`;\n\nexport const layoutHead = `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<title>Copilot Agent Dashboard</title>\n<script src=\"https://unpkg.com/htmx.org@2.0.4\" integrity=\"sha384-HGfztofotfshcF7+8n44JQL2oJmowVChPTg48S+jvZoztPfvwD79OC/LTtG6dMp+\" crossorigin=\"anonymous\"></script>\n<script src=\"https://unpkg.com/htmx-ext-sse@2.2.2/sse.js\"></script>\n<script defer src=\"https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js\"></script>\n<link rel=\"preconnect\" href=\"https://fonts.googleapis.com\">\n<link href=\"https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap\" rel=\"stylesheet\">\n<style>\n${cssStyles}\n</style>\n</head>`;\n\nexport const layoutFoot = `</html>`;\n","import type { SessionReport } from '../lib/session.js';\nimport type { CopilotProcess } from '../lib/process.js';\n\n// ─── Helpers ───────────────────────────────────────────────\nfunction esc(s: string): string {\n return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/\"/g, '"');\n}\n\nfunction fmt(n: number): string {\n return n.toLocaleString();\n}\n\nfunction fmtDur(ms: number): string {\n if (!ms) return '—';\n if (ms < 60_000) return `${Math.round(ms / 1000)}s`;\n if (ms < 3_600_000) return `${Math.round(ms / 60_000)}m`;\n const h = Math.floor(ms / 3_600_000);\n const m = Math.round((ms % 3_600_000) / 60_000);\n return `${h}h ${m}m`;\n}\n\nfunction fmtTime(iso: string): string {\n if (!iso) return '—';\n return new Date(iso).toLocaleString('en-GB', { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' });\n}\n\nfunction fmtAgo(iso: string): string {\n if (!iso) return '—';\n const diff = Date.now() - new Date(iso).getTime();\n if (diff < 60_000) return 'just now';\n if (diff < 3_600_000) return `${Math.round(diff / 60_000)}m ago`;\n if (diff < 86_400_000) return `${Math.round(diff / 3_600_000)}h ago`;\n return `${Math.round(diff / 86_400_000)}d ago`;\n}\n\nfunction shortPath(p: string, proj: string): string {\n if (proj && p.includes(proj + '/')) return p.split(proj + '/').pop() ?? p;\n return p.split('/').slice(-3).join('/');\n}\n\n// ─── Stats Bar ─────────────────────────────────────────────\nexport function renderStats(sessions: SessionReport[]): string {\n const totalPremium = sessions.reduce((a, s) => a + (s.premiumRequests ?? 0), 0);\n const totalTokens = sessions.reduce((a, s) => a + (s.outputTokens ?? 0), 0);\n const totalCommits = sessions.reduce((a, s) => a + (s.gitCommits?.length ?? 0), 0);\n const totalTasks = sessions.reduce((a, s) => a + (s.taskCompletions?.length ?? 0), 0);\n const completed = sessions.filter(s => s.complete).length;\n\n const items = [\n { label: 'Sessions', value: String(sessions.length), cls: 'cyan' },\n { label: 'Completed', value: `${completed}/${sessions.length}`, cls: 'green' },\n { label: 'Premium', value: fmt(totalPremium), cls: 'yellow' },\n { label: 'Tokens', value: fmt(totalTokens), cls: 'purple' },\n { label: 'Commits', value: String(totalCommits), cls: 'green' },\n { label: 'Tasks Done', value: String(totalTasks), cls: 'cyan' },\n ];\n\n return items.map(i =>\n `<div class=\"stat\"><div class=\"stat-label\">${i.label}</div><div class=\"stat-value ${i.cls}\">${i.value}</div></div>`\n ).join('');\n}\n\n// ─── Process List ──────────────────────────────────────────\nexport function renderProcesses(procs: CopilotProcess[]): string {\n if (procs.length === 0) return '<div class=\"empty\">No active copilot processes</div>';\n return procs.map(p => {\n const sid = p.sessionId ? p.sessionId.slice(0, 8) + '…' : '—';\n return `<div class=\"proc\">\n <div class=\"proc-dot\"></div>\n <span class=\"proc-pid\">PID ${p.pid}</span>\n <span class=\"proc-sid\">${esc(sid)}</span>\n <span class=\"proc-cwd\">${esc(p.cwd ?? '')}</span>\n </div>`;\n }).join('');\n}\n\n// ─── Session List ──────────────────────────────────────────\nexport function renderSessionList(sessions: SessionReport[], selectedId?: string): string {\n return sessions.map(s => {\n const proj = (s.cwd ?? '').split('/').pop() ?? '—';\n const isActive = s.id === selectedId;\n return `<div class=\"s-item${isActive ? ' active' : ''}\"\n hx-get=\"/partial/detail/${s.id}\" hx-target=\"#detail\" hx-swap=\"innerHTML\"\n onclick=\"document.querySelectorAll('.s-item').forEach(e=>e.classList.remove('active'));this.classList.add('active')\">\n <div class=\"s-row\">\n <span class=\"s-icon\">${s.complete ? '✅' : '⏸️'}</span>\n <div class=\"s-info\">\n <div class=\"s-title\">${esc(proj)} — ${esc(s.summary || '(no summary)')}</div>\n <div class=\"s-meta\">\n <span>${fmtDur(s.durationMs)}</span>\n <span>${fmt(s.premiumRequests)} premium</span>\n <span>${fmtAgo(s.endTime)}</span>\n <span class=\"badge ${s.complete ? 'badge-done' : 'badge-stop'}\">${s.complete ? 'done' : 'stopped'}</span>\n </div>\n </div>\n </div>\n </div>`;\n }).join('');\n}\n\n// ─── Session Detail ────────────────────────────────────────\nexport function renderDetail(s: SessionReport): string {\n const proj = (s.cwd ?? '').split('/').pop() ?? '—';\n const totalTools = Object.values(s.toolUsage ?? {}).reduce((a, b) => a + b, 0);\n const toolEntries = Object.entries(s.toolUsage ?? {}).sort((a, b) => b[1] - a[1]);\n const maxTool = toolEntries[0]?.[1] ?? 1;\n\n let html = '';\n\n // Header\n html += `<div class=\"detail-head\">\n <div class=\"detail-title\">${esc(proj)}</div>\n <div class=\"detail-id\">${s.id}</div>\n </div>`;\n\n html += `<div class=\"detail-time\">${fmtTime(s.startTime)} → ${fmtTime(s.endTime)}</div>`;\n\n // Stats grid\n html += `<div class=\"detail-stats\">\n <div class=\"d-stat\"><div class=\"d-stat-label\">Duration</div><div class=\"d-stat-val\">${fmtDur(s.durationMs)}</div></div>\n <div class=\"d-stat\"><div class=\"d-stat-label\">User Msgs</div><div class=\"d-stat-val\">${s.userMessages}</div></div>\n <div class=\"d-stat\"><div class=\"d-stat-label\">Turns</div><div class=\"d-stat-val\">${fmt(s.assistantTurns)}</div></div>\n <div class=\"d-stat\"><div class=\"d-stat-label\">Tokens</div><div class=\"d-stat-val\">${fmt(s.outputTokens)}</div></div>\n <div class=\"d-stat\"><div class=\"d-stat-label\">Premium</div><div class=\"d-stat-val\">${fmt(s.premiumRequests)}</div></div>\n <div class=\"d-stat\"><div class=\"d-stat-label\">Tool Calls</div><div class=\"d-stat-val\">${fmt(totalTools)}</div></div>\n </div>`;\n\n // Tools chart\n if (toolEntries.length > 0) {\n html += `<div class=\"sub\"><div class=\"sub-title\">🔧 Tools Used</div>`;\n for (const [tool, count] of toolEntries.slice(0, 12)) {\n const pct = Math.round((count / maxTool) * 100);\n html += `<div class=\"tool-row\">\n <span class=\"tool-name\">${esc(tool)}</span>\n <div class=\"tool-bar-bg\"><div class=\"tool-bar\" style=\"width:${pct}%\"></div></div>\n <span class=\"tool-count\">${count}</span>\n </div>`;\n }\n if (toolEntries.length > 12) html += `<div class=\"more\">… +${toolEntries.length - 12} more</div>`;\n html += `</div>`;\n }\n\n // Git commits\n if (s.gitCommits.length > 0) {\n html += `<div class=\"sub\"><div class=\"sub-title\">🔀 Git Commits <span class=\"count\">${s.gitCommits.length}</span></div><ul class=\"commit-list\">`;\n for (const msg of s.gitCommits.slice(0, 12)) {\n const first = msg.split('\\n')[0].slice(0, 80);\n html += `<li><span class=\"c-dot\">●</span><span>${esc(first)}</span></li>`;\n }\n if (s.gitCommits.length > 12) html += `<li class=\"more\">… +${s.gitCommits.length - 12} more</li>`;\n html += `</ul></div>`;\n }\n\n // Files\n const files = [\n ...s.filesCreated.map(f => ({ path: f, type: 'created' as const })),\n ...s.filesEdited.map(f => ({ path: f, type: 'edited' as const })),\n ];\n if (files.length > 0) {\n html += `<div class=\"sub\"><div class=\"sub-title\">📁 Files Changed <span class=\"count\">${files.length}</span></div><ul class=\"file-list\">`;\n for (const f of files.slice(0, 25)) {\n const cls = f.type === 'created' ? 'file-created' : 'file-edited';\n const icon = f.type === 'created' ? '+' : '~';\n html += `<li><span class=\"${cls}\">${icon}</span> ${esc(shortPath(f.path, proj))}</li>`;\n }\n if (files.length > 25) html += `<li class=\"more\">… +${files.length - 25} more</li>`;\n html += `</ul></div>`;\n }\n\n // Task completions\n if (s.taskCompletions.length > 0) {\n html += `<div class=\"sub\"><div class=\"sub-title\">✅ Tasks Completed <span class=\"count\">${s.taskCompletions.length}</span></div><ul class=\"task-list\">`;\n for (const t of s.taskCompletions.slice(0, 10)) {\n const first = t.split('\\n')[0].slice(0, 80);\n html += `<li><span class=\"t-check\">✔</span><span>${esc(first)}</span></li>`;\n }\n if (s.taskCompletions.length > 10) html += `<li class=\"more\">… +${s.taskCompletions.length - 10} more</li>`;\n html += `</ul></div>`;\n }\n\n // Errors\n if (s.errors.length > 0) {\n html += `<div class=\"sub\"><div class=\"sub-title\" style=\"color:var(--red)\">⚠️ Errors <span class=\"count\">${s.errors.length}</span></div><ul class=\"error-list\">`;\n for (const e of s.errors.slice(0, 5)) {\n html += `<li>${esc(e.slice(0, 100))}</li>`;\n }\n if (s.errors.length > 5) html += `<li class=\"more\">… +${s.errors.length - 5} more</li>`;\n html += `</ul></div>`;\n }\n\n return html;\n}\n"],"mappings":"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","names":["execSync","resolve","execSync","resolve","program","program","sleep","existsSync","readFileSync","readdirSync","join","resolve","execSync","mkdirSync","readFileSync","join","homedir","existsSync","join","resolve","execSync","resolve","existsSync","program","join","homedir","program","join","homedir","sleep","existsSync","mkdirSync","join","resolve","homedir","program","resolve","join","existsSync","homedir","mkdirSync","resolve","program","resolve","program","formatDuration","spawn","program","spawn"]}
|
package/package.json
CHANGED
|
@@ -1,15 +1,32 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "copilot-agent",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Autonomous GitHub Copilot CLI agent — auto-resume, task discovery, overnight runs",
|
|
5
5
|
"author": "magicpro97",
|
|
6
6
|
"license": "MIT",
|
|
7
|
-
"keywords": [
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
"keywords": [
|
|
8
|
+
"copilot",
|
|
9
|
+
"github",
|
|
10
|
+
"agent",
|
|
11
|
+
"autopilot",
|
|
12
|
+
"cli",
|
|
13
|
+
"automation",
|
|
14
|
+
"ai"
|
|
15
|
+
],
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "https://github.com/magicpro97/copilot-agent"
|
|
19
|
+
},
|
|
20
|
+
"bin": {
|
|
21
|
+
"copilot-agent": "./dist/index.js"
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"dist"
|
|
25
|
+
],
|
|
11
26
|
"type": "module",
|
|
12
|
-
"engines": {
|
|
27
|
+
"engines": {
|
|
28
|
+
"node": ">=18"
|
|
29
|
+
},
|
|
13
30
|
"scripts": {
|
|
14
31
|
"build": "tsup",
|
|
15
32
|
"dev": "tsup --watch",
|
|
@@ -18,18 +35,20 @@
|
|
|
18
35
|
"prepublishOnly": "npm run build"
|
|
19
36
|
},
|
|
20
37
|
"dependencies": {
|
|
38
|
+
"@hono/node-server": "^1.19.12",
|
|
21
39
|
"chalk": "^5.4.1",
|
|
22
40
|
"commander": "^13.1.0",
|
|
23
41
|
"execa": "^9.5.2",
|
|
24
42
|
"find-up": "^7.0.0",
|
|
43
|
+
"hono": "^4.12.10",
|
|
25
44
|
"ora": "^8.2.0",
|
|
26
45
|
"proper-lockfile": "^4.1.2",
|
|
27
46
|
"ps-list": "^9.0.0",
|
|
28
47
|
"yaml": "^2.7.1"
|
|
29
48
|
},
|
|
30
49
|
"devDependencies": {
|
|
31
|
-
"@types/proper-lockfile": "^4.1.4",
|
|
32
50
|
"@types/node": "^22.15.2",
|
|
51
|
+
"@types/proper-lockfile": "^4.1.4",
|
|
33
52
|
"tsup": "^8.4.0",
|
|
34
53
|
"typescript": "^5.8.3"
|
|
35
54
|
}
|