add tmux team observer + member lifecycle events (T-139, D-75)
test / unit + widget + golden + a11y (push) Failing after 27s
test / integration_test (xvfb) (push) Has been skipped
test / bundle smoke (xvfb 5s) (push) Has been skipped
test / daemon subprocess + web WASM smoke (push) Has been skipped
test / dart doc (lib API) (push) Failing after 24s
test / unit + widget + golden + a11y (push) Failing after 27s
test / integration_test (xvfb) (push) Has been skipped
test / bundle smoke (xvfb 5s) (push) Has been skipped
test / daemon subprocess + web WASM smoke (push) Has been skipped
test / dart doc (lib API) (push) Failing after 24s
team_observer.dart is the single drift-containment point for Claude Code's experimental tmux team mode. It discovers the active team for a workspace (~/.claude/teams/<team>/config.json, matched by member cwd), polls `tmux -L clide list-panes -a`, and correlates live panes with the config's tmuxPaneId to emit TeamMemberBorn / TeamMemberDied — identity (name, agentType, model, colour, pane) comes from the config, so it's reliable regardless of transcript drift. Each teammate's subagent transcript is resolved best-effort and streamed on a per-agent MessageBus channel via TranscriptPublisher (TranscriptReader gains an explicit `file:` for this). The config<->transcript join is the fragile part: no shared key, so it uses a sibling .meta.json agentType when present, else zips members-by-joinedAt against files-by-mtime. This join needs validation against a live team run. App wiring + visible surfacing land with the teammate tiles (T-140). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -187,10 +187,12 @@ class TranscriptReader {
|
||||
void Function(String)? onWarn,
|
||||
String? projectsBase,
|
||||
int? initialTailBytes,
|
||||
String? file,
|
||||
}) : _pollInterval = pollInterval,
|
||||
_onWarn = onWarn ?? _defaultWarn,
|
||||
_projectsBase = projectsBase ?? _defaultProjectsBase(),
|
||||
_initialTailBytes = initialTailBytes ?? _defaultInitialTailBytes;
|
||||
_initialTailBytes = initialTailBytes ?? _defaultInitialTailBytes,
|
||||
_explicitFile = file;
|
||||
|
||||
final String workspacePath;
|
||||
final Duration _pollInterval;
|
||||
@@ -205,6 +207,11 @@ class TranscriptReader {
|
||||
/// temp directory instead of the user's home.
|
||||
final String _projectsBase;
|
||||
|
||||
/// When set, tail this exact file instead of discovering the newest
|
||||
/// `.jsonl` in the munged dir. Used for teammate subagent transcripts
|
||||
/// (T-139), whose path the team observer resolves explicitly.
|
||||
final String? _explicitFile;
|
||||
|
||||
static String _defaultProjectsBase() {
|
||||
final home = Platform.environment['HOME'] ?? '';
|
||||
return home.isNotEmpty ? '$home/.claude/projects' : '.claude/projects';
|
||||
@@ -287,10 +294,9 @@ class TranscriptReader {
|
||||
}
|
||||
|
||||
Future<void> _tick(StreamController<ConversationItem> controller) async {
|
||||
final dir = _mungedDir();
|
||||
|
||||
// Discover or refresh the active session file.
|
||||
final newest = await _newestJsonl(dir);
|
||||
// A teammate reader tails one fixed file; otherwise discover the
|
||||
// newest session `.jsonl` in the munged dir.
|
||||
final newest = _explicitFile ?? await _newestJsonl(_mungedDir());
|
||||
if (newest == null) return;
|
||||
|
||||
if (newest != _currentPath) {
|
||||
|
||||
Reference in New Issue
Block a user