agentp 0.2.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.
Files changed (4) hide show
  1. package/README.md +38 -11
  2. package/bin/agentp +46 -18
  3. package/bin/ocmux +110 -22
  4. package/package.json +1 -1
package/README.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # agentp
2
2
 
3
+ [![npm version](https://img.shields.io/npm/v/agentp.svg)](https://www.npmjs.com/package/agentp)
4
+ [![npm license](https://img.shields.io/npm/l/agentp.svg)](https://www.npmjs.com/package/agentp)
5
+ [![npm downloads](https://img.shields.io/npm/dm/agentp.svg)](https://www.npmjs.com/package/agentp)
6
+ [![node version](https://img.shields.io/node/v/agentp.svg)](https://www.npmjs.com/package/agentp)
7
+
3
8
  This package provides two CLI tools:
4
9
 
5
10
  - **`agentp`** — pipes prompt text into a running OpenCode TUI session and streams the assistant final answer back to stdout
@@ -34,23 +39,25 @@ npm link
34
39
  Notes:
35
40
 
36
41
  - `agentp` connects to the OpenCode event endpoint over HTTP.
37
- - In practice this means running `opencode --serve` (or equivalent serve mode) so the port is open.
38
- - `opencode --attach` is optional but useful to monitor the full conversation in another terminal/tmux pane.
42
+ - In practice this means running `opencode serve` (or equivalent serve mode) so the port is open.
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.
39
45
 
40
46
  ## Usage
41
47
 
42
48
  ```bash
43
- agentp [options] [port]
49
+ agentp [options] [url]
44
50
  ```
45
51
 
46
52
  Options:
47
53
 
48
- - `--qa`: print question/answer separators around the streamed answer
54
+ - `--qa`: print the original prompt and answer with labels (useful when used as a filter)
55
+ - `--version`: show version
49
56
  - `--help`: show help message
50
57
 
51
58
  Arguments:
52
59
 
53
- - `port`: OpenCode TUI port (defaults to `4096`)
60
+ - `url`: OpenCode TUI server URL or port number (defaults to `4096`). Examples: `4096`, `http://localhost:4096`, `http://192.168.1.50:4096`
54
61
 
55
62
  ## Examples
56
63
 
@@ -73,10 +80,10 @@ Send a multi-line prompt from a file:
73
80
  cat prompt.txt | agentp
74
81
  ```
75
82
 
76
- Use QA separators and explicit port:
83
+ Use an explicit port:
77
84
 
78
85
  ```bash
79
- cat prompt.txt | agentp --qa 4096
86
+ cat prompt.txt | agentp 4096
80
87
  ```
81
88
 
82
89
  Capture answer to a file:
@@ -85,13 +92,19 @@ Capture answer to a file:
85
92
  cat prompt.txt | agentp > answer.txt
86
93
  ```
87
94
 
95
+ Connect to a remote OpenCode server:
96
+
97
+ ```bash
98
+ cat prompt.txt | agentp http://192.168.1.50:4096
99
+ ```
100
+
88
101
  From Vim/Neovim, send the current visual selection and replace it in place with the assistant answer:
89
102
 
90
103
  ```vim
91
104
  :'<,'>!agentp
92
105
  ```
93
106
 
94
- From Vim/Neovim, send the current visual selection and keep QA separators in the same file:
107
+ From Vim/Neovim, send the current visual selection and keep the prompt with the answer:
95
108
 
96
109
  ```vim
97
110
  :'<,'>!agentp --qa
@@ -109,9 +122,23 @@ Without arguments, searches upward from `<directory>` (default: `$PWD`) for `.oc
109
122
 
110
123
  Subcommands:
111
124
 
112
- - **`new [dir]`** — Create a new server in `dir` (default: `$PWD`). Errors if one already exists there. Warns if a parent directory already has a server.
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.
126
+ - `--git` resolves `dir` to the nearest parent with a `.git` entry (file or dir); errors if none is found.
127
+ - `--GIT` resolves `dir` to the nearest parent with a `.git` directory only; errors if none is found.
113
128
  - **`kill [dir]`** — Kill the server found upward from `dir`. Removes its tmux window and state file.
114
- - **`list [-l]`** — List all running servers with their directories, URLs, and status.
129
+ - **`list`** — List all running servers with their directories, URLs, and status.
130
+
131
+ Options:
132
+
133
+ - `-l`: long output for default/serve commands (append `→ <dir>` after the URL)
134
+ - `--version`: show version
135
+ - `-h`: show help message
136
+ - `--`: treat the next argument as a directory even if it matches a subcommand name
137
+
138
+ Notes:
139
+
140
+ - If `<directory>` is not a valid path, `ocmux` tries to match it against the basenames of existing sessions (exact unique match).
141
+ - When using `--git`/`--GIT`, `ocmux` refuses to create a new server above an existing `.ocmux.json` found while searching for the git root.
115
142
 
116
143
  ### Requirements
117
144
 
@@ -133,7 +160,7 @@ Subcommands:
133
160
 
134
161
  Operational hint:
135
162
 
136
- - You can keep a separate `opencode --attach` view open to see the full run context while `agentp` is used from shell scripts or editor buffers.
163
+ - You can keep a separate `opencode attach` view open to see the full run context while `agentp` is used from shell scripts or editor buffers.
137
164
 
138
165
  ## License
139
166
 
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', () => resolve({ status: res.statusCode, body }));
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
  }
@@ -47,8 +62,7 @@ async function submitPrompt(server) {
47
62
  await makeRequest(buildJsonRequest(url, 'POST', '{}'), '{}');
48
63
  }
49
64
 
50
- async function sendPrompt(port) {
51
- const server = `http://localhost:${port}`;
65
+ async function sendPrompt(server) {
52
66
  let promptText = '';
53
67
 
54
68
  await clearPrompt(server);
@@ -71,9 +85,9 @@ const HUMAN_ROW = '👤:  ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄
71
85
  const AGENT_ROW = '🤖:  ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄\n'
72
86
  const FINAL_ROW = ' ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄\n';
73
87
 
74
- function listenForFinalAnswer(port, showFinalRow) {
88
+ function listenForFinalAnswer(server, showFinalRow) {
75
89
  return new Promise((resolve, reject) => {
76
- const url = `http://localhost:${port}/event`;
90
+ const url = `${server}/event`;
77
91
  const parsed = new URL(url);
78
92
 
79
93
  const req = http.request({
@@ -81,8 +95,13 @@ function listenForFinalAnswer(port, showFinalRow) {
81
95
  port: parsed.port,
82
96
  path: parsed.pathname,
83
97
  method: 'GET',
84
- headers: { 'Accept': 'text/event-stream' }
98
+ headers: { 'Accept': 'text/event-stream', ...getAuthHeaders() }
85
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
+ }
86
105
  let buffer = '';
87
106
  const userMessageIDs = new Set();
88
107
 
@@ -155,7 +174,7 @@ function listenForFinalAnswer(port, showFinalRow) {
155
174
  }
156
175
 
157
176
  async function main() {
158
- let port = 4096;
177
+ let serverBase = 'http://localhost:4096';
159
178
  let qaMode = false;
160
179
 
161
180
  const args = process.argv.slice(2);
@@ -164,33 +183,37 @@ async function main() {
164
183
  console.log(version);
165
184
  process.exit(0);
166
185
  } else if (args[i] === '--help') {
167
- console.error('Usage: agentp [options] [port]');
186
+ console.error('Usage: agentp [options] [url]');
168
187
  console.error('');
169
- console.error('Pipe prompt text to an OpenCode TUI session running on localhost.');
170
- console.error('The assistant response is streamed to stdout.');
188
+ console.error('Pipe prompt text to an OpenCode TUI session and stream the assistant response to stdout.');
171
189
  console.error('');
172
190
  console.error('Options:');
173
191
  console.error(' --version Show version');
174
- console.error(' --qa Print question/answer separators before streaming output');
192
+ console.error(' --qa Print the original prompt and answer with labels (useful as a filter)');
175
193
  console.error(' --help Show this help message');
176
194
  console.error('');
177
195
  console.error('Arguments:');
178
- console.error(' port OpenCode TUI port (default: 4096)');
196
+ console.error(' url OpenCode TUI server URL or port number (default: 4096)');
197
+ console.error(' Examples: 4096, http://localhost:4096, http://192.168.1.50:4096');
179
198
  console.error('');
180
199
  console.error('See also: ocmux -- manage OpenCode tmux sessions (ocmux --help)');
181
200
  console.error('');
182
201
  console.error('Examples:');
183
202
  console.error(' printf "Summarize this file" | agentp');
184
- console.error(' cat prompt.txt | agentp --qa 4096');
203
+ console.error(' cat prompt.txt | agentp 4096');
204
+ console.error(' # Vim/Neovim filter, preserving prompt + answer:');
205
+ console.error(" :'<,'>!agentp --qa");
185
206
  process.exit(0);
186
207
  } else if (args[i] === '--qa') {
187
208
  qaMode = true;
188
- } else if (!isNaN(args[i]) && /^\d+$/.test(args[i])) {
189
- port = parseInt(args[i], 10);
209
+ } else if (args[i].includes('://')) {
210
+ serverBase = args[i].replace(/\/+$/, '');
211
+ } else if (/^\d+$/.test(args[i])) {
212
+ serverBase = 'http://localhost:' + args[i];
190
213
  }
191
214
  }
192
215
 
193
- const promptText = await sendPrompt(port);
216
+ const promptText = await sendPrompt(serverBase);
194
217
 
195
218
  if (qaMode) {
196
219
  process.stdout.write(HUMAN_ROW);
@@ -198,7 +221,12 @@ async function main() {
198
221
  process.stdout.write(AGENT_ROW);
199
222
  }
200
223
 
201
- await listenForFinalAnswer(port, qaMode);
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
+ }
202
230
  }
203
231
 
204
232
  main().catch((err) => {
package/bin/ocmux CHANGED
@@ -66,6 +66,52 @@ function findParentStatefile(startDir) {
66
66
  }
67
67
  }
68
68
 
69
+ function findParentGitDir(startDir, requireDir) {
70
+ let dir = path.resolve(startDir);
71
+ let stateDir = null;
72
+ while (true) {
73
+ if (!stateDir && fs.existsSync(path.join(dir, '.ocmux.json'))) {
74
+ stateDir = dir;
75
+ }
76
+
77
+ const gitPath = path.join(dir, '.git');
78
+ if (fs.existsSync(gitPath)) {
79
+ if (!requireDir) {
80
+ return { dir, stateDir, gitPath };
81
+ }
82
+ try {
83
+ if (fs.statSync(gitPath).isDirectory()) {
84
+ return { dir, stateDir, gitPath };
85
+ }
86
+ } catch {
87
+ // ignore stat errors
88
+ }
89
+ }
90
+
91
+ if (dir === HOME || dir === path.dirname(dir)) return { dir: null, stateDir, gitPath: null };
92
+ dir = path.dirname(dir);
93
+ }
94
+ }
95
+
96
+ function resolveGitDir(startDir, requireDir, flagLabel) {
97
+ const result = findParentGitDir(startDir, requireDir);
98
+ if (!result.dir) {
99
+ const label = requireDir ? '.git directory' : '.git entry';
100
+ console.error(`Error: no ${label} found in ${startDir} or any of its parents.`);
101
+ console.error(`Run '${SCRIPT} serve' without ${flagLabel} to create a server in the current directory.`);
102
+ process.exit(1);
103
+ }
104
+
105
+ if (result.stateDir && result.stateDir !== result.dir) {
106
+ console.error(`Error: found an existing ocmux server in ${result.stateDir}.`);
107
+ console.error(`Refusing to create a new server at ${result.dir} because it is above that session.`);
108
+ console.error(`Move outside ${result.stateDir} or pass an explicit directory.`);
109
+ process.exit(1);
110
+ }
111
+
112
+ return result.dir;
113
+ }
114
+
69
115
  function windowByDir(dir) {
70
116
  const r = tmux(['list-windows', '-t', SESSION, '-F', '#{window_index}\t#{window_name}']);
71
117
  if (r.status !== 0) return null;
@@ -187,9 +233,13 @@ function printHelp() {
187
233
  console.error('that session is used.');
188
234
  console.error('');
189
235
  console.error('Subcommands:');
190
- console.error(' new Create a new server in <directory> (default: $PWD).');
236
+ console.error(' serve Create a server in <directory> (default: $PWD) and attach a TUI.');
237
+ console.error(' Aliased as "new" for backwards compatibility.');
191
238
  console.error(' Errors if one already exists there.');
192
239
  console.error(' Warns if a parent directory already has a server.');
240
+ console.error(' --git Use the nearest parent with a .git entry (file or dir).');
241
+ console.error(' --GIT Use the nearest parent with a .git directory only.');
242
+ console.error(' Refuses to create above an existing .ocmux.json found while searching.');
193
243
  console.error(' kill Kill the server found upward from <directory>.');
194
244
  console.error(' Removes its tmux window and state file.');
195
245
  console.error(' list List all running servers with their directories and URLs.');
@@ -198,7 +248,7 @@ function printHelp() {
198
248
  console.error(' a subcommand name (e.g. "ocmux -- kill").');
199
249
  console.error('');
200
250
  console.error('Options:');
201
- console.error(' -l Long output: append " → <dir>" after the URL.');
251
+ console.error(' -l Long output: append " → <dir>" after the URL (serve/default).');
202
252
  console.error(' --version Show version');
203
253
  console.error(' -h Show this help');
204
254
  console.error('');
@@ -226,7 +276,7 @@ function cmdSwitch(statefile, longMode) {
226
276
  const found = windowByDir(serverDir);
227
277
  if (found == null) {
228
278
  console.error(`Error: tmux window for ${serverDir} not found`);
229
- console.error("Run 'ocmux new' to create a new server.");
279
+ console.error("Run 'ocmux serve' to create a new server.");
230
280
  process.exit(1);
231
281
  }
232
282
  winIdx = found;
@@ -344,13 +394,25 @@ function doNew(targetDir, longMode) {
344
394
 
345
395
  console.error(`Starting opencode server for ${targetDir}...`);
346
396
 
347
- const rc = tmux(['new-window', '-d', '-t', SESSION, '-n', targetDir, '-c', targetDir,
348
- `opencode serve --port 0 2>&1 | tee '${lf}'`]);
397
+ // Create window with interactive shell so .bashrc/.zshrc is sourced
398
+ const rc = tmux(['new-window', '-d', '-t', SESSION, '-n', targetDir, '-c', targetDir]);
349
399
  if (rc.status !== 0) {
350
400
  console.error(`Error: failed to create tmux window: ${rc.stderr}`);
351
401
  process.exit(1);
352
402
  }
353
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
+
354
416
  // Wait up to 10s for the URL in the logfile
355
417
  let url = null;
356
418
  for (let i = 0; i < 50; i++) {
@@ -367,21 +429,16 @@ function doNew(targetDir, longMode) {
367
429
  process.exit(1);
368
430
  }
369
431
 
370
- const winIdx = windowByDir(targetDir);
371
- if (winIdx == null) {
372
- console.error('Error: window was not created properly');
373
- process.exit(1);
374
- }
375
-
376
- pinWindowName(winIdx);
377
-
378
432
  const state = { url, logfile: lf, window_index: winIdx };
379
433
  fs.writeFileSync(path.join(targetDir, '.ocmux.json'), JSON.stringify(state) + '\n');
380
434
 
381
- tmux(['split-window', '-v', '-t', `${SESSION}:${winIdx}`, '-c', targetDir,
382
- `opencode attach --continue '${url}'`]);
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']);
383
440
  sleep(0.5);
384
- ensureTuiZoomed(winIdx);
441
+ if (tuiPane) tmux(['resize-pane', '-Z', '-t', tuiPane]);
385
442
 
386
443
  const activeWin = activeWindowIndex();
387
444
  if (activeWin !== winIdx) {
@@ -439,12 +496,25 @@ function cmdKill(statefile) {
439
496
 
440
497
  function main() {
441
498
  let longMode = false;
499
+ let gitMode = null;
442
500
  const positional = [];
443
501
  let dirIsForced = false;
444
502
 
445
503
  for (const arg of process.argv.slice(2)) {
446
504
  if (arg === '-l') {
447
505
  longMode = true;
506
+ } else if (arg === '--git') {
507
+ if (gitMode && gitMode !== 'nearest') {
508
+ console.error("Error: cannot combine '--git' with '--GIT'.");
509
+ process.exit(1);
510
+ }
511
+ gitMode = 'nearest';
512
+ } else if (arg === '--GIT') {
513
+ if (gitMode && gitMode !== 'root') {
514
+ console.error("Error: cannot combine '--git' with '--GIT'.");
515
+ process.exit(1);
516
+ }
517
+ gitMode = 'root';
448
518
  } else if (arg === '--version') {
449
519
  console.log(version);
450
520
  process.exit(0);
@@ -453,8 +523,10 @@ function main() {
453
523
  } else if (arg === '--') {
454
524
  dirIsForced = true;
455
525
  } else if (arg.startsWith('-')) {
456
- if (arg === '--new' || arg === '--kill') {
457
- console.error(`Error: '${arg}' is no longer a flag. Use 'ocmux ${arg.slice(2)}' instead.`);
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.");
458
530
  } else {
459
531
  console.error(`Error: unknown option '${arg}'`);
460
532
  console.error(`Run '${SCRIPT} -h' for help.`);
@@ -476,7 +548,7 @@ function main() {
476
548
  process.exit(1);
477
549
  }
478
550
  targetDir = resolveDir(arg);
479
- } else if (arg === 'new' || arg === 'kill' || arg === 'list') {
551
+ } else if (arg === 'serve' || arg === 'new' || arg === 'kill' || arg === 'list') {
480
552
  if (subcommand) {
481
553
  console.error(`Error: multiple subcommands specified: '${subcommand}' and '${arg}'`);
482
554
  process.exit(1);
@@ -495,27 +567,43 @@ function main() {
495
567
 
496
568
  // Dispatch
497
569
  if (subcommand === 'list') {
570
+ if (gitMode) {
571
+ console.error("Error: '--git' and '--GIT' are only valid with 'serve'.");
572
+ process.exit(1);
573
+ }
498
574
  if (targetDir !== process.cwd()) {
499
575
  console.error("Error: 'list' does not accept a directory path.");
500
576
  process.exit(1);
501
577
  }
502
578
  cmdList();
503
579
  } else if (subcommand === 'kill') {
580
+ if (gitMode) {
581
+ console.error("Error: '--git' and '--GIT' are only valid with 'serve'.");
582
+ process.exit(1);
583
+ }
504
584
  const sf = findParentStatefile(targetDir);
505
585
  if (!sf) {
506
586
  console.error(`Error: no opencode server found in ${targetDir} or any of its parents.`);
507
- console.error("Run 'ocmux new' to create a new server.");
587
+ console.error("Run 'ocmux serve' to create a new server.");
508
588
  process.exit(1);
509
589
  }
510
590
  cmdKill(sf);
511
- } else if (subcommand === 'new') {
591
+ } else if (subcommand === 'serve' || subcommand === 'new') {
592
+ if (gitMode) {
593
+ const flagLabel = gitMode === 'root' ? '--GIT' : '--git';
594
+ targetDir = resolveGitDir(targetDir, gitMode === 'root', flagLabel);
595
+ }
512
596
  cmdNew(targetDir, longMode);
513
597
  } else {
598
+ if (gitMode) {
599
+ console.error("Error: '--git' and '--GIT' are only valid with 'serve'.");
600
+ process.exit(1);
601
+ }
514
602
  // Default mode
515
603
  const sf = findParentStatefile(targetDir);
516
604
  if (!sf) {
517
605
  console.error(`Error: no opencode server found in ${targetDir} or any of its parents.`);
518
- console.error("Run 'ocmux new' to create a new server.");
606
+ console.error("Run 'ocmux serve' to create a new server.");
519
607
  process.exit(1);
520
608
  }
521
609
  ensureSession();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentp",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "Pipe prompts into a running OpenCode TUI session and stream the final answer",
5
5
  "bin": {
6
6
  "agentp": "bin/agentp",