pi-crew 0.1.49 → 0.2.0

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.
Files changed (249) hide show
  1. package/CHANGELOG.md +74 -1
  2. package/README.md +176 -781
  3. package/agents/analyst.md +11 -11
  4. package/agents/critic.md +11 -11
  5. package/agents/executor.md +11 -11
  6. package/agents/explorer.md +11 -11
  7. package/agents/planner.md +11 -11
  8. package/agents/reviewer.md +11 -11
  9. package/agents/security-reviewer.md +11 -11
  10. package/agents/test-engineer.md +11 -11
  11. package/agents/verifier.md +70 -11
  12. package/agents/writer.md +11 -11
  13. package/docs/actions-reference.md +595 -0
  14. package/docs/commands-reference.md +347 -0
  15. package/docs/runtime-flow.md +148 -148
  16. package/index.ts +6 -6
  17. package/package.json +99 -99
  18. package/skills/async-worker-recovery/SKILL.md +42 -42
  19. package/skills/context-artifact-hygiene/SKILL.md +52 -52
  20. package/skills/delegation-patterns/SKILL.md +54 -54
  21. package/skills/mailbox-interactive/SKILL.md +40 -40
  22. package/skills/model-routing-context/SKILL.md +39 -39
  23. package/skills/multi-perspective-review/SKILL.md +58 -58
  24. package/skills/observability-reliability/SKILL.md +41 -41
  25. package/skills/orchestration/SKILL.md +157 -157
  26. package/skills/ownership-session-security/SKILL.md +41 -41
  27. package/skills/pi-extension-lifecycle/SKILL.md +39 -39
  28. package/skills/requirements-to-task-packet/SKILL.md +63 -63
  29. package/skills/resource-discovery-config/SKILL.md +41 -41
  30. package/skills/runtime-state-reader/SKILL.md +44 -44
  31. package/skills/secure-agent-orchestration-review/SKILL.md +45 -45
  32. package/skills/state-mutation-locking/SKILL.md +42 -42
  33. package/skills/systematic-debugging/SKILL.md +67 -67
  34. package/skills/ui-render-performance/SKILL.md +39 -39
  35. package/skills/verification-before-done/SKILL.md +57 -57
  36. package/skills/worktree-isolation/SKILL.md +39 -39
  37. package/src/adapters/claude-adapter.ts +25 -0
  38. package/src/adapters/codex-adapter.ts +21 -0
  39. package/src/adapters/cursor-adapter.ts +17 -0
  40. package/src/adapters/export-util.ts +137 -0
  41. package/src/adapters/index.ts +15 -0
  42. package/src/adapters/registry.ts +18 -0
  43. package/src/adapters/types.ts +23 -0
  44. package/src/agents/agent-config.ts +2 -0
  45. package/src/agents/agent-search.ts +98 -98
  46. package/src/agents/discover-agents.ts +2 -1
  47. package/src/config/config.ts +14 -1
  48. package/src/config/defaults.ts +5 -5
  49. package/src/config/drift-detector.ts +211 -0
  50. package/src/config/markers.ts +327 -0
  51. package/src/config/resilient-parser.ts +108 -0
  52. package/src/config/suggestions.ts +74 -0
  53. package/src/extension/cross-extension-rpc.ts +103 -82
  54. package/src/extension/project-init.ts +36 -4
  55. package/src/extension/register.ts +67 -22
  56. package/src/extension/registration/commands.ts +77 -8
  57. package/src/extension/registration/subagent-tools.ts +10 -1
  58. package/src/extension/registration/team-tool.ts +10 -1
  59. package/src/extension/registration/viewers.ts +48 -34
  60. package/src/extension/run-bundle-schema.ts +89 -89
  61. package/src/extension/run-export.ts +26 -12
  62. package/src/extension/run-import.ts +25 -1
  63. package/src/extension/run-index.ts +5 -1
  64. package/src/extension/run-maintenance.ts +142 -68
  65. package/src/extension/team-manager-command.ts +10 -1
  66. package/src/extension/team-tool/context.ts +1 -1
  67. package/src/extension/team-tool/doctor.ts +28 -3
  68. package/src/extension/team-tool/handle-settings.ts +195 -188
  69. package/src/extension/team-tool/inspect.ts +41 -41
  70. package/src/extension/team-tool/intent-policy.ts +42 -42
  71. package/src/extension/team-tool/lifecycle-actions.ts +27 -8
  72. package/src/extension/team-tool/plan.ts +19 -19
  73. package/src/extension/team-tool/run.ts +12 -1
  74. package/src/extension/team-tool.ts +14 -3
  75. package/src/i18n.ts +184 -184
  76. package/src/observability/exporters/otlp-exporter.ts +92 -77
  77. package/src/prompt/prompt-runtime.ts +72 -72
  78. package/src/runtime/agent-memory.ts +72 -72
  79. package/src/runtime/agent-observability.ts +114 -114
  80. package/src/runtime/async-marker.ts +26 -26
  81. package/src/runtime/attention-events.ts +28 -28
  82. package/src/runtime/auto-resume.ts +100 -0
  83. package/src/runtime/background-runner.ts +11 -1
  84. package/src/runtime/cancellation-token.ts +89 -89
  85. package/src/runtime/cancellation.ts +61 -61
  86. package/src/runtime/capability-inventory.ts +116 -116
  87. package/src/runtime/child-pi.ts +7 -2
  88. package/src/runtime/compaction-summary.ts +271 -0
  89. package/src/runtime/completion-guard.ts +190 -190
  90. package/src/runtime/concurrency.ts +3 -1
  91. package/src/runtime/crash-recovery.ts +33 -0
  92. package/src/runtime/delta-conflict.ts +360 -0
  93. package/src/runtime/diagnostic-export.ts +3 -1
  94. package/src/runtime/direct-run.ts +35 -35
  95. package/src/runtime/event-stream-bridge.ts +3 -1
  96. package/src/runtime/foreground-control.ts +82 -82
  97. package/src/runtime/green-contract.ts +46 -46
  98. package/src/runtime/group-join.ts +106 -106
  99. package/src/runtime/heartbeat-gradient.ts +28 -28
  100. package/src/runtime/heartbeat-watcher.ts +124 -124
  101. package/src/runtime/iteration-hooks.ts +262 -0
  102. package/src/runtime/live-agent-control.ts +88 -88
  103. package/src/runtime/live-control-realtime.ts +36 -36
  104. package/src/runtime/live-extension-bridge.ts +150 -150
  105. package/src/runtime/live-irc.ts +92 -92
  106. package/src/runtime/live-session-health.ts +100 -100
  107. package/src/runtime/loop-gates.ts +129 -0
  108. package/src/runtime/metric-parser.ts +40 -0
  109. package/src/runtime/notebook-helpers.ts +90 -90
  110. package/src/runtime/orphan-sentinel.ts +7 -7
  111. package/src/runtime/parallel-research.ts +44 -44
  112. package/src/runtime/phase-progress.ts +217 -0
  113. package/src/runtime/pi-args.ts +38 -2
  114. package/src/runtime/pi-json-output.ts +111 -111
  115. package/src/runtime/pi-spawn.ts +74 -6
  116. package/src/runtime/policy-engine.ts +79 -79
  117. package/src/runtime/post-checks.ts +122 -0
  118. package/src/runtime/process-status.ts +14 -1
  119. package/src/runtime/progress-event-coalescer.ts +43 -43
  120. package/src/runtime/prose-compressor.ts +164 -164
  121. package/src/runtime/recovery-recipes.ts +74 -74
  122. package/src/runtime/result-extractor.ts +121 -121
  123. package/src/runtime/role-permission.ts +39 -39
  124. package/src/runtime/sensitive-paths.ts +3 -3
  125. package/src/runtime/session-resources.ts +25 -25
  126. package/src/runtime/session-snapshot.ts +59 -59
  127. package/src/runtime/session-usage.ts +79 -79
  128. package/src/runtime/sidechain-output.ts +29 -29
  129. package/src/runtime/stream-preview.ts +177 -177
  130. package/src/runtime/supervisor-contact.ts +59 -59
  131. package/src/runtime/task-display.ts +38 -38
  132. package/src/runtime/task-graph.ts +207 -0
  133. package/src/runtime/task-quality.ts +207 -0
  134. package/src/runtime/task-runner/capabilities.ts +78 -78
  135. package/src/runtime/task-runner/live-executor.ts +7 -1
  136. package/src/runtime/task-runner/progress.ts +119 -119
  137. package/src/runtime/task-runner/prompt-builder.ts +1 -1
  138. package/src/runtime/task-runner/prompt-pipeline.ts +64 -64
  139. package/src/runtime/task-runner/result-utils.ts +14 -14
  140. package/src/runtime/task-runner/run-projection.ts +103 -103
  141. package/src/runtime/task-runner/state-helpers.ts +22 -22
  142. package/src/runtime/team-runner.ts +126 -7
  143. package/src/runtime/worker-heartbeat.ts +21 -21
  144. package/src/runtime/worker-startup.ts +57 -57
  145. package/src/runtime/workflow-state.ts +187 -0
  146. package/src/runtime/workspace-tree.ts +298 -298
  147. package/src/schema/config-schema.ts +12 -0
  148. package/src/schema/validation-types.ts +148 -0
  149. package/src/skills/skill-templates.ts +374 -0
  150. package/src/state/active-run-registry.ts +35 -11
  151. package/src/state/atomic-write.ts +33 -26
  152. package/src/state/contracts.ts +1 -0
  153. package/src/state/event-reconstructor.ts +217 -0
  154. package/src/state/locks.ts +2 -11
  155. package/src/state/mailbox.ts +4 -3
  156. package/src/state/state-store.ts +32 -14
  157. package/src/state/task-claims.ts +44 -44
  158. package/src/state/types.ts +9 -0
  159. package/src/state/usage.ts +29 -29
  160. package/src/subagents/async-entry.ts +1 -1
  161. package/src/subagents/index.ts +3 -3
  162. package/src/subagents/live/control.ts +1 -1
  163. package/src/subagents/live/manager.ts +1 -1
  164. package/src/subagents/live/realtime.ts +1 -1
  165. package/src/subagents/live/session-runtime.ts +1 -1
  166. package/src/subagents/manager.ts +1 -1
  167. package/src/subagents/spawn.ts +1 -1
  168. package/src/teams/team-serializer.ts +38 -38
  169. package/src/types/diff.d.ts +18 -18
  170. package/src/ui/crew-footer.ts +101 -101
  171. package/src/ui/crew-select-list.ts +111 -111
  172. package/src/ui/crew-widget.ts +9 -4
  173. package/src/ui/dashboard-panes/cancellation-pane.ts +42 -42
  174. package/src/ui/dashboard-panes/capability-pane.ts +59 -59
  175. package/src/ui/dashboard-panes/mailbox-pane.ts +35 -35
  176. package/src/ui/dashboard-panes/metrics-pane.ts +34 -34
  177. package/src/ui/dashboard-panes/progress-pane.ts +11 -0
  178. package/src/ui/dynamic-border.ts +25 -25
  179. package/src/ui/layout-primitives.ts +106 -106
  180. package/src/ui/loaders.ts +158 -158
  181. package/src/ui/powerbar-publisher.ts +6 -0
  182. package/src/ui/render-coalescer.ts +51 -51
  183. package/src/ui/render-diff.ts +119 -119
  184. package/src/ui/render-scheduler.ts +143 -143
  185. package/src/ui/run-action-dispatcher.ts +10 -1
  186. package/src/ui/spinner.ts +17 -17
  187. package/src/ui/status-colors.ts +58 -58
  188. package/src/ui/syntax-highlight.ts +116 -116
  189. package/src/ui/transcript-entries.ts +258 -258
  190. package/src/utils/completion-dedupe.ts +63 -63
  191. package/src/utils/frontmatter.ts +68 -68
  192. package/src/utils/git.ts +262 -262
  193. package/src/utils/ids.ts +17 -17
  194. package/src/utils/incremental-reader.ts +104 -104
  195. package/src/utils/names.ts +27 -27
  196. package/src/utils/redaction.ts +44 -44
  197. package/src/utils/safe-paths.ts +47 -47
  198. package/src/utils/scan-cache.ts +136 -136
  199. package/src/utils/sleep.ts +40 -26
  200. package/src/utils/task-name-generator.ts +337 -337
  201. package/src/workflows/validate-workflow.ts +40 -40
  202. package/src/worktree/branch-freshness.ts +45 -45
  203. package/src/worktree/worktree-manager.ts +11 -3
  204. package/teams/default.team.md +12 -12
  205. package/teams/fast-fix.team.md +11 -11
  206. package/teams/implementation.team.md +18 -18
  207. package/teams/parallel-research.team.md +14 -14
  208. package/teams/research.team.md +11 -11
  209. package/teams/review.team.md +12 -12
  210. package/workflows/default.workflow.md +30 -29
  211. package/workflows/fast-fix.workflow.md +23 -22
  212. package/workflows/implementation.workflow.md +43 -38
  213. package/workflows/parallel-research.workflow.md +46 -46
  214. package/workflows/research.workflow.md +22 -22
  215. package/workflows/review.workflow.md +30 -30
  216. package/docs/refactor-tasks-phase3.md +0 -394
  217. package/docs/refactor-tasks-phase4.md +0 -564
  218. package/docs/refactor-tasks-phase5.md +0 -402
  219. package/docs/refactor-tasks-phase6.md +0 -662
  220. package/docs/refactor-tasks.md +0 -1484
  221. package/docs/research/AGENT-EXECUTION-ARCHITECTURE.md +0 -261
  222. package/docs/research/AGENT-LIFECYCLE-COMPARISON.md +0 -111
  223. package/docs/research/AUDIT_OH_MY_PI.md +0 -261
  224. package/docs/research/AUDIT_PI_CREW.md +0 -457
  225. package/docs/research/CAVEMAN-DEEP-RESEARCH.md +0 -281
  226. package/docs/research/COMPARISON_OH_MY_PI_VS_PI_CREW.md +0 -264
  227. package/docs/research/DEEP-RESEARCH-PI-POWERBAR.md +0 -343
  228. package/docs/research/DEEP_RESEARCH_SUBAGENT_ARCHITECTURE.md +0 -480
  229. package/docs/research/GAP_CLOSURE_IMPLEMENTATION_PLAN.md +0 -354
  230. package/docs/research/IMPLEMENTATION_PLAN.md +0 -385
  231. package/docs/research/LIVE-SESSION-PRODUCTION-READY-PLAN.md +0 -502
  232. package/docs/research/OH-MY-PI-DEEP-RESEARCH-v14.7.6.md +0 -266
  233. package/docs/research/REMAINING-GAPS-PLAN.md +0 -363
  234. package/docs/research/SESSION-SUMMARY-2026-05-08.md +0 -146
  235. package/docs/research/UI-RESPONSIVENESS-AUDIT.md +0 -173
  236. package/docs/research-awesome-agent-skills-distillation.md +0 -100
  237. package/docs/research-extension-examples.md +0 -297
  238. package/docs/research-extension-system.md +0 -324
  239. package/docs/research-oh-my-pi-distillation.md +0 -369
  240. package/docs/research-optimization-plan.md +0 -548
  241. package/docs/research-phase10-distillation.md +0 -199
  242. package/docs/research-phase11-distillation.md +0 -201
  243. package/docs/research-phase8-operator-experience-plan.md +0 -819
  244. package/docs/research-phase9-observability-reliability-plan.md +0 -1190
  245. package/docs/research-pi-coding-agent.md +0 -357
  246. package/docs/research-source-pi-crew-reference.md +0 -174
  247. package/docs/research-ui-optimization-plan.md +0 -480
  248. package/docs/source-runtime-refactor-map.md +0 -107
  249. package/src/utils/atomic-write.ts +0 -33
@@ -1,402 +0,0 @@
1
- # Phase 5 Refactor Plan — Footer/Selectlist/Hot-reload từ pi-mono coding-agent
2
-
3
- > Xuất xứ: re-read `source/pi-mono/packages/coding-agent/src/modes/interactive/components/{footer,bordered-loader,dynamic-border,visual-truncate,diff,countdown-timer,extension-selector,theme-selector,custom-message,tool-execution,bash-execution}.ts` + `theme/theme.ts` (28/04/2026).
4
- > Mục tiêu: vá lỗi subtle còn lại từ Phase 4, hot-reload theme, port footer/select-list pattern, chuẩn hóa border + tool state styling.
5
- > Phase 4 đã hoàn tất, baseline: tsc 0 errors, 222 unit + 21 integration pass, commit `44fdd02`.
6
-
7
- ## Quy ước chung
8
- - Không phá vỡ public API (slash commands, tool actions, config schema). Mọi thay đổi nội bộ.
9
- - Sau mỗi task: `npx tsc --noEmit` + `npm run test:unit` (+ `test:integration` nếu liên quan render/runtime).
10
- - Không thêm dependency runtime mới. Tất cả implement self-contained hoặc qua peer dep `@mariozechner/pi-tui` đã có.
11
- - Mỗi task = 1 commit độc lập có thể revert. Đặt tên test bám sát hành vi.
12
- - Ưu tiên backward compatibility: default behavior không đổi, opt-in qua config khi có hành vi mới.
13
-
14
- ## Trạng thái cập nhật
15
- - [x] Task #50 — Fix `truncateToVisualLines` slice-after-merge bug
16
- - [x] Task #51 — Memoize `visibleWidth` LRU cache
17
- - [x] Task #52 — Theme hot-reload subscription
18
- - [x] Task #53 — Theme adapter `inverse` ANSI fallback
19
- - [x] Task #54 — `CrewFooter` component port
20
- - [x] Task #55 — `CrewSelectList` adapter
21
- - [x] Task #56 — `DynamicCrewBorder` reusable + CountdownTimer 1s tick
22
- - [x] Task #57 — Tool state styling cho transcript-viewer
23
- ---
24
-
25
- ## Tier 1 — Bug fixes & correctness (low risk, immediate value)
26
-
27
- Mục tiêu: 2 task, vá bug từ Phase 4 + tăng hiệu năng nhỏ. Ước tính: 0.5 ngày.
28
-
29
- ### Task #50 — Fix `truncateToVisualLines` slice-after-merge bug
30
- **Source**: `pi-mono/coding-agent/components/visual-truncate.ts`
31
- **Đích**: `pi-crew/src/utils/visual.ts`
32
-
33
- **Lý do**: Phase 4 #47 implement `truncateToVisualLines` với logic:
34
- ```ts
35
- const visualLines = text.split("\n").flatMap((line) =>
36
- wrapHard(pad(line, ...).trimEnd(), effectiveWidth).slice(0, Math.max(1, maxVisualLines))
37
- );
38
- ```
39
- Bug: `slice(0, maxVisualLines)` áp dụng **per source line** thay vì **toàn bộ visual lines sau merge**. Nếu 1 source line wrap thành N visual lines (N > maxVisualLines), kết quả lấy đầu line đó, không phải tail của toàn bộ output. Khi nhiều source line, tổng visual có thể vượt maxVisualLines.
40
-
41
- pi-mono dùng pattern đúng: render rồi `slice(-maxVisualLines)`.
42
-
43
- **Logic chuẩn**:
44
- ```ts
45
- export function truncateToVisualLines(text, maxVisualLines, width, paddingX = 0) {
46
- if (!text) return { visualLines: [], skippedCount: 0 };
47
- const effectiveWidth = Math.max(1, width - paddingX * 2);
48
- const allVisual = text.split("\n").flatMap((line) =>
49
- wrapHard(pad(line, effectiveWidth).trimEnd(), effectiveWidth)
50
- );
51
- if (allVisual.length <= maxVisualLines) return { visualLines: allVisual, skippedCount: 0 };
52
- return { visualLines: allVisual.slice(-maxVisualLines), skippedCount: allVisual.length - maxVisualLines };
53
- }
54
- ```
55
-
56
- **Acceptance**:
57
- - 1 source line wrap thành 5 visual lines, maxVisualLines=2 → trả về 2 visual lines cuối + skippedCount=3
58
- - 3 source lines × 2 visual mỗi line = 6 visual, maxVisualLines=4 → trả về 4 cuối + skippedCount=2
59
- - empty input → `{ visualLines: [], skippedCount: 0 }` (đổi từ `[""]` về `[]` để khớp pi-mono)
60
-
61
- **Verification**: 2 unit test mới trong `test/unit/visual.test.ts`. Verify transcript-viewer integration vẫn pass test cũ.
62
-
63
- **Risk**: thay đổi semantic empty input — kiểm tra all callers (transcript-viewer, run-dashboard) handle `[]` thay vì `[""]`.
64
-
65
- ---
66
-
67
- ### Task #51 — Memoize `visibleWidth` qua LRU cache
68
- **Source**: pattern caching từ pi-tui `utils.ts`
69
- **Đích**: `pi-crew/src/utils/visual.ts`
70
-
71
- **Lý do**: `visibleWidth(value)` được gọi trong:
72
- - `pad`, `truncateToWidth`, `wrapHard` (mỗi character iter)
73
- - `crew-widget.ts colorWidgetLine` (mỗi line, mỗi tick 250ms)
74
- - `RunDashboard.render` (5-10 lần per render)
75
- - Total ước tính: 50+ calls/render × 4 render/sec = 200+ regex ops/sec.
76
-
77
- Cache key = string identity, value = width. Reset khi cache > 256 entries (FIFO eviction).
78
-
79
- **API**:
80
- ```ts
81
- const widthCache = new Map<string, number>();
82
- const CACHE_LIMIT = 256;
83
-
84
- export function visibleWidth(value: string): number {
85
- const cached = widthCache.get(value);
86
- if (cached !== undefined) return cached;
87
- let length = 0;
88
- for (const char of value.replace(ANSI_PATTERN, "")) {
89
- if (char !== "\n") length += 1;
90
- }
91
- if (widthCache.size >= CACHE_LIMIT) {
92
- const firstKey = widthCache.keys().next().value;
93
- if (firstKey !== undefined) widthCache.delete(firstKey);
94
- }
95
- widthCache.set(value, length);
96
- return length;
97
- }
98
- ```
99
-
100
- **Acceptance**:
101
- - `visibleWidth("foo")` gọi 1000 lần → chỉ tính 1 lần (kiểm qua spy với regex.exec count nếu có Diff bench).
102
- - Cache không leak: limit 256, sau 1000 unique strings thì size = 256.
103
- - Output identical với version không cache (regression test).
104
-
105
- **Verification**:
106
- - 1 unit test cache hit
107
- - 1 unit test eviction (insert 257 strings, kiểm size === 256)
108
- - Bench: `visibleWidth(longString) × 10000` → time giảm ≥ 5× (ms log).
109
-
110
- **Risk**: cache miss khi string concat/template (mỗi lần object identity khác). Nhận diện qua bench thực tế.
111
-
112
- ---
113
-
114
- ## Tier 2 — Theme & style consistency
115
-
116
- Mục tiêu: 2 task, hot-reload + inverse fallback. Ước tính: 0.5 ngày.
117
-
118
- ### Task #52 — Theme hot-reload subscription
119
- **Source**: `pi-mono/coding-agent/theme/theme.ts` `onThemeChange()` + `startThemeWatcher()`
120
- **Đích**: `pi-crew/src/ui/theme-adapter.ts`, `src/extension/register.ts`
121
-
122
- **Lý do**: pi-mono có cơ chế watch custom theme JSON, debounce 100ms reload, emit callback. pi-crew adapter chỉ snapshot theme 1 lần ở `ctx.ui.custom((tui, theme, ...) => Component)`. Khi user gõ `/theme dark` từ pi-coding-agent, các pi-crew widget hold theme cũ cho tới khi recreate component.
123
-
124
- **Approach**:
125
- 1. Add `subscribeThemeChange(theme: unknown, callback: () => void): () => void` trong theme-adapter.ts. Internally:
126
- - Test if `theme` object có `addEventListener?.("change", ...)` hoặc `onThemeChange?.(...)` API.
127
- - Fallback: poll `theme.getColorMode?.()` + key signature mỗi 1s, callback nếu thay đổi.
128
- 2. CrewWidgetComponent / LiveRunSidebar / RunDashboard / DurableTextViewer: gọi `subscribeThemeChange` trong constructor, store unsubscribe, gọi `this.invalidate()` khi callback fires.
129
- 3. dispose: unsubscribe.
130
-
131
- **Acceptance**:
132
- - Mock theme với `onThemeChange` API → callback fires trong 200ms.
133
- - Mock theme polling → kiểm callback fires sau 1.1s khi sig thay đổi.
134
- - Dispose component → no further callback.
135
-
136
- **Verification**: 2 unit test mock theme objects. Manual test: chạy pi với `/theme light` rồi `/theme dark`, kiểm RunDashboard re-render.
137
-
138
- **Risk**: polling 1s × N components → overhead. Mitigate: shared global subscription, fan-out tới components qua singleton subscriber list. Implement singleton trong theme-adapter.
139
-
140
- ---
141
-
142
- ### Task #53 — Theme adapter `inverse` ANSI fallback
143
- **Source**: `pi-mono` dùng `chalk.inverse(text)` = `\x1b[7m{text}\x1b[27m`
144
- **Đích**: `pi-crew/src/ui/theme-adapter.ts`
145
-
146
- **Lý do**: `asCrewTheme` hiện chỉ pass-through nếu source theme có `inverse`, fallback identity (return text nguyên). render-diff dùng `theme.inverse?.(value) ?? value` → khi theme nguồn không có inverse, intra-line diff highlight bị mất hoàn toàn. Bug visual subtle, không có test catch.
147
-
148
- **Logic chuẩn**:
149
- ```ts
150
- function asInverse(value: unknown): (text: string) => string {
151
- const fn = asUnaryFn(value);
152
- if (fn) return fn;
153
- return (text) => `\u001b[7m${text}\u001b[27m`;
154
- }
155
- ```
156
-
157
- **Acceptance**:
158
- - `asCrewTheme(undefined).inverse?.("x")` → `"\u001b[7mx\u001b[27m"`.
159
- - `asCrewTheme(realTheme).inverse?.("x")` → output từ chalk (test bằng `includes("\u001b[7m")`).
160
- - renderDiff với theme tối giản vẫn highlight inverse lookup.
161
-
162
- **Verification**: cập nhật `loaders.test.ts`/thêm `theme-adapter.test.ts` 2 test (default fallback + provided theme passthrough).
163
-
164
- **Risk**: thấp — additive change.
165
-
166
- ---
167
-
168
- ## Tier 3 — UX components (port pattern từ pi-mono)
169
-
170
- Mục tiêu: 3 task, footer + selectlist + dynamic border. Ước tính: 1 ngày.
171
-
172
- ### Task #54 — `CrewFooter` component port
173
- **Source**: `pi-mono/coding-agent/components/footer.ts`
174
- **Đích**: `pi-crew/src/ui/crew-footer.ts` (mới), tích hợp vào `RunDashboard`.
175
-
176
- **Lý do**: pi-mono Footer là pattern multi-line trang trí (pwd+branch, tokens, context %, model). pi-crew RunDashboard có summary 1 line trộn rời rạc. Port để đồng bộ visual với coding-agent.
177
-
178
- **Layout (3 lines)**:
179
- ```
180
- ~/proj (main) • runId • running (dim)
181
- ↑in ↓out R cache W cache $cost • 45.3%/200k (dim, % colored)
182
- [badge1] [badge2] ... (extension statuses)
183
- ```
184
-
185
- **API**:
186
- ```ts
187
- export interface CrewFooterData {
188
- pwd: string;
189
- branch?: string;
190
- runId?: string;
191
- status?: RunStatus;
192
- usage?: UsageState;
193
- contextWindow?: number;
194
- contextPercent?: number;
195
- badges?: string[]; // raw text per extension status
196
- }
197
-
198
- export class CrewFooter {
199
- constructor(private data: CrewFooterData, private theme: CrewTheme) {}
200
- setData(data: CrewFooterData): void;
201
- render(width: number): string[];
202
- invalidate(): void;
203
- }
204
- ```
205
-
206
- **Color logic**:
207
- - contextPercent > 90 → `theme.fg("error", ...)`
208
- - > 70 → `theme.fg("warning", ...)`
209
- - ≤ 70 → no color
210
-
211
- **Acceptance**:
212
- - Render cho run với usage tokens → output chứa `↑`, `↓`, `$cost`.
213
- - Truncate khi width nhỏ → ellipsis `...`.
214
- - contextPercent NaN/undefined → display `?/window`.
215
-
216
- **Verification**:
217
- - `test/unit/crew-footer.test.ts` 4 test (basic render, color thresholds, truncation, missing data).
218
- - Integrate vào `RunDashboard.renderFooter` (thay phần legacy footer).
219
-
220
- **Risk**: RunDashboard layout shift — kiểm snapshot lines count với existing tests.
221
-
222
- ---
223
-
224
- ### Task #55 — `CrewSelectList` adapter
225
- **Source**: `@mariozechner/pi-tui` `SelectList` (peer dep) + pi-mono `extension-selector.ts`/`theme-selector.ts` patterns
226
- **Đích**: `pi-crew/src/ui/crew-select-list.ts`
227
-
228
- **Lý do**: RunDashboard handle keyboard navigation thủ công (j/k/enter), không có visual highlight selected, không support `onPreview`. pi-tui SelectList có sẵn nhưng pi-crew chưa wrap. Cần adapter để xài SelectList từ peer dep pi-tui (optional dep — kiểm `import { SelectList } from "@mariozechner/pi-tui"` available).
229
-
230
- **Approach**:
231
- 1. Detect runtime: `try { require.resolve("@mariozechner/pi-tui"); }` → dùng pi-tui SelectList.
232
- 2. Fallback: simple list component port từ extension-selector.ts (j/k/↑/↓/enter/esc handlers, highlight ` → ` cho selected).
233
- 3. API:
234
- ```ts
235
- export interface CrewSelectItem<T = string> {
236
- value: T;
237
- label: string;
238
- description?: string;
239
- }
240
-
241
- export class CrewSelectList<T = string> {
242
- constructor(
243
- items: CrewSelectItem<T>[],
244
- theme: CrewTheme,
245
- options: {
246
- onSelect: (item: CrewSelectItem<T>) => void;
247
- onCancel: () => void;
248
- onPreview?: (item: CrewSelectItem<T>) => void;
249
- maxHeight?: number;
250
- }
251
- ) {}
252
- render(width: number): string[];
253
- handleInput(data: string): void;
254
- invalidate(): void;
255
- setSelectedIndex(i: number): void;
256
- getSelected(): CrewSelectItem<T> | undefined;
257
- }
258
- ```
259
-
260
- **Acceptance**:
261
- - Render với 5 items → 5 lines, selected có ` → `.
262
- - handleInput("j") → selected index +1, callback onPreview fired.
263
- - handleInput("\n") → callback onSelect with current item.
264
- - maxHeight=3 với 10 items → scroll, indicator `↑ N more`/`↓ N more`.
265
-
266
- **Verification**: `test/unit/crew-select-list.test.ts` 5 test.
267
-
268
- **Risk**: API mismatch nếu pi-tui SelectList API đổi version. Pin behavior qua adapter, fallback always available.
269
-
270
- ---
271
-
272
- ### Task #56 — `DynamicCrewBorder` reusable + CountdownTimer 1s tick
273
- **Source**: `pi-mono/coding-agent/components/dynamic-border.ts` + `countdown-timer.ts`
274
- **Đích**: `pi-crew/src/ui/dynamic-border.ts` (mới), refactor `loaders.ts`
275
-
276
- **Lý do**:
277
- 1. **DynamicBorder**: 10 LOC, render single line `─×width`. pi-crew có 3 nơi tự vẽ border:
278
- - `loaders.ts CrewBorderedLoader`: `┌─┐│└─┘` static template
279
- - `mascot.ts`: tự build `╭─╮│╰─╯`
280
- - `run-dashboard.ts/transcript-viewer.ts`: tự pad border lines
281
- → Refactor dùng chung `DynamicCrewBorder` cho horizontal lines, giữ corner chars riêng.
282
- 2. **CountdownTimer 1s tick**: hiện tại tick 250ms (4×/s). pi-mono tick chính xác 1000ms + `tui.requestRender()`. 4× tick là wasteful, gây re-render trùng lặp.
283
-
284
- **API**:
285
- ```ts
286
- // dynamic-border.ts
287
- export interface DynamicCrewBorderOptions {
288
- color?: (s: string) => string;
289
- char?: string; // default "─"
290
- }
291
- export class DynamicCrewBorder {
292
- constructor(theme: CrewTheme, options?: DynamicCrewBorderOptions) {}
293
- render(width: number): string[];
294
- invalidate(): void;
295
- }
296
- ```
297
-
298
- CountdownTimer change:
299
- ```ts
300
- // trong loaders.ts CountdownTimer
301
- - this.timer = setInterval(() => { ... }, 250);
302
- + this.timer = setInterval(() => {
303
- + const seconds = this.secondsLeft();
304
- + this.onTick(seconds);
305
- + if (seconds <= 0) this.emitExpire();
306
- + }, 1000);
307
- ```
308
-
309
- **Acceptance**:
310
- - DynamicCrewBorder.render(20) → `["─".repeat(20)]` (with color).
311
- - DynamicCrewBorder dùng trong CrewBorderedLoader, mascot box, run-dashboard separators.
312
- - CountdownTimer onTick called ~3 lần trong 3.5s (giây 3, 2, 1, 0 không nhiều hơn).
313
-
314
- **Verification**:
315
- - 2 unit test cho DynamicCrewBorder (basic render, custom char).
316
- - Update `loaders.test.ts` CountdownTimer test: kiểm onTick count = ceil(timeoutMs/1000) + 1.
317
-
318
- **Risk**: mascot CountdownTimer (nếu có) cần điều chỉnh cùng. Visual flicker giảm bằng tick 1s thay 250ms.
319
-
320
- ---
321
-
322
- ## Tier 4 — Power features
323
-
324
- Mục tiêu: 1 task, tool state styling. Ước tính: 0.25 ngày.
325
-
326
- ### Task #57 — Tool state styling cho transcript-viewer
327
- **Source**: `pi-mono/coding-agent/components/tool-execution.ts` (toolPendingBg/toolSuccessBg/toolErrorBg state)
328
- **Đích**: `pi-crew/src/ui/transcript-viewer.ts`
329
-
330
- **Lý do**: transcript-viewer hiện render `[Tool: name] type` plain text. Không phân biệt:
331
- - partial vs final result
332
- - success vs error (`result.isError`)
333
- - queued vs running
334
-
335
- User scan transcript khó tìm ra error tool nhanh.
336
-
337
- **Logic update `formatTranscriptEvent`**:
338
- ```ts
339
- const isError = obj.isError === true || asRecord(obj.result)?.isError === true;
340
- const isPartial = obj.isPartial === true;
341
- const status: RunStatus = isError ? "failed" : isPartial ? "running" : "completed";
342
- const icon = iconForStatus(status, { runningGlyph: "⋯" });
343
- const headerColor = colorForStatus(status);
344
- const header = theme.fg(headerColor, `${icon} [Tool${toolName ? `: ${toolName}` : ""}] ${type}`);
345
- ```
346
-
347
- **Acceptance**:
348
- - Event với `isError: true` → header có icon `✗`, color `error`.
349
- - Event với `isPartial: true` → header có icon `⋯`/`▶`, color `accent`.
350
- - Event normal → icon `✓`, color `success`.
351
- - Existing tests `formatTranscriptText formats message and tool JSONL into conversation lines` vẫn pass.
352
-
353
- **Verification**: thêm 2 test cho transcript-viewer (error tool, partial tool).
354
-
355
- **Risk**: thấp — schema event đã có `isError`, chỉ unwrap đúng.
356
-
357
- ---
358
-
359
- ## Thứ tự gợi ý thực hiện
360
-
361
- 1. **Day 1 — Tier 1 (bug fix + perf)**: #50 → #51
362
- - #50 fix bug subtle có thể impact nhiều screen.
363
- - #51 cache độc lập, không phụ thuộc #50.
364
-
365
- 2. **Day 1.5 — Tier 2 (theme)**: #52 → #53
366
- - #53 nhanh (additive). #52 cần test với mock theme objects.
367
-
368
- 3. **Day 2 — Tier 3 (UX)**: #54 → #55 → #56
369
- - #54 footer độc lập, không break.
370
- - #55 select-list pre-req cho future RunDashboard refactor.
371
- - #56 dynamic-border refactor 3 file (loaders, mascot, dashboard).
372
-
373
- 4. **Day 2 close — Tier 4 (#57)**: tool state styling, kết hợp với existing iconForStatus.
374
-
375
- Toàn bộ Phase 5 ước tính 1.5–2 ngày focus work, **0 dependency mới**.
376
-
377
- ---
378
-
379
- ## Metrics mục tiêu (verification cuối Phase 5)
380
-
381
- - **truncateToVisualLines correctness**: 0 known bug. New tests catch slice-after-merge.
382
- - **visibleWidth perf**: cache hit rate ≥ 80% trong tick loop, regex calls giảm ≥ 5× theo bench.
383
- - **Theme reload latency**: < 200ms từ `onThemeChange` callback tới UI re-render.
384
- - **Footer info density**: RunDashboard footer 2-3 line giống pi-coding-agent.
385
- - **Border consistency**: 1 DynamicCrewBorder thay 3 self-rolled patterns.
386
- - **Test count**: 222 unit → ~234 unit (thêm ~12 test cho 8 task).
387
- - **Type safety**: 0 unsafe theme cast (giữ nguyên Phase 4).
388
- - **Deps mới**: 0.
389
-
390
- ---
391
-
392
- ## Tracking template (per commit message)
393
-
394
- ```
395
- Phase 5 task #<num>: <title>
396
-
397
- <body — what changed, why, refs to source pi-mono>
398
-
399
- Verification: tsc --noEmit OK; test:unit OK; test:integration <OK|N/A>
400
-
401
- Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
402
- ```