agentp 0.3.0 → 0.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 +3 -2
- package/bin/agentp +28 -3
- package/bin/ocmux +36 -26
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -41,6 +41,7 @@ Notes:
|
|
|
41
41
|
- `agentp` connects to the OpenCode event endpoint over HTTP.
|
|
42
42
|
- In practice this means running `opencode serve` (or equivalent serve mode) so the port is open.
|
|
43
43
|
- `opencode attach` is optional but useful to monitor the full conversation in another terminal/tmux pane.
|
|
44
|
+
- If the OpenCode server is password-protected (`OPENCODE_SERVER_PASSWORD`), both `agentp` and `ocmux` automatically send the required HTTP Basic Auth credentials.
|
|
44
45
|
|
|
45
46
|
## Usage
|
|
46
47
|
|
|
@@ -121,7 +122,7 @@ Without arguments, searches upward from `<directory>` (default: `$PWD`) for `.oc
|
|
|
121
122
|
|
|
122
123
|
Subcommands:
|
|
123
124
|
|
|
124
|
-
- **`
|
|
125
|
+
- **`serve [--git|--GIT] [dir]`** — Create a server in `dir` (default: `$PWD`) and attach a TUI pane. Aliased as `new` for backwards compatibility. Errors if one already exists there. Warns if a parent directory already has a server.
|
|
125
126
|
- `--git` resolves `dir` to the nearest parent with a `.git` entry (file or dir); errors if none is found.
|
|
126
127
|
- `--GIT` resolves `dir` to the nearest parent with a `.git` directory only; errors if none is found.
|
|
127
128
|
- **`kill [dir]`** — Kill the server found upward from `dir`. Removes its tmux window and state file.
|
|
@@ -129,7 +130,7 @@ Subcommands:
|
|
|
129
130
|
|
|
130
131
|
Options:
|
|
131
132
|
|
|
132
|
-
- `-l`: long output for default/
|
|
133
|
+
- `-l`: long output for default/serve commands (append `→ <dir>` after the URL)
|
|
133
134
|
- `--version`: show version
|
|
134
135
|
- `-h`: show help message
|
|
135
136
|
- `--`: treat the next argument as a directory even if it matches a subcommand name
|
package/bin/agentp
CHANGED
|
@@ -4,12 +4,26 @@ const http = require('http');
|
|
|
4
4
|
const { URL } = require('url');
|
|
5
5
|
const { version } = require('../package.json');
|
|
6
6
|
|
|
7
|
+
function getAuthHeaders() {
|
|
8
|
+
const password = process.env.OPENCODE_SERVER_PASSWORD;
|
|
9
|
+
if (!password) return {};
|
|
10
|
+
const username = process.env.OPENCODE_SERVER_USERNAME || 'opencode';
|
|
11
|
+
const encoded = Buffer.from(`${username}:${password}`).toString('base64');
|
|
12
|
+
return { 'Authorization': `Basic ${encoded}` };
|
|
13
|
+
}
|
|
14
|
+
|
|
7
15
|
function makeRequest(options, data) {
|
|
8
16
|
return new Promise((resolve, reject) => {
|
|
9
17
|
const req = http.request(options, (res) => {
|
|
10
18
|
let body = '';
|
|
11
19
|
res.on('data', (chunk) => { body += chunk; });
|
|
12
|
-
res.on('end', () =>
|
|
20
|
+
res.on('end', () => {
|
|
21
|
+
if (res.statusCode === 401) {
|
|
22
|
+
reject(new Error('OpenCode server authentication failed. Set OPENCODE_SERVER_PASSWORD to match the server password.'));
|
|
23
|
+
} else {
|
|
24
|
+
resolve({ status: res.statusCode, body });
|
|
25
|
+
}
|
|
26
|
+
});
|
|
13
27
|
});
|
|
14
28
|
req.on('error', reject);
|
|
15
29
|
if (data) req.write(data);
|
|
@@ -26,7 +40,8 @@ function buildJsonRequest(url, method, body) {
|
|
|
26
40
|
method: method,
|
|
27
41
|
headers: {
|
|
28
42
|
'Content-Type': 'application/json',
|
|
29
|
-
'Content-Length': Buffer.byteLength(body)
|
|
43
|
+
'Content-Length': Buffer.byteLength(body),
|
|
44
|
+
...getAuthHeaders()
|
|
30
45
|
}
|
|
31
46
|
};
|
|
32
47
|
}
|
|
@@ -80,8 +95,13 @@ function listenForFinalAnswer(server, showFinalRow) {
|
|
|
80
95
|
port: parsed.port,
|
|
81
96
|
path: parsed.pathname,
|
|
82
97
|
method: 'GET',
|
|
83
|
-
headers: { 'Accept': 'text/event-stream' }
|
|
98
|
+
headers: { 'Accept': 'text/event-stream', ...getAuthHeaders() }
|
|
84
99
|
}, (res) => {
|
|
100
|
+
if (res.statusCode === 401) {
|
|
101
|
+
res.resume();
|
|
102
|
+
reject(new Error('OpenCode server authentication failed. Set OPENCODE_SERVER_PASSWORD to match the server password.'));
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
85
105
|
let buffer = '';
|
|
86
106
|
const userMessageIDs = new Set();
|
|
87
107
|
|
|
@@ -202,6 +222,11 @@ async function main() {
|
|
|
202
222
|
}
|
|
203
223
|
|
|
204
224
|
await listenForFinalAnswer(serverBase, qaMode);
|
|
225
|
+
|
|
226
|
+
if (!process.env.OPENCODE_SERVER_PASSWORD) {
|
|
227
|
+
process.stderr.write('\n');
|
|
228
|
+
process.stderr.write('🔓 ⚠️ Server is not password-protected! Set OPENCODE_SERVER_PASSWORD for better security.\n');
|
|
229
|
+
}
|
|
205
230
|
}
|
|
206
231
|
|
|
207
232
|
main().catch((err) => {
|
package/bin/ocmux
CHANGED
|
@@ -98,7 +98,7 @@ function resolveGitDir(startDir, requireDir, flagLabel) {
|
|
|
98
98
|
if (!result.dir) {
|
|
99
99
|
const label = requireDir ? '.git directory' : '.git entry';
|
|
100
100
|
console.error(`Error: no ${label} found in ${startDir} or any of its parents.`);
|
|
101
|
-
console.error(`Run '${SCRIPT}
|
|
101
|
+
console.error(`Run '${SCRIPT} serve' without ${flagLabel} to create a server in the current directory.`);
|
|
102
102
|
process.exit(1);
|
|
103
103
|
}
|
|
104
104
|
|
|
@@ -233,7 +233,8 @@ function printHelp() {
|
|
|
233
233
|
console.error('that session is used.');
|
|
234
234
|
console.error('');
|
|
235
235
|
console.error('Subcommands:');
|
|
236
|
-
console.error('
|
|
236
|
+
console.error(' serve Create a server in <directory> (default: $PWD) and attach a TUI.');
|
|
237
|
+
console.error(' Aliased as "new" for backwards compatibility.');
|
|
237
238
|
console.error(' Errors if one already exists there.');
|
|
238
239
|
console.error(' Warns if a parent directory already has a server.');
|
|
239
240
|
console.error(' --git Use the nearest parent with a .git entry (file or dir).');
|
|
@@ -247,7 +248,7 @@ function printHelp() {
|
|
|
247
248
|
console.error(' a subcommand name (e.g. "ocmux -- kill").');
|
|
248
249
|
console.error('');
|
|
249
250
|
console.error('Options:');
|
|
250
|
-
console.error(' -l Long output: append " → <dir>" after the URL (
|
|
251
|
+
console.error(' -l Long output: append " → <dir>" after the URL (serve/default).');
|
|
251
252
|
console.error(' --version Show version');
|
|
252
253
|
console.error(' -h Show this help');
|
|
253
254
|
console.error('');
|
|
@@ -275,7 +276,7 @@ function cmdSwitch(statefile, longMode) {
|
|
|
275
276
|
const found = windowByDir(serverDir);
|
|
276
277
|
if (found == null) {
|
|
277
278
|
console.error(`Error: tmux window for ${serverDir} not found`);
|
|
278
|
-
console.error("Run 'ocmux
|
|
279
|
+
console.error("Run 'ocmux serve' to create a new server.");
|
|
279
280
|
process.exit(1);
|
|
280
281
|
}
|
|
281
282
|
winIdx = found;
|
|
@@ -393,13 +394,25 @@ function doNew(targetDir, longMode) {
|
|
|
393
394
|
|
|
394
395
|
console.error(`Starting opencode server for ${targetDir}...`);
|
|
395
396
|
|
|
396
|
-
|
|
397
|
-
|
|
397
|
+
// Create window with interactive shell so .bashrc/.zshrc is sourced
|
|
398
|
+
const rc = tmux(['new-window', '-d', '-t', SESSION, '-n', targetDir, '-c', targetDir]);
|
|
398
399
|
if (rc.status !== 0) {
|
|
399
400
|
console.error(`Error: failed to create tmux window: ${rc.stderr}`);
|
|
400
401
|
process.exit(1);
|
|
401
402
|
}
|
|
402
403
|
|
|
404
|
+
const winIdx = windowByDir(targetDir);
|
|
405
|
+
if (winIdx == null) {
|
|
406
|
+
console.error('Error: window was not created properly');
|
|
407
|
+
process.exit(1);
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
pinWindowName(winIdx);
|
|
411
|
+
|
|
412
|
+
// Send the command to the interactive shell (like typing it manually)
|
|
413
|
+
tmux(['send-keys', '-t', `${SESSION}:${winIdx}.0`,
|
|
414
|
+
`opencode serve --port 0 2>&1 | tee '${lf}'`, 'Enter']);
|
|
415
|
+
|
|
403
416
|
// Wait up to 10s for the URL in the logfile
|
|
404
417
|
let url = null;
|
|
405
418
|
for (let i = 0; i < 50; i++) {
|
|
@@ -416,21 +429,16 @@ function doNew(targetDir, longMode) {
|
|
|
416
429
|
process.exit(1);
|
|
417
430
|
}
|
|
418
431
|
|
|
419
|
-
const winIdx = windowByDir(targetDir);
|
|
420
|
-
if (winIdx == null) {
|
|
421
|
-
console.error('Error: window was not created properly');
|
|
422
|
-
process.exit(1);
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
pinWindowName(winIdx);
|
|
426
|
-
|
|
427
432
|
const state = { url, logfile: lf, window_index: winIdx };
|
|
428
433
|
fs.writeFileSync(path.join(targetDir, '.ocmux.json'), JSON.stringify(state) + '\n');
|
|
429
434
|
|
|
430
|
-
tmux(['split-window', '-v', '-t', `${SESSION}:${winIdx}`, '-c', targetDir
|
|
431
|
-
|
|
435
|
+
const splitResult = tmux(['split-window', '-v', '-P', '-F', '#{pane_id}', '-t', `${SESSION}:${winIdx}`, '-c', targetDir]);
|
|
436
|
+
const tuiPane = splitResult.stdout.trim();
|
|
437
|
+
sleep(0.2);
|
|
438
|
+
tmux(['send-keys', '-t', tuiPane,
|
|
439
|
+
`opencode attach --continue '${url}'`, 'Enter']);
|
|
432
440
|
sleep(0.5);
|
|
433
|
-
|
|
441
|
+
if (tuiPane) tmux(['resize-pane', '-Z', '-t', tuiPane]);
|
|
434
442
|
|
|
435
443
|
const activeWin = activeWindowIndex();
|
|
436
444
|
if (activeWin !== winIdx) {
|
|
@@ -515,8 +523,10 @@ function main() {
|
|
|
515
523
|
} else if (arg === '--') {
|
|
516
524
|
dirIsForced = true;
|
|
517
525
|
} else if (arg.startsWith('-')) {
|
|
518
|
-
if (arg === '--new'
|
|
519
|
-
console.error(
|
|
526
|
+
if (arg === '--new') {
|
|
527
|
+
console.error("Error: '--new' is no longer a flag. Use 'ocmux serve' instead.");
|
|
528
|
+
} else if (arg === '--kill') {
|
|
529
|
+
console.error("Error: '--kill' is no longer a flag. Use 'ocmux kill' instead.");
|
|
520
530
|
} else {
|
|
521
531
|
console.error(`Error: unknown option '${arg}'`);
|
|
522
532
|
console.error(`Run '${SCRIPT} -h' for help.`);
|
|
@@ -538,7 +548,7 @@ function main() {
|
|
|
538
548
|
process.exit(1);
|
|
539
549
|
}
|
|
540
550
|
targetDir = resolveDir(arg);
|
|
541
|
-
} else if (arg === 'new' || arg === 'kill' || arg === 'list') {
|
|
551
|
+
} else if (arg === 'serve' || arg === 'new' || arg === 'kill' || arg === 'list') {
|
|
542
552
|
if (subcommand) {
|
|
543
553
|
console.error(`Error: multiple subcommands specified: '${subcommand}' and '${arg}'`);
|
|
544
554
|
process.exit(1);
|
|
@@ -558,7 +568,7 @@ function main() {
|
|
|
558
568
|
// Dispatch
|
|
559
569
|
if (subcommand === 'list') {
|
|
560
570
|
if (gitMode) {
|
|
561
|
-
console.error("Error: '--git' and '--GIT' are only valid with '
|
|
571
|
+
console.error("Error: '--git' and '--GIT' are only valid with 'serve'.");
|
|
562
572
|
process.exit(1);
|
|
563
573
|
}
|
|
564
574
|
if (targetDir !== process.cwd()) {
|
|
@@ -568,17 +578,17 @@ function main() {
|
|
|
568
578
|
cmdList();
|
|
569
579
|
} else if (subcommand === 'kill') {
|
|
570
580
|
if (gitMode) {
|
|
571
|
-
console.error("Error: '--git' and '--GIT' are only valid with '
|
|
581
|
+
console.error("Error: '--git' and '--GIT' are only valid with 'serve'.");
|
|
572
582
|
process.exit(1);
|
|
573
583
|
}
|
|
574
584
|
const sf = findParentStatefile(targetDir);
|
|
575
585
|
if (!sf) {
|
|
576
586
|
console.error(`Error: no opencode server found in ${targetDir} or any of its parents.`);
|
|
577
|
-
console.error("Run 'ocmux
|
|
587
|
+
console.error("Run 'ocmux serve' to create a new server.");
|
|
578
588
|
process.exit(1);
|
|
579
589
|
}
|
|
580
590
|
cmdKill(sf);
|
|
581
|
-
} else if (subcommand === 'new') {
|
|
591
|
+
} else if (subcommand === 'serve' || subcommand === 'new') {
|
|
582
592
|
if (gitMode) {
|
|
583
593
|
const flagLabel = gitMode === 'root' ? '--GIT' : '--git';
|
|
584
594
|
targetDir = resolveGitDir(targetDir, gitMode === 'root', flagLabel);
|
|
@@ -586,14 +596,14 @@ function main() {
|
|
|
586
596
|
cmdNew(targetDir, longMode);
|
|
587
597
|
} else {
|
|
588
598
|
if (gitMode) {
|
|
589
|
-
console.error("Error: '--git' and '--GIT' are only valid with '
|
|
599
|
+
console.error("Error: '--git' and '--GIT' are only valid with 'serve'.");
|
|
590
600
|
process.exit(1);
|
|
591
601
|
}
|
|
592
602
|
// Default mode
|
|
593
603
|
const sf = findParentStatefile(targetDir);
|
|
594
604
|
if (!sf) {
|
|
595
605
|
console.error(`Error: no opencode server found in ${targetDir} or any of its parents.`);
|
|
596
|
-
console.error("Run 'ocmux
|
|
606
|
+
console.error("Run 'ocmux serve' to create a new server.");
|
|
597
607
|
process.exit(1);
|
|
598
608
|
}
|
|
599
609
|
ensureSession();
|