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:
@@ -106,3 +106,74 @@ class DaemonEvent extends ClideEvent {
|
||||
@override
|
||||
Map<String, Object?> payload() => {'ts': ts.toIso8601String(), ...data};
|
||||
}
|
||||
|
||||
/// A Claude Code tmux teammate appeared (its pane is live). Identity is
|
||||
/// taken from the team config, so it is reliable regardless of transcript
|
||||
/// drift (T-139, D-75). [transcriptPath] is the best-effort resolved
|
||||
/// subagent transcript, or null if it could not be joined yet.
|
||||
class TeamMemberBorn extends ClideEvent {
|
||||
const TeamMemberBorn({
|
||||
required this.team,
|
||||
required this.agentId,
|
||||
required this.name,
|
||||
required this.agentType,
|
||||
required this.paneId,
|
||||
this.model,
|
||||
this.color,
|
||||
this.cwd,
|
||||
this.transcriptPath,
|
||||
});
|
||||
|
||||
/// Team name (the `~/.claude/teams/<team>` directory).
|
||||
final String team;
|
||||
|
||||
/// Config agent id (`<name>@<team>`).
|
||||
final String agentId;
|
||||
final String name;
|
||||
final String agentType;
|
||||
|
||||
/// tmux pane id (`%N`).
|
||||
final String paneId;
|
||||
final String? model;
|
||||
final String? color;
|
||||
final String? cwd;
|
||||
final String? transcriptPath;
|
||||
|
||||
@override
|
||||
String get subsystem => 'team';
|
||||
@override
|
||||
String get kind => 'member-born';
|
||||
@override
|
||||
Map<String, Object?> payload() => {
|
||||
'team': team,
|
||||
'agentId': agentId,
|
||||
'name': name,
|
||||
'agentType': agentType,
|
||||
'paneId': paneId,
|
||||
if (model != null) 'model': model,
|
||||
if (color != null) 'color': color,
|
||||
if (cwd != null) 'cwd': cwd,
|
||||
if (transcriptPath != null) 'transcriptPath': transcriptPath,
|
||||
};
|
||||
}
|
||||
|
||||
/// A Claude Code tmux teammate's pane went away (it exited or the team
|
||||
/// dissolved) — T-139.
|
||||
class TeamMemberDied extends ClideEvent {
|
||||
const TeamMemberDied({
|
||||
required this.team,
|
||||
required this.agentId,
|
||||
required this.paneId,
|
||||
});
|
||||
|
||||
final String team;
|
||||
final String agentId;
|
||||
final String paneId;
|
||||
|
||||
@override
|
||||
String get subsystem => 'team';
|
||||
@override
|
||||
String get kind => 'member-died';
|
||||
@override
|
||||
Map<String, Object?> payload() => {'team': team, 'agentId': agentId, 'paneId': paneId};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user