mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-05 23:19:43 +02:00
chore: rename Claudeman to Codeman
Full product rename across 109 files (~834 occurrences): - Env vars: CLAUDEMAN_* → CODEMAN_* - Data dirs: ~/.claudeman/ → ~/.codeman/, ~/claudeman-cases/ → ~/codeman-cases/ - tmux prefix: claudeman- → codeman- - localStorage: claudeman-* → codeman-* - Package/CLI: claudeman → codeman - GitHub repo: Ark0N/Claudeman → Ark0N/Codeman - systemd service: claudeman-web → codeman-web - Class: ClaudemanApp → CodemanApp Migration infrastructure for seamless transition: - state-store.ts: auto-migrates data directories on startup - tmux-manager.ts: dual-prefix detection (legacy claudeman- sessions) - app.js: localStorage key migration (preserves old keys) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -15,7 +15,7 @@ When local echo is enabled, keystrokes accumulate in the `LocalEchoOverlay.pendi
|
||||
When local echo is enabled, keystrokes accumulate **only** in `LocalEchoOverlay.pendingText` (a client-side string). Nothing reaches the server PTY until Enter is pressed. This creates three failure modes:
|
||||
|
||||
1. **Tab switch loses PTY state** — switching sessions saves overlay text to `localEchoTextCache` (a Map), but the actual Claude Code Ink process has no knowledge of what was typed. If respawn or `/clear` fires on that session, the cached text is meaningless.
|
||||
2. **Session death loses input** — if the session crashes or respawns while text is pending in the overlay, that input is gone (localStorage backup `claudeman_local_echo_pending` only survives page reloads, not session resets).
|
||||
2. **Session death loses input** — if the session crashes or respawns while text is pending in the overlay, that input is gone (localStorage backup `codeman_local_echo_pending` only survives page reloads, not session resets).
|
||||
3. **Tab completion impossible** — pressing Tab with pending overlay text sends the raw Tab character to a PTY that has no knowledge of the typed text, so completion fails.
|
||||
|
||||
## Goal
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
When local echo is enabled, keystrokes accumulate **only** in `LocalEchoOverlay.pendingText` (a client-side string). Nothing reaches the server PTY until Enter is pressed. This creates three failure modes:
|
||||
|
||||
1. **Tab switch loses PTY state** — switching sessions saves overlay text to `localEchoTextCache` (a Map), but the actual Claude Code Ink process has no knowledge of what was typed. If respawn or `/clear` fires on that session, the cached text is meaningless.
|
||||
2. **Session death loses input** — if the session crashes or respawns while text is pending in the overlay, that input is gone (localStorage backup `claudeman_local_echo_pending` only survives page reloads, not session resets).
|
||||
2. **Session death loses input** — if the session crashes or respawns while text is pending in the overlay, that input is gone (localStorage backup `codeman_local_echo_pending` only survives page reloads, not session resets).
|
||||
3. **Tab completion impossible** — pressing Tab with pending overlay text sends the raw Tab character to a PTY that has no knowledge of the typed text, so completion fails.
|
||||
|
||||
## Goal
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Browser Testing Guide for Claudeman
|
||||
# Browser Testing Guide for Codeman
|
||||
|
||||
This guide documents the browser testing infrastructure, framework comparison results, and best practices for testing the Claudeman web UI.
|
||||
This guide documents the browser testing infrastructure, framework comparison results, and best practices for testing the Codeman web UI.
|
||||
|
||||
## Quick Start
|
||||
|
||||
@@ -14,7 +14,7 @@ npm test -- test/browser-e2e.test.ts
|
||||
|
||||
## Framework Comparison Results
|
||||
|
||||
We tested three browser automation frameworks against the Claudeman web UI:
|
||||
We tested three browser automation frameworks against the Codeman web UI:
|
||||
|
||||
| Framework | Avg Duration | Best For |
|
||||
|-----------|--------------|----------|
|
||||
@@ -114,7 +114,7 @@ await page.waitForSelector('.session-tab', { state: 'visible' });
|
||||
|
||||
// Assertions with expect
|
||||
await expect(page.locator('.header')).toBeVisible();
|
||||
await expect(page).toHaveTitle('Claudeman');
|
||||
await expect(page).toHaveTitle('Codeman');
|
||||
|
||||
await browser.close();
|
||||
```
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Codebase Cleanup Findings
|
||||
|
||||
Compiled from parallel analysis of the entire Claudeman codebase by 3 research agents (2026-02-19).
|
||||
Compiled from parallel analysis of the entire Codeman codebase by 3 research agents (2026-02-19).
|
||||
|
||||
## P0 — Bug Fix
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
**Date**: 2026-02-18
|
||||
**Audit by**: 4-agent team (css-analyst, js-analyst, server-analyst, deps-analyst)
|
||||
**Scope**: First browser load of Claudeman web UI at `/`
|
||||
**Scope**: First browser load of Codeman web UI at `/`
|
||||
|
||||
---
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 859 KiB After Width: | Height: | Size: 859 KiB |
@@ -1,3 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 60">
|
||||
<text x="160" y="48" font-family="system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif" font-size="52" font-weight="700" fill="#60a5fa" text-anchor="middle">Claudeman</text>
|
||||
<text x="160" y="48" font-family="system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif" font-size="52" font-weight="700" fill="#60a5fa" text-anchor="middle">Codeman</text>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 249 B After Width: | Height: | Size: 247 B |
@@ -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.
|
||||
|
||||
@@ -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-<id>"
|
||||
tmux new-session -ds "codeman-<id>"
|
||||
tmux respawn-pane -k -t ... "claude --dangerously-skip-permissions --session-id <id>"
|
||||
↓
|
||||
pty.spawn('tmux', ['attach-session', '-t', 'claudeman-<id>'])
|
||||
pty.spawn('tmux', ['attach-session', '-t', 'codeman-<id>'])
|
||||
↓
|
||||
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-<id>"
|
||||
tmux new-session -ds "codeman-<id>"
|
||||
tmux respawn-pane -k -t ... "opencode --model <model>"
|
||||
↓
|
||||
pty.spawn('tmux', ['attach-session', '-t', 'claudeman-<id>'])
|
||||
pty.spawn('tmux', ['attach-session', '-t', 'codeman-<id>'])
|
||||
↓
|
||||
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 | `<promise>PHRASE</promise>` 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 <claudeman-id>` for initial session creation (only `--session <id>` for continuing existing sessions). This means:
|
||||
> **[REVIEW P1-6]** OpenCode does not have `--session-id <codeman-id>` for initial session creation (only `--session <id>` 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 <claudeman-id>` but OpenCode IDs have different format
|
||||
- We could pass `--session <codeman-id>` 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-<shortId>" -c <workingDir> -x 120 -y 40
|
||||
→ tmux set-option -t "claudeman-<shortId>" remain-on-exit on
|
||||
→ tmux new-session -ds "codeman-<shortId>" -c <workingDir> -x 120 -y 40
|
||||
→ tmux set-option -t "codeman-<shortId>" remain-on-exit on
|
||||
→ Build command: "export PATH=... && export LANG=... && claude --dangerously-skip-permissions --session-id <id>"
|
||||
→ tmux respawn-pane -k -t "claudeman-<shortId>" '<command>'
|
||||
→ tmux respawn-pane -k -t "codeman-<shortId>" '<command>'
|
||||
→ 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-<shortId>'], {
|
||||
→ pty.spawn('tmux', ['attach-session', '-t', 'codeman-<shortId>'], {
|
||||
name: 'xterm-256color',
|
||||
cols: 120, rows: 40,
|
||||
env: { LANG, LC_ALL, TERM }
|
||||
|
||||
@@ -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!)
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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.*
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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).*
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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 `<span class="settings-status" id="notifPer
|
||||
|
||||
The settings UI shows a hint (index.html line 996):
|
||||
```
|
||||
For remote access, HTTPS is required. Start with: claudeman web --https
|
||||
For remote access, HTTPS is required. Start with: codeman web --https
|
||||
```
|
||||
|
||||
Browser Notification API requires a secure context (HTTPS or localhost). This hint warns users who access Claudeman remotely over HTTP.
|
||||
Browser Notification API requires a secure context (HTTPS or localhost). This hint warns users who access Codeman remotely over HTTP.
|
||||
|
||||
---
|
||||
|
||||
@@ -579,7 +579,7 @@ On mobile devices:
|
||||
|
||||
### Mobile Storage Key (lines 952-956)
|
||||
|
||||
Mobile uses a separate localStorage key (`claudeman-notification-prefs-mobile`) so that enabling notifications on desktop does not accidentally enable them on a mobile device viewing the same Claudeman instance.
|
||||
Mobile uses a separate localStorage key (`codeman-notification-prefs-mobile`) so that enabling notifications on desktop does not accidentally enable them on a mobile device viewing the same Codeman instance.
|
||||
|
||||
### Mobile Drawer Styling (mobile.css lines 1049-1058)
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ The App Settings modal has tabs: Display, Claude CLI, Models, Paths, **Notificat
|
||||
|
||||
The Browser row includes an "Ask" button that calls `requestPermission()` and a status badge showing the current `Notification.permission` state.
|
||||
|
||||
There is also a hint: _"For remote access, HTTPS is required. Start with: `claudeman web --https`"_
|
||||
There is also a hint: _"For remote access, HTTPS is required. Start with: `codeman web --https`"_
|
||||
|
||||
#### Alerts Section
|
||||
| Setting | Element ID | Type | Default |
|
||||
@@ -54,16 +54,16 @@ Notification preferences are stored in **two places simultaneously**:
|
||||
|
||||
#### Layer 1: localStorage (primary, device-specific)
|
||||
|
||||
- **Storage key**: `claudeman-notification-prefs` (desktop) or `claudeman-notification-prefs-mobile` (mobile)
|
||||
- **Storage key**: `codeman-notification-prefs` (desktop) or `codeman-notification-prefs-mobile` (mobile)
|
||||
- Determined by `NotificationManager.getStorageKey()` at line 953, which calls `MobileDetection.getDeviceType()`
|
||||
- Device type is based on `window.innerWidth`: `<430` = mobile, `430-768` = tablet, `>=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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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<string, unknown>
|
||||
) {
|
||||
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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user