refactor: resolve the tmux socket from the instance config

The socket name was computed inside tmux-manager, which the TUI cannot import
just to learn which `-L` name its degraded-mode listing belongs on (that module
is the server's tmux driver, not a lookup table). The resolver moves next to
`dataPath()`, where the other half of the instance identity already lives, so
both processes agree by construction instead of by a copied default.

Behaviour is unchanged: the override still wins only when it is a name that can
be passed to `tmux -L` safely, and TmuxManager keeps warning about one that
cannot.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Codeman maintainer
2026-08-16 21:35:31 +02:00
parent 4060696faa
commit 00ef72c80e
3 changed files with 43 additions and 7 deletions
+15
View File
@@ -40,6 +40,21 @@ const INSTANCE_SUFFIX = CODEMAN_INSTANCE ? `-${CODEMAN_INSTANCE}` : '';
/** Default tmux socket for this instance. `CODEMAN_TMUX_SOCKET` still overrides. */
export const DEFAULT_TMUX_SOCKET = `codeman${INSTANCE_SUFFIX}`;
/** Characters tmux accepts in a `-L` socket name. */
export const SAFE_TMUX_SOCKET_PATTERN = /^[a-zA-Z0-9_.-]+$/;
/**
* This instance's tmux socket: the `CODEMAN_TMUX_SOCKET` override when it is a
* safe name, else the instance default. Every process that runs `tmux -L` has
* to resolve it through here (the server via TmuxManager, the TUI for its
* degraded-mode listing), or a beta instance ends up driving prod's sessions.
*/
export function resolveTmuxSocketName(): string {
const raw = process.env.CODEMAN_TMUX_SOCKET;
if (raw !== undefined && SAFE_TMUX_SOCKET_PATTERN.test(raw)) return raw;
return DEFAULT_TMUX_SOCKET;
}
let _ensured = false;
/**
+8 -6
View File
@@ -31,7 +31,13 @@ import { existsSync, readFileSync, mkdirSync } from 'node:fs';
import { writeFile, rename } from 'node:fs/promises';
import { dirname } from 'node:path';
import { homedir } from 'node:os';
import { dataPath, DEFAULT_TMUX_SOCKET, CODEMAN_INSTANCE } from './config/instance.js';
import {
dataPath,
DEFAULT_TMUX_SOCKET,
CODEMAN_INSTANCE,
SAFE_TMUX_SOCKET_PATTERN,
resolveTmuxSocketName,
} from './config/instance.js';
import {
ProcessStats,
PersistedRespawnConfig,
@@ -194,9 +200,6 @@ const SAFE_PANE_TARGET_PATTERN = /^(%\d+|\d+)$/;
* `codeman` for prod, `codeman-beta` on the beta branch). */
const DEFAULT_CODEMAN_TMUX_SOCKET = DEFAULT_TMUX_SOCKET;
/** Regex to validate tmux socket names passed to `tmux -L`. */
const SAFE_TMUX_SOCKET_PATTERN = /^[a-zA-Z0-9_.-]+$/;
/**
* Separator used in `tmux list-panes -F` output between session name and pid.
*
@@ -591,9 +594,8 @@ function resolveConfiguredTmuxSocket(): string {
const raw = process.env.CODEMAN_TMUX_SOCKET ?? DEFAULT_CODEMAN_TMUX_SOCKET;
if (!SAFE_TMUX_SOCKET_PATTERN.test(raw)) {
console.warn(`[TmuxManager] Ignoring invalid CODEMAN_TMUX_SOCKET: ${JSON.stringify(raw)}`);
return DEFAULT_CODEMAN_TMUX_SOCKET;
}
return raw;
return resolveTmuxSocketName();
}
/** Build the `tmux -L <socket>` command prefix. Socket name is shell-escaped. */