mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-02 05:29:42 +02:00
fix: local echo overlay lost on mobile redraws — preserve pending text across SSE reconnect, terminal resets, and Ink redraws
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -35,7 +35,7 @@ When user says "COM":
|
||||
1. Increment version in BOTH `package.json` AND `CLAUDE.md` (verify they match with `grep version package.json && grep Version CLAUDE.md`)
|
||||
2. Run: `git add -A && git commit -m "chore: bump version to X.XXXX" && git push && npm run build && systemctl --user restart claudeman-web`
|
||||
|
||||
**Version**: 0.1551 (must match `package.json` for npm publish)
|
||||
**Version**: 0.1552 (must match `package.json` for npm publish)
|
||||
|
||||
## Project Overview
|
||||
|
||||
@@ -124,13 +124,13 @@ journalctl --user -u claudeman-web -f
|
||||
| `src/file-stream-manager.ts` | Manages `tail -f` processes for live log viewing |
|
||||
| `src/plan-orchestrator.ts` | Multi-agent plan generation with research and planning phases |
|
||||
| `src/prompts/index.ts` | Barrel export for all agent prompts |
|
||||
| `src/prompts/*.ts` | Agent prompts (research-agent, code-reviewer, planner) |
|
||||
| `src/prompts/*.ts` | Agent prompts (research-agent, planner) |
|
||||
| `src/templates/claude-md.ts` | CLAUDE.md generation for new cases |
|
||||
| `src/cli.ts` | Command-line interface handlers |
|
||||
| `src/web/server.ts` | Fastify REST API + SSE at `/api/events` (~90 routes) |
|
||||
| `src/web/server.ts` | Fastify REST API + SSE at `/api/events` (~99 routes) |
|
||||
| `src/web/schemas.ts` | Zod v4 validation schemas with path/env security allowlists |
|
||||
| `src/web/public/app.js` | Frontend: xterm.js, tab management, subagent windows, mobile support (~16K lines) |
|
||||
| `src/types.ts` | All TypeScript interfaces (~100 types, ~1500 lines) |
|
||||
| `src/types.ts` | All TypeScript interfaces (~100 types, ~1400 lines) |
|
||||
|
||||
**Large files** (>50KB): `app.js`, `ralph-tracker.ts`, `respawn-controller.ts`, `session.ts`, `subagent-watcher.ts` — these contain complex state machines; read `docs/respawn-state-machine.md` before modifying.
|
||||
|
||||
@@ -232,7 +232,7 @@ The frontend is a single 16K-line vanilla JS file with these key systems:
|
||||
|
||||
### API Route Categories
|
||||
|
||||
~90 routes in `server.ts:buildServer()`. Key groups:
|
||||
~99 routes in `server.ts:buildServer()`. Key groups:
|
||||
|
||||
| Group | Prefix | Count | Key endpoints |
|
||||
|-------|--------|-------|---------------|
|
||||
@@ -295,6 +295,8 @@ npx vitest run -t "pattern"
|
||||
|
||||
**Respawn tests**: Use MockSession from `test/respawn-test-utils.ts` to avoid spawning real Claude processes.
|
||||
|
||||
**Mobile tests**: Separate Playwright-based suite in `mobile-test/` with 135 device profiles. Run via `npx vitest run --config mobile-test/vitest.config.ts`. See `mobile-test/README.md`.
|
||||
|
||||
## Screenshots ("sc")
|
||||
|
||||
When the user says "check the sc", "screenshot", or "sc", they mean uploaded screenshots from their mobile device. Screenshots are saved to `~/.claudeman/screenshots/` and uploaded via `/upload.html` on the Claudeman web UI. To view them, use the Read tool on the image files:
|
||||
@@ -402,6 +404,9 @@ Use `LRUMap` for bounded caches with eviction, `StaleExpirationMap` for TTL-base
|
||||
| **Mobile testing** | `docs/mobile-testing-report.md` |
|
||||
| **Run summary design** | `docs/run-summary-plan.md` |
|
||||
| **Performance audit** | `docs/perf-audit-first-load.md` |
|
||||
| **First-load optimization** | `docs/first-load-optimization-plan.md` |
|
||||
| **Dead code audit** | `docs/cleanup-findings.md` |
|
||||
| **Mobile test suite** | `mobile-test/README.md` |
|
||||
|
||||
## Scripts
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "claudeman",
|
||||
"version": "0.1551",
|
||||
"version": "0.1552",
|
||||
"description": "The missing control plane for Claude Code - run 20 autonomous agents with real-time monitoring and session persistence",
|
||||
"type": "module",
|
||||
"main": "dist/index.js",
|
||||
|
||||
+30
-2
@@ -970,6 +970,12 @@ class LocalEchoOverlay {
|
||||
}
|
||||
}
|
||||
|
||||
// Re-render overlay at current prompt position without clearing pending text.
|
||||
// Used after terminal resets/redraws that move the prompt.
|
||||
rerender() {
|
||||
if (this.pendingText) this._render();
|
||||
}
|
||||
|
||||
get hasPending() { return this.pendingText.length > 0; }
|
||||
|
||||
dispose() {
|
||||
@@ -2337,6 +2343,12 @@ class ClaudemanApp {
|
||||
if (this._wasAtBottomBeforeWrite) {
|
||||
this.terminal.scrollToBottom();
|
||||
}
|
||||
|
||||
// Re-position local echo overlay after terminal writes — Ink redraws can
|
||||
// move the ❯ prompt to a different row, making the overlay invisible.
|
||||
if (this._localEchoOverlay?.hasPending) {
|
||||
this._localEchoOverlay.rerender();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2646,6 +2658,8 @@ class ClaudemanApp {
|
||||
this.terminal.reset();
|
||||
await this.chunkedTerminalWrite(data.terminalBuffer);
|
||||
this.terminal.scrollToBottom();
|
||||
// Re-position local echo overlay at new prompt location
|
||||
this._localEchoOverlay?.rerender();
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('needsRefresh reload failed:', err);
|
||||
@@ -2672,6 +2686,8 @@ class ClaudemanApp {
|
||||
|
||||
// Send resize to ensure proper dimensions
|
||||
await this.sendResize(data.id);
|
||||
// Re-position local echo overlay at new prompt location
|
||||
this._localEchoOverlay?.rerender();
|
||||
} catch (err) {
|
||||
console.error('clearTerminal refresh failed:', err);
|
||||
}
|
||||
@@ -3717,8 +3733,10 @@ class ClaudemanApp {
|
||||
this.writeFrameScheduled = false;
|
||||
this._isLoadingBuffer = false;
|
||||
this._loadBufferQueue = null;
|
||||
// Clear local echo overlay on SSE reconnect (re-enable via _updateLocalEchoState)
|
||||
this._localEchoOverlay?.clear();
|
||||
// Preserve local echo overlay text across SSE reconnect — just hide until
|
||||
// terminal buffer reloads and prompt is visible again. _render() re-scans
|
||||
// for the ❯ prompt on every call, so rerender() after buffer load repositions it.
|
||||
this._localEchoOverlay?.rerender();
|
||||
// Clear pending hooks
|
||||
this.pendingHooks.clear();
|
||||
// Clear subagent activity/results maps (prevents leaks if data.subagents is missing)
|
||||
@@ -3864,6 +3882,8 @@ class ClaudemanApp {
|
||||
// Guard: skip if a newer handleInit has already started (race between loadState + SSE init).
|
||||
if (gen !== this._initGeneration) return;
|
||||
const previousActiveId = this.activeSessionId;
|
||||
// Save local echo pending text before selectSession clears it
|
||||
const savedEchoText = this._localEchoOverlay?.pendingText || '';
|
||||
this.activeSessionId = null;
|
||||
if (this.sessionOrder.length > 0) {
|
||||
// Priority: current active > localStorage > first session
|
||||
@@ -3877,6 +3897,14 @@ class ClaudemanApp {
|
||||
this.selectSession(this.sessionOrder[0]);
|
||||
}
|
||||
}
|
||||
// Restore local echo text that was cleared by selectSession during SSE reconnect.
|
||||
// selectSession loads the terminal buffer, so we schedule rerender after it settles.
|
||||
if (savedEchoText && this._localEchoOverlay) {
|
||||
this._localEchoOverlay.pendingText = savedEchoText;
|
||||
this._localEchoOverlay._persist();
|
||||
// Delay rerender until buffer load completes and prompt is visible
|
||||
setTimeout(() => this._localEchoOverlay?.rerender(), 500);
|
||||
}
|
||||
}
|
||||
|
||||
async loadState() {
|
||||
|
||||
Reference in New Issue
Block a user