From 3795c45cc178d5206a4caa3f3d4035b151598b7e Mon Sep 17 00:00:00 2001 From: arkon Date: Thu, 26 Feb 2026 16:44:34 +0100 Subject: [PATCH] chore: rename Claudeman to Codeman MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- CLAUDE.md | 60 ++++----- README.md | 32 ++--- agent-teams/README.md | 10 +- agent-teams/design.md | 12 +- agent-teams/experiment-log.md | 42 +++---- ...ground-keystroke-forwarding-merged-plan.md | 2 +- docs/background-keystroke-forwarding-plan.md | 2 +- docs/browser-testing-guide.md | 8 +- docs/cleanup-findings.md | 2 +- docs/first-load-optimization-plan.md | 2 +- .../{claudeman-demo.gif => codeman-demo.gif} | Bin ...{claudeman-title.svg => codeman-title.svg} | 2 +- docs/local-echo-overlay-plan.md | 2 +- docs/opencode-integration.md | 114 +++++++++--------- docs/perf-audit-first-load.md | 4 +- docs/performance-investigation-report.md | 6 +- docs/plan-improvement-roadmap.md | 2 +- docs/ralph-improvement-plan.md | 4 +- docs/ralph-wiggum-guide.md | 16 +-- docs/reports/notification-audit-summary.md | 2 +- docs/reports/notification-backend.md | 14 +-- docs/reports/notification-blinking.md | 14 +-- docs/reports/notification-frontend.md | 26 ++-- docs/reports/notification-settings.md | 20 +-- docs/terminal-anti-flicker.md | 2 +- docs/typescript-improvement-suggestions.md | 16 +-- docs/voice-input-plan.md | 2 +- install.sh | 80 ++++++------ mobile-test/README.md | 6 +- mobile-test/helpers/constants.ts | 6 +- mobile-test/settings.test.ts | 6 +- package-lock.json | 6 +- package.json | 10 +- packages/xterm-zerolag-input/LICENSE | 2 +- packages/xterm-zerolag-input/README.md | 4 +- packages/xterm-zerolag-input/package.json | 4 +- scripts/browser-comparison.mjs | 16 +-- scripts/capture-readme-screenshots.mjs | 20 +-- scripts/capture-subagent-gif.mjs | 12 +- scripts/capture-subagent-screenshots.mjs | 16 +-- ...udeman-web.service => codeman-web.service} | 6 +- scripts/mobile-screenshot.mjs | 2 +- scripts/monitor-respawn.sh | 6 +- scripts/postinstall.js | 8 +- scripts/ralph-wizard-demo.mjs | 8 +- scripts/ralph-wizard-prod.mjs | 10 +- scripts/ralph-wizard-start.mjs | 12 +- scripts/test-links-browser.mjs | 24 ++-- scripts/test-tail-links.sh | 4 +- scripts/tmux-chooser.sh | 58 ++++----- scripts/tmux-manager.sh | 16 +-- src/ai-checker-base.ts | 8 +- src/ai-idle-checker.ts | 6 +- src/ai-plan-checker.ts | 6 +- src/cli.ts | 8 +- src/config/buffer-limits.ts | 2 +- src/hooks-config.ts | 12 +- src/image-watcher.ts | 4 +- src/index.ts | 4 +- src/mux-interface.ts | 6 +- src/run-summary.ts | 2 +- src/session-lifecycle-log.ts | 4 +- src/session.ts | 30 ++--- src/state-store.ts | 22 +++- src/subagent-watcher.ts | 20 +-- src/team-watcher.ts | 4 +- src/templates/case-template.md | 6 +- src/templates/claude-md.ts | 2 +- src/tmux-manager.ts | 43 ++++--- src/types.ts | 8 +- src/web/public/app.js | 101 +++++++++------- src/web/public/index.html | 18 +-- src/web/public/styles.css | 2 +- src/web/public/upload.html | 4 +- src/web/schemas.ts | 2 +- src/web/server.ts | 70 +++++------ test/ai-idle-checker.test.ts | 6 +- test/api-responses.test.ts | 4 +- test/buffer-management.test.ts | 2 +- test/cli-commands.test.ts | 12 +- test/edge-cases.test.ts | 4 +- test/file-link-click.test.ts | 6 +- test/hooks-config.test.ts | 10 +- test/input-echo-test.mjs | 2 +- test/integration-flows.test.ts | 2 +- test/local-echo-basic-test.mjs | 4 +- test/local-echo-daily-test.mjs | 4 +- test/local-echo-edge-test.mjs | 6 +- test/local-echo-mobile-test.mjs | 6 +- test/local-echo-scroll-test.mjs | 4 +- test/local-echo-tabswitch-test.mjs | 4 +- test/local-echo-user-test.mjs | 8 +- test/memory-leak-prevention.test.ts | 2 +- test/perf-subagent-load.test.ts | 4 +- test/quick-start.test.ts | 2 +- test/ralph-integration.test.ts | 2 +- test/respawn-analysis.md | 22 ++-- test/respawn-test-plan.md | 2 +- test/respawn-test-utils.ts | 2 +- test/session-cleanup.test.ts | 2 +- test/session-state.test.ts | 38 +++--- test/setup.ts | 2 +- test/sse-events.test.ts | 2 +- test/state-store.test.ts | 2 +- test/team-watcher.test.ts | 4 +- test/templates.test.ts | 14 +-- test/terminal-parsing.test.ts | 2 +- test/tmux-manager.test.ts | 40 +++--- test/tmux-restart-recovery.test.ts | 10 +- 109 files changed, 711 insertions(+), 679 deletions(-) rename docs/images/{claudeman-demo.gif => codeman-demo.gif} (100%) rename docs/images/{claudeman-title.svg => codeman-title.svg} (79%) rename scripts/{claudeman-web.service => codeman-web.service} (75%) diff --git a/CLAUDE.md b/CLAUDE.md index 55863eca..37041ddd 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -9,13 +9,13 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co | Dev server | `npx tsx src/index.ts web` | | Type check | `tsc --noEmit` | | Single test | `npx vitest run test/.test.ts` | -| Production | `npm run build && systemctl --user restart claudeman-web` | +| Production | `npm run build && systemctl --user restart codeman-web` | ## CRITICAL: Session Safety -**You may be running inside a Claudeman-managed tmux session.** Before killing ANY tmux or Claude process: +**You may be running inside a Codeman-managed tmux session.** Before killing ANY tmux or Claude process: -1. Check: `echo $CLAUDEMAN_TMUX` - if `1`, you're in a managed session +1. Check: `echo $CODEMAN_TMUX` - if `1`, you're in a managed session 2. **NEVER** run `tmux kill-session`, `pkill tmux`, or `pkill claude` without confirming 3. Use the web UI or `./scripts/tmux-manager.sh` instead of direct kill commands @@ -33,13 +33,13 @@ The production server caches static files for 1 hour (`maxAge: '1h'` in `server. 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` +2. Run: `git add -A && git commit -m "chore: bump version to X.XXXX" && git push && npm run build && systemctl --user restart codeman-web` **Version**: 0.1650 (must match `package.json`) ## Project Overview -Claudeman is a Claude Code session manager with web interface and autonomous Ralph Loop. Spawns Claude CLI via PTY, streams via SSE, supports respawn cycling for 24+ hour autonomous runs. +Codeman is a Claude Code session manager with web interface and autonomous Ralph Loop. Spawns Claude CLI via PTY, streams via SSE, supports respawn cycling for 24+ hour autonomous runs. **Tech Stack**: TypeScript (ES2022/NodeNext, strict mode), Node.js, Fastify, node-pty, xterm.js @@ -63,24 +63,24 @@ npx tsx src/index.ts web --https # With TLS (only needed for remote access) npm run typecheck # Type check tsc --noEmit --watch # Continuous type checking -# Testing (NEVER run full suite from inside Claudeman — kills tmux sessions) -# npx vitest run # ALL tests — DANGEROUS inside Claudeman +# Testing (NEVER run full suite from inside Codeman — kills tmux sessions) +# npx vitest run # ALL tests — DANGEROUS inside Codeman npx vitest run test/.test.ts # Single file (SAFE) npx vitest run -t "pattern" # Tests matching name npm run test:coverage # With coverage report # Production npm run build -systemctl --user restart claudeman-web -journalctl --user -u claudeman-web -f +systemctl --user restart codeman-web +journalctl --user -u codeman-web -f ``` ## Common Gotchas - **`npm run dev` is NOT the web server** — it shows CLI help. Use `npx tsx src/index.ts web` - **Single-line prompts only** — `writeViaMux()` sends text and Enter separately; multi-line breaks Ink -- **Don't kill tmux sessions blindly** — Check `$CLAUDEMAN_TMUX` first; you might be inside one -- **Never run full test suite** — `npx vitest run` spawns/kills tmux sessions and will crash your Claudeman session. Run individual test files only. +- **Don't kill tmux sessions blindly** — Check `$CODEMAN_TMUX` first; you might be inside one +- **Never run full test suite** — `npx vitest run` spawns/kills tmux sessions and will crash your Codeman session. Run individual test files only. - **Global regex `lastIndex` sharing** — `ANSI_ESCAPE_PATTERN_FULL/SIMPLE` have `g` flag; use `createAnsiPatternFull/Simple()` factory functions for fresh instances in loops - **DEC 2026 sync blocks** — Never discard incomplete sync blocks (START without END); buffer up to 50ms then flush. See `app.js:extractSyncSegments()` - **Terminal writes during buffer load** — Live SSE writes are queued while `_isLoadingBuffer` is true to prevent interleaving with historical data @@ -103,7 +103,7 @@ journalctl --user -u claudeman-web -f | `src/mux-factory.ts` | Create tmux multiplexer instance | | `src/tmux-manager.ts` | tmux session management | | `src/session-manager.ts` | Session lifecycle, cleanup | -| `src/state-store.ts` | State persistence to `~/.claudeman/state.json` | +| `src/state-store.ts` | State persistence to `~/.codeman/state.json` | | `src/respawn-controller.ts` | State machine for autonomous cycling | | `src/ralph-tracker.ts` | Detects `PHRASE`, todos | | `src/ralph-loop.ts` | Autonomous task execution loop (polls queue, assigns tasks) | @@ -120,7 +120,7 @@ journalctl --user -u claudeman-web -f | `src/bash-tool-parser.ts` | Parses Claude's bash tool invocations from output | | `src/transcript-watcher.ts` | Watches Claude's transcript files for changes | | `src/hooks-config.ts` | Manages `.claude/settings.local.json` hook configuration | -| `src/session-lifecycle-log.ts` | Append-only JSONL audit log at `~/.claudeman/session-lifecycle.jsonl` | +| `src/session-lifecycle-log.ts` | Append-only JSONL audit log at `~/.codeman/session-lifecycle.jsonl` | | `src/image-watcher.ts` | Watches for image file creation (screenshots, etc.) | | `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 | @@ -169,7 +169,7 @@ journalctl --user -u claudeman-web -f 1. Session spawns `claude --dangerously-skip-permissions` via node-pty 2. PTY output buffered, ANSI stripped, parsed for JSON messages 3. WebServer broadcasts to SSE clients at `/api/events` -4. State persists to `~/.claudeman/state.json` via StateStore +4. State persists to `~/.codeman/state.json` via StateStore ### Key Patterns @@ -214,11 +214,11 @@ The frontend is a single 16K-line vanilla JS file with these key systems: ### Security -- **HTTP Basic Auth**: Optional via `CLAUDEMAN_USERNAME`/`CLAUDEMAN_PASSWORD` env vars +- **HTTP Basic Auth**: Optional via `CODEMAN_USERNAME`/`CODEMAN_PASSWORD` env vars - **CORS**: Restricted to localhost only - **Security headers**: X-Content-Type-Options, X-Frame-Options, CSP; HSTS if HTTPS - **Path validation** (`schemas.ts`): Strict allowlist regex, no shell metacharacters, no traversal, must be absolute -- **Env var allowlist**: Only `CLAUDE_CODE_*` prefixes allowed; blocks `PATH`, `LD_PRELOAD`, `NODE_OPTIONS`, `CLAUDEMAN_*` keys +- **Env var allowlist**: Only `CLAUDE_CODE_*` prefixes allowed; blocks `PATH`, `LD_PRELOAD`, `NODE_OPTIONS`, `CODEMAN_*` keys - **File streaming TOCTOU protection**: `FileStreamManager` calls `realpathSync()` twice (at validation and before spawn) to catch symlink swaps ### SSE Event Categories @@ -269,9 +269,9 @@ The frontend is a single 16K-line vanilla JS file with these key systems: | File | Purpose | |------|---------| -| `~/.claudeman/state.json` | Sessions, settings, tokens, respawn config | -| `~/.claudeman/mux-sessions.json` | Tmux session metadata for recovery | -| `~/.claudeman/settings.json` | User preferences | +| `~/.codeman/state.json` | Sessions, settings, tokens, respawn config | +| `~/.codeman/mux-sessions.json` | Tmux session metadata for recovery | +| `~/.codeman/settings.json` | User preferences | ## Default Settings @@ -281,7 +281,7 @@ UI defaults are set in `src/web/public/app.js` using `??` fallbacks. To change d ## Testing -**CRITICAL: You are running inside a Claudeman-managed tmux session.** Never run `npx vitest run` (full suite) — it spawns/kills tmux sessions and will crash your own session. Instead: +**CRITICAL: You are running inside a Codeman-managed tmux session.** Never run `npx vitest run` (full suite) — it spawns/kills tmux sessions and will crash your own session. Instead: ```bash # Safe: run individual test files @@ -290,7 +290,7 @@ npx vitest run test/.test.ts # Safe: run tests matching a pattern npx vitest run -t "pattern" -# DANGEROUS from inside Claudeman — will kill your tmux session: +# DANGEROUS from inside Codeman — will kill your tmux session: # npx vitest run ← DON'T DO THIS ``` @@ -306,10 +306,10 @@ npx vitest run -t "pattern" ## 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: +When the user says "check the sc", "screenshot", or "sc", they mean uploaded screenshots from their mobile device. Screenshots are saved to `~/.codeman/screenshots/` and uploaded via `/upload.html` on the Codeman web UI. To view them, use the Read tool on the image files: ```bash -ls ~/.claudeman/screenshots/ # List uploaded screenshots +ls ~/.codeman/screenshots/ # List uploaded screenshots # Then use Read tool on individual files — Claude Code can view images natively ``` @@ -322,7 +322,7 @@ tmux list-sessions # List tmux sessions tmux attach-session -t # Attach (Ctrl+B D to detach) curl localhost:3000/api/sessions # Check sessions curl localhost:3000/api/status | jq # Full app state -cat ~/.claudeman/state.json | jq # View persisted state +cat ~/.codeman/state.json | jq # View persisted state curl localhost:3000/api/subagents # List background agents curl localhost:3000/api/sessions/:id/run-summary | jq # Session timeline ``` @@ -337,7 +337,7 @@ curl localhost:3000/api/sessions/:id/run-summary | jq # Session timeline | Respawn not triggering | Session settings → Respawn enabled? | Enable respawn, check idle timeout config | | Terminal blank on tab switch | Network tab for `/api/sessions/:id/buffer` | Check session exists, restart server | | Tests failing on session limits | `tmux list-sessions \| wc -l` | Clean up: `tmux list-sessions \| grep test \| awk -F: '{print $1}' \| xargs -I{} tmux kill-session -t {}` | -| State not persisting | `cat ~/.claudeman/state.json` | Check file permissions, disk space | +| State not persisting | `cat ~/.codeman/state.json` | Check file permissions, disk space | ## Performance Constraints @@ -352,7 +352,7 @@ The app must stay fast with 20 sessions and 50 agent windows: ## Terminal Anti-Flicker System -Claude Code uses Ink (React for terminals), which redraws the screen on every state change. Claudeman implements a 6-layer anti-flicker pipeline for smooth 60fps output: +Claude Code uses Ink (React for terminals), which redraws the screen on every state change. Codeman implements a 6-layer anti-flicker pipeline for smooth 60fps output: ``` PTY Output → Server Batching (16-50ms) → DEC 2026 Wrap → SSE → Client rAF → xterm.js @@ -395,14 +395,14 @@ Use `LRUMap` for bounded caches with eviction, `StaleExpirationMap` for TTL-base | **Terminal anti-flicker** | `docs/terminal-anti-flicker.md` | | **API routes** | `src/web/server.ts:buildServer()` or README.md (full endpoint tables) | | **SSE events** | Search `broadcast(` in `server.ts` | -| **CLI commands** | `claudeman --help` | +| **CLI commands** | `codeman --help` | | **Frontend patterns** | `src/web/public/app.js` (subagent windows, notifications) | | **Session statuses** | `SessionStatus` type in `src/types.ts` | | **Error codes** | `createErrorResponse()` in `src/types.ts` | | **Test utilities** | `test/respawn-test-utils.ts` | | **Memory leak patterns** | `test/memory-leak-prevention.test.ts` | | **Keyboard shortcuts** | README.md or App Settings in web UI | -| **Mobile/SSH access** | README.md (Claudeman Sessions / `sc` command) | +| **Mobile/SSH access** | README.md (Codeman Sessions / `sc` command) | | **Plan orchestrator** | `src/plan-orchestrator.ts` file header | | **Agent prompts** | `src/prompts/` directory | | **Agent Teams (experimental)** | `agent-teams/README.md`, `agent-teams/design.md` | @@ -444,7 +444,7 @@ Use `LRUMap` for bounded caches with eviction, `StaleExpirationMap` for TTL-base | `scripts/test-patterns.mjs` | Test file path link detection regex patterns | | `scripts/watch-subagents.ts` | Real-time subagent transcript watcher (list, follow by session/agent ID) | | `scripts/capture-readme-screenshots.mjs` | Capture screenshots for README | -| `scripts/claudeman-web.service` | systemd service file for production deployment | +| `scripts/codeman-web.service` | systemd service file for production deployment | ## Memory Leak Prevention @@ -464,7 +464,7 @@ Run `npx vitest run test/memory-leak-prevention.test.ts` to verify patterns. ## Common Workflows -**Investigating a bug**: Start dev server (`npx tsx src/index.ts web`), reproduce in browser, check terminal output and `~/.claudeman/state.json` for clues. +**Investigating a bug**: Start dev server (`npx tsx src/index.ts web`), reproduce in browser, check terminal output and `~/.codeman/state.json` for clues. **Adding a new API endpoint**: Define types in `types.ts`, add route in `server.ts:buildServer()`, broadcast SSE events if needed, handle in `app.js:handleSSEEvent()`. diff --git a/README.md b/README.md index db3b4acc..74e64087 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@

- Claudeman + Codeman

The missing control plane for Claude Code

@@ -17,7 +17,7 @@

- Claudeman — parallel subagent visualization + Codeman — parallel subagent visualization

--- @@ -25,19 +25,19 @@ ## Quick Start - Installation ```bash -curl -fsSL https://raw.githubusercontent.com/Ark0N/claudeman/master/install.sh | bash +curl -fsSL https://raw.githubusercontent.com/Ark0N/Codeman/master/install.sh | bash ``` -This installs Node.js, tmux, and Claude CLI if missing, clones Claudeman to `~/.claudeman/app`, builds it. After install: +This installs Node.js, tmux, and Claude CLI if missing, clones Codeman to `~/.codeman/app`, builds it. After install: ```bash -claudeman web +codeman web # Open http://localhost:3000 — press Ctrl+Enter to start your first session ``` **Update to latest version:** ```bash -curl -fsSL https://raw.githubusercontent.com/Ark0N/claudeman/master/install.sh | bash -s update +curl -fsSL https://raw.githubusercontent.com/Ark0N/Codeman/master/install.sh | bash -s update ```
@@ -45,12 +45,12 @@ curl -fsSL https://raw.githubusercontent.com/Ark0N/claudeman/master/install.sh | **Linux (systemd):** ```bash -mkdir -p ~/.config/systemd/user && printf '[Unit]\nDescription=Claudeman Web Server\nAfter=network.target\n\n[Service]\nType=simple\nExecStart=%s %s/dist/index.js web\nRestart=always\nRestartSec=10\n\n[Install]\nWantedBy=default.target\n' "$(which node)" "$HOME/.claudeman/app" > ~/.config/systemd/user/claudeman-web.service && systemctl --user daemon-reload && systemctl --user enable --now claudeman-web && loginctl enable-linger $USER +mkdir -p ~/.config/systemd/user && printf '[Unit]\nDescription=Codeman Web Server\nAfter=network.target\n\n[Service]\nType=simple\nExecStart=%s %s/dist/index.js web\nRestart=always\nRestartSec=10\n\n[Install]\nWantedBy=default.target\n' "$(which node)" "$HOME/.codeman/app" > ~/.config/systemd/user/codeman-web.service && systemctl --user daemon-reload && systemctl --user enable --now codeman-web && loginctl enable-linger $USER ``` **macOS (launchd):** ```bash -mkdir -p ~/Library/LaunchAgents && printf '\n\nLabelcom.claudeman.webProgramArguments%s%s/dist/index.jswebRunAtLoadKeepAliveStandardOutPath/tmp/claudeman.logStandardErrorPath/tmp/claudeman.log\n' "$(which node)" "$HOME/.claudeman/app" > ~/Library/LaunchAgents/com.claudeman.web.plist && launchctl load ~/Library/LaunchAgents/com.claudeman.web.plist +mkdir -p ~/Library/LaunchAgents && printf '\n\nLabelcom.codeman.webProgramArguments%s%s/dist/index.jswebRunAtLoadKeepAliveStandardOutPath/tmp/codeman.logStandardErrorPath/tmp/codeman.log\n' "$(which node)" "$HOME/.codeman/app" > ~/Library/LaunchAgents/com.codeman.web.plist && launchctl load ~/Library/LaunchAgents/com.codeman.web.plist ```
@@ -58,10 +58,10 @@ mkdir -p ~/Library/LaunchAgents && printf 'Windows (WSL) ```powershell -wsl bash -c "curl -fsSL https://raw.githubusercontent.com/Ark0N/claudeman/master/install.sh | bash" +wsl bash -c "curl -fsSL https://raw.githubusercontent.com/Ark0N/Codeman/master/install.sh | bash" ``` -Claudeman requires tmux, so Windows users need [WSL](https://learn.microsoft.com/en-us/windows/wsl/install). If you don't have WSL yet: run `wsl --install` in an admin PowerShell, reboot, open Ubuntu, then install Claude CLI inside WSL: `curl -fsSL https://claude.ai/install.sh | bash`. After installing, `http://localhost:3000` is accessible from your Windows browser. +Codeman requires tmux, so Windows users need [WSL](https://learn.microsoft.com/en-us/windows/wsl/install). If you don't have WSL yet: run `wsl --install` in an admin PowerShell, reboot, open Ubuntu, then install Claude CLI inside WSL: `curl -fsSL https://claude.ai/install.sh | bash`. After installing, `http://localhost:3000` is accessible from your Windows browser. --- @@ -74,7 +74,7 @@ The most responsive Claude Code experience on any phone. Full xterm.js terminal Mobile — keyboard open Terminal Apps -Claudeman Mobile +Codeman Mobile 200-300ms input lag over remoteLocal echo — instant feedback Tiny text, no contextFull xterm.js terminal @@ -94,7 +94,7 @@ The most responsive Claude Code experience on any phone. Full xterm.js terminal - **Native momentum scrolling** — `-webkit-overflow-scrolling: touch` for buttery scroll ```bash -claudeman web --https +codeman web --https # Open on your phone: https://:3000 ``` @@ -104,7 +104,7 @@ claudeman web --https ## Live Agent Visualization -Watch Claude's background agents work in real-time. Claudeman monitors every `Task` tool invocation and displays each agent in a draggable floating window with animated Matrix-style connection lines back to the parent session. +Watch Claude's background agents work in real-time. Codeman monitors every `Task` tool invocation and displays each agent in a draggable floating window with animated Matrix-style connection lines back to the parent session.

Subagent Visualization @@ -120,7 +120,7 @@ Watch Claude's background agents work in real-time. Claudeman monitors every `Ta ## Zero-Lag Input Overlay -When accessing Claude Code remotely (VPN, Tailscale, SSH tunnel), every keystroke normally takes 200-300ms to round-trip. Claudeman implements a **Mosh-inspired local echo system** that makes typing feel instant regardless of latency. +When accessing Claude Code remotely (VPN, Tailscale, SSH tunnel), every keystroke normally takes 200-300ms to round-trip. Codeman implements a **Mosh-inspired local echo system** that makes typing feel instant regardless of latency. A pixel-perfect DOM overlay inside xterm.js renders keystrokes at 0ms. Background forwarding silently sends every character to the PTY in 50ms debounced batches, so Tab completion, `Ctrl+R` history search, and all shell features work normally. When the server echo arrives 200-300ms later, the overlay seamlessly disappears and the real terminal text takes over — the transition is invisible. @@ -186,7 +186,7 @@ Click the chart icon on any session tab to see a timeline of everything that hap ### Zero-Flicker Terminal -Claude Code uses Ink (React for terminals) which redraws the entire screen on every state change. Claudeman implements a 6-layer anti-flicker pipeline for smooth 60fps output across all sessions: +Claude Code uses Ink (React for terminals) which redraws the entire screen on every state change. Codeman implements a 6-layer anti-flicker pipeline for smooth 60fps output across all sessions: ``` PTY Output → 16ms Server Batch → DEC 2026 Wrap → SSE → Client rAF → xterm.js (60fps) @@ -268,7 +268,7 @@ Single-digit selection (1-9), color-coded status, token counts, auto-refresh. De ```mermaid flowchart TB - subgraph Claudeman["CLAUDEMAN"] + subgraph Codeman["CODEMAN"] subgraph Frontend["Frontend Layer"] UI["Web UI
xterm.js + Agent Windows"] API["REST API
Fastify"] diff --git a/agent-teams/README.md b/agent-teams/README.md index 28c00c0b..037d4d6f 100644 --- a/agent-teams/README.md +++ b/agent-teams/README.md @@ -68,7 +68,7 @@ Note: Teammate transcripts appear in the **standard subagent directory** under t } ``` -Key fields: `agentId` format is `{name}@{teamName}`, `leadSessionId` links to Claudeman session, `backendType` indicates display mode, `color` for UI theming. +Key fields: `agentId` format is `{name}@{teamName}`, `leadSessionId` links to Codeman session, `backendType` indicates display mode, `color` for UI theming. ### Task file format (verified) @@ -122,7 +122,7 @@ Message types observed: **Teammates are IN-PROCESS THREADS, not separate OS processes.** -In `in-process` mode (the default), all teammates run as threads within the single `claude` process. Only 1 claude process exists per Claudeman session, regardless of team size. +In `in-process` mode (the default), all teammates run as threads within the single `claude` process. Only 1 claude process exists per Codeman session, regardless of team size. This means: - No separate PIDs to track per teammate @@ -138,7 +138,7 @@ This means: | **tmux** | `--teammate-mode tmux` | Split panes | tmux installed | | **iTerm2** | Auto-detected | Native split panes | iTerm2 + `it2` CLI | -**For Claudeman: use `in-process` only.** Claudeman manages its own tmux sessions externally. +**For Codeman: use `in-process` only.** Codeman manages its own tmux sessions externally. **In-process UI elements:** - Status bar: `@main @teammate1 @teammate2 ...` with `shift+↑ to expand` @@ -159,7 +159,7 @@ Fires when a task is being marked complete. - Exit code 0: Allow completion - Exit code 2: Prevent completion, send feedback -These are configured in `.claude/settings.local.json` alongside existing Claudeman hooks. +These are configured in `.claude/settings.local.json` alongside existing Codeman hooks. ## Subagent-Watcher Compatibility (Verified) @@ -168,7 +168,7 @@ These are configured in `.claude/settings.local.json` alongside existing Claudem ~/.claude/projects/{hash}/{leadSessionId}/subagents/agent-{id}.jsonl ``` -Claudeman's existing `subagent-watcher.ts` discovers them automatically. They appear in `/api/subagents` with status "active". +Codeman's existing `subagent-watcher.ts` discovers them automatically. They appear in `/api/subagents` with status "active". **Distinguishing teammates from regular subagents:** - Description field starts with ` Updated 2026-02-12 with experiment findings. See `experiment-log.md` for raw data. @@ -15,7 +15,7 @@ Monitors `~/.claude/teams/` for team creation/removal and tracks active teams. **Discovery mechanism:** - Poll `~/.claude/teams/` for directories (team names) every 3-5 seconds - When found: parse `config.json` to get: - - `leadSessionId` → map to Claudeman session + - `leadSessionId` → map to Codeman session - `members` array → teammate names, agentIds, colors, models - Watch for directory deletion (cleanup signal) @@ -25,7 +25,7 @@ Monitors `~/.claude/teams/` for team creation/removal and tracks active teams. - Teammate transcripts are at `subagents/agent-{id}.jsonl` (standard subagent path), NOT separate session transcripts **Association:** -- `config.json.leadSessionId` → Claudeman session ID (direct match!) +- `config.json.leadSessionId` → Codeman session ID (direct match!) - Each member's `agentId` (e.g., `fs-researcher@research-watchers`) → links to subagent files - `agentType: "team-lead"` vs `"general-purpose"` distinguishes lead from teammates @@ -37,7 +37,7 @@ Monitors `~/.claude/teams/` for team creation/removal and tracks active teams. ### 2. Team-Aware Idle Detection (HIGHEST PRIORITY) -**Problem (confirmed by experiment):** Lead session shows status "idle" in Claudeman while teammates are actively working. Token count continues climbing but Claudeman thinks the session is inactive. +**Problem (confirmed by experiment):** Lead session shows status "idle" in Codeman while teammates are actively working. Token count continues climbing but Codeman thinks the session is inactive. **Solution:** - Before declaring a session idle, check if it's a team lead @@ -125,7 +125,7 @@ Communication uses filesystem inbox files at `~/.claude/teams/{name}/inboxes/{te **Potential for interaction (not tested, future work):** - Write to teammate inbox files to inject messages - Must respect `.json.lock` directory locking protocol -- Could enable "nudge" or "redirect" functionality from Claudeman UI +- Could enable "nudge" or "redirect" functionality from Codeman UI ## Answered Questions (from experiment) @@ -161,7 +161,7 @@ Communication uses filesystem inbox files at `~/.claude/teams/{name}/inboxes/{te 3. **Teammate badge in subagent windows** — mark teammate subagents with name/color 4. **Team tasks API + UI** — `GET /api/sessions/:id/team-tasks` + task list panel 5. **Inbox monitoring** — watch inbox files, display message timeline -6. **TeammateIdle/TaskCompleted hooks** — add to Claudeman's hooks config generator +6. **TeammateIdle/TaskCompleted hooks** — add to Codeman's hooks config generator ## What We DON'T Need to Build diff --git a/agent-teams/experiment-log.md b/agent-teams/experiment-log.md index 29fc0c70..b609b04a 100644 --- a/agent-teams/experiment-log.md +++ b/agent-teams/experiment-log.md @@ -1,7 +1,7 @@ # Agent Teams Experiment Log > Experiment date: 2026-02-12 -> Test case: `~/claudeman-cases/agent-teams-test/` +> Test case: `~/codeman-cases/agent-teams-test/` > Team name: `research-watchers` > Teammates: 3 (fs-researcher, perf-researcher, api-researcher) > Lead session: `461daa80-94ec-4e5e-a1bb-0518f78311bc` @@ -56,7 +56,7 @@ Name the team research-watchers. Subagent transcripts also appear in the standard subagent directory: ``` -~/.claude/projects/-home-arkon-claudeman-cases-agent-teams-test/ +~/.claude/projects/-home-arkon-codeman-cases-agent-teams-test/ └── 461daa80.../ ├── 461daa80...jsonl # Lead session transcript └── subagents/ @@ -102,7 +102,7 @@ Key observations: - **File locking** via `.json.lock` directories (mkdir-based atomic lock, created then deleted) - Lead also has an inbox (`team-lead.json`) for receiving messages FROM teammates -**Implication for Claudeman:** We CAN intercept messages by watching inbox JSON files! We can also potentially inject messages by writing to inbox files. +**Implication for Codeman:** We CAN intercept messages by watching inbox JSON files! We can also potentially inject messages by writing to inbox files. --- @@ -119,7 +119,7 @@ Teammates create transcript files at: This is the **exact same path pattern** that regular Task tool subagents use. The existing `subagent-watcher.ts` successfully discovers them. -Claudeman's `/api/subagents` endpoint returned them with status "active": +Codeman's `/api/subagents` endpoint returned them with status "active": ``` Agent: ae50544 Status: active Tools: 8 Model: claude-opus-4-6 Desc: - Claudeman + Codeman diff --git a/docs/local-echo-overlay-plan.md b/docs/local-echo-overlay-plan.md index 96955c23..2f9e9ac1 100644 --- a/docs/local-echo-overlay-plan.md +++ b/docs/local-echo-overlay-plan.md @@ -2,7 +2,7 @@ ## Context -User accesses Claudeman remotely from Thailand to Switzerland over Tailscale (~200-300ms RTT). +User accesses Codeman remotely from Thailand to Switzerland over Tailscale (~200-300ms RTT). Every keystroke is invisible for 200-300ms before the server echoes it back. This makes typing painfully slow on mobile. Previous attempts to write directly to xterm.js buffer failed because Ink (Claude Code's terminal framework) does full-screen redraws that corrupt injected characters. diff --git a/docs/opencode-integration.md b/docs/opencode-integration.md index 362417e0..fd683a7b 100644 --- a/docs/opencode-integration.md +++ b/docs/opencode-integration.md @@ -1,4 +1,4 @@ -# OpenCode Integration Plan for Claudeman +# OpenCode Integration Plan for Codeman > **Author**: Claude Opus 4.6 | **Date**: 2026-02-26 > **Status**: Draft — Re-reviewed, MVP scope finalized. NOT pushed to GitHub @@ -36,13 +36,13 @@ 23. [Appendix A: OpenCode CLI Reference](#appendix-a-opencode-cli-reference) 24. [Appendix B: OpenCode Plugin Events](#appendix-b-opencode-plugin-events) 25. [Appendix C: OpenCode Permission Config](#appendix-c-opencode-permission-config) -26. [Appendix D: Current Claudeman Session Spawn Flow (Annotated)](#appendix-d-current-claudeman-session-spawn-flow-annotated) +26. [Appendix D: Current Codeman Session Spawn Flow (Annotated)](#appendix-d-current-codeman-session-spawn-flow-annotated) --- ## 1. Executive Summary -This plan details how to integrate [OpenCode](https://opencode.ai) — the popular open-source AI coding CLI (111k+ GitHub stars, 75+ model providers) — into Claudeman as a first-class session type alongside Claude Code and shell sessions. +This plan details how to integrate [OpenCode](https://opencode.ai) — the popular open-source AI coding CLI (111k+ GitHub stars, 75+ model providers) — into Codeman as a first-class session type alongside Claude Code and shell sessions. ### Core Approach @@ -53,7 +53,7 @@ Extend the existing `SessionMode` type from `'claude' | 'shell'` to `'claude' | | Strategy | Approach | Complexity | Value | |----------|----------|------------|-------| | **A: TUI-in-tmux** | Spawn `opencode` CLI in tmux, render in xterm.js | Medium | Full visual parity with Claude Code | -| **B: Server API bridge** | Run `opencode serve` + proxy its API through Claudeman | High | Structured data, session control, token tracking | +| **B: Server API bridge** | Run `opencode serve` + proxy its API through Codeman | High | Structured data, session control, token tracking | **Recommended path**: Start with Strategy A (TUI-in-tmux) since it mirrors the existing Claude Code pattern exactly. Then layer Strategy B on top for advanced features like structured token tracking and model switching. @@ -71,7 +71,7 @@ Extend the existing `SessionMode` type from `'claude' | 'shell'` to `'claude' | > | **Hooks plugin bridge** | Plugin event names are speculative/unverified. Requires Phase 0 validation that hasn't happened. | Phase 0 plugin verification | > | **AI idle checker** | Spawns `claude -p` for analysis. Won't work if only OpenCode is installed. | Claude CLI availability or `opencode run` fallback | > -> **What ships in the MVP**: Phases 0-3 (spawn in tmux, render in xterm.js) + Phase 5 (API routes, mode selector, tab badges, create/kill sessions). Users can interact with OpenCode manually — type prompts, see output, manage sessions from the Claudeman web UI. This alone is the core value: multi-model AI sessions in one management interface. +> **What ships in the MVP**: Phases 0-3 (spawn in tmux, render in xterm.js) + Phase 5 (API routes, mode selector, tab badges, create/kill sessions). Users can interact with OpenCode manually — type prompts, see output, manage sessions from the Codeman web UI. This alone is the core value: multi-model AI sessions in one management interface. ### Why OpenCode? @@ -79,7 +79,7 @@ Extend the existing `SessionMode` type from `'claude' | 'shell'` to `'claude' | - **Privacy-first**: Can run fully local via Ollama — no code ever leaves the machine - **Open source**: MIT licensed, active community (700+ contributors) - **Client/server**: Built-in `opencode serve` mode enables richer programmatic integration -- **Plugin system**: JS/TS plugins with rich event hooks (including `session.idle` — perfect for Claudeman) +- **Plugin system**: JS/TS plugins with rich event hooks (including `session.idle` — perfect for Codeman) --- @@ -222,7 +222,7 @@ OPENCODE_CLIENT=... # Client identifier (default: "cli") ## 3. Architecture Comparison: Claude Code vs OpenCode -### Current Claudeman Session Flow (Claude Code) +### Current Codeman Session Flow (Claude Code) ``` POST /api/sessions → new Session({mode: 'claude', mux: TmuxManager}) @@ -230,10 +230,10 @@ POST /api/sessions/:id/interactive → session.startInteractive() ↓ TmuxManager.createSession() ↓ - tmux new-session -ds "claudeman-" + tmux new-session -ds "codeman-" tmux respawn-pane -k -t ... "claude --dangerously-skip-permissions --session-id " ↓ - pty.spawn('tmux', ['attach-session', '-t', 'claudeman-']) + pty.spawn('tmux', ['attach-session', '-t', 'codeman-']) ↓ ptyProcess.onData() → emit('terminal') → SSE broadcast → xterm.js ``` @@ -246,10 +246,10 @@ POST /api/sessions/:id/interactive → session.startInteractive() ↓ TmuxManager.createSession() ↓ - tmux new-session -ds "claudeman-" + tmux new-session -ds "codeman-" tmux respawn-pane -k -t ... "opencode --model " ↓ - pty.spawn('tmux', ['attach-session', '-t', 'claudeman-']) + pty.spawn('tmux', ['attach-session', '-t', 'codeman-']) ↓ ptyProcess.onData() → emit('terminal') → SSE broadcast → xterm.js ``` @@ -268,7 +268,7 @@ Strategy A (TUI-in-tmux) for terminal rendering + opencode serve (background, port 4096+N) ↓ -Claudeman proxy routes → GET /session/current, POST /session/message, SSE /events +Codeman proxy routes → GET /session/current, POST /session/message, SSE /events ↓ Structured data for: token tracking, session management, model switching ``` @@ -301,7 +301,7 @@ These systems work identically for OpenCode sessions: - Terminal data streaming via `ptyProcess.onData()` - SSE event broadcasting via `broadcast()` - xterm.js terminal rendering in the browser -- State persistence to `~/.claudeman/state.json` +- State persistence to `~/.codeman/state.json` - Session CRUD API routes (create, get, delete) - Tab management in frontend - Session kill/cleanup logic (`TmuxManager.killSession()`) @@ -324,7 +324,7 @@ These systems work identically for OpenCode sessions: | Subagent detection | `BashToolParser` + `SubagentWatcher` | Different tool output format | DEFERRED | | Ralph completion | `PHRASE` tags | Not applicable (needs alternative) | DEFERRED | | Hooks events | `permission_prompt`, `idle_prompt`, `stop` | `permission.asked`, `session.idle`, `session.status` | DEFERRED | -| Auto-compact | Claudeman sends `/compact` at token threshold | OpenCode has built-in `compaction.auto: true` | DEFERRED | +| Auto-compact | Codeman sends `/compact` at token threshold | OpenCode has built-in `compaction.auto: true` | DEFERRED | --- @@ -346,7 +346,7 @@ opencode --version # 3. Test interactive TUI opencode -# 4. Test in tmux (simulating Claudeman's spawn pattern) +# 4. Test in tmux (simulating Codeman's spawn pattern) tmux new-session -ds "test-opencode" -c /tmp -x 120 -y 40 tmux set-option -t "test-opencode" remain-on-exit on tmux respawn-pane -k -t "test-opencode" 'opencode --model anthropic/claude-sonnet-4-5' @@ -774,10 +774,10 @@ function buildEnvExports(mode: string, sessionId: string, muxName: string, openC `export LANG=en_US.UTF-8`, `export LC_ALL=en_US.UTF-8`, `unset COLORTERM`, // Prevent color issues in tmux - `export CLAUDEMAN_MUX=1`, - `export CLAUDEMAN_SESSION_ID=${sessionId}`, - `export CLAUDEMAN_MUX_NAME=${muxName}`, - `export CLAUDEMAN_API_URL=${process.env.CLAUDEMAN_API_URL || 'http://localhost:3000'}`, + `export CODEMAN_MUX=1`, + `export CODEMAN_SESSION_ID=${sessionId}`, + `export CODEMAN_MUX_NAME=${muxName}`, + `export CODEMAN_API_URL=${process.env.CODEMAN_API_URL || 'http://localhost:3000'}`, ]; if (mode === 'opencode') { @@ -905,7 +905,7 @@ const mode = cmd.includes('opencode') ? 'opencode' : 'claude'; ### Known Limitations (from review) -> **[REVIEW P1-6]** OpenCode does not have `--session-id ` for initial session creation (only `--session ` for continuing existing sessions). This means: +> **[REVIEW P1-6]** OpenCode does not have `--session-id ` for initial session creation (only `--session ` for continuing existing sessions). This means: > - `_claudeSessionId = this.id` correlation (session.ts:405) won't work for OpenCode > - Subagent-session correlation via Session ID matching won't work > - Transcript watching via Claude session ID path won't work @@ -1121,7 +1121,7 @@ private parseTokens(data: string): void { ### Working/Idle State Tracking -For Claude, Claudeman uses spinner characters and keywords. For OpenCode: +For Claude, Codeman uses spinner characters and keywords. For OpenCode: > **[REVIEW]** The original logic had a bug: `Date.now() - this._lastActivityAt > 100` is checked AFTER setting `_lastActivityAt = Date.now()`, so the condition would never be true (0 > 100 = false). Fixed below. @@ -1373,7 +1373,7 @@ if (session.mode === 'claude' && session.pid) { > **[REVIEW C3] Phase reordered**: This was originally Phase 7 but has been moved before Respawn. The plugin bridge provides the reliable `session.idle` event that the respawn controller needs. Without it, respawn relies on output-silence-only detection, which is unreliable with Bubble Tea TUIs (see Review C1). **Do not implement respawn (Phase 7) until this phase is complete and tested.** ### Goal -Bridge Claudeman's hook system with OpenCode's plugin system for rich event forwarding. +Bridge Codeman's hook system with OpenCode's plugin system for rich event forwarding. ### Background: Two Different Approaches @@ -1383,19 +1383,19 @@ Bridge Claudeman's hook system with OpenCode's plugin system for rich event forw | Trigger | Hook name matches event type | Event name subscription | | Key events | `stop`, `idle_prompt`, `permission_prompt`, `elicitation_dialog` | `session.idle`, `permission.asked`, `session.status` | | Communication | Exit codes + environment variables | Function context + return values | -| Install | Auto-generated by Claudeman | Must be placed in `.opencode/plugins/` | +| Install | Auto-generated by Codeman | Must be placed in `.opencode/plugins/` | -### Claudeman Plugin for OpenCode +### Codeman Plugin for OpenCode -Create a Claudeman plugin that OpenCode loads, which communicates back to Claudeman's API: +Create a Codeman plugin that OpenCode loads, which communicates back to Codeman's API: -**File: `.opencode/plugins/claudeman-bridge.js`** (generated per session) +**File: `.opencode/plugins/codeman-bridge.js`** (generated per session) ```javascript -// This plugin bridges OpenCode events to Claudeman's API -export const claudemanBridge = async ({ project, $ }) => { - const apiUrl = process.env.CLAUDEMAN_API_URL || 'http://localhost:3000'; - const sessionId = process.env.CLAUDEMAN_SESSION_ID; +// This plugin bridges OpenCode events to Codeman's API +export const codemanBridge = async ({ project, $ }) => { + const apiUrl = process.env.CODEMAN_API_URL || 'http://localhost:3000'; + const sessionId = process.env.CODEMAN_SESSION_ID; if (!sessionId) return {}; @@ -1440,7 +1440,7 @@ export const claudemanBridge = async ({ project, $ }) => { ### Plugin Installation -When creating an OpenCode session, Claudeman generates this plugin in the project's `.opencode/plugins/` directory: +When creating an OpenCode session, Codeman generates this plugin in the project's `.opencode/plugins/` directory: ```typescript // In session.ts or a new opencode-hooks.ts: @@ -1448,8 +1448,8 @@ async function installOpenCodePlugin(workingDir: string, sessionId: string): Pro const pluginDir = join(workingDir, '.opencode', 'plugins'); await mkdirp(pluginDir); - const pluginContent = generateClaudemanBridgePlugin(sessionId); - await writeFile(join(pluginDir, 'claudeman-bridge.js'), pluginContent); + const pluginContent = generateCodemanBridgePlugin(sessionId); + await writeFile(join(pluginDir, 'codeman-bridge.js'), pluginContent); } ``` @@ -1458,7 +1458,7 @@ async function installOpenCodePlugin(workingDir: string, sessionId: string): Pro > **[REVIEW]** Add `session.compacted` to the plugin bridge — it's free and useful for tracking when OpenCode auto-compacts (relevant for token tracking and respawn timing). ```javascript -// Add to claudeman-bridge.js return object: +// Add to codeman-bridge.js return object: 'session.compacted': async (info) => { await notifyClademan('session_compacted', { info }); }, @@ -1472,12 +1472,12 @@ async function installOpenCodePlugin(workingDir: string, sessionId: string): Pro ### Benefits of the Plugin Bridge -Once installed, Claudeman receives structured events from OpenCode: +Once installed, Codeman receives structured events from OpenCode: - **`session.idle`** → Definitive idle detection (replaces output-silence guessing) -- **`permission.asked`** → Show permission prompts in Claudeman UI +- **`permission.asked`** → Show permission prompts in Codeman UI - **`tool.execute.*`** → Tool call tracking (similar to BashToolParser for Claude) -- **`todo.updated`** → OpenCode's built-in todo system → Claudeman can display it -- **`session.error`** → Error surfacing in Claudeman UI +- **`todo.updated`** → OpenCode's built-in todo system → Codeman can display it +- **`session.error`** → Error surfacing in Codeman UI - **`session.compacted`** → Track auto-compaction events --- @@ -1664,7 +1664,7 @@ tmux session ─── opencode TUI (interactive, port N/A) │ ├── xterm.js (terminal rendering, Strategy A) │ -Claudeman ──── opencode serve (port 4096+N, background process) +Codeman ──── opencode serve (port 4096+N, background process) │ ├── GET /session/* → structured session data ├── POST /session/message → send prompt programmatically @@ -1678,7 +1678,7 @@ Claudeman ──── opencode serve (port 4096+N, background process) > **[REVIEW M8]** Running both `opencode` (TUI) and `opencode serve` in the same project directory creates a **shared SQLite state problem**. The TUI creates sessions in SQLite; the server reads from the same SQLite. But they're separate processes — there's no guarantee of session ID consistency between them. > > **Consider alternatives**: -> - (a) Use `opencode serve` INSTEAD of the TUI (not alongside it) — server becomes the single backend, Claudeman renders its own UI +> - (a) Use `opencode serve` INSTEAD of the TUI (not alongside it) — server becomes the single backend, Codeman renders its own UI > - (b) Use `opencode attach` to connect the TUI to the server, making the server the single source of truth > - (c) Accept the dual-process model with explicit documentation of limitations > @@ -1805,7 +1805,7 @@ if (this.mode === 'opencode' && this._openCodeConfig?.serverPort) { |------|---------|-------|--------| | `src/utils/ansi-content-filter.ts` | Strip cosmetic ANSI sequences for idle detection | 4 | DEFERRED | | `src/completion-detector.ts` | `CompletionDetector` interface + implementations | 7 | DEFERRED | -| `src/opencode-plugin-generator.ts` | Generate `.opencode/plugins/claudeman-bridge.js` | 6 | DEFERRED | +| `src/opencode-plugin-generator.ts` | Generate `.opencode/plugins/codeman-bridge.js` | 6 | DEFERRED | | `src/opencode-api-client.ts` | Client for OpenCode's REST API (Strategy B) | 8 | DEFERRED | | `test/opencode-respawn.test.ts` | Tests for OpenCode respawn cycle (port 3156) | 7 | DEFERRED | | `test/ansi-content-filter.test.ts` | Tests for ANSI content filter | 4 | DEFERRED | @@ -1898,7 +1898,7 @@ npx vitest run test/opencode-respawn.test.ts ### Safety Rules -- **Never run OpenCode tests that spawn real tmux sessions inside Claudeman** (same safety rule as Claude tests) +- **Never run OpenCode tests that spawn real tmux sessions inside Codeman** (same safety rule as Claude tests) - **Use MockSession** from `test/respawn-test-utils.ts` for respawn testing - **Mock the opencode binary** for unit tests (`jest.mock` or stub) - **Use unique test ports** (3155+) — never port 3000 @@ -1939,12 +1939,12 @@ npx vitest run test/opencode-respawn.test.ts 5. **Should we auto-generate `opencode.json` in the working directory?** - Option A: Let OpenCode use existing project config (respect user settings) - - Option B: Generate a temporary one with Claudeman's settings - - Recommendation: Option A (use `OPENCODE_CONFIG_CONTENT` env var for Claudeman-specific overrides, don't modify project files) + - Option B: Generate a temporary one with Codeman's settings + - Recommendation: Option A (use `OPENCODE_CONFIG_CONTENT` env var for Codeman-specific overrides, don't modify project files) -6. **How should OpenCode session IDs map to Claudeman session IDs?** +6. **How should OpenCode session IDs map to Codeman session IDs?** - OpenCode manages its own sessions (SQLite DB) - - We could pass `--session ` but OpenCode IDs have different format + - We could pass `--session ` but OpenCode IDs have different format - Recommendation: Let OpenCode manage its own sessions, store the mapping in SessionState --- @@ -1970,7 +1970,7 @@ Phase 3: Tmux spawn (2-3 hours) ← CRITICAL INTEGRATION POINT ↓ Phase 5: API + frontend (2-3 hours) ← FIRST USER-VISIBLE RESULT ↓ - ✅ MVP COMPLETE — OpenCode sessions managed from Claudeman web UI + ✅ MVP COMPLETE — OpenCode sessions managed from Codeman web UI ═══════════════════════════════════════════════════════ DEFERRED (requires real PTY data + verified APIs) @@ -1991,7 +1991,7 @@ Phase 8: Server API — DEFERRED, optional advanced feature | Milestone | Phase | What You Can Do | Scope | |-----------|-------|-----------------|-------| -| **M1: "It renders"** | 0-3 | OpenCode TUI visible in xterm.js via Claudeman | **MVP** | +| **M1: "It renders"** | 0-3 | OpenCode TUI visible in xterm.js via Codeman | **MVP** | | **M2: "It's usable"** | 5 | Create OpenCode sessions from web UI, type and interact, manage tabs | **MVP** | | **M3: "It's observable"** | 4 | Idle/working state detection, ANSI content filter | Deferred | | **M4: "It's smart"** | 6 | Plugin bridge provides definitive idle/permission/tool events | Deferred | @@ -2012,7 +2012,7 @@ Phase 8: Server API — DEFERRED, optional advanced feature ## 21. Review Findings -> **Reviewed**: 2026-02-26 by a 4-agent team. Each agent reviewed a different area of the plan against the actual Claudeman codebase. +> **Reviewed**: 2026-02-26 by a 4-agent team. Each agent reviewed a different area of the plan against the actual Codeman codebase. ### Review Team @@ -2182,7 +2182,7 @@ Environment Variables: Full list of subscribable events in OpenCode's plugin system: -| Category | Event | Description | Claudeman Relevance | +| Category | Event | Description | Codeman Relevance | |----------|-------|-------------|---------------------| | **Command** | `command.executed` | Slash command run | Low | | **Files** | `file.edited` | File modified | Medium (track changes) | @@ -2194,7 +2194,7 @@ Full list of subscribable events in OpenCode's plugin system: | | `message.updated` | Complete message | High (completion detection) | | | `message.removed` | Message deleted | Low | | | `message.part.removed` | Part deleted | Low | -| **Permissions** | `permission.asked` | Tool approval needed | **Critical** (show in Claudeman) | +| **Permissions** | `permission.asked` | Tool approval needed | **Critical** (show in Codeman) | | | `permission.replied` | User responded | High (track approvals) | | **Server** | `server.connected` | Server started | Medium | | **Sessions** | `session.idle` | Agent finished working | **Critical** (idle detection!) | @@ -2254,7 +2254,7 @@ Full list of subscribable events in OpenCode's plugin system: - `"ask"` — Prompt user for approval - `"deny"` — Block the action -### Delivery Method for Claudeman +### Delivery Method for Codeman Use `OPENCODE_CONFIG_CONTENT` environment variable to inject permissions without modifying project files: @@ -2265,7 +2265,7 @@ opencode --model anthropic/claude-sonnet-4-5 --- -## Appendix D: Current Claudeman Session Spawn Flow (Annotated) +## Appendix D: Current Codeman Session Spawn Flow (Annotated) ### Exact Code Path (for reference during implementation) @@ -2285,15 +2285,15 @@ opencode --model anthropic/claude-sonnet-4-5 → If none: this._mux.createSession(id, workingDir, 'claude', ...) 4. TmuxManager.createSession() (tmux-manager.ts:225) - → tmux new-session -ds "claudeman-" -c -x 120 -y 40 - → tmux set-option -t "claudeman-" remain-on-exit on + → tmux new-session -ds "codeman-" -c -x 120 -y 40 + → tmux set-option -t "codeman-" remain-on-exit on → Build command: "export PATH=... && export LANG=... && claude --dangerously-skip-permissions --session-id " - → tmux respawn-pane -k -t "claudeman-" '' + → tmux respawn-pane -k -t "codeman-" '' → Wait 100ms, configure tmux, get PID → Return MuxSession { muxName, pid, mode } 5. Back in startInteractive() (session.ts:~950) - → pty.spawn('tmux', ['attach-session', '-t', 'claudeman-'], { + → pty.spawn('tmux', ['attach-session', '-t', 'codeman-'], { name: 'xterm-256color', cols: 120, rows: 40, env: { LANG, LC_ALL, TERM } diff --git a/docs/perf-audit-first-load.md b/docs/perf-audit-first-load.md index 50357b7b..62b231d9 100644 --- a/docs/perf-audit-first-load.md +++ b/docs/perf-audit-first-load.md @@ -1,7 +1,7 @@ # Performance Audit: First Page Load **Date**: 2026-02-18 -**Scope**: Browser first-load of Claudeman web UI (`/`) +**Scope**: Browser first-load of Codeman web UI (`/`) **Method**: Static analysis by 4 parallel audit agents (server, frontend, SSE/xterm, asset pipeline) --- @@ -40,7 +40,7 @@ Browser hits / │ │ [FIRST PAINT blocked until ALL CSS downloaded + parsed] │ -├── JS executes: new ClaudemanApp().init() +├── JS executes: new CodemanApp().init() │ ├── initTerminal() ................... (SYNC: new Terminal() + terminal.open() → canvas creation) │ ├── connectSSE() → /api/events ....... (SSE → fires 'init' with getLightState()) │ ├── loadState() → /api/status ........ (DUPLICATE #1: same data as SSE init!) diff --git a/docs/performance-investigation-report.md b/docs/performance-investigation-report.md index 74dc122c..17abb184 100644 --- a/docs/performance-investigation-report.md +++ b/docs/performance-investigation-report.md @@ -1,14 +1,14 @@ -# Claudeman Performance Investigation Report +# Codeman Performance Investigation Report **Date**: 2026-02-20 -**Scope**: Why Claudeman feels sluggish when multiple Claude tabs are very busy +**Scope**: Why Codeman feels sluggish when multiple Claude tabs are very busy **Method**: 4-agent parallel analysis of server, PTY pipeline, frontend, and background systems --- ## Executive Summary -When multiple Claude sessions are actively producing heavy terminal output (e.g., building, writing files, running tests), Claudeman's UI becomes sluggish. This investigation identified **14 bottlenecks** across 4 layers of the stack. The root cause is **cumulative event loop blocking** — no single operation is catastrophically slow, but dozens of small synchronous operations run on every PTY data chunk, and with N busy sessions producing chunks every few milliseconds, the event loop gets saturated. +When multiple Claude sessions are actively producing heavy terminal output (e.g., building, writing files, running tests), Codeman's UI becomes sluggish. This investigation identified **14 bottlenecks** across 4 layers of the stack. The root cause is **cumulative event loop blocking** — no single operation is catastrophically slow, but dozens of small synchronous operations run on every PTY data chunk, and with N busy sessions producing chunks every few milliseconds, the event loop gets saturated. The most impactful findings are ranked by severity below. diff --git a/docs/plan-improvement-roadmap.md b/docs/plan-improvement-roadmap.md index 56d0bcca..9b933641 100644 --- a/docs/plan-improvement-roadmap.md +++ b/docs/plan-improvement-roadmap.md @@ -244,4 +244,4 @@ At iterations 5, 10, 20, 30, 50: --- -*This document is part of the Claudeman project. See [CLAUDE.md](../CLAUDE.md) for main documentation.* +*This document is part of the Codeman project. See [CLAUDE.md](../CLAUDE.md) for main documentation.* diff --git a/docs/ralph-improvement-plan.md b/docs/ralph-improvement-plan.md index dda795e5..9fd0bbb7 100644 --- a/docs/ralph-improvement-plan.md +++ b/docs/ralph-improvement-plan.md @@ -2,7 +2,7 @@ ## Overview -This plan details improvements to Claudeman's Ralph Loop system based on best practices from the Ralph Claude Code repository (https://github.com/frankbria/ralph-claude-code). +This plan details improvements to Codeman's Ralph Loop system based on best practices from the Ralph Claude Code repository (https://github.com/frankbria/ralph-claude-code). ## Key Concepts to Implement @@ -181,7 +181,7 @@ Three states: CLOSED → HALF_OPEN → OPEN ### 3.1 Template Library - Bug Fix, Feature, Refactoring, Test Coverage, Documentation templates - Template selector in wizard -- Custom templates in `~/.claudeman/templates/` +- Custom templates in `~/.codeman/templates/` ### 3.2 Tool Permissions - Configure allowed Claude tools per loop diff --git a/docs/ralph-wiggum-guide.md b/docs/ralph-wiggum-guide.md index 1156d9c9..fd3cbcb7 100644 --- a/docs/ralph-wiggum-guide.md +++ b/docs/ralph-wiggum-guide.md @@ -19,7 +19,7 @@ 8. [Prompt Templates](#prompt-templates) 9. [When to Use (and Not Use)](#when-to-use-and-not-use) 10. [Real-World Examples](#real-world-examples) -11. [Claudeman Implementation](#claudeman-implementation) +11. [Codeman Implementation](#codeman-implementation) 12. [Troubleshooting](#troubleshooting) --- @@ -148,18 +148,18 @@ The completion phrase pattern is the core contract between Claude and the loop s ### False Positive Prevention -The official implementation (and Claudeman) prevents false positives when completion phrases appear in: +The official implementation (and Codeman) prevents false positives when completion phrases appear in: - Initial prompts - Documentation or examples - Comments -**Solution**: Claudeman uses **occurrence-based detection** to distinguish prompts from actual completions: +**Solution**: Codeman uses **occurrence-based detection** to distinguish prompts from actual completions: - **1st occurrence**: Store as expected phrase (likely in the prompt) - **2nd occurrence**: Emit `completionDetected` (actual completion) - **If loop already active**: Emit immediately (explicit loop start via `/ralph-loop:ralph-loop`) ```typescript -// From claudeman/src/ralph-tracker.ts +// From codeman/src/ralph-tracker.ts private handleCompletionPhrase(phrase: string): void { const count = (this._completionPhraseCount.get(phrase) || 0) + 1; this._completionPhraseCount.set(phrase, count); @@ -631,9 +631,9 @@ Ask yourself: --- -## Claudeman Implementation +## Codeman Implementation -Claudeman implements Ralph Wiggum tracking via the `RalphTracker` class in `src/ralph-tracker.ts`. +Codeman implements Ralph Wiggum tracking via the `RalphTracker` class in `src/ralph-tracker.ts`. ### Auto-Detection Patterns @@ -833,7 +833,7 @@ POST /api/sessions/:id/auto-clear - [Claude Fast - Autonomous Agent Loops](https://claudefa.st/blog/guide/mechanics/autonomous-agent-loops) - [DeepWiki - Ralph Loop](https://deepwiki.com/anthropics/claude-plugins-official/5.2.2-ralph-loop) -### Related Claudeman Files +### Related Codeman Files - `src/ralph-tracker.ts` - Core detection engine - `src/ralph-loop.ts` - Task orchestration - `src/respawn-controller.ts` - Session cycling @@ -843,4 +843,4 @@ POST /api/sessions/:id/auto-clear --- -*This documentation is maintained as part of the Claudeman project. For updates, see the main [CLAUDE.md](../CLAUDE.md).* +*This documentation is maintained as part of the Codeman project. For updates, see the main [CLAUDE.md](../CLAUDE.md).* diff --git a/docs/reports/notification-audit-summary.md b/docs/reports/notification-audit-summary.md index b74b4d40..75470808 100644 --- a/docs/reports/notification-audit-summary.md +++ b/docs/reports/notification-audit-summary.md @@ -4,7 +4,7 @@ Date: 2026-02-17 ## Scope -Full audit of the Claudeman notification system covering: +Full audit of the Codeman notification system covering: - Backend event pipeline (server.ts, hooks-config.ts, team-watcher.ts, subagent-watcher.ts) - Frontend notification manager (app.js NotificationManager class, 4-layer architecture) - Settings UI and persistence (localStorage + server backup) diff --git a/docs/reports/notification-backend.md b/docs/reports/notification-backend.md index 203c6f2a..42e108aa 100644 --- a/docs/reports/notification-backend.md +++ b/docs/reports/notification-backend.md @@ -1,10 +1,10 @@ -# Claudeman Notification System - Backend Research Report +# Codeman Notification System - Backend Research Report Date: 2026-02-17 ## Executive Summary -The Claudeman notification system is a **multi-layer, event-driven pipeline** that flows from backend event emitters, through SSE broadcasts, to a frontend `NotificationManager` class. The backend itself has no concept of "notifications" -- it broadcasts structured SSE events, and the frontend decides which events warrant user notification (browser notifications, audio alerts, tab title flashing, in-app notification drawer, tab alert badges). +The Codeman notification system is a **multi-layer, event-driven pipeline** that flows from backend event emitters, through SSE broadcasts, to a frontend `NotificationManager` class. The backend itself has no concept of "notifications" -- it broadcasts structured SSE events, and the frontend decides which events warrant user notification (browser notifications, audio alerts, tab title flashing, in-app notification drawer, tab alert badges). The system handles ~25 distinct notification-triggering SSE events across 5 categories: hook events, session lifecycle, respawn state machine, Ralph Loop, and UI actions. @@ -96,14 +96,14 @@ Terminal and output data use separate batching pipelines that bypass `broadcast( ### 2.1 Hook Configuration Generator (Lines 24-67) -The `generateHooksConfig()` function creates `.claude/settings.local.json` entries that make Claude Code POST to Claudeman when hooks fire: +The `generateHooksConfig()` function creates `.claude/settings.local.json` entries that make Claude Code POST to Codeman when hooks fire: ```typescript const curlCmd = (event: HookEventType) => `HOOK_DATA=$(cat 2>/dev/null || echo '{}'); ` + - `curl -s -X POST "$CLAUDEMAN_API_URL/api/hook-event" ` + + `curl -s -X POST "$CODEMAN_API_URL/api/hook-event" ` + `-H 'Content-Type: application/json' ` + - `-d "{\\"event\\":\\"${event}\\",\\"sessionId\\":\\"$CLAUDEMAN_SESSION_ID\\",\\"data\\":$HOOK_DATA}" ` + + `-d "{\\"event\\":\\"${event}\\",\\"sessionId\\":\\"$CODEMAN_SESSION_ID\\",\\"data\\":$HOOK_DATA}" ` + `2>/dev/null || true`; ``` @@ -143,8 +143,8 @@ The `sanitizeHookData()` function limits what gets broadcast: ### 2.4 Environment Variables (Lines 70-101) Two env vars are set per case directory via `updateCaseEnvVars()`: -- `CLAUDEMAN_API_URL` -- server URL (e.g., `http://localhost:3000`) -- `CLAUDEMAN_SESSION_ID` -- session identifier +- `CODEMAN_API_URL` -- server URL (e.g., `http://localhost:3000`) +- `CODEMAN_SESSION_ID` -- session identifier These are resolved at runtime by the shell, so the hook config is static per case. diff --git a/docs/reports/notification-blinking.md b/docs/reports/notification-blinking.md index 4c9f5224..42902031 100644 --- a/docs/reports/notification-blinking.md +++ b/docs/reports/notification-blinking.md @@ -2,7 +2,7 @@ ## Overview -Claudeman implements a **4-layer notification system** managed by the `NotificationManager` class (app.js lines 860-1265). The layers are: +Codeman implements a **4-layer notification system** managed by the `NotificationManager` class (app.js lines 860-1265). The layers are: 1. **In-app notification drawer** (Layer 1) - badge + list UI 2. **Document title flashing** (Layer 2) - tab title blinks when hidden @@ -32,19 +32,19 @@ updateTabTitle() { this.titleFlashInterval = setInterval(() => { this.titleFlashState = !this.titleFlashState; document.title = this.titleFlashState - ? `\u26A0\uFE0F (${this.unreadCount}) Claudeman` + ? `\u26A0\uFE0F (${this.unreadCount}) Codeman` : this.originalTitle; }, TITLE_FLASH_INTERVAL_MS); // Set immediately - document.title = `\u26A0\uFE0F (${this.unreadCount}) Claudeman`; + document.title = `\u26A0\uFE0F (${this.unreadCount}) Codeman`; } } } ``` The title alternates between: -- Warning emoji + unread count: `"(3) Claudeman"` -- Original title: `"Claudeman"` +- Warning emoji + unread count: `"(3) Codeman"` +- Original title: `"Codeman"` ### What Triggers It Title flashing starts when `notify()` is called **while the tab is not visible** (`!this.isTabVisible`). The check is at lines 1026-1028: @@ -126,7 +126,7 @@ It shows a lightning bolt icon on a dark background. The favicon is **static** a Browser notifications reference `/favicon.ico` as their icon (line 1130): ```js -const notif = new Notification(`Claudeman: ${title}`, { +const notif = new Notification(`Codeman: ${title}`, { body, tag, icon: '/favicon.ico', @@ -306,7 +306,7 @@ Key detail: Title flash always stops when tab becomes visible, but **unread coun ## 5. Focus/Blur Handling ### No window focus/blur listeners -Claudeman does **not** use `window.addEventListener('focus')` or `window.addEventListener('blur')`. It relies solely on the Page Visibility API (`visibilitychange` + `pageshow`). +Codeman does **not** use `window.addEventListener('focus')` or `window.addEventListener('blur')`. It relies solely on the Page Visibility API (`visibilitychange` + `pageshow`). This is the correct modern approach. The `focus`/`blur` events are unreliable (fire for devtools, iframe changes, etc.) while `visibilitychange` accurately reflects whether the user can see the tab. diff --git a/docs/reports/notification-frontend.md b/docs/reports/notification-frontend.md index 469e5942..c14b05a1 100644 --- a/docs/reports/notification-frontend.md +++ b/docs/reports/notification-frontend.md @@ -1,11 +1,11 @@ -# Claudeman Frontend Notification System -- Detailed Report +# Codeman Frontend Notification System -- Detailed Report > Generated: 2026-02-17 > Source files analyzed: -> - `/home/arkon/default/claudeman/src/web/public/app.js` (main frontend, ~15k lines) -> - `/home/arkon/default/claudeman/src/web/public/index.html` -> - `/home/arkon/default/claudeman/src/web/public/styles.css` -> - `/home/arkon/default/claudeman/src/web/public/mobile.css` +> - `/home/arkon/default/codeman/src/web/public/app.js` (main frontend, ~15k lines) +> - `/home/arkon/default/codeman/src/web/public/index.html` +> - `/home/arkon/default/codeman/src/web/public/styles.css` +> - `/home/arkon/default/codeman/src/web/public/mobile.css` --- @@ -87,8 +87,8 @@ const defaults = { #### Storage Keys (lines 952-956) Device-specific localStorage keys prevent mobile settings from overriding desktop settings: -- Desktop: `claudeman-notification-prefs` -- Mobile: `claudeman-notification-prefs-mobile` +- Desktop: `codeman-notification-prefs` +- Mobile: `codeman-notification-prefs-mobile` #### Version Migrations (lines 928-940) @@ -260,8 +260,8 @@ Mobile override: full-width with safe area padding (mobile.css lines 1049-1058). When the tab is not visible and there are unread notifications: 1. `setInterval` at 1500ms toggles between: - - Warning emoji + unread count: `"(3) Claudeman"` - - Original title: `"Claudeman"` + - Warning emoji + unread count: `"(3) Codeman"` + - Original title: `"Codeman"` 2. Set immediately on first notification (no wait for first interval tick) ### Stopping @@ -311,7 +311,7 @@ sendBrowserNotif() called ### Notification Object (lines 1127-1143) ```js -new Notification(`Claudeman: ${title}`, { +new Notification(`Codeman: ${title}`, { body, tag, // Groups same-tag notifications (replaces previous with same tag) icon: '/favicon.ico', @@ -341,10 +341,10 @@ In settings (index.html line 993), a `=768` = desktop - Read in `loadPreferences()` (line 896), written in `savePreferences()` (line 958) -#### Layer 2: Server-side (`~/.claudeman/settings.json`) +#### Layer 2: Server-side (`~/.codeman/settings.json`) - On save, notification prefs are bundled with app settings: `{ ...settings, notificationPreferences: notifPrefsToSave }` (line 9475) - Sent via `PUT /api/settings` to the Fastify server -- Server does a shallow merge: `const merged = { ...existing, ...settings }` then writes to `~/.claudeman/settings.json` (line 3098 of server.ts) +- Server does a shallow merge: `const merged = { ...existing, ...settings }` then writes to `~/.codeman/settings.json` (line 3098 of server.ts) - The `notificationPreferences` key sits at the top level of the settings JSON alongside app settings #### Load priority @@ -109,8 +109,8 @@ On startup, `loadAppSettingsFromServer()` (line 9787) fetches from server and: ### App settings (separate from notification prefs) App settings use a different device-specific localStorage key: -- Desktop: `claudeman-app-settings` -- Mobile: `claudeman-app-settings-mobile` +- Desktop: `codeman-app-settings` +- Mobile: `codeman-app-settings-mobile` - Determined by `getSettingsStorageKey()` at line 9562 @@ -213,8 +213,8 @@ const AUTO_CLOSE_NOTIFICATION_MS = 8000; // Auto-close browser notifications ### Separate storage keys - YES Desktop and mobile use completely separate localStorage keys: -- **Notification prefs**: `claudeman-notification-prefs` vs `claudeman-notification-prefs-mobile` -- **App settings**: `claudeman-app-settings` vs `claudeman-app-settings-mobile` +- **Notification prefs**: `codeman-notification-prefs` vs `codeman-notification-prefs-mobile` +- **App settings**: `codeman-app-settings` vs `codeman-app-settings-mobile` ### Different defaults - YES @@ -303,7 +303,7 @@ The settings UI shows the current permission state via a status badge: ### HTTPS requirement -Browser notifications require HTTPS for remote access. The settings UI includes a hint: _"For remote access, HTTPS is required. Start with: `claudeman web --https`"_. On localhost, HTTP works fine. +Browser notifications require HTTPS for remote access. The settings UI includes a hint: _"For remote access, HTTPS is required. Start with: `codeman web --https`"_. On localhost, HTTP works fine. ## 7. Audio Setting @@ -354,7 +354,7 @@ Yes, given the prerequisites above are met. However, due to the category key mis Notification preferences are **strictly global**. There is no per-session notification configuration. -- The `NotificationManager` is a singleton on the `ClaudemanApp` instance (line 1404) +- The `NotificationManager` is a singleton on the `CodemanApp` instance (line 1404) - Preferences are loaded once from localStorage (line 878) - All sessions share the same notification rules diff --git a/docs/terminal-anti-flicker.md b/docs/terminal-anti-flicker.md index 0d69781d..82f45b1b 100644 --- a/docs/terminal-anti-flicker.md +++ b/docs/terminal-anti-flicker.md @@ -1,6 +1,6 @@ # Terminal Anti-Flicker System -Claude Code uses [Ink](https://github.com/vadimdemedes/ink) (React for terminals), which redraws the entire screen on every state change. Without special handling, users see constant flickering. Claudeman implements a 6-layer anti-flicker pipeline. +Claude Code uses [Ink](https://github.com/vadimdemedes/ink) (React for terminals), which redraws the entire screen on every state change. Without special handling, users see constant flickering. Codeman implements a 6-layer anti-flicker pipeline. ## Pipeline Overview diff --git a/docs/typescript-improvement-suggestions.md b/docs/typescript-improvement-suggestions.md index fb9d7483..a53d05d5 100644 --- a/docs/typescript-improvement-suggestions.md +++ b/docs/typescript-improvement-suggestions.md @@ -1,4 +1,4 @@ -# Claudeman TypeScript Improvement Suggestions +# Codeman TypeScript Improvement Suggestions **Generated**: February 2026 **Based on**: Research into TypeScript best practices (2024-2025) and codebase analysis @@ -229,33 +229,33 @@ Replace string-based errors with typed errors: ```typescript // src/errors.ts -export class ClaudemanError extends Error { +export class CodemanError extends Error { constructor( message: string, public code: string, public context?: Record ) { super(message); - Object.setPrototypeOf(this, ClaudemanError.prototype); - this.name = 'ClaudemanError'; + Object.setPrototypeOf(this, CodemanError.prototype); + this.name = 'CodemanError'; } } -export class SessionError extends ClaudemanError { +export class SessionError extends CodemanError { constructor(message: string, code: string, public sessionId: string) { super(message, code, { sessionId }); this.name = 'SessionError'; } } -export class ValidationError extends ClaudemanError { +export class ValidationError extends CodemanError { constructor(message: string, public field: string, public value: unknown) { super(message, 'VALIDATION_ERROR', { field, value }); this.name = 'ValidationError'; } } -export class ScreenError extends ClaudemanError { +export class ScreenError extends CodemanError { constructor(message: string, public screenName: string, public operation: string) { super(message, 'SCREEN_ERROR', { screenName, operation }); this.name = 'ScreenError'; @@ -324,7 +324,7 @@ Enforce ID formats at compile time: ```typescript type CycleIdFormat = `${string}:cycle-${number}`; -type ScreenSessionName = `claudeman-${string}`; +type ScreenSessionName = `codeman-${string}`; interface RespawnCycleMetrics { cycleId: CycleIdFormat; // Enforces format at compile time diff --git a/docs/voice-input-plan.md b/docs/voice-input-plan.md index 16f4d7a0..b46b2b7f 100644 --- a/docs/voice-input-plan.md +++ b/docs/voice-input-plan.md @@ -56,7 +56,7 @@ The blue-tinted voice button in the accessory bar is distinctive but subtle. Whe Confirmed by research: Web Speech API is the right choice. - **Free, fast (150-300ms interim), trivial complexity** -- Chrome + Safari = ~70% of users, ~95% of Claudeman's target audience (devs on Chrome) +- Chrome + Safari = ~70% of users, ~95% of Codeman's target audience (devs on Chrome) - Works on localhost without HTTPS - Accuracy is adequate for English command dictation - Deepgram streaming (Phase 2 optional) only if accuracy complaints arise diff --git a/install.sh b/install.sh index aac6dbb8..6a70f500 100755 --- a/install.sh +++ b/install.sh @@ -1,14 +1,14 @@ #!/usr/bin/env bash -# Claudeman Universal Installer -# https://github.com/Ark0N/claudeman +# Codeman Universal Installer +# https://github.com/Ark0N/Codeman # -# Usage: curl -fsSL https://raw.githubusercontent.com/Ark0N/claudeman/master/install.sh | bash +# Usage: curl -fsSL https://raw.githubusercontent.com/Ark0N/Codeman/master/install.sh | bash # # Environment variables: -# CLAUDEMAN_NONINTERACTIVE=1 - Skip all prompts (for CI/automation) -# CLAUDEMAN_INSTALL_DIR - Custom install directory (default: ~/.claudeman/app) -# CLAUDEMAN_SKIP_SYSTEMD=1 - Skip systemd service setup prompt -# CLAUDEMAN_NODE_VERSION - Node.js major version to install (default: 22) +# CODEMAN_NONINTERACTIVE=1 - Skip all prompts (for CI/automation) +# CODEMAN_INSTALL_DIR - Custom install directory (default: ~/.codeman/app) +# CODEMAN_SKIP_SYSTEMD=1 - Skip systemd service setup prompt +# CODEMAN_NODE_VERSION - Node.js major version to install (default: 22) set -euo pipefail @@ -16,12 +16,12 @@ set -euo pipefail # Configuration # ============================================================================ -INSTALL_DIR="${CLAUDEMAN_INSTALL_DIR:-$HOME/.claudeman/app}" -REPO_URL="https://github.com/Ark0N/claudeman.git" +INSTALL_DIR="${CODEMAN_INSTALL_DIR:-$HOME/.codeman/app}" +REPO_URL="https://github.com/Ark0N/Codeman.git" MIN_NODE_VERSION=18 -TARGET_NODE_VERSION="${CLAUDEMAN_NODE_VERSION:-22}" -NONINTERACTIVE="${CLAUDEMAN_NONINTERACTIVE:-0}" -SKIP_SYSTEMD="${CLAUDEMAN_SKIP_SYSTEMD:-0}" +TARGET_NODE_VERSION="${CODEMAN_NODE_VERSION:-22}" +NONINTERACTIVE="${CODEMAN_NONINTERACTIVE:-0}" +SKIP_SYSTEMD="${CODEMAN_SKIP_SYSTEMD:-0}" # Claude CLI search paths (from src/session.ts) CLAUDE_SEARCH_PATHS=( @@ -611,15 +611,15 @@ add_to_path() { if [[ "$shell_name" == "fish" ]]; then echo "" >> "$profile" - echo "# Added by Claudeman installer" >> "$profile" + echo "# Added by Codeman installer" >> "$profile" echo "fish_add_path $bin_dir" >> "$profile" else echo "" >> "$profile" - echo "# Added by Claudeman installer" >> "$profile" + echo "# Added by Codeman installer" >> "$profile" echo "export PATH=\"$bin_dir:\$PATH\"" >> "$profile" fi - # Also export for the current process so claudeman works immediately + # Also export for the current process so codeman works immediately export PATH="$bin_dir:$PATH" success "Added to $profile" @@ -636,7 +636,7 @@ setup_sc_alias() { fi echo "" >> "$profile" - echo "# Claudeman tmux session shortcut" >> "$profile" + echo "# Codeman tmux session shortcut" >> "$profile" echo "alias sc='tmux-chooser'" >> "$profile" info "Added 'sc' alias for tmux-chooser" @@ -648,7 +648,7 @@ setup_sc_alias() { setup_systemd_service() { local service_dir="$HOME/.config/systemd/user" - local service_file="$service_dir/claudeman-web.service" + local service_file="$service_dir/codeman-web.service" info "Setting up systemd user service..." @@ -661,7 +661,7 @@ setup_systemd_service() { # Create service file cat > "$service_file" << EOF [Unit] -Description=Claudeman Web Server +Description=Codeman Web Server After=network.target [Service] @@ -681,7 +681,7 @@ EOF systemctl --user daemon-reload # Enable service - systemctl --user enable claudeman-web.service 2>/dev/null || true + systemctl --user enable codeman-web.service 2>/dev/null || true # Enable lingering (allows service to run after logout) if command -v loginctl &>/dev/null; then @@ -689,7 +689,7 @@ EOF fi success "Systemd service installed at $service_file" - info "Start with: systemctl --user start claudeman-web" + info "Start with: systemctl --user start codeman-web" } # ============================================================================ @@ -760,7 +760,7 @@ main() { if prompt_yes_no "Git is not installed. Install it now?"; then install_dependency "git" "$os" "$distro" else - die "Git is required to install Claudeman." + die "Git is required to install Codeman." fi else success "Git is installed" @@ -781,7 +781,7 @@ main() { # Rehash to pick up new node hash -r 2>/dev/null || true else - die "Node.js $MIN_NODE_VERSION+ is required to run Claudeman." + die "Node.js $MIN_NODE_VERSION+ is required to run Codeman." fi else local node_ver @@ -832,7 +832,7 @@ main() { # Clone/Update Repository # ======================================================================== - info "Installing Claudeman to $INSTALL_DIR..." + info "Installing Codeman to $INSTALL_DIR..." if [[ -d "$INSTALL_DIR/.git" ]]; then info "Existing installation found, updating..." @@ -882,8 +882,8 @@ main() { local symlink_dir="$HOME/.local/bin" mkdir -p "$symlink_dir" 2>/dev/null || true if [[ -d "$symlink_dir" ]]; then - ln -sf "$INSTALL_DIR/dist/index.js" "$symlink_dir/claudeman" - info "Created symlink: $symlink_dir/claudeman" + ln -sf "$INSTALL_DIR/dist/index.js" "$symlink_dir/codeman" + info "Created symlink: $symlink_dir/codeman" # Install tmux-chooser as 'tmux-chooser' command if [[ -f "$INSTALL_DIR/scripts/tmux-chooser.sh" ]]; then @@ -916,16 +916,16 @@ main() { echo "" echo -e "${GREEN}${BOLD}============================================================${NC}" - echo -e "${GREEN}${BOLD} Claudeman installed successfully!${NC}" + echo -e "${GREEN}${BOLD} Codeman installed successfully!${NC}" echo -e "${GREEN}${BOLD}============================================================${NC}" echo "" echo -e " ${BOLD}Quick Start:${NC}" echo "" echo -e " ${CYAN}# Start the web server${NC}" - echo -e " claudeman web" + echo -e " codeman web" echo "" echo -e " ${CYAN}# Start with HTTPS (only needed for remote access)${NC}" - echo -e " claudeman web --https" + echo -e " codeman web --https" echo "" echo -e " ${CYAN}# Open in browser${NC}" echo -e " http://localhost:3000" @@ -937,21 +937,21 @@ main() { echo -e " ${CYAN}sc -h${NC} # Help" echo "" - if [[ "$os" == "linux" ]] && [[ -f "$HOME/.config/systemd/user/claudeman-web.service" ]]; then + if [[ "$os" == "linux" ]] && [[ -f "$HOME/.config/systemd/user/codeman-web.service" ]]; then echo -e " ${BOLD}Systemd Service:${NC}" echo "" - echo -e " ${CYAN}systemctl --user start claudeman-web${NC} # Start" - echo -e " ${CYAN}systemctl --user status claudeman-web${NC} # Check status" - echo -e " ${CYAN}journalctl --user -u claudeman-web -f${NC} # View logs" + echo -e " ${CYAN}systemctl --user start codeman-web${NC} # Start" + echo -e " ${CYAN}systemctl --user status codeman-web${NC} # Check status" + echo -e " ${CYAN}journalctl --user -u codeman-web -f${NC} # View logs" echo "" fi echo -e " ${BOLD}Documentation:${NC}" - echo -e " https://github.com/Ark0N/claudeman" + echo -e " https://github.com/Ark0N/Codeman" echo "" if ! check_claude; then - echo -e " ${YELLOW}${BOLD}Reminder:${NC} Install Claude CLI to start using Claudeman:" + echo -e " ${YELLOW}${BOLD}Reminder:${NC} Install Claude CLI to start using Codeman:" echo -e " ${CYAN}curl -fsSL https://claude.ai/install.sh | bash${NC}" echo "" fi @@ -959,20 +959,20 @@ main() { # Check if PATH needs reload in user's shell local profile profile=$(detect_shell_profile) - if ! command -v claudeman &>/dev/null 2>&1; then - echo -e " ${YELLOW}Run this to start using claudeman now:${NC}" + if ! command -v codeman &>/dev/null 2>&1; then + echo -e " ${YELLOW}Run this to start using codeman now:${NC}" echo "" - echo -e " ${CYAN}source $profile && claudeman web${NC}" + echo -e " ${CYAN}source $profile && codeman web${NC}" echo "" fi } update() { if [[ ! -d "$INSTALL_DIR/.git" ]]; then - die "Claudeman is not installed at $INSTALL_DIR. Run the installer first." + die "Codeman is not installed at $INSTALL_DIR. Run the installer first." fi - info "Updating Claudeman..." + info "Updating Codeman..." cd "$INSTALL_DIR" git fetch --quiet origin git reset --hard origin/master --quiet @@ -980,7 +980,7 @@ update() { npm run build --quiet 2>/dev/null || npm run build success "Updated to $(node -e "console.log(require('./package.json').version)")" echo "" - echo -e " ${DIM}Restart claudeman web to use the new version.${NC}" + echo -e " ${DIM}Restart codeman web to use the new version.${NC}" echo "" } diff --git a/mobile-test/README.md b/mobile-test/README.md index e971caa8..ce98c344 100644 --- a/mobile-test/README.md +++ b/mobile-test/README.md @@ -1,12 +1,12 @@ -# Claudeman Mobile Test Suite +# Codeman Mobile Test Suite -Comprehensive mobile UI testing for Claudeman's web interface using Playwright with dual-engine support (Chromium + WebKit). +Comprehensive mobile UI testing for Codeman's web interface using Playwright with dual-engine support (Chromium + WebKit). **325 tests across 135 devices — all passing.** ## Purpose -Validates Claudeman's mobile UI across 135 devices, covering: +Validates Codeman's mobile UI across 135 devices, covering: - **Keyboard simulation** — 3-layer approach to emulate virtual keyboards in headless browsers - **Touch/swipe interactions** — CDP trusted events (Chromium) + synthetic fallback (WebKit) diff --git a/mobile-test/helpers/constants.ts b/mobile-test/helpers/constants.ts index 9832b412..3ce0b112 100644 --- a/mobile-test/helpers/constants.ts +++ b/mobile-test/helpers/constants.ts @@ -126,7 +126,7 @@ export const BODY_CLASSES = { // Settings localStorage keys export const STORAGE_KEYS = { - SETTINGS_MOBILE: 'claudeman-app-settings-mobile', - SETTINGS_DESKTOP: 'claudeman-app-settings', - NOTIFICATION_PREFS_MOBILE: 'claudeman-notification-prefs-mobile', + SETTINGS_MOBILE: 'codeman-app-settings-mobile', + SETTINGS_DESKTOP: 'codeman-app-settings', + NOTIFICATION_PREFS_MOBILE: 'codeman-notification-prefs-mobile', } as const; diff --git a/mobile-test/settings.test.ts b/mobile-test/settings.test.ts index 32ea5425..c18ecf87 100644 --- a/mobile-test/settings.test.ts +++ b/mobile-test/settings.test.ts @@ -43,7 +43,7 @@ describe('Settings Modal', () => { await context.close(); }); - it('uses claudeman-app-settings-mobile localStorage key', async () => { + it('uses codeman-app-settings-mobile localStorage key', async () => { const key = await page.evaluate(() => { return (window as any).app?.getSettingsStorageKey?.() ?? null; }); @@ -53,10 +53,10 @@ describe('Settings Modal', () => { } else { // Verify by checking what key is used when saving settings await page.evaluate(() => { - localStorage.setItem('claudeman-app-settings-mobile', JSON.stringify({ testFlag: true })); + localStorage.setItem('codeman-app-settings-mobile', JSON.stringify({ testFlag: true })); }); const stored = await page.evaluate(() => { - return localStorage.getItem('claudeman-app-settings-mobile'); + return localStorage.getItem('codeman-app-settings-mobile'); }); expect(stored).toContain('testFlag'); } diff --git a/package-lock.json b/package-lock.json index 3c958e6c..d42811e6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,11 +1,11 @@ { - "name": "claudeman", + "name": "codeman", "version": "0.1619", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "claudeman", + "name": "codeman", "version": "0.1619", "hasInstallScript": true, "license": "MIT", @@ -25,7 +25,7 @@ "zod": "^4.3.6" }, "bin": { - "claudeman": "dist/index.js" + "codeman": "dist/index.js" }, "devDependencies": { "@types/node": "^20.19.33", diff --git a/package.json b/package.json index 1ba69dcc..0ed91982 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,12 @@ { - "name": "claudeman", + "name": "codeman", "version": "0.1650", "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", "types": "dist/index.d.ts", "bin": { - "claudeman": "./dist/index.js" + "codeman": "./dist/index.js" }, "scripts": { "postinstall": "node scripts/postinstall.js", @@ -71,12 +71,12 @@ }, "repository": { "type": "git", - "url": "git+https://github.com/Ark0N/claudeman.git" + "url": "git+https://github.com/Ark0N/Codeman.git" }, "bugs": { - "url": "https://github.com/Ark0N/claudeman/issues" + "url": "https://github.com/Ark0N/Codeman/issues" }, - "homepage": "https://github.com/Ark0N/claudeman#readme", + "homepage": "https://github.com/Ark0N/Codeman#readme", "files": [ "dist", "scripts/postinstall.js", diff --git a/packages/xterm-zerolag-input/LICENSE b/packages/xterm-zerolag-input/LICENSE index f3d77e8e..4ea287bd 100644 --- a/packages/xterm-zerolag-input/LICENSE +++ b/packages/xterm-zerolag-input/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2026 Claudeman Contributors +Copyright (c) 2026 Codeman Contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/packages/xterm-zerolag-input/README.md b/packages/xterm-zerolag-input/README.md index f6a069f0..b4207e1f 100644 --- a/packages/xterm-zerolag-input/README.md +++ b/packages/xterm-zerolag-input/README.md @@ -39,7 +39,7 @@ Server echoes 'h' ←─────────────────── ## Origin -This library was extracted from [Claudeman](https://github.com/Ark0N/Claudeman), a Claude Code session manager that runs 20+ autonomous AI agents over 24-hour sessions. The local echo system was built to make mobile and remote access feel instant, then battle-tested across thousands of hours of real usage. After 3 deep code audits, it was extracted into this standalone library with 78 tests covering every state transition. +This library was extracted from [Codeman](https://github.com/Ark0N/Codeman), a Claude Code session manager that runs 20+ autonomous AI agents over 24-hour sessions. The local echo system was built to make mobile and remote access feel instant, then battle-tested across thousands of hours of real usage. After 3 deep code audits, it was extracted into this standalone library with 78 tests covering every state transition. ## Install @@ -375,4 +375,4 @@ Overlay hides when scrolled up (`viewportY !== baseY`). Debounced re-render when ## License -MIT — [Claudeman](https://github.com/Ark0N/Claudeman) Contributors +MIT — [Codeman](https://github.com/Ark0N/Codeman) Contributors diff --git a/packages/xterm-zerolag-input/package.json b/packages/xterm-zerolag-input/package.json index 65284329..2846ed7a 100644 --- a/packages/xterm-zerolag-input/package.json +++ b/packages/xterm-zerolag-input/package.json @@ -32,10 +32,10 @@ "addon" ], "license": "MIT", - "homepage": "https://github.com/Ark0N/Claudeman/tree/master/packages/xterm-zerolag-input#readme", + "homepage": "https://github.com/Ark0N/Codeman/tree/master/packages/xterm-zerolag-input#readme", "repository": { "type": "git", - "url": "git+https://github.com/Ark0N/Claudeman.git", + "url": "git+https://github.com/Ark0N/Codeman.git", "directory": "packages/xterm-zerolag-input" }, "devDependencies": { diff --git a/scripts/browser-comparison.mjs b/scripts/browser-comparison.mjs index 934bdf1d..f780f8e6 100644 --- a/scripts/browser-comparison.mjs +++ b/scripts/browser-comparison.mjs @@ -2,7 +2,7 @@ /** * Browser Framework Comparison Script * - * Compares Playwright, Puppeteer, and Agent-Browser for testing Claudeman web UI. + * Compares Playwright, Puppeteer, and Agent-Browser for testing Codeman web UI. * Run: node scripts/browser-comparison.mjs */ @@ -88,7 +88,7 @@ async function main() { const page = await playwrightBrowser.newPage(); await page.goto(`http://localhost:${PORTS.playwright}`); const title = await page.title(); - if (title !== 'Claudeman') throw new Error(`Expected Claudeman, got ${title}`); + if (title !== 'Codeman') throw new Error(`Expected Codeman, got ${title}`); await page.close(); }); @@ -98,7 +98,7 @@ async function main() { await page.goto(`http://localhost:${PORTS.playwright}`); const logo = await page.locator('.header-brand .logo').textContent(); const version = await page.locator('#versionDisplay').textContent(); - if (logo !== 'Claudeman') throw new Error('Logo mismatch'); + if (logo !== 'Codeman') throw new Error('Logo mismatch'); if (!version.match(/v\d+/)) throw new Error('Version mismatch'); await page.close(); }); @@ -149,7 +149,7 @@ async function main() { const page = await puppeteerBrowser.newPage(); await page.goto(`http://localhost:${PORTS.puppeteer}`); const title = await page.title(); - if (title !== 'Claudeman') throw new Error(`Expected Claudeman, got ${title}`); + if (title !== 'Codeman') throw new Error(`Expected Codeman, got ${title}`); await page.close(); }); @@ -159,7 +159,7 @@ async function main() { await page.goto(`http://localhost:${PORTS.puppeteer}`); const logo = await page.$eval('.header-brand .logo', el => el.textContent); const version = await page.$eval('#versionDisplay', el => el.textContent); - if (logo !== 'Claudeman') throw new Error('Logo mismatch'); + if (logo !== 'Codeman') throw new Error('Logo mismatch'); if (!version.match(/v\d+/)) throw new Error('Version mismatch'); await page.close(); }); @@ -202,7 +202,7 @@ async function main() { agentBrowser(`open http://localhost:${PORTS.agentBrowser}`); await new Promise(r => setTimeout(r, 2000)); const title = agentBrowserJson('get title'); - agentBrowserAvailable = title.title === 'Claudeman'; + agentBrowserAvailable = title.title === 'Codeman'; console.log(' Browser launched'); // Test 1: Page load @@ -210,14 +210,14 @@ async function main() { agentBrowser(`open http://localhost:${PORTS.agentBrowser}`); await new Promise(r => setTimeout(r, 1000)); const title = agentBrowserJson('get title'); - if (title.title !== 'Claudeman') throw new Error(`Expected Claudeman, got ${title.title}`); + if (title.title !== 'Codeman') throw new Error(`Expected Codeman, got ${title.title}`); }); // Test 2: Element selection await runBenchmark('element-selection', 'agent-browser', async () => { const logo = agentBrowserJson('get text ".header-brand .logo"'); const version = agentBrowserJson('get text "#versionDisplay"'); - if (logo.text !== 'Claudeman') throw new Error('Logo mismatch'); + if (logo.text !== 'Codeman') throw new Error('Logo mismatch'); if (!version.text.match(/v\d+/)) throw new Error('Version mismatch'); }); diff --git a/scripts/capture-readme-screenshots.mjs b/scripts/capture-readme-screenshots.mjs index c758948b..f4b34f49 100644 --- a/scripts/capture-readme-screenshots.mjs +++ b/scripts/capture-readme-screenshots.mjs @@ -98,7 +98,7 @@ function makeSession(id, name, mode, status, extra = {}) { id, pid: status === 'idle' ? null : 12345 + Math.floor(Math.random() * 10000), status, - workingDir: '/home/arkon/claudeman-cases/testcase', + workingDir: '/home/arkon/codeman-cases/testcase', currentTaskId: null, createdAt: Date.now() - 3600000, lastActivityAt: Date.now() - (status === 'idle' ? 60000 : 5000), @@ -336,7 +336,7 @@ const TERMINAL_INIT = [ '', ` ${RED}████${RST} ${BOLD}Claude Code${RST} v2.1.47`, ` ${RED}████${RST} ${GRY}Opus 4.6${RST} ${DIM}·${RST} ${GRY}Claude Max${RST}`, - ` ${RED}██${RST} ${RED}██${RST} ${GRY}~/claudeman-cases/testcase${RST}`, + ` ${RED}██${RST} ${RED}██${RST} ${GRY}~/codeman-cases/testcase${RST}`, '', '', `${GRY}❯ Try "how do I log an error?"${RST}`, @@ -353,7 +353,7 @@ const TERMINAL_WORKING = [ `${GRN}●${RST} The codebase is essentially a template/scaffold with just a CLAUDE.md file and empty ${BOLD}src/${RST} directory. Since there's already a comprehensive`, `CLAUDE.md file present, let me read it fully and suggest improvements based on the /init command requirements:`, '', - `${GRN}●${RST} ${BOLD}Read${RST}(/home/arkon/claudeman-cases/testcase/CLAUDE.md)`, + `${GRN}●${RST} ${BOLD}Read${RST}(/home/arkon/codeman-cases/testcase/CLAUDE.md)`, ` ${GRY}░${RST} Read ${BOLD}407${RST} lines`, '', `${GRN}●${RST} Now I understand the situation. This is a ${BOLD}template CLAUDE.md file${RST} designed for the Claude Code framework with the "Ralph Loop" autonomous work`, @@ -420,15 +420,15 @@ const TERMINAL_RALPH = [ const SUBAGENT_ACTIVITY = { 'agent-001': [ { type: 'tool', tool: 'Glob', input: { pattern: 'src/**/*.ts' }, timestamp: new Date().toISOString(), agentId: 'agent-001' }, - { type: 'tool', tool: 'Read', input: { file_path: '/home/arkon/claudeman/src/web/server.ts' }, timestamp: new Date().toISOString(), agentId: 'agent-001' }, + { type: 'tool', tool: 'Read', input: { file_path: '/home/arkon/codeman/src/web/server.ts' }, timestamp: new Date().toISOString(), agentId: 'agent-001' }, { type: 'tool', tool: 'Grep', input: { pattern: 'app\\.get|app\\.post|app\\.put|app\\.delete', path: 'src/' }, timestamp: new Date().toISOString(), agentId: 'agent-001' }, - { type: 'tool', tool: 'Read', input: { file_path: '/home/arkon/claudeman/src/web/schemas.ts' }, timestamp: new Date().toISOString(), agentId: 'agent-001' }, + { type: 'tool', tool: 'Read', input: { file_path: '/home/arkon/codeman/src/web/schemas.ts' }, timestamp: new Date().toISOString(), agentId: 'agent-001' }, { type: 'message', role: 'assistant', text: 'Found 47 API endpoints across server.ts. Documenting REST paths...', timestamp: new Date().toISOString(), agentId: 'agent-001' }, ], 'agent-002': [ { type: 'tool', tool: 'Glob', input: { pattern: 'test/**/*.test.ts' }, timestamp: new Date().toISOString(), agentId: 'agent-002' }, - { type: 'tool', tool: 'Read', input: { file_path: '/home/arkon/claudeman/test/respawn-test-utils.ts' }, timestamp: new Date().toISOString(), agentId: 'agent-002' }, - { type: 'tool', tool: 'Read', input: { file_path: '/home/arkon/claudeman/vitest.config.ts' }, timestamp: new Date().toISOString(), agentId: 'agent-002' }, + { type: 'tool', tool: 'Read', input: { file_path: '/home/arkon/codeman/test/respawn-test-utils.ts' }, timestamp: new Date().toISOString(), agentId: 'agent-002' }, + { type: 'tool', tool: 'Read', input: { file_path: '/home/arkon/codeman/vitest.config.ts' }, timestamp: new Date().toISOString(), agentId: 'agent-002' }, { type: 'message', role: 'assistant', text: 'Analyzing test patterns: MockSession, unique ports, fileParallelism: false...', timestamp: new Date().toISOString(), agentId: 'agent-002' }, ], }; @@ -436,9 +436,9 @@ const SUBAGENT_ACTIVITY = { // Subagent spawn terminal content const TERMINAL_SUBAGENT = [ '', - `${GRN}●${RST} Working on ${CYN}/home/arkon/claudeman-cases/testcase${RST} - I'll use the ${BOLD}Task tool${RST} to spawn parallel agents.`, + `${GRN}●${RST} Working on ${CYN}/home/arkon/codeman-cases/testcase${RST} - I'll use the ${BOLD}Task tool${RST} to spawn parallel agents.`, '', - `${GRN}●${RST} ${BOLD}Read${RST}(/home/arkon/claudeman-cases/testcase/CLAUDE.md)`, + `${GRN}●${RST} ${BOLD}Read${RST}(/home/arkon/codeman-cases/testcase/CLAUDE.md)`, ` ${GRY}░${RST} Read ${BOLD}127${RST} lines ${GRY}│${RST} ${CYN}1.2KB${RST}`, '', `${GRN}●${RST} ${BOLD}Bash${RST}(find . -name "*.ts" -not -path "*/node_modules/*" | head -20)`, @@ -864,7 +864,7 @@ async function captureMultiSessionMonitor(page) { async function main() { console.log('='.repeat(60)); - console.log('Claudeman README Screenshot Capture'); + console.log('Codeman README Screenshot Capture'); console.log('='.repeat(60)); console.log(`Port: ${PORT} | Viewport: ${VIEWPORT.width}x${VIEWPORT.height}`); console.log(''); diff --git a/scripts/capture-subagent-gif.mjs b/scripts/capture-subagent-gif.mjs index 613d2e3e..0efac224 100644 --- a/scripts/capture-subagent-gif.mjs +++ b/scripts/capture-subagent-gif.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node /** - * Capture a GIF of subagent spawning on the LIVE Claudeman server. + * Capture a GIF of subagent spawning on the LIVE Codeman server. * * Connects to the running server on port 3000, creates a test session, * sends a prompt that spawns 3 parallel agents, and captures a tight @@ -69,7 +69,7 @@ async function capture() { try { // Create case and seed with real source files console.log(`Creating case: ${CASE_NAME}`); - const caseDir = join(process.env.HOME, 'claudeman-cases', CASE_NAME); + const caseDir = join(process.env.HOME, 'codeman-cases', CASE_NAME); const caseSrc = join(caseDir, 'src'); const caseTest = join(caseDir, 'test'); mkdirSync(caseSrc, { recursive: true }); @@ -123,7 +123,7 @@ async function capture() { // Configure settings: enable subagents, disable Files pane await setupPage.evaluate(() => { - const existing = JSON.parse(localStorage.getItem('claudeman-app-settings') || '{}'); + const existing = JSON.parse(localStorage.getItem('codeman-app-settings') || '{}'); Object.assign(existing, { showSubagents: true, subagentTrackingEnabled: true, @@ -132,7 +132,7 @@ async function capture() { showProjectInsights: false, showFileBrowser: false, }); - localStorage.setItem('claudeman-app-settings', JSON.stringify(existing)); + localStorage.setItem('codeman-app-settings', JSON.stringify(existing)); }); await setupPage.reload({ waitUntil: 'domcontentloaded' }); await sleep(1000); @@ -227,7 +227,7 @@ async function capture() { // Re-apply settings (new context = fresh localStorage) await recordPage.evaluate(() => { - const existing = JSON.parse(localStorage.getItem('claudeman-app-settings') || '{}'); + const existing = JSON.parse(localStorage.getItem('codeman-app-settings') || '{}'); Object.assign(existing, { showSubagents: true, subagentTrackingEnabled: true, @@ -236,7 +236,7 @@ async function capture() { showProjectInsights: false, showFileBrowser: false, }); - localStorage.setItem('claudeman-app-settings', JSON.stringify(existing)); + localStorage.setItem('codeman-app-settings', JSON.stringify(existing)); }); await recordPage.reload({ waitUntil: 'domcontentloaded' }); await sleep(1000); diff --git a/scripts/capture-subagent-screenshots.mjs b/scripts/capture-subagent-screenshots.mjs index 6a572d5e..d90411c1 100755 --- a/scripts/capture-subagent-screenshots.mjs +++ b/scripts/capture-subagent-screenshots.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node /** - * Capture screenshots and GIFs of Claudeman's subagent visualization + * Capture screenshots and GIFs of Codeman's subagent visualization * * Uses real Claude sessions that spawn actual subagents via the Task tool. * @@ -23,7 +23,7 @@ import { mkdirSync, existsSync, unlinkSync, rmSync } from 'fs'; const __dirname = dirname(fileURLToPath(import.meta.url)); const PROJECT_ROOT = join(__dirname, '..'); const OUTPUT_DIR = join(PROJECT_ROOT, 'docs', 'images'); -const CASES_DIR = join(process.env.HOME, 'claudeman-cases'); +const CASES_DIR = join(process.env.HOME, 'codeman-cases'); // Configuration const PORT = 3198; // Unique port for capture script (avoid 3199 conflicts) @@ -58,10 +58,10 @@ let serverProcess = null; let browser = null; /** - * Start the Claudeman web server + * Start the Codeman web server */ async function startServer() { - console.log(`Starting Claudeman server on port ${PORT}...`); + console.log(`Starting Codeman server on port ${PORT}...`); serverProcess = spawn('npx', ['tsx', 'src/index.ts', 'web', '--port', String(PORT)], { cwd: PROJECT_ROOT, @@ -222,7 +222,7 @@ async function configureSettings(page) { subagentActiveTabOnly: false, // Show all subagents regardless of active tab showMonitor: true, }; - localStorage.setItem('claudeman-app-settings', JSON.stringify(settings)); + localStorage.setItem('codeman-app-settings', JSON.stringify(settings)); }); await page.reload({ waitUntil: 'domcontentloaded' }); await sleep(500); @@ -292,7 +292,7 @@ function convertToGif(inputPath, outputPath) { */ async function capture() { console.log('='.repeat(60)); - console.log('Claudeman Subagent Screenshot Capture'); + console.log('Codeman Subagent Screenshot Capture'); console.log('='.repeat(60)); console.log(`Output directory: ${OUTPUT_DIR}`); console.log(`Case name: ${CASE_NAME}`); @@ -323,8 +323,8 @@ async function capture() { const page = await context.newPage(); page.setDefaultTimeout(30000); - // Navigate to Claudeman - console.log('Loading Claudeman...'); + // Navigate to Codeman + console.log('Loading Codeman...'); await page.goto(BASE_URL, { waitUntil: 'domcontentloaded' }); await sleep(1000); diff --git a/scripts/claudeman-web.service b/scripts/codeman-web.service similarity index 75% rename from scripts/claudeman-web.service rename to scripts/codeman-web.service index 597c9981..d6f60429 100644 --- a/scripts/claudeman-web.service +++ b/scripts/codeman-web.service @@ -1,10 +1,10 @@ [Unit] -Description=Claudeman Web Server +Description=Codeman Web Server After=network.target [Service] Type=simple -WorkingDirectory=/home/arkon/default/claudeman +WorkingDirectory=/home/arkon/default/codeman ExecStart=/usr/bin/node dist/index.js web --https Restart=always RestartSec=5 @@ -15,7 +15,7 @@ Environment=HOME=/home/arkon # Logging StandardOutput=journal StandardError=journal -SyslogIdentifier=claudeman +SyslogIdentifier=codeman # Resource limits LimitNOFILE=65536 diff --git a/scripts/mobile-screenshot.mjs b/scripts/mobile-screenshot.mjs index 25f3f4ea..f91bc0c4 100644 --- a/scripts/mobile-screenshot.mjs +++ b/scripts/mobile-screenshot.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node /** - * Take mobile screenshots of Claudeman using Playwright + * Take mobile screenshots of Codeman using Playwright * Emulates iPhone 15 Pro (closest to iPhone 17 Pro) * Includes keyboard simulation */ diff --git a/scripts/monitor-respawn.sh b/scripts/monitor-respawn.sh index 9432f8b4..ad5340f0 100755 --- a/scripts/monitor-respawn.sh +++ b/scripts/monitor-respawn.sh @@ -4,8 +4,8 @@ SESSION_ID="${1:-5ecdf859-3605-42d8-b0a2-f8f0a1b5ff98}" DURATION_HOURS="${2:-12}" -ISSUES_FILE="/home/arkon/default/claudeman/respawn-monitor-issues.md" -FIXES_FILE="/home/arkon/default/claudeman/respawn-monitor-fixes.md" +ISSUES_FILE="/home/arkon/default/codeman/respawn-monitor-issues.md" +FIXES_FILE="/home/arkon/default/codeman/respawn-monitor-fixes.md" API_URL="https://localhost:3000" POLL_INTERVAL=60 # seconds @@ -54,7 +54,7 @@ while [ $(date +%s) -lt $END_TIME ]; do if [ -z "$RESP" ]; then log_issue "ERROR" "API not responding - server may be down" - add_fix "API not responding" "Check if claudeman-web service is running:\n\`\`\`bash\nsystemctl --user status claudeman-web\nsystemctl --user restart claudeman-web\n\`\`\`" + add_fix "API not responding" "Check if codeman-web service is running:\n\`\`\`bash\nsystemctl --user status codeman-web\nsystemctl --user restart codeman-web\n\`\`\`" sleep $POLL_INTERVAL continue fi diff --git a/scripts/postinstall.js b/scripts/postinstall.js index 8e1ff9b9..610947a2 100644 --- a/scripts/postinstall.js +++ b/scripts/postinstall.js @@ -1,7 +1,7 @@ #!/usr/bin/env node /** - * Claudeman postinstall verification script + * Codeman postinstall verification script * Runs after `npm install` to check environment readiness */ @@ -94,7 +94,7 @@ function getTmuxInstallInstructions() { // Main Checks // ============================================================================ -console.log(colors.bold('Claudeman postinstall check...')); +console.log(colors.bold('Codeman postinstall check...')); console.log(''); let hasWarnings = false; @@ -259,11 +259,11 @@ if (hasErrors) { console.log(colors.bold('Next steps:')); if (isGlobalInstall) { - console.log(colors.dim(' 1. Start: ') + colors.cyan('claudeman web')); + console.log(colors.dim(' 1. Start: ') + colors.cyan('codeman web')); console.log(colors.dim(' 2. Open: ') + colors.cyan('http://localhost:3000')); } else { console.log(colors.dim(' 1. Build: ') + colors.cyan('npm run build')); - console.log(colors.dim(' 2. Start: ') + colors.cyan('claudeman web')); + console.log(colors.dim(' 2. Start: ') + colors.cyan('codeman web')); console.log(colors.dim(' 3. Open: ') + colors.cyan('http://localhost:3000')); } diff --git a/scripts/ralph-wizard-demo.mjs b/scripts/ralph-wizard-demo.mjs index e0477975..861b0eec 100644 --- a/scripts/ralph-wizard-demo.mjs +++ b/scripts/ralph-wizard-demo.mjs @@ -8,7 +8,7 @@ import { join } from 'node:path'; import { homedir } from 'node:os'; const BASE_URL = 'https://localhost:3000'; -const CASE_NAME = 'claudeman-ios'; +const CASE_NAME = 'codeman-ios'; async function main() { console.log('🎬 Starting Ralph Loop Wizard demo...\n'); @@ -25,7 +25,7 @@ async function main() { }); const page = await context.newPage(); - console.log('📱 Opening Claudeman web UI...'); + console.log('📱 Opening Codeman web UI...'); await page.goto(BASE_URL); await page.waitForLoadState('networkidle'); @@ -41,8 +41,8 @@ async function main() { await page.selectOption('#ralphCaseSelect', CASE_NAME); // Load initprompt.md if it exists - const initPromptPath = join(homedir(), 'claudeman-cases', CASE_NAME, 'initprompt.md'); - let taskDescription = 'Build an awesome iOS app for Claudeman!'; + const initPromptPath = join(homedir(), 'codeman-cases', CASE_NAME, 'initprompt.md'); + let taskDescription = 'Build an awesome iOS app for Codeman!'; if (existsSync(initPromptPath)) { taskDescription = readFileSync(initPromptPath, 'utf-8').trim(); console.log(`📝 Loaded initprompt.md (${taskDescription.length} chars)`); diff --git a/scripts/ralph-wizard-prod.mjs b/scripts/ralph-wizard-prod.mjs index 2069c97a..11b13553 100644 --- a/scripts/ralph-wizard-prod.mjs +++ b/scripts/ralph-wizard-prod.mjs @@ -10,8 +10,8 @@ import { join } from 'node:path'; import { homedir } from 'node:os'; const BASE_URL = 'https://localhost:3000'; -const CASE_NAME = 'claudeman-ios'; -const CASE_PATH = join(homedir(), 'claudeman-cases', CASE_NAME); +const CASE_NAME = 'codeman-ios'; +const CASE_PATH = join(homedir(), 'codeman-cases', CASE_NAME); async function main() { // Read initprompt.md @@ -49,7 +49,7 @@ async function main() { page.on('pageerror', err => console.log(`[Browser Error] ${err.message}`)); try { - console.log('[1/10] Navigating to Claudeman...'); + console.log('[1/10] Navigating to Codeman...'); await page.goto(BASE_URL, { timeout: 10000 }); console.log('[2/10] Clicking Ralph Loop button (.btn-ralph)...'); @@ -122,7 +122,7 @@ async function main() { }); session = sessions - .filter(s => s.workingDir?.includes('claudeman-ios')) + .filter(s => s.workingDir?.includes('codeman-ios')) .sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt))[0]; if (session) { @@ -151,7 +151,7 @@ async function main() { console.log('SUCCESS! Ralph Loop started.'); console.log('========================================'); console.log(`Session ID: ${session?.id}`); - console.log(`Screen: claudeman-${session?.id?.slice(0, 8)}`); + console.log(`Screen: codeman-${session?.id?.slice(0, 8)}`); console.log(`Status: ${session?.status}`); console.log(''); console.log('Session is now running. View at: https://localhost:3000'); diff --git a/scripts/ralph-wizard-start.mjs b/scripts/ralph-wizard-start.mjs index 1a3e23be..5faad32b 100644 --- a/scripts/ralph-wizard-start.mjs +++ b/scripts/ralph-wizard-start.mjs @@ -8,7 +8,7 @@ import { join } from 'node:path'; import { homedir } from 'node:os'; const BASE_URL = 'https://localhost:3000'; -const CASE_NAME = 'claudeman-ios'; +const CASE_NAME = 'codeman-ios'; async function main() { console.log('Starting Ralph Loop via wizard on production server...\n'); @@ -21,7 +21,7 @@ async function main() { const context = await browser.newContext({ ignoreHTTPSErrors: true }); const page = await context.newPage(); - console.log('1. Opening Claudeman web UI...'); + console.log('1. Opening Codeman web UI...'); await page.goto(BASE_URL); await page.waitForLoadState('networkidle'); @@ -36,8 +36,8 @@ async function main() { await page.selectOption('#ralphCaseSelect', CASE_NAME); // Load initprompt.md - const initPromptPath = join(homedir(), 'claudeman-cases', CASE_NAME, 'initprompt.md'); - let taskDescription = 'Build an awesome iOS app for Claudeman!'; + const initPromptPath = join(homedir(), 'codeman-cases', CASE_NAME, 'initprompt.md'); + let taskDescription = 'Build an awesome iOS app for Codeman!'; if (existsSync(initPromptPath)) { taskDescription = readFileSync(initPromptPath, 'utf-8').trim(); console.log(`5. Loaded initprompt.md (${taskDescription.length} chars)`); @@ -87,13 +87,13 @@ async function main() { return res.json(); }); - const iosSession = sessions.find(s => s.workingDir?.includes('claudeman-ios')); + const iosSession = sessions.find(s => s.workingDir?.includes('codeman-ios')); console.log('\n========================================'); console.log('SUCCESS! Ralph Loop started.'); console.log('========================================'); console.log(`Session ID: ${iosSession?.id}`); - console.log(`Screen: claudeman-${iosSession?.id?.slice(0, 8)}`); + console.log(`Screen: codeman-${iosSession?.id?.slice(0, 8)}`); console.log(`Working Dir: ${iosSession?.workingDir}`); console.log('\nThe session is now running on your production server.'); console.log('View it at: https://localhost:3000'); diff --git a/scripts/test-links-browser.mjs b/scripts/test-links-browser.mjs index 5f73262f..6477067f 100644 --- a/scripts/test-links-browser.mjs +++ b/scripts/test-links-browser.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node /** - * Browser test for clickable file links in Claudeman terminal + * Browser test for clickable file links in Codeman terminal * Uses Playwright directly to ignore HTTPS errors */ @@ -33,8 +33,8 @@ async function main() { const page = await context.newPage(); try { - // Navigate to Claudeman - console.log('Navigating to Claudeman...'); + // Navigate to Codeman + console.log('Navigating to Codeman...'); await page.goto(BASE_URL, { waitUntil: 'networkidle', timeout: 30000 }); console.log('Page loaded: ' + await page.title()); @@ -63,9 +63,9 @@ async function main() { await page.waitForTimeout(2000); } - // Get active session (use claudeman session if exists) - const claudemanSession = sessions.find(s => s.workingDir?.includes('claudeman')); - const sessionId = claudemanSession?.id || sessions[0]?.id; + // Get active session (use codeman session if exists) + const codemanSession = sessions.find(s => s.workingDir?.includes('codeman')); + const sessionId = codemanSession?.id || sessions[0]?.id; console.log(`Using session: ${sessionId}\n`); // Send a command that outputs file paths @@ -81,8 +81,8 @@ async function main() { await page.waitForTimeout(2000); // Take screenshot - await page.screenshot({ path: '/tmp/claudeman-link-test-1.png' }); - console.log('Screenshot saved: /tmp/claudeman-link-test-1.png\n'); + await page.screenshot({ path: '/tmp/codeman-link-test-1.png' }); + console.log('Screenshot saved: /tmp/codeman-link-test-1.png\n'); // Check if terminal contains our file path const terminalContent = await page.evaluate(() => { @@ -132,8 +132,8 @@ async function main() { console.log('Log viewer windows:', logViewerCount); // Take final screenshot - await page.screenshot({ path: '/tmp/claudeman-link-test-2.png' }); - console.log('\nFinal screenshot: /tmp/claudeman-link-test-2.png'); + await page.screenshot({ path: '/tmp/codeman-link-test-2.png' }); + console.log('\nFinal screenshot: /tmp/codeman-link-test-2.png'); // Test the link provider registration console.log('\n--- Link Provider Debug ---'); @@ -155,8 +155,8 @@ async function main() { } catch (error) { console.error('Error:', error.message); - await page.screenshot({ path: '/tmp/claudeman-link-test-error.png' }); - console.log('Error screenshot saved to /tmp/claudeman-link-test-error.png'); + await page.screenshot({ path: '/tmp/codeman-link-test-error.png' }); + console.log('Error screenshot saved to /tmp/codeman-link-test-error.png'); } finally { await browser.close(); console.log('\nBrowser closed'); diff --git a/scripts/test-tail-links.sh b/scripts/test-tail-links.sh index fd0a399e..b6787122 100755 --- a/scripts/test-tail-links.sh +++ b/scripts/test-tail-links.sh @@ -1,8 +1,8 @@ #!/bin/bash -# Test script for clickable file links in Claudeman terminal +# Test script for clickable file links in Codeman terminal # Creates a log file and continuously writes timestamped data -LOGFILE="/tmp/claudeman-test-$(date +%s).log" +LOGFILE="/tmp/codeman-test-$(date +%s).log" echo "Created log file: $LOGFILE" echo "" diff --git a/scripts/tmux-chooser.sh b/scripts/tmux-chooser.sh index 908e33ed..0aef49d5 100755 --- a/scripts/tmux-chooser.sh +++ b/scripts/tmux-chooser.sh @@ -1,6 +1,6 @@ #!/bin/bash # ============================================================================ -# Claudeman Sessions - Mobile-friendly Tmux Session Chooser +# Codeman Sessions - Mobile-friendly Tmux Session Chooser # Optimized for iPhone/Termius (portrait ~45 chars, landscape ~95 chars) # ============================================================================ # @@ -8,7 +8,7 @@ # - Single-digit selection (1-9) for fast thumb typing # - Compact display, no wasted space # - Color-coded status for quick scanning -# - Names pulled from Claudeman state.json +# - Names pulled from Codeman state.json # - Minimal keystrokes to attach # # Usage: @@ -29,8 +29,8 @@ set -e # Configuration # ============================================================================ -CLAUDEMAN_STATE="$HOME/.claudeman/state.json" -CLAUDEMAN_SESSIONS="$HOME/.claudeman/mux-sessions.json" +CODEMAN_STATE="$HOME/.codeman/state.json" +CODEMAN_SESSIONS="$HOME/.codeman/mux-sessions.json" # iPhone 17 Pro portrait width (conservative) @@ -106,22 +106,22 @@ truncate() { find_full_session_id() { local short_id="$1" - if [ -f "$CLAUDEMAN_STATE" ]; then + if [ -f "$CODEMAN_STATE" ]; then local full_id full_id=$(jq -r --arg short "$short_id" ' .sessions | keys[] | select(startswith($short)) - ' "$CLAUDEMAN_STATE" 2>/dev/null | head -1) + ' "$CODEMAN_STATE" 2>/dev/null | head -1) if [ -n "$full_id" ]; then echo "$full_id" return fi fi - if [ -f "$CLAUDEMAN_SESSIONS" ]; then + if [ -f "$CODEMAN_SESSIONS" ]; then local full_id full_id=$(jq -r --arg short "$short_id" ' .[] | select(.sessionId | startswith($short)) | .sessionId - ' "$CLAUDEMAN_SESSIONS" 2>/dev/null | head -1) + ' "$CODEMAN_SESSIONS" 2>/dev/null | head -1) if [ -n "$full_id" ]; then echo "$full_id" return @@ -136,22 +136,22 @@ get_session_name() { local name="" local workdir="" - if [ -f "$CLAUDEMAN_SESSIONS" ]; then + if [ -f "$CODEMAN_SESSIONS" ]; then local result result=$(jq -r --arg id "$session_id" ' .[] | select(.sessionId | startswith($id)) | "\(.name // "")\t\(.workingDir // "")" - ' "$CLAUDEMAN_SESSIONS" 2>/dev/null | head -1) + ' "$CODEMAN_SESSIONS" 2>/dev/null | head -1) if [ -n "$result" ]; then name="${result%% *}" workdir="${result#* }" fi fi - if [ -z "$name" ] && [ -f "$CLAUDEMAN_STATE" ]; then + if [ -z "$name" ] && [ -f "$CODEMAN_STATE" ]; then local result result=$(jq -r --arg id "$session_id" ' .sessions | to_entries[] | select(.key | startswith($id)) | "\(.value.name // "")\t\(.value.workingDir // "")" - ' "$CLAUDEMAN_STATE" 2>/dev/null | head -1) + ' "$CODEMAN_STATE" 2>/dev/null | head -1) if [ -n "$result" ]; then name="${result%% *}" [ -z "$workdir" ] && workdir="${result#* }" @@ -174,22 +174,22 @@ get_session_name() { get_working_dir() { local session_id="$1" - if [ -f "$CLAUDEMAN_SESSIONS" ]; then + if [ -f "$CODEMAN_SESSIONS" ]; then local dir dir=$(jq -r --arg id "$session_id" ' .[] | select(.sessionId | startswith($id)) | .workingDir // empty - ' "$CLAUDEMAN_SESSIONS" 2>/dev/null | head -1) + ' "$CODEMAN_SESSIONS" 2>/dev/null | head -1) if [ -n "$dir" ] && [ "$dir" != "null" ]; then echo "${dir/#$HOME/~}" return fi fi - if [ -f "$CLAUDEMAN_STATE" ]; then + if [ -f "$CODEMAN_STATE" ]; then local dir dir=$(jq -r --arg id "$session_id" ' .sessions | to_entries[] | select(.key | startswith($id)) | .value.workingDir // empty - ' "$CLAUDEMAN_STATE" 2>/dev/null | head -1) + ' "$CODEMAN_STATE" 2>/dev/null | head -1) if [ -n "$dir" ] && [ "$dir" != "null" ]; then echo "${dir/#$HOME/~}" return @@ -201,12 +201,12 @@ get_working_dir() { get_tokens() { local session_id="$1" - if [ -f "$CLAUDEMAN_STATE" ]; then + if [ -f "$CODEMAN_STATE" ]; then local tokens tokens=$(jq -r --arg id "$session_id" ' .sessions | to_entries[] | select(.key | startswith($id)) | ((.value.inputTokens // 0) + (.value.outputTokens // 0)) - ' "$CLAUDEMAN_STATE" 2>/dev/null | head -1) + ' "$CODEMAN_STATE" 2>/dev/null | head -1) if [ -n "$tokens" ] && [ "$tokens" != "null" ] && [ "$tokens" -gt 0 ] 2>/dev/null; then if [ "$tokens" -gt 1000 ]; then @@ -223,11 +223,11 @@ get_tokens() { get_respawn_status() { local session_id="$1" - if [ -f "$CLAUDEMAN_SESSIONS" ]; then + if [ -f "$CODEMAN_SESSIONS" ]; then local respawn_enabled respawn_enabled=$(jq -r --arg id "$session_id" ' .[] | select(.sessionId | startswith($id)) | .respawnConfig.enabled // false - ' "$CLAUDEMAN_SESSIONS" 2>/dev/null | head -1) + ' "$CODEMAN_SESSIONS" 2>/dev/null | head -1) if [ "$respawn_enabled" = "true" ]; then echo "R" @@ -273,8 +273,8 @@ parse_sessions() { while IFS= read -r line; do local session_name="${line%%:*}" - # Only show claudeman sessions - if [[ "$session_name" != claudeman-* ]]; then + # Only show codeman sessions + if [[ "$session_name" != codeman-* ]]; then continue fi @@ -292,9 +292,9 @@ parse_sessions() { MUX_NAMES+=("$session_name") SESSION_STATES+=("$state") - # Extract session ID from claudeman session name + # Extract session ID from codeman session name local session_id="" - local cm_regex='^claudeman-(.+)$' + local cm_regex='^codeman-(.+)$' if [[ "$session_name" =~ $cm_regex ]]; then session_id="${BASH_REMATCH[1]}" fi @@ -327,7 +327,7 @@ clear_screen() { print_header() { local count=${#SESSION_PIDS[@]} - echo -e "${B}${CYAN}Claudeman Sessions${R} ${D}($count)${R}" + echo -e "${B}${CYAN}Codeman Sessions${R} ${D}($count)${R}" echo -e "${D}$(printf '%.0s─' {1..32})${R}" } @@ -395,13 +395,13 @@ print_footer() { print_no_sessions() { clear_screen - echo -e "${B}${CYAN}Claudeman Sessions${R}" + echo -e "${B}${CYAN}Codeman Sessions${R}" echo -e "${D}$(printf '%.0s─' {1..32})${R}" echo "" echo -e " ${YELLOW}No tmux sessions found${R}" echo "" echo -e " ${D}Start one with:${R}" - echo -e " ${WHITE}claudeman web${R}" + echo -e " ${WHITE}codeman web${R}" echo "" echo -e "${D}$(printf '%.0s─' {1..32})${R}" echo -e " ${GRAY}[${WHITE}r${GRAY}]efresh [${WHITE}q${GRAY}]uit${R}" @@ -584,7 +584,7 @@ quick_attach() { show_help() { cat << 'EOF' -Claudeman Sessions - Mobile-friendly Tmux Session Chooser +Codeman Sessions - Mobile-friendly Tmux Session Chooser USAGE: sc Interactive chooser @@ -607,7 +607,7 @@ INDICATORS: TIPS: - Detach from tmux: Ctrl+B D - - Session names from Claudeman state + - Session names from Codeman state - Optimized for Termius/iPhone EOF diff --git a/scripts/tmux-manager.sh b/scripts/tmux-manager.sh index a5f25757..01de1847 100755 --- a/scripts/tmux-manager.sh +++ b/scripts/tmux-manager.sh @@ -1,8 +1,8 @@ #!/bin/bash # -# Claudeman Tmux Session Manager +# Codeman Tmux Session Manager # Interactive tool with arrow key navigation -# Reads from ~/.claudeman/mux-sessions.json +# Reads from ~/.codeman/mux-sessions.json # # Colors @@ -17,8 +17,8 @@ DIM='\033[2m' NC='\033[0m' REVERSE='\033[7m' -# Use the same path as claudeman (src/tmux-manager.ts) -SESSIONS_FILE="${HOME}/.claudeman/mux-sessions.json" +# Use the same path as codeman (src/tmux-manager.ts) +SESSIONS_FILE="${HOME}/.codeman/mux-sessions.json" # Cached data @@ -133,7 +133,7 @@ kill_session() { # Draw header (only once) draw_header() { echo -e "${BOLD}${CYAN}╔══════════════════════════════════════════════════════════╗${NC}" - echo -e "${BOLD}${CYAN}║ Claudeman Tmux Session Manager ║${NC}" + echo -e "${BOLD}${CYAN}║ Codeman Tmux Session Manager ║${NC}" echo -e "${BOLD}${CYAN}║ ${DIM}Press q or Esc to exit${CYAN} ║${NC}" echo -e "${BOLD}${CYAN}╚══════════════════════════════════════════════════════════╝${NC}" echo "" @@ -401,11 +401,11 @@ quick_list() { local now=$(date +%s) if [[ $CACHED_COUNT -eq 0 ]]; then - echo "No claudeman sessions found." + echo "No codeman sessions found." exit 0 fi - echo "Claudeman Sessions ($SESSIONS_FILE):" + echo "Codeman Sessions ($SESSIONS_FILE):" echo "" printf "%-4s %-22s %-14s %-10s %-8s\n" "#" "NAME" "RUNNING" "STATUS" "MODE" echo "─────────────────────────────────────────────────────────────────" @@ -432,7 +432,7 @@ quick_list() { # Usage usage() { cat << EOF -Claudeman Tmux Session Manager +Codeman Tmux Session Manager Reads from: $SESSIONS_FILE diff --git a/src/ai-checker-base.ts b/src/ai-checker-base.ts index f67f778d..dc9711c7 100644 --- a/src/ai-checker-base.ts +++ b/src/ai-checker-base.ts @@ -11,9 +11,9 @@ * - Event emission for state changes * * Subclasses implement: - * - `muxNamePrefix`: Prefix for mux session names (e.g., 'claudeman-aicheck-') + * - `muxNamePrefix`: Prefix for mux session names (e.g., 'codeman-aicheck-') * - `doneMarker`: Completion marker in output file (e.g., '__AICHECK_DONE__') - * - `tempFilePrefix`: Prefix for temp files (e.g., 'claudeman-aicheck') + * - `tempFilePrefix`: Prefix for temp files (e.g., 'codeman-aicheck') * - `logPrefix`: Prefix for log messages (e.g., '[AiIdleChecker]') * - `buildPrompt()`: Build the prompt from terminal buffer * - `parseVerdict()`: Parse the verdict from AI output @@ -143,13 +143,13 @@ export abstract class AiCheckerBase< // ========== Abstract Properties ========== - /** Prefix for mux session names (e.g., 'claudeman-aicheck-') */ + /** Prefix for mux session names (e.g., 'codeman-aicheck-') */ protected abstract readonly muxNamePrefix: string; /** Marker written to temp file when check is complete */ protected abstract readonly doneMarker: string; - /** Prefix for temp files (e.g., 'claudeman-aicheck') */ + /** Prefix for temp files (e.g., 'codeman-aicheck') */ protected abstract readonly tempFilePrefix: string; /** Prefix for log messages (e.g., '[AiIdleChecker]') */ diff --git a/src/ai-idle-checker.ts b/src/ai-idle-checker.ts index 89aaf409..b5154602 100644 --- a/src/ai-idle-checker.ts +++ b/src/ai-idle-checker.ts @@ -8,7 +8,7 @@ * ## How It Works * * 1. Generate temp file path for output capture - * 2. Spawn tmux: `tmux new-session -d -s claudeman-aicheck- bash -c 'claude -p ...'` + * 2. Spawn tmux: `tmux new-session -d -s codeman-aicheck- bash -c 'claude -p ...'` * 3. Poll the temp file every 500ms for `__AICHECK_DONE__` marker * 4. Parse the file content for IDLE/WORKING on the first word * 5. Kill tmux session and delete temp file @@ -129,9 +129,9 @@ export class AiIdleChecker extends AiCheckerBase< AiCheckResult, AiCheckState > { - protected readonly muxNamePrefix = 'claudeman-aicheck-'; + protected readonly muxNamePrefix = 'codeman-aicheck-'; protected readonly doneMarker = '__AICHECK_DONE__'; - protected readonly tempFilePrefix = 'claudeman-aicheck'; + protected readonly tempFilePrefix = 'codeman-aicheck'; protected readonly logPrefix = '[AiIdleChecker]'; protected readonly checkDescription = 'AI idle check'; diff --git a/src/ai-plan-checker.ts b/src/ai-plan-checker.ts index eec922ef..f302f88f 100644 --- a/src/ai-plan-checker.ts +++ b/src/ai-plan-checker.ts @@ -8,7 +8,7 @@ * ## How It Works * * 1. Generate temp file path for output capture - * 2. Spawn tmux: `tmux new-session -d -s claudeman-plancheck- bash -c 'claude -p ...'` + * 2. Spawn tmux: `tmux new-session -d -s codeman-plancheck- bash -c 'claude -p ...'` * 3. Poll the temp file every 500ms for `__PLANCHECK_DONE__` marker * 4. Parse the file content for PLAN_MODE/NOT_PLAN_MODE on the first line * 5. Kill tmux session and delete temp file @@ -91,9 +91,9 @@ export class AiPlanChecker extends AiCheckerBase< AiPlanCheckResult, AiPlanCheckState > { - protected readonly muxNamePrefix = 'claudeman-plancheck-'; + protected readonly muxNamePrefix = 'codeman-plancheck-'; protected readonly doneMarker = '__PLANCHECK_DONE__'; - protected readonly tempFilePrefix = 'claudeman-plancheck'; + protected readonly tempFilePrefix = 'codeman-plancheck'; protected readonly logPrefix = '[AiPlanChecker]'; protected readonly checkDescription = 'AI plan check'; diff --git a/src/cli.ts b/src/cli.ts index ad4fca2e..425d6c03 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -1,5 +1,5 @@ /** - * @fileoverview Claudeman CLI command definitions + * @fileoverview Codeman CLI command definitions * * Defines all CLI commands and subcommands for managing Claude sessions, * tasks, Ralph loops, and the web server. @@ -22,7 +22,7 @@ const pkg = require('../package.json') as { version: string }; const program = new Command(); program - .name('claudeman') + .name('codeman') .description('Claude Code session manager with autonomous Ralph Loop') .version(pkg.version); @@ -407,7 +407,7 @@ program ? sessions.filter((s) => s.isBusy()).length : storedValues.filter((s) => s.status === 'busy').length; - console.log(chalk.bold('\nClaudeman Status')); + console.log(chalk.bold('\nCodeman Status')); console.log('─'.repeat(40)); console.log(chalk.bold('\nSessions:')); @@ -504,7 +504,7 @@ program const https = !!options.https; const protocol = https ? 'https' : 'http'; - console.log(chalk.cyan(`Starting Claudeman web interface on port ${port}${https ? ' (HTTPS)' : ''}...`)); + console.log(chalk.cyan(`Starting Codeman web interface on port ${port}${https ? ' (HTTPS)' : ''}...`)); try { const server = await startWebServer(port, https); diff --git a/src/config/buffer-limits.ts b/src/config/buffer-limits.ts index 90b14eba..41f7bcd5 100644 --- a/src/config/buffer-limits.ts +++ b/src/config/buffer-limits.ts @@ -2,7 +2,7 @@ * @fileoverview Centralized buffer size limits for memory management. * * These constants define the maximum sizes for various buffers throughout - * Claudeman. Consolidating them here ensures consistent limits and makes + * Codeman. Consolidating them here ensures consistent limits and makes * it easy to tune memory usage. * * Memory Budget Rationale (for 20 concurrent sessions): diff --git a/src/hooks-config.ts b/src/hooks-config.ts index d00627ea..f9843c71 100644 --- a/src/hooks-config.ts +++ b/src/hooks-config.ts @@ -2,9 +2,9 @@ * @fileoverview Claude Code hooks configuration generator * * Generates .claude/settings.local.json with hook definitions that POST - * to Claudeman's /api/hook-event endpoint when Claude Code fires - * notification or stop hooks. Uses $CLAUDEMAN_API_URL and - * $CLAUDEMAN_SESSION_ID env vars (set on every managed session) so the + * to Codeman's /api/hook-event endpoint when Claude Code fires + * notification or stop hooks. Uses $CODEMAN_API_URL and + * $CODEMAN_SESSION_ID env vars (set on every managed session) so the * config is static per case directory. */ @@ -18,7 +18,7 @@ import type { HookEventType } from './types.js'; * Generates the hooks section for .claude/settings.local.json * * The hook commands read stdin JSON from Claude Code (contains tool_name, - * tool_input, etc.) and forward it as the `data` field to Claudeman's API. + * tool_input, etc.) and forward it as the `data` field to Codeman's API. * Env vars are resolved at runtime by the shell, so the config is static * per case directory. */ @@ -27,9 +27,9 @@ export function generateHooksConfig(): { hooks: Record } { // Falls back to empty object if stdin is unavailable or malformed. const curlCmd = (event: HookEventType) => `HOOK_DATA=$(cat 2>/dev/null || echo '{}'); ` + - `curl -s -X POST "$CLAUDEMAN_API_URL/api/hook-event" ` + + `curl -s -X POST "$CODEMAN_API_URL/api/hook-event" ` + `-H 'Content-Type: application/json' ` + - `-d "{\\"event\\":\\"${event}\\",\\"sessionId\\":\\"$CLAUDEMAN_SESSION_ID\\",\\"data\\":$HOOK_DATA}" ` + + `-d "{\\"event\\":\\"${event}\\",\\"sessionId\\":\\"$CODEMAN_SESSION_ID\\",\\"data\\":$HOOK_DATA}" ` + `2>/dev/null || true`; return { diff --git a/src/image-watcher.ts b/src/image-watcher.ts index eb5e4443..87c43dc1 100644 --- a/src/image-watcher.ts +++ b/src/image-watcher.ts @@ -137,7 +137,7 @@ export class ImageWatcher extends EventEmitter { /** * Start watching a session's working directory for new images. * - * @param sessionId - Claudeman session ID + * @param sessionId - Codeman session ID * @param workingDir - Path to the session's working directory */ watchSession(sessionId: string, workingDir: string): void { @@ -200,7 +200,7 @@ export class ImageWatcher extends EventEmitter { /** * Stop watching a session's working directory. * - * @param sessionId - Claudeman session ID to stop watching + * @param sessionId - Codeman session ID to stop watching */ unwatchSession(sessionId: string): void { const watcher = this.sessionWatchers.get(sessionId); diff --git a/src/index.ts b/src/index.ts index de4c52e1..ea502157 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,8 +1,8 @@ #!/usr/bin/env node /** - * @fileoverview Claudeman CLI entry point + * @fileoverview Codeman CLI entry point * - * This is the main executable entry point for the Claudeman CLI. + * This is the main executable entry point for the Codeman CLI. * It sets up global error handlers and invokes the CLI parser. * * @module index diff --git a/src/mux-interface.ts b/src/mux-interface.ts index fd475b5f..e3a91ecc 100644 --- a/src/mux-interface.ts +++ b/src/mux-interface.ts @@ -13,9 +13,9 @@ import type { ProcessStats, PersistedRespawnConfig, NiceConfig, ClaudeMode, Sess * Multiplexer session metadata. */ export interface MuxSession { - /** Claudeman session ID */ + /** Codeman session ID */ sessionId: string; - /** Multiplexer session name (e.g., "claudeman-abc12345") */ + /** Multiplexer session name (e.g., "codeman-abc12345") */ muxName: string; /** Process PID */ pid: number; @@ -105,7 +105,7 @@ export interface TerminalMultiplexer extends EventEmitter { /** Get all tracked sessions */ getSessions(): MuxSession[]; - /** Get a session by Claudeman session ID */ + /** Get a session by Codeman session ID */ getSession(sessionId: string): MuxSession | undefined; /** Get all sessions with process resource statistics */ diff --git a/src/run-summary.ts b/src/run-summary.ts index cbb21981..7a9c0fae 100644 --- a/src/run-summary.ts +++ b/src/run-summary.ts @@ -1,5 +1,5 @@ /** - * @fileoverview Run Summary Tracker for Claudeman sessions + * @fileoverview Run Summary Tracker for Codeman sessions * * Tracks significant events during a session's lifetime to provide users * with a consolidated "what happened while I was away" view. diff --git a/src/session-lifecycle-log.ts b/src/session-lifecycle-log.ts index 4aa1262e..ddab9978 100644 --- a/src/session-lifecycle-log.ts +++ b/src/session-lifecycle-log.ts @@ -2,7 +2,7 @@ * @fileoverview Append-only JSONL audit log for session lifecycle events. * * Records every session creation, start, exit, deletion, recovery, and server - * start/stop to ~/.claudeman/session-lifecycle.jsonl. Survives server restarts + * start/stop to ~/.codeman/session-lifecycle.jsonl. Survives server restarts * (unlike RunSummary which is in-memory only). * * @module session-lifecycle-log @@ -22,7 +22,7 @@ export class SessionLifecycleLog { private writeQueue: Promise = Promise.resolve(); constructor(filePath?: string) { - this.filePath = filePath || join(homedir(), '.claudeman', 'session-lifecycle.jsonl'); + this.filePath = filePath || join(homedir(), '.codeman', 'session-lifecycle.jsonl'); const dir = dirname(this.filePath); if (!existsSync(dir)) { mkdirSync(dir, { recursive: true, mode: 0o700 }); diff --git a/src/session.ts b/src/session.ts index 97f54059..8d64a404 100644 --- a/src/session.ts +++ b/src/session.ts @@ -400,8 +400,8 @@ export class Session extends EventEmitter { this.mode = config.mode || 'claude'; this._name = config.name || ''; this._lastActivityAt = this.createdAt; - // Set claudeSessionId immediately — Claudeman always passes --session-id ${this.id} - // to Claude CLI, so the Claude session ID always matches the Claudeman session ID. + // Set claudeSessionId immediately — Codeman always passes --session-id ${this.id} + // to Claude CLI, so the Claude session ID always matches the Codeman session ID. // This ensures subagent matching works even for recovered sessions (where // startInteractive() hasn't been called yet). this._claudeSessionId = this.id; @@ -1041,7 +1041,7 @@ export class Session extends EventEmitter { throw new Error('OpenCode sessions require tmux. Direct PTY fallback is not supported.'); } try { - // Pass --session-id to use the SAME ID as the Claudeman session + // Pass --session-id to use the SAME ID as the Codeman session // This ensures subagents can be directly matched to the correct tab const args = [...this._buildPermissionArgs(), '--session-id', this.id]; if (this._model) args.push('--model', this._model); @@ -1058,10 +1058,10 @@ export class Session extends EventEmitter { TERM: 'xterm-256color', COLORTERM: undefined, CLAUDECODE: undefined, - // Inform Claude it's running within Claudeman (helps prevent self-termination) - CLAUDEMAN_MUX: '1', - CLAUDEMAN_SESSION_ID: this.id, - CLAUDEMAN_API_URL: process.env.CLAUDEMAN_API_URL || 'http://localhost:3000', + // Inform Claude it's running within Codeman (helps prevent self-termination) + CODEMAN_MUX: '1', + CODEMAN_SESSION_ID: this.id, + CODEMAN_API_URL: process.env.CODEMAN_API_URL || 'http://localhost:3000', }, }); } catch (spawnErr) { @@ -1376,9 +1376,9 @@ export class Session extends EventEmitter { LANG: 'en_US.UTF-8', LC_ALL: 'en_US.UTF-8', TERM: 'xterm-256color', - CLAUDEMAN_MUX: '1', - CLAUDEMAN_SESSION_ID: this.id, - CLAUDEMAN_API_URL: process.env.CLAUDEMAN_API_URL || 'http://localhost:3000', + CODEMAN_MUX: '1', + CODEMAN_SESSION_ID: this.id, + CODEMAN_API_URL: process.env.CODEMAN_API_URL || 'http://localhost:3000', }, }); } catch (spawnErr) { @@ -1509,10 +1509,10 @@ export class Session extends EventEmitter { TERM: 'xterm-256color', COLORTERM: undefined, CLAUDECODE: undefined, - // Inform Claude it's running within Claudeman - CLAUDEMAN_MUX: '1', - CLAUDEMAN_SESSION_ID: this.id, - CLAUDEMAN_API_URL: process.env.CLAUDEMAN_API_URL || 'http://localhost:3000', + // Inform Claude it's running within Codeman + CODEMAN_MUX: '1', + CODEMAN_SESSION_ID: this.id, + CODEMAN_API_URL: process.env.CODEMAN_API_URL || 'http://localhost:3000', }, }); } catch (spawnErr) { @@ -1867,7 +1867,7 @@ export class Session extends EventEmitter { } // Parse Claude Code CLI info from terminal startup output - // Extracts version, model, and account type for display in Claudeman UI + // Extracts version, model, and account type for display in Codeman UI // Note: Expects cleanData with ANSI codes already stripped by caller private parseClaudeCodeInfo(cleanData: string): void { // Only parse once per session (during startup) diff --git a/src/state-store.ts b/src/state-store.ts index 5d64f335..cd872b90 100644 --- a/src/state-store.ts +++ b/src/state-store.ts @@ -1,8 +1,8 @@ /** - * @fileoverview Persistent JSON state storage for Claudeman. + * @fileoverview Persistent JSON state storage for Codeman. * * This module provides the StateStore class which persists application state - * to `~/.claudeman/state.json` with debounced writes to prevent excessive disk I/O. + * to `~/.codeman/state.json` with debounced writes to prevent excessive disk I/O. * * State is split into two files: * - `state.json`: Main app state (sessions, tasks, config) @@ -68,7 +68,23 @@ export class StateStore { private _saveInFlight: Promise | null = null; constructor(filePath?: string) { - this.filePath = filePath || join(homedir(), '.claudeman', 'state.json'); + // Migrate legacy data directory (~/.claudeman → ~/.codeman) + if (!filePath) { + const legacyDir = join(homedir(), '.claudeman'); + const newDir = join(homedir(), '.codeman'); + if (existsSync(legacyDir) && !existsSync(newDir)) { + console.log(`[state-store] Migrating data directory: ${legacyDir} → ${newDir}`); + renameSync(legacyDir, newDir); + } + const legacyCasesDir = join(homedir(), 'claudeman-cases'); + const newCasesDir = join(homedir(), 'codeman-cases'); + if (existsSync(legacyCasesDir) && !existsSync(newCasesDir)) { + console.log(`[state-store] Migrating cases directory: ${legacyCasesDir} → ${newCasesDir}`); + renameSync(legacyCasesDir, newCasesDir); + } + } + + this.filePath = filePath || join(homedir(), '.codeman', 'state.json'); this.ralphStatePath = this.filePath.replace('.json', '-inner.json'); this.state = this.load(); this.state.config.stateFilePath = this.filePath; diff --git a/src/subagent-watcher.ts b/src/subagent-watcher.ts index 7b725c86..e9008055 100644 --- a/src/subagent-watcher.ts +++ b/src/subagent-watcher.ts @@ -310,7 +310,7 @@ export class SubagentWatcher extends EventEmitter { /** * Run pgrep once and read /proc info for all Claude PIDs in parallel. * Returns a Map of pid -> { environ, cmdline } for subagent processes only. - * Excludes main Claudeman-managed Claude processes (CLAUDEMAN_MUX=1). + * Excludes main Codeman-managed Claude processes (CODEMAN_MUX=1). * Also updates cached PIDs on tracked agents when a match is found. */ private async getClaudePids(): Promise> { @@ -330,8 +330,8 @@ export class SubagentWatcher extends EventEmitter { let cmdline = ''; try { environ = await readFile(`/proc/${pid}/environ`, 'utf8'); } catch { /* skip */ } try { cmdline = await readFile(`/proc/${pid}/cmdline`, 'utf8'); } catch { /* skip */ } - // Skip main Claudeman-managed Claude processes — only track subagents - if (environ.includes('CLAUDEMAN_MUX=1')) return; + // Skip main Codeman-managed Claude processes — only track subagents + if (environ.includes('CODEMAN_MUX=1')) return; if (environ || cmdline) { result.set(pid, { environ, cmdline }); } @@ -562,8 +562,8 @@ export class SubagentWatcher extends EventEmitter { } /** - * Get subagents for a specific Claudeman session - * Maps Claudeman working directory to Claude's project hash + * Get subagents for a specific Codeman session + * Maps Codeman working directory to Claude's project hash */ getSubagentsForSession(workingDir: string): SubagentInfo[] { const projectHash = this.getProjectHash(workingDir); @@ -677,7 +677,7 @@ export class SubagentWatcher extends EventEmitter { } /** - * Kill all subagents for a specific Claudeman session. + * Kill all subagents for a specific Codeman session. * IMPORTANT: Must scope to sessionId to avoid cross-session kills. * All sessions in the same workingDir share a projectHash, so filtering * by workingDir alone would kill subagents belonging to OTHER sessions. @@ -696,7 +696,7 @@ export class SubagentWatcher extends EventEmitter { /** * Find the process ID of a Claude subagent by its session ID. * Searches /proc for claude processes with matching session ID in environment. - * Skips main Claudeman-managed Claude processes (identified by CLAUDEMAN_MUX=1). + * Skips main Codeman-managed Claude processes (identified by CODEMAN_MUX=1). * Caches the discovered PID on the matching agent info for future fast checks. */ private async findSubagentProcess(sessionId: string): Promise { @@ -721,9 +721,9 @@ export class SubagentWatcher extends EventEmitter { // Can't read this process's environ - skip } - // Defense-in-depth: never kill a main Claudeman-managed Claude process. - // Main processes have CLAUDEMAN_MUX=1 in their environment; subagents don't. - if (environ.includes('CLAUDEMAN_MUX=1')) continue; + // Defense-in-depth: never kill a main Codeman-managed Claude process. + // Main processes have CODEMAN_MUX=1 in their environment; subagents don't. + if (environ.includes('CODEMAN_MUX=1')) continue; if (environ.includes(sessionId)) { // Cache PID on the matching agent diff --git a/src/team-watcher.ts b/src/team-watcher.ts index d6346699..4087859e 100644 --- a/src/team-watcher.ts +++ b/src/team-watcher.ts @@ -2,7 +2,7 @@ * @fileoverview Agent Teams Watcher * * Polls ~/.claude/teams/ and ~/.claude/tasks/ for agent team activity. - * Matches teams to Claudeman sessions via leadSessionId and emits + * Matches teams to Codeman sessions via leadSessionId and emits * events for UI updates and team-aware idle detection. * * @module team-watcher @@ -70,7 +70,7 @@ export class TeamWatcher extends EventEmitter { return Array.from(this.teams.values()); } - /** Get team associated with a Claudeman session (matched by leadSessionId) */ + /** Get team associated with a Codeman session (matched by leadSessionId) */ getTeamForSession(sessionId: string): TeamConfig | undefined { const teamName = this.sessionToTeam.get(sessionId); if (teamName) { diff --git a/src/templates/case-template.md b/src/templates/case-template.md index 681a9469..97662c14 100644 --- a/src/templates/case-template.md +++ b/src/templates/case-template.md @@ -18,11 +18,11 @@ Then update the Project Overview section below. --- -## Claudeman Environment +## Codeman Environment -This session is managed by **Claudeman** and runs within a tmux session. +This session is managed by **Codeman** and runs within a tmux session. -**Important**: Check for `CLAUDEMAN_MUX=1` environment variable to confirm. +**Important**: Check for `CODEMAN_MUX=1` environment variable to confirm. - Do NOT attempt to kill your own tmux session - The session persists across disconnects - your work is safe - Token usage, costs, and background tasks are tracked externally diff --git a/src/templates/claude-md.ts b/src/templates/claude-md.ts index e2769886..dca10f83 100644 --- a/src/templates/claude-md.ts +++ b/src/templates/claude-md.ts @@ -1,7 +1,7 @@ /** * @fileoverview CLAUDE.md template generation * - * Generates CLAUDE.md configuration files for new Claudeman projects. + * Generates CLAUDE.md configuration files for new Codeman projects. * Reads the bundled case-template.md and performs placeholder substitution. * Supports custom templates via settings.json override. * diff --git a/src/tmux-manager.ts b/src/tmux-manager.ts index 94731a77..af62c836 100644 --- a/src/tmux-manager.ts +++ b/src/tmux-manager.ts @@ -10,7 +10,7 @@ * - **Reliable input**: `send-keys -l` sends literal text in a single command * - **Teammate support**: Immutable pane IDs enable targeting individual teammates * - * tmux sessions are named `claudeman-{sessionId}` and stored in ~/.claudeman/mux-sessions.json. + * tmux sessions are named `codeman-{sessionId}` and stored in ~/.codeman/mux-sessions.json. * * Key features: * - `send-keys 'text' Enter` sends literal text in a single command @@ -74,15 +74,18 @@ const DEFAULT_STATS_INTERVAL_MS = 2000; * - Create a tmux session * - Send input to a tmux session * - Discover/reconcile real tmux sessions - * - Read/write ~/.claudeman/mux-sessions.json + * - Read/write ~/.codeman/mux-sessions.json */ const IS_TEST_MODE = !!process.env.VITEST; /** Path to persisted mux session metadata */ -const MUX_SESSIONS_FILE = join(homedir(), '.claudeman', 'mux-sessions.json'); +const MUX_SESSIONS_FILE = join(homedir(), '.codeman', 'mux-sessions.json'); /** Regex to validate tmux session names (only allow safe characters) */ -const SAFE_MUX_NAME_PATTERN = /^claudeman-[a-f0-9-]+$/; +const SAFE_MUX_NAME_PATTERN = /^codeman-[a-f0-9-]+$/; + +/** Legacy pattern for pre-rename sessions (claudeman- prefix) */ +const LEGACY_MUX_NAME_PATTERN = /^claudeman-[a-f0-9-]+$/; /** Regex to validate tmux pane targets (e.g., "%0", "%1", "0", "1") */ const SAFE_PANE_TARGET_PATTERN = /^(%\d+|\d+)$/; @@ -92,7 +95,7 @@ const SAFE_PANE_TARGET_PATTERN = /^(%\d+|\d+)$/; * Prevents command injection via malformed session IDs. */ function isValidMuxName(name: string): boolean { - return SAFE_MUX_NAME_PATTERN.test(name); + return SAFE_MUX_NAME_PATTERN.test(name) || LEGACY_MUX_NAME_PATTERN.test(name); } /** @@ -336,7 +339,7 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer { */ async createSession(options: CreateSessionOptions): Promise { const { sessionId, workingDir, mode, name, niceConfig, model, claudeMode, allowedTools, openCodeConfig } = options; - const muxName = `claudeman-${sessionId.slice(0, 8)}`; + const muxName = `codeman-${sessionId.slice(0, 8)}`; if (!isValidMuxName(muxName)) { throw new Error('Invalid session name: contains unsafe characters'); @@ -382,10 +385,10 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer { 'export LANG=en_US.UTF-8', 'export LC_ALL=en_US.UTF-8', 'unset COLORTERM', - 'export CLAUDEMAN_MUX=1', - `export CLAUDEMAN_SESSION_ID=${sessionId}`, - `export CLAUDEMAN_MUX_NAME=${muxName}`, - `export CLAUDEMAN_API_URL=${process.env.CLAUDEMAN_API_URL || 'http://localhost:3000'}`, + 'export CODEMAN_MUX=1', + `export CODEMAN_SESSION_ID=${sessionId}`, + `export CODEMAN_MUX_NAME=${muxName}`, + `export CODEMAN_API_URL=${process.env.CODEMAN_API_URL || 'http://localhost:3000'}`, ]; // Only unset CLAUDECODE for Claude sessions if (mode === 'claude') envExports.splice(2, 0, 'unset CLAUDECODE'); @@ -440,7 +443,7 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer { // Mouse mode is OFF by default so xterm.js handles text selection natively. // It gets enabled dynamically when panes are split (agent teams). const configPromises: Promise[] = [ - // Disable tmux status bar — Claudeman's web UI provides session info + // Disable tmux status bar — Codeman's web UI provides session info execAsync(`tmux set-option -t "${muxName}" status off`, { timeout: EXEC_TIMEOUT_MS }) .then(() => {}).catch(() => { /* Non-critical — session still works with status bar */ }), // Override global remain-on-exit with session-level setting @@ -567,10 +570,10 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer { 'export LANG=en_US.UTF-8', 'export LC_ALL=en_US.UTF-8', 'unset COLORTERM', - 'export CLAUDEMAN_MUX=1', - `export CLAUDEMAN_SESSION_ID=${sessionId}`, - `export CLAUDEMAN_MUX_NAME=${muxName}`, - `export CLAUDEMAN_API_URL=${process.env.CLAUDEMAN_API_URL || 'http://localhost:3000'}`, + 'export CODEMAN_MUX=1', + `export CODEMAN_SESSION_ID=${sessionId}`, + `export CODEMAN_MUX_NAME=${muxName}`, + `export CODEMAN_API_URL=${process.env.CODEMAN_API_URL || 'http://localhost:3000'}`, ]; if (mode === 'claude') envExports.splice(2, 0, 'unset CLAUDECODE'); const envExportsStr = envExports.join(' && '); @@ -685,7 +688,7 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer { } // SAFETY: Never kill the tmux session we're running inside of - const currentMuxName = process.env.CLAUDEMAN_MUX_NAME; + const currentMuxName = process.env.CODEMAN_MUX_NAME; if (currentMuxName && session.muxName === currentMuxName) { console.error(`[TmuxManager] BLOCKED: Refusing to kill own tmux session: ${session.muxName}`); return false; @@ -824,7 +827,7 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer { } } - // Discover unknown claudeman sessions + // Discover unknown codeman sessions try { const output = execSync( "tmux list-sessions -F '#{session_name}' 2>/dev/null || true", @@ -833,7 +836,7 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer { for (const line of output.split('\n')) { const sessionName = line.trim(); - if (!sessionName || !sessionName.startsWith('claudeman-')) continue; + if (!sessionName || (!sessionName.startsWith('codeman-') && !sessionName.startsWith('claudeman-'))) continue; // Check if this session is already known let isKnown = false; @@ -846,7 +849,7 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer { if (!isKnown) { // Extract session ID fragment from name - const fragment = sessionName.replace('claudeman-', ''); + const fragment = sessionName.replace(/^(?:codeman|claudeman)-/, ''); const sessionId = `restored-${fragment}`; const pid = this.getPanePid(sessionName); @@ -1310,7 +1313,7 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer { return false; } - // Build target: sessionName.paneId (e.g., "claudeman-abc12345.%1") + // Build target: sessionName.paneId (e.g., "codeman-abc12345.%1") const target = paneTarget.startsWith('%') ? `${muxName}.${paneTarget}` : `${muxName}.%${paneTarget}`; diff --git a/src/types.ts b/src/types.ts index 69db2d49..342ac9a9 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,8 +1,8 @@ /** - * @fileoverview Type definitions for Claudeman + * @fileoverview Type definitions for Codeman * * This module contains all TypeScript interfaces, types, and enums used - * throughout the Claudeman application. It provides type safety for: + * throughout the Codeman application. It provides type safety for: * - Session management * - Task queue operations * - Ralph Loop configuration @@ -859,7 +859,7 @@ export const DEFAULT_CONFIG: AppConfig = { * Types for tracking Ralph Wiggum loops and todo lists * running inside Claude Code sessions. * - * This allows Claudeman to detect and display when Claude Code + * This allows Codeman to detect and display when Claude Code * is running its own autonomous loops internally. */ @@ -1369,7 +1369,7 @@ export interface ActiveBashTool { * Used to trigger automatic image popup display in the web UI. */ export interface ImageDetectedEvent { - /** Claudeman session ID where the image was detected */ + /** Codeman session ID where the image was detected */ sessionId: string; /** Full path to the detected image file */ filePath: string; diff --git a/src/web/public/app.js b/src/web/public/app.js index 932ff523..c174490f 100644 --- a/src/web/public/app.js +++ b/src/web/public/app.js @@ -1,4 +1,4 @@ -// Claudeman App - Tab-based Terminal UI +// Codeman App - Tab-based Terminal UI // ============================================================================ // Constants @@ -852,14 +852,14 @@ const VoiceInput = { _getDeepgramConfig() { try { - return JSON.parse(localStorage.getItem('claudeman-voice-settings') || '{}'); + return JSON.parse(localStorage.getItem('codeman-voice-settings') || '{}'); } catch (_e) { return {}; } }, _saveDeepgramConfig(config) { - localStorage.setItem('claudeman-voice-settings', JSON.stringify(config)); + localStorage.setItem('codeman-voice-settings', JSON.stringify(config)); }, _shouldUseDeepgram() { @@ -2294,7 +2294,7 @@ class NotificationManager { // Get storage key for notification prefs (device-specific) getStorageKey() { const isMobile = MobileDetection.getDeviceType() === 'mobile'; - return isMobile ? 'claudeman-notification-prefs-mobile' : 'claudeman-notification-prefs'; + return isMobile ? 'codeman-notification-prefs-mobile' : 'codeman-notification-prefs'; } savePreferences() { @@ -2449,11 +2449,11 @@ class NotificationManager { this.titleFlashInterval = setInterval(() => { this.titleFlashState = !this.titleFlashState; document.title = this.titleFlashState - ? `\u26A0\uFE0F (${this.unreadCount}) Claudeman` + ? `\u26A0\uFE0F (${this.unreadCount}) Codeman` : this.originalTitle; }, TITLE_FLASH_INTERVAL_MS); // Set immediately - document.title = `\u26A0\uFE0F (${this.unreadCount}) Claudeman`; + document.title = `\u26A0\uFE0F (${this.unreadCount}) Codeman`; } } } @@ -2488,7 +2488,7 @@ class NotificationManager { if (now - this.lastBrowserNotifTime < 3000) return; this.lastBrowserNotifTime = now; - const notif = new Notification(`Claudeman: ${title}`, { + const notif = new Notification(`Codeman: ${title}`, { body, tag, // Groups same-tag notifications icon: '/favicon.ico', @@ -2634,7 +2634,7 @@ class NotificationManager { } } -class ClaudemanApp { +class CodemanApp { constructor() { this.sessions = new Map(); this.sessionOrder = []; // Track tab order for drag-and-drop reordering @@ -2919,7 +2919,7 @@ class ClaudemanApp { initTerminal() { // Load scrollback setting from localStorage (default 5000) - const scrollback = parseInt(localStorage.getItem('claudeman-scrollback')) || DEFAULT_SCROLLBACK; + const scrollback = parseInt(localStorage.getItem('codeman-scrollback')) || DEFAULT_SCROLLBACK; this.terminal = new Terminal({ theme: { @@ -4023,7 +4023,7 @@ class ClaudemanApp { this._cleanupSessionData(data.id); if (this.activeSessionId === data.id) { this.activeSessionId = null; - try { localStorage.removeItem('claudeman-active-session'); } catch {} + try { localStorage.removeItem('codeman-active-session'); } catch {} this.terminal.clear(); this.showWelcome(); } @@ -4709,11 +4709,11 @@ class ClaudemanApp { } this.renderSubagentPanel(); - // Find which Claudeman session owns this subagent (direct claudeSessionId match only) + // Find which Codeman session owns this subagent (direct claudeSessionId match only) this.findParentSessionForSubagent(data.agentId); - // Auto-open window for new active agents — but ONLY if they belong to a Claudeman session tab. - // Agents from external Claude sessions (not managed by Claudeman) should not pop up. + // Auto-open window for new active agents — but ONLY if they belong to a Codeman session tab. + // Agents from external Claude sessions (not managed by Codeman) should not pop up. if (data.status === 'active') { const agentForCheck = this.subagents.get(data.agentId); const hasMatchingTab = agentForCheck?.sessionId && @@ -5106,11 +5106,11 @@ class ClaudemanApp { const headerVersionEl = this.$('headerVersion'); if (versionEl) { versionEl.textContent = `v${data.version}`; - versionEl.title = `Claudeman v${data.version}`; + versionEl.title = `Codeman v${data.version}`; } if (headerVersionEl) { headerVersionEl.textContent = `v${data.version}`; - headerVersionEl.title = `Claudeman v${data.version}`; + headerVersionEl.title = `Codeman v${data.version}`; } } @@ -5299,7 +5299,7 @@ class ClaudemanApp { // Priority: current active > localStorage > first session let restoreId = previousActiveId; if (!restoreId || !this.sessions.has(restoreId)) { - try { restoreId = localStorage.getItem('claudeman-active-session'); } catch {} + try { restoreId = localStorage.getItem('codeman-active-session'); } catch {} } if (restoreId && this.sessions.has(restoreId)) { this.selectSession(restoreId); @@ -5605,7 +5605,7 @@ class ClaudemanApp { // Load session order from localStorage loadSessionOrder() { try { - const saved = localStorage.getItem('claudeman-session-order'); + const saved = localStorage.getItem('codeman-session-order'); return saved ? JSON.parse(saved) : []; } catch { return []; @@ -5615,7 +5615,7 @@ class ClaudemanApp { // Save session order to localStorage saveSessionOrder() { try { - localStorage.setItem('claudeman-session-order', JSON.stringify(this.sessionOrder)); + localStorage.setItem('codeman-session-order', JSON.stringify(this.sessionOrder)); } catch { // Ignore storage errors } @@ -5924,7 +5924,7 @@ class ClaudemanApp { this._localEchoOverlay.suppressBufferDetection(); } this.activeSessionId = sessionId; - try { localStorage.setItem('claudeman-active-session', sessionId); } catch {} + try { localStorage.setItem('codeman-active-session', sessionId); } catch {} this.hideWelcome(); // Clear idle hooks on view, but keep action hooks until user interacts this.clearPendingHooks(sessionId, 'idle_prompt'); @@ -6160,7 +6160,7 @@ class ClaudemanApp { if (this.activeSessionId === sessionId) { this.activeSessionId = null; - try { localStorage.removeItem('claudeman-active-session'); } catch {} + try { localStorage.removeItem('codeman-active-session'); } catch {} // Select another session or show welcome (use sessionOrder for consistent ordering) if (this.sessionOrder.length > 0 && this.sessions.size > 0) { const nextSessionId = this.sessionOrder[0]; @@ -6242,7 +6242,7 @@ class ClaudemanApp { goHome() { // Deselect active session and show welcome screen this.activeSessionId = null; - try { localStorage.removeItem('claudeman-active-session'); } catch {} + try { localStorage.removeItem('codeman-active-session'); } catch {} this.terminal.clear(); this.showWelcome(); this.renderSessionTabs(); @@ -9250,7 +9250,7 @@ class ClaudemanApp { } else { // No cases exist yet - show the default case name as directory select.value = 'testcase'; - document.getElementById('dirDisplay').textContent = '~/claudeman-cases/testcase'; + document.getElementById('dirDisplay').textContent = '~/codeman-cases/testcase'; this.updateMobileCaseLabel('testcase'); } @@ -9317,7 +9317,7 @@ class ClaudemanApp { setRunMode(mode) { this._runMode = mode; - try { localStorage.setItem('claudeman_runMode', mode); } catch {} + try { localStorage.setItem('codeman_runMode', mode); } catch {} this._applyRunMode(); // Close menu document.getElementById('runModeMenu')?.classList.remove('active'); @@ -9361,7 +9361,7 @@ class ClaudemanApp { } _initRunMode() { - try { this._runMode = localStorage.getItem('claudeman_runMode') || 'claude'; } catch { this._runMode = 'claude'; } + try { this._runMode = localStorage.getItem('codeman_runMode') || 'claude'; } catch { this._runMode = 'claude'; } this._applyRunMode(); } @@ -10132,7 +10132,7 @@ class ClaudemanApp { this.terminalBuffers.clear(); this.terminalBufferCache.clear(); this.activeSessionId = null; - try { localStorage.removeItem('claudeman-active-session'); } catch {} + try { localStorage.removeItem('codeman-active-session'); } catch {} this.respawnStatus = {}; this.respawnCountdownTimers = {}; this.respawnActionLogs = {}; @@ -10239,13 +10239,13 @@ class ClaudemanApp { this.terminal.options.fontSize = size; document.getElementById('fontSizeDisplay').textContent = size; this.fitAddon.fit(); - localStorage.setItem('claudeman-font-size', size); + localStorage.setItem('codeman-font-size', size); // Update overlay font cache and re-render at new cell dimensions this._localEchoOverlay?.refreshFont(); } loadFontSize() { - const saved = localStorage.getItem('claudeman-font-size'); + const saved = localStorage.getItem('codeman-font-size'); if (saved) { const size = parseInt(saved, 10); if (size >= 10 && size <= 24) { @@ -10676,7 +10676,7 @@ class ClaudemanApp { // ========== Respawn Presets ========== loadRespawnPresets() { - const saved = localStorage.getItem('claudeman-respawn-presets'); + const saved = localStorage.getItem('codeman-respawn-presets'); const custom = saved ? JSON.parse(saved) : []; return [...BUILTIN_RESPAWN_PRESETS, ...custom]; } @@ -10684,7 +10684,7 @@ class ClaudemanApp { saveRespawnPresets(presets) { // Only save custom presets (not built-in) const custom = presets.filter(p => !p.builtIn); - localStorage.setItem('claudeman-respawn-presets', JSON.stringify(custom)); + localStorage.setItem('codeman-respawn-presets', JSON.stringify(custom)); } renderPresetDropdown() { @@ -11842,7 +11842,7 @@ class ClaudemanApp { // Get the settings storage key based on device type (mobile vs desktop) getSettingsStorageKey() { const isMobile = MobileDetection.getDeviceType() === 'mobile'; - return isMobile ? 'claudeman-app-settings-mobile' : 'claudeman-app-settings'; + return isMobile ? 'codeman-app-settings-mobile' : 'codeman-app-settings'; } // Get default settings based on device type @@ -12138,7 +12138,7 @@ class ClaudemanApp { // Sync voice settings from server (seed localStorage if no local API key) if (voiceSettings) { - const localVoice = localStorage.getItem('claudeman-voice-settings'); + const localVoice = localStorage.getItem('codeman-voice-settings'); if (!localVoice || !JSON.parse(localVoice).apiKey) { VoiceInput._saveDeepgramConfig(voiceSettings); } @@ -12179,7 +12179,7 @@ class ClaudemanApp { const windowStates = { minimized: minimizedState, open: openWindows }; // Save to localStorage for quick restore - localStorage.setItem('claudeman-subagent-window-states', JSON.stringify(windowStates)); + localStorage.setItem('codeman-subagent-window-states', JSON.stringify(windowStates)); // Save to server for cross-browser persistence try { @@ -12206,7 +12206,7 @@ class ClaudemanApp { if (res.ok) { states = await res.json(); // Also update localStorage - localStorage.setItem('claudeman-subagent-window-states', JSON.stringify(states)); + localStorage.setItem('codeman-subagent-window-states', JSON.stringify(states)); } } catch (err) { console.error('Failed to load subagent window states from server:', err); @@ -12215,7 +12215,7 @@ class ClaudemanApp { // Fallback to localStorage if (!states) { try { - const saved = localStorage.getItem('claudeman-subagent-window-states'); + const saved = localStorage.getItem('codeman-subagent-window-states'); if (saved) { states = JSON.parse(saved); } @@ -12321,7 +12321,7 @@ class ClaudemanApp { // Save to localStorage for instant recovery try { - localStorage.setItem('claudeman-subagent-parents', JSON.stringify(mapData)); + localStorage.setItem('codeman-subagent-parents', JSON.stringify(mapData)); } catch (err) { console.error('Failed to save subagent parents to localStorage:', err); } @@ -12351,7 +12351,7 @@ class ClaudemanApp { if (res.ok) { mapData = await res.json(); // Update localStorage as cache - localStorage.setItem('claudeman-subagent-parents', JSON.stringify(mapData)); + localStorage.setItem('codeman-subagent-parents', JSON.stringify(mapData)); } } catch (err) { console.error('Failed to load subagent parents from server:', err); @@ -12360,7 +12360,7 @@ class ClaudemanApp { // Fallback to localStorage if (!mapData) { try { - const saved = localStorage.getItem('claudeman-subagent-parents'); + const saved = localStorage.getItem('codeman-subagent-parents'); if (saved) { mapData = JSON.parse(saved); } @@ -14670,8 +14670,8 @@ class ClaudemanApp { const agent = this.subagents.get(agentId); if (!agent) return; - // Only open windows for agents that belong to a Claudeman-managed session tab. - // Agents from external Claude sessions (not tracked by Claudeman) should not pop up. + // Only open windows for agents that belong to a Codeman-managed session tab. + // Agents from external Claude sessions (not tracked by Codeman) should not pop up. if (agent.sessionId) { const hasMatchingTab = Array.from(this.sessions.values()).some(s => s.claudeSessionId === agent.sessionId); if (!hasMatchingTab) return; @@ -15610,7 +15610,7 @@ class ClaudemanApp { /** Open a standalone terminal window for a tmux-pane teammate (no subagent entry needed) */ openTeammateTerminalWindow(paneData) { - // Only open if the session has a tab in Claudeman + // Only open if the session has a tab in Codeman if (!this.sessions.has(paneData.sessionId)) return; // Use pane target as the unique ID for this window @@ -16831,7 +16831,7 @@ class ClaudemanApp { this.sessions.clear(); this.muxSessions = []; this.activeSessionId = null; - try { localStorage.removeItem('claudeman-active-session'); } catch {} + try { localStorage.removeItem('codeman-active-session'); } catch {} this.renderSessionTabs(); this.renderMuxSessions(); this.terminal.clear(); @@ -16842,7 +16842,7 @@ class ClaudemanApp { // Just remove tabs, keep mux sessions running this.sessions.clear(); this.activeSessionId = null; - try { localStorage.removeItem('claudeman-active-session'); } catch {} + try { localStorage.removeItem('codeman-active-session'); } catch {} this.renderSessionTabs(); this.terminal.clear(); this.terminal.reset(); @@ -17554,12 +17554,25 @@ class ClaudemanApp { escapeHtml(text) { if (!text) return ''; - return text.replace(ClaudemanApp._htmlEscapePattern, char => ClaudemanApp._htmlEscapeMap[char]); + return text.replace(CodemanApp._htmlEscapePattern, char => CodemanApp._htmlEscapeMap[char]); } } +// Migrate legacy localStorage keys (claudeman-* → codeman-*) +try { + for (let i = 0; i < localStorage.length; i++) { + const key = localStorage.key(i); + if (key && (key.startsWith('claudeman-') || key.startsWith('claudeman_'))) { + const newKey = key.replace(/^claudeman[-_]/, (m) => 'codeman' + m.charAt(m.length - 1)); + if (localStorage.getItem(newKey) === null) { + localStorage.setItem(newKey, localStorage.getItem(key)); + } + } + } +} catch {} + // Initialize -const app = new ClaudemanApp(); +const app = new CodemanApp(); // Expose for debugging/testing window.app = app; diff --git a/src/web/public/index.html b/src/web/public/index.html index e12e9992..67b94eee 100644 --- a/src/web/public/index.html +++ b/src/web/public/index.html @@ -6,7 +6,7 @@ - Claudeman + Codeman @@ -37,7 +37,7 @@

- Claudeman + Codeman
@@ -49,7 +49,7 @@
- +
@@ -231,7 +231,7 @@
-

Claudeman

+

Codeman

Manage AI Coding tools in persistent tmux sessions.

- v0.0.0 + v0.0.0
@@ -1086,7 +1086,7 @@ ?
- For remote access, HTTPS is required. Start with: claudeman web --https + For remote access, HTTPS is required. Start with: codeman web --https
Alerts
@@ -1222,7 +1222,7 @@
- + Comma-separated terms to boost recognition accuracy
@@ -1253,7 +1253,7 @@
- Letters, numbers, hyphens, underscores only. Created in ~/claudeman-cases/ + Letters, numbers, hyphens, underscores only. Created in ~/codeman-cases/
@@ -1265,7 +1265,7 @@
- Name to identify this case in Claudeman + Name to identify this case in Codeman
diff --git a/src/web/public/styles.css b/src/web/public/styles.css index b653ffae..29af4b3d 100644 --- a/src/web/public/styles.css +++ b/src/web/public/styles.css @@ -1,4 +1,4 @@ -/* Claudeman - Terminal-First UI */ +/* Codeman - Terminal-First UI */ :root { --bg-dark: #0a0a0a; diff --git a/src/web/public/upload.html b/src/web/public/upload.html index dbd88fc8..cec405cb 100644 --- a/src/web/public/upload.html +++ b/src/web/public/upload.html @@ -2,7 +2,7 @@ -Upload Screenshot - Claudeman +Upload Screenshot - Codeman
- ← Back to Claudeman + ← Back to Codeman

Upload Screenshot

Tap to select image

diff --git a/src/web/schemas.ts b/src/web/schemas.ts index 78082c12..3189cf91 100644 --- a/src/web/schemas.ts +++ b/src/web/schemas.ts @@ -39,7 +39,7 @@ const ALLOWED_ENV_PREFIXES = ['CLAUDE_CODE_', 'OPENCODE_']; /** Env var keys that are always blocked (security-sensitive) */ const BLOCKED_ENV_KEYS = new Set([ 'PATH', 'LD_PRELOAD', 'LD_LIBRARY_PATH', 'NODE_OPTIONS', - 'CLAUDEMAN_MUX_NAME', 'CLAUDEMAN_TMUX', + 'CODEMAN_MUX_NAME', 'CODEMAN_TMUX', 'OPENCODE_SERVER_PASSWORD', // Security-sensitive: server auth password ]); diff --git a/src/web/server.ts b/src/web/server.ts index 08077521..6e98f406 100644 --- a/src/web/server.ts +++ b/src/web/server.ts @@ -1,5 +1,5 @@ /** - * @fileoverview Claudeman web server and REST API + * @fileoverview Codeman web server and REST API * * Provides a Fastify-based web server with: * - REST API for session management, respawn control, and monitoring @@ -142,7 +142,7 @@ const MAX_HOOK_DATA_SIZE = 8 * 1024; // Maximum screenshot upload size (10MB) const MAX_SCREENSHOT_SIZE = 10 * 1024 * 1024; // Screenshots directory -const SCREENSHOTS_DIR = join(homedir(), '.claudeman', 'screenshots'); +const SCREENSHOTS_DIR = join(homedir(), '.codeman', 'screenshots'); // Stats collection interval (2 seconds) const STATS_COLLECTION_INTERVAL_MS = 2000; // Session limit wait time before retrying (5 seconds) @@ -272,10 +272,10 @@ function autoConfigureRalph(session: Session, workingDir: string, broadcast: (ev /** * Get or generate a self-signed TLS certificate for HTTPS. - * Certs are stored in ~/.claudeman/certs/ and reused across restarts. + * Certs are stored in ~/.codeman/certs/ and reused across restarts. */ function getOrCreateSelfSignedCert(): { key: string; cert: string } { - const certsDir = join(homedir(), '.claudeman', 'certs'); + const certsDir = join(homedir(), '.codeman', 'certs'); const keyPath = join(certsDir, 'server.key'); const certPath = join(certsDir, 'server.crt'); @@ -292,7 +292,7 @@ function getOrCreateSelfSignedCert(): { key: string; cert: string } { execSync( `openssl req -x509 -newkey rsa:2048 -nodes ` + `-keyout "${keyPath}" -out "${certPath}" ` + - `-days 365 -subj "/CN=claudeman" ` + + `-days 365 -subj "/CN=codeman" ` + `-addext "subjectAltName=DNS:localhost,IP:127.0.0.1,IP:0.0.0.0"`, { stdio: 'pipe' } ); @@ -582,10 +582,10 @@ export class WebServer extends EventEmitter { threshold: 1024, }); - // Optional HTTP Basic Auth (set CLAUDEMAN_PASSWORD env var to enable) - const authPassword = process.env.CLAUDEMAN_PASSWORD; + // Optional HTTP Basic Auth (set CODEMAN_PASSWORD env var to enable) + const authPassword = process.env.CODEMAN_PASSWORD; if (authPassword) { - const authUsername = process.env.CLAUDEMAN_USERNAME || 'admin'; + const authUsername = process.env.CODEMAN_USERNAME || 'admin'; const expectedHeader = 'Basic ' + Buffer.from(`${authUsername}:${authPassword}`).toString('base64'); this.app.addHook('onRequest', (req, reply, done) => { const auth = req.headers.authorization; @@ -593,7 +593,7 @@ export class WebServer extends EventEmitter { done(); return; } - reply.header('WWW-Authenticate', 'Basic realm="Claudeman"'); + reply.header('WWW-Authenticate', 'Basic realm="Codeman"'); reply.code(401).send('Unauthorized'); }); } @@ -2350,7 +2350,7 @@ export class WebServer extends EventEmitter { }); // Case management - const casesDir = join(homedir(), 'claudeman-cases'); + const casesDir = join(homedir(), 'codeman-cases'); this.app.get('/api/cases', async (): Promise => { const cases: CaseInfo[] = []; @@ -2372,7 +2372,7 @@ export class WebServer extends EventEmitter { } // Get linked cases - const linkedCasesFile = join(homedir(), '.claudeman', 'linked-cases.json'); + const linkedCasesFile = join(homedir(), '.codeman', 'linked-cases.json'); try { const linkedCases: Record = JSON.parse(await fs.readFile(linkedCasesFile, 'utf-8')); for (const [name, path] of Object.entries(linkedCases)) { @@ -2456,11 +2456,11 @@ export class WebServer extends EventEmitter { // Check if case name already exists in casesDir const casePath = join(casesDir, name); if (existsSync(casePath)) { - return createErrorResponse(ApiErrorCode.ALREADY_EXISTS, 'A case with this name already exists in claudeman-cases.'); + return createErrorResponse(ApiErrorCode.ALREADY_EXISTS, 'A case with this name already exists in codeman-cases.'); } // Load existing linked cases - const linkedCasesFile = join(homedir(), '.claudeman', 'linked-cases.json'); + const linkedCasesFile = join(homedir(), '.codeman', 'linked-cases.json'); let linkedCases: Record = {}; try { linkedCases = JSON.parse(await fs.readFile(linkedCasesFile, 'utf-8')); @@ -2478,9 +2478,9 @@ export class WebServer extends EventEmitter { // Save the linked case linkedCases[name] = expandedPath; try { - const claudemanDir = join(homedir(), '.claudeman'); - if (!existsSync(claudemanDir)) { - mkdirSync(claudemanDir, { recursive: true }); + const codemanDir = join(homedir(), '.codeman'); + if (!existsSync(codemanDir)) { + mkdirSync(codemanDir, { recursive: true }); } await fs.writeFile(linkedCasesFile, JSON.stringify(linkedCases, null, 2)); this.broadcast('case:linked', { name, path: expandedPath }); @@ -2494,7 +2494,7 @@ export class WebServer extends EventEmitter { const { name } = req.params as { name: string }; // First check linked cases - const linkedCasesFile = join(homedir(), '.claudeman', 'linked-cases.json'); + const linkedCasesFile = join(homedir(), '.codeman', 'linked-cases.json'); try { const linkedCases: Record = JSON.parse(await fs.readFile(linkedCasesFile, 'utf-8')); if (linkedCases[name]) { @@ -2531,7 +2531,7 @@ export class WebServer extends EventEmitter { // Get case path (check linked cases first, then casesDir) let casePath: string | null = null; - const linkedCasesFile = join(homedir(), '.claudeman', 'linked-cases.json'); + const linkedCasesFile = join(homedir(), '.codeman', 'linked-cases.json'); try { const linkedCases: Record = JSON.parse(await fs.readFile(linkedCasesFile, 'utf-8')); if (linkedCases[name]) { @@ -2737,7 +2737,7 @@ export class WebServer extends EventEmitter { // Save lastUsedCase to settings for TUI/web sync try { - const settingsFilePath = join(homedir(), '.claudeman', 'settings.json'); + const settingsFilePath = join(homedir(), '.codeman', 'settings.json'); let settings: Record = {}; try { settings = JSON.parse(await fs.readFile(settingsFilePath, 'utf-8')); @@ -2974,7 +2974,7 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; // Determine output directory for saving wizard results let outputDir: string | undefined; if (caseName) { - const casesDir = join(homedir(), 'claudeman-cases'); + const casesDir = join(homedir(), 'codeman-cases'); const casePath = join(casesDir, caseName); // Security: Path traversal protection - use relative path check const resolvedCase = resolve(casePath); @@ -3101,7 +3101,7 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; // Get ralph-wizard files for a case (prompts and results) this.app.get('/api/cases/:caseName/ralph-wizard/files', async (req) => { const { caseName } = req.params as { caseName: string }; - const casesDir = join(homedir(), 'claudeman-cases'); + const casesDir = join(homedir(), 'codeman-cases'); let casePath = join(casesDir, caseName); // Security: Path traversal protection - use relative path check @@ -3114,7 +3114,7 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; // Check linked cases if path doesn't exist if (!existsSync(casePath)) { - const linkedCasesFile = join(homedir(), '.claudeman', 'linked-cases.json'); + const linkedCasesFile = join(homedir(), '.codeman', 'linked-cases.json'); try { const linkedCases: Record = JSON.parse(await fs.readFile(linkedCasesFile, 'utf-8')); if (linkedCases[caseName]) { @@ -3162,7 +3162,7 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; // Cache disabled to ensure fresh prompts when starting new plan generations this.app.get('/api/cases/:caseName/ralph-wizard/file/:filePath', async (req, reply) => { const { caseName, filePath } = req.params as { caseName: string; filePath: string }; - const casesDir = join(homedir(), 'claudeman-cases'); + const casesDir = join(homedir(), 'codeman-cases'); let casePath = join(casesDir, caseName); // Prevent browser caching - prompts change between plan generations @@ -3180,7 +3180,7 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; // Check linked cases if path doesn't exist if (!existsSync(casePath)) { - const linkedCasesFile = join(homedir(), '.claudeman', 'linked-cases.json'); + const linkedCasesFile = join(homedir(), '.codeman', 'linked-cases.json'); try { const linkedCases: Record = JSON.parse(await fs.readFile(linkedCasesFile, 'utf-8')); if (linkedCases[caseName]) { @@ -3369,7 +3369,7 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; }); // ============ App Settings Endpoints ============ - const settingsPath = join(homedir(), '.claudeman', 'settings.json'); + const settingsPath = join(homedir(), '.codeman', 'settings.json'); this.app.get('/api/settings', async () => { try { @@ -3520,7 +3520,7 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; // ============ Subagent Window State Endpoints ============ // Persists minimized/open window states for cross-browser sync - const windowStatesPath = join(homedir(), '.claudeman', 'subagent-window-states.json'); + const windowStatesPath = join(homedir(), '.codeman', 'subagent-window-states.json'); this.app.get('/api/subagent-window-states', async () => { try { @@ -3555,7 +3555,7 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; // ============ Subagent Parent Associations ============ // Persists which TAB each agent window connects to. // This is the PERMANENT record of agent -> tab associations. - const parentMapPath = join(homedir(), '.claudeman', 'subagent-parents.json'); + const parentMapPath = join(homedir(), '.codeman', 'subagent-parents.json'); this.app.get('/api/subagent-parents', async () => { try { @@ -3836,7 +3836,7 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; ext = map[ctMatch[1].toLowerCase()] ?? ext; } - // Save to ~/.claudeman/screenshots/ + // Save to ~/.codeman/screenshots/ if (!existsSync(SCREENSHOTS_DIR)) { mkdirSync(SCREENSHOTS_DIR, { recursive: true }); } @@ -4707,7 +4707,7 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; // Helper to get custom CLAUDE.md template path from settings private async getDefaultClaudeMdPath(): Promise { - const settingsPath = join(homedir(), '.claudeman', 'settings.json'); + const settingsPath = join(homedir(), '.codeman', 'settings.json'); try { const content = await fs.readFile(settingsPath, 'utf-8'); @@ -4723,7 +4723,7 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; return undefined; } - // Read ~/.claudeman/settings.json once and return the parsed object. + // Read ~/.codeman/settings.json once and return the parsed object. // Cached for 2s to avoid redundant reads during session creation bursts. private _settingsCache: { data: Record; ts: number } | null = null; private async readSettings(): Promise> { @@ -4731,7 +4731,7 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; if (this._settingsCache && now - this._settingsCache.ts < 2000) { return this._settingsCache.data; } - const settingsPath = join(homedir(), '.claudeman', 'settings.json'); + const settingsPath = join(homedir(), '.codeman', 'settings.json'); try { const content = await fs.readFile(settingsPath, 'utf-8'); const data = JSON.parse(content) as Record; @@ -5293,10 +5293,10 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; await this.app.listen({ port: this.port, host: '0.0.0.0' }); const protocol = this.https ? 'https' : 'http'; - console.log(`Claudeman web interface running at ${protocol}://localhost:${this.port}`); + console.log(`Codeman web interface running at ${protocol}://localhost:${this.port}`); // Set API URL for child processes (MCP server, spawned sessions) - process.env.CLAUDEMAN_API_URL = `${protocol}://localhost:${this.port}`; + process.env.CODEMAN_API_URL = `${protocol}://localhost:${this.port}`; // Start scheduled runs cleanup timer this.scheduledCleanupTimer = setInterval(() => { @@ -5339,7 +5339,7 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; * Check if subagent tracking is enabled in settings (default: true) */ private async isSubagentTrackingEnabled(): Promise { - const settingsPath = join(homedir(), '.claudeman', 'settings.json'); + const settingsPath = join(homedir(), '.codeman', 'settings.json'); try { const content = await fs.readFile(settingsPath, 'utf-8'); const settings = JSON.parse(content); @@ -5357,7 +5357,7 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; * Check if image watcher is enabled in settings (default: false) */ private async isImageWatcherEnabled(): Promise { - const settingsPath = join(homedir(), '.claudeman', 'settings.json'); + const settingsPath = join(homedir(), '.codeman', 'settings.json'); try { const content = await fs.readFile(settingsPath, 'utf-8'); const settings = JSON.parse(content); diff --git a/test/ai-idle-checker.test.ts b/test/ai-idle-checker.test.ts index 6f66962e..342b06d5 100644 --- a/test/ai-idle-checker.test.ts +++ b/test/ai-idle-checker.test.ts @@ -149,7 +149,7 @@ describe('AiIdleChecker', () => { // Verify tmux was spawned with correct args expect(mockedSpawn).toHaveBeenCalledWith( 'tmux', - expect.arrayContaining(['new-session', '-d', '-s', expect.stringContaining('claudeman-aicheck-')]), + expect.arrayContaining(['new-session', '-d', '-s', expect.stringContaining('codeman-aicheck-')]), expect.objectContaining({ detached: true, stdio: 'ignore' }) ); }); @@ -163,7 +163,7 @@ describe('AiIdleChecker', () => { // First call should try to kill existing session expect(mockedExecSync).toHaveBeenCalledWith( - expect.stringContaining('tmux kill-session -t "claudeman-aicheck-'), + expect.stringContaining('tmux kill-session -t "codeman-aicheck-'), expect.any(Object) ); }); @@ -176,7 +176,7 @@ describe('AiIdleChecker', () => { await checkPromise; expect(mockedWriteFileSync).toHaveBeenCalledWith( - expect.stringContaining('claudeman-aicheck-'), + expect.stringContaining('codeman-aicheck-'), '' ); }); diff --git a/test/api-responses.test.ts b/test/api-responses.test.ts index 6f7f7ea8..8db04c33 100644 --- a/test/api-responses.test.ts +++ b/test/api-responses.test.ts @@ -537,7 +537,7 @@ describe('API Response Structures', () => { it('should validate case info', () => { const caseInfo: CaseInfo = { name: 'my-project', - path: '/home/user/claudeman-cases/my-project', + path: '/home/user/codeman-cases/my-project', hasClaudeMd: true, }; @@ -549,7 +549,7 @@ describe('API Response Structures', () => { it('should handle optional hasClaudeMd', () => { const caseInfo: CaseInfo = { name: 'new-project', - path: '/home/user/claudeman-cases/new-project', + path: '/home/user/codeman-cases/new-project', }; expect(caseInfo.hasClaudeMd).toBeUndefined(); diff --git a/test/buffer-management.test.ts b/test/buffer-management.test.ts index 62251a48..1940eecc 100644 --- a/test/buffer-management.test.ts +++ b/test/buffer-management.test.ts @@ -1,7 +1,7 @@ /** * @fileoverview Tests for buffer management and memory limits * - * Tests the buffer management strategies used in Claudeman sessions + * Tests the buffer management strategies used in Codeman sessions * for handling large terminal output and message storage. */ diff --git a/test/cli-commands.test.ts b/test/cli-commands.test.ts index 68501c79..db903c41 100644 --- a/test/cli-commands.test.ts +++ b/test/cli-commands.test.ts @@ -318,7 +318,7 @@ describe('CLI Command Parsing', () => { describe('Help Text Generation', () => { const generateHelp = (command: string, description: string, options: string[]): string => { - let help = `Usage: claudeman ${command}\n\n`; + let help = `Usage: codeman ${command}\n\n`; help += `${description}\n`; if (options.length > 0) { help += '\nOptions:\n'; @@ -331,7 +331,7 @@ describe('CLI Command Parsing', () => { it('should generate basic help', () => { const help = generateHelp('status', 'Show overall status', []); - expect(help).toContain('Usage: claudeman status'); + expect(help).toContain('Usage: codeman status'); expect(help).toContain('Show overall status'); }); @@ -724,8 +724,8 @@ describe('CLI Configuration', () => { maxConcurrentSessions: 5, defaultPort: 3000, defaultHost: '0.0.0.0', - casesDirectory: '~/claudeman-cases', - stateDirectory: '~/.claudeman', + casesDirectory: '~/codeman-cases', + stateDirectory: '~/.codeman', }; const expandPath = (path: string): string => { @@ -742,8 +742,8 @@ describe('CLI Configuration', () => { }); it('should expand home directory paths', () => { - expect(expandPath('~/claudeman-cases')).toBe('/home/user/claudeman-cases'); - expect(expandPath('~/.claudeman')).toBe('/home/user/.claudeman'); + expect(expandPath('~/codeman-cases')).toBe('/home/user/codeman-cases'); + expect(expandPath('~/.codeman')).toBe('/home/user/.codeman'); }); it('should not modify absolute paths', () => { diff --git a/test/edge-cases.test.ts b/test/edge-cases.test.ts index 38de6e8f..5e03b575 100644 --- a/test/edge-cases.test.ts +++ b/test/edge-cases.test.ts @@ -5,7 +5,7 @@ import { join } from 'node:path'; import { homedir } from 'node:os'; const TEST_PORT = 3110; -const CASES_DIR = join(homedir(), 'claudeman-cases'); +const CASES_DIR = join(homedir(), 'codeman-cases'); describe('Edge Cases and Error Handling', () => { let server: WebServer; @@ -349,7 +349,7 @@ describe('Concurrent Session Handling', () => { const { join } = await import('node:path'); const { homedir } = await import('node:os'); for (const name of createdCases) { - const path = join(homedir(), 'claudeman-cases', name); + const path = join(homedir(), 'codeman-cases', name); if (existsSync(path)) { rmSync(path, { recursive: true, force: true }); } diff --git a/test/file-link-click.test.ts b/test/file-link-click.test.ts index 57065ed4..0e37cafb 100644 --- a/test/file-link-click.test.ts +++ b/test/file-link-click.test.ts @@ -1,5 +1,5 @@ /** - * File Link Click Tests for Claudeman Web UI + * File Link Click Tests for Codeman Web UI * * Tests that file paths displayed in terminal output are clickable * and open the log viewer window correctly. @@ -88,7 +88,7 @@ describe('File Link Click Tests', () => { closeBrowser(); // Create test directory and log file - testDir = join(tmpdir(), `claudeman-link-test-${Date.now()}`); + testDir = join(tmpdir(), `codeman-link-test-${Date.now()}`); mkdirSync(testDir, { recursive: true }); testLogFile = join(testDir, 'test.log'); writeFileSync(testLogFile, '=== Test Log Started ===\n'); @@ -102,7 +102,7 @@ describe('File Link Click Tests', () => { browser(`open ${baseUrl}`); await new Promise(r => setTimeout(r, 2000)); const title = browserJson<{ title: string }>('get title'); - browserAvailable = title.title === 'Claudeman'; + browserAvailable = title.title === 'Codeman'; } catch (e) { console.warn('Browser not available, skipping browser tests:', (e as Error).message); browserAvailable = false; diff --git a/test/hooks-config.test.ts b/test/hooks-config.test.ts index a85786ff..3c4fa688 100644 --- a/test/hooks-config.test.ts +++ b/test/hooks-config.test.ts @@ -54,8 +54,8 @@ describe('generateHooksConfig', () => { const config = generateHooksConfig(); const notifHooks = config.hooks.Notification as Array<{ hooks: Array<{ command: string }> }>; const cmd = notifHooks[0].hooks[0].command; - expect(cmd).toContain('$CLAUDEMAN_API_URL'); - expect(cmd).toContain('$CLAUDEMAN_SESSION_ID'); + expect(cmd).toContain('$CODEMAN_API_URL'); + expect(cmd).toContain('$CODEMAN_SESSION_ID'); expect(cmd).not.toContain('localhost'); }); @@ -99,7 +99,7 @@ describe('generateHooksConfig', () => { }); describe('writeHooksConfig', () => { - const testDir = join(tmpdir(), 'claudeman-hooks-test-' + Date.now()); + const testDir = join(tmpdir(), 'codeman-hooks-test-' + Date.now()); beforeEach(() => { if (!existsSync(testDir)) { @@ -648,8 +648,8 @@ describe('Hook Config Generation - Extended', () => { const config = generateHooksConfig(); const notifHooks = config.hooks.Notification as Array<{ hooks: Array<{ command: string }> }>; const cmd = notifHooks[0].hooks[0].command; - expect(cmd).toContain('$CLAUDEMAN_API_URL'); - expect(cmd).toContain('$CLAUDEMAN_SESSION_ID'); + expect(cmd).toContain('$CODEMAN_API_URL'); + expect(cmd).toContain('$CODEMAN_SESSION_ID'); }); it('should generate POST curl commands', () => { diff --git a/test/input-echo-test.mjs b/test/input-echo-test.mjs index 768d4f19..322fa580 100644 --- a/test/input-echo-test.mjs +++ b/test/input-echo-test.mjs @@ -96,7 +96,7 @@ async function main() { page.on('console', msg => consoleLogs.push(`[${msg.type()}] ${msg.text()}`)); try { - console.log('Opening Claudeman...'); + console.log('Opening Codeman...'); await page.goto(BASE); await page.waitForSelector('.xterm-screen', { timeout: 10000 }); await page.waitForTimeout(2000); diff --git a/test/integration-flows.test.ts b/test/integration-flows.test.ts index a13baa83..51aba94b 100644 --- a/test/integration-flows.test.ts +++ b/test/integration-flows.test.ts @@ -5,7 +5,7 @@ import { join } from 'node:path'; import { homedir } from 'node:os'; const TEST_PORT = 3115; -const CASES_DIR = join(homedir(), 'claudeman-cases'); +const CASES_DIR = join(homedir(), 'codeman-cases'); /** * Integration tests for complete user flows diff --git a/test/local-echo-basic-test.mjs b/test/local-echo-basic-test.mjs index 7f67fd01..ca486172 100644 --- a/test/local-echo-basic-test.mjs +++ b/test/local-echo-basic-test.mjs @@ -149,9 +149,9 @@ async function main() { // Enable local echo await page.evaluate(() => { - const s = JSON.parse(localStorage.getItem('claudeman-app-settings') || '{}'); + const s = JSON.parse(localStorage.getItem('codeman-app-settings') || '{}'); s.localEchoEnabled = true; - localStorage.setItem('claudeman-app-settings', JSON.stringify(s)); + localStorage.setItem('codeman-app-settings', JSON.stringify(s)); window.app?._updateLocalEchoState?.(); }); diff --git a/test/local-echo-daily-test.mjs b/test/local-echo-daily-test.mjs index e51e2649..ade03727 100644 --- a/test/local-echo-daily-test.mjs +++ b/test/local-echo-daily-test.mjs @@ -117,9 +117,9 @@ async function main() { // Enable local echo await page.evaluate(() => { - const s = JSON.parse(localStorage.getItem('claudeman-app-settings') || '{}'); + const s = JSON.parse(localStorage.getItem('codeman-app-settings') || '{}'); s.localEchoEnabled = true; - localStorage.setItem('claudeman-app-settings', JSON.stringify(s)); + localStorage.setItem('codeman-app-settings', JSON.stringify(s)); window.app?._updateLocalEchoState?.(); }); diff --git a/test/local-echo-edge-test.mjs b/test/local-echo-edge-test.mjs index 711074cd..005c3841 100644 --- a/test/local-echo-edge-test.mjs +++ b/test/local-echo-edge-test.mjs @@ -120,9 +120,9 @@ async function main() { // Enable local echo await page.evaluate(() => { - const s = JSON.parse(localStorage.getItem('claudeman-app-settings') || '{}'); + const s = JSON.parse(localStorage.getItem('codeman-app-settings') || '{}'); s.localEchoEnabled = true; - localStorage.setItem('claudeman-app-settings', JSON.stringify(s)); + localStorage.setItem('codeman-app-settings', JSON.stringify(s)); window.app?._updateLocalEchoState?.(); }); @@ -307,7 +307,7 @@ async function main() { await page.keyboard.type('will-be-lost', { delay: 20 }); await page.waitForTimeout(200); - const lsBefore = await page.evaluate(() => localStorage.getItem('claudeman_local_echo_pending')); + const lsBefore = await page.evaluate(() => localStorage.getItem('codeman_local_echo_pending')); if (!lsBefore) pass('localStorage not written (persist is no-op)'); else fail('localStorage written', `value="${lsBefore}"`); diff --git a/test/local-echo-mobile-test.mjs b/test/local-echo-mobile-test.mjs index d4b0bd44..07434f8c 100644 --- a/test/local-echo-mobile-test.mjs +++ b/test/local-echo-mobile-test.mjs @@ -227,7 +227,7 @@ async function main() { try { // ── SETUP ── - console.log('Opening Claudeman...'); + console.log('Opening Codeman...'); await page.goto(BASE, { waitUntil: 'domcontentloaded' }); await page.waitForSelector('.xterm-screen', { timeout: 10000 }); await page.waitForTimeout(2000); @@ -235,9 +235,9 @@ async function main() { // Enable local echo via settings console.log('Enabling local echo...'); await page.evaluate(() => { - const settings = JSON.parse(localStorage.getItem('claudeman-app-settings') || '{}'); + const settings = JSON.parse(localStorage.getItem('codeman-app-settings') || '{}'); settings.localEchoEnabled = true; - localStorage.setItem('claudeman-app-settings', JSON.stringify(settings)); + localStorage.setItem('codeman-app-settings', JSON.stringify(settings)); window.app?._updateLocalEchoState?.(); }); await page.waitForTimeout(300); diff --git a/test/local-echo-scroll-test.mjs b/test/local-echo-scroll-test.mjs index 12d4e62a..7c28133d 100644 --- a/test/local-echo-scroll-test.mjs +++ b/test/local-echo-scroll-test.mjs @@ -126,9 +126,9 @@ async function main() { // Enable local echo await page.evaluate(() => { - const s = JSON.parse(localStorage.getItem('claudeman-app-settings') || '{}'); + const s = JSON.parse(localStorage.getItem('codeman-app-settings') || '{}'); s.localEchoEnabled = true; - localStorage.setItem('claudeman-app-settings', JSON.stringify(s)); + localStorage.setItem('codeman-app-settings', JSON.stringify(s)); window.app?._updateLocalEchoState?.(); }); diff --git a/test/local-echo-tabswitch-test.mjs b/test/local-echo-tabswitch-test.mjs index 67021511..b4c181b5 100644 --- a/test/local-echo-tabswitch-test.mjs +++ b/test/local-echo-tabswitch-test.mjs @@ -144,7 +144,7 @@ async function main() { try { // ── SETUP ── - console.log('Opening Claudeman...'); + console.log('Opening Codeman...'); await page.goto(BASE, { waitUntil: 'domcontentloaded' }); await page.waitForSelector('.xterm-screen', { timeout: 10000 }); await page.waitForTimeout(2500); @@ -152,7 +152,7 @@ async function main() { // Enable local echo console.log('Enabling local echo...'); await page.evaluate(() => { - const key = window.app?.getSettingsStorageKey?.() || 'claudeman-app-settings'; + const key = window.app?.getSettingsStorageKey?.() || 'codeman-app-settings'; const settings = JSON.parse(localStorage.getItem(key) || '{}'); settings.localEchoEnabled = true; localStorage.setItem(key, JSON.stringify(settings)); diff --git a/test/local-echo-user-test.mjs b/test/local-echo-user-test.mjs index f26c37e0..b0b633f8 100644 --- a/test/local-echo-user-test.mjs +++ b/test/local-echo-user-test.mjs @@ -241,9 +241,9 @@ async function main() { // Enable local echo await page.evaluate(() => { - const s = JSON.parse(localStorage.getItem('claudeman-app-settings') || '{}'); + const s = JSON.parse(localStorage.getItem('codeman-app-settings') || '{}'); s.localEchoEnabled = true; - localStorage.setItem('claudeman-app-settings', JSON.stringify(s)); + localStorage.setItem('codeman-app-settings', JSON.stringify(s)); window.app?._updateLocalEchoState?.(); }); @@ -916,9 +916,9 @@ async function main() { await page.evaluate((id) => document.querySelector(`.session-tab[data-id="${id}"]`)?.click(), sA); await page.waitForTimeout(2000); await page.evaluate(() => { - const s = JSON.parse(localStorage.getItem('claudeman-app-settings') || '{}'); + const s = JSON.parse(localStorage.getItem('codeman-app-settings') || '{}'); s.localEchoEnabled = true; - localStorage.setItem('claudeman-app-settings', JSON.stringify(s)); + localStorage.setItem('codeman-app-settings', JSON.stringify(s)); window.app?._updateLocalEchoState?.(); }); await page.waitForTimeout(300); diff --git a/test/memory-leak-prevention.test.ts b/test/memory-leak-prevention.test.ts index 30351ea3..f7a75e7d 100644 --- a/test/memory-leak-prevention.test.ts +++ b/test/memory-leak-prevention.test.ts @@ -2,7 +2,7 @@ * @fileoverview Tests for memory leak prevention patterns * * These tests verify the cleanup patterns used to prevent memory leaks - * in long-running Claudeman sessions (P1 improvements from P0 fixes). + * in long-running Codeman sessions (P1 improvements from P0 fixes). * * Port: N/A (unit tests, no server) */ diff --git a/test/perf-subagent-load.test.ts b/test/perf-subagent-load.test.ts index 84d6fb5a..9cbb1bcd 100644 --- a/test/perf-subagent-load.test.ts +++ b/test/perf-subagent-load.test.ts @@ -1,5 +1,5 @@ /** - * Performance tests: Claudeman responsiveness under subagent load + * Performance tests: Codeman responsiveness under subagent load * * Measures event loop lag caused by: * 1. SubagentWatcher processing many agent files simultaneously @@ -112,7 +112,7 @@ describe('SubagentWatcher performance', () => { let projectsDir: string; beforeEach(() => { - tmpDir = mkdtempSync(join(tmpdir(), 'claudeman-perf-')); + tmpDir = mkdtempSync(join(tmpdir(), 'codeman-perf-')); projectsDir = join(tmpDir, 'projects'); mkdirSync(projectsDir, { recursive: true }); }); diff --git a/test/quick-start.test.ts b/test/quick-start.test.ts index 9a97298b..6b16dc74 100644 --- a/test/quick-start.test.ts +++ b/test/quick-start.test.ts @@ -5,7 +5,7 @@ import { join } from 'node:path'; import { homedir } from 'node:os'; const TEST_PORT = 3099; -const CASES_DIR = join(homedir(), 'claudeman-cases'); +const CASES_DIR = join(homedir(), 'codeman-cases'); describe('Quick Start API', () => { let server: WebServer; diff --git a/test/ralph-integration.test.ts b/test/ralph-integration.test.ts index a7fa9584..d84b9a6c 100644 --- a/test/ralph-integration.test.ts +++ b/test/ralph-integration.test.ts @@ -18,7 +18,7 @@ import { join } from 'node:path'; import { homedir } from 'node:os'; const TEST_PORT = 3125; -const CASES_DIR = join(homedir(), 'claudeman-cases'); +const CASES_DIR = join(homedir(), 'codeman-cases'); describe('Ralph Integration Tests', () => { let server: WebServer; diff --git a/test/respawn-analysis.md b/test/respawn-analysis.md index 32d152b2..ef73b374 100644 --- a/test/respawn-analysis.md +++ b/test/respawn-analysis.md @@ -2,10 +2,10 @@ **Date**: 2026-01-25 **Analyzed Files**: -- `/home/arkon/default/claudeman/src/respawn-controller.ts` -- `/home/arkon/default/claudeman/src/ai-idle-checker.ts` -- `/home/arkon/default/claudeman/src/ai-plan-checker.ts` -- `/home/arkon/default/claudeman/test/respawn-controller.test.ts` +- `/home/arkon/default/codeman/src/respawn-controller.ts` +- `/home/arkon/default/codeman/src/ai-idle-checker.ts` +- `/home/arkon/default/codeman/src/ai-plan-checker.ts` +- `/home/arkon/default/codeman/test/respawn-controller.test.ts` --- @@ -55,7 +55,7 @@ The following areas lack test coverage: ### Issue 1: E2BIG Error in ai-plan-checker.ts (HIGH) -**File**: `/home/arkon/default/claudeman/src/ai-plan-checker.ts` +**File**: `/home/arkon/default/codeman/src/ai-plan-checker.ts` **Lines**: 341-346 **Severity**: HIGH @@ -84,7 +84,7 @@ const claudeCmd = `cat "${this.checkPromptFile}" | claude -p ${modelArg} --outpu ### Issue 2: Missing Prompt File Cleanup on Timeout (MEDIUM) -**File**: `/home/arkon/default/claudeman/src/ai-idle-checker.ts` +**File**: `/home/arkon/default/codeman/src/ai-idle-checker.ts` **Lines**: 392-398 **Severity**: MEDIUM @@ -98,7 +98,7 @@ const claudeCmd = `cat "${this.checkPromptFile}" | claude -p ${modelArg} --outpu ### Issue 3: Race Condition in cancel() with Promise Resolution (MEDIUM) -**File**: `/home/arkon/default/claudeman/src/ai-idle-checker.ts` +**File**: `/home/arkon/default/codeman/src/ai-idle-checker.ts` **Lines**: 265-279 **Severity**: MEDIUM @@ -127,7 +127,7 @@ cancel(): void { ### Issue 4: Stale Screen Name Collision (LOW) -**File**: `/home/arkon/default/claudeman/src/ai-idle-checker.ts`, `ai-plan-checker.ts` +**File**: `/home/arkon/default/codeman/src/ai-idle-checker.ts`, `ai-plan-checker.ts` **Lines**: 326-329 (idle), 333-336 (plan) **Severity**: LOW @@ -135,21 +135,21 @@ cancel(): void { **Code**: ```typescript -this.checkScreenName = `claudeman-aicheck-${shortId}`; +this.checkScreenName = `codeman-aicheck-${shortId}`; ``` **Impact**: Very unlikely in practice since checks have cooldowns, but theoretically possible. **Suggested Fix**: Already partially mitigated by the `timestamp` in temp file names. Could add timestamp to screen name too: ```typescript -this.checkScreenName = `claudeman-aicheck-${shortId}-${timestamp}`; +this.checkScreenName = `codeman-aicheck-${shortId}-${timestamp}`; ``` --- ### Issue 5: DetectionStatus Calculation During ai_checking State (LOW) -**File**: `/home/arkon/default/claudeman/src/respawn-controller.ts` +**File**: `/home/arkon/default/codeman/src/respawn-controller.ts` **Lines**: 759-762 **Severity**: LOW diff --git a/test/respawn-test-plan.md b/test/respawn-test-plan.md index 3bf76f69..aada16eb 100644 --- a/test/respawn-test-plan.md +++ b/test/respawn-test-plan.md @@ -243,7 +243,7 @@ afterEach(() => { The global `test/setup.ts` handles: -1. **Screen Cleanup**: Kills any orphaned `claudeman-*` screens created during tests +1. **Screen Cleanup**: Kills any orphaned `codeman-*` screens created during tests 2. **Process Cleanup**: Kills any Claude processes spawned by tests 3. **Pre-existing Protection**: Never kills screens that existed before tests started diff --git a/test/respawn-test-utils.ts b/test/respawn-test-utils.ts index 42572d66..dc3f1b7b 100644 --- a/test/respawn-test-utils.ts +++ b/test/respawn-test-utils.ts @@ -98,7 +98,7 @@ export class MockSession extends EventEmitter { constructor(id: string = 'mock-session-id') { super(); this.id = id; - this._muxName = `claudeman-test-${id.slice(0, 8)}`; + this._muxName = `codeman-test-${id.slice(0, 8)}`; } /** Direct PTY write (used by session.write()) */ diff --git a/test/session-cleanup.test.ts b/test/session-cleanup.test.ts index 446137a7..3e539c6f 100644 --- a/test/session-cleanup.test.ts +++ b/test/session-cleanup.test.ts @@ -5,7 +5,7 @@ import { join } from 'node:path'; import { homedir } from 'node:os'; const TEST_PORT = 3120; -const CASES_DIR = join(homedir(), 'claudeman-cases'); +const CASES_DIR = join(homedir(), 'codeman-cases'); /** * Session Cleanup Tests diff --git a/test/session-state.test.ts b/test/session-state.test.ts index 3b2c5c8d..57d45104 100644 --- a/test/session-state.test.ts +++ b/test/session-state.test.ts @@ -280,41 +280,41 @@ describe('Session State Management', () => { describe('Mux Session Environment', () => { interface MuxEnv { - CLAUDEMAN_MUX: string; - CLAUDEMAN_SESSION_ID: string; - CLAUDEMAN_MUX_NAME: string; + CODEMAN_MUX: string; + CODEMAN_SESSION_ID: string; + CODEMAN_MUX_NAME: string; } const createMuxEnv = (sessionId: string, muxName: string): MuxEnv => ({ - CLAUDEMAN_MUX: '1', - CLAUDEMAN_SESSION_ID: sessionId, - CLAUDEMAN_MUX_NAME: muxName, + CODEMAN_MUX: '1', + CODEMAN_SESSION_ID: sessionId, + CODEMAN_MUX_NAME: muxName, }); - const isClaudemanSession = (env: Record): boolean => { - return env.CLAUDEMAN_MUX === '1'; + const isCodemanSession = (env: Record): boolean => { + return env.CODEMAN_MUX === '1'; }; it('should create valid mux environment', () => { - const env = createMuxEnv('session-123', 'claudeman-test'); - expect(env.CLAUDEMAN_MUX).toBe('1'); - expect(env.CLAUDEMAN_SESSION_ID).toBe('session-123'); - expect(env.CLAUDEMAN_MUX_NAME).toBe('claudeman-test'); + const env = createMuxEnv('session-123', 'codeman-test'); + expect(env.CODEMAN_MUX).toBe('1'); + expect(env.CODEMAN_SESSION_ID).toBe('session-123'); + expect(env.CODEMAN_MUX_NAME).toBe('codeman-test'); }); - it('should detect claudeman session', () => { - const env = createMuxEnv('session-123', 'claudeman-test'); - expect(isClaudemanSession(env)).toBe(true); + it('should detect codeman session', () => { + const env = createMuxEnv('session-123', 'codeman-test'); + expect(isCodemanSession(env)).toBe(true); }); - it('should detect non-claudeman session', () => { - const env = { CLAUDEMAN_MUX: '0' }; - expect(isClaudemanSession(env)).toBe(false); + it('should detect non-codeman session', () => { + const env = { CODEMAN_MUX: '0' }; + expect(isCodemanSession(env)).toBe(false); }); it('should handle missing environment variable', () => { const env = {}; - expect(isClaudemanSession(env)).toBe(false); + expect(isCodemanSession(env)).toBe(false); }); }); diff --git a/test/setup.ts b/test/setup.ts index 5cab0bd2..eb853324 100644 --- a/test/setup.ts +++ b/test/setup.ts @@ -1,5 +1,5 @@ /** - * @fileoverview Global test setup for Claudeman tests + * @fileoverview Global test setup for Codeman tests * * SAFETY: TmuxManager has built-in test mode detection * (via process.env.VITEST) that makes ALL shell commands no-ops. diff --git a/test/sse-events.test.ts b/test/sse-events.test.ts index 04b084c7..4ee745f8 100644 --- a/test/sse-events.test.ts +++ b/test/sse-events.test.ts @@ -293,7 +293,7 @@ describe('SSE Event Types', () => { const { join } = await import('node:path'); const { homedir } = await import('node:os'); try { - rmSync(join(homedir(), 'claudeman-cases', caseName), { recursive: true }); + rmSync(join(homedir(), 'codeman-cases', caseName), { recursive: true }); } catch {} }); }); diff --git a/test/state-store.test.ts b/test/state-store.test.ts index 6fada8ea..8d588e33 100644 --- a/test/state-store.test.ts +++ b/test/state-store.test.ts @@ -17,7 +17,7 @@ import type { AppState, SessionState, TaskState, RalphSessionState } from '../sr import { StateStore, getStore } from '../src/state-store.js'; describe('StateStore', () => { - const testDir = join(tmpdir(), 'claudeman-test-' + Date.now()); + const testDir = join(tmpdir(), 'codeman-test-' + Date.now()); const testFilePath = join(testDir, 'state.json'); const testInnerPath = join(testDir, 'state-inner.json'); diff --git a/test/team-watcher.test.ts b/test/team-watcher.test.ts index 8e92eab7..c5bfaa1c 100644 --- a/test/team-watcher.test.ts +++ b/test/team-watcher.test.ts @@ -2,7 +2,7 @@ * @fileoverview Tests for TeamWatcher - Agent Teams filesystem polling * * Test port: 3150 (if server needed) - * SAFETY: Never uses port 3000, never kills w1-claudeman/w2/w3-claudeman + * SAFETY: Never uses port 3000, never kills w1-codeman/w2/w3-codeman */ import { mkdirSync, writeFileSync, rmSync, existsSync } from 'node:fs'; @@ -13,7 +13,7 @@ import { TeamWatcher } from '../src/team-watcher.js'; import type { TeamConfig, TeamTask, InboxMessage } from '../src/types.js'; // Unique temp dir per test run -const TEST_BASE = join(tmpdir(), `claudeman-test-teams-${randomUUID().substring(0, 8)}`); +const TEST_BASE = join(tmpdir(), `codeman-test-teams-${randomUUID().substring(0, 8)}`); const TEAMS_DIR = join(TEST_BASE, 'teams'); const TASKS_DIR = join(TEST_BASE, 'tasks'); diff --git a/test/templates.test.ts b/test/templates.test.ts index a086a8c1..137ef695 100644 --- a/test/templates.test.ts +++ b/test/templates.test.ts @@ -12,7 +12,7 @@ import { tmpdir } from 'node:os'; import { generateClaudeMd } from '../src/templates/claude-md.js'; describe('generateClaudeMd', () => { - const testDir = join(tmpdir(), 'claudeman-template-test-' + Date.now()); + const testDir = join(tmpdir(), 'codeman-template-test-' + Date.now()); beforeEach(() => { if (!existsSync(testDir)) { @@ -54,11 +54,11 @@ describe('generateClaudeMd', () => { expect(result).toContain(`**Last Updated**: ${today}`); }); - it('should include Claudeman environment section', () => { + it('should include Codeman environment section', () => { const result = generateClaudeMd('my-project'); - expect(result).toContain('## Claudeman Environment'); - expect(result).toContain('CLAUDEMAN_MUX=1'); + expect(result).toContain('## Codeman Environment'); + expect(result).toContain('CODEMAN_MUX=1'); }); it('should include work principles', () => { @@ -146,20 +146,20 @@ About [PROJECT_NAME]: [PROJECT_DESCRIPTION] const result = generateClaudeMd('my-project', 'desc', '/nonexistent/template.md'); // Should get default template content - expect(result).toContain('## Claudeman Environment'); + expect(result).toContain('## Codeman Environment'); expect(result).toContain('**Project Name**: my-project'); }); it('should fall back to default template if custom path is empty', () => { const result = generateClaudeMd('my-project', 'desc', ''); - expect(result).toContain('## Claudeman Environment'); + expect(result).toContain('## Codeman Environment'); }); it('should fall back to default template if custom path is undefined', () => { const result = generateClaudeMd('my-project', 'desc', undefined); - expect(result).toContain('## Claudeman Environment'); + expect(result).toContain('## Codeman Environment'); }); }); }); diff --git a/test/terminal-parsing.test.ts b/test/terminal-parsing.test.ts index ee5413d4..132a49f5 100644 --- a/test/terminal-parsing.test.ts +++ b/test/terminal-parsing.test.ts @@ -2,7 +2,7 @@ * @fileoverview Tests for terminal output parsing utilities * * Tests various terminal output parsing patterns used throughout - * the Claudeman application. + * the Codeman application. */ import { describe, it, expect } from 'vitest'; diff --git a/test/tmux-manager.test.ts b/test/tmux-manager.test.ts index 559e8d74..b93a207f 100644 --- a/test/tmux-manager.test.ts +++ b/test/tmux-manager.test.ts @@ -78,8 +78,8 @@ describe('TmuxManager (unit)', () => { describe('getAttachArgs', () => { it('should return attach-session args', () => { - const args = manager.getAttachArgs('claudeman-abc12345'); - expect(args).toEqual(['attach-session', '-t', 'claudeman-abc12345']); + const args = manager.getAttachArgs('codeman-abc12345'); + expect(args).toEqual(['attach-session', '-t', 'codeman-abc12345']); }); }); @@ -111,7 +111,7 @@ describe('TmuxManager (unit)', () => { beforeEach(() => { manager.registerSession({ sessionId: 'test-id', - muxName: 'claudeman-1e571234', + muxName: 'codeman-1e571234', pid: 12345, createdAt: Date.now(), workingDir: '/tmp', @@ -145,7 +145,7 @@ describe('TmuxManager (unit)', () => { it('should return all registered sessions as alive', async () => { manager.registerSession({ sessionId: 'alive-1', - muxName: 'claudeman-a11ce111', + muxName: 'codeman-a11ce111', pid: 100, createdAt: Date.now(), workingDir: '/tmp', @@ -181,7 +181,7 @@ describe('TmuxManager (unit)', () => { it('should remove session from memory in test mode', async () => { manager.registerSession({ sessionId: 'kill-test', - muxName: 'claudeman-5e1f1111', + muxName: 'codeman-5e1f1111', pid: 999, createdAt: Date.now(), workingDir: '/tmp', @@ -194,14 +194,14 @@ describe('TmuxManager (unit)', () => { expect(manager.getSession('kill-test')).toBeUndefined(); }); - it('should allow kill when session does NOT match CLAUDEMAN_MUX_NAME', async () => { - const originalEnv = process.env.CLAUDEMAN_MUX_NAME; - process.env.CLAUDEMAN_MUX_NAME = 'claudeman-0ther1111'; + it('should allow kill when session does NOT match CODEMAN_MUX_NAME', async () => { + const originalEnv = process.env.CODEMAN_MUX_NAME; + process.env.CODEMAN_MUX_NAME = 'codeman-0ther1111'; try { manager.registerSession({ sessionId: 'other-kill-test', - muxName: 'claudeman-d1ff1111', + muxName: 'codeman-d1ff1111', pid: 888, createdAt: Date.now(), workingDir: '/tmp', @@ -219,21 +219,21 @@ describe('TmuxManager (unit)', () => { expect(manager.getSession('other-kill-test')).toBeUndefined(); } finally { if (originalEnv === undefined) { - delete process.env.CLAUDEMAN_MUX_NAME; + delete process.env.CODEMAN_MUX_NAME; } else { - process.env.CLAUDEMAN_MUX_NAME = originalEnv; + process.env.CODEMAN_MUX_NAME = originalEnv; } } }); - it('should allow kill when CLAUDEMAN_MUX_NAME is not set', async () => { - const originalEnv = process.env.CLAUDEMAN_MUX_NAME; - delete process.env.CLAUDEMAN_MUX_NAME; + it('should allow kill when CODEMAN_MUX_NAME is not set', async () => { + const originalEnv = process.env.CODEMAN_MUX_NAME; + delete process.env.CODEMAN_MUX_NAME; try { manager.registerSession({ sessionId: 'no-env-test', - muxName: 'claudeman-aaa11111', + muxName: 'codeman-aaa11111', pid: 777, createdAt: Date.now(), workingDir: '/tmp', @@ -247,9 +247,9 @@ describe('TmuxManager (unit)', () => { expect(result).toBe(true); } finally { if (originalEnv === undefined) { - delete process.env.CLAUDEMAN_MUX_NAME; + delete process.env.CODEMAN_MUX_NAME; } else { - process.env.CLAUDEMAN_MUX_NAME = originalEnv; + process.env.CODEMAN_MUX_NAME = originalEnv; } } }); @@ -259,7 +259,7 @@ describe('TmuxManager (unit)', () => { beforeEach(() => { manager.registerSession({ sessionId: 'meta-test', - muxName: 'claudeman-ae1a1234', + muxName: 'codeman-ae1a1234', pid: 300, createdAt: Date.now(), workingDir: '/tmp', @@ -308,7 +308,7 @@ describe('TmuxManager (unit)', () => { it('should return all registered sessions', () => { manager.registerSession({ sessionId: 's1', - muxName: 'claudeman-51111111', + muxName: 'codeman-51111111', pid: 1, createdAt: Date.now(), workingDir: '/tmp', @@ -317,7 +317,7 @@ describe('TmuxManager (unit)', () => { }); manager.registerSession({ sessionId: 's2', - muxName: 'claudeman-52222222', + muxName: 'codeman-52222222', pid: 2, createdAt: Date.now(), workingDir: '/tmp', diff --git a/test/tmux-restart-recovery.test.ts b/test/tmux-restart-recovery.test.ts index 2808b5de..aa70455d 100644 --- a/test/tmux-restart-recovery.test.ts +++ b/test/tmux-restart-recovery.test.ts @@ -59,7 +59,7 @@ describe('TmuxManager restart recovery (test mode safety)', () => { it('should report all registered sessions as alive in test mode', async () => { manager.registerSession({ sessionId: 'test-recovery-1', - muxName: 'claudeman-de51ecaf', + muxName: 'codeman-de51ecaf', pid: 1, createdAt: Date.now(), workingDir: '/tmp', @@ -89,7 +89,7 @@ describe('TmuxManager restart recovery (test mode safety)', () => { it('should not execute any tmux commands in test mode', async () => { manager.registerSession({ sessionId: 'alive-session', - muxName: 'claudeman-a11eeaaa', + muxName: 'codeman-a11eeaaa', pid: 1, createdAt: Date.now(), workingDir: '/tmp', @@ -110,7 +110,7 @@ describe('TmuxManager restart recovery (test mode safety)', () => { it('should handle multiple sessions correctly in test mode', async () => { manager.registerSession({ sessionId: 'session-1', - muxName: 'claudeman-a11eeaaa', + muxName: 'codeman-a11eeaaa', pid: 1, createdAt: Date.now(), workingDir: '/tmp', @@ -120,7 +120,7 @@ describe('TmuxManager restart recovery (test mode safety)', () => { }); manager.registerSession({ sessionId: 'session-2', - muxName: 'claudeman-b22ffbbb', + muxName: 'codeman-b22ffbbb', pid: 2, createdAt: Date.now(), workingDir: '/tmp', @@ -140,7 +140,7 @@ describe('TmuxManager restart recovery (test mode safety)', () => { it('should safely remove sessions via killSession in test mode', async () => { manager.registerSession({ sessionId: 'kill-me', - muxName: 'claudeman-deadbeef', + muxName: 'codeman-deadbeef', pid: 99999, createdAt: Date.now(), workingDir: '/tmp',