Read workflow-status telemetry from CLI transcript files

Dynamic ultracode workflows run as a detached background task with their
own transcript dir, so their subagent events never flow through the main
-p stream. The previous parent_tool_use_id tap therefore captured nothing
for real workflows and the status stayed "none" the whole run.

Replace the tap with a file-based reader:
- TapWorkflowLaunch parses the "Transcript dir:" line from the Workflow
  tool_result and registers the run.
- WorkflowProgressTracker becomes a per-session registry of transcript
  paths (no longer a stream accumulator).
- WorkflowTelemetryReader reads journal.jsonl for live counts (running)
  and <runId>.json for rich per-agent telemetry (completed); FinalizeChain
  persists the rich JSON into chains.workflow_info.
- Modal renders phases + a per-agent list (label/phase/state/tokens/
  tool-calls/duration) instead of the obsolete tool breakdown.

Sync ARCHITECTURE.md, ARCHITECTURE_QUICK.md and README.md to the new
mechanism.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
MelekiandClaude Opus 4.8 committed 2026-06-20 18:14:42 +02:00
1 parent b6e546f618
commit 2b95161596
9 files changed
+453 -175

No files matched your search

+90 -8
View File
@@ -1025,9 +1025,27 @@
opacity: var(--semi-transparent);
}
.wf-title {
display: flex;
flex-direction: column;
gap: .15em;
margin-bottom: var(--box-spacing);
}
.wf-name {
font-family: var(--mono);
color: var(--text-accent);
font-weight: 600;
}
.wf-summary {
font-size: .9em;
opacity: var(--semi-transparent);
}
.wf-stat-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-template-columns: repeat(auto-fit, minmax(88px, 1fr));
gap: var(--badge-spacing);
}
@@ -1060,27 +1078,91 @@
margin-bottom: var(--badge-spacing);
}
.wf-tool-list {
/* Phasen-Liste */
.wf-phase-list {
display: flex;
flex-direction: column;
gap: var(--border-width);
}
.wf-tool-row {
.wf-phase-row {
display: flex;
justify-content: space-between;
align-items: baseline;
gap: var(--badge-spacing);
padding: .35em var(--badge-spacing);
background: var(--f3-bg);
border-radius: var(--border-radius);
}
.wf-tool-name {
font-family: var(--mono);
.wf-phase-title {
font-weight: 600;
}
.wf-tool-count {
color: var(--primary);
.wf-phase-detail {
font-size: .85em;
opacity: var(--semi-transparent);
}
/* Subagenten-Liste */
.wf-agent-list {
display: flex;
flex-direction: column;
gap: var(--border-width);
}
.wf-agent-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: var(--badge-spacing);
padding: .4em var(--badge-spacing);
background: var(--f3-bg);
border-radius: var(--border-radius);
}
.wf-agent-main {
display: flex;
align-items: center;
gap: var(--badge-spacing);
min-width: 0;
}
.wf-agent-state {
width: .6em;
height: .6em;
border-radius: 50%;
flex-shrink: 0;
background: var(--text);
}
.wf-agent-state.wf-ag-done { background: var(--secondary); }
.wf-agent-state.wf-ag-running { background: var(--info); }
.wf-agent-state.wf-ag-other { background: var(--primary); opacity: var(--semi-transparent); }
.wf-agent-label {
font-weight: 600;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.wf-agent-phase {
font-size: .8em;
opacity: var(--semi-transparent);
white-space: nowrap;
}
.wf-agent-metrics {
display: flex;
gap: var(--box-spacing);
font-family: var(--mono);
font-size: .82em;
opacity: var(--semi-transparent);
flex-shrink: 0;
}
.wf-agent-metrics span {
white-space: nowrap;
}
.wf-meta {