copilot-agent 0.1.0 → 0.3.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/README.md +29 -0
- package/dist/index.js +347 -250
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -9,6 +9,8 @@ Autonomous GitHub Copilot CLI agent — auto-resume sessions, discover tasks, ru
|
|
|
9
9
|
- **`run`** — Auto-discover and fix issues in any project
|
|
10
10
|
- **`overnight`** — Run tasks continuously until a deadline (e.g. 07:00)
|
|
11
11
|
- **`research`** — Research improvements, dependencies, architecture
|
|
12
|
+
- **`daemon`** — Background watchdog that auto-resumes interrupted sessions
|
|
13
|
+
- **`multi`** — Multi-project orchestrator (register projects, run health/research on all)
|
|
12
14
|
|
|
13
15
|
## Install
|
|
14
16
|
|
|
@@ -79,6 +81,33 @@ copilot-agent research
|
|
|
79
81
|
copilot-agent research "migrate from Room to SQLDelight"
|
|
80
82
|
```
|
|
81
83
|
|
|
84
|
+
### Background daemon
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
# Start watchdog (monitors & auto-resumes sessions)
|
|
88
|
+
copilot-agent daemon start --resume
|
|
89
|
+
|
|
90
|
+
# Check status / view logs / stop
|
|
91
|
+
copilot-agent daemon status
|
|
92
|
+
copilot-agent daemon logs
|
|
93
|
+
copilot-agent daemon stop
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Multi-project
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
# Register projects
|
|
100
|
+
copilot-agent multi add ~/project-a
|
|
101
|
+
copilot-agent multi add ~/project-b
|
|
102
|
+
copilot-agent multi list
|
|
103
|
+
|
|
104
|
+
# Run health check on all projects
|
|
105
|
+
copilot-agent multi health
|
|
106
|
+
|
|
107
|
+
# Run research on all projects
|
|
108
|
+
copilot-agent multi research --dry-run
|
|
109
|
+
```
|
|
110
|
+
|
|
82
111
|
## How it works
|
|
83
112
|
|
|
84
113
|
1. **Session detection** — Reads `~/.copilot/session-state/*/events.jsonl` to detect task completion vs interruption
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,6 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
1
|
// src/index.ts
|
|
4
2
|
import { Command } from "commander";
|
|
5
3
|
|
|
6
|
-
// src/commands/status.ts
|
|
7
|
-
import chalk from "chalk";
|
|
8
|
-
|
|
9
4
|
// src/lib/session.ts
|
|
10
5
|
import {
|
|
11
6
|
existsSync,
|
|
@@ -148,6 +143,9 @@ import { execSync } from "child_process";
|
|
|
148
143
|
var RED = "\x1B[31m";
|
|
149
144
|
var GREEN = "\x1B[32m";
|
|
150
145
|
var YELLOW = "\x1B[33m";
|
|
146
|
+
var CYAN = "\x1B[36m";
|
|
147
|
+
var DIM = "\x1B[2m";
|
|
148
|
+
var BOLD = "\x1B[1m";
|
|
151
149
|
var RESET = "\x1B[0m";
|
|
152
150
|
|
|
153
151
|
// src/lib/logger.ts
|
|
@@ -186,6 +184,11 @@ function fail(msg) {
|
|
|
186
184
|
console.error(out);
|
|
187
185
|
writeToFile(`\u2716 ${msg}`);
|
|
188
186
|
}
|
|
187
|
+
function info(msg) {
|
|
188
|
+
const out = `${CYAN}\u2139 ${msg}${RESET}`;
|
|
189
|
+
console.log(out);
|
|
190
|
+
writeToFile(`\u2139 ${msg}`);
|
|
191
|
+
}
|
|
189
192
|
function notify(message, title = "copilot-agent") {
|
|
190
193
|
try {
|
|
191
194
|
if (process.platform === "darwin") {
|
|
@@ -226,16 +229,20 @@ function findCopilotProcesses() {
|
|
|
226
229
|
try {
|
|
227
230
|
const output = execSync2("ps -eo pid,command", { encoding: "utf-8" });
|
|
228
231
|
const results = [];
|
|
232
|
+
const myPid = process.pid;
|
|
233
|
+
const parentPid = process.ppid;
|
|
229
234
|
for (const line of output.split("\n")) {
|
|
230
235
|
const trimmed = line.trim();
|
|
231
236
|
if (!trimmed) continue;
|
|
232
237
|
if ((trimmed.includes("copilot") || trimmed.includes("@githubnext/copilot")) && !trimmed.includes("ps -eo") && !trimmed.includes("copilot-agent") && !trimmed.includes("grep")) {
|
|
233
238
|
const match = trimmed.match(/^(\d+)\s+(.+)$/);
|
|
234
239
|
if (match) {
|
|
240
|
+
const pid = parseInt(match[1], 10);
|
|
241
|
+
if (pid === myPid || pid === parentPid) continue;
|
|
235
242
|
const cmd = match[2];
|
|
236
243
|
const sidMatch = cmd.match(/resume[= ]+([a-f0-9-]{36})/);
|
|
237
244
|
results.push({
|
|
238
|
-
pid
|
|
245
|
+
pid,
|
|
239
246
|
command: cmd,
|
|
240
247
|
sessionId: sidMatch?.[1]
|
|
241
248
|
});
|
|
@@ -252,6 +259,30 @@ function findPidForSession(sid) {
|
|
|
252
259
|
const matching = procs.filter((p) => p.command.includes(sid)).sort((a, b) => b.pid - a.pid);
|
|
253
260
|
return matching[0]?.pid ?? null;
|
|
254
261
|
}
|
|
262
|
+
async function waitForAllCopilotToFinish(timeoutMs = 144e5, pollMs = 1e4) {
|
|
263
|
+
const start = Date.now();
|
|
264
|
+
let warned = false;
|
|
265
|
+
while (Date.now() - start < timeoutMs) {
|
|
266
|
+
const procs = findCopilotProcesses();
|
|
267
|
+
if (procs.length === 0) return;
|
|
268
|
+
if (!warned) {
|
|
269
|
+
warn(`Waiting for ${procs.length} copilot process(es) to finish before starting...`);
|
|
270
|
+
for (const p of procs) {
|
|
271
|
+
log(` PID ${p.pid}: ${p.command.slice(0, 80)}`);
|
|
272
|
+
}
|
|
273
|
+
warned = true;
|
|
274
|
+
}
|
|
275
|
+
await sleep(pollMs);
|
|
276
|
+
}
|
|
277
|
+
warn("Timeout waiting for copilot processes to finish");
|
|
278
|
+
}
|
|
279
|
+
function assertSessionNotRunning(sid) {
|
|
280
|
+
const pid = findPidForSession(sid);
|
|
281
|
+
if (pid) {
|
|
282
|
+
fail(`Session ${sid.slice(0, 8)}\u2026 already has copilot running (PID ${pid}). Cannot resume \u2014 would corrupt the session.`);
|
|
283
|
+
process.exit(1);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
255
286
|
async function waitForExit(pid, timeoutMs = 144e5) {
|
|
256
287
|
const start = Date.now();
|
|
257
288
|
while (Date.now() - start < timeoutMs) {
|
|
@@ -264,8 +295,9 @@ async function waitForExit(pid, timeoutMs = 144e5) {
|
|
|
264
295
|
}
|
|
265
296
|
return false;
|
|
266
297
|
}
|
|
267
|
-
function runCopilot(args, options) {
|
|
268
|
-
|
|
298
|
+
async function runCopilot(args, options) {
|
|
299
|
+
await waitForAllCopilotToFinish();
|
|
300
|
+
return new Promise((resolve4) => {
|
|
269
301
|
const child = spawn("copilot", args, {
|
|
270
302
|
cwd: options?.cwd,
|
|
271
303
|
stdio: "inherit",
|
|
@@ -275,18 +307,19 @@ function runCopilot(args, options) {
|
|
|
275
307
|
await sleep(3e3);
|
|
276
308
|
const sid = getLatestSessionId();
|
|
277
309
|
const premium = sid ? getSessionPremium(sid) : 0;
|
|
278
|
-
|
|
310
|
+
resolve4({
|
|
279
311
|
exitCode: code ?? 1,
|
|
280
312
|
sessionId: sid,
|
|
281
313
|
premium
|
|
282
314
|
});
|
|
283
315
|
});
|
|
284
316
|
child.on("error", () => {
|
|
285
|
-
|
|
317
|
+
resolve4({ exitCode: 1, sessionId: null, premium: 0 });
|
|
286
318
|
});
|
|
287
319
|
});
|
|
288
320
|
}
|
|
289
321
|
function runCopilotResume(sid, steps, message, cwd) {
|
|
322
|
+
assertSessionNotRunning(sid);
|
|
290
323
|
const args = [
|
|
291
324
|
`--resume=${sid}`,
|
|
292
325
|
"--autopilot",
|
|
@@ -314,61 +347,77 @@ function sleep(ms) {
|
|
|
314
347
|
}
|
|
315
348
|
|
|
316
349
|
// src/commands/status.ts
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
350
|
+
function registerStatusCommand(program2) {
|
|
351
|
+
program2.command("status").description("Show copilot session status").option("-l, --limit <n>", "Number of sessions to show", "10").option("-a, --active", "Show only active (running) processes").option("-i, --incomplete", "Only show incomplete sessions").action((opts) => {
|
|
352
|
+
if (opts.active) {
|
|
353
|
+
showActive();
|
|
354
|
+
} else {
|
|
355
|
+
showRecent(parseInt(opts.limit, 10), opts.incomplete ?? false);
|
|
356
|
+
}
|
|
357
|
+
});
|
|
322
358
|
}
|
|
323
|
-
|
|
324
|
-
const procs =
|
|
359
|
+
function showActive() {
|
|
360
|
+
const procs = findCopilotProcesses();
|
|
325
361
|
if (procs.length === 0) {
|
|
326
|
-
log(
|
|
362
|
+
log(`${DIM}No active copilot processes.${RESET}`);
|
|
327
363
|
return;
|
|
328
364
|
}
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
${"PID".padEnd(8)} ${"Session".padEnd(40)} ${"Command".slice(0, 60)}`
|
|
333
|
-
)
|
|
334
|
-
);
|
|
335
|
-
console.log("\u2500".repeat(108));
|
|
365
|
+
log(`
|
|
366
|
+
${BOLD}${"PID".padEnd(8)} ${"Session".padEnd(40)} Command${RESET}`);
|
|
367
|
+
log("\u2500".repeat(108));
|
|
336
368
|
for (const p of procs) {
|
|
337
|
-
|
|
338
|
-
`${String(p.pid).padEnd(8)} ${(p.sessionId ?? "\u2014").padEnd(40)} ${(p.command
|
|
369
|
+
log(
|
|
370
|
+
`${CYAN}${String(p.pid).padEnd(8)}${RESET} ${(p.sessionId ?? "\u2014").padEnd(40)} ${truncate(p.command, 58)}`
|
|
339
371
|
);
|
|
340
372
|
}
|
|
341
|
-
|
|
373
|
+
log("");
|
|
342
374
|
}
|
|
343
|
-
function showRecent(limit) {
|
|
344
|
-
|
|
375
|
+
function showRecent(limit, incompleteOnly) {
|
|
376
|
+
let sessions = listSessions(limit);
|
|
377
|
+
if (incompleteOnly) {
|
|
378
|
+
sessions = sessions.filter((s) => !s.complete);
|
|
379
|
+
}
|
|
345
380
|
if (sessions.length === 0) {
|
|
346
|
-
log(
|
|
381
|
+
log(`${DIM}No sessions found.${RESET}`);
|
|
347
382
|
return;
|
|
348
383
|
}
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
${"Status".padEnd(10)} ${"Premium".padEnd(10)} ${"Last Event".padEnd(25)} ${"Summary".padEnd(40)} ${"ID"}`
|
|
353
|
-
)
|
|
384
|
+
log(
|
|
385
|
+
`
|
|
386
|
+
${BOLD}${"Status".padEnd(10)} ${"Premium".padEnd(10)} ${"Last Event".padEnd(25)} ${"Summary".padEnd(40)} ID${RESET}`
|
|
354
387
|
);
|
|
355
|
-
|
|
388
|
+
log("\u2500".repeat(120));
|
|
356
389
|
for (const s of sessions) {
|
|
357
|
-
const
|
|
358
|
-
const
|
|
359
|
-
const
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
console.log(
|
|
363
|
-
`${status.padEnd(20)} ${premium.padEnd(10)} ${lastEvt.padEnd(25)} ${summary.padEnd(40)} ${chalk.dim(s.id)}`
|
|
390
|
+
const status = s.complete ? `${GREEN}\u2714 done${RESET}` : `${YELLOW}\u23F8 stop${RESET}`;
|
|
391
|
+
const premium = String(s.premiumRequests);
|
|
392
|
+
const summary = truncate(s.summary || "\u2014", 38);
|
|
393
|
+
log(
|
|
394
|
+
`${status.padEnd(10 + 9)} ${premium.padEnd(10)} ${s.lastEvent.padEnd(25)} ${summary.padEnd(40)} ${DIM}${s.id}${RESET}`
|
|
364
395
|
);
|
|
365
396
|
}
|
|
366
|
-
|
|
397
|
+
log(`
|
|
398
|
+
${DIM}Total: ${sessions.length} session(s)${RESET}`);
|
|
399
|
+
}
|
|
400
|
+
function truncate(s, max) {
|
|
401
|
+
if (s.length <= max) return s;
|
|
402
|
+
return s.substring(0, max - 1) + "\u2026";
|
|
367
403
|
}
|
|
368
404
|
|
|
369
405
|
// src/commands/watch.ts
|
|
370
|
-
|
|
371
|
-
|
|
406
|
+
function registerWatchCommand(program2) {
|
|
407
|
+
program2.command("watch [session-id]").description("Watch a session and auto-resume when it stops").option("-s, --steps <n>", "Max autopilot continues per resume", "30").option("-r, --max-resumes <n>", "Max number of resumes", "10").option("-c, --cooldown <n>", "Seconds between resumes", "10").option("-m, --message <msg>", "Message to send on resume").action(async (sid, opts) => {
|
|
408
|
+
try {
|
|
409
|
+
await watchCommand(sid, {
|
|
410
|
+
steps: parseInt(opts.steps, 10),
|
|
411
|
+
maxResumes: parseInt(opts.maxResumes, 10),
|
|
412
|
+
cooldown: parseInt(opts.cooldown, 10),
|
|
413
|
+
message: opts.message
|
|
414
|
+
});
|
|
415
|
+
} catch (err) {
|
|
416
|
+
fail(`Watch error: ${err instanceof Error ? err.message : err}`);
|
|
417
|
+
process.exit(1);
|
|
418
|
+
}
|
|
419
|
+
});
|
|
420
|
+
}
|
|
372
421
|
async function watchCommand(sid, opts) {
|
|
373
422
|
assertCopilot();
|
|
374
423
|
if (!sid) {
|
|
@@ -377,7 +426,7 @@ async function watchCommand(sid, opts) {
|
|
|
377
426
|
fail("No incomplete session found.");
|
|
378
427
|
process.exit(1);
|
|
379
428
|
}
|
|
380
|
-
|
|
429
|
+
info(`Auto-detected incomplete session: ${CYAN}${sid}${RESET}`);
|
|
381
430
|
}
|
|
382
431
|
if (!validateSession(sid)) {
|
|
383
432
|
fail(`Invalid session: ${sid}`);
|
|
@@ -389,13 +438,10 @@ async function watchCommand(sid, opts) {
|
|
|
389
438
|
}
|
|
390
439
|
let resumes = 0;
|
|
391
440
|
while (resumes < opts.maxResumes) {
|
|
392
|
-
const pid =
|
|
441
|
+
const pid = findPidForSession(sid);
|
|
393
442
|
if (pid) {
|
|
394
|
-
|
|
395
|
-
`Watching PID ${pid} for session ${chalk2.cyan(sid.slice(0, 8))}\u2026`
|
|
396
|
-
).start();
|
|
443
|
+
info(`Watching PID ${pid} for session ${CYAN}${sid.slice(0, 8)}${RESET}\u2026`);
|
|
397
444
|
const exited = await waitForExit(pid);
|
|
398
|
-
spinner.stop();
|
|
399
445
|
if (!exited) {
|
|
400
446
|
warn("Timeout waiting for process exit.");
|
|
401
447
|
break;
|
|
@@ -403,19 +449,25 @@ async function watchCommand(sid, opts) {
|
|
|
403
449
|
}
|
|
404
450
|
await sleep2(3e3);
|
|
405
451
|
if (hasTaskComplete(sid)) {
|
|
406
|
-
ok(
|
|
407
|
-
`Task complete! Summary: ${getSessionSummary(sid) || "none"}`
|
|
408
|
-
);
|
|
452
|
+
ok(`Task complete! Summary: ${getSessionSummary(sid) || "none"}`);
|
|
409
453
|
notify("Task completed!", `Session ${sid.slice(0, 8)}`);
|
|
410
454
|
return;
|
|
411
455
|
}
|
|
412
456
|
resumes++;
|
|
413
|
-
log(
|
|
414
|
-
|
|
457
|
+
log(`Session interrupted (${getLastEvent(sid)}). Resume ${resumes}/${opts.maxResumes}\u2026`);
|
|
458
|
+
if (opts.cooldown > 0 && resumes > 1) {
|
|
459
|
+
info(`Cooldown ${opts.cooldown}s...`);
|
|
460
|
+
await sleep2(opts.cooldown * 1e3);
|
|
461
|
+
}
|
|
462
|
+
const cwd = getSessionCwd(sid) || void 0;
|
|
463
|
+
const result = await runCopilotResume(
|
|
464
|
+
sid,
|
|
465
|
+
opts.steps,
|
|
466
|
+
opts.message ?? "Continue remaining work. Pick up where you left off and complete the task.",
|
|
467
|
+
cwd
|
|
415
468
|
);
|
|
416
|
-
const result = await runCopilotResume(sid, opts.steps, opts.message);
|
|
417
469
|
if (result.sessionId && result.sessionId !== sid) {
|
|
418
|
-
|
|
470
|
+
info(`New session created: ${CYAN}${result.sessionId}${RESET}`);
|
|
419
471
|
sid = result.sessionId;
|
|
420
472
|
}
|
|
421
473
|
}
|
|
@@ -426,10 +478,6 @@ function sleep2(ms) {
|
|
|
426
478
|
return new Promise((r) => setTimeout(r, ms));
|
|
427
479
|
}
|
|
428
480
|
|
|
429
|
-
// src/commands/run.ts
|
|
430
|
-
import chalk3 from "chalk";
|
|
431
|
-
import ora2 from "ora";
|
|
432
|
-
|
|
433
481
|
// src/lib/detect.ts
|
|
434
482
|
import { existsSync as existsSync2, readFileSync as readFileSync2, readdirSync as readdirSync2 } from "fs";
|
|
435
483
|
import { join as join2, basename, resolve as resolve2 } from "path";
|
|
@@ -479,6 +527,27 @@ function detectProjectName(dir) {
|
|
|
479
527
|
}
|
|
480
528
|
return basename(resolve2(dir));
|
|
481
529
|
}
|
|
530
|
+
function detectMainBranch(dir) {
|
|
531
|
+
try {
|
|
532
|
+
const ref = execSync3("git symbolic-ref refs/remotes/origin/HEAD", {
|
|
533
|
+
cwd: dir,
|
|
534
|
+
encoding: "utf-8",
|
|
535
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
536
|
+
}).trim();
|
|
537
|
+
return ref.split("/").pop() ?? "main";
|
|
538
|
+
} catch {
|
|
539
|
+
}
|
|
540
|
+
try {
|
|
541
|
+
const branch = execSync3("git branch --show-current", {
|
|
542
|
+
cwd: dir,
|
|
543
|
+
encoding: "utf-8",
|
|
544
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
545
|
+
}).trim();
|
|
546
|
+
if (branch) return branch;
|
|
547
|
+
} catch {
|
|
548
|
+
}
|
|
549
|
+
return "main";
|
|
550
|
+
}
|
|
482
551
|
|
|
483
552
|
// src/lib/tasks.ts
|
|
484
553
|
var COMMON_TASKS = [
|
|
@@ -633,51 +702,67 @@ async function withLock(name, fn) {
|
|
|
633
702
|
}
|
|
634
703
|
|
|
635
704
|
// src/lib/git.ts
|
|
705
|
+
import { existsSync as existsSync4 } from "fs";
|
|
706
|
+
import { join as join4 } from "path";
|
|
636
707
|
import { execSync as execSync4 } from "child_process";
|
|
637
|
-
function
|
|
708
|
+
function gitExec(dir, cmd) {
|
|
638
709
|
try {
|
|
639
|
-
return execSync4(
|
|
640
|
-
cwd,
|
|
641
|
-
encoding: "utf-8"
|
|
710
|
+
return execSync4(cmd, {
|
|
711
|
+
cwd: dir,
|
|
712
|
+
encoding: "utf-8",
|
|
713
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
642
714
|
}).trim();
|
|
643
715
|
} catch {
|
|
644
|
-
return
|
|
716
|
+
return null;
|
|
645
717
|
}
|
|
646
718
|
}
|
|
647
|
-
function
|
|
648
|
-
|
|
649
|
-
return execSync4("git status --porcelain", {
|
|
650
|
-
cwd,
|
|
651
|
-
encoding: "utf-8"
|
|
652
|
-
}).trim();
|
|
653
|
-
} catch {
|
|
654
|
-
return "";
|
|
655
|
-
}
|
|
719
|
+
function isGitRepo(dir) {
|
|
720
|
+
return existsSync4(join4(dir, ".git"));
|
|
656
721
|
}
|
|
657
|
-
function
|
|
658
|
-
|
|
659
|
-
cwd,
|
|
660
|
-
stdio: "ignore"
|
|
661
|
-
});
|
|
722
|
+
function gitCurrentBranch(dir) {
|
|
723
|
+
return gitExec(dir, "git branch --show-current");
|
|
662
724
|
}
|
|
663
|
-
function
|
|
664
|
-
|
|
725
|
+
function gitStash(dir) {
|
|
726
|
+
return gitExec(dir, "git stash -q") !== null;
|
|
665
727
|
}
|
|
666
|
-
function
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
}
|
|
671
|
-
|
|
672
|
-
|
|
728
|
+
function gitCheckout(dir, branch) {
|
|
729
|
+
return gitExec(dir, `git checkout ${branch} -q`) !== null;
|
|
730
|
+
}
|
|
731
|
+
function gitCreateBranch(dir, branch) {
|
|
732
|
+
return gitExec(dir, `git checkout -b ${branch}`) !== null;
|
|
733
|
+
}
|
|
734
|
+
function gitCountCommits(dir, from, to) {
|
|
735
|
+
const result = gitExec(dir, `git log ${from}..${to} --oneline`);
|
|
736
|
+
if (!result) return 0;
|
|
737
|
+
return result.split("\n").filter((l) => l.trim()).length;
|
|
738
|
+
}
|
|
739
|
+
function gitStatus(dir) {
|
|
740
|
+
return gitExec(dir, "git status --porcelain") ?? "";
|
|
673
741
|
}
|
|
674
742
|
|
|
675
743
|
// src/commands/run.ts
|
|
744
|
+
function registerRunCommand(program2) {
|
|
745
|
+
program2.command("run [dir]").description("Discover and fix issues in a project").option("-s, --steps <n>", "Max autopilot continues per task", "30").option("-t, --max-tasks <n>", "Max number of tasks to run", "5").option("-p, --max-premium <n>", "Max total premium requests", "50").option("--dry-run", "Show tasks without executing").action(async (dir, opts) => {
|
|
746
|
+
try {
|
|
747
|
+
await runCommand(dir ?? process.cwd(), {
|
|
748
|
+
steps: parseInt(opts.steps, 10),
|
|
749
|
+
maxTasks: parseInt(opts.maxTasks, 10),
|
|
750
|
+
maxPremium: parseInt(opts.maxPremium, 10),
|
|
751
|
+
dryRun: opts.dryRun ?? false
|
|
752
|
+
});
|
|
753
|
+
} catch (err) {
|
|
754
|
+
fail(`Run error: ${err instanceof Error ? err.message : err}`);
|
|
755
|
+
process.exit(1);
|
|
756
|
+
}
|
|
757
|
+
});
|
|
758
|
+
}
|
|
676
759
|
async function runCommand(dir, opts) {
|
|
677
760
|
assertCopilot();
|
|
678
761
|
const projectType = detectProjectType(dir);
|
|
679
762
|
const name = detectProjectName(dir);
|
|
680
|
-
|
|
763
|
+
const mainBranch = isGitRepo(dir) ? detectMainBranch(dir) : null;
|
|
764
|
+
info(`Project: ${CYAN}${name}${RESET} (${projectType})`);
|
|
765
|
+
if (mainBranch) info(`Main branch: ${mainBranch}`);
|
|
681
766
|
const tasks = getTasksForProject(projectType).slice(0, opts.maxTasks);
|
|
682
767
|
if (tasks.length === 0) {
|
|
683
768
|
warn("No tasks found for this project type.");
|
|
@@ -685,232 +770,244 @@ async function runCommand(dir, opts) {
|
|
|
685
770
|
}
|
|
686
771
|
log(`Found ${tasks.length} tasks:`);
|
|
687
772
|
for (const t of tasks) {
|
|
688
|
-
|
|
773
|
+
log(` ${DIM}\u2022${RESET} ${t.title}`);
|
|
689
774
|
}
|
|
690
775
|
if (opts.dryRun) {
|
|
691
|
-
log(
|
|
776
|
+
log(`${DIM}(dry-run \u2014 not executing)${RESET}`);
|
|
692
777
|
return;
|
|
693
778
|
}
|
|
694
|
-
const originalBranch =
|
|
779
|
+
const originalBranch = isGitRepo(dir) ? gitCurrentBranch(dir) : null;
|
|
695
780
|
let completed = 0;
|
|
696
781
|
let premiumTotal = 0;
|
|
697
782
|
for (const task of tasks) {
|
|
783
|
+
if (premiumTotal >= opts.maxPremium) {
|
|
784
|
+
warn(`Premium request limit reached (${premiumTotal}/${opts.maxPremium}).`);
|
|
785
|
+
break;
|
|
786
|
+
}
|
|
698
787
|
log(`
|
|
699
788
|
${"\u2550".repeat(60)}`);
|
|
700
|
-
log(
|
|
789
|
+
log(`${BOLD}${CYAN}Task: ${task.title}${RESET}`);
|
|
701
790
|
log(`${"\u2550".repeat(60)}`);
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
791
|
+
const timestamp = Date.now().toString(36);
|
|
792
|
+
const random = Math.random().toString(36).substring(2, 6);
|
|
793
|
+
const branchName = `agent/fix-${completed + 1}-${timestamp}-${random}`;
|
|
794
|
+
if (mainBranch && isGitRepo(dir)) {
|
|
795
|
+
if (gitStatus(dir)) gitStash(dir);
|
|
796
|
+
gitCheckout(dir, mainBranch);
|
|
797
|
+
if (!gitCreateBranch(dir, branchName)) {
|
|
798
|
+
warn(`Could not create branch ${branchName}, continuing on current.`);
|
|
709
799
|
}
|
|
710
800
|
}
|
|
711
|
-
|
|
801
|
+
info(`Running: ${task.title}\u2026`);
|
|
712
802
|
const result = await withLock(
|
|
713
803
|
"copilot-run",
|
|
714
|
-
() => runCopilotTask(task.prompt, opts.steps)
|
|
804
|
+
() => runCopilotTask(task.prompt, opts.steps, dir)
|
|
715
805
|
);
|
|
716
|
-
|
|
806
|
+
const commits = mainBranch ? gitCountCommits(dir, mainBranch, "HEAD") : 0;
|
|
717
807
|
premiumTotal += result.premium;
|
|
718
808
|
completed++;
|
|
719
|
-
ok(`${task.title} \u2014
|
|
720
|
-
if (originalBranch &&
|
|
721
|
-
|
|
722
|
-
gitCheckout(dir, originalBranch);
|
|
723
|
-
} catch {
|
|
724
|
-
}
|
|
809
|
+
ok(`${task.title} \u2014 ${commits} commit(s), ${result.premium} premium`);
|
|
810
|
+
if (originalBranch && isGitRepo(dir)) {
|
|
811
|
+
gitCheckout(dir, mainBranch ?? originalBranch);
|
|
725
812
|
}
|
|
726
813
|
}
|
|
727
814
|
log(`
|
|
728
|
-
|
|
815
|
+
${BOLD}\u2550\u2550\u2550 Run Summary \u2550\u2550\u2550${RESET}`);
|
|
816
|
+
log(`Completed ${completed}/${tasks.length} tasks. Total premium: ${premiumTotal}`);
|
|
729
817
|
notify(`Completed ${completed} tasks`, name);
|
|
730
818
|
}
|
|
731
819
|
|
|
732
820
|
// src/commands/overnight.ts
|
|
733
|
-
import
|
|
734
|
-
import ora3 from "ora";
|
|
735
|
-
import { join as join4 } from "path";
|
|
821
|
+
import { join as join5 } from "path";
|
|
736
822
|
import { homedir as homedir3 } from "os";
|
|
823
|
+
function registerOvernightCommand(program2) {
|
|
824
|
+
program2.command("overnight [dir]").description("Run tasks continuously until a deadline").option("-u, --until <HH>", "Stop at this hour (24h format)", "07").option("-s, --steps <n>", "Max autopilot continues per task", "50").option("-c, --cooldown <n>", "Seconds between tasks", "15").option("-p, --max-premium <n>", "Max premium requests budget", "300").option("--dry-run", "Show plan without executing").action(async (dir, opts) => {
|
|
825
|
+
try {
|
|
826
|
+
await overnightCommand(dir ?? process.cwd(), {
|
|
827
|
+
until: parseInt(opts.until, 10),
|
|
828
|
+
steps: parseInt(opts.steps, 10),
|
|
829
|
+
cooldown: parseInt(opts.cooldown, 10),
|
|
830
|
+
maxPremium: parseInt(opts.maxPremium, 10),
|
|
831
|
+
dryRun: opts.dryRun ?? false
|
|
832
|
+
});
|
|
833
|
+
} catch (err) {
|
|
834
|
+
fail(`Overnight error: ${err instanceof Error ? err.message : err}`);
|
|
835
|
+
process.exit(1);
|
|
836
|
+
}
|
|
837
|
+
});
|
|
838
|
+
}
|
|
839
|
+
function isPastDeadline(untilHour) {
|
|
840
|
+
const hour = (/* @__PURE__ */ new Date()).getHours();
|
|
841
|
+
return hour >= untilHour && hour < 20;
|
|
842
|
+
}
|
|
737
843
|
async function overnightCommand(dir, opts) {
|
|
738
844
|
assertCopilot();
|
|
739
845
|
const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "").slice(0, 15);
|
|
740
|
-
const logPath =
|
|
741
|
-
homedir3(),
|
|
742
|
-
".copilot",
|
|
743
|
-
"auto-resume-logs",
|
|
744
|
-
`overnight-${ts}.log`
|
|
745
|
-
);
|
|
846
|
+
const logPath = join5(homedir3(), ".copilot", "auto-resume-logs", `overnight-${ts}.log`);
|
|
746
847
|
setLogFile(logPath);
|
|
747
|
-
const deadline = parseDeadline(opts.until);
|
|
748
848
|
const name = detectProjectName(dir);
|
|
749
849
|
const projectType = detectProjectType(dir);
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
850
|
+
const mainBranch = isGitRepo(dir) ? detectMainBranch(dir) : null;
|
|
851
|
+
info(`Overnight runner for ${CYAN}${name}${RESET} (${projectType})`);
|
|
852
|
+
info(`Deadline: ${String(opts.until).padStart(2, "0")}:00`);
|
|
853
|
+
info(`Max premium: ${opts.maxPremium}, Steps: ${opts.steps}`);
|
|
854
|
+
info(`Log: ${logPath}`);
|
|
855
|
+
const tasks = getTasksForProject(projectType);
|
|
754
856
|
if (opts.dryRun) {
|
|
755
|
-
const tasks2 = getTasksForProject(projectType);
|
|
756
857
|
log(`
|
|
757
|
-
Would run ${
|
|
758
|
-
for (const t of
|
|
858
|
+
Would run ${tasks.length} tasks:`);
|
|
859
|
+
for (const t of tasks) log(` ${DIM}\u2022${RESET} ${t.title}`);
|
|
759
860
|
return;
|
|
760
861
|
}
|
|
761
|
-
const
|
|
862
|
+
const existingSession = findLatestIncomplete();
|
|
863
|
+
if (existingSession && validateSession(existingSession)) {
|
|
864
|
+
info(`Found incomplete session: ${existingSession}`);
|
|
865
|
+
const pid = findPidForSession(existingSession);
|
|
866
|
+
if (pid) {
|
|
867
|
+
info(`Waiting for running copilot (PID ${pid})...`);
|
|
868
|
+
await waitForExit(pid);
|
|
869
|
+
}
|
|
870
|
+
if (!hasTaskComplete(existingSession) && !isPastDeadline(opts.until)) {
|
|
871
|
+
info("Resuming incomplete session...");
|
|
872
|
+
const cwd = getSessionCwd(existingSession) || dir;
|
|
873
|
+
await runCopilotResume(
|
|
874
|
+
existingSession,
|
|
875
|
+
opts.steps,
|
|
876
|
+
"Continue remaining work. Complete the task.",
|
|
877
|
+
cwd
|
|
878
|
+
);
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
const originalBranch = isGitRepo(dir) ? gitCurrentBranch(dir) : null;
|
|
762
882
|
let taskIdx = 0;
|
|
763
883
|
let totalPremium = 0;
|
|
764
|
-
let
|
|
765
|
-
|
|
766
|
-
while (Date.now() < deadline) {
|
|
884
|
+
let totalCommits = 0;
|
|
885
|
+
while (!isPastDeadline(opts.until) && taskIdx < tasks.length) {
|
|
767
886
|
if (totalPremium >= opts.maxPremium) {
|
|
768
887
|
warn(`Premium budget exhausted: ${totalPremium}/${opts.maxPremium}`);
|
|
769
888
|
break;
|
|
770
889
|
}
|
|
771
890
|
const task = tasks[taskIdx % tasks.length];
|
|
772
|
-
cycle++;
|
|
773
891
|
taskIdx++;
|
|
774
892
|
log(`
|
|
775
893
|
${"\u2550".repeat(60)}`);
|
|
776
|
-
log(
|
|
777
|
-
|
|
778
|
-
);
|
|
779
|
-
log(`Time remaining: ${msToHuman(deadline - Date.now())}`);
|
|
894
|
+
log(`${BOLD}${CYAN}[${(/* @__PURE__ */ new Date()).toLocaleTimeString()}] Task ${taskIdx}: ${task.title}${RESET}`);
|
|
895
|
+
log(`${DIM}Premium: ${totalPremium}/${opts.maxPremium}${RESET}`);
|
|
780
896
|
log(`${"\u2550".repeat(60)}`);
|
|
781
|
-
const
|
|
897
|
+
const timestamp = Date.now().toString(36);
|
|
898
|
+
const random = Math.random().toString(36).substring(2, 6);
|
|
899
|
+
const branchName = `agent/overnight-${taskIdx}-${timestamp}-${random}`;
|
|
900
|
+
if (mainBranch && isGitRepo(dir)) {
|
|
901
|
+
gitStash(dir);
|
|
902
|
+
gitCheckout(dir, mainBranch);
|
|
903
|
+
gitCreateBranch(dir, branchName);
|
|
904
|
+
}
|
|
905
|
+
info(`Running: ${task.title}\u2026`);
|
|
782
906
|
try {
|
|
783
907
|
const result = await withLock(
|
|
784
908
|
"copilot-overnight",
|
|
785
|
-
() => runCopilotTask(task.prompt, opts.steps)
|
|
909
|
+
() => runCopilotTask(task.prompt, opts.steps, dir)
|
|
786
910
|
);
|
|
787
|
-
|
|
911
|
+
const commits = mainBranch ? gitCountCommits(dir, mainBranch, "HEAD") : 0;
|
|
788
912
|
totalPremium += result.premium;
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
`${
|
|
792
|
-
|
|
913
|
+
totalCommits += commits;
|
|
914
|
+
if (commits > 0) {
|
|
915
|
+
ok(`${commits} commit(s) on ${branchName}`);
|
|
916
|
+
} else {
|
|
917
|
+
log(`${DIM}No commits on ${branchName}${RESET}`);
|
|
918
|
+
}
|
|
793
919
|
} catch (err) {
|
|
794
|
-
spinner.stop();
|
|
795
920
|
fail(`Task failed: ${err}`);
|
|
796
921
|
}
|
|
797
|
-
if (
|
|
798
|
-
|
|
799
|
-
await sleep3(3e4);
|
|
922
|
+
if (mainBranch && isGitRepo(dir)) {
|
|
923
|
+
gitCheckout(dir, mainBranch);
|
|
800
924
|
}
|
|
925
|
+
if (!isPastDeadline(opts.until)) {
|
|
926
|
+
info(`Cooldown ${opts.cooldown}s\u2026`);
|
|
927
|
+
await sleep3(opts.cooldown * 1e3);
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
if (originalBranch && isGitRepo(dir)) {
|
|
931
|
+
gitCheckout(dir, originalBranch);
|
|
801
932
|
}
|
|
802
|
-
const summary = `Overnight done
|
|
803
|
-
|
|
933
|
+
const summary = `Overnight done \u2014 ${taskIdx} tasks, ${totalCommits} commits, ${totalPremium} premium.`;
|
|
934
|
+
ok(summary);
|
|
804
935
|
notify(summary, name);
|
|
805
936
|
}
|
|
806
|
-
function parseDeadline(hhmm) {
|
|
807
|
-
const [h, m] = hhmm.split(":").map(Number);
|
|
808
|
-
const now = /* @__PURE__ */ new Date();
|
|
809
|
-
const target = new Date(now);
|
|
810
|
-
target.setHours(h, m, 0, 0);
|
|
811
|
-
if (target <= now) target.setDate(target.getDate() + 1);
|
|
812
|
-
return target.getTime();
|
|
813
|
-
}
|
|
814
|
-
function msToHuman(ms) {
|
|
815
|
-
const h = Math.floor(ms / 36e5);
|
|
816
|
-
const m = Math.floor(ms % 36e5 / 6e4);
|
|
817
|
-
return `${h}h ${m}m`;
|
|
818
|
-
}
|
|
819
937
|
function sleep3(ms) {
|
|
820
938
|
return new Promise((r) => setTimeout(r, ms));
|
|
821
939
|
}
|
|
822
940
|
|
|
823
941
|
// src/commands/research.ts
|
|
824
|
-
import
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
},
|
|
830
|
-
{
|
|
831
|
-
title: "Performance review",
|
|
832
|
-
prompt: "Profile the application for performance bottlenecks. Check startup time, memory usage, and hot paths. Suggest optimizations with benchmarks."
|
|
833
|
-
},
|
|
834
|
-
{
|
|
835
|
-
title: "Architecture review",
|
|
836
|
-
prompt: "Review the project architecture. Check for code smells, circular dependencies, and coupling issues. Suggest improvements following clean architecture."
|
|
837
|
-
},
|
|
838
|
-
{
|
|
839
|
-
title: "Accessibility audit",
|
|
840
|
-
prompt: "Audit the UI for accessibility issues. Check color contrast, screen reader support, and keyboard navigation. Create a report."
|
|
841
|
-
},
|
|
842
|
-
{
|
|
843
|
-
title: "Best practices",
|
|
844
|
-
prompt: "Compare the codebase against current best practices for this framework/language. Identify gaps and suggest improvements."
|
|
845
|
-
}
|
|
846
|
-
];
|
|
847
|
-
async function researchCommand(topic, opts) {
|
|
848
|
-
assertCopilot();
|
|
849
|
-
if (topic) {
|
|
850
|
-
log(`Research topic: ${chalk5.cyan(topic)}`);
|
|
851
|
-
const result = await withLock(
|
|
852
|
-
"copilot-research",
|
|
853
|
-
() => runCopilotTask(
|
|
854
|
-
`Research the following topic and create a detailed report: ${topic}`,
|
|
855
|
-
opts.steps
|
|
856
|
-
)
|
|
857
|
-
);
|
|
858
|
-
ok(`Research complete \u2014 premium: ${result.premium}`);
|
|
859
|
-
notify("Research complete", topic.slice(0, 30));
|
|
860
|
-
return;
|
|
861
|
-
}
|
|
862
|
-
log("Running predefined research tasks\u2026");
|
|
863
|
-
for (const r of RESEARCH_PROMPTS) {
|
|
864
|
-
log(`
|
|
865
|
-
${chalk5.bold(r.title)}`);
|
|
942
|
+
import { existsSync as existsSync5, copyFileSync, mkdirSync as mkdirSync3 } from "fs";
|
|
943
|
+
import { join as join6, resolve as resolve3 } from "path";
|
|
944
|
+
import { homedir as homedir4 } from "os";
|
|
945
|
+
function registerResearchCommand(program2) {
|
|
946
|
+
program2.command("research [project]").description("Research improvements or a specific topic").option("-s, --steps <n>", "Max autopilot continues", "50").action(async (project, opts) => {
|
|
866
947
|
try {
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
);
|
|
871
|
-
ok(`${r.title} \u2014 premium: ${result.premium}`);
|
|
948
|
+
await researchCommand(project ?? process.cwd(), {
|
|
949
|
+
steps: parseInt(opts.steps, 10)
|
|
950
|
+
});
|
|
872
951
|
} catch (err) {
|
|
873
|
-
fail(
|
|
952
|
+
fail(`Research error: ${err instanceof Error ? err.message : err}`);
|
|
953
|
+
process.exit(1);
|
|
874
954
|
}
|
|
875
|
-
}
|
|
876
|
-
|
|
955
|
+
});
|
|
956
|
+
}
|
|
957
|
+
function buildResearchPrompt(projectType, projectName) {
|
|
958
|
+
return `You are a senior software architect. Analyze this ${projectType} project "${projectName}" thoroughly.
|
|
959
|
+
|
|
960
|
+
Research and produce a file called RESEARCH-PROPOSALS.md with:
|
|
961
|
+
|
|
962
|
+
1. **Architecture Assessment** \u2014 Current architecture, patterns used, strengths and weaknesses
|
|
963
|
+
2. **Code Quality Report** \u2014 Common issues, anti-patterns, technical debt areas
|
|
964
|
+
3. **Security Audit** \u2014 Potential vulnerabilities, dependency risks, configuration issues
|
|
965
|
+
4. **Performance Analysis** \u2014 Bottlenecks, optimization opportunities, resource usage
|
|
966
|
+
5. **Testing Gap Analysis** \u2014 Untested areas, test quality, coverage recommendations
|
|
967
|
+
6. **Improvement Proposals** \u2014 Prioritized list of actionable improvements with effort estimates
|
|
968
|
+
|
|
969
|
+
For each proposal, include:
|
|
970
|
+
- Priority (P0/P1/P2)
|
|
971
|
+
- Estimated effort (hours)
|
|
972
|
+
- Impact description
|
|
973
|
+
- Suggested implementation approach
|
|
974
|
+
|
|
975
|
+
Write RESEARCH-PROPOSALS.md in the project root.`;
|
|
976
|
+
}
|
|
977
|
+
async function researchCommand(dir, opts) {
|
|
978
|
+
assertCopilot();
|
|
979
|
+
const projectDir = resolve3(dir);
|
|
980
|
+
const projectType = detectProjectType(projectDir);
|
|
981
|
+
const projectName = detectProjectName(projectDir);
|
|
982
|
+
info(`Researching: ${CYAN}${projectName}${RESET} (${projectType})`);
|
|
983
|
+
const prompt = buildResearchPrompt(projectType, projectName);
|
|
984
|
+
const result = await withLock(
|
|
985
|
+
"copilot-research",
|
|
986
|
+
() => runCopilotTask(prompt, opts.steps, projectDir)
|
|
987
|
+
);
|
|
988
|
+
log(`Copilot exited with code ${result.exitCode}`);
|
|
989
|
+
const proposalsFile = join6(projectDir, "RESEARCH-PROPOSALS.md");
|
|
990
|
+
if (existsSync5(proposalsFile)) {
|
|
991
|
+
ok("RESEARCH-PROPOSALS.md generated.");
|
|
992
|
+
const backupDir = join6(homedir4(), ".copilot", "research-reports");
|
|
993
|
+
mkdirSync3(backupDir, { recursive: true });
|
|
994
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
995
|
+
const backupFile = join6(backupDir, `${projectName}-${timestamp}.md`);
|
|
996
|
+
copyFileSync(proposalsFile, backupFile);
|
|
997
|
+
ok(`Backup saved: ${backupFile}`);
|
|
998
|
+
} else {
|
|
999
|
+
warn("RESEARCH-PROPOSALS.md was not generated. Check copilot output.");
|
|
1000
|
+
}
|
|
1001
|
+
notify("Research complete", projectName);
|
|
877
1002
|
}
|
|
878
1003
|
|
|
879
1004
|
// src/index.ts
|
|
880
1005
|
var program = new Command();
|
|
881
|
-
program.name("copilot-agent").description("Autonomous GitHub Copilot CLI agent \u2014 auto-resume, task discovery, overnight
|
|
882
|
-
program
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
});
|
|
888
|
-
program.command("watch [session-id]").description("Watch a session and auto-resume when it stops").option("-s, --steps <n>", "Max autopilot continues per resume", "50").option("-r, --max-resumes <n>", "Max number of resumes", "20").option("-m, --message <msg>", "Message to send on resume").action(async (sid, opts) => {
|
|
889
|
-
await watchCommand(sid, {
|
|
890
|
-
steps: parseInt(opts.steps),
|
|
891
|
-
maxResumes: parseInt(opts.maxResumes),
|
|
892
|
-
message: opts.message
|
|
893
|
-
});
|
|
894
|
-
});
|
|
895
|
-
program.command("run [dir]").description("Discover and fix issues in a project").option("-s, --steps <n>", "Max autopilot continues per task", "30").option("-t, --max-tasks <n>", "Max number of tasks to run", "5").option("--dry-run", "Show tasks without executing").action(async (dir, opts) => {
|
|
896
|
-
await runCommand(dir ?? process.cwd(), {
|
|
897
|
-
steps: parseInt(opts.steps),
|
|
898
|
-
maxTasks: parseInt(opts.maxTasks),
|
|
899
|
-
dryRun: opts.dryRun ?? false
|
|
900
|
-
});
|
|
901
|
-
});
|
|
902
|
-
program.command("overnight [dir]").description("Run tasks continuously until a deadline").option("-u, --until <HH:MM>", "Deadline time (24h format)", "07:00").option("-s, --steps <n>", "Max autopilot continues per task", "50").option("-p, --max-premium <n>", "Max premium requests budget", "300").option("--dry-run", "Show plan without executing").action(async (dir, opts) => {
|
|
903
|
-
await overnightCommand(dir ?? process.cwd(), {
|
|
904
|
-
until: opts.until,
|
|
905
|
-
steps: parseInt(opts.steps),
|
|
906
|
-
maxPremium: parseInt(opts.maxPremium),
|
|
907
|
-
dryRun: opts.dryRun ?? false
|
|
908
|
-
});
|
|
909
|
-
});
|
|
910
|
-
program.command("research [topic]").description("Research improvements or a specific topic").option("-s, --steps <n>", "Max autopilot continues", "30").action(async (topic, opts) => {
|
|
911
|
-
await researchCommand(topic, {
|
|
912
|
-
steps: parseInt(opts.steps)
|
|
913
|
-
});
|
|
914
|
-
});
|
|
1006
|
+
program.name("copilot-agent").version("0.3.0").description("Autonomous GitHub Copilot CLI agent \u2014 auto-resume, task discovery, overnight runs");
|
|
1007
|
+
registerStatusCommand(program);
|
|
1008
|
+
registerWatchCommand(program);
|
|
1009
|
+
registerRunCommand(program);
|
|
1010
|
+
registerOvernightCommand(program);
|
|
1011
|
+
registerResearchCommand(program);
|
|
915
1012
|
program.parse();
|
|
916
1013
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/commands/status.ts","../src/lib/session.ts","../src/lib/process.ts","../src/lib/logger.ts","../src/lib/colors.ts","../src/commands/watch.ts","../src/commands/run.ts","../src/lib/detect.ts","../src/lib/tasks.ts","../src/lib/lock.ts","../src/lib/git.ts","../src/commands/overnight.ts","../src/commands/research.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { Command } from \"commander\";\nimport { statusCommand } from \"./commands/status.js\";\nimport { watchCommand } from \"./commands/watch.js\";\nimport { runCommand } from \"./commands/run.js\";\nimport { overnightCommand } from \"./commands/overnight.js\";\nimport { researchCommand } from \"./commands/research.js\";\n\nconst program = new Command();\n\nprogram\n .name(\"copilot-agent\")\n .description(\"Autonomous GitHub Copilot CLI agent — auto-resume, task discovery, overnight runner\")\n .version(\"0.1.0\");\n\nprogram\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) sessions\")\n .action(async (opts) => {\n await statusCommand({\n limit: parseInt(opts.limit),\n active: opts.active ?? false,\n });\n });\n\nprogram\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\", \"50\")\n .option(\"-r, --max-resumes <n>\", \"Max number of resumes\", \"20\")\n .option(\"-m, --message <msg>\", \"Message to send on resume\")\n .action(async (sid, opts) => {\n await watchCommand(sid, {\n steps: parseInt(opts.steps),\n maxResumes: parseInt(opts.maxResumes),\n message: opts.message,\n });\n });\n\nprogram\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(\"--dry-run\", \"Show tasks without executing\")\n .action(async (dir, opts) => {\n await runCommand(dir ?? process.cwd(), {\n steps: parseInt(opts.steps),\n maxTasks: parseInt(opts.maxTasks),\n dryRun: opts.dryRun ?? false,\n });\n });\n\nprogram\n .command(\"overnight [dir]\")\n .description(\"Run tasks continuously until a deadline\")\n .option(\"-u, --until <HH:MM>\", \"Deadline time (24h format)\", \"07:00\")\n .option(\"-s, --steps <n>\", \"Max autopilot continues per task\", \"50\")\n .option(\"-p, --max-premium <n>\", \"Max premium requests budget\", \"300\")\n .option(\"--dry-run\", \"Show plan without executing\")\n .action(async (dir, opts) => {\n await overnightCommand(dir ?? process.cwd(), {\n until: opts.until,\n steps: parseInt(opts.steps),\n maxPremium: parseInt(opts.maxPremium),\n dryRun: opts.dryRun ?? false,\n });\n });\n\nprogram\n .command(\"research [topic]\")\n .description(\"Research improvements or a specific topic\")\n .option(\"-s, --steps <n>\", \"Max autopilot continues\", \"30\")\n .action(async (topic, opts) => {\n await researchCommand(topic, {\n steps: parseInt(opts.steps),\n });\n });\n\nprogram.parse();\n","import chalk from \"chalk\";\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\";\n\nexport interface StatusOptions {\n limit: number;\n active: boolean;\n}\n\nexport async function statusCommand(opts: StatusOptions): Promise<void> {\n if (opts.active) {\n return showActive();\n }\n showRecent(opts.limit);\n}\n\nasync function showActive(): Promise<void> {\n const procs = await findCopilotProcesses();\n if (procs.length === 0) {\n log(\"No active copilot processes.\");\n return;\n }\n\n console.log(\n chalk.bold(\n `\\n${\"PID\".padEnd(8)} ${\"Session\".padEnd(40)} ${\"Command\".slice(0, 60)}`,\n ),\n );\n console.log(\"─\".repeat(108));\n\n for (const p of procs) {\n console.log(\n `${String(p.pid).padEnd(8)} ${(p.sessionId ?? \"—\").padEnd(40)} ${(p.command ?? \"\").slice(0, 60)}`,\n );\n }\n console.log();\n}\n\nfunction showRecent(limit: number): void {\n const sessions = listSessions(limit);\n if (sessions.length === 0) {\n log(\"No sessions found.\");\n return;\n }\n\n console.log(\n chalk.bold(\n `\\n${\"Status\".padEnd(10)} ${\"Premium\".padEnd(10)} ${\"Last Event\".padEnd(25)} ${\"Summary\".padEnd(40)} ${\"ID\"}`,\n ),\n );\n console.log(\"─\".repeat(120));\n\n for (const s of sessions) {\n const done = hasTaskComplete(s.id);\n const status = done\n ? chalk.green(\"✅ done\")\n : chalk.yellow(\"⏸️ stopped\");\n const premium = String(getSessionPremium(s.id));\n const lastEvt = getLastEvent(s.id);\n const summary = (s.summary ?? \"—\").slice(0, 38);\n\n console.log(\n `${status.padEnd(20)} ${premium.padEnd(10)} ${lastEvt.padEnd(25)} ${summary.padEnd(40)} ${chalk.dim(s.id)}`,\n );\n }\n console.log();\n}\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\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","import { execSync, spawn } from 'node:child_process';\nimport { getLatestSessionId, getSessionPremium } from './session.js';\nimport { fail } from './logger.js';\n\nexport interface CopilotProcess {\n pid: number;\n command: string;\n sessionId?: 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 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 cmd = match[2];\n const sidMatch = cmd.match(/resume[= ]+([a-f0-9-]{36})/);\n results.push({\n pid: parseInt(match[1], 10),\n command: cmd,\n sessionId: sidMatch?.[1],\n });\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\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 function runCopilot(\n args: string[],\n options?: { cwd?: string },\n): Promise<CopilotResult> {\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 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): 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 });\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 chalk from \"chalk\";\nimport ora from \"ora\";\nimport {\n validateSession,\n hasTaskComplete,\n getSessionSummary,\n getLastEvent,\n findLatestIncomplete,\n} from \"../lib/session.js\";\nimport {\n findPidForSession,\n waitForExit,\n runCopilotResume,\n assertCopilot,\n} from \"../lib/process.js\";\nimport { log, ok, warn, fail, notify } from \"../lib/logger.js\";\n\nexport interface WatchOptions {\n steps: number;\n maxResumes: number;\n message?: string;\n}\n\nexport async function watchCommand(\n sid: string | undefined,\n opts: WatchOptions,\n): 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 log(`Auto-detected incomplete session: ${chalk.cyan(sid)}`);\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 = await findPidForSession(sid);\n\n if (pid) {\n const spinner = ora(\n `Watching PID ${pid} for session ${chalk.cyan(sid.slice(0, 8))}…`,\n ).start();\n const exited = await waitForExit(pid);\n spinner.stop();\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(\n `Task complete! Summary: ${getSessionSummary(sid) || \"none\"}`,\n );\n notify(\"Task completed!\", `Session ${sid.slice(0, 8)}`);\n return;\n }\n\n // Interrupted — resume\n resumes++;\n log(\n `Session interrupted (${getLastEvent(sid)}). Resume ${resumes}/${opts.maxResumes}…`,\n );\n\n const result = await runCopilotResume(sid, opts.steps, opts.message);\n if (result.sessionId && result.sessionId !== sid) {\n log(`New session created: ${chalk.cyan(result.sessionId)}`);\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 chalk from \"chalk\";\nimport ora from \"ora\";\nimport { detectProjectType, detectProjectName } from \"../lib/detect.js\";\nimport { getTasksForProject } from \"../lib/tasks.js\";\nimport { runCopilotTask, assertCopilot } from \"../lib/process.js\";\nimport { withLock } from \"../lib/lock.js\";\nimport { gitBranch, gitStatus, gitStash, gitCheckout, gitIsRepo } from \"../lib/git.js\";\nimport { log, ok, warn, fail, notify } from \"../lib/logger.js\";\n\nexport interface RunOptions {\n steps: number;\n maxTasks: number;\n dryRun: boolean;\n}\n\nexport async function runCommand(\n dir: string,\n opts: RunOptions,\n): Promise<void> {\n assertCopilot();\n\n const projectType = detectProjectType(dir);\n const name = detectProjectName(dir);\n log(`Project: ${chalk.cyan(name)} (${projectType})`);\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 console.log(` ${chalk.dim(\"•\")} ${t.title}`);\n }\n\n if (opts.dryRun) {\n log(chalk.dim(\"(dry-run — not executing)\"));\n return;\n }\n\n const originalBranch = gitIsRepo(dir) ? gitBranch(dir) : null;\n let completed = 0;\n let premiumTotal = 0;\n\n for (const task of tasks) {\n log(`\\n${\"═\".repeat(60)}`);\n log(`Task: ${chalk.bold(task.title)}`);\n log(`${\"═\".repeat(60)}`);\n\n // Create a feature branch for safety\n if (originalBranch && gitIsRepo(dir)) {\n const branch = `copilot-agent/${task.title.toLowerCase().replace(/[^a-z0-9]+/g, \"-\")}`;\n try {\n if (gitStatus(dir)) gitStash(dir);\n gitCheckout(dir, branch);\n } catch (e) {\n warn(`Could not create branch ${branch}, continuing on current.`);\n }\n }\n\n const spinner = ora(`Running: ${task.title}…`).start();\n\n const result = await withLock(\"copilot-run\", () =>\n runCopilotTask(task.prompt, opts.steps),\n );\n\n spinner.stop();\n\n premiumTotal += result.premium;\n completed++;\n ok(`${task.title} — exit ${result.exitCode}, premium: ${result.premium}`);\n\n if (originalBranch && gitIsRepo(dir)) {\n try {\n gitCheckout(dir, originalBranch);\n } catch {\n /* stay on feature branch */\n }\n }\n }\n\n log(`\\nCompleted ${completed}/${tasks.length} tasks. Total premium: ${premiumTotal}`);\n notify(`Completed ${completed} tasks`, name);\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 { execSync } from \"node:child_process\";\n\nexport function gitBranch(cwd: string): string {\n try {\n return execSync(\"git rev-parse --abbrev-ref HEAD\", {\n cwd,\n encoding: \"utf-8\",\n }).trim();\n } catch {\n return \"unknown\";\n }\n}\n\nexport function gitStatus(cwd: string): string {\n try {\n return execSync(\"git status --porcelain\", {\n cwd,\n encoding: \"utf-8\",\n }).trim();\n } catch {\n return \"\";\n }\n}\n\nexport function gitStash(cwd: string): void {\n execSync(\"git stash push -m 'copilot-agent auto-stash'\", {\n cwd,\n stdio: \"ignore\",\n });\n}\n\nexport function gitCheckout(cwd: string, branch: string): void {\n execSync(`git checkout -B ${branch}`, { cwd, stdio: \"ignore\" });\n}\n\nexport function gitIsRepo(cwd: string): boolean {\n try {\n execSync(\"git rev-parse --git-dir\", { cwd, stdio: \"ignore\" });\n return true;\n } catch {\n return false;\n }\n}\n","import chalk from \"chalk\";\nimport ora from \"ora\";\nimport { detectProjectType, detectProjectName } from \"../lib/detect.js\";\nimport { getTasksForProject } from \"../lib/tasks.js\";\nimport { runCopilotTask, assertCopilot } from \"../lib/process.js\";\nimport { withLock } from \"../lib/lock.js\";\nimport { log, ok, warn, fail, setLogFile, notify } from \"../lib/logger.js\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\n\nexport interface OvernightOptions {\n until: string; // HH:MM\n steps: number;\n maxPremium: number;\n dryRun: boolean;\n}\n\nexport async function overnightCommand(\n dir: string,\n opts: OvernightOptions,\n): Promise<void> {\n assertCopilot();\n\n const ts = new Date().toISOString().replace(/[:.]/g, \"\").slice(0, 15);\n const logPath = join(\n homedir(),\n \".copilot\",\n \"auto-resume-logs\",\n `overnight-${ts}.log`,\n );\n setLogFile(logPath);\n\n const deadline = parseDeadline(opts.until);\n const name = detectProjectName(dir);\n const projectType = detectProjectType(dir);\n\n log(`Overnight runner for ${chalk.cyan(name)} (${projectType})`);\n log(`Deadline: ${opts.until} (${msToHuman(deadline - Date.now())} from now)`);\n log(`Max premium: ${opts.maxPremium}, Steps: ${opts.steps}`);\n log(`Log: ${logPath}`);\n\n if (opts.dryRun) {\n const tasks = getTasksForProject(projectType);\n log(`\\nWould run ${tasks.length} tasks:`);\n for (const t of tasks) console.log(` ${chalk.dim(\"•\")} ${t.title}`);\n return;\n }\n\n const tasks = getTasksForProject(projectType);\n let taskIdx = 0;\n let totalPremium = 0;\n let completedTasks = 0;\n let cycle = 0;\n\n while (Date.now() < deadline) {\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 cycle++;\n taskIdx++;\n\n log(`\\n${\"═\".repeat(60)}`);\n log(\n `Cycle ${cycle} | Task: ${chalk.bold(task.title)} | Premium: ${totalPremium}/${opts.maxPremium}`,\n );\n log(`Time remaining: ${msToHuman(deadline - Date.now())}`);\n log(`${\"═\".repeat(60)}`);\n\n const spinner = ora(`Running: ${task.title}…`).start();\n\n try {\n const result = await withLock(\"copilot-overnight\", () =>\n runCopilotTask(task.prompt, opts.steps),\n );\n spinner.stop();\n\n totalPremium += result.premium;\n completedTasks++;\n ok(\n `${task.title} — exit ${result.exitCode}, premium: ${result.premium}`,\n );\n } catch (err) {\n spinner.stop();\n fail(`Task failed: ${err}`);\n }\n\n // Cooldown between tasks\n if (Date.now() < deadline) {\n log(\"Cooldown 30s…\");\n await sleep(30_000);\n }\n }\n\n const summary = `Overnight done. ${completedTasks} tasks, ${totalPremium} premium.`;\n log(summary);\n notify(summary, name);\n}\n\nfunction parseDeadline(hhmm: string): number {\n const [h, m] = hhmm.split(\":\").map(Number);\n const now = new Date();\n const target = new Date(now);\n target.setHours(h, m, 0, 0);\n if (target <= now) target.setDate(target.getDate() + 1);\n return target.getTime();\n}\n\nfunction msToHuman(ms: number): string {\n const h = Math.floor(ms / 3_600_000);\n const m = Math.floor((ms % 3_600_000) / 60_000);\n return `${h}h ${m}m`;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((r) => setTimeout(r, ms));\n}\n","import chalk from \"chalk\";\nimport { runCopilotTask, assertCopilot } from \"../lib/process.js\";\nimport { withLock } from \"../lib/lock.js\";\nimport { log, ok, fail, notify } from \"../lib/logger.js\";\n\nexport interface ResearchOptions {\n steps: number;\n}\n\nconst RESEARCH_PROMPTS = [\n {\n title: \"Dependency updates\",\n prompt:\n \"Research the latest versions of all dependencies. Check changelogs for breaking changes. Create a summary of what can be safely updated.\",\n },\n {\n title: \"Performance review\",\n prompt:\n \"Profile the application for performance bottlenecks. Check startup time, memory usage, and hot paths. Suggest optimizations with benchmarks.\",\n },\n {\n title: \"Architecture review\",\n prompt:\n \"Review the project architecture. Check for code smells, circular dependencies, and coupling issues. Suggest improvements following clean architecture.\",\n },\n {\n title: \"Accessibility audit\",\n prompt:\n \"Audit the UI for accessibility issues. Check color contrast, screen reader support, and keyboard navigation. Create a report.\",\n },\n {\n title: \"Best practices\",\n prompt:\n \"Compare the codebase against current best practices for this framework/language. Identify gaps and suggest improvements.\",\n },\n];\n\nexport async function researchCommand(\n topic: string | undefined,\n opts: ResearchOptions,\n): Promise<void> {\n assertCopilot();\n\n if (topic) {\n log(`Research topic: ${chalk.cyan(topic)}`);\n const result = await withLock(\"copilot-research\", () =>\n runCopilotTask(\n `Research the following topic and create a detailed report: ${topic}`,\n opts.steps,\n ),\n );\n ok(`Research complete — premium: ${result.premium}`);\n notify(\"Research complete\", topic.slice(0, 30));\n return;\n }\n\n log(\"Running predefined research tasks…\");\n for (const r of RESEARCH_PROMPTS) {\n log(`\\n${chalk.bold(r.title)}`);\n try {\n const result = await withLock(\"copilot-research\", () =>\n runCopilotTask(r.prompt, opts.steps),\n );\n ok(`${r.title} — premium: ${result.premium}`);\n } catch (err) {\n fail(`${r.title} failed: ${err}`);\n }\n }\n notify(\"All research tasks complete\");\n}\n"],"mappings":"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","names":["execSync","execSync","resolve","chalk","chalk","sleep","chalk","ora","existsSync","readFileSync","readdirSync","join","resolve","execSync","mkdirSync","readFileSync","join","homedir","execSync","chalk","ora","chalk","ora","join","homedir","chalk","tasks","ora","sleep","chalk","chalk"]}
|
|
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"],"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';\n\nconst program = new Command();\n\nprogram\n .name('copilot-agent')\n .version('0.3.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);\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\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","import { execSync, spawn } from 'node:child_process';\nimport { getLatestSessionId, getSessionPremium } from './session.js';\nimport { log, warn, fail } from './logger.js';\n\nexport interface CopilotProcess {\n pid: number;\n command: string;\n sessionId?: 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 results.push({\n pid,\n command: cmd,\n sessionId: sidMatch?.[1],\n });\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 other copilot processes are running.\n * Prevents race conditions from concurrent copilot instances.\n */\nexport async function waitForAllCopilotToFinish(\n timeoutMs = 14_400_000,\n pollMs = 10_000,\n): Promise<void> {\n const start = Date.now();\n let warned = false;\n while (Date.now() - start < timeoutMs) {\n const procs = findCopilotProcesses();\n if (procs.length === 0) return;\n if (!warned) {\n warn(`Waiting for ${procs.length} copilot process(es) to finish before starting...`);\n for (const p of procs) {\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 processes to finish');\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 },\n): Promise<CopilotResult> {\n // SAFETY: Wait for all existing copilot processes to finish first\n await waitForAllCopilotToFinish();\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): 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 });\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 } from 'node:fs';\nimport { join } 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","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 } 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 .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 });\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}\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 const result = await withLock('copilot-run', () =>\n runCopilotTask(task.prompt, opts.steps, dir),\n );\n\n const commits = mainBranch ? gitCountCommits(dir, mainBranch, 'HEAD') : 0;\n premiumTotal += result.premium;\n completed++;\n ok(`${task.title} — ${commits} commit(s), ${result.premium} premium`);\n\n if (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, waitForExit, runCopilotResume } from '../lib/process.js';\nimport { withLock } from '../lib/lock.js';\nimport { isGitRepo, gitCurrentBranch, gitStash, gitCheckout, gitCreateBranch, gitCountCommits } 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 .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 });\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}\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 try {\n const result = await withLock('copilot-overnight', () =>\n runCopilotTask(task.prompt, opts.steps, dir),\n );\n\n const commits = mainBranch ? gitCountCommits(dir, 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 if (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"],"mappings":"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","names":["execSync","execSync","resolve","program","program","sleep","existsSync","readFileSync","readdirSync","join","resolve","execSync","mkdirSync","readFileSync","join","homedir","existsSync","join","execSync","program","join","homedir","program","join","homedir","sleep","existsSync","mkdirSync","join","resolve","homedir","program","resolve","join","existsSync","homedir","mkdirSync"]}
|