autodev-cli 1.4.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 +174 -0
- package/bin/autodev-ping.js +83 -0
- package/bin/autodev-watch.js +138 -0
- package/bin/autodev.js +11 -0
- package/out/cli.js +119 -0
- package/out/cli.js.map +1 -0
- package/out/commands/config.js +124 -0
- package/out/commands/config.js.map +1 -0
- package/out/commands/connect.js +66 -0
- package/out/commands/connect.js.map +1 -0
- package/out/commands/init.js +195 -0
- package/out/commands/init.js.map +1 -0
- package/out/commands/start.js +86 -0
- package/out/commands/start.js.map +1 -0
- package/out/commands/status.js +103 -0
- package/out/commands/status.js.map +1 -0
- package/out/commands/tailOutput.js +102 -0
- package/out/commands/tailOutput.js.map +1 -0
- package/out/commands/up.js +82 -0
- package/out/commands/up.js.map +1 -0
- package/out/connect.js +169 -0
- package/out/connect.js.map +1 -0
- package/out/launchIde.js +218 -0
- package/out/launchIde.js.map +1 -0
- package/out/logger.js +47 -0
- package/out/logger.js.map +1 -0
- package/package.json +41 -0
package/README.md
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# autodev-cli
|
|
2
|
+
|
|
3
|
+
AutoAIDev's CLI — autonomous AI task loop with an optional one-shot launcher for **VS Code** and **Cursor**, plus a wire-protocol for connecting a workspace to a pixel-office server.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
# Install globally
|
|
7
|
+
npm install -g autodev-cli
|
|
8
|
+
|
|
9
|
+
# Init the current folder + open it in VS Code (or Cursor)
|
|
10
|
+
autodev --ide=vscode .
|
|
11
|
+
autodev --ide=cursor .
|
|
12
|
+
|
|
13
|
+
# Connect to a pixel-office agent in one shot (signed URL from the UI)
|
|
14
|
+
autodev --setup-url='https://pixel-office.tools.ooyes.net/api/cli/setup/<id>?expires=…&signature=…' .
|
|
15
|
+
|
|
16
|
+
# Or paste the WS URL directly
|
|
17
|
+
autodev --connect='wss://pixel-office.tools.ooyes.net/ws?token=<api_key>&endpoint=<slug>' .
|
|
18
|
+
|
|
19
|
+
# Combine the two: init + open IDE + bind credentials
|
|
20
|
+
autodev --setup-url='…' --ide=vscode .
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
That single command:
|
|
24
|
+
|
|
25
|
+
1. Creates `TODO.md` and `.autodev/settings.json`
|
|
26
|
+
2. Adds `.autodev/` to `.gitignore`
|
|
27
|
+
3. Installs the **AutoAIDev** extension into the chosen IDE (skipped if already installed)
|
|
28
|
+
4. Opens the folder in the IDE
|
|
29
|
+
5. (with `--setup-url` / `--connect`) writes the pixel-office credentials into `.autodev/settings.json`
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Install (from this repo)
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
cd autodev-cli
|
|
37
|
+
npm install
|
|
38
|
+
npm run build
|
|
39
|
+
npm link # optional — adds `autodev` to your PATH
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
> Requires the sibling `autodev-vscode-extension` to be compiled first:
|
|
43
|
+
> ```bash
|
|
44
|
+
> cd ../autodev-vscode-extension
|
|
45
|
+
> npm install
|
|
46
|
+
> npm run compile
|
|
47
|
+
> ```
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Commands
|
|
52
|
+
|
|
53
|
+
### `autodev --ide=<ide> [path]` — top-level shortcut
|
|
54
|
+
Same as `autodev up --ide=<ide>`. Inits the workspace and launches the IDE.
|
|
55
|
+
|
|
56
|
+
### `autodev up --ide=<ide> [path]`
|
|
57
|
+
Init + launch in one step. Auto-installs the extension if missing.
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
autodev up --ide=vscode .
|
|
61
|
+
autodev up --ide=cursor ~/myproject -p copilot-cli
|
|
62
|
+
autodev up --ide=vscode . --no-extension # skip extension install
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### `autodev launch --ide=<ide> [path]`
|
|
66
|
+
Open an existing workspace in an IDE. No init.
|
|
67
|
+
|
|
68
|
+
### `autodev connect --setup-url=<url> [path]` / `autodev connect --url=<wsurl> [path]`
|
|
69
|
+
Bind the workspace to a pixel-office agent.
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
# Signed URL from the pixel-office UI (preferred)
|
|
73
|
+
autodev connect --setup-url='https://pixel-office.tools.ooyes.net/api/cli/setup/<id>?expires=…&signature=…' .
|
|
74
|
+
|
|
75
|
+
# Or paste a full WS URL
|
|
76
|
+
autodev connect --url='wss://host/ws?token=<api_key>&endpoint=<slug>' .
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Either form writes `wsUrl`, `serverApiKey`, `webhookSlug`, and `serverBaseUrl` into `.autodev/settings.json`. The signed URL is HMAC-protected and expires in 30 minutes.
|
|
80
|
+
|
|
81
|
+
### `autodev init [path]`
|
|
82
|
+
Scaffold a workspace — `TODO.md` and `.vscode/autodev.json`.
|
|
83
|
+
Pass `--ide=vscode|cursor` to also open it after init.
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
autodev init # current directory
|
|
87
|
+
autodev init ~/myproject # specific path
|
|
88
|
+
autodev init . --ide=vscode # also open in VS Code
|
|
89
|
+
autodev init . --ide=cursor --no-extension # don't auto-install extension
|
|
90
|
+
autodev init . --provider claude-cli # pick the default provider
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### `autodev start [path]`
|
|
94
|
+
Start the autonomous loop — reads `TODO.md` and drives the AI until all tasks are done.
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
autodev start # current directory, claude-cli
|
|
98
|
+
autodev start ~/myproject -p copilot-cli
|
|
99
|
+
autodev start . --provider opencode-cli
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Press **Ctrl+C** to stop gracefully.
|
|
103
|
+
|
|
104
|
+
### `autodev status [path]`
|
|
105
|
+
Summary of tasks in `TODO.md`.
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
autodev status
|
|
109
|
+
autodev status ~/myproject --all # also list completed tasks
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### `autodev config [path]`
|
|
113
|
+
Read or update `.vscode/autodev.json`.
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
autodev config # print all settings
|
|
117
|
+
autodev config get provider # get one value
|
|
118
|
+
autodev config set provider copilot-cli # set provider
|
|
119
|
+
autodev config set taskTimeoutMinutes 60
|
|
120
|
+
autodev config set discordToken TOKEN
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## IDE launcher details
|
|
126
|
+
|
|
127
|
+
| `--ide` value | Resolves to | Extension installed |
|
|
128
|
+
|---------------|-------------|---------------------|
|
|
129
|
+
| `vscode` | `code` (or `code-insiders`) on PATH | `AutoAIDev.autoaidev` |
|
|
130
|
+
| `cursor` | `cursor` on PATH | `AutoAIDev.autoaidev` |
|
|
131
|
+
|
|
132
|
+
The launcher first looks for a sibling `autoaidev.vsix` next to the CLI install (handy for offline / dev installs). If it can't find one it falls back to the marketplace id `AutoAIDev.autoaidev`.
|
|
133
|
+
|
|
134
|
+
Pass `--no-extension` to skip the extension install. Pass `--no-launch` (only on `init`) to install the extension without opening the IDE.
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## Configuration
|
|
139
|
+
|
|
140
|
+
Settings live in `.autodev/settings.json` inside the workspace. The legacy path `.vscode/autodev.json` is still read for back-compat — the next write migrates it to the new location automatically. Highlights:
|
|
141
|
+
|
|
142
|
+
| Key | Default | Description |
|
|
143
|
+
|-----|---------|-------------|
|
|
144
|
+
| `provider` | `claude-cli` | AI provider to use |
|
|
145
|
+
| `loopInterval` | `30` | Seconds between polling cycles |
|
|
146
|
+
| `taskTimeoutMinutes` | `30` | Minutes of TODO.md inactivity before timeout |
|
|
147
|
+
| `taskCheckInMinutes` | `20` | Minutes of JSONL inactivity before reminder |
|
|
148
|
+
| `discordToken` | `""` | Discord bot token for notifications |
|
|
149
|
+
| `discordChannelId` | `""` | Discord channel for notifications |
|
|
150
|
+
| `serverBaseUrl` | `""` | A2A webhook server URL |
|
|
151
|
+
| `serverApiKey` | `""` | A2A webhook API key |
|
|
152
|
+
| `gitEnabled` | `false` | Enable git commit after each task |
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## How the loop works
|
|
157
|
+
|
|
158
|
+
1. Reads `TODO.md` from the workspace root
|
|
159
|
+
2. Picks the first `[ ]` task, sends a prompt to the chosen AI CLI provider
|
|
160
|
+
3. Watches `TODO.md` for the AI to mark the task `[x]` done
|
|
161
|
+
4. Loops until all tasks are complete
|
|
162
|
+
5. Sends Discord / webhook notifications at each step
|
|
163
|
+
|
|
164
|
+
The loop never stops while `[ ]` or `[~]` tasks remain.
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## Providers
|
|
169
|
+
|
|
170
|
+
| Provider | CLI command |
|
|
171
|
+
|----------|-------------|
|
|
172
|
+
| `claude-cli` | `claude` (Anthropic Claude CLI) |
|
|
173
|
+
| `copilot-cli` | `gh copilot` (GitHub Copilot CLI) |
|
|
174
|
+
| `opencode-cli` | `opencode` (OpenCode CLI) |
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Quick WS-handshake verifier. Reads wsUrl from <cwd>/.autodev/settings.json
|
|
3
|
+
// (or .vscode/autodev.json), opens a WebSocket connection, waits for the
|
|
4
|
+
// server's first frame (or a 2s grace period), then exits 0 on success.
|
|
5
|
+
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
const http = require('http');
|
|
9
|
+
const https = require('https');
|
|
10
|
+
const crypto = require('crypto');
|
|
11
|
+
|
|
12
|
+
const cwd = process.argv[2] ? path.resolve(process.argv[2]) : process.cwd();
|
|
13
|
+
const candidates = [
|
|
14
|
+
path.join(cwd, '.autodev', 'settings.json'),
|
|
15
|
+
path.join(cwd, '.vscode', 'autodev.json'),
|
|
16
|
+
];
|
|
17
|
+
const file = candidates.find(p => fs.existsSync(p));
|
|
18
|
+
if (!file) { console.error('No settings file found in', cwd); process.exit(1); }
|
|
19
|
+
const settings = JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
20
|
+
const wsUrl = settings.wsUrl;
|
|
21
|
+
if (!wsUrl) { console.error('settings.wsUrl is empty'); process.exit(1); }
|
|
22
|
+
|
|
23
|
+
const u = new URL(wsUrl);
|
|
24
|
+
const isTls = u.protocol === 'wss:';
|
|
25
|
+
const lib = isTls ? https : http;
|
|
26
|
+
const port = u.port ? Number(u.port) : (isTls ? 443 : 80);
|
|
27
|
+
const key = crypto.randomBytes(16).toString('base64');
|
|
28
|
+
|
|
29
|
+
console.log(`Connecting to ${wsUrl}…`);
|
|
30
|
+
const req = lib.request({
|
|
31
|
+
host: u.hostname,
|
|
32
|
+
port,
|
|
33
|
+
path: u.pathname + u.search,
|
|
34
|
+
method: 'GET',
|
|
35
|
+
headers: {
|
|
36
|
+
'Connection': 'Upgrade',
|
|
37
|
+
'Upgrade': 'websocket',
|
|
38
|
+
'Sec-WebSocket-Version': '13',
|
|
39
|
+
'Sec-WebSocket-Key': key,
|
|
40
|
+
'Origin': `${u.protocol}//${u.hostname}`,
|
|
41
|
+
'User-Agent': 'autodev-ping',
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
req.on('upgrade', (res, socket) => {
|
|
46
|
+
console.log('Handshake OK — status', res.statusCode);
|
|
47
|
+
let closed = false;
|
|
48
|
+
socket.on('data', (buf) => {
|
|
49
|
+
if (closed) return;
|
|
50
|
+
closed = true;
|
|
51
|
+
console.log('First frame:', buf.length, 'bytes — server is talking.');
|
|
52
|
+
try { socket.destroy(); } catch {}
|
|
53
|
+
setTimeout(() => process.exit(0), 50);
|
|
54
|
+
});
|
|
55
|
+
setTimeout(() => {
|
|
56
|
+
if (closed) return;
|
|
57
|
+
console.log('No frame in 2.5s, but handshake succeeded — connection is alive.');
|
|
58
|
+
try { socket.destroy(); } catch {}
|
|
59
|
+
process.exit(0);
|
|
60
|
+
}, 2500);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
req.on('response', (res) => {
|
|
64
|
+
let body = '';
|
|
65
|
+
res.on('data', c => body += c);
|
|
66
|
+
res.on('end', () => {
|
|
67
|
+
console.error(`Server returned HTTP ${res.statusCode} (no upgrade): ${body.slice(0, 300)}`);
|
|
68
|
+
process.exit(2);
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
req.on('error', (err) => {
|
|
73
|
+
console.error('Connection error:', err.message);
|
|
74
|
+
process.exit(2);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
req.setTimeout(10_000, () => {
|
|
78
|
+
console.error('Timed out waiting for handshake');
|
|
79
|
+
req.destroy();
|
|
80
|
+
process.exit(2);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
req.end();
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Long-lived WS watcher — opens the agent's WebSocket and prints all text
|
|
3
|
+
// frames received. Use this to verify task delivery end-to-end.
|
|
4
|
+
//
|
|
5
|
+
// Usage: node autodev-watch.js [workspaceDir] [seconds]
|
|
6
|
+
// default workspaceDir = cwd
|
|
7
|
+
// default seconds = 30
|
|
8
|
+
//
|
|
9
|
+
// Reads wsUrl from <workspaceDir>/.autodev/settings.json (or .vscode/autodev.json).
|
|
10
|
+
|
|
11
|
+
const fs = require('fs');
|
|
12
|
+
const path = require('path');
|
|
13
|
+
const http = require('http');
|
|
14
|
+
const https = require('https');
|
|
15
|
+
const crypto = require('crypto');
|
|
16
|
+
|
|
17
|
+
const cwd = process.argv[2] ? path.resolve(process.argv[2]) : process.cwd();
|
|
18
|
+
const watchSeconds = process.argv[3] ? Number(process.argv[3]) : 30;
|
|
19
|
+
|
|
20
|
+
const candidates = [
|
|
21
|
+
path.join(cwd, '.autodev', 'settings.json'),
|
|
22
|
+
path.join(cwd, '.vscode', 'autodev.json'),
|
|
23
|
+
];
|
|
24
|
+
const file = candidates.find(p => fs.existsSync(p));
|
|
25
|
+
if (!file) { console.error('No settings file found in', cwd); process.exit(1); }
|
|
26
|
+
const settings = JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
27
|
+
const wsUrl = settings.wsUrl;
|
|
28
|
+
if (!wsUrl) { console.error('settings.wsUrl is empty'); process.exit(1); }
|
|
29
|
+
|
|
30
|
+
const u = new URL(wsUrl);
|
|
31
|
+
const isTls = u.protocol === 'wss:';
|
|
32
|
+
const lib = isTls ? https : http;
|
|
33
|
+
const port = u.port ? Number(u.port) : (isTls ? 443 : 80);
|
|
34
|
+
const key = crypto.randomBytes(16).toString('base64');
|
|
35
|
+
|
|
36
|
+
console.log(`[watch] Connecting to ${wsUrl}`);
|
|
37
|
+
console.log(`[watch] Watching for ${watchSeconds}s, then exiting.`);
|
|
38
|
+
|
|
39
|
+
const req = lib.request({
|
|
40
|
+
host: u.hostname,
|
|
41
|
+
port,
|
|
42
|
+
path: u.pathname + u.search,
|
|
43
|
+
method: 'GET',
|
|
44
|
+
headers: {
|
|
45
|
+
'Connection': 'Upgrade',
|
|
46
|
+
'Upgrade': 'websocket',
|
|
47
|
+
'Sec-WebSocket-Version': '13',
|
|
48
|
+
'Sec-WebSocket-Key': key,
|
|
49
|
+
'Origin': `${u.protocol}//${u.hostname}`,
|
|
50
|
+
'User-Agent': 'autodev-watch',
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
req.on('upgrade', (res, socket) => {
|
|
55
|
+
console.log(`[watch] Handshake OK — status ${res.statusCode}`);
|
|
56
|
+
|
|
57
|
+
// Minimal RFC 6455 frame parser. Server-to-client frames are unmasked.
|
|
58
|
+
let buf = Buffer.alloc(0);
|
|
59
|
+
|
|
60
|
+
socket.on('data', (chunk) => {
|
|
61
|
+
buf = Buffer.concat([buf, chunk]);
|
|
62
|
+
while (buf.length >= 2) {
|
|
63
|
+
const fin = (buf[0] & 0x80) !== 0;
|
|
64
|
+
const opcode = buf[0] & 0x0f;
|
|
65
|
+
const masked = (buf[1] & 0x80) !== 0;
|
|
66
|
+
let len = buf[1] & 0x7f;
|
|
67
|
+
let off = 2;
|
|
68
|
+
|
|
69
|
+
if (len === 126) {
|
|
70
|
+
if (buf.length < 4) break;
|
|
71
|
+
len = buf.readUInt16BE(2); off = 4;
|
|
72
|
+
} else if (len === 127) {
|
|
73
|
+
if (buf.length < 10) break;
|
|
74
|
+
len = Number(buf.readBigUInt64BE(2)); off = 10;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
let mask = null;
|
|
78
|
+
if (masked) { if (buf.length < off + 4) break; mask = buf.slice(off, off + 4); off += 4; }
|
|
79
|
+
if (buf.length < off + len) break;
|
|
80
|
+
|
|
81
|
+
let payload = buf.slice(off, off + len);
|
|
82
|
+
if (mask) {
|
|
83
|
+
const out = Buffer.alloc(payload.length);
|
|
84
|
+
for (let i = 0; i < payload.length; i++) out[i] = payload[i] ^ mask[i % 4];
|
|
85
|
+
payload = out;
|
|
86
|
+
}
|
|
87
|
+
buf = buf.slice(off + len);
|
|
88
|
+
|
|
89
|
+
if (opcode === 0x1) { // text frame
|
|
90
|
+
const text = payload.toString('utf8');
|
|
91
|
+
const ts = new Date().toISOString().slice(11, 19);
|
|
92
|
+
console.log(`[${ts}] ← ${truncate(text, 800)}`);
|
|
93
|
+
} else if (opcode === 0x9) { // ping → pong
|
|
94
|
+
const pong = makeMaskedFrame(0xa, payload);
|
|
95
|
+
socket.write(pong);
|
|
96
|
+
} else if (opcode === 0x8) { // close
|
|
97
|
+
console.log(`[watch] Server closed the connection.`);
|
|
98
|
+
socket.end();
|
|
99
|
+
process.exit(0);
|
|
100
|
+
}
|
|
101
|
+
if (!fin) break; // continuation handling intentionally minimal
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
socket.on('error', (e) => { console.error('[watch] socket error:', e.message); process.exit(1); });
|
|
106
|
+
socket.on('close', () => { console.log('[watch] socket closed'); process.exit(0); });
|
|
107
|
+
|
|
108
|
+
setTimeout(() => {
|
|
109
|
+
console.log(`[watch] ${watchSeconds}s elapsed — exiting.`);
|
|
110
|
+
try { socket.end(); } catch {}
|
|
111
|
+
setTimeout(() => process.exit(0), 100);
|
|
112
|
+
}, watchSeconds * 1000);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
req.on('response', (res) => {
|
|
116
|
+
let body = '';
|
|
117
|
+
res.on('data', c => body += c);
|
|
118
|
+
res.on('end', () => {
|
|
119
|
+
console.error(`[watch] Server returned HTTP ${res.statusCode}: ${body.slice(0, 300)}`);
|
|
120
|
+
process.exit(2);
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
req.on('error', (err) => { console.error('[watch] Connection error:', err.message); process.exit(2); });
|
|
124
|
+
req.end();
|
|
125
|
+
|
|
126
|
+
function makeMaskedFrame(opcode, payload) {
|
|
127
|
+
const mask = crypto.randomBytes(4);
|
|
128
|
+
const len = payload.length;
|
|
129
|
+
let header;
|
|
130
|
+
if (len < 126) header = Buffer.from([0x80 | opcode, 0x80 | len]);
|
|
131
|
+
else if (len < 65536) { header = Buffer.alloc(4); header[0] = 0x80 | opcode; header[1] = 0x80 | 126; header.writeUInt16BE(len, 2); }
|
|
132
|
+
else { header = Buffer.alloc(10); header[0] = 0x80 | opcode; header[1] = 0x80 | 127; header.writeBigUInt64BE(BigInt(len), 2); }
|
|
133
|
+
const masked = Buffer.alloc(payload.length);
|
|
134
|
+
for (let i = 0; i < payload.length; i++) masked[i] = payload[i] ^ mask[i % 4];
|
|
135
|
+
return Buffer.concat([header, mask, masked]);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function truncate(s, n) { return s.length > n ? s.slice(0, n) + ` … (+${s.length - n} bytes)` : s; }
|
package/bin/autodev.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
|
|
5
|
+
const compiled = path.join(__dirname, '..', 'out', 'cli.js');
|
|
6
|
+
if (!fs.existsSync(compiled)) {
|
|
7
|
+
console.error('autodev-cli: missing compiled output.');
|
|
8
|
+
console.error('Run `npm run build` inside the autodev-cli directory and try again.');
|
|
9
|
+
process.exit(1);
|
|
10
|
+
}
|
|
11
|
+
require(compiled);
|
package/out/cli.js
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
const path = __importStar(require("path"));
|
|
37
|
+
const commander_1 = require("commander");
|
|
38
|
+
const start_1 = require("./commands/start");
|
|
39
|
+
const init_1 = require("./commands/init");
|
|
40
|
+
const config_1 = require("./commands/config");
|
|
41
|
+
const status_1 = require("./commands/status");
|
|
42
|
+
const up_1 = require("./commands/up");
|
|
43
|
+
const connect_1 = require("./commands/connect");
|
|
44
|
+
const tailOutput_1 = require("./commands/tailOutput");
|
|
45
|
+
const connect_2 = require("./connect");
|
|
46
|
+
const logger_1 = require("./logger");
|
|
47
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
48
|
+
const { version } = require('../package.json');
|
|
49
|
+
const program = new commander_1.Command()
|
|
50
|
+
.name('autodev')
|
|
51
|
+
.description('AutoAIDev — autonomous AI task loop with optional IDE launcher and pixel-office connect')
|
|
52
|
+
.version(version)
|
|
53
|
+
// Without this, the program-level --ide / --setup-url / --connect options
|
|
54
|
+
// greedily eat the same option names from subcommands. With it, anything
|
|
55
|
+
// after a subcommand name is parsed against that subcommand only.
|
|
56
|
+
.enablePositionalOptions()
|
|
57
|
+
// Top-level shortcuts. Any combination is valid:
|
|
58
|
+
// autodev --ide=vscode .
|
|
59
|
+
// autodev --setup-url=https://… .
|
|
60
|
+
// autodev --setup-url=https://… --ide=cursor .
|
|
61
|
+
// autodev --connect=wss://host?token=…&endpoint=… .
|
|
62
|
+
.option('--ide <ide>', 'Init and launch the workspace in an IDE (vscode | cursor)')
|
|
63
|
+
.option('-p, --provider <provider>', 'Default AI provider', 'claude-cli')
|
|
64
|
+
.option('--force', 'Overwrite existing files (with --ide)')
|
|
65
|
+
.option('--no-extension', 'Skip auto-installing the autoaidev extension (with --ide)')
|
|
66
|
+
.option('--connect <wsurl>', 'Bind the workspace to a ws:// / wss:// URL with ?token=&endpoint=')
|
|
67
|
+
.option('--setup-url <url>', 'Bind the workspace using a signed pixel-office setup URL')
|
|
68
|
+
.option('--git', 'Enable git auto-commit')
|
|
69
|
+
.option('--file-browser', 'Enable file browser tab')
|
|
70
|
+
.option('--profile <path>', 'Use this AUTODEV.md profile')
|
|
71
|
+
.argument('[path]', 'Workspace path (default: cwd)')
|
|
72
|
+
.action(async (maybePath, opts) => {
|
|
73
|
+
const cwd = maybePath ? path.resolve(maybePath) : process.cwd();
|
|
74
|
+
const didSomething = !!(opts.ide || opts.connect || opts.setupUrl);
|
|
75
|
+
if (!didSomething) {
|
|
76
|
+
program.help();
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
// Order matters: bind credentials FIRST so when the extension activates
|
|
80
|
+
// on IDE launch, it reads the up-to-date wsUrl + autoStartLoop flag and
|
|
81
|
+
// can auto-connect immediately. Otherwise the extension activates with
|
|
82
|
+
// stale settings and the user has to reload the window.
|
|
83
|
+
try {
|
|
84
|
+
if (opts.setupUrl) {
|
|
85
|
+
await (0, connect_2.applySetupUrl)(cwd, opts.setupUrl);
|
|
86
|
+
}
|
|
87
|
+
else if (opts.connect) {
|
|
88
|
+
(0, connect_2.applyWsUrl)(cwd, opts.connect);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
catch (err) {
|
|
92
|
+
logger_1.log.error(err.message);
|
|
93
|
+
process.exit(1);
|
|
94
|
+
}
|
|
95
|
+
if (opts.ide || opts.git || opts.fileBrowser || opts.profile) {
|
|
96
|
+
(0, init_1.runInit)(maybePath, {
|
|
97
|
+
ide: opts.ide,
|
|
98
|
+
provider: opts.provider,
|
|
99
|
+
force: opts.force,
|
|
100
|
+
extension: opts.extension,
|
|
101
|
+
git: opts.git,
|
|
102
|
+
fileBrowser: opts.fileBrowser,
|
|
103
|
+
profile: opts.profile,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
(0, start_1.startCommand)(program);
|
|
108
|
+
(0, init_1.initCommand)(program);
|
|
109
|
+
(0, up_1.upCommand)(program);
|
|
110
|
+
(0, up_1.launchCommand)(program);
|
|
111
|
+
(0, connect_1.connectCommand)(program);
|
|
112
|
+
(0, tailOutput_1.tailOutputCommand)(program);
|
|
113
|
+
(0, config_1.configCommand)(program);
|
|
114
|
+
(0, status_1.statusCommand)(program);
|
|
115
|
+
program.parseAsync(process.argv).catch((err) => {
|
|
116
|
+
console.error(err.message);
|
|
117
|
+
process.exit(1);
|
|
118
|
+
});
|
|
119
|
+
//# sourceMappingURL=cli.js.map
|
package/out/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.configCommand = configCommand;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
const logger_1 = require("../logger");
|
|
40
|
+
const settings_1 = require("autoaidev/settings");
|
|
41
|
+
function configPath(cwd) {
|
|
42
|
+
// Read path: prefer the canonical .autodev/settings.json, fall back to the
|
|
43
|
+
// legacy .vscode/autodev.json if the new file is absent.
|
|
44
|
+
const canonical = path.join(cwd, '.autodev', 'settings.json');
|
|
45
|
+
if (fs.existsSync(canonical)) {
|
|
46
|
+
return canonical;
|
|
47
|
+
}
|
|
48
|
+
const legacy = path.join(cwd, '.vscode', 'autodev.json');
|
|
49
|
+
if (fs.existsSync(legacy)) {
|
|
50
|
+
return legacy;
|
|
51
|
+
}
|
|
52
|
+
return canonical;
|
|
53
|
+
}
|
|
54
|
+
function configWritePath(cwd) {
|
|
55
|
+
return path.join(cwd, '.autodev', 'settings.json');
|
|
56
|
+
}
|
|
57
|
+
function saveSettings(cwd, settings) {
|
|
58
|
+
const file = configWritePath(cwd);
|
|
59
|
+
const dir = path.dirname(file);
|
|
60
|
+
if (!fs.existsSync(dir)) {
|
|
61
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
62
|
+
}
|
|
63
|
+
fs.writeFileSync(file, JSON.stringify(settings, null, 2) + '\n', 'utf8');
|
|
64
|
+
}
|
|
65
|
+
function configCommand(program) {
|
|
66
|
+
const cmd = program
|
|
67
|
+
.command('config')
|
|
68
|
+
.description('Read or write workspace configuration (.autodev/settings.json)')
|
|
69
|
+
.argument('[path]', 'Workspace directory (default: cwd)');
|
|
70
|
+
// autodev config [path] — print all settings
|
|
71
|
+
cmd.action((workspacePath) => {
|
|
72
|
+
const cwd = workspacePath ? path.resolve(workspacePath) : process.cwd();
|
|
73
|
+
const settings = (0, settings_1.loadSettingsForRoot)(cwd);
|
|
74
|
+
logger_1.log.section('⚙ AutoDev Config');
|
|
75
|
+
logger_1.log.info(`File: ${configPath(cwd)}`);
|
|
76
|
+
logger_1.log.plain('');
|
|
77
|
+
for (const [k, v] of Object.entries(settings)) {
|
|
78
|
+
const masked = typeof v === 'string' && (k.toLowerCase().includes('token') || k.toLowerCase().includes('password') || k.toLowerCase().includes('apikey'))
|
|
79
|
+
? (v ? '***' : '')
|
|
80
|
+
: String(v);
|
|
81
|
+
logger_1.log.plain(` ${k.padEnd(28)} ${masked}`);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
// autodev config set <key> <value> [path]
|
|
85
|
+
cmd
|
|
86
|
+
.command('set <key> <value> [path]')
|
|
87
|
+
.description('Set a config value')
|
|
88
|
+
.action((key, value, workspacePath) => {
|
|
89
|
+
const cwd = workspacePath ? path.resolve(workspacePath) : process.cwd();
|
|
90
|
+
const settings = (0, settings_1.loadSettingsForRoot)(cwd);
|
|
91
|
+
if (!(key in settings_1.SETTINGS_DEFAULTS)) {
|
|
92
|
+
logger_1.log.error(`Unknown key "${key}". Valid keys: ${Object.keys(settings_1.SETTINGS_DEFAULTS).join(', ')}`);
|
|
93
|
+
process.exit(1);
|
|
94
|
+
}
|
|
95
|
+
const defaultVal = settings_1.SETTINGS_DEFAULTS[key];
|
|
96
|
+
let parsed;
|
|
97
|
+
if (typeof defaultVal === 'number') {
|
|
98
|
+
parsed = Number(value);
|
|
99
|
+
}
|
|
100
|
+
else if (typeof defaultVal === 'boolean') {
|
|
101
|
+
parsed = value === 'true' || value === '1';
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
parsed = value;
|
|
105
|
+
}
|
|
106
|
+
settings[key] = parsed;
|
|
107
|
+
saveSettings(cwd, settings);
|
|
108
|
+
logger_1.log.success(`Set ${key} = ${value}`);
|
|
109
|
+
});
|
|
110
|
+
// autodev config get <key> [path]
|
|
111
|
+
cmd
|
|
112
|
+
.command('get <key> [path]')
|
|
113
|
+
.description('Get a config value')
|
|
114
|
+
.action((key, workspacePath) => {
|
|
115
|
+
const cwd = workspacePath ? path.resolve(workspacePath) : process.cwd();
|
|
116
|
+
const settings = (0, settings_1.loadSettingsForRoot)(cwd);
|
|
117
|
+
if (!(key in settings)) {
|
|
118
|
+
logger_1.log.error(`Unknown key "${key}"`);
|
|
119
|
+
process.exit(1);
|
|
120
|
+
}
|
|
121
|
+
console.log(String(settings[key]));
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"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"}
|