taskchef 7.26.0 → 7.26.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -31,7 +31,10 @@ export function ActivityTimeline({ highlightTurnRef, task }: { highlightTurnRef:
31
31
  <Stack gap={7}>
32
32
  <Box className="taskchef-turn-heading">
33
33
  <StatusBadge status={presentation.status} />
34
- <RelativeTime label="Turn update time" value={presentation.updatedAt} />
34
+ <Box className="taskchef-turn-timing">
35
+ <RelativeTime label="Turn update time" value={presentation.updatedAt} />
36
+ <TurnReportedWork turn={turn} />
37
+ </Box>
35
38
  </Box>
36
39
  {presentation.sourceLabel && <Text c="dimmed" size="xs">{presentation.sourceLabel}</Text>}
37
40
  <Box>
@@ -63,7 +66,6 @@ export function ActivityTimeline({ highlightTurnRef, task }: { highlightTurnRef:
63
66
  title={usage.title}
64
67
  value={usage.cost.value}
65
68
  />
66
- <TurnReportedWorkMetric turn={turn} />
67
69
  </Box>
68
70
  {usage.note && <Text c="dimmed" size="xs">{usage.note}</Text>}
69
71
  <Text c="dimmed" className="taskchef-mono" size="xs">Turn ref: {identity ?? "—"}</Text>
@@ -75,16 +77,20 @@ export function ActivityTimeline({ highlightTurnRef, task }: { highlightTurnRef:
75
77
  );
76
78
  }
77
79
 
78
- function TurnReportedWorkMetric({ turn }: { turn: TaskTurn }) {
80
+ function TurnReportedWork({ turn }: { turn: TaskTurn }) {
79
81
  const now = useLiveNow(turn.result === null);
80
82
  const elapsed = turnReportedWorkView(turn, now);
81
83
  return (
82
- <TurnMetric
83
- accessibleLabel={elapsed.accessibleLabel}
84
- label={elapsed.label}
84
+ <Text
85
+ aria-label={elapsed.accessibleLabel}
86
+ c="dimmed"
87
+ className="taskchef-turn-duration"
88
+ size="xs"
85
89
  title={elapsed.title}
86
- value={elapsed.value}
87
- />
90
+ >
91
+ <span className="taskchef-field-label">{elapsed.label}</span>
92
+ <span>{elapsed.value}</span>
93
+ </Text>
88
94
  );
89
95
  }
90
96
 
@@ -70,11 +70,15 @@ test("covers terminal, active, and unavailable timeline metrics", () => {
70
70
  <MantineProvider><ActivityTimeline highlightTurnRef={null} task={task} /></MantineProvider>,
71
71
  );
72
72
  const metrics = container.querySelector(".taskchef-turn-metrics") as HTMLElement;
73
+ const timing = container.querySelector(".taskchef-turn-timing") as HTMLElement;
73
74
  expect(metrics).not.toBeNull();
75
+ expect(timing).not.toBeNull();
74
76
  expect(within(metrics).getByText("Tokens").nextSibling).toHaveTextContent("330");
75
77
  expect(within(metrics).getByText("Estimated cost").nextSibling).toHaveTextContent("$0.12");
76
- expect(within(metrics).getByText("Elapsed").nextSibling).toHaveTextContent("18m 32s");
77
- expect(within(metrics).getByLabelText(/completed turn reported wall-clock elapsed time/i)).toBeVisible();
78
+ expect(within(metrics).queryByText("Elapsed")).not.toBeInTheDocument();
79
+ expect(within(timing).getByLabelText(/^Turn update time:/i)).toBeVisible();
80
+ expect(within(timing).getByLabelText(/completed turn reported wall-clock elapsed time/i))
81
+ .toHaveTextContent("Elapsed18m 32s");
78
82
  cleanup();
79
83
  }
80
84
 
@@ -89,7 +93,8 @@ test("covers terminal, active, and unavailable timeline metrics", () => {
89
93
  vi.spyOn(window, "clearInterval").mockImplementation(() => undefined);
90
94
  const task = fixtureTask();
91
95
  render(<MantineProvider><ActivityTimeline highlightTurnRef={null} task={task} /></MantineProvider>);
92
- expect(screen.getByText("Elapsed so far").nextSibling).toHaveTextContent("18m 32s");
96
+ expect(screen.getByLabelText(/current turn reported wall-clock elapsed time/i))
97
+ .toHaveTextContent("Elapsed so far18m 32s");
93
98
  expect(screen.getByText("Tokens").nextSibling).toHaveTextContent("Pending");
94
99
  expect(screen.getByText("Estimated cost").nextSibling).toHaveTextContent("Pending");
95
100
 
@@ -98,7 +103,8 @@ test("covers terminal, active, and unavailable timeline metrics", () => {
98
103
  tick?.();
99
104
  });
100
105
 
101
- expect(screen.getByText("Elapsed so far").nextSibling).toHaveTextContent("18m 34s");
106
+ expect(screen.getByLabelText(/current turn reported wall-clock elapsed time/i))
107
+ .toHaveTextContent("Elapsed so far18m 34s");
102
108
  cleanup();
103
109
  vi.restoreAllMocks();
104
110
  }
@@ -126,8 +132,8 @@ test("covers terminal, active, and unavailable timeline metrics", () => {
126
132
  },
127
133
  });
128
134
  render(<MantineProvider><ActivityTimeline highlightTurnRef={null} task={task} /></MantineProvider>);
129
- expect(screen.getByText("Elapsed").nextSibling).toHaveTextContent("Unavailable");
130
- expect(screen.getByLabelText(/elapsed unavailable.*reported wall-clock/i)).toBeVisible();
135
+ expect(screen.getByLabelText(/elapsed unavailable.*reported wall-clock/i))
136
+ .toHaveTextContent("ElapsedUnavailable");
131
137
  expect(screen.getByText("Manual dashboard turns do not have usage boundaries.")).toBeVisible();
132
138
  expect(screen.getByLabelText(/tokens unavailable: manual dashboard turns/i)).toBeVisible();
133
139
  }
@@ -81,7 +81,9 @@ body {
81
81
  .taskchef-turn { background: var(--taskchef-surface-muted); }
82
82
  .taskchef-turn-highlighted { border-color: var(--mantine-color-teal-6); box-shadow: inset 3px 0 var(--mantine-color-teal-6); outline: 3px solid color-mix(in srgb, var(--mantine-color-teal-6) 22%, transparent); }
83
83
  .taskchef-turn-heading { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
84
- .taskchef-turn-metrics { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--mantine-spacing-xs); }
84
+ .taskchef-turn-timing { display: flex; align-items: center; justify-content: flex-end; gap: var(--mantine-spacing-sm); min-width: 0; }
85
+ .taskchef-turn-duration { display: inline-flex; align-items: baseline; gap: 4px; white-space: nowrap; }
86
+ .taskchef-turn-metrics { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--mantine-spacing-xs); }
85
87
  .taskchef-turn-metric { min-width: 0; overflow-wrap: anywhere; }
86
88
  .taskchef-mono { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; overflow-wrap: anywhere; }
87
89
  .taskchef-code-panel { max-height: 280px; margin: 0; padding: 12px; overflow: auto; border-radius: var(--mantine-radius-md); background: var(--taskchef-surface-muted); white-space: pre-wrap; overflow-wrap: anywhere; font: 0.78rem/1.55 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
@@ -123,6 +125,8 @@ body {
123
125
  .taskchef-metadata { grid-template-columns: 1fr; }
124
126
  .taskchef-metrics { grid-template-columns: repeat(2, minmax(0, 1fr)); }
125
127
  .taskchef-turn-metrics { grid-template-columns: 1fr; }
128
+ .taskchef-turn-heading { align-items: flex-start; flex-direction: column; gap: 6px; }
129
+ .taskchef-turn-timing { flex-wrap: wrap; justify-content: flex-start; }
126
130
  .taskchef-metadata dt { padding-bottom: 0; border-bottom: 0; }
127
131
  }
128
132