Commit Graph
173 Commits
Author SHA1 Message Date
480584de63 chore: project setup and tooling cleanup (#26)
* add project setup

* add tools to eslint

* remove contributing.md

* update claude md

* chore: simplify CI to single Node.js version (22)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* use node 20

* adjust formatting

* fix linting

* format

* fix layout

* fix: align CI node version to .nvmrc (22), remove redundant gotcha

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: arkon <arkon.85@hotmail.com>
2026-02-27 13:16:23 +01:00
arkon b99821cd10 fix: tunnel stop respawning + fix pre-existing TS errors 2026-02-27 08:54:00 +01:00
arkon 8038145d40 chore: bump version to 0.1658 2026-02-27 08:53:30 +01:00
arkonandClaude Opus 4.6 c668f9bae1 chore: bump version to 0.1656
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 08:28:30 +01:00
arkonandClaude Opus 4.6 8fc0dc8c2e chore: bump version to 0.1655
Security hardening: timing-safe auth comparison, localhost-only hook bypass,
SSE client limit, TLS key permissions, strict settings schema, logout endpoint.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 01:13:58 +01:00
arkonandClaude Opus 4.6 f699002cbf chore: bump version to 0.1654
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 01:07:03 +01:00
arkon 5f1f66bf60 chore: bump version to 0.1652 2026-02-27 00:34:38 +01:00
arkonandClaude Opus 4.6 3795c45cc1 chore: rename Claudeman to Codeman
Full product rename across 109 files (~834 occurrences):
- Env vars: CLAUDEMAN_* → CODEMAN_*
- Data dirs: ~/.claudeman/ → ~/.codeman/, ~/claudeman-cases/ → ~/codeman-cases/
- tmux prefix: claudeman- → codeman-
- localStorage: claudeman-* → codeman-*
- Package/CLI: claudeman → codeman
- GitHub repo: Ark0N/Claudeman → Ark0N/Codeman
- systemd service: claudeman-web → codeman-web
- Class: ClaudemanApp → CodemanApp

Migration infrastructure for seamless transition:
- state-store.ts: auto-migrates data directories on startup
- tmux-manager.ts: dual-prefix detection (legacy claudeman- sessions)
- app.js: localStorage key migration (preserves old keys)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 16:44:34 +01:00
arkonandClaude Opus 4.6 a899a8b67a fix: address code review findings for OpenCode integration
- Add _isStopped guard to OpenCode 3s readiness timeout (session.ts)
- Block respawn for opencode sessions on interactive-respawn and
  respawn/enable routes (server.ts)
- Fail fast in direct PTY fallback for OpenCode mode (session.ts)
- Validate configContent as JSON at schema level (schemas.ts)
- Update JSDoc example for createSession options API (tmux-manager.ts)
- Un-hide Context tab for OpenCode sessions (index.html)
- Add OpenCode UI tests (opencode-resize.test.ts)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 15:58:26 +01:00
arkonandClaude Opus 4.6 33f39c91ba fix: update mobile CSS for OpenCode run button group
Replace dead .btn-claude selectors in mobile.css with proper styling
for the new split run button (.btn-run + .btn-run-gear). Add mobile
touch-friendly dropdown menu options (10px padding, 35px height).
Include mode-specific colors for both Claude (blue) and OpenCode
(green) on mobile. Also guard Claude-specific features (Ralph,
Respawn) from running on OpenCode sessions in server.ts.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 15:06:36 +01:00
arkonandClaude Opus 4.6 2e3a08fad2 fix: emit needsRefresh after OpenCode TUI stabilizes
After the 3s TUI stabilization timeout, emit needsRefresh so the
client fetches the full terminal buffer. Without this, the terminal
appears empty until the user manually refreshes or switches tabs.

Wire needsRefresh as a proper session listener in server.ts with
cleanup in both removal paths to prevent memory leaks.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-02-26 13:03:28 +01:00
arkonandClaude Opus 4.6 02f3bea3c1 feat: OpenCode integration Phase 5 — API routes, frontend UI
API changes:
- GET /api/opencode/status — check if OpenCode CLI is available
- POST /api/sessions — support mode: 'opencode' with openCodeConfig
- POST /api/quick-start — support mode: 'opencode', guard writeHooksConfig
- Fix hardcoded mode: 'claude' in lifecycle logs (use session.mode)

Schema changes:
- Add 'opencode' to mode enums in CreateSessionSchema, QuickStartSchema
- Add OpenCodeConfigSchema (model, autoAllowTools, continueSession, etc.)
- Add 'OPENCODE_' to ALLOWED_ENV_PREFIXES
- Block OPENCODE_SERVER_PASSWORD in BLOCKED_ENV_KEYS (atomic with prefix addition)

Frontend UI:
- "Run OC" button in toolbar + "Run OpenCode" on welcome screen
- Green "oc" tab badge for OpenCode sessions (matching green brand)
- runOpenCode() method — checks availability, quick-starts with autoAllowTools
- Feature gating: hide Respawn/Context/Ralph tabs for OpenCode sessions
- Session options defaults to Summary tab for OpenCode
- CSS: OpenCode button styles, tab badge styles

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-02-26 10:16:20 +01:00
arkonandClaude Opus 4.6 fd0b75c9a5 chore: bump version to 0.1640
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 13:40:55 +01:00
arkonandClaude Opus 4.6 5170c188c3 fix: respect Claude CLI startup mode setting (#12)
The "Startup Mode" setting (normal/bypass/allowedTools) was saved to
settings but never read when spawning sessions. All code paths had
--dangerously-skip-permissions hardcoded. Now reads claudeMode from
~/.claudeman/settings.json and passes it through Session → TmuxManager.

Closes #12

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 15:52:55 +01:00
arkon 37af7ead20 chore: bump version to 0.1614 2026-02-24 13:36:42 +01:00
arkonandClaude Opus 4.6 819b1771c3 chore: bump version to 0.1580
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 15:04:45 +01:00
arkon 3f9632c8c7 chore: bump version to 0.1579 2026-02-20 14:33:06 +01:00
arkonandClaude Opus 4.6 868d4f1196 perf: fix memory leaks — strip task outputs from SSE broadcasts, use light state everywhere
- TaskTracker.getTaskTreeLight(): strips large `output` strings from tasks
  in SSE broadcasts (was serializing 5-10MB every 500ms with many subagents)
- session:created broadcasts now use toLightDetailedState() (consistent with
  session:updated which already did)
- GET /api/sessions/:id returns light state (no 2-3MB terminal+text buffers)
- Ralph wizard polls /terminal?tail=2048 instead of full session endpoint

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 06:50:59 +01:00
arkon 5b882c448e chore: bump version to 0.1570 2026-02-20 06:09:28 +01:00
arkon 99ad44e907 perf: speed up session creation by ~500ms — remove redundant sleep, reduce tmux wait, fire-and-forget config 2026-02-20 04:30:02 +01:00
arkon 1b21e1b8d8 fix: server shutdown no longer kills tmux sessions — detach instead of cleanup
Previously, server.stop() called cleanupSession(killMux=false) for all sessions,
which still tore down session state, removed listeners, killed PTY processes via
node-pty SIGHUP, and broadcast session:deleted. This caused Claude sessions
running inside tmux to be disrupted during COM deploys.

Now server shutdown just persists state, removes listeners, and lets the Node.js
process exit naturally. The tmux sessions survive independently, and
restoreMuxSessions() finds them alive on restart.

Also adds defense-in-depth in session.stop(): when killMux=false, skip PTY kill
entirely (just null the reference). And adds 'detached' lifecycle event type for
accurate audit logging.
2026-02-19 22:15:36 +01:00
arkonandClaude Opus 4.6 383ed5e5a0 feat: session lifecycle audit log — append-only JSONL at ~/.claudeman/session-lifecycle.jsonl
Records every session create, start, exit, delete, recover, stale-clean,
mux-died, and server start/stop with timestamps, names, reasons, and exit
codes. Survives server restarts (unlike in-memory RunSummary).

- New SessionLifecycleLog singleton (src/session-lifecycle-log.ts)
- LifecycleEventType + LifecycleEntry types in types.ts
- GET /api/session-lifecycle endpoint with sessionId/event/since/limit filters
- cleanupSession() now takes reason parameter for audit trail
- state-store cleanupStaleSessions returns cleaned session IDs+names
- UI: lifecycle log modal accessible from header clipboard icon
- Auto-trims to 8k entries when exceeding 10k on server start

chore: bump version to 0.1556

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 18:30:14 +01:00
arkonandClaude Opus 4.6 fe1f665531 fix: ralph tracker — 3 bugs: first-occurrence completion, double-counting, TodoWrite pattern
Bug 1 (CRITICAL): canonicalCount >= 1 always fired on first <promise> tag
(prompt echo). Changed to >= 2 so only 2nd+ occurrence triggers completion.

Bug 2: checkMultiLinePatterns() re-detected complete tags already handled
by processLine(), double-counting. Now only tries completion when partial
buffer is non-empty (cross-chunk scenario).

Bug 3: TodoWrite ✔ patterns required "Task #N" but real Claude Code output
is plain "✔ content". Added TODO_PLAIN_CHECKMARK_PATTERN fallback.

Includes 71 new deep tests + real-life verification.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 14:00:10 +01:00
arkon 926e77b1c2 chore: bump version to 0.1550 2026-02-19 08:49:36 +01:00
arkon 1833a9ac2d chore: bump version to 0.1549 2026-02-18 23:14:39 +01:00
arkonandClaude Opus 4.6 d7ad617d7f chore: bump version to 0.1545
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 21:53:34 +01:00
arkon 88422cab57 chore: bump version to 0.1538 2026-02-18 12:51:35 +01:00
arkonandClaude Opus 4.6 c548c2d6ee fix: mobile keyboard handlers killed on SSE reconnect — re-init after cleanup
handleInit() called KeyboardHandler.cleanup() and MobileDetection.cleanup()
on every SSE connect but never re-initialized them, breaking keyboard
scroll-into-view and the /init /clear accessory bar on mobile.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 11:59:42 +01:00
arkon 62ddfdea36 chore: bump version to 0.1531 2026-02-18 10:23:10 +01:00
arkon 50b17184ee chore: bump version to 0.1529 2026-02-18 07:28:15 +01:00
arkonandClaude Opus 4.6 31d3e7bc70 chore: bump version to 0.1528
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 07:06:34 +01:00
arkon 9d67a571ba chore: bump version to 0.1527 2026-02-18 05:36:20 +01:00
arkon 4fd8174680 chore: bump version to 0.1524 2026-02-17 16:47:54 +01:00
arkon ea3e534607 chore: bump version to 0.1520 2026-02-16 21:19:16 +01:00
arkonandClaude Opus 4.6 da74ac248b fix: mobile keyboard layout — scroll-to-bottom on show, robust dismiss detection
Three bugs fixed in KeyboardHandler:
1. onKeyboardShow() used sessionData.terminal (always undefined) instead of app.terminal
2. Keyboard dismiss threshold (50px) too tight for iOS address bar drift — widened to 100px
3. No terminal refit on keyboard hide — caused black gap below terminal

Also added: dynamic baseline update for initialViewportHeight, safety check in
updateLayoutForKeyboard() that forces dismiss when keyboardOffset <= 0.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 12:10:44 +01:00
arkonandClaude Opus 4.6 9ab62adfa8 fix: medium severity audit fixes — races, leaks, perf, warnings
- Clear teams/teamTasks maps in handleInit() on SSE reconnect
- Fix saveNowAsync() race condition with in-flight promise guard
- Add setMaxListeners() on Session, WebServer, SubagentWatcher,
  ImageWatcher, TmuxManager to prevent MaxListenersExceeded warnings
- Debounce persistSessionState() per-session (100ms) to reduce
  redundant toState() serialization across 25+ call sites
- Cache getLightSessionsState() with 1s TTL to avoid re-serializing
  all sessions on every SSE connect and /api/sessions request

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 05:33:34 +01:00
arkonandClaude Opus 4.6 f223501164 fix: async I/O, map iteration bug, unified cleanup, Zod validation, error handling
- Convert sync readFileSync/statSync to async in subagent-watcher.ts to
  unblock event loop on hot paths (transcript reads, liveness checks)
- Fix Map mutation during iteration in closeSessionLogViewerWindows and
  closeSessionImagePopups (collect IDs first, then iterate to close)
- Unify session cleanup into shared _cleanupSessionData() method called
  from both closeSession() and session:deleted handler to prevent leaks
- Add Zod validation schemas for 20+ API routes that used raw type casts
- Add consecutive error tracking (5 errors/60s triggers exit for systemd
  restart) and SIGHUP handler for SSH disconnect safety

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 05:26:29 +01:00
arkon 641fd28211 chore: bump version to 0.1504 2026-02-13 21:21:33 +01:00
arkon 26373aabd0 chore: bump version to 0.1503 2026-02-13 21:07:49 +01:00
arkon d63fe2063f chore: bump version to 0.1502 2026-02-13 20:25:56 +01:00
arkon 3a77fe48e3 chore: bump version to 0.1496 2026-02-13 07:42:50 +01:00
arkonandClaude Opus 4.6 7d2519cacb fix: subagent windows not opening — two cascading bugs
1. handleInit crash: commit cdc822d removed Map initializations for
   teammateTerminals, teammatePanesByName, teams, teamTasks, teammateMap
   from the constructor but left cleanup code that iterates them.
   cleanupAllFloatingWindows() crashed on "not iterable", preventing
   ALL frontend data (sessions, subagents) from loading.

2. claudeSessionId null on recovered sessions: only set inside
   startInteractive(), never in constructor or persisted. After server
   restart, recovered sessions had null claudeSessionId, so the
   hasMatchingTab check always failed → no subagent windows.

Fixes:
- Re-add all 5 missing Map initializations in app.js constructor
- Set _claudeSessionId = this.id in Session constructor (Claudeman
  always passes --session-id to Claude, so they always match)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 05:07:51 +01:00
arkon f47ae4b80f chore: bump version to 0.1491 2026-02-12 20:14:01 +01:00
arkonandClaude Opus 4.6 0314de7789 fix: bulletproof test safety — IS_TEST_MODE guards prevent tests from killing real tmux sessions
Added IS_TEST_MODE (process.env.VITEST) guards to every method in TmuxManager and
ScreenManager that touches real tmux/screen sessions. Tests can never create, kill,
discover, or send input to real sessions. Removed broken E2E test suite entirely.
Rewrote test/setup.ts from 459 lines to minimal cleanup. Rewrote tmux-related tests
to verify test-mode safety behavior.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 18:26:16 +01:00
arkon cdc822d657 fix: add Agent Teams types to types.ts, remove unused server imports 2026-02-12 14:42:58 +01:00
arkon e44f827473 chore: bump version to 0.1488 2026-02-12 14:41:27 +01:00
arkonandClaude Opus 4.6 a4e778c7c4 chore: bump version to 0.1486
feat: interactive teammate tmux pane windows with xterm.js terminals
feat: auto-cleanup teams/subagents/pane windows on session delete
fix: only show agent/teammate windows when matching Claudeman tab exists
fix: UTF-8 encoding in teammate pane terminal output (Uint8Array)
fix: standalone pane window cleanup via subagentParentMap lookup
fix: xterm.js dimensions crash with deferred init + null-safe dispose

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 13:44:07 +01:00
arkon 65f81667d0 chore: bump version to 0.1481 2026-02-12 10:29:57 +01:00
arkonandClaude Opus 4.6 3145b3f9a3 chore: bump version to 0.1479
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 08:34:51 +01:00
arkonandClaude Opus 4.5 8f0bbf33d6 chore: bump version to 0.1477
Location: Ko Samui

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 07:24:32 +01:00