mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-02 21:49:42 +02:00
Compare commits
6
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4295faefc9 | ||
|
|
93e1ba5110 | ||
|
|
abbbf9e90a | ||
|
|
3a41de7b57 | ||
|
|
8267edc6fe | ||
|
|
cc624d2575 |
@@ -1,5 +1,11 @@
|
|||||||
# aicodeman
|
# aicodeman
|
||||||
|
|
||||||
|
## 0.3.12
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Add WebSocket terminal I/O with server-side DEC 2026 synchronized update markers. Replaces per-keystroke HTTP POST + SSE terminal output with a single bidirectional WebSocket connection for dramatically lower input latency. Server-side 8ms micro-batching with 16KB flush threshold groups rapid PTY events into single WS frames wrapped in DEC 2026 markers for flicker-free atomic rendering. Includes 30s ping/pong heartbeat with 10s timeout for stale connection detection through tunnels. Existing SSE + HTTP POST paths remain fully functional as transparent fallback. Resize messages validated to match HTTP route bounds (cols 1-500, rows 1-200, integers only). 16 automated route tests added for WS endpoint. Also patches 5 dependency vulnerabilities (basic-ftp, fastify, minimatch, serialize-javascript).
|
||||||
|
|
||||||
## 0.3.11
|
## 0.3.11
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ When user says "COM":
|
|||||||
4. **Sync CLAUDE.md version**: Update the `**Version**` line below to match the new version from `package.json`
|
4. **Sync CLAUDE.md version**: Update the `**Version**` line below to match the new version from `package.json`
|
||||||
5. **Commit and deploy**: `git add -A && git commit -m "chore: version packages" && git push && npm run build && systemctl --user restart codeman-web`
|
5. **Commit and deploy**: `git add -A && git commit -m "chore: version packages" && git push && npm run build && systemctl --user restart codeman-web`
|
||||||
|
|
||||||
**Version**: 0.3.11 (must match `package.json`)
|
**Version**: 0.3.12 (must match `package.json`)
|
||||||
|
|
||||||
## Project Overview
|
## Project Overview
|
||||||
|
|
||||||
@@ -109,8 +109,8 @@ Codeman is a Claude Code session manager with web interface and autonomous Ralph
|
|||||||
| **Infra** | `src/hooks-config.ts`, `src/push-store.ts`, `src/tunnel-manager.ts`, `src/image-watcher.ts`, `src/file-stream-manager.ts` | |
|
| **Infra** | `src/hooks-config.ts`, `src/push-store.ts`, `src/tunnel-manager.ts`, `src/image-watcher.ts`, `src/file-stream-manager.ts` | |
|
||||||
| **Plan** | `src/plan-orchestrator.ts`, `src/prompts/*.ts`, `src/templates/claude-md.ts` | |
|
| **Plan** | `src/plan-orchestrator.ts`, `src/prompts/*.ts`, `src/templates/claude-md.ts` | |
|
||||||
| **Web** | `src/web/server.ts`, `src/web/sse-events.ts`, `src/web/routes/*.ts` (12 route modules + barrel), `src/web/ports/*.ts`, `src/web/middleware/auth.ts`, `src/web/schemas.ts` | |
|
| **Web** | `src/web/server.ts`, `src/web/sse-events.ts`, `src/web/routes/*.ts` (12 route modules + barrel), `src/web/ports/*.ts`, `src/web/middleware/auth.ts`, `src/web/schemas.ts` | |
|
||||||
| **Frontend** | `src/web/public/app.js` ★ (~12.1K lines) + 9 JS modules (incl. `sw.js` service worker) | |
|
| **Frontend** | `src/web/public/app.js` ★ (~12.5K lines) + 9 JS modules (incl. `sw.js` service worker) | |
|
||||||
| **Types** | `src/types/index.ts` → 14 domain files | See `@fileoverview` in index.ts |
|
| **Types** | `src/types/index.ts` → 13 domain files | See `@fileoverview` in index.ts |
|
||||||
|
|
||||||
★ = Large file (>50KB). All files have `@fileoverview` JSDoc — read that before diving in.
|
★ = Large file (>50KB). All files have `@fileoverview` JSDoc — read that before diving in.
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "aicodeman",
|
"name": "aicodeman",
|
||||||
"version": "0.3.11",
|
"version": "0.3.12",
|
||||||
"description": "The missing control plane for AI coding agents - run 20 autonomous agents with real-time monitoring and session persistence",
|
"description": "The missing control plane for AI coding agents - run 20 autonomous agents with real-time monitoring and session persistence",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
|
|||||||
@@ -38,6 +38,13 @@ const WS_BATCH_INTERVAL_MS = 8;
|
|||||||
/** Flush immediately when batch exceeds this size (bytes) for responsiveness. */
|
/** Flush immediately when batch exceeds this size (bytes) for responsiveness. */
|
||||||
const WS_BATCH_FLUSH_THRESHOLD = 16384;
|
const WS_BATCH_FLUSH_THRESHOLD = 16384;
|
||||||
|
|
||||||
|
/** How often to ping each WebSocket client (ms). Detects stale connections that
|
||||||
|
* TCP keepalive won't catch for minutes, especially through tunnels/proxies. */
|
||||||
|
const WS_PING_INTERVAL_MS = 30_000;
|
||||||
|
|
||||||
|
/** If pong isn't received within this window after a ping, terminate the socket. */
|
||||||
|
const WS_PONG_TIMEOUT_MS = 10_000;
|
||||||
|
|
||||||
/** DEC 2026 synchronized update markers. Wrapping output in these tells xterm.js
|
/** DEC 2026 synchronized update markers. Wrapping output in these tells xterm.js
|
||||||
* to buffer all content and render atomically in a single frame — eliminates
|
* to buffer all content and render atomically in a single frame — eliminates
|
||||||
* flicker from cursor-up redraws that Ink sends without its own sync markers
|
* flicker from cursor-up redraws that Ink sends without its own sync markers
|
||||||
@@ -133,7 +140,35 @@ export function registerWsRoutes(app: FastifyInstance, ctx: SessionPort): void {
|
|||||||
session.on('clearTerminal', onClearTerminal);
|
session.on('clearTerminal', onClearTerminal);
|
||||||
session.on('needsRefresh', onNeedsRefresh);
|
session.on('needsRefresh', onNeedsRefresh);
|
||||||
|
|
||||||
|
// Heartbeat: detect stale connections (especially through tunnels where
|
||||||
|
// TCP RST can take minutes to propagate).
|
||||||
|
let pongTimeout: ReturnType<typeof setTimeout> | null = null;
|
||||||
|
let alive = true;
|
||||||
|
|
||||||
|
socket.on('pong', () => {
|
||||||
|
alive = true;
|
||||||
|
if (pongTimeout) {
|
||||||
|
clearTimeout(pongTimeout);
|
||||||
|
pongTimeout = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const pingInterval = setInterval(() => {
|
||||||
|
if (!alive) {
|
||||||
|
// Previous ping never got a pong — connection is dead
|
||||||
|
socket.terminate();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
alive = false;
|
||||||
|
socket.ping();
|
||||||
|
pongTimeout = setTimeout(() => {
|
||||||
|
socket.terminate();
|
||||||
|
}, WS_PONG_TIMEOUT_MS);
|
||||||
|
}, WS_PING_INTERVAL_MS);
|
||||||
|
|
||||||
socket.on('close', () => {
|
socket.on('close', () => {
|
||||||
|
clearInterval(pingInterval);
|
||||||
|
if (pongTimeout) clearTimeout(pongTimeout);
|
||||||
if (batchTimer) clearTimeout(batchTimer);
|
if (batchTimer) clearTimeout(batchTimer);
|
||||||
batchChunks = [];
|
batchChunks = [];
|
||||||
session.off('terminal', onTerminal);
|
session.off('terminal', onTerminal);
|
||||||
|
|||||||
Reference in New Issue
Block a user