Files
Codeman/src/utils/index.ts
T
Codeman maintainer 89177651a6 perf(sessions): closing a session no longer waits on the server
Closing a tab took ~0.55-0.7s on an idle machine, more with child
processes or recently active subagents. Most of it was waiting:

- The web UI kept the tab until DELETE returned, then removed it on the
  100ms tab-render debounce, which every session update restarts.
  closeSession() is now optimistic: the tab, tile and split go and the
  next session is selected before the request is sent, rendered at
  once. A refused delete (checked with a GET, since a delete can land
  and lose its reply) puts the row back at its old index with the
  error toast. This also fixes a latent bug: _apiDelete never throws,
  so an HTTP error used to report "Session closed" while the session
  kept running. SSE upserts skip ids that are being closed.
- The kill path slept fixed intervals (100ms PTY grace, 200ms for the
  pane's children, 100ms for the process group) and verified in 100ms
  steps. waitForProcessesExit() (utils/process-exit-wait.ts) keeps
  every deadline but returns once the processes are gone, counting a
  zombie as exited. Signal decisions keep kill(pid, 0).
- tmux kill-session and the pane-pid lookup ran via execSync, freezing
  the server for ~70ms per close. Now async.
- killSubagentsForSession() ran a full `pgrep -f claude` scan per
  active/idle subagent (~85ms each with ~100 matching processes). It
  now scans once for all of them.

Measured on an isolated instance: click to tab gone 540-690ms -> 58-95ms;
DELETE of a claude session ~450ms -> ~200-260ms.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-10 04:20:46 +02:00

81 lines
3.0 KiB
TypeScript

/**
* @fileoverview Utility module exports.
*
* This module re-exports all utility classes and functions for easy import.
*
* @module utils
*/
export { BufferAccumulator } from './buffer-accumulator.js';
export { CleanupManager } from './cleanup-manager.js';
export { Debouncer, KeyedDebouncer } from './debouncer.js';
export { startEventLoopMonitor } from './event-loop-monitor.js';
export type { EventLoopMonitorHandle } from './event-loop-monitor.js';
export { StaleExpirationMap } from './stale-expiration-map.js';
export { isProcessRunning, waitForProcessesExit, PROCESS_EXIT_POLL_MS } from './process-exit-wait.js';
export {
ANSI_ESCAPE_PATTERN_FULL,
ANSI_ESCAPE_PATTERN_SIMPLE,
TOKEN_PATTERN,
SPINNER_PATTERN,
CLAUDE_WORKING_LINE_PATTERN,
stripAnsi,
SAFE_PATH_PATTERN,
execPattern,
} from './regex-patterns.js';
export { MAX_SESSION_TOKENS } from './token-validation.js';
export { isSafePushEndpoint } from './push-endpoint-validation.js';
export { stringSimilarity, fuzzyPhraseMatch, todoContentHash } from './string-similarity.js';
export { assertNever } from './type-safety.js';
export { wrapWithNice } from './nice-wrapper.js';
export { resolveLocalShell, loginShellArgs } from './shell-resolver.js';
export {
findClaudeDir,
getAugmentedPath,
getClaudeCliVersion,
getClaudeBinaryPath,
getClaudeNotFoundMessage,
} from './claude-cli-resolver.js';
export { spawnPtyWithHelperRepair } from './node-pty-repair.js';
export { resolveOpenCodeDir, getOpenCodeNotFoundMessage } from './opencode-cli-resolver.js';
export {
resolveCodexDir,
resolveCodexBinaryPath,
isCodexAvailable,
getCodexNotFoundMessage,
readCodexPlanUsage,
} from './codex-cli-resolver.js';
export { resolveGeminiDir, isGeminiAvailable, getGeminiNotFoundMessage } from './gemini-cli-resolver.js';
export {
resolveAntigravityDir,
isAntigravityAvailable,
getAntigravityNotFoundMessage,
} from './antigravity-cli-resolver.js';
export { resolvePiDir, isPiAvailable, getPiCliVersion, getPiNotFoundMessage } from './pi-cli-resolver.js';
export { resolveGrokDir, isGrokAvailable, getGrokCliVersion, getGrokNotFoundMessage } from './grok-cli-resolver.js';
export {
resolveDeepSeekDir,
isDeepSeekAvailable,
isDeepSeekRunnable,
getDeepSeekCliVersion,
getDeepSeekNotFoundMessage,
listDeepSeekProfiles,
resolveDefaultDeepSeekProfile,
isLaunchableProfile,
resolveDshHome,
profileExists,
} from './deepseek-cli-resolver.js';
export type { DeepSeekProfile, DeepSeekProfileKind } from './deepseek-cli-resolver.js';
export { compileFileQuery, matchFileQuery } from './file-query.js';
export type { FileQueryMatcher } from './file-query.js';
export { resolveOmpDir, isOmpAvailable, getOmpNotFoundMessage, getOmpCliVersion } from './omp-cli-resolver.js';
export {
boundedPathExists,
describeUnknownPath,
probePath,
probePathKind,
isNearStalledPath,
unknownPathReason,
} from './bounded-path-probe.js';
export type { PathProbeState, PathProbeKind, PathProbeOptions } from './bounded-path-probe.js';