mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-09 00:49:41 +02:00
fix: date a working row by its turn, not by the session age
`TuiSessionRow` declared `lastSubmitAt`/`inputTokens`/`outputTokens`, `stateSince()` ordered the WORKING group by the first of them and `renderRowLines()` painted the other two, but nothing ever filled any of them in: the unified list carries none, and the `session:updated` payload that does was discarded (an event only schedules a refetch). So a running turn was dated by its SESSION's creation instead. Measured against the live server before the fix: w65 (created 21h ago, turn started one minute earlier) outranked w67 (created 15 minutes ago, turn started five minutes earlier), the reverse of the rule docs/tui.md states, and the elapsed column read `21h` for a turn a minute old. The token column was unreachable code for the same reason. `fetchLiveSessionMetrics()` reads the three fields from `GET /api/sessions` and `applyLiveMetrics()` folds them onto the rows. That route answers from the server's cached LIGHT state (no terminal buffers): 10-20ms measured, against the ~550ms the unified list in the same `Promise.all` already costs, so it is cheap enough to ride every refresh. It is best-effort like the approvals and tmux reads beside it, because losing the anchor is better than losing the list. A ZERO is treated as unknown rather than merged: `stateSince()` reads `lastSubmitAt ?? createdAt` and 0 is not nullish, so a merged 0 would date every never-submitted session to the epoch. The snapshot path gets the same merge, or `codeman tui --list` would number the WORKING group differently from the dashboard that `codeman tui <n>` indexes into. Verified live: working rows now show 28m/8m (turn age, tokens 280.5k/65.2k) where they showed 21h/34m and no tokens. The e2e assertion fails on master's wiring with `[*] 10m` against a session that pressed Enter one minute ago. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -63,6 +63,17 @@ const defaultResponder: Responder = (req, res) => {
|
||||
data: { sessions: [{ sessionId: 'abc', name: 'w1-codeman', sources: ['live'] }], total: 1 },
|
||||
});
|
||||
}
|
||||
if (url === '/api/sessions' || url.startsWith('/api/sessions?')) {
|
||||
// The light state, plus the two rows the narrowing has to discard.
|
||||
return sendJson(res, 200, {
|
||||
success: true,
|
||||
data: [
|
||||
{ id: 'abc', lastSubmitAt: 4000, inputTokens: 900, outputTokens: 100, status: 'busy' },
|
||||
{ id: '', lastSubmitAt: 7000 },
|
||||
{ id: 'zzz', lastSubmitAt: '5', inputTokens: null },
|
||||
],
|
||||
});
|
||||
}
|
||||
if (url.startsWith('/api/approvals')) {
|
||||
return sendJson(res, 200, {
|
||||
success: true,
|
||||
@@ -318,6 +329,23 @@ describe('TuiClient remaining API surface', () => {
|
||||
expect(recorded[0].url).toBe('/api/sessions/abc/terminal?tail=4096');
|
||||
});
|
||||
|
||||
it('reads the turn stamp and token counters off the light session state', async () => {
|
||||
const metrics = await client().fetchLiveSessionMetrics();
|
||||
expect(recorded[0].url).toBe('/api/sessions');
|
||||
// Narrowed to the three fields, keyed by id: a row with no usable id is
|
||||
// dropped rather than folded in under an empty key, and a field of the
|
||||
// wrong type is left absent rather than merged as a string.
|
||||
expect(metrics).toEqual([
|
||||
{ sessionId: 'abc', lastSubmitAt: 4000, inputTokens: 900, outputTokens: 100 },
|
||||
{ sessionId: 'zzz' },
|
||||
]);
|
||||
});
|
||||
|
||||
it('reports an unreadable session list as empty rather than throwing', async () => {
|
||||
responder = (_req, res) => sendJson(res, 200, { success: true, data: { sessions: 'not an array' } });
|
||||
await expect(client().fetchLiveSessionMetrics()).resolves.toEqual([]);
|
||||
});
|
||||
|
||||
it('starts sessions through quick-start', async () => {
|
||||
const result = await client().quickStart({ caseName: 'x', mode: 'claude', parentSessionId: 'abc' });
|
||||
expect(result.sessionId).toBe('new-1');
|
||||
|
||||
Reference in New Issue
Block a user