mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-09-30 12:39:42 +02:00
Includes review fixes: breaker reset only on explicit clearBreaker restarts (auto-reattach never clears), trip observability survives listener detach, push notification wired into PUSH_EVENT_MAP. # Conflicts: # src/session.ts
304 lines
11 KiB
TypeScript
304 lines
11 KiB
TypeScript
/**
|
|
* @fileoverview Session type definitions.
|
|
*
|
|
* Core domain type — SessionState is the primary entity in the system.
|
|
*
|
|
* Key exports:
|
|
* - SessionState — full session state (status, tokens, respawn, ralph, CLI metadata)
|
|
* - SessionConfig — creation-time config (id, workingDir, createdAt)
|
|
* - SessionOutput — captured stdout/stderr/exitCode
|
|
* - SessionStatus — 'idle' | 'busy' | 'stopped' | 'error'
|
|
* - SessionMode — 'claude' | 'shell' | 'opencode' | 'codex' | 'gemini' (which CLI backend)
|
|
* - ClaudeMode — CLI permission mode ('dangerously-skip-permissions' | 'normal' | 'allowedTools')
|
|
* - SessionColor — visual differentiation color
|
|
* - OpenCodeConfig — OpenCode-specific settings (model, autoAllowTools, continueSession)
|
|
* - CodexConfig — Codex (OpenAI CLI)-specific settings (model, resumeSessionId)
|
|
* - GeminiConfig — Gemini CLI-specific settings (model, approvalMode, resumeSession)
|
|
*
|
|
* Cross-domain relationships:
|
|
* - SessionState.respawnConfig embeds RespawnConfig (respawn domain)
|
|
* - SessionState.id is referenced by: RalphSessionState.sessionId (ralph),
|
|
* RunSummary.sessionId (run-summary), ActiveBashTool.sessionId (tools),
|
|
* TeamConfig.leadSessionId (teams), RespawnCycleMetrics.sessionId (respawn),
|
|
* TaskState.assignedSessionId (task)
|
|
*
|
|
* Persisted to `~/.codeman/state.json`. Served at `GET /api/sessions` and
|
|
* `GET /api/sessions/:id`.
|
|
*/
|
|
|
|
import type { RespawnConfig } from './respawn.js';
|
|
import type { AttachmentDetectedType } from './tools.js';
|
|
|
|
/** Status of a Claude session */
|
|
export type SessionStatus = 'idle' | 'busy' | 'stopped' | 'error';
|
|
|
|
/**
|
|
* Claude CLI startup permission mode.
|
|
* - `'dangerously-skip-permissions'`: Bypass all permission prompts (default)
|
|
* - `'normal'`: Standard mode with permission prompts
|
|
* - `'allowedTools'`: Only allow specific tools (requires allowedTools list)
|
|
*/
|
|
export type ClaudeMode = 'dangerously-skip-permissions' | 'normal' | 'allowedTools';
|
|
|
|
/** Session mode: which CLI backend a session runs */
|
|
export type SessionMode = 'claude' | 'shell' | 'opencode' | 'codex' | 'gemini';
|
|
|
|
export type RemoteCommandMode = Extract<SessionMode, 'shell' | 'claude' | 'opencode' | 'codex' | 'gemini'>;
|
|
|
|
/**
|
|
* Advanced SSH connection options shared by RemoteHost and SessionRemote.
|
|
*
|
|
* COD-107 — all fields are optional; every field absent reproduces today's
|
|
* behavior (port-22, default-identity, directly-SSH-able hosts). These describe
|
|
* HOW Codeman reaches the host (identity, proxy, jump host, arbitrary `-o`),
|
|
* letting it connect to e.g. a host fronted by a cloudflared SOCKS5 proxy on a
|
|
* custom port — the same connection `ssh-aa-desktop` makes — without a wrapper.
|
|
*/
|
|
export interface RemoteSshOptions {
|
|
/**
|
|
* Path to an SSH identity (private key) file — path ONLY, never key bytes.
|
|
* A leading `~`/`$HOME` is expanded to an absolute path at command-build time
|
|
* (ssh does not expand `~` in `-i`).
|
|
*/
|
|
identityFile?: string;
|
|
/**
|
|
* SOCKS5 proxy as `host:port` (e.g. `127.0.0.1:1080`). Expands to
|
|
* `-o ProxyCommand=nc -X 5 -x <host:port> %h %p` (the cloudflared/SOCKS5 case).
|
|
*/
|
|
socksProxy?: string;
|
|
/** SSH jump host (`[user@]host[:port]`) emitted as `-J <jumpHost>`. */
|
|
jumpHost?: string;
|
|
/** Arbitrary additional `-o KEY=VALUE` options (escape hatch). Each `KEY=VALUE`. */
|
|
extraSshOptions?: string[];
|
|
}
|
|
|
|
export interface RemoteHost extends RemoteSshOptions {
|
|
id: string;
|
|
label: string;
|
|
host: string;
|
|
username: string;
|
|
port?: number;
|
|
commands?: Partial<Record<RemoteCommandMode, string>>;
|
|
}
|
|
|
|
export interface RemoteCase {
|
|
name: string;
|
|
type: 'remote';
|
|
hostId: string;
|
|
remotePath: string;
|
|
}
|
|
|
|
export interface SessionRemote extends RemoteSshOptions {
|
|
hostId: string;
|
|
label: string;
|
|
host: string;
|
|
username: string;
|
|
port?: number;
|
|
remotePath: string;
|
|
commands?: Partial<Record<RemoteCommandMode, string>>;
|
|
}
|
|
|
|
/**
|
|
* Valid Claude CLI effort levels (claude >= 2.1.154).
|
|
* `ultracode` = xhigh effort + standing dynamic-workflow orchestration; it is a
|
|
* separate `ultracode` settings key rather than an `effortLevel` value.
|
|
*/
|
|
export const EFFORT_LEVELS = ['low', 'medium', 'high', 'xhigh', 'max', 'ultracode'] as const;
|
|
|
|
/** Claude CLI effort level for new sessions (soft default, switchable via /effort in-session) */
|
|
export type EffortLevel = (typeof EFFORT_LEVELS)[number];
|
|
|
|
/** Type guard: is the string a valid EffortLevel? */
|
|
export function isEffortLevel(value: string | undefined): value is EffortLevel {
|
|
return value !== undefined && (EFFORT_LEVELS as readonly string[]).includes(value);
|
|
}
|
|
|
|
/** OpenCode session configuration */
|
|
export interface OpenCodeConfig {
|
|
/** Model identifier (e.g., "anthropic/claude-sonnet-4-5", "openai/gpt-5.2", "ollama/codellama") */
|
|
model?: string;
|
|
/** Whether to auto-allow all tool executions (sets permission.* = allow) */
|
|
autoAllowTools?: boolean;
|
|
/** Session ID to continue from */
|
|
continueSession?: string;
|
|
/** Whether to fork when continuing (branch the conversation) */
|
|
forkSession?: boolean;
|
|
/** Custom inline config JSON (passed via OPENCODE_CONFIG_CONTENT) */
|
|
configContent?: string;
|
|
}
|
|
|
|
/** Codex (OpenAI CLI) browser rendering strategy. Hybrid TUI is the only supported mode. */
|
|
export type CodexRenderMode = 'hybrid';
|
|
|
|
/** Codex (OpenAI CLI) session configuration */
|
|
export interface CodexConfig {
|
|
/** Model identifier (e.g., "gpt-5", "o4-mini"). Passed via --model. */
|
|
model?: string;
|
|
/** Resume a previous codex conversation by session id (passed via --resume) */
|
|
resumeSessionId?: string;
|
|
/** Bypass approval prompts (passes --dangerously-bypass-approvals-and-sandbox) */
|
|
dangerouslyBypassApprovals?: boolean;
|
|
/** Browser rendering strategy for Codex sessions. Hybrid TUI is the only supported mode. */
|
|
renderMode?: CodexRenderMode;
|
|
}
|
|
|
|
/** Gemini CLI session configuration */
|
|
export interface GeminiConfig {
|
|
/** Model identifier (e.g., "gemini-2.5-pro"). Passed via --model. */
|
|
model?: string;
|
|
/** Gemini approval mode for tool calls. */
|
|
approvalMode?: 'default' | 'auto_edit' | 'yolo' | 'plan';
|
|
/** Resume a previous Gemini session ("latest", index, or session id). */
|
|
resumeSession?: string;
|
|
}
|
|
|
|
/**
|
|
* Configuration for creating a new session
|
|
*/
|
|
export interface SessionConfig {
|
|
/** Unique session identifier */
|
|
id: string;
|
|
/** Working directory for the session */
|
|
workingDir: string;
|
|
/** Timestamp when session was created */
|
|
createdAt: number;
|
|
}
|
|
|
|
/**
|
|
* Available session colors for visual differentiation
|
|
*/
|
|
export type SessionColor = 'default' | 'red' | 'orange' | 'yellow' | 'green' | 'blue' | 'purple' | 'pink';
|
|
|
|
export type SessionAttachmentHistorySource = 'detected' | 'external';
|
|
|
|
/**
|
|
* Session-scoped attachment history entry.
|
|
*
|
|
* `externalPath` is server-private. It may be present in the internal persisted
|
|
* history copy, but API-bound session state must sanitize it before returning
|
|
* to the browser.
|
|
*/
|
|
export interface SessionAttachmentHistoryItem {
|
|
/** Stable history identity used for dedupe and list rendering */
|
|
id: string;
|
|
/** Codeman session ID this item belongs to */
|
|
sessionId: string;
|
|
/** Display filename */
|
|
fileName: string;
|
|
/** Lowercase extension without a leading dot */
|
|
extension: string;
|
|
/** Viewer category used by the web UI */
|
|
attachmentType: AttachmentDetectedType;
|
|
/** File size in bytes */
|
|
size: number;
|
|
/** Last modified timestamp in milliseconds, if known */
|
|
mtimeMs: number;
|
|
/** Last time this attachment was seen or explicitly published */
|
|
timestamp: number;
|
|
/** How the attachment entered the session */
|
|
source: SessionAttachmentHistorySource;
|
|
/** Workspace-relative path for detected session files */
|
|
relativePath?: string;
|
|
/** Server-private absolute path for explicitly published external files */
|
|
externalPath?: string;
|
|
}
|
|
|
|
/**
|
|
* Current state of a session
|
|
*/
|
|
export interface SessionState {
|
|
/** Unique session identifier */
|
|
id: string;
|
|
/** Process ID of the PTY process, null if not running */
|
|
pid: number | null;
|
|
/** Current session status */
|
|
status: SessionStatus;
|
|
/** Working directory path */
|
|
workingDir: string;
|
|
/** Remote execution metadata, present when this session runs over SSH through local tmux */
|
|
remote?: SessionRemote;
|
|
/** ID of currently assigned task, null if none */
|
|
currentTaskId: string | null;
|
|
/** Timestamp when session was created */
|
|
createdAt: number;
|
|
/** Timestamp of last activity */
|
|
lastActivityAt: number;
|
|
/** Session display name */
|
|
name?: string;
|
|
/** Session mode */
|
|
mode?: SessionMode;
|
|
/** Auto-clear enabled */
|
|
autoClearEnabled?: boolean;
|
|
/** Auto-clear token threshold */
|
|
autoClearThreshold?: number;
|
|
/** Auto-compact enabled */
|
|
autoCompactEnabled?: boolean;
|
|
/** Auto-compact token threshold */
|
|
autoCompactThreshold?: number;
|
|
/** Auto-compact prompt */
|
|
autoCompactPrompt?: string;
|
|
/** Auto-resume on usage limit enabled */
|
|
autoResumeEnabled?: boolean;
|
|
/** Pending usage-limit auto-resume fire time (epoch ms), if armed */
|
|
autoResumeAt?: number;
|
|
/** Image watcher enabled for this session */
|
|
imageWatcherEnabled?: boolean;
|
|
/** Total cost in USD */
|
|
totalCost?: number;
|
|
/** Input tokens used */
|
|
inputTokens?: number;
|
|
/** Output tokens used */
|
|
outputTokens?: number;
|
|
/** Whether respawn controller is currently enabled/running */
|
|
respawnEnabled?: boolean;
|
|
/** Respawn controller config (if enabled) */
|
|
respawnConfig?: RespawnConfig & { durationMinutes?: number };
|
|
/** Ralph / Todo tracker enabled */
|
|
ralphEnabled?: boolean;
|
|
/** Ralph auto-enable disabled (user explicitly turned off Ralph) */
|
|
ralphAutoEnableDisabled?: boolean;
|
|
/** Ralph completion phrase (if set) */
|
|
ralphCompletionPhrase?: string;
|
|
/** Parent agent ID if this session is a spawned agent */
|
|
parentAgentId?: string;
|
|
/** Child agent IDs spawned by this session */
|
|
childAgentIds?: string[];
|
|
/** Nice priority enabled */
|
|
niceEnabled?: boolean;
|
|
/** Nice value (-20 to 19) */
|
|
niceValue?: number;
|
|
/** User-assigned color for visual differentiation */
|
|
color?: SessionColor;
|
|
/** Flicker filter enabled (buffers output after screen clears) */
|
|
flickerFilterEnabled?: boolean;
|
|
/** Claude Code CLI version (parsed from terminal, e.g., "2.1.27") */
|
|
cliVersion?: string;
|
|
/** Claude model in use (parsed from terminal, e.g., "Opus 4.5") */
|
|
cliModel?: string;
|
|
/** Account type (parsed from terminal, e.g., "Claude Max", "API") */
|
|
cliAccountType?: string;
|
|
/** Latest CLI version available (parsed from version check) */
|
|
cliLatestVersion?: string;
|
|
/** OpenCode-specific configuration (only for mode === 'opencode') */
|
|
openCodeConfig?: OpenCodeConfig;
|
|
/** Codex-specific configuration (only for mode === 'codex') */
|
|
codexConfig?: CodexConfig;
|
|
/** Gemini-specific configuration (only for mode === 'gemini') */
|
|
geminiConfig?: GeminiConfig;
|
|
/** Claude conversation session ID to resume after reboot (set by restore script) */
|
|
resumeSessionId?: string;
|
|
/** Claude CLI effort level (soft default via --settings, switchable in-session via /effort) */
|
|
effort?: EffortLevel;
|
|
/** Sanitized per-session attachment history. */
|
|
attachmentHistory?: SessionAttachmentHistoryItem[];
|
|
/**
|
|
* PTY-exit circuit breaker tripped — respawn blocked until an explicit restart
|
|
* (COD-118). Runtime-only: never restored on boot (fresh server = fresh breaker).
|
|
*/
|
|
respawnBlocked?: boolean;
|
|
}
|
|
|
|
/**
|
|
* Output captured from a session
|
|
*/
|