1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
|
// subtask-placeholder.test.mjs — placeholder text for empty subtask rollup
//
// Run with: node --test web/test/subtask-placeholder.test.mjs
import { describe, it } from 'node:test';
import assert from 'node:assert/strict';
// ── Logic under test ──────────────────────────────────────────────────────────
//
// When a task is BLOCKED/READY and the subtask list is empty, the rollup shows
// meaningful content instead of a generic placeholder:
// 1. task.elaboration_input (raw user prompt) if present
// 2. task.description truncated to ~120 chars (word boundary)
// 3. fallback to task.name if no description
// 4. fallback to 'Waiting for subtasks…' if neither
function truncateToWordBoundary(text, maxLen = 120) {
if (!text || text.length <= maxLen) return text;
const cut = text.lastIndexOf(' ', maxLen);
return (cut > 0 ? text.slice(0, cut) : text.slice(0, maxLen)) + '…';
}
function getSubtaskPlaceholder(task) {
const blurb = task.elaboration_input || task.description || task.name;
return blurb ? truncateToWordBoundary(blurb) : 'Waiting for subtasks…';
}
// ── Tests ─────────────────────────────────────────────────────────────────────
describe('truncateToWordBoundary', () => {
it('returns text unchanged when shorter than maxLen', () => {
assert.equal(truncateToWordBoundary('hello world', 120), 'hello world');
});
it('returns text unchanged when exactly maxLen', () => {
const text = 'a'.repeat(120);
assert.equal(truncateToWordBoundary(text, 120), text);
});
it('truncates at word boundary and appends ellipsis', () => {
const text = 'Fix the login bug that causes users to be logged out unexpectedly when they navigate between pages in the application user interface';
const result = truncateToWordBoundary(text, 120);
assert.ok(result.length <= 121, `result too long: ${result.length}`);
assert.ok(result.endsWith('…'), 'should end with ellipsis');
assert.ok(result.startsWith('Fix the'), 'should keep beginning of text');
});
it('truncates at character boundary when no word boundary exists', () => {
const text = 'a'.repeat(200);
const result = truncateToWordBoundary(text, 120);
assert.equal(result, 'a'.repeat(120) + '…');
});
it('returns empty string unchanged', () => {
assert.equal(truncateToWordBoundary(''), '');
});
it('returns null unchanged', () => {
assert.equal(truncateToWordBoundary(null), null);
});
});
describe('getSubtaskPlaceholder', () => {
it('prefers task.elaboration_input over description and name', () => {
const task = { elaboration_input: 'fix the login bug', description: 'Fix authentication issue', name: 'auth-fix' };
assert.equal(getSubtaskPlaceholder(task), 'fix the login bug');
});
it('truncates task.elaboration_input at 120 chars', () => {
const longInput = 'Please fix the login bug that causes users to be logged out unexpectedly when they navigate between pages in the application user interface';
const task = { elaboration_input: longInput, name: 'auth-fix' };
const result = getSubtaskPlaceholder(task);
assert.ok(result.endsWith('…'), 'should end with ellipsis');
assert.ok(result.length <= 122, `result too long: ${result.length}`);
});
it('uses task.description when elaboration_input is absent', () => {
const task = { description: 'Fix auth bug', name: 'auth-fix' };
assert.equal(getSubtaskPlaceholder(task), 'Fix auth bug');
});
it('truncates task.description at 120 chars', () => {
const longDesc = 'This is a very long description that exceeds the limit. ' +
'It goes on and on describing what the task is about in great detail. ' +
'Eventually it reaches the maximum allowed length.';
const task = { description: longDesc, name: 'long-task' };
const result = getSubtaskPlaceholder(task);
assert.ok(result.endsWith('…'), 'should end with ellipsis');
assert.ok(result.length <= 122, `result too long: ${result.length}`);
});
it('falls back to task.name when description is absent', () => {
const task = { name: 'deploy-frontend' };
assert.equal(getSubtaskPlaceholder(task), 'deploy-frontend');
});
it('falls back to task.name when description is empty string', () => {
const task = { description: '', name: 'deploy-frontend' };
assert.equal(getSubtaskPlaceholder(task), 'deploy-frontend');
});
it('falls back to generic text when both description and name are absent', () => {
const task = {};
assert.equal(getSubtaskPlaceholder(task), 'Waiting for subtasks…');
});
});
|