copilot-agent 0.12.0 → 1.0.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 +55 -0
- package/dist/index.js +693 -13
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -639,7 +639,7 @@ async function runCopilot(args, options) {
|
|
|
639
639
|
if (!options?.useWorktree) {
|
|
640
640
|
await waitForAgentInDir(dir, "copilot");
|
|
641
641
|
}
|
|
642
|
-
return new Promise((
|
|
642
|
+
return new Promise((resolve8) => {
|
|
643
643
|
const child = spawn("copilot", args, {
|
|
644
644
|
cwd: options?.cwd,
|
|
645
645
|
stdio: "inherit",
|
|
@@ -649,10 +649,10 @@ async function runCopilot(args, options) {
|
|
|
649
649
|
await sleep(3e3);
|
|
650
650
|
const sid = getLatestSessionId();
|
|
651
651
|
const premium = sid ? getSessionPremium(sid) : 0;
|
|
652
|
-
|
|
652
|
+
resolve8({ exitCode: code ?? 1, sessionId: sid, premium });
|
|
653
653
|
});
|
|
654
654
|
child.on("error", () => {
|
|
655
|
-
|
|
655
|
+
resolve8({ exitCode: 1, sessionId: null, premium: 0 });
|
|
656
656
|
});
|
|
657
657
|
});
|
|
658
658
|
}
|
|
@@ -685,7 +685,7 @@ async function runClaude(args, options) {
|
|
|
685
685
|
if (!options?.useWorktree) {
|
|
686
686
|
await waitForAgentInDir(dir, "claude");
|
|
687
687
|
}
|
|
688
|
-
return new Promise((
|
|
688
|
+
return new Promise((resolve8) => {
|
|
689
689
|
const child = spawn("claude", args, {
|
|
690
690
|
cwd: options?.cwd,
|
|
691
691
|
stdio: "inherit",
|
|
@@ -694,10 +694,10 @@ async function runClaude(args, options) {
|
|
|
694
694
|
child.on("close", async (code) => {
|
|
695
695
|
await sleep(2e3);
|
|
696
696
|
const sid = getLatestClaudeSessionId(options?.cwd);
|
|
697
|
-
|
|
697
|
+
resolve8({ exitCode: code ?? 1, sessionId: sid, premium: 0 });
|
|
698
698
|
});
|
|
699
699
|
child.on("error", () => {
|
|
700
|
-
|
|
700
|
+
resolve8({ exitCode: 1, sessionId: null, premium: 0 });
|
|
701
701
|
});
|
|
702
702
|
});
|
|
703
703
|
}
|
|
@@ -1232,9 +1232,9 @@ async function runCommand(dir, opts) {
|
|
|
1232
1232
|
${"\u2550".repeat(60)}`);
|
|
1233
1233
|
log(`${BOLD}${CYAN}Task: ${task.title}${RESET}`);
|
|
1234
1234
|
log(`${"\u2550".repeat(60)}`);
|
|
1235
|
-
const
|
|
1235
|
+
const timestamp2 = Date.now().toString(36);
|
|
1236
1236
|
const random = Math.random().toString(36).substring(2, 6);
|
|
1237
|
-
const branchName = `agent/fix-${completed + 1}-${
|
|
1237
|
+
const branchName = `agent/fix-${completed + 1}-${timestamp2}-${random}`;
|
|
1238
1238
|
if (mainBranch && isGitRepo(dir)) {
|
|
1239
1239
|
if (gitStatus(dir)) gitStash(dir);
|
|
1240
1240
|
gitCheckout(dir, mainBranch);
|
|
@@ -1367,9 +1367,9 @@ ${"\u2550".repeat(60)}`);
|
|
|
1367
1367
|
log(`${BOLD}${CYAN}[${(/* @__PURE__ */ new Date()).toLocaleTimeString()}] Task ${taskIdx}: ${task.title}${RESET}`);
|
|
1368
1368
|
log(`${DIM}Premium: ${totalPremium}/${opts.maxPremium}${RESET}`);
|
|
1369
1369
|
log(`${"\u2550".repeat(60)}`);
|
|
1370
|
-
const
|
|
1370
|
+
const timestamp2 = Date.now().toString(36);
|
|
1371
1371
|
const random = Math.random().toString(36).substring(2, 6);
|
|
1372
|
-
const branchName = `agent/overnight-${taskIdx}-${
|
|
1372
|
+
const branchName = `agent/overnight-${taskIdx}-${timestamp2}-${random}`;
|
|
1373
1373
|
if (mainBranch && isGitRepo(dir)) {
|
|
1374
1374
|
gitStash(dir);
|
|
1375
1375
|
gitCheckout(dir, mainBranch);
|
|
@@ -1492,8 +1492,8 @@ async function researchCommand(dir, opts) {
|
|
|
1492
1492
|
ok("RESEARCH-PROPOSALS.md generated.");
|
|
1493
1493
|
const backupDir = join6(homedir4(), ".copilot", "research-reports");
|
|
1494
1494
|
mkdirSync3(backupDir, { recursive: true });
|
|
1495
|
-
const
|
|
1496
|
-
const backupFile = join6(backupDir, `${projectName}-${
|
|
1495
|
+
const timestamp2 = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
1496
|
+
const backupFile = join6(backupDir, `${projectName}-${timestamp2}.md`);
|
|
1497
1497
|
copyFileSync(proposalsFile, backupFile);
|
|
1498
1498
|
ok(`Backup saved: ${backupFile}`);
|
|
1499
1499
|
} else {
|
|
@@ -1826,11 +1826,16 @@ function cacheDetail(cache, s) {
|
|
|
1826
1826
|
}
|
|
1827
1827
|
function runBlessedDashboard(refreshSec, limit) {
|
|
1828
1828
|
const cache = createCache();
|
|
1829
|
+
const origTerm = process.env.TERM;
|
|
1830
|
+
if (origTerm?.includes("256color")) {
|
|
1831
|
+
process.env.TERM = "xterm";
|
|
1832
|
+
}
|
|
1829
1833
|
const screen = blessed.screen({
|
|
1830
1834
|
smartCSR: true,
|
|
1831
1835
|
title: "copilot-agent dashboard",
|
|
1832
1836
|
fullUnicode: true
|
|
1833
1837
|
});
|
|
1838
|
+
if (origTerm) process.env.TERM = origTerm;
|
|
1834
1839
|
const BG = "#0d1117";
|
|
1835
1840
|
const FG = "#e6edf3";
|
|
1836
1841
|
const BORDER_COLOR = "#30363d";
|
|
@@ -3611,9 +3616,681 @@ function fmtDur2(ms) {
|
|
|
3611
3616
|
return `${Math.floor(ms / 36e5)}h ${Math.round(ms % 36e5 / 6e4)}m`;
|
|
3612
3617
|
}
|
|
3613
3618
|
|
|
3619
|
+
// src/commands/multi.ts
|
|
3620
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync8, readFileSync as readFileSync8, writeFileSync as writeFileSync7 } from "fs";
|
|
3621
|
+
import { join as join13, resolve as resolve7, basename as basename3 } from "path";
|
|
3622
|
+
import { homedir as homedir11 } from "os";
|
|
3623
|
+
import chalk10 from "chalk";
|
|
3624
|
+
import { parse as parseYaml4, stringify as stringifyYaml3 } from "yaml";
|
|
3625
|
+
var CONFIG_DIR3 = join13(homedir11(), ".copilot-agent");
|
|
3626
|
+
var PROJECTS_FILE = join13(CONFIG_DIR3, "multi-projects.txt");
|
|
3627
|
+
var STATUS_FILE = join13(CONFIG_DIR3, "multi-status.yaml");
|
|
3628
|
+
var LOG_DIR = join13(CONFIG_DIR3, "multi-logs");
|
|
3629
|
+
var MAX_CONCURRENCY = 3;
|
|
3630
|
+
function registerMultiCommand(program2) {
|
|
3631
|
+
program2.command("multi <action> [args...]").description("Multi-project orchestration \u2014 add/remove/list/run/status/research").option("-a, --agent <type>", "Agent to use (copilot or claude)", "copilot").option("--parallel", "Run projects in parallel (max 3 concurrent)").option("--cooldown <n>", "Cooldown between projects in seconds", "30").option("-s, --steps <n>", "Max steps per task", "10").option("--max-premium <n>", "Premium budget per project", "50").option("--dry-run", "Preview without executing").action(async (action, args, opts) => {
|
|
3632
|
+
try {
|
|
3633
|
+
await multiCommand(action, args, {
|
|
3634
|
+
agent: resolveAgent(opts.agent),
|
|
3635
|
+
parallel: opts.parallel ?? false,
|
|
3636
|
+
cooldown: parseInt(opts.cooldown, 10),
|
|
3637
|
+
steps: parseInt(opts.steps, 10),
|
|
3638
|
+
maxPremium: parseInt(opts.maxPremium, 10),
|
|
3639
|
+
dryRun: opts.dryRun ?? false
|
|
3640
|
+
});
|
|
3641
|
+
} catch (err) {
|
|
3642
|
+
fail(`Multi error: ${err instanceof Error ? err.message : err}`);
|
|
3643
|
+
process.exit(1);
|
|
3644
|
+
}
|
|
3645
|
+
});
|
|
3646
|
+
}
|
|
3647
|
+
async function multiCommand(action, args, opts) {
|
|
3648
|
+
ensureFiles();
|
|
3649
|
+
switch (action) {
|
|
3650
|
+
case "add":
|
|
3651
|
+
return addProject(args[0]);
|
|
3652
|
+
case "remove":
|
|
3653
|
+
return removeProject(args[0]);
|
|
3654
|
+
case "list":
|
|
3655
|
+
return listProjects();
|
|
3656
|
+
case "status":
|
|
3657
|
+
return showStatus();
|
|
3658
|
+
case "run":
|
|
3659
|
+
case "health":
|
|
3660
|
+
return runAll("health", opts);
|
|
3661
|
+
case "research":
|
|
3662
|
+
return runAll("research", opts);
|
|
3663
|
+
default:
|
|
3664
|
+
fail(`Unknown action: ${action}. Use: add, remove, list, run, status, research`);
|
|
3665
|
+
process.exit(1);
|
|
3666
|
+
}
|
|
3667
|
+
}
|
|
3668
|
+
function ensureFiles() {
|
|
3669
|
+
mkdirSync8(LOG_DIR, { recursive: true });
|
|
3670
|
+
mkdirSync8(CONFIG_DIR3, { recursive: true });
|
|
3671
|
+
if (!existsSync11(PROJECTS_FILE)) writeFileSync7(PROJECTS_FILE, "");
|
|
3672
|
+
}
|
|
3673
|
+
function readProjects() {
|
|
3674
|
+
return readFileSync8(PROJECTS_FILE, "utf-8").split("\n").map((l) => l.trim()).filter(Boolean);
|
|
3675
|
+
}
|
|
3676
|
+
function writeProjects(projects) {
|
|
3677
|
+
writeFileSync7(PROJECTS_FILE, projects.join("\n") + "\n");
|
|
3678
|
+
}
|
|
3679
|
+
function readStatusFile() {
|
|
3680
|
+
if (!existsSync11(STATUS_FILE)) return [];
|
|
3681
|
+
try {
|
|
3682
|
+
const raw = readFileSync8(STATUS_FILE, "utf-8");
|
|
3683
|
+
const parsed = parseYaml4(raw);
|
|
3684
|
+
return Array.isArray(parsed) ? parsed : [];
|
|
3685
|
+
} catch {
|
|
3686
|
+
return [];
|
|
3687
|
+
}
|
|
3688
|
+
}
|
|
3689
|
+
function writeStatusFile(statuses) {
|
|
3690
|
+
writeFileSync7(STATUS_FILE, stringifyYaml3(statuses));
|
|
3691
|
+
}
|
|
3692
|
+
function upsertStatus(entry) {
|
|
3693
|
+
const statuses = readStatusFile();
|
|
3694
|
+
const idx = statuses.findIndex((s) => s.project === entry.project);
|
|
3695
|
+
if (idx >= 0) {
|
|
3696
|
+
statuses[idx] = entry;
|
|
3697
|
+
} else {
|
|
3698
|
+
statuses.push(entry);
|
|
3699
|
+
}
|
|
3700
|
+
writeStatusFile(statuses);
|
|
3701
|
+
}
|
|
3702
|
+
function formatDuration2(ms) {
|
|
3703
|
+
const totalSec = Math.round(ms / 1e3);
|
|
3704
|
+
const min = Math.floor(totalSec / 60);
|
|
3705
|
+
const sec = totalSec % 60;
|
|
3706
|
+
return min > 0 ? `${min}m ${sec}s` : `${sec}s`;
|
|
3707
|
+
}
|
|
3708
|
+
async function addProject(path) {
|
|
3709
|
+
if (!path) {
|
|
3710
|
+
fail("Usage: copilot-agent multi add <path>");
|
|
3711
|
+
process.exit(1);
|
|
3712
|
+
}
|
|
3713
|
+
const resolved = resolve7(path);
|
|
3714
|
+
if (!existsSync11(resolved)) {
|
|
3715
|
+
fail(`Not found: ${resolved}`);
|
|
3716
|
+
process.exit(1);
|
|
3717
|
+
}
|
|
3718
|
+
await withLock("projects-file", async () => {
|
|
3719
|
+
const projects = readProjects();
|
|
3720
|
+
if (projects.includes(resolved)) {
|
|
3721
|
+
warn(`Already registered: ${resolved}`);
|
|
3722
|
+
return;
|
|
3723
|
+
}
|
|
3724
|
+
projects.push(resolved);
|
|
3725
|
+
writeProjects(projects);
|
|
3726
|
+
ok(`Added: ${resolved}`);
|
|
3727
|
+
});
|
|
3728
|
+
}
|
|
3729
|
+
async function removeProject(path) {
|
|
3730
|
+
if (!path) {
|
|
3731
|
+
fail("Usage: copilot-agent multi remove <path>");
|
|
3732
|
+
process.exit(1);
|
|
3733
|
+
}
|
|
3734
|
+
const resolved = resolve7(path);
|
|
3735
|
+
await withLock("projects-file", async () => {
|
|
3736
|
+
const projects = readProjects();
|
|
3737
|
+
const filtered = projects.filter((p) => p !== resolved);
|
|
3738
|
+
if (filtered.length === projects.length) {
|
|
3739
|
+
warn(`Not registered: ${resolved}`);
|
|
3740
|
+
return;
|
|
3741
|
+
}
|
|
3742
|
+
writeProjects(filtered);
|
|
3743
|
+
ok(`Removed: ${resolved}`);
|
|
3744
|
+
});
|
|
3745
|
+
}
|
|
3746
|
+
function listProjects() {
|
|
3747
|
+
const projects = readProjects();
|
|
3748
|
+
if (projects.length === 0) {
|
|
3749
|
+
log("No projects registered. Add: copilot-agent multi add <path>");
|
|
3750
|
+
return;
|
|
3751
|
+
}
|
|
3752
|
+
const statuses = readStatusFile();
|
|
3753
|
+
console.log(chalk10.bold("\nRegistered projects:"));
|
|
3754
|
+
for (let i = 0; i < projects.length; i++) {
|
|
3755
|
+
const p = projects[i];
|
|
3756
|
+
const exists = existsSync11(p);
|
|
3757
|
+
const icon = exists ? chalk10.green("\u2705") : chalk10.red("\u274C");
|
|
3758
|
+
const type = exists ? detectProjectType(p) : "?";
|
|
3759
|
+
const st = statuses.find((s) => s.project === p);
|
|
3760
|
+
const statusTag = st ? chalk10.dim(` [${st.status} \u2014 ${st.agent} \u2014 ${st.duration}]`) : "";
|
|
3761
|
+
console.log(` ${i + 1}. ${icon} ${p} ${chalk10.dim(`(${type})`)}${statusTag}`);
|
|
3762
|
+
}
|
|
3763
|
+
console.log();
|
|
3764
|
+
}
|
|
3765
|
+
function showStatus() {
|
|
3766
|
+
const statuses = readStatusFile();
|
|
3767
|
+
if (statuses.length === 0) {
|
|
3768
|
+
log("No run history. Execute: copilot-agent multi run");
|
|
3769
|
+
return;
|
|
3770
|
+
}
|
|
3771
|
+
console.log(chalk10.bold("\nMulti-project status:"));
|
|
3772
|
+
for (const s of statuses) {
|
|
3773
|
+
const icon = s.status === "success" ? chalk10.green("\u2705") : s.status === "failed" ? chalk10.red("\u274C") : chalk10.yellow("\u{1F504}");
|
|
3774
|
+
console.log(
|
|
3775
|
+
` ${icon} ${chalk10.bold(basename3(s.project))} \u2014 ${s.agent} \u2014 ${s.tasks} tasks \u2014 ${s.duration} \u2014 ${chalk10.dim(s.lastRun)}`
|
|
3776
|
+
);
|
|
3777
|
+
}
|
|
3778
|
+
console.log();
|
|
3779
|
+
}
|
|
3780
|
+
function createSemaphore(max) {
|
|
3781
|
+
let running = 0;
|
|
3782
|
+
const queue = [];
|
|
3783
|
+
async function acquire() {
|
|
3784
|
+
if (running < max) {
|
|
3785
|
+
running++;
|
|
3786
|
+
return;
|
|
3787
|
+
}
|
|
3788
|
+
return new Promise((resolve8) => {
|
|
3789
|
+
queue.push(() => {
|
|
3790
|
+
running++;
|
|
3791
|
+
resolve8();
|
|
3792
|
+
});
|
|
3793
|
+
});
|
|
3794
|
+
}
|
|
3795
|
+
function release() {
|
|
3796
|
+
running--;
|
|
3797
|
+
const next = queue.shift();
|
|
3798
|
+
if (next) next();
|
|
3799
|
+
}
|
|
3800
|
+
return { acquire, release };
|
|
3801
|
+
}
|
|
3802
|
+
async function runAll(mode, opts) {
|
|
3803
|
+
assertAgent(opts.agent);
|
|
3804
|
+
const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "").slice(0, 15);
|
|
3805
|
+
setLogFile(join13(LOG_DIR, `multi-${mode}-${ts}.log`));
|
|
3806
|
+
const projects = readProjects();
|
|
3807
|
+
if (projects.length === 0) {
|
|
3808
|
+
fail("No projects registered. Add: copilot-agent multi add <path>");
|
|
3809
|
+
process.exit(1);
|
|
3810
|
+
}
|
|
3811
|
+
log(`\u{1F3ED} Multi-project ${mode} \u2014 ${projects.length} projects \u2014 agent: ${opts.agent}${opts.parallel ? " (parallel)" : ""}`);
|
|
3812
|
+
if (opts.dryRun) {
|
|
3813
|
+
for (const p of projects) {
|
|
3814
|
+
const type = existsSync11(p) ? detectProjectType(p) : "unknown";
|
|
3815
|
+
const tasks = getTasksForProject(type);
|
|
3816
|
+
console.log(`
|
|
3817
|
+
${chalk10.bold(basename3(p))} (${type})`);
|
|
3818
|
+
for (const t of tasks.slice(0, 3)) {
|
|
3819
|
+
console.log(` ${chalk10.dim("\u2022")} ${t.title}`);
|
|
3820
|
+
}
|
|
3821
|
+
}
|
|
3822
|
+
log(chalk10.dim("\n(dry-run \u2014 not executing)"));
|
|
3823
|
+
return;
|
|
3824
|
+
}
|
|
3825
|
+
const results = [];
|
|
3826
|
+
if (opts.parallel) {
|
|
3827
|
+
const sem = createSemaphore(MAX_CONCURRENCY);
|
|
3828
|
+
const promises = projects.map(async (project) => {
|
|
3829
|
+
await sem.acquire();
|
|
3830
|
+
try {
|
|
3831
|
+
const res = await runSingleProject(project, mode, opts);
|
|
3832
|
+
results.push(res);
|
|
3833
|
+
} finally {
|
|
3834
|
+
sem.release();
|
|
3835
|
+
}
|
|
3836
|
+
});
|
|
3837
|
+
await Promise.all(promises);
|
|
3838
|
+
} else {
|
|
3839
|
+
for (let i = 0; i < projects.length; i++) {
|
|
3840
|
+
const res = await runSingleProject(projects[i], mode, opts);
|
|
3841
|
+
results.push(res);
|
|
3842
|
+
if (i < projects.length - 1 && !res.skipped) {
|
|
3843
|
+
log(`Cooldown ${opts.cooldown}s\u2026`);
|
|
3844
|
+
await new Promise((r) => setTimeout(r, opts.cooldown * 1e3));
|
|
3845
|
+
}
|
|
3846
|
+
}
|
|
3847
|
+
}
|
|
3848
|
+
const success = results.filter((r) => r.success && !r.skipped).length;
|
|
3849
|
+
const failed = results.filter((r) => !r.success && !r.skipped).length;
|
|
3850
|
+
const skipped = results.filter((r) => r.skipped).length;
|
|
3851
|
+
const total = results.length;
|
|
3852
|
+
console.log(`
|
|
3853
|
+
${"\u2550".repeat(50)}`);
|
|
3854
|
+
log(`\u{1F4CA} Summary: ${success}/${total} succeeded, ${failed} failed, ${skipped} skipped`);
|
|
3855
|
+
for (const r of results) {
|
|
3856
|
+
const icon = r.skipped ? "\u23ED " : r.success ? "\u2705" : "\u274C";
|
|
3857
|
+
console.log(` ${icon} ${r.name}`);
|
|
3858
|
+
}
|
|
3859
|
+
console.log();
|
|
3860
|
+
notify(`Multi-${mode}: ${success}/${total} succeeded`, "copilot-agent");
|
|
3861
|
+
}
|
|
3862
|
+
async function runSingleProject(project, mode, opts) {
|
|
3863
|
+
const name = existsSync11(project) ? detectProjectName(project) : basename3(project);
|
|
3864
|
+
if (!existsSync11(project)) {
|
|
3865
|
+
warn(`Skipping (not found): ${project}`);
|
|
3866
|
+
return { name, success: false, skipped: true };
|
|
3867
|
+
}
|
|
3868
|
+
const type = detectProjectType(project);
|
|
3869
|
+
log(`
|
|
3870
|
+
${"\u2550".repeat(50)}`);
|
|
3871
|
+
log(`${chalk10.bold(name)} (${type}) \u2014 agent: ${opts.agent}`);
|
|
3872
|
+
log(`${"\u2550".repeat(50)}`);
|
|
3873
|
+
const tasks = mode === "research" ? [{ title: "Research", prompt: "Research latest best practices, dependency updates, and architecture improvements. Create a report.", priority: 1 }] : getTasksForProject(type).slice(0, 3);
|
|
3874
|
+
const startTime = Date.now();
|
|
3875
|
+
let projectSuccess = true;
|
|
3876
|
+
upsertStatus({
|
|
3877
|
+
project,
|
|
3878
|
+
lastRun: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3879
|
+
status: "running",
|
|
3880
|
+
agent: opts.agent,
|
|
3881
|
+
tasks: tasks.length,
|
|
3882
|
+
duration: "\u2014"
|
|
3883
|
+
});
|
|
3884
|
+
for (const task of tasks) {
|
|
3885
|
+
try {
|
|
3886
|
+
const result = await withLock(
|
|
3887
|
+
"agent-multi",
|
|
3888
|
+
() => runAgentTask(opts.agent, `Project: ${project}
|
|
3889
|
+
|
|
3890
|
+
${task.prompt}`, opts.steps, project)
|
|
3891
|
+
);
|
|
3892
|
+
ok(`${task.title} \u2014 exit ${result.exitCode}, premium: ${result.premium}`);
|
|
3893
|
+
} catch (err) {
|
|
3894
|
+
fail(`${task.title} failed: ${err}`);
|
|
3895
|
+
projectSuccess = false;
|
|
3896
|
+
}
|
|
3897
|
+
}
|
|
3898
|
+
const duration = formatDuration2(Date.now() - startTime);
|
|
3899
|
+
upsertStatus({
|
|
3900
|
+
project,
|
|
3901
|
+
lastRun: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3902
|
+
status: projectSuccess ? "success" : "failed",
|
|
3903
|
+
agent: opts.agent,
|
|
3904
|
+
tasks: tasks.length,
|
|
3905
|
+
duration
|
|
3906
|
+
});
|
|
3907
|
+
return { name, success: projectSuccess, skipped: false };
|
|
3908
|
+
}
|
|
3909
|
+
|
|
3910
|
+
// src/commands/review.ts
|
|
3911
|
+
import chalk11 from "chalk";
|
|
3912
|
+
import { execSync as execSync6 } from "child_process";
|
|
3913
|
+
var MAX_DIFF_LENGTH = 15e3;
|
|
3914
|
+
var MAX_BUFFER = 1024 * 1024;
|
|
3915
|
+
function getSessionDiff(sessionId) {
|
|
3916
|
+
const report = getAgentSessionReport(sessionId, "copilot") ?? getAgentSessionReport(sessionId, "claude");
|
|
3917
|
+
if (!report || report.gitCommits.length === 0) {
|
|
3918
|
+
return execSync6("git --no-pager diff HEAD~3", {
|
|
3919
|
+
encoding: "utf-8",
|
|
3920
|
+
maxBuffer: MAX_BUFFER
|
|
3921
|
+
});
|
|
3922
|
+
}
|
|
3923
|
+
return execSync6("git --no-pager diff HEAD~" + report.gitCommits.length, {
|
|
3924
|
+
encoding: "utf-8",
|
|
3925
|
+
cwd: report.cwd || process.cwd(),
|
|
3926
|
+
maxBuffer: MAX_BUFFER
|
|
3927
|
+
});
|
|
3928
|
+
}
|
|
3929
|
+
function getWorkingDiff() {
|
|
3930
|
+
const staged = execSync6("git --no-pager diff --cached", {
|
|
3931
|
+
encoding: "utf-8",
|
|
3932
|
+
maxBuffer: MAX_BUFFER
|
|
3933
|
+
});
|
|
3934
|
+
const unstaged = execSync6("git --no-pager diff", {
|
|
3935
|
+
encoding: "utf-8",
|
|
3936
|
+
maxBuffer: MAX_BUFFER
|
|
3937
|
+
});
|
|
3938
|
+
return staged + unstaged;
|
|
3939
|
+
}
|
|
3940
|
+
function getPrDiff(prNumber) {
|
|
3941
|
+
return execSync6(`gh pr diff ${prNumber} --color=never`, {
|
|
3942
|
+
encoding: "utf-8",
|
|
3943
|
+
maxBuffer: MAX_BUFFER
|
|
3944
|
+
});
|
|
3945
|
+
}
|
|
3946
|
+
var focusInstructions = {
|
|
3947
|
+
all: "Review for bugs, security issues, performance problems, and code quality.",
|
|
3948
|
+
security: "Focus exclusively on security vulnerabilities, injection risks, auth issues, and data exposure.",
|
|
3949
|
+
performance: "Focus exclusively on performance issues: N+1 queries, memory leaks, unnecessary allocations, slow algorithms.",
|
|
3950
|
+
bugs: "Focus exclusively on logic bugs, edge cases, null/undefined issues, race conditions.",
|
|
3951
|
+
style: "Focus exclusively on code style, naming, readability, and consistency."
|
|
3952
|
+
};
|
|
3953
|
+
function buildReviewPrompt(diff, focus) {
|
|
3954
|
+
const instruction = focusInstructions[focus] ?? focusInstructions.all;
|
|
3955
|
+
const truncatedDiff = diff.length > MAX_DIFF_LENGTH ? diff.slice(0, MAX_DIFF_LENGTH) + "\n... (truncated)" : diff;
|
|
3956
|
+
return `You are a senior code reviewer. ${instruction}
|
|
3957
|
+
|
|
3958
|
+
Review this diff and provide:
|
|
3959
|
+
1. **Critical Issues** (bugs, security) \u2014 must fix
|
|
3960
|
+
2. **Suggestions** \u2014 should fix for quality
|
|
3961
|
+
3. **Positive Notes** \u2014 good patterns observed
|
|
3962
|
+
4. **Summary** \u2014 one paragraph overall assessment
|
|
3963
|
+
|
|
3964
|
+
Be concise. Only flag real issues, not style nitpicks (unless focus is style).
|
|
3965
|
+
|
|
3966
|
+
\`\`\`diff
|
|
3967
|
+
${truncatedDiff}
|
|
3968
|
+
\`\`\``;
|
|
3969
|
+
}
|
|
3970
|
+
async function runReview(label, diff, agent, focus, steps) {
|
|
3971
|
+
if (!diff.trim()) {
|
|
3972
|
+
fail("No changes found to review.");
|
|
3973
|
+
process.exit(1);
|
|
3974
|
+
}
|
|
3975
|
+
info(`Reviewing: ${chalk11.cyan(label)}`);
|
|
3976
|
+
log(`Focus: ${chalk11.yellow(focus)} | Agent: ${chalk11.yellow(agent)} | Steps: ${steps}`);
|
|
3977
|
+
const prompt = buildReviewPrompt(diff, focus);
|
|
3978
|
+
const result = await runAgentTask(agent, prompt, steps, process.cwd());
|
|
3979
|
+
if (result.exitCode === 0) {
|
|
3980
|
+
ok("Review complete.");
|
|
3981
|
+
} else {
|
|
3982
|
+
fail(`Agent exited with code ${result.exitCode}`);
|
|
3983
|
+
}
|
|
3984
|
+
}
|
|
3985
|
+
function registerReviewCommand(program2) {
|
|
3986
|
+
const cmd = program2.command("review [session-id]").description("AI-powered code review of agent changes or git diffs").option("-a, --agent <type>", "Agent to use: copilot or claude", "copilot").option(
|
|
3987
|
+
"-f, --focus <area>",
|
|
3988
|
+
"Focus area: all, security, performance, bugs, style",
|
|
3989
|
+
"all"
|
|
3990
|
+
).option("-s, --steps <n>", "Max agent steps", "5").action(async (sessionId, opts) => {
|
|
3991
|
+
try {
|
|
3992
|
+
const agent = resolveAgent(opts.agent);
|
|
3993
|
+
const steps = parseInt(opts.steps, 10);
|
|
3994
|
+
let sid = sessionId;
|
|
3995
|
+
if (!sid) {
|
|
3996
|
+
const sessions = listAllSessions(1);
|
|
3997
|
+
if (sessions.length === 0) {
|
|
3998
|
+
fail('No sessions found. Use "review diff" to review working tree changes.');
|
|
3999
|
+
process.exit(1);
|
|
4000
|
+
}
|
|
4001
|
+
sid = sessions[0].id;
|
|
4002
|
+
log(`Using latest session: ${chalk11.dim(sid)}`);
|
|
4003
|
+
}
|
|
4004
|
+
const diff = getSessionDiff(sid);
|
|
4005
|
+
await runReview(`session ${sid.slice(0, 8)}\u2026`, diff, agent, opts.focus, steps);
|
|
4006
|
+
} catch (err) {
|
|
4007
|
+
fail(`Review error: ${err instanceof Error ? err.message : err}`);
|
|
4008
|
+
process.exit(1);
|
|
4009
|
+
}
|
|
4010
|
+
});
|
|
4011
|
+
cmd.command("diff").description("Review current working tree changes").option("-a, --agent <type>", "Agent to use: copilot or claude", "copilot").option(
|
|
4012
|
+
"-f, --focus <area>",
|
|
4013
|
+
"Focus area: all, security, performance, bugs, style",
|
|
4014
|
+
"all"
|
|
4015
|
+
).option("-s, --steps <n>", "Max agent steps", "5").action(async (opts) => {
|
|
4016
|
+
try {
|
|
4017
|
+
const agent = resolveAgent(opts.agent);
|
|
4018
|
+
const steps = parseInt(opts.steps, 10);
|
|
4019
|
+
const diff = getWorkingDiff();
|
|
4020
|
+
await runReview("working tree changes", diff, agent, opts.focus, steps);
|
|
4021
|
+
} catch (err) {
|
|
4022
|
+
fail(`Review error: ${err instanceof Error ? err.message : err}`);
|
|
4023
|
+
process.exit(1);
|
|
4024
|
+
}
|
|
4025
|
+
});
|
|
4026
|
+
cmd.command("pr <number>").description("Review a GitHub Pull Request").option("-a, --agent <type>", "Agent to use: copilot or claude", "copilot").option(
|
|
4027
|
+
"-f, --focus <area>",
|
|
4028
|
+
"Focus area: all, security, performance, bugs, style",
|
|
4029
|
+
"all"
|
|
4030
|
+
).option("-s, --steps <n>", "Max agent steps", "5").action(async (number, opts) => {
|
|
4031
|
+
try {
|
|
4032
|
+
const agent = resolveAgent(opts.agent);
|
|
4033
|
+
const steps = parseInt(opts.steps, 10);
|
|
4034
|
+
const diff = getPrDiff(number);
|
|
4035
|
+
await runReview(`PR #${number}`, diff, agent, opts.focus, steps);
|
|
4036
|
+
} catch (err) {
|
|
4037
|
+
fail(`Review error: ${err instanceof Error ? err.message : err}`);
|
|
4038
|
+
process.exit(1);
|
|
4039
|
+
}
|
|
4040
|
+
});
|
|
4041
|
+
}
|
|
4042
|
+
|
|
4043
|
+
// src/commands/schedule.ts
|
|
4044
|
+
import { readFileSync as readFileSync9, writeFileSync as writeFileSync8, existsSync as existsSync12, mkdirSync as mkdirSync9 } from "fs";
|
|
4045
|
+
import { join as join14 } from "path";
|
|
4046
|
+
import { homedir as homedir12 } from "os";
|
|
4047
|
+
import { parse as parseYaml5, stringify as stringifyYaml4 } from "yaml";
|
|
4048
|
+
var CONFIG_DIR4 = join14(homedir12(), ".copilot-agent");
|
|
4049
|
+
var SCHEDULES_FILE = join14(CONFIG_DIR4, "schedules.yaml");
|
|
4050
|
+
function ensureConfigDir2() {
|
|
4051
|
+
if (!existsSync12(CONFIG_DIR4)) mkdirSync9(CONFIG_DIR4, { recursive: true });
|
|
4052
|
+
}
|
|
4053
|
+
function loadSchedules() {
|
|
4054
|
+
if (!existsSync12(SCHEDULES_FILE)) return [];
|
|
4055
|
+
try {
|
|
4056
|
+
const raw = parseYaml5(readFileSync9(SCHEDULES_FILE, "utf-8"));
|
|
4057
|
+
return Array.isArray(raw) ? raw : [];
|
|
4058
|
+
} catch {
|
|
4059
|
+
return [];
|
|
4060
|
+
}
|
|
4061
|
+
}
|
|
4062
|
+
function saveSchedules(schedules) {
|
|
4063
|
+
ensureConfigDir2();
|
|
4064
|
+
writeFileSync8(SCHEDULES_FILE, stringifyYaml4(schedules), "utf-8");
|
|
4065
|
+
}
|
|
4066
|
+
function matchesCron(cron, date) {
|
|
4067
|
+
const parts = cron.trim().split(/\s+/);
|
|
4068
|
+
if (parts.length !== 5) return false;
|
|
4069
|
+
const [minPart, hourPart, , , dowPart] = parts;
|
|
4070
|
+
const minute = date.getMinutes();
|
|
4071
|
+
const hour = date.getHours();
|
|
4072
|
+
const dow = date.getDay();
|
|
4073
|
+
if (!matchField(minPart, minute)) return false;
|
|
4074
|
+
if (!matchField(hourPart, hour)) return false;
|
|
4075
|
+
if (!matchField(dowPart, dow)) return false;
|
|
4076
|
+
return true;
|
|
4077
|
+
}
|
|
4078
|
+
function matchField(pattern, value) {
|
|
4079
|
+
if (pattern === "*") return true;
|
|
4080
|
+
const stepMatch = pattern.match(/^\*\/(\d+)$/);
|
|
4081
|
+
if (stepMatch) {
|
|
4082
|
+
const step = parseInt(stepMatch[1], 10);
|
|
4083
|
+
return step > 0 && value % step === 0;
|
|
4084
|
+
}
|
|
4085
|
+
const num = parseInt(pattern, 10);
|
|
4086
|
+
if (!isNaN(num)) return value === num;
|
|
4087
|
+
return false;
|
|
4088
|
+
}
|
|
4089
|
+
function nextRunTime(cron) {
|
|
4090
|
+
const now = /* @__PURE__ */ new Date();
|
|
4091
|
+
const limit = 7 * 24 * 60;
|
|
4092
|
+
const candidate = new Date(now.getFullYear(), now.getMonth(), now.getDate(), now.getHours(), now.getMinutes());
|
|
4093
|
+
for (let i = 1; i <= limit; i++) {
|
|
4094
|
+
candidate.setMinutes(candidate.getMinutes() + 1);
|
|
4095
|
+
if (matchesCron(cron, candidate)) return new Date(candidate);
|
|
4096
|
+
}
|
|
4097
|
+
return null;
|
|
4098
|
+
}
|
|
4099
|
+
function formatTime2(date) {
|
|
4100
|
+
return date.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit", hour12: false });
|
|
4101
|
+
}
|
|
4102
|
+
function formatDateTime(date) {
|
|
4103
|
+
const day = date.toLocaleDateString([], { weekday: "short", month: "short", day: "numeric" });
|
|
4104
|
+
return `${day} ${formatTime2(date)}`;
|
|
4105
|
+
}
|
|
4106
|
+
function timestamp() {
|
|
4107
|
+
return `${DIM}[${formatTime2(/* @__PURE__ */ new Date())}]${RESET}`;
|
|
4108
|
+
}
|
|
4109
|
+
function listCommand() {
|
|
4110
|
+
const schedules = loadSchedules();
|
|
4111
|
+
if (schedules.length === 0) {
|
|
4112
|
+
info("No schedules configured.");
|
|
4113
|
+
info(`Add one with: ${CYAN}copilot-agent schedule add <name> --cron "..." --prompt "..."${RESET}`);
|
|
4114
|
+
return;
|
|
4115
|
+
}
|
|
4116
|
+
log(`
|
|
4117
|
+
${BOLD}Schedules${RESET} ${DIM}(${SCHEDULES_FILE})${RESET}
|
|
4118
|
+
`);
|
|
4119
|
+
for (const s of schedules) {
|
|
4120
|
+
const status = s.enabled ? `${GREEN}\u25CF${RESET}` : `${DIM}\u25CB${RESET}`;
|
|
4121
|
+
const next = s.enabled ? nextRunTime(s.cron) : null;
|
|
4122
|
+
const nextStr = next ? `${DIM}next: ${formatDateTime(next)}${RESET}` : "";
|
|
4123
|
+
log(` ${status} ${BOLD}${s.name}${RESET} ${DIM}${s.cron}${RESET} ${nextStr}`);
|
|
4124
|
+
log(` ${DIM}prompt:${RESET} ${s.prompt.length > 60 ? s.prompt.slice(0, 57) + "..." : s.prompt}`);
|
|
4125
|
+
log(` ${DIM}project:${RESET} ${s.project} ${DIM}agent:${RESET} ${s.agent} ${DIM}steps:${RESET} ${s.maxSteps ?? 30}`);
|
|
4126
|
+
log("");
|
|
4127
|
+
}
|
|
4128
|
+
}
|
|
4129
|
+
function addCommand(name, opts) {
|
|
4130
|
+
const schedules = loadSchedules();
|
|
4131
|
+
if (schedules.some((s) => s.name === name)) {
|
|
4132
|
+
fail(`Schedule "${name}" already exists. Remove it first or use a different name.`);
|
|
4133
|
+
process.exit(1);
|
|
4134
|
+
}
|
|
4135
|
+
if (!opts.cron || opts.cron.trim().split(/\s+/).length !== 5) {
|
|
4136
|
+
fail("Invalid cron expression. Expected 5 fields: minute hour day month weekday");
|
|
4137
|
+
process.exit(1);
|
|
4138
|
+
}
|
|
4139
|
+
const schedule = {
|
|
4140
|
+
name,
|
|
4141
|
+
cron: opts.cron,
|
|
4142
|
+
prompt: opts.prompt,
|
|
4143
|
+
project: opts.project || process.cwd(),
|
|
4144
|
+
agent: resolveAgent(opts.agent),
|
|
4145
|
+
enabled: !opts.disabled,
|
|
4146
|
+
maxSteps: parseInt(opts.steps, 10) || 30
|
|
4147
|
+
};
|
|
4148
|
+
schedules.push(schedule);
|
|
4149
|
+
saveSchedules(schedules);
|
|
4150
|
+
ok(`Added schedule "${name}"`);
|
|
4151
|
+
const next = nextRunTime(schedule.cron);
|
|
4152
|
+
if (next) {
|
|
4153
|
+
info(`Next run: ${formatDateTime(next)}`);
|
|
4154
|
+
}
|
|
4155
|
+
}
|
|
4156
|
+
function removeCommand(name) {
|
|
4157
|
+
const schedules = loadSchedules();
|
|
4158
|
+
const idx = schedules.findIndex((s) => s.name === name);
|
|
4159
|
+
if (idx === -1) {
|
|
4160
|
+
fail(`Schedule "${name}" not found.`);
|
|
4161
|
+
process.exit(1);
|
|
4162
|
+
}
|
|
4163
|
+
schedules.splice(idx, 1);
|
|
4164
|
+
saveSchedules(schedules);
|
|
4165
|
+
ok(`Removed schedule "${name}"`);
|
|
4166
|
+
}
|
|
4167
|
+
function dryRunCommand() {
|
|
4168
|
+
const schedules = loadSchedules().filter((s) => s.enabled);
|
|
4169
|
+
if (schedules.length === 0) {
|
|
4170
|
+
info("No enabled schedules.");
|
|
4171
|
+
return;
|
|
4172
|
+
}
|
|
4173
|
+
log(`
|
|
4174
|
+
${BOLD}Dry run \u2014 what would run next${RESET}
|
|
4175
|
+
`);
|
|
4176
|
+
for (const s of schedules) {
|
|
4177
|
+
const next = nextRunTime(s.cron);
|
|
4178
|
+
if (next) {
|
|
4179
|
+
log(` ${CYAN}${s.name}${RESET} \u2192 ${formatDateTime(next)}`);
|
|
4180
|
+
log(` ${DIM}${s.agent}${RESET} in ${s.project}`);
|
|
4181
|
+
log(` ${DIM}prompt:${RESET} ${s.prompt.length > 70 ? s.prompt.slice(0, 67) + "..." : s.prompt}`);
|
|
4182
|
+
log("");
|
|
4183
|
+
}
|
|
4184
|
+
}
|
|
4185
|
+
}
|
|
4186
|
+
async function runDaemon() {
|
|
4187
|
+
const schedules = loadSchedules();
|
|
4188
|
+
const enabled = schedules.filter((s) => s.enabled);
|
|
4189
|
+
if (enabled.length === 0) {
|
|
4190
|
+
fail("No enabled schedules. Add one first.");
|
|
4191
|
+
process.exit(1);
|
|
4192
|
+
}
|
|
4193
|
+
for (const s of enabled) {
|
|
4194
|
+
assertAgent(s.agent);
|
|
4195
|
+
}
|
|
4196
|
+
log(`
|
|
4197
|
+
${BOLD}${CYAN}Scheduler daemon started${RESET}`);
|
|
4198
|
+
info(`${enabled.length} schedule(s) active. Press Ctrl+C to stop.
|
|
4199
|
+
`);
|
|
4200
|
+
const lastRun = /* @__PURE__ */ new Map();
|
|
4201
|
+
const showStatus2 = () => {
|
|
4202
|
+
const now = /* @__PURE__ */ new Date();
|
|
4203
|
+
let soonestName = "";
|
|
4204
|
+
let soonestTime = null;
|
|
4205
|
+
for (const s of enabled) {
|
|
4206
|
+
const next = nextRunTime(s.cron);
|
|
4207
|
+
if (next && (!soonestTime || next < soonestTime)) {
|
|
4208
|
+
soonestTime = next;
|
|
4209
|
+
soonestName = s.name;
|
|
4210
|
+
}
|
|
4211
|
+
}
|
|
4212
|
+
const nextStr = soonestTime ? `next: ${CYAN}${soonestName}${RESET} at ${formatTime2(soonestTime)}` : "no upcoming runs";
|
|
4213
|
+
log(`${timestamp()} ${DIM}Scheduler running \u2014 ${enabled.length} schedules, ${nextStr}${RESET}`);
|
|
4214
|
+
};
|
|
4215
|
+
showStatus2();
|
|
4216
|
+
const check = async () => {
|
|
4217
|
+
const now = /* @__PURE__ */ new Date();
|
|
4218
|
+
const minuteKey = `${now.getFullYear()}-${now.getMonth()}-${now.getDate()}-${now.getHours()}-${now.getMinutes()}`;
|
|
4219
|
+
for (const s of enabled) {
|
|
4220
|
+
if (!matchesCron(s.cron, now)) continue;
|
|
4221
|
+
const runKey = `${s.name}:${minuteKey}`;
|
|
4222
|
+
if (lastRun.has(runKey)) continue;
|
|
4223
|
+
lastRun.set(runKey, Date.now());
|
|
4224
|
+
const cutoff = Date.now() - 2 * 60 * 1e3;
|
|
4225
|
+
for (const [k, v] of lastRun) {
|
|
4226
|
+
if (v < cutoff) lastRun.delete(k);
|
|
4227
|
+
}
|
|
4228
|
+
log(`
|
|
4229
|
+
${timestamp()} ${BOLD}${YELLOW}\u25B6 Running: ${s.name}${RESET}`);
|
|
4230
|
+
log(` ${DIM}cron:${RESET} ${s.cron} ${DIM}agent:${RESET} ${s.agent} ${DIM}project:${RESET} ${s.project}`);
|
|
4231
|
+
log(` ${DIM}prompt:${RESET} ${s.prompt}`);
|
|
4232
|
+
try {
|
|
4233
|
+
const result = await runAgentTask(
|
|
4234
|
+
s.agent,
|
|
4235
|
+
s.prompt,
|
|
4236
|
+
s.maxSteps ?? 30,
|
|
4237
|
+
s.project
|
|
4238
|
+
);
|
|
4239
|
+
if (result.exitCode === 0) {
|
|
4240
|
+
ok(`${timestamp()} \u2713 ${s.name} completed (session: ${result.sessionId?.slice(0, 8) ?? "n/a"})`);
|
|
4241
|
+
} else {
|
|
4242
|
+
warn(`${timestamp()} ${s.name} exited with code ${result.exitCode}`);
|
|
4243
|
+
}
|
|
4244
|
+
} catch (err) {
|
|
4245
|
+
fail(`${timestamp()} ${s.name} failed: ${err instanceof Error ? err.message : err}`);
|
|
4246
|
+
}
|
|
4247
|
+
showStatus2();
|
|
4248
|
+
}
|
|
4249
|
+
};
|
|
4250
|
+
await check();
|
|
4251
|
+
const interval = setInterval(() => {
|
|
4252
|
+
check().catch((err) => {
|
|
4253
|
+
fail(`Scheduler error: ${err instanceof Error ? err.message : err}`);
|
|
4254
|
+
});
|
|
4255
|
+
}, 6e4);
|
|
4256
|
+
const shutdown = () => {
|
|
4257
|
+
log(`
|
|
4258
|
+
${timestamp()} ${DIM}Scheduler stopped.${RESET}`);
|
|
4259
|
+
clearInterval(interval);
|
|
4260
|
+
process.exit(0);
|
|
4261
|
+
};
|
|
4262
|
+
process.on("SIGINT", shutdown);
|
|
4263
|
+
process.on("SIGTERM", shutdown);
|
|
4264
|
+
await new Promise(() => {
|
|
4265
|
+
});
|
|
4266
|
+
}
|
|
4267
|
+
function registerScheduleCommand(program2) {
|
|
4268
|
+
const cmd = program2.command("schedule").description("Cron-like recurring task scheduler");
|
|
4269
|
+
cmd.command("list").description("Show all configured schedules").action(() => {
|
|
4270
|
+
listCommand();
|
|
4271
|
+
});
|
|
4272
|
+
cmd.command("add <name>").description("Add a recurring schedule").requiredOption("--cron <expression>", 'Cron expression (e.g. "0 */6 * * *")').requiredOption("--prompt <text>", "Agent prompt to execute").option("--project <path>", "Project directory", process.cwd()).option("-a, --agent <type>", "Agent: copilot or claude").option("-s, --steps <n>", "Max autopilot steps", "30").option("--disabled", "Add as disabled").action((name, opts) => {
|
|
4273
|
+
addCommand(name, opts);
|
|
4274
|
+
});
|
|
4275
|
+
cmd.command("remove <name>").description("Remove a schedule").action((name) => {
|
|
4276
|
+
removeCommand(name);
|
|
4277
|
+
});
|
|
4278
|
+
cmd.command("run").description("Start the scheduler daemon (foreground)").action(async () => {
|
|
4279
|
+
try {
|
|
4280
|
+
await runDaemon();
|
|
4281
|
+
} catch (err) {
|
|
4282
|
+
fail(`Scheduler error: ${err instanceof Error ? err.message : err}`);
|
|
4283
|
+
process.exit(1);
|
|
4284
|
+
}
|
|
4285
|
+
});
|
|
4286
|
+
cmd.command("dry-run").description("Show what would run next for each schedule").action(() => {
|
|
4287
|
+
dryRunCommand();
|
|
4288
|
+
});
|
|
4289
|
+
}
|
|
4290
|
+
|
|
3614
4291
|
// src/index.ts
|
|
3615
4292
|
var program = new Command();
|
|
3616
|
-
program.name("copilot-agent").version("0.
|
|
4293
|
+
program.name("copilot-agent").version("1.0.0").description("Autonomous AI agent manager \u2014 auto-resume, task discovery, overnight runs. Supports GitHub Copilot CLI + Claude Code.");
|
|
3617
4294
|
registerStatusCommand(program);
|
|
3618
4295
|
registerWatchCommand(program);
|
|
3619
4296
|
registerRunCommand(program);
|
|
@@ -3631,5 +4308,8 @@ registerHooksCommand(program);
|
|
|
3631
4308
|
registerPrCommand(program);
|
|
3632
4309
|
registerLogCommand(program);
|
|
3633
4310
|
registerTemplateCommand(program);
|
|
4311
|
+
registerMultiCommand(program);
|
|
4312
|
+
registerReviewCommand(program);
|
|
4313
|
+
registerScheduleCommand(program);
|
|
3634
4314
|
program.parse();
|
|
3635
4315
|
//# sourceMappingURL=index.js.map
|