agentp 0.9.0 → 0.11.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/CONTRIBUTING.md +139 -0
- package/README.md +54 -8
- package/bin/agentp +159 -20
- package/bin/ocmux +56 -41
- package/bin/tgagentp +971 -206
- package/docs/specification.md +391 -0
- package/lib/ocmux.js +113 -2
- package/lib/opencode.js +79 -12
- package/package.json +9 -2
- package/AGENTS.md +0 -177
- package/CHANGELOG.md +0 -24
- package/debugging_tg_integration.md +0 -5594
- package/tgagentp.log +0 -2156
package/lib/opencode.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const http = require('http');
|
|
4
|
+
const https = require('https');
|
|
4
5
|
const { URL } = require('url');
|
|
5
6
|
|
|
6
7
|
function getAuthHeaders() {
|
|
@@ -11,7 +12,7 @@ function getAuthHeaders() {
|
|
|
11
12
|
return { 'Authorization': `Basic ${encoded}` };
|
|
12
13
|
}
|
|
13
14
|
|
|
14
|
-
function makeRequest(options, data, cancelRef) {
|
|
15
|
+
function makeRequest(options, data, cancelRef, timeoutMs) {
|
|
15
16
|
return new Promise((resolve, reject) => {
|
|
16
17
|
const req = http.request(options, (res) => {
|
|
17
18
|
let body = '';
|
|
@@ -24,6 +25,12 @@ function makeRequest(options, data, cancelRef) {
|
|
|
24
25
|
}
|
|
25
26
|
});
|
|
26
27
|
});
|
|
28
|
+
if (timeoutMs) {
|
|
29
|
+
req.setTimeout(timeoutMs, () => {
|
|
30
|
+
req.destroy();
|
|
31
|
+
reject(new Error('Request timed out'));
|
|
32
|
+
});
|
|
33
|
+
}
|
|
27
34
|
req.on('error', reject);
|
|
28
35
|
if (cancelRef) cancelRef.current = req;
|
|
29
36
|
if (data) req.write(data);
|
|
@@ -243,6 +250,36 @@ async function selectSession(server, sessionId) {
|
|
|
243
250
|
}
|
|
244
251
|
}
|
|
245
252
|
|
|
253
|
+
// Get a single session by ID, including its message history.
|
|
254
|
+
// Tries GET /session/:id first; falls back to filtering the sessions list.
|
|
255
|
+
async function getSession(server, sessionId) {
|
|
256
|
+
const encoded = encodeURIComponent(sessionId);
|
|
257
|
+
// Try several endpoint patterns that different opencode versions may expose
|
|
258
|
+
const urls = [
|
|
259
|
+
`${server}/session/${encoded}`,
|
|
260
|
+
`${server}/session/${encoded}/messages`,
|
|
261
|
+
`${server}/session/${encoded}/history`,
|
|
262
|
+
`${server}/session/${encoded}/conversation`,
|
|
263
|
+
`${server}/conversation/${encoded}`,
|
|
264
|
+
];
|
|
265
|
+
for (const url of urls) {
|
|
266
|
+
try {
|
|
267
|
+
const { status, body } = await makeRequest(buildJsonRequest(url, 'GET'), null, null, 10000);
|
|
268
|
+
if (status === 200) {
|
|
269
|
+
try {
|
|
270
|
+
const parsed = JSON.parse(body);
|
|
271
|
+
if (parsed != null) return parsed;
|
|
272
|
+
} catch {}
|
|
273
|
+
}
|
|
274
|
+
} catch {}
|
|
275
|
+
}
|
|
276
|
+
// Fallback: get all sessions and find the one we need
|
|
277
|
+
const sessions = await listSessions(server);
|
|
278
|
+
const match = sessions.find(s => String(s.id) === String(sessionId));
|
|
279
|
+
if (match) return match;
|
|
280
|
+
throw new Error(`Session ${sessionId} not found`);
|
|
281
|
+
}
|
|
282
|
+
|
|
246
283
|
// List all agents from the OpenCode server.
|
|
247
284
|
async function listAgents(server) {
|
|
248
285
|
const url = `${server}/agent`;
|
|
@@ -283,8 +320,13 @@ async function respondToPermission(server, sessionId, permissionId, response, re
|
|
|
283
320
|
// permission requests. Resolves with the full collected text when the session goes idle.
|
|
284
321
|
// callbacks: { onText(chunk), onPermission(permission), onThinking(chunk), onConnected() }
|
|
285
322
|
// cancelRef — allows aborting the SSE stream via req.destroy()
|
|
286
|
-
|
|
287
|
-
|
|
323
|
+
// logFn — optional logger; if provided, used instead of process.stderr.write
|
|
324
|
+
function listenForSessionEvents(server, sessionId, callbacks, cancelRef, logFn) {
|
|
325
|
+
const sseLog = logFn || ((msg) => {
|
|
326
|
+
const ts = new Date().toISOString().replace('T', ' ').replace(/\.\d{3}Z$/, '');
|
|
327
|
+
process.stderr.write(`${ts} ${msg}`);
|
|
328
|
+
});
|
|
329
|
+
sseLog(` [SSE] connecting to ${server}/event for session ${sessionId}\n`);
|
|
288
330
|
return new Promise((resolve, reject) => {
|
|
289
331
|
const url = `${server}/event`;
|
|
290
332
|
const parsed = new URL(url);
|
|
@@ -301,7 +343,7 @@ function listenForSessionEvents(server, sessionId, callbacks, cancelRef) {
|
|
|
301
343
|
reject(new Error('OpenCode server authentication failed. Set OPENCODE_SERVER_PASSWORD to match the server password.'));
|
|
302
344
|
return;
|
|
303
345
|
}
|
|
304
|
-
|
|
346
|
+
sseLog(` [SSE] connected for session ${sessionId}\n`);
|
|
305
347
|
if (callbacks.onConnected) callbacks.onConnected();
|
|
306
348
|
let buffer = '';
|
|
307
349
|
const userMessageIDs = new Set();
|
|
@@ -312,7 +354,7 @@ function listenForSessionEvents(server, sessionId, callbacks, cancelRef) {
|
|
|
312
354
|
const safetyTimer = setTimeout(() => {
|
|
313
355
|
if (resolved) return;
|
|
314
356
|
resolved = true;
|
|
315
|
-
|
|
357
|
+
sseLog(` [SSE] safety timeout (90s) for session ${sessionId}, collected ${collected.length} chars\n`);
|
|
316
358
|
cleanup();
|
|
317
359
|
req.destroy();
|
|
318
360
|
res.destroy();
|
|
@@ -338,9 +380,9 @@ function listenForSessionEvents(server, sessionId, callbacks, cancelRef) {
|
|
|
338
380
|
const props = event.properties || {};
|
|
339
381
|
|
|
340
382
|
if (event.type === 'session.status') {
|
|
341
|
-
|
|
383
|
+
sseLog(` [SSE] session.status: type=${props.status?.type} status=${JSON.stringify(props.status)}\n`);
|
|
342
384
|
} else {
|
|
343
|
-
|
|
385
|
+
sseLog(` [SSE] event type=${event.type} sessionID=${props.sessionID} waitSession=${sessionId}\n`);
|
|
344
386
|
}
|
|
345
387
|
|
|
346
388
|
// Filter by sessionID when the event carries one (string-compare to handle type mismatches)
|
|
@@ -353,18 +395,18 @@ function listenForSessionEvents(server, sessionId, callbacks, cancelRef) {
|
|
|
353
395
|
|
|
354
396
|
if (event.type === 'permission.asked') {
|
|
355
397
|
const permStr = JSON.stringify(props);
|
|
356
|
-
|
|
398
|
+
sseLog(` [SSE] PERMISSION ASKED: ${permStr}\n`);
|
|
357
399
|
if (callbacks.onPermission) {
|
|
358
|
-
|
|
400
|
+
sseLog(` [SSE] calling onPermission callback\n`);
|
|
359
401
|
callbacks.onPermission(props);
|
|
360
402
|
} else {
|
|
361
|
-
|
|
403
|
+
sseLog(` [SSE] WARNING: no onPermission callback registered\n`);
|
|
362
404
|
}
|
|
363
405
|
continue;
|
|
364
406
|
}
|
|
365
407
|
|
|
366
408
|
if (event.type === 'permission.replied') {
|
|
367
|
-
|
|
409
|
+
sseLog(` [SSE] PERMISSION REPLIED: type=${props.type}\n`);
|
|
368
410
|
if (callbacks.onPermissionReplied) {
|
|
369
411
|
callbacks.onPermissionReplied(props);
|
|
370
412
|
}
|
|
@@ -426,7 +468,7 @@ function listenForSessionEvents(server, sessionId, callbacks, cancelRef) {
|
|
|
426
468
|
if (resolved) return;
|
|
427
469
|
resolved = true;
|
|
428
470
|
cleanup();
|
|
429
|
-
|
|
471
|
+
sseLog(` [SSE] response stream error for session ${sessionId}: ${err.message}\n`);
|
|
430
472
|
resolve(collected); // resolve with what we have
|
|
431
473
|
});
|
|
432
474
|
});
|
|
@@ -445,6 +487,29 @@ function listenForSessionEvents(server, sessionId, callbacks, cancelRef) {
|
|
|
445
487
|
});
|
|
446
488
|
}
|
|
447
489
|
|
|
490
|
+
// Check if an OpenCode server is reachable by making a GET /session request.
|
|
491
|
+
// Returns a Promise that resolves to `true` (any response) or `false` (connection error / timeout).
|
|
492
|
+
function isServerAlive(url) {
|
|
493
|
+
return new Promise((resolve) => {
|
|
494
|
+
const mod = url.startsWith('https') ? https : http;
|
|
495
|
+
const parsed = new URL(url + '/session');
|
|
496
|
+
const opts = {
|
|
497
|
+
hostname: parsed.hostname,
|
|
498
|
+
port: parsed.port,
|
|
499
|
+
path: parsed.pathname,
|
|
500
|
+
method: 'GET',
|
|
501
|
+
headers: { ...getAuthHeaders() },
|
|
502
|
+
};
|
|
503
|
+
const req = mod.request(opts, (res) => {
|
|
504
|
+
res.resume();
|
|
505
|
+
resolve(true);
|
|
506
|
+
});
|
|
507
|
+
req.on('error', () => resolve(false));
|
|
508
|
+
req.setTimeout(5000, () => { req.destroy(); resolve(false); });
|
|
509
|
+
req.end();
|
|
510
|
+
});
|
|
511
|
+
}
|
|
512
|
+
|
|
448
513
|
module.exports = {
|
|
449
514
|
getAuthHeaders,
|
|
450
515
|
makeRequest,
|
|
@@ -455,6 +520,7 @@ module.exports = {
|
|
|
455
520
|
sendText,
|
|
456
521
|
listenForFinalAnswer,
|
|
457
522
|
listSessions,
|
|
523
|
+
getSession,
|
|
458
524
|
createSession,
|
|
459
525
|
updateSession,
|
|
460
526
|
selectSession,
|
|
@@ -464,4 +530,5 @@ module.exports = {
|
|
|
464
530
|
listenForSessionEvents,
|
|
465
531
|
listAgents,
|
|
466
532
|
listProviders,
|
|
533
|
+
isServerAlive,
|
|
467
534
|
};
|
package/package.json
CHANGED
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.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",
|
|
7
7
|
"ocmux": "bin/ocmux",
|
|
8
8
|
"tgagentp": "bin/tgagentp"
|
|
9
9
|
},
|
|
10
|
+
"files": [
|
|
11
|
+
"bin/",
|
|
12
|
+
"lib/",
|
|
13
|
+
"README.md",
|
|
14
|
+
"CONTRIBUTING.md",
|
|
15
|
+
"docs/"
|
|
16
|
+
],
|
|
10
17
|
"keywords": [
|
|
11
18
|
"ai",
|
|
12
19
|
"cli",
|
|
@@ -24,7 +31,7 @@
|
|
|
24
31
|
"node": ">=18"
|
|
25
32
|
},
|
|
26
33
|
"scripts": {
|
|
27
|
-
"test": "
|
|
34
|
+
"test": "node --test tests/*.test.js"
|
|
28
35
|
},
|
|
29
36
|
"type": "commonjs"
|
|
30
37
|
}
|
package/AGENTS.md
DELETED
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
# agentp — agent notes
|
|
2
|
-
|
|
3
|
-
## Three binaries, all registered
|
|
4
|
-
|
|
5
|
-
- `bin/agentp` (Node.js) — registered in `package.json` `"bin"` — pipes stdin → opencode session
|
|
6
|
-
- `bin/ocmux` (Node.js) — registered in `package.json` `"bin"` — manages opencode tmux sessions
|
|
7
|
-
- `bin/tgagentp` (Node.js) — registered in `package.json` `"bin"` — bridges Telegram bot ↔ opencode TUI
|
|
8
|
-
|
|
9
|
-
## Package facts
|
|
10
|
-
|
|
11
|
-
- **Zero npm dependencies.** All scripts use only Node.js stdlib (`http`, `https`, `readline`, `url`, `child_process`, `fs`, `path`, `crypto`, `os`).
|
|
12
|
-
- **No tests, no CI, no lint, no formatter.** `npm test` is a stub that exits 1.
|
|
13
|
-
- **No lockfile.** Versions resolve at install time.
|
|
14
|
-
- **`"type": "commonjs"`**, requires Node >= 18.
|
|
15
|
-
- **Linux and macOS compatible.** All tools use portable Node.js APIs only.
|
|
16
|
-
|
|
17
|
-
## Logging conventions (tgagentp)
|
|
18
|
-
|
|
19
|
-
- **stdout** — informational messages (startup, discovery, session switches)
|
|
20
|
-
- **stderr** — errors (always shown) + trace/debug (only with `--verbose` flag)
|
|
21
|
-
- Default usage for clean console: `tgagentp 2>/dev/null`
|
|
22
|
-
- The `log` helper object at the top of `bin/tgagentp` provides `log.info()`, `log.error()`, and `log.debug()`.
|
|
23
|
-
|
|
24
|
-
## `.ocmux.json`
|
|
25
|
-
|
|
26
|
-
Runtime state file created by `bin/ocmux` (contains URL, log path, and window index). **Not in `.gitignore`** — avoid committing it.
|
|
27
|
-
|
|
28
|
-
## Shared `lib/opencode.js`
|
|
29
|
-
|
|
30
|
-
Extracted from `bin/agentp`; used by both `agentp` and `tgagentp`:
|
|
31
|
-
|
|
32
|
-
- `getAuthHeaders()` — reads `OPENCODE_SERVER_PASSWORD` / `OPENCODE_SERVER_USERNAME`
|
|
33
|
-
- `makeRequest(options, data)` — thin `http.request` wrapper returning a Promise
|
|
34
|
-
- `buildJsonRequest(url, method, body)` — builds request options for JSON POST/GET (no Content-Type/Length for bodyless requests)
|
|
35
|
-
- `clearPrompt(server)`, `appendPrompt(server, text)`, `submitPrompt(server)` — TUI prompt endpoints
|
|
36
|
-
- `sendText(server, text)` — convenience: clear + append + submit in one call
|
|
37
|
-
- `listenForFinalAnswer(server, onText?, cancelRef?)` — SSE event stream listener; `cancelRef` allows true server-side abort via `req.destroy()`
|
|
38
|
-
- `listSessions(server, directory?)` — `GET /session`; returns parsed JSON array; optional `?directory=` filter
|
|
39
|
-
- `createSession(server, title?)` — `POST /session`; returns the created `Session` object; optional `title`
|
|
40
|
-
- `updateSession(server, sessionId, title, agent?)` — `PATCH /session/:id`; returns the updated `Session` object; optional `agent` to set the session's agent
|
|
41
|
-
- `sendToSession(server, sessionId, text, agent?, cancelRef?)` — `POST /session/:id/message`; returns concatenated text parts from response; optional `agent`, optional `cancelRef` for aborting the request
|
|
42
|
-
- `sendToSessionAsync(server, sessionId, text, agent?)` — `POST /session/:id/prompt_async`; returns 204; non-blocking, answer delivered via SSE
|
|
43
|
-
- `respondToPermission(server, sessionId, permissionId, response)` — `POST /session/:id/permissions/:id`
|
|
44
|
-
- `selectSession(server, sessionId)` — `POST /session/:id/select`; tells the TUI to navigate to the given session (silently ignores 404 if the endpoint isn't available in older opencode versions)
|
|
45
|
-
- `listAgents(server)` — `GET /agent`; returns parsed JSON array of agent objects
|
|
46
|
-
- `listProviders(server)` — `GET /provider`; returns parsed JSON array of provider objects
|
|
47
|
-
- `listenForSessionEvents(server, sessionId, callbacks, cancelRef?)` — SSE listener for session events (text parts, permissions, thinking, session.idle)
|
|
48
|
-
|
|
49
|
-
## Shared `lib/ocmux.js`
|
|
50
|
-
|
|
51
|
-
Shared ocmux session discovery; used by both `bin/ocmux` and `bin/tgagentp`:
|
|
52
|
-
|
|
53
|
-
- `readState(file)` — parses `.ocmux.json`, returns `null` on error
|
|
54
|
-
- `statefileFor(dir)` — `path.join(dir, '.ocmux.json')`
|
|
55
|
-
- `tuiPaneId(windowIndex)` — returns pane ID of the TUI pane (pane index != 0), `null` if dead
|
|
56
|
-
- `windowByDir(dir)` — returns window index by name match
|
|
57
|
-
- `windowNameByIndex(idx)` — reverse: name from index
|
|
58
|
-
- `activeWindowIndex()` — returns index of currently selected tmux window
|
|
59
|
-
- `paneCount(windowIndex)` — number of panes in a window
|
|
60
|
-
- `listServers()` — scans all tmux windows for `.ocmux.json` state files; returns `{ url, dir, index, status }` array
|
|
61
|
-
- `activateServer(dir, index, url)` — pin window name, restart dead TUI pane, select window, zoom pane
|
|
62
|
-
|
|
63
|
-
## OpenCode HTTP protocol
|
|
64
|
-
|
|
65
|
-
These endpoints are consumed but not documented elsewhere in the repo:
|
|
66
|
-
|
|
67
|
-
- `POST /tui/clear-prompt`
|
|
68
|
-
- `POST /tui/append-prompt`
|
|
69
|
-
- `POST /tui/submit-prompt`
|
|
70
|
-
- `GET /event` (SSE stream)
|
|
71
|
-
- `GET /session` — list sessions (optional `?directory=` filter)
|
|
72
|
-
- `POST /session` — create a new session (optional `{ title? }` body)
|
|
73
|
-
- `PATCH /session/:id` — update session properties (`{ title }`, optional `{ agent }`)
|
|
74
|
-
- `POST /session/:id/select` — tell the TUI to navigate to a session (only with TUI attached)
|
|
75
|
-
- `POST /session/:id/message` — send message to session (returns parts synchronously; optional `agent` field)
|
|
76
|
-
- `POST /session/:id/prompt_async` — send message to session (returns 204; answer via SSE)
|
|
77
|
-
- `GET /agent` — list available agents
|
|
78
|
-
- `GET /provider` — list connected providers/models
|
|
79
|
-
|
|
80
|
-
## Agentp gateway (tgagentp ↔ agentp interop)
|
|
81
|
-
|
|
82
|
-
- tgagentp starts a tiny HTTP server (POST /send) on `127.0.0.1`, port from `TGAGENTP_PORT` (default 0 = random).
|
|
83
|
-
- Port is written to `/tmp/tgagentp-port` for agentp discovery.
|
|
84
|
-
- Validates `Authorization` header against `OPENCODE_SERVER_PASSWORD`.
|
|
85
|
-
- agentp `--tg` reads the port file and POSTs `{ text, server }` to the gateway.
|
|
86
|
-
- Messages for the active server are delivered immediately; others are queued per-server.
|
|
87
|
-
- Debounced Telegram notification (configurable via `TGAGENTP_DEBOUNCE_MS`, default 5000ms).
|
|
88
|
-
- Queued messages are flushed on `/servers switch`.
|
|
89
|
-
|
|
90
|
-
## OpenCode tmux session model (ocmux)
|
|
91
|
-
|
|
92
|
-
- Single tmux session named `"Opencode"`
|
|
93
|
-
- Windows named by full project directory path
|
|
94
|
-
- Server pane runs `opencode serve --port 0` (via send-keys → interactive shell for env var support), TUI pane runs `opencode attach --continue`; `ocmux serve --print-logs` adds `--print-logs` to the serve command
|
|
95
|
-
- Log file per project: `/tmp/opencode-serve-<hashDir(dir)>.log` — captured via `tee`, read by ocmux polling loop
|
|
96
|
-
- Per-project `.ocmux.json` with upward directory search (git-like)
|
|
97
|
-
- Auto-restarts dead TUI panes on switch (respawn-pane or split-window)
|
|
98
|
-
- Auto-zooms TUI pane on switch/create
|
|
99
|
-
|
|
100
|
-
## Commands
|
|
101
|
-
|
|
102
|
-
| Command | What |
|
|
103
|
-
|---|---|---|
|
|
104
|
-
| `npm link` | local dev install |
|
|
105
|
-
| `npm install -g .` | alternative local install |
|
|
106
|
-
| `agentp [--qa] [--tg|--no-tg] [port]` | pipe stdin → opencode session, stream answer to stdout (uses session API); `--tg` forwards answer to Telegram |
|
|
107
|
-
| `tgagentp [port]` | bridge Telegram bot ↔ opencode TUI (needs `TELEGRAM_BOT_TOKEN`) |
|
|
108
|
-
| `tgagentp --dev` | enable `/shutdown` command for remote restart |
|
|
109
|
-
| `ocmux serve [--print-logs] [dir]` | start opencode serve in a tmux window (primary verb) |
|
|
110
|
-
| `ocmux new [dir]` | alias for `serve` (backwards compat, to be removed in 1.0) |
|
|
111
|
-
| `ocmux kill [dir]` | kill server + tmux window |
|
|
112
|
-
| `ocmux list [-l]` | list running servers |
|
|
113
|
-
| `ocmux [dir]` | switch to existing opencode tmux window |
|
|
114
|
-
|
|
115
|
-
## TODO
|
|
116
|
-
|
|
117
|
-
### Pending
|
|
118
|
-
|
|
119
|
-
- `agentp --getLast n` — retrieve last n answers from session history
|
|
120
|
-
|
|
121
|
-
### In Progress
|
|
122
|
-
|
|
123
|
-
*(none)*
|
|
124
|
-
|
|
125
|
-
### Done
|
|
126
|
-
|
|
127
|
-
- agentp `--qa` full context forwarding to Telegram (rulers, prompt, answer) — 0.9.0
|
|
128
|
-
- agentp resilience: 5s HTTP timeout, pre-send gate check, post-send warning (not hard error) for `--tg`; auto mode silently degrades — 0.9.0
|
|
129
|
-
- tgagentp: `lockedChatId` set at startup to fix race condition with agentp gateway — 0.9.0
|
|
130
|
-
- tgagentp: server error handler + try-catch in gateway handler (no crash on socket errors) — 0.9.0
|
|
131
|
-
- agentp `--tg`/`--no-tg` — gateway forwards answer to Telegram via tgagentp HTTP server; per-server queue with debounced notifications; auto-flush on server switch
|
|
132
|
-
- agentp session API migration — uses `POST /session/:id/message` instead of TUI endpoints
|
|
133
|
-
- ocmux `--print-logs` flag — pass-through to `opencode serve --print-logs` (prints server logs to stderr in the server pane)
|
|
134
|
-
- /agents lists only primary agents with ▶ active marker
|
|
135
|
-
- /agents switch calls `updateSession(agent)` to persist agent on session + `selectSession` to refresh TUI
|
|
136
|
-
- Logging rebalance: stdout for info, stderr for errors/debug/trace, `--verbose` flag, `2>/dev/null` default usage
|
|
137
|
-
- `/shutdown force` — refuses shutdown when busy unless `force` flag is given; goodbye message includes state
|
|
138
|
-
- `/think [on|off|switch]` — toggle real-time forwarding of model thinking messages to the chat; `--think` CLI flag to start enabled
|
|
139
|
-
- Event-driven permission handling (`POST /session/:id/prompt_async` + SSE listener + `/allow`, `/reject`, `/always` commands) — included in v0.7.0
|
|
140
|
-
- TUI navigation on `/sessions switch` and `/sessions new` — `POST /tui/select-session` now works in opencode 1.15.13 (was: tried second, never reached)
|
|
141
|
-
- /sessions new [name] — create a new session, TUI follows via /session/:id/select
|
|
142
|
-
- /sessions rename <name> — rename the current active session
|
|
143
|
-
- Merge /session into /sessions (keep /session as alias)
|
|
144
|
-
- Case-insensitive matching for all switch subcommands (/servers, /sessions, /agents)
|
|
145
|
-
- Fix: /sessions filter includes sessions with directory (TUI sessions) + active session exception
|
|
146
|
-
- Fix: /sessions now shows the active session even without agent set (exception in filter)
|
|
147
|
-
- Fix: /sessions switch and /sessions new call selectSession (TUI navigation didn't work in opencode < 1.15.x)
|
|
148
|
-
- Fix: active session highlighted with ▶ bullet in session list
|
|
149
|
-
- Fix: discover TUI session on startup and server switch via `discoverActiveSession()`
|
|
150
|
-
- Message splitting (>4096 chars, breaks at newlines)
|
|
151
|
-
- Fix: tuiPaneId detects 'bun' (opencode 1.15.x) in addition to 'node'
|
|
152
|
-
- Fix: URL polling in ocmux doNew takes last match, not first (more robust with bun startup)
|
|
153
|
-
- lib/ocmux.js shared session discovery, refactor ocmux + tgagentp
|
|
154
|
-
- /cancel with true server-side SSE abort via cancelRef
|
|
155
|
-
- /shutdown (--dev mode) with Telegram offset acknowledgment
|
|
156
|
-
|
|
157
|
-
### Verified
|
|
158
|
-
|
|
159
|
-
- Password auth support (OPENCODE_SERVER_PASSWORD) for agentp, ocmux, tgagentp
|
|
160
|
-
- agentp HTTP Basic Auth headers on all requests (POST and SSE)
|
|
161
|
-
- agentp clear 401 error reporting
|
|
162
|
-
- ocmux interactive shells (send-keys) for env var propagation
|
|
163
|
-
- tgagentp Telegram bridge bot with long-polling
|
|
164
|
-
- Markdown→HTML converter (**bold**, *italic*, `code`, code blocks, headings, tables)
|
|
165
|
-
- Chat allowlist (TGAGENTP_ALLOWED_CHAT_IDS)
|
|
166
|
-
- Slash command system (/help, /servers, /sessions, /session, /agents, /agents switch, /models, /status, /cancel, /shutdown)
|
|
167
|
-
- Per-server state tracking (busy/idle, pendingResponse, activeSessionId, activeAgentName, taskId)
|
|
168
|
-
- Background async processing (non-commands fire without await)
|
|
169
|
-
- /servers switch activates tmux window (pin, restart TUI, select, zoom)
|
|
170
|
-
- Startup greeting with /status-style info persisted via temp file
|
|
171
|
-
- Fix port mismatch bug: truncate stale log file before send-keys in doNew
|
|
172
|
-
- Update README with full tgagentp features (slash commands, --dev, env vars)
|
|
173
|
-
- Update AGENTS.md with lib/ocmux.js, missing API endpoints, current architecture
|
|
174
|
-
- Single-user lock: first chat to connect owns the session
|
|
175
|
-
- Fix startup greeting markdown not being converted to HTML
|
|
176
|
-
|
|
177
|
-
*(Keep this TODO up to date: move items between categories as their status changes.)*
|
package/CHANGELOG.md
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
All notable changes to this project will be documented in this file.
|
|
4
|
-
|
|
5
|
-
## [Unreleased]
|
|
6
|
-
|
|
7
|
-
- Rename package and CLI command from `aprompt` to `agentp`.
|
|
8
|
-
- Extract shared OpenCode client logic into `lib/opencode.js`.
|
|
9
|
-
- Add `tgagentp` — bridge a Telegram bot chat with an OpenCode TUI session.
|
|
10
|
-
|
|
11
|
-
## [0.8.0] - 2026-06-03
|
|
12
|
-
|
|
13
|
-
- Fix `/servers` crash: `serverBase is not defined` error.
|
|
14
|
-
- Logging rebalance: stdout for info, stderr for errors/debug with `--verbose` flag (`2>/dev/null` for clean console).
|
|
15
|
-
- `/shutdown force`: refuse shutdown when busy unless `force` flag given.
|
|
16
|
-
- `/think [on|off|switch]`: toggle real-time forwarding of model thinking messages; `--think` CLI flag.
|
|
17
|
-
- Reply quoting: when replying to a Telegram message, prepend quoted text with safe backtick fencing.
|
|
18
|
-
- Reply chaining: answers use `reply_to_message_id` to appear as replies.
|
|
19
|
-
- TUI navigation: `POST /tui/select-session` tried first (works in opencode 1.15.13).
|
|
20
|
-
|
|
21
|
-
## [0.1.0] - 2026-05-08
|
|
22
|
-
|
|
23
|
-
- Initial release.
|
|
24
|
-
- Add project documentation and usage examples.
|