copilot-agent 0.1.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/LICENSE +21 -0
- package/README.md +109 -0
- package/dist/index.js +916 -0
- package/dist/index.js.map +1 -0
- package/package.json +36 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 magicpro97
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# copilot-agent
|
|
2
|
+
|
|
3
|
+
Autonomous GitHub Copilot CLI agent — auto-resume sessions, discover tasks, run overnight.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **`status`** — View recent & active Copilot sessions with premium usage
|
|
8
|
+
- **`watch`** — Monitor a session, auto-resume when it stops
|
|
9
|
+
- **`run`** — Auto-discover and fix issues in any project
|
|
10
|
+
- **`overnight`** — Run tasks continuously until a deadline (e.g. 07:00)
|
|
11
|
+
- **`research`** — Research improvements, dependencies, architecture
|
|
12
|
+
|
|
13
|
+
## Install
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install -g copilot-agent
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Requires [GitHub Copilot CLI](https://docs.github.com/en/copilot/github-copilot-in-the-cli) installed and authenticated.
|
|
20
|
+
|
|
21
|
+
## Usage
|
|
22
|
+
|
|
23
|
+
### Show session status
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
# Recent sessions
|
|
27
|
+
copilot-agent status
|
|
28
|
+
|
|
29
|
+
# Active (running) sessions only
|
|
30
|
+
copilot-agent status --active
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Watch & auto-resume
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
# Auto-detect latest incomplete session
|
|
37
|
+
copilot-agent watch
|
|
38
|
+
|
|
39
|
+
# Watch specific session
|
|
40
|
+
copilot-agent watch abc12345-...
|
|
41
|
+
|
|
42
|
+
# Custom resume settings
|
|
43
|
+
copilot-agent watch --steps 100 --max-resumes 50
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Discover & fix issues
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
# Run on current directory
|
|
50
|
+
copilot-agent run
|
|
51
|
+
|
|
52
|
+
# Run on specific project
|
|
53
|
+
copilot-agent run ~/my-project
|
|
54
|
+
|
|
55
|
+
# Preview tasks without executing
|
|
56
|
+
copilot-agent run --dry-run
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Overnight runner
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
# Run until 7am (default)
|
|
63
|
+
copilot-agent overnight ~/my-project
|
|
64
|
+
|
|
65
|
+
# Custom deadline & budget
|
|
66
|
+
copilot-agent overnight --until 06:00 --max-premium 200
|
|
67
|
+
|
|
68
|
+
# Preview
|
|
69
|
+
copilot-agent overnight --dry-run
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Research
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
# Run all predefined research tasks
|
|
76
|
+
copilot-agent research
|
|
77
|
+
|
|
78
|
+
# Research a specific topic
|
|
79
|
+
copilot-agent research "migrate from Room to SQLDelight"
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## How it works
|
|
83
|
+
|
|
84
|
+
1. **Session detection** — Reads `~/.copilot/session-state/*/events.jsonl` to detect task completion vs interruption
|
|
85
|
+
2. **Auto-resume** — Uses `copilot --resume=SESSION_ID --autopilot` to continue interrupted sessions
|
|
86
|
+
3. **Task discovery** — Detects project type (KMP, React, Python, etc.) and generates relevant maintenance tasks
|
|
87
|
+
4. **Race prevention** — File locking via `proper-lockfile` prevents concurrent copilot runs
|
|
88
|
+
5. **Process tracking** — Uses `ps-list` to find and wait for copilot processes by PID
|
|
89
|
+
|
|
90
|
+
## Supported project types
|
|
91
|
+
|
|
92
|
+
| Type | Detection | Specialized tasks |
|
|
93
|
+
|------|-----------|-------------------|
|
|
94
|
+
| KMP | `gradle.properties` + `composeApp/` | Compose optimization, expect/actual, Room migrations |
|
|
95
|
+
| TypeScript | `tsconfig.json` | Strict types, `any` removal |
|
|
96
|
+
| React | `vite.config.ts` | Performance, re-renders |
|
|
97
|
+
| Node | `package.json` | Error handling |
|
|
98
|
+
| Python | `pyproject.toml` | Type hints |
|
|
99
|
+
| + 7 more | Auto-detected | Common tasks (TODOs, deps, tests, lint, docs, security) |
|
|
100
|
+
|
|
101
|
+
## Requirements
|
|
102
|
+
|
|
103
|
+
- Node.js ≥ 18
|
|
104
|
+
- GitHub Copilot CLI installed & authenticated
|
|
105
|
+
- macOS or Linux
|
|
106
|
+
|
|
107
|
+
## License
|
|
108
|
+
|
|
109
|
+
MIT
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,916 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import { Command } from "commander";
|
|
5
|
+
|
|
6
|
+
// src/commands/status.ts
|
|
7
|
+
import chalk from "chalk";
|
|
8
|
+
|
|
9
|
+
// src/lib/session.ts
|
|
10
|
+
import {
|
|
11
|
+
existsSync,
|
|
12
|
+
readdirSync,
|
|
13
|
+
readFileSync,
|
|
14
|
+
statSync
|
|
15
|
+
} from "fs";
|
|
16
|
+
import { join, resolve } from "path";
|
|
17
|
+
import { homedir } from "os";
|
|
18
|
+
var SESSION_DIR = join(homedir(), ".copilot", "session-state");
|
|
19
|
+
function validateSession(sid) {
|
|
20
|
+
const events = join(SESSION_DIR, sid, "events.jsonl");
|
|
21
|
+
try {
|
|
22
|
+
return existsSync(events) && statSync(events).size > 0;
|
|
23
|
+
} catch {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function listSessions(limit = 20) {
|
|
28
|
+
if (!existsSync(SESSION_DIR)) return [];
|
|
29
|
+
const entries = readdirSync(SESSION_DIR, { withFileTypes: true }).filter((d) => d.isDirectory());
|
|
30
|
+
const dirs = [];
|
|
31
|
+
for (const entry of entries) {
|
|
32
|
+
const dirPath = join(SESSION_DIR, entry.name);
|
|
33
|
+
if (!existsSync(join(dirPath, "events.jsonl"))) continue;
|
|
34
|
+
try {
|
|
35
|
+
const stat = statSync(dirPath);
|
|
36
|
+
dirs.push({ id: entry.name, dir: dirPath, mtime: stat.mtimeMs });
|
|
37
|
+
} catch {
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
dirs.sort((a, b) => b.mtime - a.mtime);
|
|
41
|
+
return dirs.slice(0, limit).map((s) => ({
|
|
42
|
+
id: s.id,
|
|
43
|
+
dir: s.dir,
|
|
44
|
+
mtime: s.mtime,
|
|
45
|
+
lastEvent: getLastEvent(s.id),
|
|
46
|
+
premiumRequests: getSessionPremium(s.id),
|
|
47
|
+
summary: getSessionSummary(s.id),
|
|
48
|
+
cwd: getSessionCwd(s.id),
|
|
49
|
+
complete: hasTaskComplete(s.id)
|
|
50
|
+
}));
|
|
51
|
+
}
|
|
52
|
+
function getLatestSessionId() {
|
|
53
|
+
if (!existsSync(SESSION_DIR)) return null;
|
|
54
|
+
const entries = readdirSync(SESSION_DIR, { withFileTypes: true }).filter((d) => d.isDirectory());
|
|
55
|
+
let latest = null;
|
|
56
|
+
for (const entry of entries) {
|
|
57
|
+
try {
|
|
58
|
+
const stat = statSync(join(SESSION_DIR, entry.name));
|
|
59
|
+
if (!latest || stat.mtimeMs > latest.mtime) {
|
|
60
|
+
latest = { id: entry.name, mtime: stat.mtimeMs };
|
|
61
|
+
}
|
|
62
|
+
} catch {
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return latest?.id ?? null;
|
|
66
|
+
}
|
|
67
|
+
function hasTaskComplete(sid) {
|
|
68
|
+
if (!validateSession(sid)) return false;
|
|
69
|
+
try {
|
|
70
|
+
const content = readFileSync(join(SESSION_DIR, sid, "events.jsonl"), "utf-8");
|
|
71
|
+
return content.includes('"session.task_complete"');
|
|
72
|
+
} catch {
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
function getLastEvent(sid) {
|
|
77
|
+
if (!validateSession(sid)) return "invalid";
|
|
78
|
+
try {
|
|
79
|
+
const lines = readFileSync(join(SESSION_DIR, sid, "events.jsonl"), "utf-8").trimEnd().split("\n");
|
|
80
|
+
const last = JSON.parse(lines[lines.length - 1]);
|
|
81
|
+
return last.type ?? "unknown";
|
|
82
|
+
} catch {
|
|
83
|
+
return "corrupted";
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
function getSessionPremium(sid) {
|
|
87
|
+
if (!validateSession(sid)) return 0;
|
|
88
|
+
try {
|
|
89
|
+
const content = readFileSync(join(SESSION_DIR, sid, "events.jsonl"), "utf-8");
|
|
90
|
+
const lines = content.trimEnd().split("\n");
|
|
91
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
92
|
+
try {
|
|
93
|
+
const event = JSON.parse(lines[i]);
|
|
94
|
+
if (event.type === "session.shutdown" && event.data?.totalPremiumRequests != null) {
|
|
95
|
+
return event.data.totalPremiumRequests;
|
|
96
|
+
}
|
|
97
|
+
} catch {
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return 0;
|
|
101
|
+
} catch {
|
|
102
|
+
return 0;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
function parseSimpleYaml(content) {
|
|
106
|
+
const result = {};
|
|
107
|
+
for (const line of content.split("\n")) {
|
|
108
|
+
const idx = line.indexOf(": ");
|
|
109
|
+
if (idx === -1) continue;
|
|
110
|
+
const key = line.substring(0, idx).trim();
|
|
111
|
+
const value = line.substring(idx + 2).trim();
|
|
112
|
+
if (key) result[key] = value;
|
|
113
|
+
}
|
|
114
|
+
return result;
|
|
115
|
+
}
|
|
116
|
+
function readWorkspace(sid) {
|
|
117
|
+
const wsPath = join(SESSION_DIR, sid, "workspace.yaml");
|
|
118
|
+
if (!existsSync(wsPath)) return {};
|
|
119
|
+
try {
|
|
120
|
+
return parseSimpleYaml(readFileSync(wsPath, "utf-8"));
|
|
121
|
+
} catch {
|
|
122
|
+
return {};
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
function getSessionSummary(sid) {
|
|
126
|
+
return readWorkspace(sid).summary ?? "";
|
|
127
|
+
}
|
|
128
|
+
function getSessionCwd(sid) {
|
|
129
|
+
return readWorkspace(sid).cwd ?? "";
|
|
130
|
+
}
|
|
131
|
+
function findLatestIncomplete() {
|
|
132
|
+
const sessions = listSessions(50);
|
|
133
|
+
for (const s of sessions) {
|
|
134
|
+
if (!s.complete) return s.id;
|
|
135
|
+
}
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// src/lib/process.ts
|
|
140
|
+
import { execSync as execSync2, spawn } from "child_process";
|
|
141
|
+
|
|
142
|
+
// src/lib/logger.ts
|
|
143
|
+
import { appendFileSync, mkdirSync } from "fs";
|
|
144
|
+
import { dirname } from "path";
|
|
145
|
+
import { execSync } from "child_process";
|
|
146
|
+
|
|
147
|
+
// src/lib/colors.ts
|
|
148
|
+
var RED = "\x1B[31m";
|
|
149
|
+
var GREEN = "\x1B[32m";
|
|
150
|
+
var YELLOW = "\x1B[33m";
|
|
151
|
+
var RESET = "\x1B[0m";
|
|
152
|
+
|
|
153
|
+
// src/lib/logger.ts
|
|
154
|
+
var logFilePath = null;
|
|
155
|
+
var ANSI_RE = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g;
|
|
156
|
+
function stripAnsi(s) {
|
|
157
|
+
return s.replace(ANSI_RE, "");
|
|
158
|
+
}
|
|
159
|
+
function writeToFile(msg) {
|
|
160
|
+
if (!logFilePath) return;
|
|
161
|
+
try {
|
|
162
|
+
appendFileSync(logFilePath, stripAnsi(msg) + "\n");
|
|
163
|
+
} catch {
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
function setLogFile(path) {
|
|
167
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
168
|
+
logFilePath = path;
|
|
169
|
+
}
|
|
170
|
+
function log(msg) {
|
|
171
|
+
console.log(msg);
|
|
172
|
+
writeToFile(msg);
|
|
173
|
+
}
|
|
174
|
+
function warn(msg) {
|
|
175
|
+
const out = `${YELLOW}\u26A0 ${msg}${RESET}`;
|
|
176
|
+
console.log(out);
|
|
177
|
+
writeToFile(`\u26A0 ${msg}`);
|
|
178
|
+
}
|
|
179
|
+
function ok(msg) {
|
|
180
|
+
const out = `${GREEN}\u2714 ${msg}${RESET}`;
|
|
181
|
+
console.log(out);
|
|
182
|
+
writeToFile(`\u2714 ${msg}`);
|
|
183
|
+
}
|
|
184
|
+
function fail(msg) {
|
|
185
|
+
const out = `${RED}\u2716 ${msg}${RESET}`;
|
|
186
|
+
console.error(out);
|
|
187
|
+
writeToFile(`\u2716 ${msg}`);
|
|
188
|
+
}
|
|
189
|
+
function notify(message, title = "copilot-agent") {
|
|
190
|
+
try {
|
|
191
|
+
if (process.platform === "darwin") {
|
|
192
|
+
execSync(
|
|
193
|
+
`osascript -e 'display notification "${message.replace(/"/g, '\\"')}" with title "${title.replace(/"/g, '\\"')}"'`,
|
|
194
|
+
{ stdio: "ignore" }
|
|
195
|
+
);
|
|
196
|
+
} else {
|
|
197
|
+
try {
|
|
198
|
+
execSync("which notify-send", { stdio: "pipe" });
|
|
199
|
+
execSync(
|
|
200
|
+
`notify-send "${title}" "${message.replace(/"/g, '\\"')}"`,
|
|
201
|
+
{ stdio: "ignore" }
|
|
202
|
+
);
|
|
203
|
+
} catch {
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
} catch {
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// src/lib/process.ts
|
|
211
|
+
function isCopilotInstalled() {
|
|
212
|
+
try {
|
|
213
|
+
execSync2("which copilot", { stdio: "pipe", encoding: "utf-8" });
|
|
214
|
+
return true;
|
|
215
|
+
} catch {
|
|
216
|
+
return false;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
function assertCopilot() {
|
|
220
|
+
if (!isCopilotInstalled()) {
|
|
221
|
+
fail("copilot CLI not found. Install with: npm i -g @githubnext/copilot");
|
|
222
|
+
process.exit(1);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
function findCopilotProcesses() {
|
|
226
|
+
try {
|
|
227
|
+
const output = execSync2("ps -eo pid,command", { encoding: "utf-8" });
|
|
228
|
+
const results = [];
|
|
229
|
+
for (const line of output.split("\n")) {
|
|
230
|
+
const trimmed = line.trim();
|
|
231
|
+
if (!trimmed) continue;
|
|
232
|
+
if ((trimmed.includes("copilot") || trimmed.includes("@githubnext/copilot")) && !trimmed.includes("ps -eo") && !trimmed.includes("copilot-agent") && !trimmed.includes("grep")) {
|
|
233
|
+
const match = trimmed.match(/^(\d+)\s+(.+)$/);
|
|
234
|
+
if (match) {
|
|
235
|
+
const cmd = match[2];
|
|
236
|
+
const sidMatch = cmd.match(/resume[= ]+([a-f0-9-]{36})/);
|
|
237
|
+
results.push({
|
|
238
|
+
pid: parseInt(match[1], 10),
|
|
239
|
+
command: cmd,
|
|
240
|
+
sessionId: sidMatch?.[1]
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
return results;
|
|
246
|
+
} catch {
|
|
247
|
+
return [];
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
function findPidForSession(sid) {
|
|
251
|
+
const procs = findCopilotProcesses();
|
|
252
|
+
const matching = procs.filter((p) => p.command.includes(sid)).sort((a, b) => b.pid - a.pid);
|
|
253
|
+
return matching[0]?.pid ?? null;
|
|
254
|
+
}
|
|
255
|
+
async function waitForExit(pid, timeoutMs = 144e5) {
|
|
256
|
+
const start = Date.now();
|
|
257
|
+
while (Date.now() - start < timeoutMs) {
|
|
258
|
+
try {
|
|
259
|
+
process.kill(pid, 0);
|
|
260
|
+
await sleep(5e3);
|
|
261
|
+
} catch {
|
|
262
|
+
return true;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
return false;
|
|
266
|
+
}
|
|
267
|
+
function runCopilot(args, options) {
|
|
268
|
+
return new Promise((resolve3) => {
|
|
269
|
+
const child = spawn("copilot", args, {
|
|
270
|
+
cwd: options?.cwd,
|
|
271
|
+
stdio: "inherit",
|
|
272
|
+
env: { ...process.env }
|
|
273
|
+
});
|
|
274
|
+
child.on("close", async (code) => {
|
|
275
|
+
await sleep(3e3);
|
|
276
|
+
const sid = getLatestSessionId();
|
|
277
|
+
const premium = sid ? getSessionPremium(sid) : 0;
|
|
278
|
+
resolve3({
|
|
279
|
+
exitCode: code ?? 1,
|
|
280
|
+
sessionId: sid,
|
|
281
|
+
premium
|
|
282
|
+
});
|
|
283
|
+
});
|
|
284
|
+
child.on("error", () => {
|
|
285
|
+
resolve3({ exitCode: 1, sessionId: null, premium: 0 });
|
|
286
|
+
});
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
function runCopilotResume(sid, steps, message, cwd) {
|
|
290
|
+
const args = [
|
|
291
|
+
`--resume=${sid}`,
|
|
292
|
+
"--autopilot",
|
|
293
|
+
"--allow-all",
|
|
294
|
+
"--max-autopilot-continues",
|
|
295
|
+
String(steps),
|
|
296
|
+
"--no-ask-user"
|
|
297
|
+
];
|
|
298
|
+
if (message) args.push("-p", message);
|
|
299
|
+
return runCopilot(args, { cwd });
|
|
300
|
+
}
|
|
301
|
+
function runCopilotTask(prompt, steps, cwd) {
|
|
302
|
+
return runCopilot([
|
|
303
|
+
"-p",
|
|
304
|
+
prompt,
|
|
305
|
+
"--autopilot",
|
|
306
|
+
"--allow-all",
|
|
307
|
+
"--max-autopilot-continues",
|
|
308
|
+
String(steps),
|
|
309
|
+
"--no-ask-user"
|
|
310
|
+
], { cwd });
|
|
311
|
+
}
|
|
312
|
+
function sleep(ms) {
|
|
313
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// src/commands/status.ts
|
|
317
|
+
async function statusCommand(opts) {
|
|
318
|
+
if (opts.active) {
|
|
319
|
+
return showActive();
|
|
320
|
+
}
|
|
321
|
+
showRecent(opts.limit);
|
|
322
|
+
}
|
|
323
|
+
async function showActive() {
|
|
324
|
+
const procs = await findCopilotProcesses();
|
|
325
|
+
if (procs.length === 0) {
|
|
326
|
+
log("No active copilot processes.");
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
console.log(
|
|
330
|
+
chalk.bold(
|
|
331
|
+
`
|
|
332
|
+
${"PID".padEnd(8)} ${"Session".padEnd(40)} ${"Command".slice(0, 60)}`
|
|
333
|
+
)
|
|
334
|
+
);
|
|
335
|
+
console.log("\u2500".repeat(108));
|
|
336
|
+
for (const p of procs) {
|
|
337
|
+
console.log(
|
|
338
|
+
`${String(p.pid).padEnd(8)} ${(p.sessionId ?? "\u2014").padEnd(40)} ${(p.command ?? "").slice(0, 60)}`
|
|
339
|
+
);
|
|
340
|
+
}
|
|
341
|
+
console.log();
|
|
342
|
+
}
|
|
343
|
+
function showRecent(limit) {
|
|
344
|
+
const sessions = listSessions(limit);
|
|
345
|
+
if (sessions.length === 0) {
|
|
346
|
+
log("No sessions found.");
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
console.log(
|
|
350
|
+
chalk.bold(
|
|
351
|
+
`
|
|
352
|
+
${"Status".padEnd(10)} ${"Premium".padEnd(10)} ${"Last Event".padEnd(25)} ${"Summary".padEnd(40)} ${"ID"}`
|
|
353
|
+
)
|
|
354
|
+
);
|
|
355
|
+
console.log("\u2500".repeat(120));
|
|
356
|
+
for (const s of sessions) {
|
|
357
|
+
const done = hasTaskComplete(s.id);
|
|
358
|
+
const status = done ? chalk.green("\u2705 done") : chalk.yellow("\u23F8\uFE0F stopped");
|
|
359
|
+
const premium = String(getSessionPremium(s.id));
|
|
360
|
+
const lastEvt = getLastEvent(s.id);
|
|
361
|
+
const summary = (s.summary ?? "\u2014").slice(0, 38);
|
|
362
|
+
console.log(
|
|
363
|
+
`${status.padEnd(20)} ${premium.padEnd(10)} ${lastEvt.padEnd(25)} ${summary.padEnd(40)} ${chalk.dim(s.id)}`
|
|
364
|
+
);
|
|
365
|
+
}
|
|
366
|
+
console.log();
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// src/commands/watch.ts
|
|
370
|
+
import chalk2 from "chalk";
|
|
371
|
+
import ora from "ora";
|
|
372
|
+
async function watchCommand(sid, opts) {
|
|
373
|
+
assertCopilot();
|
|
374
|
+
if (!sid) {
|
|
375
|
+
sid = findLatestIncomplete() ?? void 0;
|
|
376
|
+
if (!sid) {
|
|
377
|
+
fail("No incomplete session found.");
|
|
378
|
+
process.exit(1);
|
|
379
|
+
}
|
|
380
|
+
log(`Auto-detected incomplete session: ${chalk2.cyan(sid)}`);
|
|
381
|
+
}
|
|
382
|
+
if (!validateSession(sid)) {
|
|
383
|
+
fail(`Invalid session: ${sid}`);
|
|
384
|
+
process.exit(1);
|
|
385
|
+
}
|
|
386
|
+
if (hasTaskComplete(sid)) {
|
|
387
|
+
ok(`Session ${sid} already completed.`);
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
let resumes = 0;
|
|
391
|
+
while (resumes < opts.maxResumes) {
|
|
392
|
+
const pid = await findPidForSession(sid);
|
|
393
|
+
if (pid) {
|
|
394
|
+
const spinner = ora(
|
|
395
|
+
`Watching PID ${pid} for session ${chalk2.cyan(sid.slice(0, 8))}\u2026`
|
|
396
|
+
).start();
|
|
397
|
+
const exited = await waitForExit(pid);
|
|
398
|
+
spinner.stop();
|
|
399
|
+
if (!exited) {
|
|
400
|
+
warn("Timeout waiting for process exit.");
|
|
401
|
+
break;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
await sleep2(3e3);
|
|
405
|
+
if (hasTaskComplete(sid)) {
|
|
406
|
+
ok(
|
|
407
|
+
`Task complete! Summary: ${getSessionSummary(sid) || "none"}`
|
|
408
|
+
);
|
|
409
|
+
notify("Task completed!", `Session ${sid.slice(0, 8)}`);
|
|
410
|
+
return;
|
|
411
|
+
}
|
|
412
|
+
resumes++;
|
|
413
|
+
log(
|
|
414
|
+
`Session interrupted (${getLastEvent(sid)}). Resume ${resumes}/${opts.maxResumes}\u2026`
|
|
415
|
+
);
|
|
416
|
+
const result = await runCopilotResume(sid, opts.steps, opts.message);
|
|
417
|
+
if (result.sessionId && result.sessionId !== sid) {
|
|
418
|
+
log(`New session created: ${chalk2.cyan(result.sessionId)}`);
|
|
419
|
+
sid = result.sessionId;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
warn(`Max resumes (${opts.maxResumes}) reached.`);
|
|
423
|
+
notify("Max resumes reached", `Session ${sid.slice(0, 8)}`);
|
|
424
|
+
}
|
|
425
|
+
function sleep2(ms) {
|
|
426
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
// src/commands/run.ts
|
|
430
|
+
import chalk3 from "chalk";
|
|
431
|
+
import ora2 from "ora";
|
|
432
|
+
|
|
433
|
+
// src/lib/detect.ts
|
|
434
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2, readdirSync as readdirSync2 } from "fs";
|
|
435
|
+
import { join as join2, basename, resolve as resolve2 } from "path";
|
|
436
|
+
import { execSync as execSync3 } from "child_process";
|
|
437
|
+
function detectProjectType(dir) {
|
|
438
|
+
const exists = (f) => existsSync2(join2(dir, f));
|
|
439
|
+
if (exists("build.gradle.kts") || exists("build.gradle")) {
|
|
440
|
+
if (exists("composeApp") || exists("gradle.properties")) {
|
|
441
|
+
try {
|
|
442
|
+
const gradle = readFileSync2(join2(dir, "build.gradle.kts"), "utf-8");
|
|
443
|
+
if (gradle.includes("multiplatform") || gradle.includes("KotlinMultiplatform")) return "kmp";
|
|
444
|
+
} catch {
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
if (exists("pom.xml")) return "java";
|
|
448
|
+
return "kotlin";
|
|
449
|
+
}
|
|
450
|
+
if (exists("pubspec.yaml")) return "flutter";
|
|
451
|
+
if (exists("Package.swift")) return "swift";
|
|
452
|
+
try {
|
|
453
|
+
const entries = readdirSync2(dir);
|
|
454
|
+
if (entries.some((e) => e.endsWith(".xcodeproj"))) return "swift";
|
|
455
|
+
} catch {
|
|
456
|
+
}
|
|
457
|
+
if (exists("Cargo.toml")) return "rust";
|
|
458
|
+
if (exists("go.mod")) return "go";
|
|
459
|
+
if (exists("pyproject.toml") || exists("setup.py") || exists("requirements.txt")) return "python";
|
|
460
|
+
if (exists("package.json")) {
|
|
461
|
+
try {
|
|
462
|
+
const pkg = JSON.parse(readFileSync2(join2(dir, "package.json"), "utf-8"));
|
|
463
|
+
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
464
|
+
if (allDeps["next"]) return "next";
|
|
465
|
+
if (allDeps["react"]) return "react";
|
|
466
|
+
if (allDeps["typescript"] || exists("tsconfig.json")) return "typescript";
|
|
467
|
+
} catch {
|
|
468
|
+
}
|
|
469
|
+
return "node";
|
|
470
|
+
}
|
|
471
|
+
if (exists("pom.xml")) return "java";
|
|
472
|
+
return "unknown";
|
|
473
|
+
}
|
|
474
|
+
function detectProjectName(dir) {
|
|
475
|
+
try {
|
|
476
|
+
const pkg = JSON.parse(readFileSync2(join2(dir, "package.json"), "utf-8"));
|
|
477
|
+
if (pkg.name) return pkg.name;
|
|
478
|
+
} catch {
|
|
479
|
+
}
|
|
480
|
+
return basename(resolve2(dir));
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// src/lib/tasks.ts
|
|
484
|
+
var COMMON_TASKS = [
|
|
485
|
+
{
|
|
486
|
+
title: "Fix TODOs",
|
|
487
|
+
prompt: "Scan for TODO, FIXME, HACK comments. Fix the most impactful ones. Run tests to verify.",
|
|
488
|
+
priority: 1
|
|
489
|
+
},
|
|
490
|
+
{
|
|
491
|
+
title: "Update dependencies",
|
|
492
|
+
prompt: "Check for outdated dependencies. Update patch/minor versions that are safe. Run tests after updating.",
|
|
493
|
+
priority: 2
|
|
494
|
+
},
|
|
495
|
+
{
|
|
496
|
+
title: "Improve test coverage",
|
|
497
|
+
prompt: "Find untested public functions. Write tests for the most critical ones. Target 80%+ coverage.",
|
|
498
|
+
priority: 3
|
|
499
|
+
},
|
|
500
|
+
{
|
|
501
|
+
title: "Fix lint warnings",
|
|
502
|
+
prompt: "Run the project linter. Fix all warnings without changing behavior. Run tests.",
|
|
503
|
+
priority: 4
|
|
504
|
+
},
|
|
505
|
+
{
|
|
506
|
+
title: "Improve documentation",
|
|
507
|
+
prompt: "Review README and code docs. Add missing JSDoc/KDoc for public APIs. Update outdated sections.",
|
|
508
|
+
priority: 5
|
|
509
|
+
},
|
|
510
|
+
{
|
|
511
|
+
title: "Security audit",
|
|
512
|
+
prompt: "Check for common security issues: hardcoded secrets, SQL injection, XSS, insecure defaults. Fix any found.",
|
|
513
|
+
priority: 6
|
|
514
|
+
}
|
|
515
|
+
];
|
|
516
|
+
var TYPE_TASKS = {
|
|
517
|
+
kmp: [
|
|
518
|
+
{
|
|
519
|
+
title: "KMP: Optimize Compose",
|
|
520
|
+
prompt: "Review Compose UI code for recomposition issues. Add @Stable/@Immutable where needed. Check remember usage.",
|
|
521
|
+
priority: 2
|
|
522
|
+
},
|
|
523
|
+
{
|
|
524
|
+
title: "KMP: Check expect/actual",
|
|
525
|
+
prompt: "Review expect/actual declarations. Ensure all platforms have proper implementations. Check for missing iOS/Desktop actuals.",
|
|
526
|
+
priority: 3
|
|
527
|
+
},
|
|
528
|
+
{
|
|
529
|
+
title: "KMP: Room migrations",
|
|
530
|
+
prompt: "Check Room database schema. Ensure migrations are defined for schema changes. Add missing migration tests.",
|
|
531
|
+
priority: 4
|
|
532
|
+
}
|
|
533
|
+
],
|
|
534
|
+
typescript: [
|
|
535
|
+
{
|
|
536
|
+
title: "TS: Strict type safety",
|
|
537
|
+
prompt: "Find `any` types and loose assertions. Replace with proper types. Enable stricter tsconfig options if safe.",
|
|
538
|
+
priority: 2
|
|
539
|
+
}
|
|
540
|
+
],
|
|
541
|
+
react: [
|
|
542
|
+
{
|
|
543
|
+
title: "React: Performance",
|
|
544
|
+
prompt: "Find unnecessary re-renders. Add React.memo, useMemo, useCallback where beneficial. Check bundle size.",
|
|
545
|
+
priority: 2
|
|
546
|
+
}
|
|
547
|
+
],
|
|
548
|
+
python: [
|
|
549
|
+
{
|
|
550
|
+
title: "Python: Type hints",
|
|
551
|
+
prompt: "Add type hints to public functions. Run mypy to check type safety. Fix any type errors.",
|
|
552
|
+
priority: 2
|
|
553
|
+
}
|
|
554
|
+
],
|
|
555
|
+
node: [
|
|
556
|
+
{
|
|
557
|
+
title: "Node: Error handling",
|
|
558
|
+
prompt: "Review async error handling. Add try/catch for unhandled promises. Check for missing error middleware.",
|
|
559
|
+
priority: 2
|
|
560
|
+
}
|
|
561
|
+
]
|
|
562
|
+
};
|
|
563
|
+
function getTasksForProject(type) {
|
|
564
|
+
const specific = TYPE_TASKS[type] ?? [];
|
|
565
|
+
return [...specific, ...COMMON_TASKS].sort(
|
|
566
|
+
(a, b) => a.priority - b.priority
|
|
567
|
+
);
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
// src/lib/lock.ts
|
|
571
|
+
import { mkdirSync as mkdirSync2, readFileSync as readFileSync3, rmSync, writeFileSync } from "fs";
|
|
572
|
+
import { join as join3 } from "path";
|
|
573
|
+
import { homedir as homedir2 } from "os";
|
|
574
|
+
var LOCK_BASE = join3(homedir2(), ".copilot", "locks");
|
|
575
|
+
function lockDir(name) {
|
|
576
|
+
return join3(LOCK_BASE, `${name}.lock`);
|
|
577
|
+
}
|
|
578
|
+
function isPidAlive(pid) {
|
|
579
|
+
try {
|
|
580
|
+
process.kill(pid, 0);
|
|
581
|
+
return true;
|
|
582
|
+
} catch {
|
|
583
|
+
return false;
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
function acquireLock(name, timeoutMs = 3e4) {
|
|
587
|
+
mkdirSync2(LOCK_BASE, { recursive: true });
|
|
588
|
+
const dir = lockDir(name);
|
|
589
|
+
const deadline = Date.now() + timeoutMs;
|
|
590
|
+
while (Date.now() < deadline) {
|
|
591
|
+
try {
|
|
592
|
+
mkdirSync2(dir);
|
|
593
|
+
writeFileSync(join3(dir, "pid"), String(process.pid));
|
|
594
|
+
writeFileSync(join3(dir, "acquired"), (/* @__PURE__ */ new Date()).toISOString());
|
|
595
|
+
return true;
|
|
596
|
+
} catch {
|
|
597
|
+
try {
|
|
598
|
+
const holderPid = parseInt(readFileSync3(join3(dir, "pid"), "utf-8").trim(), 10);
|
|
599
|
+
if (!isPidAlive(holderPid)) {
|
|
600
|
+
rmSync(dir, { recursive: true, force: true });
|
|
601
|
+
continue;
|
|
602
|
+
}
|
|
603
|
+
} catch {
|
|
604
|
+
rmSync(dir, { recursive: true, force: true });
|
|
605
|
+
continue;
|
|
606
|
+
}
|
|
607
|
+
const waitMs = Math.min(500, deadline - Date.now());
|
|
608
|
+
if (waitMs > 0) {
|
|
609
|
+
const start = Date.now();
|
|
610
|
+
while (Date.now() - start < waitMs) {
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
return false;
|
|
616
|
+
}
|
|
617
|
+
function releaseLock(name) {
|
|
618
|
+
const dir = lockDir(name);
|
|
619
|
+
try {
|
|
620
|
+
rmSync(dir, { recursive: true, force: true });
|
|
621
|
+
} catch {
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
async function withLock(name, fn) {
|
|
625
|
+
if (!acquireLock(name)) {
|
|
626
|
+
throw new Error(`Failed to acquire lock: ${name}`);
|
|
627
|
+
}
|
|
628
|
+
try {
|
|
629
|
+
return await fn();
|
|
630
|
+
} finally {
|
|
631
|
+
releaseLock(name);
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
// src/lib/git.ts
|
|
636
|
+
import { execSync as execSync4 } from "child_process";
|
|
637
|
+
function gitBranch(cwd) {
|
|
638
|
+
try {
|
|
639
|
+
return execSync4("git rev-parse --abbrev-ref HEAD", {
|
|
640
|
+
cwd,
|
|
641
|
+
encoding: "utf-8"
|
|
642
|
+
}).trim();
|
|
643
|
+
} catch {
|
|
644
|
+
return "unknown";
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
function gitStatus(cwd) {
|
|
648
|
+
try {
|
|
649
|
+
return execSync4("git status --porcelain", {
|
|
650
|
+
cwd,
|
|
651
|
+
encoding: "utf-8"
|
|
652
|
+
}).trim();
|
|
653
|
+
} catch {
|
|
654
|
+
return "";
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
function gitStash(cwd) {
|
|
658
|
+
execSync4("git stash push -m 'copilot-agent auto-stash'", {
|
|
659
|
+
cwd,
|
|
660
|
+
stdio: "ignore"
|
|
661
|
+
});
|
|
662
|
+
}
|
|
663
|
+
function gitCheckout(cwd, branch) {
|
|
664
|
+
execSync4(`git checkout -B ${branch}`, { cwd, stdio: "ignore" });
|
|
665
|
+
}
|
|
666
|
+
function gitIsRepo(cwd) {
|
|
667
|
+
try {
|
|
668
|
+
execSync4("git rev-parse --git-dir", { cwd, stdio: "ignore" });
|
|
669
|
+
return true;
|
|
670
|
+
} catch {
|
|
671
|
+
return false;
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
// src/commands/run.ts
|
|
676
|
+
async function runCommand(dir, opts) {
|
|
677
|
+
assertCopilot();
|
|
678
|
+
const projectType = detectProjectType(dir);
|
|
679
|
+
const name = detectProjectName(dir);
|
|
680
|
+
log(`Project: ${chalk3.cyan(name)} (${projectType})`);
|
|
681
|
+
const tasks = getTasksForProject(projectType).slice(0, opts.maxTasks);
|
|
682
|
+
if (tasks.length === 0) {
|
|
683
|
+
warn("No tasks found for this project type.");
|
|
684
|
+
return;
|
|
685
|
+
}
|
|
686
|
+
log(`Found ${tasks.length} tasks:`);
|
|
687
|
+
for (const t of tasks) {
|
|
688
|
+
console.log(` ${chalk3.dim("\u2022")} ${t.title}`);
|
|
689
|
+
}
|
|
690
|
+
if (opts.dryRun) {
|
|
691
|
+
log(chalk3.dim("(dry-run \u2014 not executing)"));
|
|
692
|
+
return;
|
|
693
|
+
}
|
|
694
|
+
const originalBranch = gitIsRepo(dir) ? gitBranch(dir) : null;
|
|
695
|
+
let completed = 0;
|
|
696
|
+
let premiumTotal = 0;
|
|
697
|
+
for (const task of tasks) {
|
|
698
|
+
log(`
|
|
699
|
+
${"\u2550".repeat(60)}`);
|
|
700
|
+
log(`Task: ${chalk3.bold(task.title)}`);
|
|
701
|
+
log(`${"\u2550".repeat(60)}`);
|
|
702
|
+
if (originalBranch && gitIsRepo(dir)) {
|
|
703
|
+
const branch = `copilot-agent/${task.title.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`;
|
|
704
|
+
try {
|
|
705
|
+
if (gitStatus(dir)) gitStash(dir);
|
|
706
|
+
gitCheckout(dir, branch);
|
|
707
|
+
} catch (e) {
|
|
708
|
+
warn(`Could not create branch ${branch}, continuing on current.`);
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
const spinner = ora2(`Running: ${task.title}\u2026`).start();
|
|
712
|
+
const result = await withLock(
|
|
713
|
+
"copilot-run",
|
|
714
|
+
() => runCopilotTask(task.prompt, opts.steps)
|
|
715
|
+
);
|
|
716
|
+
spinner.stop();
|
|
717
|
+
premiumTotal += result.premium;
|
|
718
|
+
completed++;
|
|
719
|
+
ok(`${task.title} \u2014 exit ${result.exitCode}, premium: ${result.premium}`);
|
|
720
|
+
if (originalBranch && gitIsRepo(dir)) {
|
|
721
|
+
try {
|
|
722
|
+
gitCheckout(dir, originalBranch);
|
|
723
|
+
} catch {
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
log(`
|
|
728
|
+
Completed ${completed}/${tasks.length} tasks. Total premium: ${premiumTotal}`);
|
|
729
|
+
notify(`Completed ${completed} tasks`, name);
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
// src/commands/overnight.ts
|
|
733
|
+
import chalk4 from "chalk";
|
|
734
|
+
import ora3 from "ora";
|
|
735
|
+
import { join as join4 } from "path";
|
|
736
|
+
import { homedir as homedir3 } from "os";
|
|
737
|
+
async function overnightCommand(dir, opts) {
|
|
738
|
+
assertCopilot();
|
|
739
|
+
const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "").slice(0, 15);
|
|
740
|
+
const logPath = join4(
|
|
741
|
+
homedir3(),
|
|
742
|
+
".copilot",
|
|
743
|
+
"auto-resume-logs",
|
|
744
|
+
`overnight-${ts}.log`
|
|
745
|
+
);
|
|
746
|
+
setLogFile(logPath);
|
|
747
|
+
const deadline = parseDeadline(opts.until);
|
|
748
|
+
const name = detectProjectName(dir);
|
|
749
|
+
const projectType = detectProjectType(dir);
|
|
750
|
+
log(`Overnight runner for ${chalk4.cyan(name)} (${projectType})`);
|
|
751
|
+
log(`Deadline: ${opts.until} (${msToHuman(deadline - Date.now())} from now)`);
|
|
752
|
+
log(`Max premium: ${opts.maxPremium}, Steps: ${opts.steps}`);
|
|
753
|
+
log(`Log: ${logPath}`);
|
|
754
|
+
if (opts.dryRun) {
|
|
755
|
+
const tasks2 = getTasksForProject(projectType);
|
|
756
|
+
log(`
|
|
757
|
+
Would run ${tasks2.length} tasks:`);
|
|
758
|
+
for (const t of tasks2) console.log(` ${chalk4.dim("\u2022")} ${t.title}`);
|
|
759
|
+
return;
|
|
760
|
+
}
|
|
761
|
+
const tasks = getTasksForProject(projectType);
|
|
762
|
+
let taskIdx = 0;
|
|
763
|
+
let totalPremium = 0;
|
|
764
|
+
let completedTasks = 0;
|
|
765
|
+
let cycle = 0;
|
|
766
|
+
while (Date.now() < deadline) {
|
|
767
|
+
if (totalPremium >= opts.maxPremium) {
|
|
768
|
+
warn(`Premium budget exhausted: ${totalPremium}/${opts.maxPremium}`);
|
|
769
|
+
break;
|
|
770
|
+
}
|
|
771
|
+
const task = tasks[taskIdx % tasks.length];
|
|
772
|
+
cycle++;
|
|
773
|
+
taskIdx++;
|
|
774
|
+
log(`
|
|
775
|
+
${"\u2550".repeat(60)}`);
|
|
776
|
+
log(
|
|
777
|
+
`Cycle ${cycle} | Task: ${chalk4.bold(task.title)} | Premium: ${totalPremium}/${opts.maxPremium}`
|
|
778
|
+
);
|
|
779
|
+
log(`Time remaining: ${msToHuman(deadline - Date.now())}`);
|
|
780
|
+
log(`${"\u2550".repeat(60)}`);
|
|
781
|
+
const spinner = ora3(`Running: ${task.title}\u2026`).start();
|
|
782
|
+
try {
|
|
783
|
+
const result = await withLock(
|
|
784
|
+
"copilot-overnight",
|
|
785
|
+
() => runCopilotTask(task.prompt, opts.steps)
|
|
786
|
+
);
|
|
787
|
+
spinner.stop();
|
|
788
|
+
totalPremium += result.premium;
|
|
789
|
+
completedTasks++;
|
|
790
|
+
ok(
|
|
791
|
+
`${task.title} \u2014 exit ${result.exitCode}, premium: ${result.premium}`
|
|
792
|
+
);
|
|
793
|
+
} catch (err) {
|
|
794
|
+
spinner.stop();
|
|
795
|
+
fail(`Task failed: ${err}`);
|
|
796
|
+
}
|
|
797
|
+
if (Date.now() < deadline) {
|
|
798
|
+
log("Cooldown 30s\u2026");
|
|
799
|
+
await sleep3(3e4);
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
const summary = `Overnight done. ${completedTasks} tasks, ${totalPremium} premium.`;
|
|
803
|
+
log(summary);
|
|
804
|
+
notify(summary, name);
|
|
805
|
+
}
|
|
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
|
+
function sleep3(ms) {
|
|
820
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
// src/commands/research.ts
|
|
824
|
+
import chalk5 from "chalk";
|
|
825
|
+
var RESEARCH_PROMPTS = [
|
|
826
|
+
{
|
|
827
|
+
title: "Dependency updates",
|
|
828
|
+
prompt: "Research the latest versions of all dependencies. Check changelogs for breaking changes. Create a summary of what can be safely updated."
|
|
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)}`);
|
|
866
|
+
try {
|
|
867
|
+
const result = await withLock(
|
|
868
|
+
"copilot-research",
|
|
869
|
+
() => runCopilotTask(r.prompt, opts.steps)
|
|
870
|
+
);
|
|
871
|
+
ok(`${r.title} \u2014 premium: ${result.premium}`);
|
|
872
|
+
} catch (err) {
|
|
873
|
+
fail(`${r.title} failed: ${err}`);
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
notify("All research tasks complete");
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
// src/index.ts
|
|
880
|
+
var program = new Command();
|
|
881
|
+
program.name("copilot-agent").description("Autonomous GitHub Copilot CLI agent \u2014 auto-resume, task discovery, overnight runner").version("0.1.0");
|
|
882
|
+
program.command("status").description("Show copilot session status").option("-l, --limit <n>", "Number of sessions to show", "10").option("-a, --active", "Show only active (running) sessions").action(async (opts) => {
|
|
883
|
+
await statusCommand({
|
|
884
|
+
limit: parseInt(opts.limit),
|
|
885
|
+
active: opts.active ?? false
|
|
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
|
+
});
|
|
915
|
+
program.parse();
|
|
916
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +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"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "copilot-agent",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Autonomous GitHub Copilot CLI agent — auto-resume, task discovery, overnight runs",
|
|
5
|
+
"author": "magicpro97",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"keywords": ["copilot", "github", "agent", "autopilot", "cli", "automation", "ai"],
|
|
8
|
+
"repository": { "type": "git", "url": "https://github.com/magicpro97/copilot-agent" },
|
|
9
|
+
"bin": { "copilot-agent": "./dist/index.js" },
|
|
10
|
+
"files": ["dist"],
|
|
11
|
+
"type": "module",
|
|
12
|
+
"engines": { "node": ">=18" },
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsup",
|
|
15
|
+
"dev": "tsup --watch",
|
|
16
|
+
"start": "node dist/index.js",
|
|
17
|
+
"lint": "tsc --noEmit",
|
|
18
|
+
"prepublishOnly": "npm run build"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"chalk": "^5.4.1",
|
|
22
|
+
"commander": "^13.1.0",
|
|
23
|
+
"execa": "^9.5.2",
|
|
24
|
+
"find-up": "^7.0.0",
|
|
25
|
+
"ora": "^8.2.0",
|
|
26
|
+
"proper-lockfile": "^4.1.2",
|
|
27
|
+
"ps-list": "^9.0.0",
|
|
28
|
+
"yaml": "^2.7.1"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@types/proper-lockfile": "^4.1.4",
|
|
32
|
+
"@types/node": "^22.15.2",
|
|
33
|
+
"tsup": "^8.4.0",
|
|
34
|
+
"typescript": "^5.8.3"
|
|
35
|
+
}
|
|
36
|
+
}
|