pi-goal-x 0.25.1 → 0.25.2
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.
- package/README.md +4 -6
- package/docs/.pi/goals/.goals-pool-snapshot.json +1 -0
- package/docs/.pi/goals/{active_goal_2026080612411949_mshg3jex-svqfyt.md → archived/goal_2026080613543398_mshg3jex-svqfyt.md} +6 -6
- package/docs/.pi/goals/{active_goal_2026080613564540_mshisjml-bl1gar.md → archived/goal_2026080614052654_mshisjml-bl1gar.md} +4 -4
- package/docs/.pi/goals/archived/goal_2026080614441814_mshk5uvt-nnkztu.md +80 -0
- package/docs/.pi/goals/archived/goal_2026080708140425_msilpn44-qqa4fa.md +76 -0
- package/docs/.pi/goals/archived/goal_2026080708322737_msim9m81-5aa98r.md +92 -0
- package/docs/.pi/goals/goal_events.jsonl +42 -0
- package/docs/unified-dashboard.md +36 -31
- package/extensions/goal-state.ts +6 -4
- package/extensions/widgets/goal-dashboard-model.ts +32 -12
- package/extensions/widgets/goal-dashboard-renderer.ts +74 -59
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -249,17 +249,15 @@ Verify that the generated report contains every required section.
|
|
|
249
249
|
Always visible above the editor while a goal is focused:
|
|
250
250
|
|
|
251
251
|
```text
|
|
252
|
-
╭─ pi-goal-x ─ Add CSV export to reports
|
|
253
|
-
│
|
|
254
|
-
|
|
255
|
-
├─ Tasks ────────────────────────────────────────────────────────────┤
|
|
252
|
+
╭─ pi-goal-x ─ Add CSV export to reports ────────────────────────────╮
|
|
253
|
+
│ goal: running [12m47s 18.2K] (+2 open) │
|
|
254
|
+
├─ Tasks · ✓3 done · 2 open ──────────── [█████░░░] · Sub 2/3 [██░░] ┤
|
|
256
255
|
│ ✓ t1 Review reports page and data source │
|
|
257
256
|
│ ✓ t2 Implement filtered CSV export │
|
|
258
|
-
│ ▸ t3 Add the download button
|
|
257
|
+
│ ▸ t3 Add the download button ☑ ▸ 2/3 │
|
|
259
258
|
│ · t4 Add documentation │
|
|
260
259
|
│ … +1 more task │
|
|
261
260
|
│ Current t3 · Add the download button │
|
|
262
|
-
│ Subtasks [███████░░░] 2/3 · 67% │
|
|
263
261
|
│ Verify Run npm test with zero failures. │
|
|
264
262
|
│ File .pi/goals/active_goal_... │
|
|
265
263
|
╰─ Ctrl+Shift+T: expand tasks ───────────────────────────────────────╯
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":1,"dirMtimeMs":1786087947377.8738,"goals":[]}
|
|
@@ -10,13 +10,12 @@
|
|
|
10
10
|
},
|
|
11
11
|
"sisyphus": false,
|
|
12
12
|
"createdAt": "2026-08-06T11:41:19.497Z",
|
|
13
|
-
"updatedAt": "2026-08-
|
|
14
|
-
"
|
|
15
|
-
"stopReason": "agent",
|
|
13
|
+
"updatedAt": "2026-08-06T13:26:28.723Z",
|
|
14
|
+
"stopReason": "user",
|
|
16
15
|
"pauseReason": "All deliverables verified and committed; the goal cannot complete without the user's signoff (criterion 7) and their acceptance of the documented B4 content-floor exemption (recommendation (a)). Presenting for review in the terminal.",
|
|
17
16
|
"pauseSuggestedAction": "Open specs/2026-08-06-non-agent-flow-optimization/BENCH-DIFF.md + HEADROOM.md and sign off: confirm the B4 content-floor exemption (or run /goal-tweak to relax targets / authorize guidance removal instead). Then tell me to complete the goal.",
|
|
18
17
|
"skipAuditor": true,
|
|
19
|
-
"revision":
|
|
18
|
+
"revision": 163,
|
|
20
19
|
"taskList": {
|
|
21
20
|
"tasks": [
|
|
22
21
|
{
|
|
@@ -50,7 +49,8 @@
|
|
|
50
49
|
"proposedAt": "2026-08-06T11:38:58.636Z"
|
|
51
50
|
},
|
|
52
51
|
"currentTaskId": "task-4",
|
|
53
|
-
"verificationContract": "run `npm run bench` (fresh BEFORE committed, then AFTER), `npm run bench:gate` PASS (including the new ≥10x invariant), `npm test` 0 failures, `npm run check` clean, re-read this goal and confirm every success criterion is met, then user signoff in a real terminal."
|
|
52
|
+
"verificationContract": "run `npm run bench` (fresh BEFORE committed, then AFTER), `npm run bench:gate` PASS (including the new ≥10x invariant), `npm test` 0 failures, `npm run check` clean, re-read this goal and confirm every success criterion is met, then user signoff in a real terminal.",
|
|
53
|
+
"archivedPath": ".pi/goals/archived/goal_2026080613543398_mshg3jex-svqfyt.md"
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
# Goal Prompt
|
|
@@ -68,7 +68,7 @@ If blocked: stop and ask the user.
|
|
|
68
68
|
|
|
69
69
|
## Progress
|
|
70
70
|
|
|
71
|
-
- Status: paused
|
|
71
|
+
- Status: paused
|
|
72
72
|
- Auto-continue: off
|
|
73
73
|
- Sisyphus mode: no
|
|
74
74
|
- Time spent: 36m29s
|
|
@@ -10,11 +10,10 @@
|
|
|
10
10
|
},
|
|
11
11
|
"sisyphus": false,
|
|
12
12
|
"createdAt": "2026-08-06T12:56:45.405Z",
|
|
13
|
-
"updatedAt": "2026-08-06T13:
|
|
14
|
-
"activePath": ".pi/goals/active_goal_2026080613564540_mshisjml-bl1gar.md",
|
|
13
|
+
"updatedAt": "2026-08-06T13:26:32.828Z",
|
|
15
14
|
"stopReason": "user",
|
|
16
15
|
"skipAuditor": true,
|
|
17
|
-
"revision":
|
|
16
|
+
"revision": 81,
|
|
18
17
|
"taskList": {
|
|
19
18
|
"tasks": [
|
|
20
19
|
{
|
|
@@ -56,7 +55,8 @@
|
|
|
56
55
|
"blockCompletion": true,
|
|
57
56
|
"proposedAt": "2026-08-06T12:56:41.516Z"
|
|
58
57
|
},
|
|
59
|
-
"currentTaskId": "task-6"
|
|
58
|
+
"currentTaskId": "task-6",
|
|
59
|
+
"archivedPath": ".pi/goals/archived/goal_2026080614052654_mshisjml-bl1gar.md"
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
# Goal Prompt
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"id": "mshk5uvt-nnkztu",
|
|
4
|
+
"objective": "Move goal status information from the bottom of the pi screen into the goal widget: in both the compact and expanded dashboard status lines, replace the \"Focused: yes / Other goals: N\" bits with `goal: <statusLabel> [<elapsed> <tokens>] (+N open)` using the footer-status formatting (statusLabel + usage bracket, no objective preview — the header title already shows it, and the header's right-side usage folds away to avoid duplication), and stop rendering the focused-goal footer line (setStatus(\"goal\", undefined) when a goal is focused) while keeping the unfocused hint — with updated tests/goldens, spec docs, CHANGELOG entry, and a green validation, on a new branch off main.",
|
|
5
|
+
"status": "complete",
|
|
6
|
+
"autoContinue": true,
|
|
7
|
+
"usage": {
|
|
8
|
+
"tokensUsed": 120532,
|
|
9
|
+
"activeSeconds": 517
|
|
10
|
+
},
|
|
11
|
+
"sisyphus": false,
|
|
12
|
+
"skipAuditor": true,
|
|
13
|
+
"revision": 64,
|
|
14
|
+
"createdAt": "2026-08-06T13:35:06.137Z",
|
|
15
|
+
"updatedAt": "2026-08-06T13:44:18.147Z",
|
|
16
|
+
"taskList": {
|
|
17
|
+
"tasks": [
|
|
18
|
+
{
|
|
19
|
+
"id": "task-1",
|
|
20
|
+
"title": "New branch off main (e.g. feat/goal-widget-status) + scaffold specs/YYYY-MM-DD-goal-widget-status/ (PRODUCT.md, TECH.md, MILESTONES.md)",
|
|
21
|
+
"status": "complete",
|
|
22
|
+
"completedAt": "2026-08-06T13:35:37.864Z",
|
|
23
|
+
"evidence": "Branch feat/goal-widget-status created off main (15aa826); specs/2026-08-06-goal-widget-status/ scaffolded with PRODUCT.md, TECH.md, MILESTONES.md (user decisions recorded)."
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"id": "task-2",
|
|
27
|
+
"title": "Renderer change: compact + expanded dashboard status lines show `goal: <statusLabel> [<elapsed> <tokens>] (+N open)` (footer-status formatting via statusLabel + usage bits, no objective preview); remove the Focused:/Other goals: bits and the header's right-side usage (now redundant)",
|
|
28
|
+
"status": "complete",
|
|
29
|
+
"completedAt": "2026-08-06T13:40:01.161Z",
|
|
30
|
+
"evidence": "Renderer (compact + expanded) + model updated: status lines now render `goal: <footerLabel> [<footerBits>] (+N open)` via shared statusLine() helper; Focused:/Other goals: bits, STATUS_SYMBOL, and dea"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"id": "task-3",
|
|
34
|
+
"title": "Footer removal: goal-state.ts renderUI stops calling setStatus('goal', ...) when a goal is focused (widget is the single home); keep the unfocused `goal: unfocused [N open]` hint",
|
|
35
|
+
"status": "complete",
|
|
36
|
+
"completedAt": "2026-08-06T13:40:31.928Z",
|
|
37
|
+
"evidence": "goal-state.ts renderUI: focused-goal branch now calls setStatus('goal', undefined) (clears stale unfocused hint); unfocused hint branch untouched; unused footerStatus import removed; tsc clean."
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"id": "task-4",
|
|
41
|
+
"title": "Tests + goldens: update pinned assertions (In progress · Focused: yes, Other goals: 2) in goal-widget.test.ts, goal-dashboard-golden.test.ts, goal-status.test.ts; add new assertions pinning the `goal: <status> [<usage>] (+N open)` format in compact + expanded",
|
|
42
|
+
"status": "complete",
|
|
43
|
+
"completedAt": "2026-08-06T13:43:06.406Z",
|
|
44
|
+
"evidence": "Updated pinned assertions in goal-widget.test.ts (7), goal-dashboard-golden.test.ts (6 incl. new expanded status-line pin), goal-status.test.ts (1), goal-dashboard-model.test.ts (2: footerBits usage +"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"id": "task-5",
|
|
48
|
+
"title": "Docs + validation + commit: CHANGELOG Unreleased entry, PRODUCT/TECH/MILESTONES per AGENTS.md, npm run check clean, npm test 0 failures, grep confirms no Focused:/Other goals: text remains, commit on the new branch",
|
|
49
|
+
"status": "complete",
|
|
50
|
+
"completedAt": "2026-08-06T13:44:11.522Z",
|
|
51
|
+
"evidence": "CHANGELOG [Unreleased] entry added; PRODUCT/TECH/MILESTONES updated; npm run check clean; npm test 665/665 pass; grep confirms no functional Focused:/Other goals: remnants and no footerStatus(displayG"
|
|
52
|
+
}
|
|
53
|
+
],
|
|
54
|
+
"blockCompletion": true,
|
|
55
|
+
"proposedAt": "2026-08-06T13:33:22.135Z"
|
|
56
|
+
},
|
|
57
|
+
"stopReason": "agent",
|
|
58
|
+
"archivedPath": ".pi/goals/archived/goal_2026080614441814_mshk5uvt-nnkztu.md"
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
# Goal Prompt
|
|
62
|
+
|
|
63
|
+
Move goal status information from the bottom of the pi screen into the goal widget: in both the compact and expanded dashboard status lines, replace the "Focused: yes / Other goals: N" bits with `goal: <statusLabel> [<elapsed> <tokens>] (+N open)` using the footer-status formatting (statusLabel + usage bracket, no objective preview — the header title already shows it, and the header's right-side usage folds away to avoid duplication), and stop rendering the focused-goal footer line (setStatus("goal", undefined) when a goal is focused) while keeping the unfocused hint — with updated tests/goldens, spec docs, CHANGELOG entry, and a green validation, on a new branch off main.
|
|
64
|
+
|
|
65
|
+
## Progress
|
|
66
|
+
|
|
67
|
+
- Status: complete
|
|
68
|
+
- Auto-continue: on
|
|
69
|
+
- Sisyphus mode: no
|
|
70
|
+
- Time spent: 8m37s
|
|
71
|
+
- Tokens used: 121K (120,532) tokens
|
|
72
|
+
## Tasks
|
|
73
|
+
|
|
74
|
+
<!-- blockCompletion: true -->
|
|
75
|
+
- [x] task-1: New branch off main (e.g. feat/goal-widget-status) + scaffold specs/YYYY-MM-DD-goal-widget-status/ (PRODUCT.md, TECH.md, MILESTONES.md) — evidence: Branch feat/goal-widget-status created off main (15aa826); specs/2026-08-06-goal-widget-status/ scaffolded with PRODUCT.md, TECH.md, MILESTONES.md (user decisions recorded).
|
|
76
|
+
- [x] task-2: Renderer change: compact + expanded dashboard status lines show `goal: <statusLabel> [<elapsed> <tokens>] (+N open)` (footer-status formatting via statusLabel + usage bits, no objective preview); remove the Focused:/Other goals: bits and the header's right-side usage (now redundant) — evidence: Renderer (compact + expanded) + model updated: status lines now render `goal: <footerLabel> [<footerBits>] (+N open)` via shared statusLine() helper; Focused:/Other goals: bits, STATUS_SYMBOL, and dea
|
|
77
|
+
- [x] task-3: Footer removal: goal-state.ts renderUI stops calling setStatus('goal', ...) when a goal is focused (widget is the single home); keep the unfocused `goal: unfocused [N open]` hint — evidence: goal-state.ts renderUI: focused-goal branch now calls setStatus('goal', undefined) (clears stale unfocused hint); unfocused hint branch untouched; unused footerStatus import removed; tsc clean.
|
|
78
|
+
- [x] task-4: Tests + goldens: update pinned assertions (In progress · Focused: yes, Other goals: 2) in goal-widget.test.ts, goal-dashboard-golden.test.ts, goal-status.test.ts; add new assertions pinning the `goal: <status> [<usage>] (+N open)` format in compact + expanded — evidence: Updated pinned assertions in goal-widget.test.ts (7), goal-dashboard-golden.test.ts (6 incl. new expanded status-line pin), goal-status.test.ts (1), goal-dashboard-model.test.ts (2: footerBits usage +
|
|
79
|
+
- [x] task-5: Docs + validation + commit: CHANGELOG Unreleased entry, PRODUCT/TECH/MILESTONES per AGENTS.md, npm run check clean, npm test 0 failures, grep confirms no Focused:/Other goals: text remains, commit on the new branch — evidence: CHANGELOG [Unreleased] entry added; PRODUCT/TECH/MILESTONES updated; npm run check clean; npm test 665/665 pass; grep confirms no functional Focused:/Other goals: remnants and no footerStatus(displayG
|
|
80
|
+
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"id": "msilpn44-qqa4fa",
|
|
4
|
+
"objective": "Add task counts and a progress bar to the compact goal dashboard's \"Tasks\" header row, and make subtask progress visible per task row: the header becomes a single row with `✓N done · M open` (skipped counted as done) followed by a compact progress bar at the end of the row, the redundant standalone compact `Tasks [bar] X/Y · %` line is removed (expanded dashboard keeps its Progress section unchanged), task rows with subtasks show a `▸ done/total` marker, and the current-task subtask bar is kept.",
|
|
5
|
+
"status": "complete",
|
|
6
|
+
"autoContinue": true,
|
|
7
|
+
"usage": {
|
|
8
|
+
"tokensUsed": 113743,
|
|
9
|
+
"activeSeconds": 421
|
|
10
|
+
},
|
|
11
|
+
"sisyphus": false,
|
|
12
|
+
"skipAuditor": true,
|
|
13
|
+
"revision": 69,
|
|
14
|
+
"createdAt": "2026-08-07T07:06:14.980Z",
|
|
15
|
+
"updatedAt": "2026-08-07T07:14:04.254Z",
|
|
16
|
+
"taskList": {
|
|
17
|
+
"tasks": [
|
|
18
|
+
{
|
|
19
|
+
"id": "spec-docs",
|
|
20
|
+
"title": "Write spec docs (PRODUCT.md, TECH.md, MILESTONES.md) under specs/2026-08-07-compact-task-counts/",
|
|
21
|
+
"status": "complete",
|
|
22
|
+
"verificationContract": "Spec dir exists per AGENTS.md convention; PRODUCT.md documents the header row (counts then bar at the end), removal of the standalone compact progress line, and subtask markers; TECH.md covers model/renderer changes; MILESTONES.md updated throughout implementation.",
|
|
23
|
+
"completedAt": "2026-08-07T07:08:11.771Z",
|
|
24
|
+
"evidence": "specs/2026-08-07-compact-task-counts/ created with PRODUCT.md (header row counts+bar-at-end, standalone-line removal, subtask markers), TECH.md (model/renderer/test changes), MILESTONES.md."
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"id": "model",
|
|
28
|
+
"title": "Extend the dashboard model so each task node carries subtask counts (total + completed) for per-row markers; keep top-level progress derivation for the header bar/counts",
|
|
29
|
+
"status": "complete",
|
|
30
|
+
"verificationContract": "DashboardTaskNode gains subtask fields populated by flattenTaskTree (or equivalent); unit tests in goal-dashboard-model.test.ts pin the new fields; tsc clean.",
|
|
31
|
+
"completedAt": "2026-08-07T07:09:05.403Z",
|
|
32
|
+
"evidence": "DashboardTaskNode gains required totalSubtasks/completedSubtasks populated by flattenTaskTree (direct children, skipped=done); model tests pin parent 2/3, leaves 0, skipped-as-done; npm run check clea"
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"id": "renderer",
|
|
36
|
+
"title": "Compact dashboard: single Tasks header row with `✓N done · M open` first and a compact progress bar at the end of the row, remove the standalone compact progress line, add per-row subtask markers in the windowed list without breaking width bounds",
|
|
37
|
+
"status": "complete",
|
|
38
|
+
"verificationContract": "Compact render shows a single `├─ Tasks …` header containing `✓N done · M open` (skipped counts as done) followed by a progress bar at the end of the row before the closing frame; the standalone `Tasks [bar]` line is gone from compact; rows with subtasks show `▸ done/total`; tasks without subtasks show no marker; current-task subtask bar intact; expanded dashboard unchanged; header/rows truncate safely within the bounded width across wide/medium/narrow/minimal modes.",
|
|
39
|
+
"completedAt": "2026-08-07T07:13:51.345Z",
|
|
40
|
+
"evidence": "Compact header is `├─ Tasks · ✓3 done · 2 open ──... [█████░░░] ┤` (counts then bar at end, skipped=done); standalone compact progress line removed; `▸ done/total` markers on rows with subtasks (leaf "
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"id": "tests-docs",
|
|
44
|
+
"title": "Update unit + golden tests, run full validation, update CHANGELOG",
|
|
45
|
+
"status": "complete",
|
|
46
|
+
"verificationContract": "npm run check (tsc --noEmit) clean; npm test full suite green with goldens pinned to the new header format and subtask markers; grep confirms no standalone compact progress-line format remains; CHANGELOG entry added.",
|
|
47
|
+
"completedAt": "2026-08-07T07:13:51.346Z",
|
|
48
|
+
"evidence": "npm run check clean; npm test 667/667 green; test:integration 28/28 green; goldens pinned to new header/marker formats; grep: no `Tasks [` in extensions/tests; README + docs/unified-dashboard.md exam"
|
|
49
|
+
}
|
|
50
|
+
],
|
|
51
|
+
"blockCompletion": false,
|
|
52
|
+
"proposedAt": "2026-08-07T07:05:48.948Z"
|
|
53
|
+
},
|
|
54
|
+
"stopReason": "agent",
|
|
55
|
+
"archivedPath": ".pi/goals/archived/goal_2026080708140425_msilpn44-qqa4fa.md"
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
# Goal Prompt
|
|
59
|
+
|
|
60
|
+
Add task counts and a progress bar to the compact goal dashboard's "Tasks" header row, and make subtask progress visible per task row: the header becomes a single row with `✓N done · M open` (skipped counted as done) followed by a compact progress bar at the end of the row, the redundant standalone compact `Tasks [bar] X/Y · %` line is removed (expanded dashboard keeps its Progress section unchanged), task rows with subtasks show a `▸ done/total` marker, and the current-task subtask bar is kept.
|
|
61
|
+
|
|
62
|
+
## Progress
|
|
63
|
+
|
|
64
|
+
- Status: complete
|
|
65
|
+
- Auto-continue: on
|
|
66
|
+
- Sisyphus mode: no
|
|
67
|
+
- Time spent: 7m01s
|
|
68
|
+
- Tokens used: 114K (113,743) tokens
|
|
69
|
+
## Tasks
|
|
70
|
+
|
|
71
|
+
<!-- blockCompletion: false -->
|
|
72
|
+
- [x] spec-docs: Write spec docs (PRODUCT.md, TECH.md, MILESTONES.md) under specs/2026-08-07-compact-task-counts/ — evidence: specs/2026-08-07-compact-task-counts/ created with PRODUCT.md (header row counts+bar-at-end, standalone-line removal, subtask markers), TECH.md (model/renderer/test changes), MILESTONES.md.
|
|
73
|
+
- [x] model: Extend the dashboard model so each task node carries subtask counts (total + completed) for per-row markers; keep top-level progress derivation for the header bar/counts — evidence: DashboardTaskNode gains required totalSubtasks/completedSubtasks populated by flattenTaskTree (direct children, skipped=done); model tests pin parent 2/3, leaves 0, skipped-as-done; npm run check clea
|
|
74
|
+
- [x] renderer: Compact dashboard: single Tasks header row with `✓N done · M open` first and a compact progress bar at the end of the row, remove the standalone compact progress line, add per-row subtask markers in the windowed list without breaking width bounds — evidence: Compact header is `├─ Tasks · ✓3 done · 2 open ──... [█████░░░] ┤` (counts then bar at end, skipped=done); standalone compact progress line removed; `▸ done/total` markers on rows with subtasks (leaf
|
|
75
|
+
- [x] tests-docs: Update unit + golden tests, run full validation, update CHANGELOG — evidence: npm run check clean; npm test 667/667 green; test:integration 28/28 green; goldens pinned to new header/marker formats; grep: no `Tasks [` in extensions/tests; README + docs/unified-dashboard.md exam
|
|
76
|
+
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"id": "msim9m81-5aa98r",
|
|
4
|
+
"objective": "Move the compact dashboard's subtask progress bar next to the task progress bar in the Tasks header row: the header becomes a single row with `✓N done · M open` (skipped counted as done), the task progress bar, then a short `Sub done/total` label with the subtask bar beside it (e.g. `├─ Tasks · ✓3 done · 2 open ─ [█████░░░] · Sub 2/3 [██░░] ┤`, shown only when the current task has subtasks); the standalone `Subtasks [bar] done/total · %` line is removed from the compact view; per-row `▸ done/total` markers and the expanded dashboard's Progress/current-task sections stay unchanged; the header remains width-safe in every layout mode.\n\nSuccess criteria:\n- The compact dashboard's Tasks section rule renders as one row: counts first (`✓N done · M open`, skipped counted as done), then a dash run, then the task progress bar, then ` · Sub done/total ` and the subtask progress bar beside it — only when the current task has subtasks; when the current task is a leaf (or there is no current task), the subtask segment is omitted.\n- The standalone compact `Subtasks [bar] done/total · %` line is gone from the compact dashboard; the current task's subtask data now lives only in the header segment and the per-row `▸ done/total` markers.\n- Per-row `▸ done/total` markers on tasks with direct subtasks remain; leaf rows show none.\n- The expanded dashboard is byte-identical to today: its Progress section and the Current-task block's `Subtasks [bar] 2/3 · 67%` line are unchanged.\n- The header truncates width-safely across all layout modes (wide/medium/narrow/minimal): the counts and both bars always survive; only the label/dash run may shrink.\n\nBoundaries:\n- In scope: extensions/widgets/goal-dashboard-renderer.ts (compact header rendering, removal of the standalone Subtasks line), spec docs under specs/2026-08-07-compact-task-counts/, golden/unit/e2e tests, README.md, docs/unified-dashboard.md, CHANGELOG.md.\n- Out of scope: the model layer (DashboardTaskNode subtask counts and taskProgress already provide everything needed), the expanded dashboard, per-row marker semantics, current-task block content, and any other widget.\n\nConstraints:\n- Follow AGENTS.md: spec docs live in specs/2026-08-07-compact-task-counts/ with MILESTONES.md updated throughout.\n- No new dependencies; no changes to expanded-dashboard output.\n- Header/rows must stay within bounded widths in every layout mode; bars use per-mode widths from LayoutSpec (task bar = headerBarWidth; subtask bar shorter, clamped to a readable minimum).\n- Keep the muted frame-tone styling of the counts/`Sub` segment consistent with the current header.\n\nVerification contract:\n- npm run check (tsc --noEmit) clean; npm test (667 cases) and npm run test:integration (28) green.\n- Golden tests pin the new header format (`· Sub 2/3 [bar]`) and the absence of the standalone compact Subtasks line.\n- grep/rg over extensions/tests confirms no `Subtasks \\[` compact standalone line remains (the expanded Current-task line and per-row markers are allowed to match only their own patterns).\n- README.md and docs/unified-dashboard.md compact examples refreshed to the new header; CHANGELOG entry added under [Unreleased].\n\nIf blocked: stop and ask the user.",
|
|
5
|
+
"status": "complete",
|
|
6
|
+
"autoContinue": true,
|
|
7
|
+
"usage": {
|
|
8
|
+
"tokensUsed": 170005,
|
|
9
|
+
"activeSeconds": 595
|
|
10
|
+
},
|
|
11
|
+
"sisyphus": false,
|
|
12
|
+
"skipAuditor": true,
|
|
13
|
+
"revision": 54,
|
|
14
|
+
"createdAt": "2026-08-07T07:21:46.945Z",
|
|
15
|
+
"updatedAt": "2026-08-07T07:32:27.376Z",
|
|
16
|
+
"taskList": {
|
|
17
|
+
"tasks": [
|
|
18
|
+
{
|
|
19
|
+
"id": "spec-docs",
|
|
20
|
+
"title": "Update spec docs (PRODUCT.md, TECH.md, MILESTONES.md) under specs/2026-08-07-compact-task-counts/ for the header layout change",
|
|
21
|
+
"status": "complete",
|
|
22
|
+
"verificationContract": "PRODUCT.md documents the header row carrying the task bar plus the `Sub done/total` subtask segment (current task only, omitted for leaf/no-current-task) and removal of the standalone compact Subtasks line; TECH.md covers the renderer change, per-mode subtask-bar widths, and truncation rules; MILESTONES.md gains the new milestone.",
|
|
23
|
+
"completedAt": "2026-08-07T07:26:30.409Z",
|
|
24
|
+
"evidence": "PRODUCT.md documents the header row with counts + task bar + `Sub done/total` subtask segment (current task only, omitted for leaf/minimal), narrow short form, and removal of both standalone compact l"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"id": "renderer",
|
|
28
|
+
"title": "Compact Tasks header: render task bar + `Sub done/total` + subtask bar beside it (current task with subtasks only), remove the standalone compact Subtasks line, keep expanded unchanged, stay width-safe",
|
|
29
|
+
"status": "complete",
|
|
30
|
+
"verificationContract": "Compact render shows `├─ Tasks · ✓N done · M open ─ [task bar] · Sub done/total [subtask bar] ┤` when the current task has subtasks; no subtask segment when the current task is a leaf or absent; the `Subtasks [bar] …` line is gone from compact; per-row `▸ done/total` markers intact; expanded dashboard's Progress + Current-task blocks byte-identical; header truncates width-safely across wide/medium/narrow/minimal with counts and both bars surviving.",
|
|
31
|
+
"completedAt": "2026-08-07T07:32:11.976Z",
|
|
32
|
+
"evidence": "Compact header is now `├─ Tasks · ✓N done · M open ─ [task bar] · Sub done/total [subtask bar] ┤` (wide/medium labeled, narrow short `· 2/3`, minimal omits segment); no segment for leaf/absent current"
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"id": "tests-docs",
|
|
36
|
+
"title": "Update golden/unit/e2e tests, README + docs examples, CHANGELOG; run full validation",
|
|
37
|
+
"status": "complete",
|
|
38
|
+
"verificationContract": "npm run check clean; npm test (667) and npm run test:integration (28) green; goldens pin the new header segment and absence of the standalone compact Subtasks line; grep confirms no `Subtasks [` compact line remains in extensions/tests; README.md and docs/unified-dashboard.md compact examples and CHANGELOG updated.",
|
|
39
|
+
"completedAt": "2026-08-07T07:32:11.977Z",
|
|
40
|
+
"evidence": "npm run check clean; npm test 667/667; test:integration 28/28; goldens pin `· Sub 2/3 [bar]` and absence of standalone compact Subtasks line; grep: zero `Subtasks [` and zero `Tasks [` in extensions"
|
|
41
|
+
}
|
|
42
|
+
],
|
|
43
|
+
"blockCompletion": false,
|
|
44
|
+
"proposedAt": "2026-08-07T07:21:38.166Z"
|
|
45
|
+
},
|
|
46
|
+
"stopReason": "agent",
|
|
47
|
+
"archivedPath": ".pi/goals/archived/goal_2026080708322737_msim9m81-5aa98r.md"
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
# Goal Prompt
|
|
51
|
+
|
|
52
|
+
Move the compact dashboard's subtask progress bar next to the task progress bar in the Tasks header row: the header becomes a single row with `✓N done · M open` (skipped counted as done), the task progress bar, then a short `Sub done/total` label with the subtask bar beside it (e.g. `├─ Tasks · ✓3 done · 2 open ─ [█████░░░] · Sub 2/3 [██░░] ┤`, shown only when the current task has subtasks); the standalone `Subtasks [bar] done/total · %` line is removed from the compact view; per-row `▸ done/total` markers and the expanded dashboard's Progress/current-task sections stay unchanged; the header remains width-safe in every layout mode.
|
|
53
|
+
|
|
54
|
+
Success criteria:
|
|
55
|
+
- The compact dashboard's Tasks section rule renders as one row: counts first (`✓N done · M open`, skipped counted as done), then a dash run, then the task progress bar, then ` · Sub done/total ` and the subtask progress bar beside it — only when the current task has subtasks; when the current task is a leaf (or there is no current task), the subtask segment is omitted.
|
|
56
|
+
- The standalone compact `Subtasks [bar] done/total · %` line is gone from the compact dashboard; the current task's subtask data now lives only in the header segment and the per-row `▸ done/total` markers.
|
|
57
|
+
- Per-row `▸ done/total` markers on tasks with direct subtasks remain; leaf rows show none.
|
|
58
|
+
- The expanded dashboard is byte-identical to today: its Progress section and the Current-task block's `Subtasks [bar] 2/3 · 67%` line are unchanged.
|
|
59
|
+
- The header truncates width-safely across all layout modes (wide/medium/narrow/minimal): the counts and both bars always survive; only the label/dash run may shrink.
|
|
60
|
+
|
|
61
|
+
Boundaries:
|
|
62
|
+
- In scope: extensions/widgets/goal-dashboard-renderer.ts (compact header rendering, removal of the standalone Subtasks line), spec docs under specs/2026-08-07-compact-task-counts/, golden/unit/e2e tests, README.md, docs/unified-dashboard.md, CHANGELOG.md.
|
|
63
|
+
- Out of scope: the model layer (DashboardTaskNode subtask counts and taskProgress already provide everything needed), the expanded dashboard, per-row marker semantics, current-task block content, and any other widget.
|
|
64
|
+
|
|
65
|
+
Constraints:
|
|
66
|
+
- Follow AGENTS.md: spec docs live in specs/2026-08-07-compact-task-counts/ with MILESTONES.md updated throughout.
|
|
67
|
+
- No new dependencies; no changes to expanded-dashboard output.
|
|
68
|
+
- Header/rows must stay within bounded widths in every layout mode; bars use per-mode widths from LayoutSpec (task bar = headerBarWidth; subtask bar shorter, clamped to a readable minimum).
|
|
69
|
+
- Keep the muted frame-tone styling of the counts/`Sub` segment consistent with the current header.
|
|
70
|
+
|
|
71
|
+
Verification contract:
|
|
72
|
+
- npm run check (tsc --noEmit) clean; npm test (667 cases) and npm run test:integration (28) green.
|
|
73
|
+
- Golden tests pin the new header format (`· Sub 2/3 [bar]`) and the absence of the standalone compact Subtasks line.
|
|
74
|
+
- grep/rg over extensions/tests confirms no `Subtasks \[` compact standalone line remains (the expanded Current-task line and per-row markers are allowed to match only their own patterns).
|
|
75
|
+
- README.md and docs/unified-dashboard.md compact examples refreshed to the new header; CHANGELOG entry added under [Unreleased].
|
|
76
|
+
|
|
77
|
+
If blocked: stop and ask the user.
|
|
78
|
+
|
|
79
|
+
## Progress
|
|
80
|
+
|
|
81
|
+
- Status: complete
|
|
82
|
+
- Auto-continue: on
|
|
83
|
+
- Sisyphus mode: no
|
|
84
|
+
- Time spent: 9m55s
|
|
85
|
+
- Tokens used: 170K (170,005) tokens
|
|
86
|
+
## Tasks
|
|
87
|
+
|
|
88
|
+
<!-- blockCompletion: false -->
|
|
89
|
+
- [x] spec-docs: Update spec docs (PRODUCT.md, TECH.md, MILESTONES.md) under specs/2026-08-07-compact-task-counts/ for the header layout change — evidence: PRODUCT.md documents the header row with counts + task bar + `Sub done/total` subtask segment (current task only, omitted for leaf/minimal), narrow short form, and removal of both standalone compact l
|
|
90
|
+
- [x] renderer: Compact Tasks header: render task bar + `Sub done/total` + subtask bar beside it (current task with subtasks only), remove the standalone compact Subtasks line, keep expanded unchanged, stay width-safe — evidence: Compact header is now `├─ Tasks · ✓N done · M open ─ [task bar] · Sub done/total [subtask bar] ┤` (wide/medium labeled, narrow short `· 2/3`, minimal omits segment); no segment for leaf/absent current
|
|
91
|
+
- [x] tests-docs: Update golden/unit/e2e tests, README + docs examples, CHANGELOG; run full validation — evidence: npm run check clean; npm test 667/667; test:integration 28/28; goldens pin `· Sub 2/3 [bar]` and absence of standalone compact Subtasks line; grep: zero `Subtasks [` and zero `Tasks [` in extensions
|
|
92
|
+
|
|
@@ -78,3 +78,45 @@
|
|
|
78
78
|
{"type":"audit_skipped","goalId":"mshjewld-9z3e9p","reason":"disabled","at":"2026-08-06T13:17:34.172Z"}
|
|
79
79
|
{"type":"goal_completed","goalId":"mshjewld-9z3e9p","archivePath":".pi/goals/archived/goal_2026080614173417_mshjewld-9z3e9p.md","at":"2026-08-06T13:17:34.177Z"}
|
|
80
80
|
{"type":"goal_archived","goalId":"mshjewld-9z3e9p","archivePath":".pi/goals/archived/goal_2026080614173417_mshjewld-9z3e9p.md","at":"2026-08-06T13:17:34.178Z"}
|
|
81
|
+
{"type":"goal_focused","goalId":"mshg3jex-svqfyt","reason":"selected","at":"2026-08-06T13:26:27.232Z"}
|
|
82
|
+
{"type":"goal_focused","goalId":"mshisjml-bl1gar","reason":"selected","at":"2026-08-06T13:26:31.604Z"}
|
|
83
|
+
{"type":"goal_created","goalId":"mshk5uvt-nnkztu","objective":"Move goal status information from the bottom of the pi screen into the goal widget: in both the compact and expanded dashboard status lines, replace the \"Focused: yes / Other goals: N\" bits with `goal: <statusLabel> [<elapsed> <tokens>] (+N open)` using the footer-status formatting (statusLabel + usage bracket, no objective preview — the header title already shows it, and the header's right-side usage folds away to avoid duplication), and stop rendering the focused-goal footer line (setStatus(\"goal\", undefined) when a goal is focused) while keeping the unfocused hint — with updated tests/goldens, spec docs, CHANGELOG entry, and a green validation, on a new branch off main.","sisyphus":false,"autoContinue":true,"at":"2026-08-06T13:35:06.137Z"}
|
|
84
|
+
{"type":"task_list_set","goalId":"mshk5uvt-nnkztu","taskCount":5,"blockCompletion":true,"at":"2026-08-06T13:35:06.137Z"}
|
|
85
|
+
{"type":"task_started","goalId":"mshk5uvt-nnkztu","taskId":"task-1","at":"2026-08-06T13:35:13.881Z"}
|
|
86
|
+
{"type":"task_complete","goalId":"mshk5uvt-nnkztu","taskId":"task-1","evidence":"Branch feat/goal-widget-status created off main (15aa826); specs/2026-08-06-goal-widget-status/ scaffolded with PRODUCT.md, TECH.md, MILESTONES.md (user decisions recorded).","at":"2026-08-06T13:35:37.865Z"}
|
|
87
|
+
{"type":"task_started","goalId":"mshk5uvt-nnkztu","taskId":"task-2","at":"2026-08-06T13:35:37.866Z"}
|
|
88
|
+
{"type":"task_complete","goalId":"mshk5uvt-nnkztu","taskId":"task-2","evidence":"Renderer (compact + expanded) + model updated: status lines now render `goal: <footerLabel> [<footerBits>] (+N open)` via shared statusLine() helper; Focused:/Other goals: bits, STATUS_SYMBOL, and dea","at":"2026-08-06T13:40:01.162Z"}
|
|
89
|
+
{"type":"task_started","goalId":"mshk5uvt-nnkztu","taskId":"task-3","at":"2026-08-06T13:40:01.162Z"}
|
|
90
|
+
{"type":"task_complete","goalId":"mshk5uvt-nnkztu","taskId":"task-3","evidence":"goal-state.ts renderUI: focused-goal branch now calls setStatus('goal', undefined) (clears stale unfocused hint); unfocused hint branch untouched; unused footerStatus import removed; tsc clean.","at":"2026-08-06T13:40:31.928Z"}
|
|
91
|
+
{"type":"task_started","goalId":"mshk5uvt-nnkztu","taskId":"task-4","at":"2026-08-06T13:40:31.928Z"}
|
|
92
|
+
{"type":"task_complete","goalId":"mshk5uvt-nnkztu","taskId":"task-4","evidence":"Updated pinned assertions in goal-widget.test.ts (7), goal-dashboard-golden.test.ts (6 incl. new expanded status-line pin), goal-status.test.ts (1), goal-dashboard-model.test.ts (2: footerBits usage +","at":"2026-08-06T13:43:06.406Z"}
|
|
93
|
+
{"type":"task_started","goalId":"mshk5uvt-nnkztu","taskId":"task-5","at":"2026-08-06T13:43:06.407Z"}
|
|
94
|
+
{"type":"task_complete","goalId":"mshk5uvt-nnkztu","taskId":"task-5","evidence":"CHANGELOG [Unreleased] entry added; PRODUCT/TECH/MILESTONES updated; npm run check clean; npm test 665/665 pass; grep confirms no functional Focused:/Other goals: remnants and no footerStatus(displayG","at":"2026-08-06T13:44:11.522Z"}
|
|
95
|
+
{"type":"completion_requested","goalId":"mshk5uvt-nnkztu","at":"2026-08-06T13:44:18.145Z"}
|
|
96
|
+
{"type":"audit_skipped","goalId":"mshk5uvt-nnkztu","reason":"disabled","at":"2026-08-06T13:44:18.145Z"}
|
|
97
|
+
{"type":"goal_completed","goalId":"mshk5uvt-nnkztu","archivePath":".pi/goals/archived/goal_2026080614441814_mshk5uvt-nnkztu.md","at":"2026-08-06T13:44:18.148Z"}
|
|
98
|
+
{"type":"goal_archived","goalId":"mshk5uvt-nnkztu","archivePath":".pi/goals/archived/goal_2026080614441814_mshk5uvt-nnkztu.md","at":"2026-08-06T13:44:18.148Z"}
|
|
99
|
+
{"type":"goal_created","goalId":"msilpn44-qqa4fa","objective":"Add task counts and a progress bar to the compact goal dashboard's \"Tasks\" header row, and make subtask progress visible per task row: the header becomes a single row with `✓N done · M open` (skipped counted as done) followed by a compact progress bar at the end of the row, the redundant standalone compact `Tasks [bar] X/Y · %` line is removed (expanded dashboard keeps its Progress section unchanged), task rows with subtasks show a `▸ done/total` marker, and the current-task subtask bar is kept.","sisyphus":false,"autoContinue":true,"at":"2026-08-07T07:06:14.980Z"}
|
|
100
|
+
{"type":"task_list_set","goalId":"msilpn44-qqa4fa","taskCount":4,"blockCompletion":false,"at":"2026-08-07T07:06:14.980Z"}
|
|
101
|
+
{"type":"task_started","goalId":"msilpn44-qqa4fa","taskId":"spec-docs","at":"2026-08-07T07:06:20.796Z"}
|
|
102
|
+
{"type":"task_complete","goalId":"msilpn44-qqa4fa","taskId":"spec-docs","evidence":"specs/2026-08-07-compact-task-counts/ created with PRODUCT.md (header row counts+bar-at-end, standalone-line removal, subtask markers), TECH.md (model/renderer/test changes), MILESTONES.md.","at":"2026-08-07T07:08:11.771Z"}
|
|
103
|
+
{"type":"task_started","goalId":"msilpn44-qqa4fa","taskId":"model","at":"2026-08-07T07:08:11.773Z"}
|
|
104
|
+
{"type":"task_complete","goalId":"msilpn44-qqa4fa","taskId":"model","evidence":"DashboardTaskNode gains required totalSubtasks/completedSubtasks populated by flattenTaskTree (direct children, skipped=done); model tests pin parent 2/3, leaves 0, skipped-as-done; npm run check clea","at":"2026-08-07T07:09:05.403Z"}
|
|
105
|
+
{"type":"task_started","goalId":"msilpn44-qqa4fa","taskId":"renderer","at":"2026-08-07T07:09:05.405Z"}
|
|
106
|
+
{"type":"task_complete","goalId":"msilpn44-qqa4fa","taskId":"renderer","evidence":"Compact header is `├─ Tasks · ✓3 done · 2 open ──... [█████░░░] ┤` (counts then bar at end, skipped=done); standalone compact progress line removed; `▸ done/total` markers on rows with subtasks (leaf ","at":"2026-08-07T07:13:51.346Z"}
|
|
107
|
+
{"type":"task_complete","goalId":"msilpn44-qqa4fa","taskId":"tests-docs","evidence":"npm run check clean; npm test 667/667 green; test:integration 28/28 green; goldens pinned to new header/marker formats; grep: no `Tasks [` in extensions/tests; README + docs/unified-dashboard.md exam","at":"2026-08-07T07:13:51.347Z"}
|
|
108
|
+
{"type":"completion_requested","goalId":"msilpn44-qqa4fa","at":"2026-08-07T07:14:04.248Z"}
|
|
109
|
+
{"type":"audit_skipped","goalId":"msilpn44-qqa4fa","reason":"disabled","at":"2026-08-07T07:14:04.249Z"}
|
|
110
|
+
{"type":"goal_completed","goalId":"msilpn44-qqa4fa","archivePath":".pi/goals/archived/goal_2026080708140425_msilpn44-qqa4fa.md","at":"2026-08-07T07:14:04.255Z"}
|
|
111
|
+
{"type":"goal_archived","goalId":"msilpn44-qqa4fa","archivePath":".pi/goals/archived/goal_2026080708140425_msilpn44-qqa4fa.md","at":"2026-08-07T07:14:04.255Z"}
|
|
112
|
+
{"type":"goal_created","goalId":"msim9m81-5aa98r","objective":"Move the compact dashboard's subtask progress bar next to the task progress bar in the Tasks header row: the header becomes a single row with `✓N done · M open` (skipped counted as done), the task progress bar, then a short `Sub done/total` label with the subtask bar beside it (e.g. `├─ Tasks · ✓3 done · 2 open ─ [█████░░░] · Sub 2/3 [██░░] ┤`, shown only when the current task has subtasks); the standalone `Subtasks [bar] done/total · %` line is removed from the compact view; per-row `▸ done/total` markers and the expanded dashboard's Progress/current-task sections stay unchanged; the header remains width-safe in every layout mode.\n\nSuccess criteria:\n- The compact dashboard's Tasks section rule renders as one row: counts first (`✓N done · M open`, skipped counted as done), then a dash run, then the task progress bar, then ` · Sub done/total ` and the subtask progress bar beside it — only when the current task has subtasks; when the current task is a leaf (or there is no current task), the subtask segment is omitted.\n- The standalone compact `Subtasks [bar] done/total · %` line is gone from the compact dashboard; the current task's subtask data now lives only in the header segment and the per-row `▸ done/total` markers.\n- Per-row `▸ done/total` markers on tasks with direct subtasks remain; leaf rows show none.\n- The expanded dashboard is byte-identical to today: its Progress section and the Current-task block's `Subtasks [bar] 2/3 · 67%` line are unchanged.\n- The header truncates width-safely across all layout modes (wide/medium/narrow/minimal): the counts and both bars always survive; only the label/dash run may shrink.\n\nBoundaries:\n- In scope: extensions/widgets/goal-dashboard-renderer.ts (compact header rendering, removal of the standalone Subtasks line), spec docs under specs/2026-08-07-compact-task-counts/, golden/unit/e2e tests, README.md, docs/unified-dashboard.md, CHANGELOG.md.\n- Out of scope: the model layer (DashboardTaskNode subtask counts and taskProgress already provide everything needed), the expanded dashboard, per-row marker semantics, current-task block content, and any other widget.\n\nConstraints:\n- Follow AGENTS.md: spec docs live in specs/2026-08-07-compact-task-counts/ with MILESTONES.md updated throughout.\n- No new dependencies; no changes to expanded-dashboard output.\n- Header/rows must stay within bounded widths in every layout mode; bars use per-mode widths from LayoutSpec (task bar = headerBarWidth; subtask bar shorter, clamped to a readable minimum).\n- Keep the muted frame-tone styling of the counts/`Sub` segment consistent with the current header.\n\nVerification contract:\n- npm run check (tsc --noEmit) clean; npm test (667 cases) and npm run test:integration (28) green.\n- Golden tests pin the new header format (`· Sub 2/3 [bar]`) and the absence of the standalone compact Subtasks line.\n- grep/rg over extensions/tests confirms no `Subtasks \\[` compact standalone line remains (the expanded Current-task line and per-row markers are allowed to match only their own patterns).\n- README.md and docs/unified-dashboard.md compact examples refreshed to the new header; CHANGELOG entry added under [Unreleased].\n\nIf blocked: stop and ask the user.","sisyphus":false,"autoContinue":true,"at":"2026-08-07T07:21:46.945Z"}
|
|
113
|
+
{"type":"task_list_set","goalId":"msim9m81-5aa98r","taskCount":3,"blockCompletion":false,"at":"2026-08-07T07:21:46.945Z"}
|
|
114
|
+
{"type":"task_started","goalId":"msim9m81-5aa98r","taskId":"spec-docs","at":"2026-08-07T07:21:53.250Z"}
|
|
115
|
+
{"type":"task_complete","goalId":"msim9m81-5aa98r","taskId":"spec-docs","evidence":"PRODUCT.md documents the header row with counts + task bar + `Sub done/total` subtask segment (current task only, omitted for leaf/minimal), narrow short form, and removal of both standalone compact l","at":"2026-08-07T07:26:30.410Z"}
|
|
116
|
+
{"type":"task_started","goalId":"msim9m81-5aa98r","taskId":"renderer","at":"2026-08-07T07:26:30.410Z"}
|
|
117
|
+
{"type":"task_complete","goalId":"msim9m81-5aa98r","taskId":"renderer","evidence":"Compact header is now `├─ Tasks · ✓N done · M open ─ [task bar] · Sub done/total [subtask bar] ┤` (wide/medium labeled, narrow short `· 2/3`, minimal omits segment); no segment for leaf/absent current","at":"2026-08-07T07:32:11.976Z"}
|
|
118
|
+
{"type":"task_complete","goalId":"msim9m81-5aa98r","taskId":"tests-docs","evidence":"npm run check clean; npm test 667/667; test:integration 28/28; goldens pin `· Sub 2/3 [bar]` and absence of standalone compact Subtasks line; grep: zero `Subtasks [` and zero `Tasks [` in extensions","at":"2026-08-07T07:32:11.977Z"}
|
|
119
|
+
{"type":"completion_requested","goalId":"msim9m81-5aa98r","at":"2026-08-07T07:32:27.371Z"}
|
|
120
|
+
{"type":"audit_skipped","goalId":"msim9m81-5aa98r","reason":"disabled","at":"2026-08-07T07:32:27.371Z"}
|
|
121
|
+
{"type":"goal_completed","goalId":"msim9m81-5aa98r","archivePath":".pi/goals/archived/goal_2026080708322737_msim9m81-5aa98r.md","at":"2026-08-07T07:32:27.377Z"}
|
|
122
|
+
{"type":"goal_archived","goalId":"msim9m81-5aa98r","archivePath":".pi/goals/archived/goal_2026080708322737_msim9m81-5aa98r.md","at":"2026-08-07T07:32:27.378Z"}
|
|
@@ -21,49 +21,54 @@ activity are never fabricated for display.
|
|
|
21
21
|
Always visible above the editor while a goal is focused:
|
|
22
22
|
|
|
23
23
|
```text
|
|
24
|
-
╭─ pi-goal-x ─ Add CSV export to reports
|
|
25
|
-
│
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
│ ✓
|
|
29
|
-
│
|
|
30
|
-
│
|
|
31
|
-
│
|
|
32
|
-
│
|
|
33
|
-
│
|
|
34
|
-
│
|
|
35
|
-
|
|
36
|
-
│ File .pi/goals/active_goal_g1.md │
|
|
37
|
-
╰─ Ctrl+Shift+T: expand tasks─────────────────────────────────────────────╯
|
|
24
|
+
╭─ pi-goal-x ─ Add CSV export to reports ────────────────────────────────────────────────╮
|
|
25
|
+
│ goal: running [12m47s 18.2K] (+2 open) │
|
|
26
|
+
├─ Tasks · ✓3 done · 2 open ─────────────────────────────────── [████░░] · Sub 2/3 [██░] ┤
|
|
27
|
+
│ ✓ t1 Review reports page and data source │
|
|
28
|
+
│ ✓ t2 Implement filtered CSV export │
|
|
29
|
+
│ ▸ t3 Add the download button ☑ ▸ 2/3 │
|
|
30
|
+
│ · t4 Add documentation │
|
|
31
|
+
│ … +1 more task │
|
|
32
|
+
│ Current t3 · Add the download button │
|
|
33
|
+
│ Verify Run npm test with zero failures. │
|
|
34
|
+
│ File .pi/goals/active_goal_g1.md │
|
|
35
|
+
╰─ Ctrl+Shift+T: expand tasks ───────────────────────────────────────────────────────────╯
|
|
38
36
|
```
|
|
39
37
|
|
|
40
38
|
Compact rows, in order:
|
|
41
39
|
|
|
42
|
-
1. Header (rounded corners): title
|
|
43
|
-
|
|
44
|
-
|
|
40
|
+
1. Header (rounded corners): title. (Usage lives in the status line below,
|
|
41
|
+
not in the header.)
|
|
42
|
+
2. Status: `goal: <status> [<elapsed> <tokens>] (+N open)` — the same
|
|
43
|
+
terminology as the pi footer status line.
|
|
45
44
|
3. Token budget (when configured): `⛽ Budget 18.2K / 50K · 36%`.
|
|
46
|
-
4.
|
|
47
|
-
|
|
48
|
-
|
|
45
|
+
4. Tasks header row: `Tasks · ✓N done · M open` with the compact task
|
|
46
|
+
progress bar, then the current task's subtask bar beside it
|
|
47
|
+
(` · Sub done/total ` + bar — the word `Sub` is dropped in narrow mode so
|
|
48
|
+
the full counts still fit at 50 columns, and the segment is omitted
|
|
49
|
+
entirely in minimal mode, where the counts and task bar alone use all
|
|
50
|
+
available space). `N` counts top-level tasks complete **or skipped** — a
|
|
51
|
+
skipped top-level task counts as done (§9.1) — and `M` counts pending
|
|
52
|
+
tasks. The subtask segment appears only when the current task has direct
|
|
53
|
+
children. The whole header row is neutral gray (label, counts, bar fill,
|
|
54
|
+
and empty cells) so nothing in the progress info is colourful.
|
|
49
55
|
5. Task list section: the top-level tasks shown by default in **pastel
|
|
50
56
|
amber** (`mdHeading`) with colour-coded markers and ids (✓ complete muted
|
|
51
57
|
green, ▸ current teal, ~ skipped gray, · pending amber), an aligned id
|
|
52
58
|
column, truncated amber titles, and a `… +N more` overflow line when the
|
|
53
59
|
list is longer than the row budget (5 rows at wide, 4 medium, 3 narrow, 2
|
|
54
|
-
minimal).
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
60
|
+
minimal). Tasks that have direct subtasks show a muted `▸ done/total`
|
|
61
|
+
marker at the end of their row (leaf tasks show none). The current task
|
|
62
|
+
is fully highlighted in the theme's accent color (marker, id, title). The
|
|
63
|
+
whole box chrome — top/bottom frame, left/right edges, corners and
|
|
64
|
+
interior rules — is drawn in one tone: the theme's neutral gray
|
|
65
|
+
(`muted`). No blue tinge.
|
|
58
66
|
6. Current task: `Current t3 · Add the download button` (id and title in the
|
|
59
67
|
accent color).
|
|
60
|
-
7.
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
9. Blocked or paused detail (reason, suggested action).
|
|
65
|
-
10. Active (or archived) goal file path.
|
|
66
|
-
11. Footer with the expansion shortcut. The whole footer line — leading dash,
|
|
68
|
+
7. Goal-level verification contract (first line, truncated).
|
|
69
|
+
8. Blocked or paused detail (reason, suggested action).
|
|
70
|
+
9. Active (or archived) goal file path.
|
|
71
|
+
10. Footer with the expansion shortcut. The whole footer line — leading dash,
|
|
67
72
|
shortcut hint and trailing fill — is drawn in one frame tone (the
|
|
68
73
|
neutral-gray `muted`), so the color spans the full width with no two-tone
|
|
69
74
|
split; the header line is likewise one tone with only the `pi-goal-x`
|
package/extensions/goal-state.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { type AgentToolResult, type ExtensionAPI, type ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
2
|
-
import { footerStatus } from "./goal-core.ts";
|
|
3
2
|
import { FOCUS_ENTRY, STATE_ENTRY, GOAL_EVENT_ENTRY, goalDetails } from "./goal-format.ts";
|
|
4
3
|
import { loadGoalSettings, loadGoalSettingsFileConfig } from "./goal-settings.ts";
|
|
5
4
|
import {
|
|
@@ -669,9 +668,12 @@ export function createGoalCore(
|
|
|
669
668
|
return;
|
|
670
669
|
}
|
|
671
670
|
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
671
|
+
// The goal widget is the single home for goal status: the status line
|
|
672
|
+
// lives in the compact/expanded dashboard (goal: <label> [<usage>]
|
|
673
|
+
// (+N open)), so the focused-goal footer segment is cleared — a stale
|
|
674
|
+
// unfocused hint or earlier status must not linger once a goal is
|
|
675
|
+
// focused. The unfocused branch above still sets its own hint.
|
|
676
|
+
ctx.ui.setStatus("goal", undefined);
|
|
675
677
|
|
|
676
678
|
if (!widgetRegistered) {
|
|
677
679
|
ctx.ui.setWidget(
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* the durable ledger.
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import { displayObjectiveTitle, formatDuration } from "../goal-core.ts";
|
|
12
|
+
import { displayObjectiveTitle, formatDuration, statusLabel } from "../goal-core.ts";
|
|
13
13
|
import type { GoalLedgerEvent } from "../goal-ledger.ts";
|
|
14
14
|
import type { GoalRecord, GoalTask } from "../goal-record.ts";
|
|
15
15
|
import { deriveGoalActivity, type GoalActivityItem } from "../goal-activity.ts";
|
|
@@ -27,6 +27,8 @@ export interface GoalDashboardModel {
|
|
|
27
27
|
status: {
|
|
28
28
|
code: DashboardStatusCode;
|
|
29
29
|
label: string;
|
|
30
|
+
/** Footer-status label (goal-core statusLabel), e.g. `running`, `paused (agent)`. */
|
|
31
|
+
footerLabel: string;
|
|
30
32
|
reason?: string;
|
|
31
33
|
suggestedAction?: string;
|
|
32
34
|
};
|
|
@@ -36,9 +38,9 @@ export interface GoalDashboardModel {
|
|
|
36
38
|
|
|
37
39
|
usage: {
|
|
38
40
|
activeSeconds: number;
|
|
39
|
-
elapsedLabel: string;
|
|
40
41
|
tokens: number;
|
|
41
|
-
|
|
42
|
+
/** Footer-style usage content, e.g. `49h49m36s 19M` (empty when unused). */
|
|
43
|
+
footerBits: string;
|
|
42
44
|
};
|
|
43
45
|
|
|
44
46
|
budget?: {
|
|
@@ -88,6 +90,10 @@ export interface DashboardTaskNode {
|
|
|
88
90
|
evidence?: string;
|
|
89
91
|
/** Completion timestamp (when status is complete) — the scroll anchor (§9.6). */
|
|
90
92
|
completedAt?: string;
|
|
93
|
+
/** Direct-child subtask total — 0 for a leaf task (§9.3 rule: direct children only). */
|
|
94
|
+
totalSubtasks: number;
|
|
95
|
+
/** Direct children complete or skipped (same "done" rule as §9.1). */
|
|
96
|
+
completedSubtasks: number;
|
|
91
97
|
}
|
|
92
98
|
|
|
93
99
|
export interface GoalDashboardModelOptions {
|
|
@@ -106,6 +112,10 @@ export interface GoalDashboardModelOptions {
|
|
|
106
112
|
export interface DashboardGoalStatus {
|
|
107
113
|
code: DashboardStatusCode;
|
|
108
114
|
label: string;
|
|
115
|
+
/** Footer-status label (goal-core statusLabel: running / paused (agent) /
|
|
116
|
+
* blocked / budget limited / active / complete, with sisyphus prefix) — the
|
|
117
|
+
* widget status line shows the same terminology as the pi footer. */
|
|
118
|
+
footerLabel: string;
|
|
109
119
|
reason?: string;
|
|
110
120
|
suggestedAction?: string;
|
|
111
121
|
}
|
|
@@ -118,25 +128,25 @@ export function deriveGoalStatus(goal: GoalRecord): DashboardGoalStatus {
|
|
|
118
128
|
switch (goal.status) {
|
|
119
129
|
case "active":
|
|
120
130
|
return goal.autoContinue
|
|
121
|
-
? { code: "running", label: "In progress" }
|
|
122
|
-
: { code: "idle", label: "Idle" };
|
|
131
|
+
? { code: "running", label: "In progress", footerLabel: statusLabel(goal) }
|
|
132
|
+
: { code: "idle", label: "Idle", footerLabel: statusLabel(goal) };
|
|
123
133
|
case "paused": {
|
|
124
134
|
const who = goal.stopReason === "agent" ? " (agent)" : goal.stopReason === "user" ? " (user)" : "";
|
|
125
|
-
const status: DashboardGoalStatus = { code: "paused", label: `Paused${who}
|
|
135
|
+
const status: DashboardGoalStatus = { code: "paused", label: `Paused${who}`, footerLabel: statusLabel(goal) };
|
|
126
136
|
if (goal.pauseReason) status.reason = goal.pauseReason;
|
|
127
137
|
if (goal.pauseSuggestedAction) status.suggestedAction = goal.pauseSuggestedAction;
|
|
128
138
|
return status;
|
|
129
139
|
}
|
|
130
140
|
case "blocked": {
|
|
131
|
-
const status: DashboardGoalStatus = { code: "blocked", label: "Blocked" };
|
|
141
|
+
const status: DashboardGoalStatus = { code: "blocked", label: "Blocked", footerLabel: statusLabel(goal) };
|
|
132
142
|
if (goal.pauseReason) status.reason = goal.pauseReason;
|
|
133
143
|
if (goal.pauseSuggestedAction) status.suggestedAction = goal.pauseSuggestedAction;
|
|
134
144
|
return status;
|
|
135
145
|
}
|
|
136
146
|
case "budget_limited":
|
|
137
|
-
return { code: "budget_limited", label: "Budget limited" };
|
|
147
|
+
return { code: "budget_limited", label: "Budget limited", footerLabel: statusLabel(goal) };
|
|
138
148
|
case "complete":
|
|
139
|
-
return { code: "complete", label: "Complete" };
|
|
149
|
+
return { code: "complete", label: "Complete", footerLabel: statusLabel(goal) };
|
|
140
150
|
}
|
|
141
151
|
}
|
|
142
152
|
|
|
@@ -181,6 +191,8 @@ export function flattenTaskTree(tasks: readonly GoalTask[] | undefined, currentT
|
|
|
181
191
|
if (!tasks) return nodes;
|
|
182
192
|
const walk = (list: readonly GoalTask[], depth: number): void => {
|
|
183
193
|
for (const t of list) {
|
|
194
|
+
const children = t.subtasks ?? [];
|
|
195
|
+
const completed = children.filter((c) => c.status === "complete" || c.status === "skipped").length;
|
|
184
196
|
nodes.push({
|
|
185
197
|
id: t.id,
|
|
186
198
|
title: t.title,
|
|
@@ -190,8 +202,10 @@ export function flattenTaskTree(tasks: readonly GoalTask[] | undefined, currentT
|
|
|
190
202
|
verificationContract: t.verificationContract,
|
|
191
203
|
evidence: t.evidence,
|
|
192
204
|
completedAt: t.completedAt,
|
|
205
|
+
totalSubtasks: children.length,
|
|
206
|
+
completedSubtasks: completed,
|
|
193
207
|
});
|
|
194
|
-
if (
|
|
208
|
+
if (children.length > 0) walk(children, depth + 1);
|
|
195
209
|
}
|
|
196
210
|
};
|
|
197
211
|
walk(tasks, 0);
|
|
@@ -472,6 +486,13 @@ export function deriveGoalDashboardModel(
|
|
|
472
486
|
const taskTitles = new Map(taskTree.map((n) => [n.id, n.title]));
|
|
473
487
|
const recentActivity = deriveGoalActivity(ledgerEvents, goal.id, { taskTitles, limit: activityLimit });
|
|
474
488
|
|
|
489
|
+
// Footer-status usage bits (goal-core footerStatus parity): compact
|
|
490
|
+
// duration + compact token count, e.g. `49h49m36s 19M`. The status line
|
|
491
|
+
// renders them inside brackets; empty when the goal has no usage yet.
|
|
492
|
+
const footerUsageBits: string[] = [];
|
|
493
|
+
if (goal.usage.activeSeconds > 0) footerUsageBits.push(formatDuration(goal.usage.activeSeconds));
|
|
494
|
+
if (goal.usage.tokensUsed > 0) footerUsageBits.push(formatCompactTokens(goal.usage.tokensUsed));
|
|
495
|
+
|
|
475
496
|
return {
|
|
476
497
|
goalId: goal.id,
|
|
477
498
|
title: displayObjectiveTitle(goal.objective),
|
|
@@ -480,9 +501,8 @@ export function deriveGoalDashboardModel(
|
|
|
480
501
|
filePath: goal.activePath ?? goal.archivedPath,
|
|
481
502
|
usage: {
|
|
482
503
|
activeSeconds: goal.usage.activeSeconds,
|
|
483
|
-
elapsedLabel: formatDashboardDuration(goal.usage.activeSeconds),
|
|
484
504
|
tokens: goal.usage.tokensUsed,
|
|
485
|
-
|
|
505
|
+
footerBits: footerUsageBits.join(" "),
|
|
486
506
|
},
|
|
487
507
|
budget,
|
|
488
508
|
taskProgress,
|
|
@@ -77,12 +77,23 @@ function boxRule(theme: Theme, width: number): string {
|
|
|
77
77
|
return frame(theme, `├${H.repeat(Math.max(1, width - 2))}┤`);
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
/** Section separator with a label
|
|
81
|
-
|
|
80
|
+
/** Section separator with a label and optional right-side content:
|
|
81
|
+
* `├─ Tasks ──── [████░] · Sub 2/3 [██░░] ┤` (§5.1). The right content
|
|
82
|
+
* (e.g. the header progress bars) always survives; the label truncates when
|
|
83
|
+
* tight. Hardened so label + right never exceed the inner width: the fill is
|
|
84
|
+
* `max(0, …)` and the truncation budget leaves room for the `─ ` prefix and
|
|
85
|
+
* trailing space. */
|
|
86
|
+
function boxSectionRule(theme: Theme, width: number, label: string, right = ""): string {
|
|
82
87
|
const inner = Math.max(4, width - 2);
|
|
83
88
|
const left = frame(theme, `${H} ${label} `);
|
|
84
|
-
const
|
|
85
|
-
|
|
89
|
+
const r = right ? ` ${right} ` : "";
|
|
90
|
+
let l = left;
|
|
91
|
+
if (visibleWidth(left) + visibleWidth(r) > inner) {
|
|
92
|
+
const budget = Math.max(4, inner - visibleWidth(r) - 3);
|
|
93
|
+
l = frame(theme, `${H} ${fit(label, budget)} `);
|
|
94
|
+
}
|
|
95
|
+
const fill = Math.max(0, inner - visibleWidth(l) - visibleWidth(r));
|
|
96
|
+
return `${frame(theme, "├")}${l}${frame(theme, H.repeat(fill))}${r}${frame(theme, "┤")}`;
|
|
86
97
|
}
|
|
87
98
|
|
|
88
99
|
function boxFooter(theme: Theme, width: number, content: string): string {
|
|
@@ -97,16 +108,7 @@ function boxFooter(theme: Theme, width: number, content: string): string {
|
|
|
97
108
|
return `${frame(theme, "╰")}${l}${frame(theme, H.repeat(fill))}${frame(theme, "╯")}`;
|
|
98
109
|
}
|
|
99
110
|
|
|
100
|
-
// ── §5.2 status
|
|
101
|
-
|
|
102
|
-
const STATUS_SYMBOL: Record<DashboardStatusCode, string> = {
|
|
103
|
-
running: "●",
|
|
104
|
-
idle: "○",
|
|
105
|
-
paused: "◐",
|
|
106
|
-
blocked: "⊘",
|
|
107
|
-
budget_limited: "⛽",
|
|
108
|
-
complete: "✓",
|
|
109
|
-
};
|
|
111
|
+
// ── §5.2 status colors ──────────────────────────────────────────────────────
|
|
110
112
|
|
|
111
113
|
const STATUS_COLOR: Record<DashboardStatusCode, RenderColor> = {
|
|
112
114
|
running: "accent",
|
|
@@ -117,6 +119,20 @@ const STATUS_COLOR: Record<DashboardStatusCode, RenderColor> = {
|
|
|
117
119
|
complete: "success",
|
|
118
120
|
};
|
|
119
121
|
|
|
122
|
+
/**
|
|
123
|
+
* Widget status line — footer-status parity: `goal: <label> [<usage>] (+N open)`.
|
|
124
|
+
* Same terminology/format as the pi footer status line (goal-core statusLabel +
|
|
125
|
+
* usage bracket), without the objective preview (the header title shows it) and
|
|
126
|
+
* without the old `Focused: yes` / `Other goals: N` bits. The open-goals count
|
|
127
|
+
* appears only when other open goals exist.
|
|
128
|
+
*/
|
|
129
|
+
function statusLine(theme: Theme, model: GoalDashboardModel): string {
|
|
130
|
+
const color = STATUS_COLOR[model.status.code];
|
|
131
|
+
const usage = model.usage.footerBits ? ` [${model.usage.footerBits}]` : "";
|
|
132
|
+
const open = model.otherOpenGoals > 0 ? ` (+${model.otherOpenGoals} open)` : "";
|
|
133
|
+
return `${theme.fg(color, `goal: ${model.status.footerLabel}`)}${muted(theme, `${usage}${open}`)}`;
|
|
134
|
+
}
|
|
135
|
+
|
|
120
136
|
// ── §5.3 progress bars ──────────────────────────────────────────────────────
|
|
121
137
|
|
|
122
138
|
function progressBar(theme: Theme, pct: number, barWidth: number): string {
|
|
@@ -140,24 +156,26 @@ function layoutMode(width: number): LayoutMode {
|
|
|
140
156
|
|
|
141
157
|
interface LayoutSpec {
|
|
142
158
|
barWidth: number;
|
|
143
|
-
|
|
144
|
-
|
|
159
|
+
/** Compact progress bar width inside the Tasks header row (bar at the end). */
|
|
160
|
+
headerBarWidth: number;
|
|
161
|
+
/** Subtask progress bar width inside the Tasks header row, beside the task
|
|
162
|
+
* bar (wide/medium/narrow; minimal omits the segment — unused there). */
|
|
163
|
+
subtaskBarWidth: number;
|
|
145
164
|
showPath: boolean;
|
|
146
165
|
showPauseAction: boolean;
|
|
147
166
|
footerHint: string;
|
|
148
|
-
statusLine: "full" | "brief";
|
|
149
167
|
}
|
|
150
168
|
|
|
151
169
|
function specFor(mode: LayoutMode): LayoutSpec {
|
|
152
170
|
switch (mode) {
|
|
153
171
|
case "wide":
|
|
154
|
-
return { barWidth: 26,
|
|
172
|
+
return { barWidth: 26, headerBarWidth: 8, subtaskBarWidth: 4, showPath: true, showPauseAction: true, footerHint: "Ctrl+Shift+T: expand tasks" };
|
|
155
173
|
case "medium":
|
|
156
|
-
return { barWidth: 18,
|
|
174
|
+
return { barWidth: 18, headerBarWidth: 6, subtaskBarWidth: 3, showPath: true, showPauseAction: true, footerHint: "Ctrl+Shift+T: expand tasks" };
|
|
157
175
|
case "narrow":
|
|
158
|
-
return { barWidth: 12,
|
|
176
|
+
return { barWidth: 12, headerBarWidth: 5, subtaskBarWidth: 2, showPath: false, showPauseAction: false, footerHint: "Ctrl+Shift+T: expand" };
|
|
159
177
|
case "minimal":
|
|
160
|
-
return { barWidth: 8,
|
|
178
|
+
return { barWidth: 8, headerBarWidth: 4, subtaskBarWidth: 2, showPath: false, showPauseAction: false, footerHint: "Ctrl+Shift+T: expand" };
|
|
161
179
|
}
|
|
162
180
|
}
|
|
163
181
|
|
|
@@ -230,15 +248,19 @@ function renderCompactTaskRows(theme: Theme, nodes: DashboardTaskNode[], viewpor
|
|
|
230
248
|
for (const node of shown) {
|
|
231
249
|
const marker = taskMarker(node);
|
|
232
250
|
const contractMark = node.verificationContract ? dim(theme, " ☑") : "";
|
|
251
|
+
// §9.3 compact subtask marker: direct-child done/total for tasks that
|
|
252
|
+
// have subtasks, muted so it stays annotation — the current-task bar
|
|
253
|
+
// below carries the visual weight.
|
|
254
|
+
const subtaskMark = node.totalSubtasks > 0 ? muted(theme, ` ▸ ${node.completedSubtasks}/${node.totalSubtasks}`) : "";
|
|
233
255
|
const id = node.id.padEnd(idWidth);
|
|
234
256
|
const prefix = `${marker.symbol} ${id} `;
|
|
235
|
-
const titleBudget = Math.max(4, available - visibleWidth(prefix) - visibleWidth(contractMark));
|
|
257
|
+
const titleBudget = Math.max(4, available - visibleWidth(prefix) - visibleWidth(contractMark) - visibleWidth(subtaskMark));
|
|
236
258
|
const title = fit(node.title, titleBudget);
|
|
237
259
|
const markerText = theme.fg(marker.color, marker.symbol);
|
|
238
260
|
// Colour-coded: id shares the marker color; titles amber; current accent.
|
|
239
261
|
const idText = node.isCurrent ? accent(theme, id) : theme.fg(marker.color, id);
|
|
240
262
|
const body = node.isCurrent ? accent(theme, title) : amber(theme, title);
|
|
241
|
-
rows.push(`${markerText} ${idText} ${body}${contractMark}`);
|
|
263
|
+
rows.push(`${markerText} ${idText} ${body}${contractMark}${subtaskMark}`);
|
|
242
264
|
}
|
|
243
265
|
if (viewport.hiddenBelow > 0) {
|
|
244
266
|
rows.push(muted(theme, `… +${viewport.hiddenBelow} more task${viewport.hiddenBelow === 1 ? "" : "s"}`));
|
|
@@ -273,21 +295,13 @@ export function renderCompactDashboard(
|
|
|
273
295
|
const inner = safeWidth - 2;
|
|
274
296
|
const lines: string[] = [];
|
|
275
297
|
|
|
276
|
-
|
|
277
|
-
? `${model.usage.elapsedLabel} · ${model.usage.tokenLabel}`
|
|
278
|
-
: "";
|
|
279
|
-
lines.push(boxHeader(theme, safeWidth, `${accent(theme, "pi-goal-x")} ${frame(theme, `─ ${model.title}`)}`, usageRight ? frame(theme, usageRight) : ""));
|
|
298
|
+
lines.push(boxHeader(theme, safeWidth, `${accent(theme, "pi-goal-x")} ${frame(theme, `─ ${model.title}`)}`));
|
|
280
299
|
|
|
281
300
|
// Status line.
|
|
282
301
|
if (model.status.code === "complete") {
|
|
283
302
|
lines.push(boxLine(theme, safeWidth, `${success(theme, "✓")} ${success(theme, "All required work is complete.")}`));
|
|
284
303
|
} else {
|
|
285
|
-
|
|
286
|
-
const color = STATUS_COLOR[model.status.code];
|
|
287
|
-
const bits = [`${theme.fg(color, symbol)} ${theme.fg(color, model.status.label)}`];
|
|
288
|
-
if (spec.showFocused) bits.push(muted(theme, `Focused: ${model.focused ? "yes" : "no"}`));
|
|
289
|
-
if (spec.showOtherGoals && model.otherOpenGoals > 0) bits.push(muted(theme, `Other goals: ${model.otherOpenGoals}`));
|
|
290
|
-
lines.push(boxLine(theme, safeWidth, bits.join(" · ")));
|
|
304
|
+
lines.push(boxLine(theme, safeWidth, statusLine(theme, model)));
|
|
291
305
|
}
|
|
292
306
|
|
|
293
307
|
// Budget (when configured): fuel gauge + amount, amber until the budget is
|
|
@@ -297,25 +311,38 @@ export function renderCompactDashboard(
|
|
|
297
311
|
lines.push(boxLine(theme, safeWidth, `${theme.fg(fuel as RenderColor, "⛽")} ${muted(theme, "Budget")} ${theme.fg(fuel as RenderColor, formatBudget(model.budget.used, model.budget.total))}`));
|
|
298
312
|
}
|
|
299
313
|
|
|
300
|
-
//
|
|
301
|
-
//
|
|
302
|
-
if (model.taskProgress) {
|
|
303
|
-
const bar = progressBar(theme, model.taskProgress.percentage, spec.barWidth);
|
|
304
|
-
lines.push(boxLine(theme, safeWidth, `${muted(theme, "Tasks")} ${bar} ${muted(theme, `${model.taskProgress.completed}/${model.taskProgress.total} · ${model.taskProgress.percentage}%`)}`));
|
|
305
|
-
}
|
|
314
|
+
// §9.1 compact task counts + progress bars live in the Tasks header row
|
|
315
|
+
// (below); the standalone progress lines were removed in favor of it.
|
|
306
316
|
|
|
307
317
|
// §9.2/§9.6 compact task list: a window over the top-level tasks, anchored
|
|
308
318
|
// by default so the most recently completed tasks are visible; when the
|
|
309
319
|
// list overflows the window, the footer advertises Ctrl+Shift+↑↓ to scroll
|
|
310
|
-
// it.
|
|
311
|
-
//
|
|
320
|
+
// it. The current task's subtask progress lives in the header segment, and
|
|
321
|
+
// per-row subtask markers show which tasks have subtasks.
|
|
312
322
|
const topLevel = model.taskTree.filter((node) => node.depth === 0);
|
|
313
323
|
const compactRows = compactTaskViewportRows(safeWidth);
|
|
314
324
|
const listOverflows = topLevel.length > compactRows;
|
|
315
325
|
if (topLevel.length > 0) {
|
|
316
326
|
const offset = opts.scrollOffset ?? anchoredScrollOffset(topLevel, compactRows);
|
|
317
327
|
const viewport = deriveTaskListViewport(topLevel.length, compactRows, offset);
|
|
318
|
-
|
|
328
|
+
// §9.1/§9.3 header row: counts first (`✓N done · M open`, skipped
|
|
329
|
+
// counts as done), compact task progress bar, then the current task's
|
|
330
|
+
// subtask progress bar beside it (` · Sub done/total `, wide/medium;
|
|
331
|
+
// narrow drops the word `Sub` so the full counts fit at 50 cols;
|
|
332
|
+
// minimal omits the segment — counts + task bar alone cannot share 38
|
|
333
|
+
// inner columns with a second bar). All muted: the header stays one
|
|
334
|
+
// frame-tone block. The standalone compact progress lines were removed
|
|
335
|
+
// in favor of this row.
|
|
336
|
+
const headerLabel = model.taskProgress
|
|
337
|
+
? `Tasks · ✓${model.taskProgress.completed} done · ${model.taskProgress.total - model.taskProgress.completed} open`
|
|
338
|
+
: "Tasks";
|
|
339
|
+
let headerRight = model.taskProgress ? progressBar(theme, model.taskProgress.percentage, spec.headerBarWidth) : "";
|
|
340
|
+
if (model.currentTask && model.currentTask.totalSubtasks > 0 && mode !== "minimal") {
|
|
341
|
+
const subBar = progressBar(theme, model.currentTask.subtaskPercentage, spec.subtaskBarWidth);
|
|
342
|
+
const subWord = mode === "narrow" ? "" : "Sub ";
|
|
343
|
+
headerRight += `${muted(theme, ` · ${subWord}`)}${muted(theme, `${model.currentTask.completedSubtasks}/${model.currentTask.totalSubtasks}`)} ${subBar}`;
|
|
344
|
+
}
|
|
345
|
+
lines.push(boxSectionRule(theme, safeWidth, headerLabel, headerRight));
|
|
319
346
|
for (const row of renderCompactTaskRows(theme, topLevel, viewport, inner)) {
|
|
320
347
|
lines.push(boxLine(theme, safeWidth, row));
|
|
321
348
|
}
|
|
@@ -336,11 +363,9 @@ export function renderCompactDashboard(
|
|
|
336
363
|
}
|
|
337
364
|
}
|
|
338
365
|
|
|
339
|
-
// Current-task subtask progress (§9.3)
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
lines.push(boxLine(theme, safeWidth, `${muted(theme, "Subtasks")} ${bar} ${muted(theme, `${model.currentTask.completedSubtasks}/${model.currentTask.totalSubtasks}`)} · ${muted(theme, `${model.currentTask.subtaskPercentage}%`)}`));
|
|
343
|
-
}
|
|
366
|
+
// Current-task subtask progress moved into the Tasks header row (§9.3);
|
|
367
|
+
// the standalone compact Subtasks progress line was removed. (The
|
|
368
|
+
// expanded dashboard's Current-task block still shows it.)
|
|
344
369
|
|
|
345
370
|
// Goal-level verification (§11.1): truncated first line in compact.
|
|
346
371
|
if (model.goalVerificationContract && mode !== "minimal") {
|
|
@@ -397,19 +422,9 @@ export function renderExpandedDashboard(
|
|
|
397
422
|
const inner = safeWidth - 2;
|
|
398
423
|
const lines: string[] = [];
|
|
399
424
|
|
|
400
|
-
|
|
401
|
-
? `${model.usage.elapsedLabel} · ${model.usage.tokenLabel}`
|
|
402
|
-
: "";
|
|
403
|
-
lines.push(boxHeader(theme, safeWidth, `${accent(theme, "pi-goal-x")} ${frame(theme, `─ ${model.title}`)}`, usageRight ? frame(theme, usageRight) : ""));
|
|
425
|
+
lines.push(boxHeader(theme, safeWidth, `${accent(theme, "pi-goal-x")} ${frame(theme, `─ ${model.title}`)}`));
|
|
404
426
|
|
|
405
|
-
|
|
406
|
-
const color = STATUS_COLOR[model.status.code];
|
|
407
|
-
const statusBits = [
|
|
408
|
-
`Status: ${theme.fg(color, symbol)} ${theme.fg(color, model.status.label)}`,
|
|
409
|
-
...((spec.showFocused ? [muted(theme, `Focused: ${model.focused ? "yes" : "no"}`)] : []) as string[]),
|
|
410
|
-
...((spec.showOtherGoals && model.otherOpenGoals > 0 ? [muted(theme, `Other goals: ${model.otherOpenGoals}`)] : []) as string[]),
|
|
411
|
-
];
|
|
412
|
-
lines.push(boxLine(theme, safeWidth, statusBits.join(" · ")));
|
|
427
|
+
lines.push(boxLine(theme, safeWidth, statusLine(theme, model)));
|
|
413
428
|
|
|
414
429
|
if (spec.showPath && model.filePath) {
|
|
415
430
|
lines.push(boxLine(theme, safeWidth, dim(theme, `File: ${model.filePath}`)));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-goal-x",
|
|
3
|
-
"version": "0.25.
|
|
3
|
+
"version": "0.25.2",
|
|
4
4
|
"description": "Goal mode extension for pi: durable long-running objectives, five model tools, structured tasks, independent completion audit, Sisyphus mode, auto-continue, and a status overlay.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "pi-goal-x contributors",
|