surface Claude Code Workflow runs in convo + sidebar (T-416)
A `Workflow` tool-use launches its multi-agent run in the background and returns immediately; the real fan-out arrives out-of-band on stream-json `type:"system"` task_* events (task_started / task_progress / task_updated / task_notification) keyed by the launching tool-use id — which clide was dropping. (Wire shape captured by two live stream-json probes; recorded on the ticket.) - workflow_run.dart: a pure, Flutter-free WorkflowRun/WorkflowAgent model that folds those events (phases, per-agent start→progress→done deltas, usage) into a snapshot. - StreamJsonSession recognises the events, accumulates a Map<toolUseId, WorkflowRun>, and exposes `workflows` + `workflowsStream`. - A `Workflow` tool-use with a live run renders a dedicated run card — phase groups, per-agent rows with spinner/check status, usage, and the script — falling back to the generic tool card pre-progress or on reload. The run breaks the activity cluster so it's always first-class (like T-342). - The sidebar Activity tab adds a WORKFLOWS section: one row per run with its done/total agent count, tinted by running/done state. Closes T-416 and the T-410 epic (all children done). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -9,12 +9,20 @@ import 'package:clide/builtin/claude/src/claude_stats.dart';
|
||||
import 'package:clide/builtin/claude/src/claude_status.dart' show ClaudeUsage, formatTokenCount, permissionModeLabel, shortModelLabel;
|
||||
import 'package:clide/builtin/claude/src/meta_sidebar/models.dart';
|
||||
import 'package:clide/builtin/claude/src/transcript_reader.dart' show SessionStatus;
|
||||
import 'package:clide/builtin/claude/src/workflow_run.dart';
|
||||
import 'package:clide/kernel/kernel.dart';
|
||||
import 'package:clide/widgets/widgets.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
class ActivityTabView extends StatelessWidget {
|
||||
const ActivityTabView({super.key, required this.stats, required this.primaryStatus, required this.config, this.usage});
|
||||
const ActivityTabView({
|
||||
super.key,
|
||||
required this.stats,
|
||||
required this.primaryStatus,
|
||||
required this.config,
|
||||
this.usage,
|
||||
this.workflows = const <String, WorkflowRun>{},
|
||||
});
|
||||
|
||||
final ClaudeStats stats;
|
||||
final SessionStatus? primaryStatus;
|
||||
@@ -24,6 +32,11 @@ class ActivityTabView extends StatelessWidget {
|
||||
/// control (T-415). Null until the first refresh.
|
||||
final ClaudeUsage? usage;
|
||||
|
||||
/// Live Workflow runs in the primary session, keyed by launching tool-use id
|
||||
/// (T-416). Rendered as an aggregate WORKFLOWS section — one row per run with
|
||||
/// its done/total agent count and running/done state.
|
||||
final Map<String, WorkflowRun> workflows;
|
||||
|
||||
/// Publish a slash command for the primary pane to execute — the session
|
||||
/// controls are the same code path as typing the command (D-6).
|
||||
void _command(BuildContext context, String text) {
|
||||
@@ -36,6 +49,7 @@ class ActivityTabView extends StatelessWidget {
|
||||
final latest = stats.latest;
|
||||
final u = usage;
|
||||
final sections = <MetaSection>[
|
||||
..._workflowSection(tokens),
|
||||
if (u != null)
|
||||
MetaSection('USAGE', [
|
||||
if (u.session != null) MetaRow('session', u.session!),
|
||||
@@ -94,6 +108,24 @@ class ActivityTabView extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
/// An aggregate WORKFLOWS section while one or more workflow runs exist this
|
||||
/// session (T-416): a row per run — its name and `done/total agents`, tinted
|
||||
/// focus while running and success once complete.
|
||||
List<MetaSection> _workflowSection(SurfaceTokens tokens) {
|
||||
final runs = workflows.values.toList();
|
||||
if (runs.isEmpty) return const [];
|
||||
return [
|
||||
MetaSection('WORKFLOWS', [
|
||||
for (final r in runs)
|
||||
MetaRow(
|
||||
r.name ?? r.taskId ?? 'workflow',
|
||||
r.agentCount == 0 ? (r.done ? 'done' : 'starting') : '${r.doneCount}/${r.agentCount} agents${r.done ? ' ✓' : ''}',
|
||||
valueColor: r.done ? tokens.statusSuccess : tokens.globalFocus,
|
||||
),
|
||||
]),
|
||||
];
|
||||
}
|
||||
|
||||
List<MetaSection> _runtimeSection(SurfaceTokens tokens) {
|
||||
final st = primaryStatus;
|
||||
final skills = config?.skills.length;
|
||||
|
||||
Reference in New Issue
Block a user