Commit Graph
27 Commits
Author SHA1 Message Date
Codeman maintainer c5b59633d8 feat(pi): add Pi (pi.dev) as a sixth CLI run mode (#206)
SessionMode gains 'pi', a first-class backend alongside Claude Code,
OpenCode, Codex, Gemini and Antigravity: its own PTY, tmux session, rose
tab identity, welcome button, run-mode entry, cron agentType, Docker and
remote-SSH command defaults, and clone-repo Brain option.

Pi is a different shape of CLI from the other four, and three decisions
follow from that:

- It has NO permission prompts and no sandbox, so there is no
  --dangerously-skip-permissions analog and none was invented. The
  privilege-shaped knob is the tri-state approveProjectTrust, which makes
  pi load and EXECUTE repo-local .pi/extensions TypeScript and install
  missing project packages. clampExternalCliBypassForOwner() therefore
  puts pi in the MATERIALIZE branch: a non-granted multi-user owner gets
  --no-approve even when no config was sent, because pi's own default is
  a prompt the session user could answer themselves. That helper had zero
  test coverage; it now has coverage for all four CLIs.
- Only the PI_ prefix joins the env allowlist. Pi's ~34 provider key vars
  share no prefix and ALLOWED_ENV_PREFIXES is one global list with no mode
  context, so admitting them would widen the allowlist for every mode at
  once. Auth goes through pi's /login or the server's own environment.
  --api-key is deliberately never wired: it would put a provider secret on
  the spawn command line.
- pi stays OUT of isAltScreenStripMode(). Its default TUI renders into the
  main screen with terminal-owned scrollback, and its 0.84.0 fullscreen
  mode is runtime-switchable via /settings; that flip was measured to put
  the pane into the alt screen, which the strip would have corrupted.

pi-cli-resolver.ts additionally sanity-probes `pi --version` and requires
semver-shaped output, because `pi` is a short generic name a stray binary
can shadow; GET /api/pi/status surfaces path and version so a
misresolution is diagnosable rather than presenting as a broken mode.

Docker installs pi in its own --ignore-scripts step so that flag cannot
affect the other four CLIs, and seeds its credentials per-file rather than
whole-dir (~/.pi/agent also holds sessions, extensions and package trees).

Verified end to end against pi 0.84.1 on an isolated instance: resolver
search-dir fallback, flag construction, piConfig persistence across a full
server restart, the trust prompt and its --no-approve suppression, the
rose Run button on the default daylight-blue skin (the nested skin block
eats per-mode gradients unless the rule lives inside it), and the buffer
local-echo policy, which pi tolerates where codex did not.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-13 13:54:47 +02:00
Codeman maintainer b03780dfd2 fix(session): decide working/idle from the pane, not the composer redraw
Every working Claude session reported `status: "idle"` about two seconds
into its turn. Measured on live workers: two sessions mid-tool-call at 13
and 17 minutes both read `idle` while their panes showed
`✻ Actualizing… (13m 23s · ↓ 47.5k tokens)`.

Two things had drifted apart:

1. The working indicator changed. Claude animates the glyph through
   `· ✢ ✳ ∗ ✻ ✽` and randomizes the gerund per turn, so neither
   SPINNER_PATTERN (braille, no longer drawn) nor the keyword list
   (Thinking/Writing/Reading/Running) matches a turn anymore.
2. A `❯` sighting is not the end of a turn. Claude redraws the composer
   roughly once a second all the way through one, and that redraw armed
   the "2s later, call it idle" timer.

Matching the new status line in the STREAM does not fix it either: tmux
ships partial repaints, so the complete line reached the PTY about once
every 20 seconds while the `❯` arrived every second.

So the decision moves off the stream:

- An unbroken run of repaints marks a turn as started. Sampled once a
  second for 12s over six live sessions, the two working ones produced
  output in 12/12 windows and the four idle ones in 0/12. Pure helpers in
  session-activity.ts carry the thresholds.
- Idle now needs the pane to go quiet AND the screen to agree.
  `_confirmIdle()` asks tmux what is rendered (new `capturePaneText()`,
  one plain `capture-pane`, floored at 1.5s per session and only ever at
  a transition) and re-checks every 5s while the screen still shows work.
  A turn can sit silent for tens of seconds inside one tool call, so
  silence alone proves nothing.
- The same screen check vetoes keystroke echo, which is a steady stream
  of repaints too but is not work.

CLAUDE_WORKING_LINE_PATTERN matches the `… (elapsed)` shape rather than
the glyph, because the FINISHED line (`✻ Cooked for 2m 49s`) carries the
same glyph and would otherwise pin a session at working forever.

Claude mode only. An external CLI has no `❯`, so nothing would arm the
confirmation and such a session would latch busy.

respawn-patterns.hasWorkingPattern() had the same blind spot (its gerund
list cannot see "Actualizing"), so it takes the pattern as an extra
signal. That can only make respawn less eager, never more.

Idle now lands about 3 to 5 seconds after a turn ends instead of 2
seconds into one. Verified end to end against a live worker, sampled
against the CLI's own "esc to interrupt" footer as independent ground
truth: busy for all 25s of a turn, idle 3s after it ended.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-09 15:31:02 +02:00
Codeman maintainer 2b89f35599 fix(shell,remote-ssh): allowlist the login flags, and keep only CRASHED remote panes
Follow-up to #209 and #210. Both land a real fix (a pane that is a login shell
picks up /etc/profile and the per-user PATH entries an ssh remote command never
sees, which is what was failing agent CLIs with exit 127). Three corrections:

1. `-i -l` is no longer hardcoded onto the resolved shell. That path ultimately
   comes from the passwd entry, which is user data and can name anything, and a
   shell that rejects an unknown flag exits on the spot: nushell, elvish and xonsh
   take neither flag, so a user with one of those in passwd would have gotten a
   dead pane on arrival, which is exactly the #208 failure #209 builds on top of.
   loginShellArgs() applies them only to the POSIX-family shells verified to
   accept both, and a test really launches every allowlisted shell present on the
   machine rather than trusting the set. csh/tcsh are excluded deliberately: tcsh
   honors -l only when it is the ONLY flag.

2. `remain-on-exit on` -> `failed`, moved LAST in the tmux command chain. `on`
   keeps the pane after a CLEAN exit too, so typing `exit` in a remote shell
   stranded a dead pane, the session outlived it, and the next launch's `-A`
   reattached to that corpse: "Pane is dead (status 0)" instead of a shell,
   permanently, on the DEFAULT path. Verified against a real tmux, as was the
   fix: `failed` tears the session down on status 0 and keeps the pane on 127
   with the "command not found" still on screen, which is the case #210 wanted.
   It is last because tmux aborts the remaining commands of a `\;` sequence once
   one errors (also verified) and `failed` needs tmux >= 3.2 on the REMOTE host;
   leading, a rejection there would have silently dropped status/mouse/prefix/
   escape-time/window-size along with it.

3. `$SHELL` -> `"${SHELL:-/bin/sh}"`, via one shared remoteLoginShellCommand()
   helper instead of the string being rebuilt in tmux-manager as well.

Also corrects the rationale both PRs carried: a tmux pane already hands the shell
a tty, so it was interactive all along ($- contains i for a bare /bin/bash in a
pane) and ~/.bashrc was always being sourced. `-l` is the flag doing the work.

End-to-end verified, not just unit-tested: the emitted remote pane command was
run through all three quoting layers under a minimal sshd-style PATH with the
CLI installed only on a login-shell PATH entry, and it resolved and launched the
CLI with its arguments intact and a space-containing remote path preserved.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-05 01:40:37 +02:00
Codeman maintainer 529d8fa8ea chore: version packages 2026-08-04 23:09:00 +02:00
Codeman maintainer 23f258a85d chore: version packages
Release 1.9.8 (aicodeman) and 0.1.8 (xterm-zerolag-input).

Fixes macOS session start (`posix_spawnp failed.`, issues #6 and #204):
node-pty ships its macOS spawn-helper as mode 0644 and macOS launches every
PTY through it. `scripts/fix-node-pty.mjs` (npm run fix:node-pty) chmods every
helper, prebuilds/ included, then verifies by really opening a PTY; the blind
Node-22+ rebuild is gone. `spawnPtyWithHelperRepair()` self-heals an already
broken install on the first failed spawn.

Adds the phone home screen (session overview under 430px, per-device
`mobileOverviewEnabled`, default ON) and a guided Tailscale path in
install.sh, plus `install.sh tailscale` to retrofit it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-04 15:02:46 +02:00
Codeman maintainer 26cbbe0dcb feat(cli): Antigravity run mode
Adds Antigravity as a sixth CLI backend alongside Claude Code, shell, OpenCode,
Codex and Gemini, following the existing pluggable-resolver pattern.

- `utils/antigravity-cli-resolver.ts` resolves the CLI, mirroring the other
  resolvers; `GET /api/antigravity/status` reports availability and path.
- `ANTIGRAVITY_*` joins the `ALLOWED_ENV_PREFIXES` allowlist in schemas.ts, so
  env overrides stay CLI-scoped rather than blanket-forwarded.
- Session, tmux-manager, mux-interface and types carry the new mode; secrets are
  injected via socket-scoped `tmux setenv`, never on the spawn command line, so
  the mode requires tmux with no direct PTY fallback like the other external CLIs.
- Frontend: Run-dropdown entry, agent-type option, `ag` tab badge and toolbar
  colours. `runAntigravity()` routes remote/docker cases through
  `POST /api/quick-start` and skips the local status probe for them.

Tests: test/antigravity-mode.test.ts, plus run-mode-ui and system-routes coverage.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-04 12:59:40 +02:00
Codeman maintainer 7b79d4207c fix(terminal): restore Claude scroll-back on macOS trackpads (#154)
Deterministic claude --version probe seeds cliVersion so wheel-forwarding
to Claude's transcript engages (banner scrape was unreliable on 2.1.187+
and resumed sessions). Shift+wheel reads the dominant axis so a trackpad's
horizontal Shift-scroll reaches local scrollback. New per-device
"Wheel Scrolls Local History" opt-out. Wheel reports use a fire-and-forget
send path so they no longer flicker the pending-bytes indicator.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 09:33:39 +02:00
Codeman maintainer 368fc20fc2 fix: address PR review findings for Gemini run mode + Ralph todo-config
Gemini (PR #134) blockers:
- runGemini() now unwraps the {success,data} envelope: status check reads
  .data.available, quick-start reads data.data.sessionId (was reading the raw
  shape, so the Run-Gemini button could never start a session).
- setGeminiEnvVars() now uses the socket-scoped ${this.tmux()} setenv instead of
  bare tmux — Gemini/Google auth env vars were targeting the wrong tmux server
  and silently failing on every install.

Gemini parity polish:
- gemini tab-mode badge ('gm') + .tab-mode.gemini CSS; kill-dialog label
  'Kill Tmux & Gemini'; codeman doctor dependency-registry entry; export
  isGeminiAvailable from utils barrel; COLORTERM=truecolor + unset NO_COLOR;
  add gemini to isAltScreenStripMode (Ink TUI, repaints inline like Codex/Claude).
- Revert 4 system-routes.test.ts envelope assertions weakened to
  (body.message ?? body.error) back to (body.success === false).
- Add a runGemini() vm-sandbox test that drives the envelope path end-to-end.

Ralph todo-config (PR #135): maxTodos/todoExpirationMinutes are now persisted
and read back — surfaced via the loopState getter (RalphTrackerState) into
toState()/SSE broadcast and restored in restoreState(), mirroring maxIterations.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 00:26:06 +02:00
Aamer Akhter 19139837e4 feat: add Gemini run mode 2026-06-19 13:10:17 -04:00
Aamer AkhterandSaqeb Akhter 70378315da feat(codex): add Codex (OpenAI CLI) run-mode foundation
Add Codex as a first-class session mode alongside Claude/Shell/OpenCode.

- codex-cli-resolver: locate the `codex` binary and augment PATH (mirrors the
  OpenCode resolver)
- SessionMode 'codex' + CodexConfig (model, resumeSessionId, dangerouslyBypass,
  renderMode); persisted in SessionState and threaded through CreateSession/
  RespawnPane options
- schema validation: CodexConfigSchema, CODEX_ env-var prefix allowlist, mode
  enums on create/quick-start, codexDangerouslyBypassApprovals setting
- tmux launch: buildCodexCommand, setenv for OPENAI_API_KEY/CODEX_* (keeps
  secrets out of ps), truecolor COLORTERM, codex PATH resolution
- session + routes: availability check (clear install hint), config passthrough,
  tmux-required guard; Codex skips Claude-only parsers (Ralph/respawn/token)
- run-mode UI: "Run CX" selector option + dedicated Codex CLI settings tab with
  the bypass-approvals toggle; GET /api/codex/status

Scope: foundation only. Codex terminal redraw handling and xterm snapshot/replay
are intentionally excluded and tracked separately.

Verification: tsc --noEmit, eslint, prettier --check, check:frontend-syntax all
clean; full test:ci suite green (2712 passed, 0 failed); server boot smoke OK.

Co-Authored-By: Saqeb Akhter <saqeb.akhter@gmail.com>
2026-06-10 09:34:52 -04:00
arkonandClaude Opus 4.8 b84438a0aa fix(security): push-endpoint SSRF guard + tmux name validation; document tail-file roots
- M7 (SSRF): add isSafePushEndpoint (https-only; reject internal/loopback/link-local/metadata IPs incl. IPv4-mapped); enforce in PushSubscribeSchema and re-check before webpush.sendNotification. + unit test.
- M1 (command injection): validate tmux session names with isValidMuxName in sessionExists, killSession, and reconcileSessions before they reach a shell call site.
- M5: keep the intentional /var/log + ~/logs log-tail roots (a tested feature) and document the wider read scope in docs/security-architecture.md section 5 instead of dropping it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 20:02:17 +02:00
Tenggan ZhangandTeigen 06f9ff6d9c fix: avoid event-loop stalls from synchronous tmux/ps calls (#100)
The stats collector (~2s) and mouse-mode sync (5s) ran execSync (pgrep/ps/
list-panes, 5s timeout each) per session on the server's single thread,
blocking the event loop. With several sessions or a momentarily slow tmux this
froze port 3000 for seconds-to-tens-of-seconds while the process stayed alive
and other ports were unaffected — self-healing, so it never restarted and the
60s loopback healthcheck missed it. Convert these hot-path calls to execAsync.

Also add an always-on event-loop lag monitor (utils/event-loop-monitor.ts) that
logs stalls >=1s to the web log, so this otherwise-invisible class of incident
leaves a quantified, timestamped trace.

Co-authored-by: Teigen <teigen@TeigendeMac-mini.local>
2026-06-01 19:32:24 +02:00
arkonandClaude Opus 4.7 02e2f3e8b5 refactor: remove dead code and narrow internal exports (knip sweep)
Knip-driven cleanup. All changes verified with tsc --noEmit, lint, and
build.

Removed (zero consumers):
- VERIFICATION_PROMPT constant + its barrel re-export
- createInitialOrchestratorPersistState factory
- transcriptWatcher singleton export
- createAnsiPatternFull / createAnsiPatternSimple factories
- TimerInfo interface + unused AiCheckResult/AiPlanCheckResult imports
  in respawn-controller.ts
- 35 unused Zod z.infer \`*Input\` types in schemas.ts
- Dead re-exports: SessionMode from session.ts, AuthSessionRecord from
  web/ports/index.ts, EnhancedPlanTask/CheckpointReview from
  ralph-tracker.ts, 7 unused entries in utils/index.ts
- 14 event/config interfaces that lived only as JSDoc hints (no TS type
  position usage): Session/Respawn/RalphLoop/RalphTracker/
  SessionManager/SessionAutoOps/Subagent/TaskQueue/TaskTracker/
  TranscriptWatcher/Image/OrchestratorLoop Events + RespawnPreset +
  SessionOutput

Narrowed to module scope (kept but no longer exported):
- buildPermissionArgs in session-cli-builder.ts
- 28 type/interface declarations used only within their own file:
  Ai{Idle,Plan}Check{Config,State}, BashToolParser{Events,Config},
  FileStream/CreateStream{Options,Result}, PlanSubagentEvent,
  SubagentCallback, RalphLoopConfig, RalphLoop{Events,Options},
  ActiveTimerInfo, DetectionStatus, ActionLogEntry, AutoOpsCallbacks,
  TunnelStatus, Timer/LRUMap/StaleExpirationMap Options, AuthState,
  SessionListenerDeps, SseStreamManagerDeps, and 8 more

Docs: CLAUDE.md advice for global-regex `lastIndex` now points to the
remaining `execPattern()` helper instead of the deleted factories.

Knip delta: unused files 42→0, unused exports 161→16, unused types 92→0.
The 16 remaining exports are a mobile-test helper toolkit intentionally
kept for upcoming tests.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 11:57:00 +02:00
arkonandClaude Opus 4.6 0717cfbfec refactor: codebase cleanup — dead code, regex helper, centralized constants, tests
- Remove unused validateTokenCounts/validateTokensAndCost exports and PlanPhase type alias
- Add execPattern() helper to eliminate 8 repetitive .lastIndex=0 + exec() loops
- Centralize 11 magic number constants into config/ai-defaults.ts and config/server-timing.ts
- Remove stale src/tui from tsconfig.json exclude
- Fix CLAUDE.md inaccuracies (session helpers, app.js line count, module count)
- Add 316 new tests: LRUMap (38), StaleExpirationMap (42), BufferAccumulator (33),
  respawn helpers (142), system-routes expansion (11→61)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 07:33:44 +01:00
arkonandClaude Opus 4.6 e0a2774d37 perf: implement phase 1-3 performance optimizations
Add implementation plans and code structure analysis for a 3-phase
performance optimization effort. Refactor core modules to reduce
timer overhead, consolidate regex usage, extract exec timeout config,
add debouncer utility, and streamline server/schema validation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 17:39:44 +01:00
arkonandClaude Opus 4.6 545913790b chore: remove dead code and unused exports (-159 lines)
Remove confirmed-unused code found via team-based codebase analysis:
- Dead interfaces: SessionResponse (types.ts), PlannerResult (plan-orchestrator.ts)
- Dead functions: withTimeout (session.ts), getOpenCodeAugmentedPath, resetOpenCodeCache (opencode-cli-resolver.ts)
- Dead config constants: MAX_RUN_SUMMARY_EVENTS, TRIM_RUN_SUMMARY_TO, MAX_MESSAGES_PER_CHANNEL (buffer-limits.ts), MAX_TRACKED_AGENTS, MAX_SUBAGENT_ACTIVITY_PER_AGENT, MAX_TOOL_RESULTS_PER_AGENT, COMPLETED_TODO_TTL_MS (map-limits.ts)
- Dead legacy code: idleTimer property + clearIdleTimer() no-op method + 6 call sites (respawn-controller.ts)
- Stale barrel re-exports: createAnsiPatternFull/Simple, validateTokenCounts/Cost, stripAnsi, normalizePhrase, getOpenCodeAugmentedPath (utils/index.ts)
- Un-exported internal-only symbols: ErrorMessages (types.ts), destroyRalphLoop (ralph-loop.ts)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 02:01:21 +01:00
480584de63 chore: project setup and tooling cleanup (#26)
* add project setup

* add tools to eslint

* remove contributing.md

* update claude md

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

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

* use node 20

* adjust formatting

* fix linting

* format

* fix layout

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

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

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: arkon <arkon.85@hotmail.com>
2026-02-27 13:16:23 +01:00
arkonandClaude Opus 4.6 0b60f2691f feat: OpenCode integration Phases 1-3 — types, CLI resolver, tmux spawn
Phase 1: Type system
- Add SessionMode = 'claude' | 'shell' | 'opencode' to types.ts (single source of truth)
- Add OpenCodeConfig interface (model, autoAllowTools, continueSession, etc.)
- Add openCodeConfig to SessionState
- Import SessionMode in session.ts, mux-interface.ts (remove duplicates)
- Refactor createSession/respawnPane to options objects (CreateSessionOptions, RespawnPaneOptions)

Phase 2: CLI resolver
- New opencode-cli-resolver.ts mirroring claude-cli-resolver.ts
- Searches ~/.opencode/bin, ~/.local/bin, /usr/local/bin, ~/go/bin, etc.
- Exported via utils/index.ts

Phase 3: Tmux spawn
- Extract buildSpawnCommand() shared helper (eliminates duplication)
- Add buildOpenCodeCommand() for opencode CLI flags
- Add setOpenCodeEnvVars() — API keys via tmux setenv (not visible in ps)
- Add setOpenCodeConfigContent() — JSON config via tmux setenv (prevents shell injection)
- Gate _processExpensiveParsers() for opencode mode (skip Claude-specific parsers)
- OpenCode-specific TUI ready detection (timeout-based, no ❯ prompt scanning)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-02-26 10:07:43 +01:00
arkon 0fe6251424 chore: bump version to 0.1585 2026-02-21 07:12:57 +01:00
arkon 926e77b1c2 chore: bump version to 0.1550 2026-02-19 08:49:36 +01:00
arkonandClaude Opus 4.6 0314de7789 fix: bulletproof test safety — IS_TEST_MODE guards prevent tests from killing real tmux sessions
Added IS_TEST_MODE (process.env.VITEST) guards to every method in TmuxManager and
ScreenManager that touches real tmux/screen sessions. Tests can never create, kill,
discover, or send input to real sessions. Removed broken E2E test suite entirely.
Rewrote test/setup.ts from 459 lines to minimal cleanup. Rewrote tmux-related tests
to verify test-mode safety behavior.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 18:26:16 +01:00
arkon 59a8f6bd7d chore: bump version to 0.1485 2026-02-12 11:35:10 +01:00
arkonandClaude Opus 4.5 8f0bbf33d6 chore: bump version to 0.1477
Location: Ko Samui

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 07:24:32 +01:00
arkon 5b6dd078f1 chore: bump version to 0.1438 2026-01-30 17:20:53 +01:00
arkonandClaude Opus 4.5 6c07541288 refactor: consolidate shared regex patterns and token validation
- Create src/utils/regex-patterns.ts with ANSI_ESCAPE_PATTERN_FULL,
  ANSI_ESCAPE_PATTERN_SIMPLE, TOKEN_PATTERN, and helper functions
- Create src/utils/token-validation.ts with MAX_SESSION_TOKENS and
  validation utilities
- Update session.ts, respawn-controller.ts, ai-checker-base.ts,
  ralph-tracker.ts, state-store.ts to use shared utilities
- Export all new utilities from src/utils/index.ts

Reduces code duplication while maintaining pre-compiled patterns
for performance.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-29 10:55:49 +01:00
arkonandClaude Opus 4.5 596098015f feat: add StaleExpirationMap utility for TTL-based cache expiration
- Automatically removes entries not accessed within TTL
- Periodic cleanup with configurable interval
- Optional onExpire callback for cleanup notifications
- Refresh TTL on get (configurable)
- Touch, peek, getAge, getRemainingTtl methods
- Full iteration support
- Implements Disposable interface

Useful for caching ephemeral data like pending tool calls, subagent activity.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 04:41:49 +01:00
arkonandClaude Opus 4.5 83e5b0b78e feat: add resource management types and utilities for memory optimization
- Add Disposable, BufferConfig, MemoryMetrics, CleanupRegistration types
- Create src/config/buffer-limits.ts with consolidated buffer size constants
- Create src/config/map-limits.ts with Map size limits to prevent unbounded growth
- Implement BufferAccumulator utility with configurable trim and onTrim callback
- Implement LRUMap with automatic eviction and O(1) operations
- Implement CleanupManager for unified resource cleanup with isStopped guard
- Add comprehensive tests for all new utilities

This lays the foundation for memory leak prevention and performance improvements.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 04:35:20 +01:00