Complete three overdue cleanups discovered during macOS health check: D-56 daemon dissolution: delete bin/clide.dart, DaemonServer, and orphaned tests (test/cli/, subprocess_test, in_process_test). Update stale "clide --daemon" references in i18n catalogs, error messages, editor_commands, CI scripts, and decision records. ptyc retirement: delete ptyc/ source tree, PtySession, scm_rights. Remove from Toolchain resolution, ToolCheck gate, backend serialization, testmode harness, Makefile, CI, and sandbox entitlements. PTY spawning uses NativePty (Dart FFI forkpty) since the terminal was absorbed in-tree. D-5 amended. Golden tests: wire the existing but never-applied clideGoldenConfig via flutter_test_config.dart. Disable CI goldens (Skia anti-aliasing differs between macOS/Linux even with Ahem). Keep platform-keyed goldens only — goldens/linux/ and goldens/macos/ each run on their own OS. Test suite: 826 pass, 0 fail on macOS (was 829 pass, 11 fail). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
57 lines
2.1 KiB
Dart
57 lines
2.1 KiB
Dart
/// tmux server interactions for Claude panes (D-41 lifecycle).
|
|
///
|
|
/// `pane.close` only kills the PTY-spawned tmux *client*; tmux is
|
|
/// client/server, so the server-side session keeps running after the
|
|
/// client disconnects. To honour D-41 ("closing a secondary kills that
|
|
/// tmux session" + "secondary numbering resets between clide runs"),
|
|
/// we need explicit `tmux kill-session` calls — that's what lives here.
|
|
library;
|
|
|
|
import 'dart:io';
|
|
|
|
/// Override-able runner so tests don't shell out for real.
|
|
typedef TmuxRunner = Future<ProcessResult> Function(List<String> args);
|
|
|
|
TmuxRunner tmuxRunner = _defaultRunner;
|
|
|
|
Future<ProcessResult> _defaultRunner(List<String> args) => Process.run('tmux', args);
|
|
|
|
const _socket = ['-L', 'clide'];
|
|
|
|
/// Kill the named tmux session on the clide socket. No-op if the
|
|
/// session does not exist (kill-session exits non-zero — we ignore it).
|
|
Future<void> killSession(String name) async {
|
|
await tmuxRunner([..._socket, 'kill-session', '-t', name]);
|
|
}
|
|
|
|
/// Return the names of all sessions currently alive on the clide
|
|
/// socket. Empty list if the server is not running.
|
|
Future<List<String>> listClideSessions() async {
|
|
final r = await tmuxRunner([..._socket, 'list-sessions', '-F', '#{session_name}']);
|
|
if (r.exitCode != 0) return const [];
|
|
return (r.stdout as String).split('\n').map((s) => s.trim()).where((s) => s.isNotEmpty).toList();
|
|
}
|
|
|
|
/// Kill every secondary clide-claude session whose name begins with
|
|
/// [primaryName] and ends with `-<digits>`. Leaves the primary itself
|
|
/// alive (D-41).
|
|
Future<void> reapSecondaries(String primaryName) async {
|
|
final pattern = RegExp('^${RegExp.escape(primaryName)}-\\d+\$');
|
|
for (final s in await listClideSessions()) {
|
|
if (pattern.hasMatch(s)) {
|
|
await killSession(s);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Kill every clide-claude session for [primaryName], including the
|
|
/// primary itself. Used by the explicit `claude.kill-all-sessions`
|
|
/// command when the user wants a hard reset.
|
|
Future<void> killAllForRepo(String primaryName) async {
|
|
for (final s in await listClideSessions()) {
|
|
if (s == primaryName || s.startsWith('$primaryName-')) {
|
|
await killSession(s);
|
|
}
|
|
}
|
|
}
|