@lumenflow/core 1.0.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 (263) hide show
  1. package/LICENSE +190 -0
  2. package/README.md +119 -0
  3. package/dist/active-wu-detector.d.ts +33 -0
  4. package/dist/active-wu-detector.js +106 -0
  5. package/dist/adapters/filesystem-metrics.adapter.d.ts +108 -0
  6. package/dist/adapters/filesystem-metrics.adapter.js +519 -0
  7. package/dist/adapters/terminal-renderer.adapter.d.ts +106 -0
  8. package/dist/adapters/terminal-renderer.adapter.js +337 -0
  9. package/dist/arg-parser.d.ts +63 -0
  10. package/dist/arg-parser.js +560 -0
  11. package/dist/backlog-editor.d.ts +98 -0
  12. package/dist/backlog-editor.js +179 -0
  13. package/dist/backlog-generator.d.ts +111 -0
  14. package/dist/backlog-generator.js +381 -0
  15. package/dist/backlog-parser.d.ts +45 -0
  16. package/dist/backlog-parser.js +102 -0
  17. package/dist/backlog-sync-validator.d.ts +78 -0
  18. package/dist/backlog-sync-validator.js +294 -0
  19. package/dist/branch-drift.d.ts +34 -0
  20. package/dist/branch-drift.js +51 -0
  21. package/dist/cleanup-install-config.d.ts +33 -0
  22. package/dist/cleanup-install-config.js +37 -0
  23. package/dist/cleanup-lock.d.ts +139 -0
  24. package/dist/cleanup-lock.js +313 -0
  25. package/dist/code-path-validator.d.ts +146 -0
  26. package/dist/code-path-validator.js +537 -0
  27. package/dist/code-paths-overlap.d.ts +55 -0
  28. package/dist/code-paths-overlap.js +245 -0
  29. package/dist/commands-logger.d.ts +77 -0
  30. package/dist/commands-logger.js +254 -0
  31. package/dist/commit-message-utils.d.ts +25 -0
  32. package/dist/commit-message-utils.js +41 -0
  33. package/dist/compliance-parser.d.ts +150 -0
  34. package/dist/compliance-parser.js +507 -0
  35. package/dist/constants/backlog-patterns.d.ts +20 -0
  36. package/dist/constants/backlog-patterns.js +23 -0
  37. package/dist/constants/dora-constants.d.ts +49 -0
  38. package/dist/constants/dora-constants.js +53 -0
  39. package/dist/constants/gate-constants.d.ts +15 -0
  40. package/dist/constants/gate-constants.js +15 -0
  41. package/dist/constants/linter-constants.d.ts +16 -0
  42. package/dist/constants/linter-constants.js +16 -0
  43. package/dist/constants/tokenizer-constants.d.ts +15 -0
  44. package/dist/constants/tokenizer-constants.js +15 -0
  45. package/dist/core/scope-checker.d.ts +97 -0
  46. package/dist/core/scope-checker.js +163 -0
  47. package/dist/core/tool-runner.d.ts +161 -0
  48. package/dist/core/tool-runner.js +393 -0
  49. package/dist/core/tool.constants.d.ts +105 -0
  50. package/dist/core/tool.constants.js +101 -0
  51. package/dist/core/tool.schemas.d.ts +226 -0
  52. package/dist/core/tool.schemas.js +226 -0
  53. package/dist/core/worktree-guard.d.ts +130 -0
  54. package/dist/core/worktree-guard.js +242 -0
  55. package/dist/coverage-gate.d.ts +108 -0
  56. package/dist/coverage-gate.js +196 -0
  57. package/dist/date-utils.d.ts +75 -0
  58. package/dist/date-utils.js +140 -0
  59. package/dist/dependency-graph.d.ts +142 -0
  60. package/dist/dependency-graph.js +550 -0
  61. package/dist/dependency-guard.d.ts +54 -0
  62. package/dist/dependency-guard.js +142 -0
  63. package/dist/dependency-validator.d.ts +105 -0
  64. package/dist/dependency-validator.js +154 -0
  65. package/dist/docs-path-validator.d.ts +36 -0
  66. package/dist/docs-path-validator.js +95 -0
  67. package/dist/domain/orchestration.constants.d.ts +99 -0
  68. package/dist/domain/orchestration.constants.js +97 -0
  69. package/dist/domain/orchestration.schemas.d.ts +280 -0
  70. package/dist/domain/orchestration.schemas.js +211 -0
  71. package/dist/domain/orchestration.types.d.ts +133 -0
  72. package/dist/domain/orchestration.types.js +12 -0
  73. package/dist/error-handler.d.ts +116 -0
  74. package/dist/error-handler.js +136 -0
  75. package/dist/file-classifiers.d.ts +62 -0
  76. package/dist/file-classifiers.js +108 -0
  77. package/dist/gates-agent-mode.d.ts +81 -0
  78. package/dist/gates-agent-mode.js +94 -0
  79. package/dist/generate-traceability.d.ts +107 -0
  80. package/dist/generate-traceability.js +411 -0
  81. package/dist/git-adapter.d.ts +395 -0
  82. package/dist/git-adapter.js +649 -0
  83. package/dist/git-staged-validator.d.ts +32 -0
  84. package/dist/git-staged-validator.js +48 -0
  85. package/dist/hardcoded-strings.d.ts +61 -0
  86. package/dist/hardcoded-strings.js +270 -0
  87. package/dist/incremental-lint.d.ts +78 -0
  88. package/dist/incremental-lint.js +129 -0
  89. package/dist/incremental-test.d.ts +39 -0
  90. package/dist/incremental-test.js +61 -0
  91. package/dist/index.d.ts +42 -0
  92. package/dist/index.js +61 -0
  93. package/dist/invariants/check-automated-tests.d.ts +50 -0
  94. package/dist/invariants/check-automated-tests.js +166 -0
  95. package/dist/invariants-runner.d.ts +103 -0
  96. package/dist/invariants-runner.js +527 -0
  97. package/dist/lane-checker.d.ts +50 -0
  98. package/dist/lane-checker.js +319 -0
  99. package/dist/lane-inference.d.ts +39 -0
  100. package/dist/lane-inference.js +195 -0
  101. package/dist/lane-lock.d.ts +211 -0
  102. package/dist/lane-lock.js +474 -0
  103. package/dist/lane-validator.d.ts +48 -0
  104. package/dist/lane-validator.js +114 -0
  105. package/dist/logs-lib.d.ts +104 -0
  106. package/dist/logs-lib.js +207 -0
  107. package/dist/lumenflow-config-schema.d.ts +272 -0
  108. package/dist/lumenflow-config-schema.js +207 -0
  109. package/dist/lumenflow-config.d.ts +95 -0
  110. package/dist/lumenflow-config.js +236 -0
  111. package/dist/manual-test-validator.d.ts +80 -0
  112. package/dist/manual-test-validator.js +200 -0
  113. package/dist/merge-lock.d.ts +115 -0
  114. package/dist/merge-lock.js +251 -0
  115. package/dist/micro-worktree.d.ts +159 -0
  116. package/dist/micro-worktree.js +427 -0
  117. package/dist/migration-deployer.d.ts +69 -0
  118. package/dist/migration-deployer.js +151 -0
  119. package/dist/orchestration-advisory-loader.d.ts +28 -0
  120. package/dist/orchestration-advisory-loader.js +87 -0
  121. package/dist/orchestration-advisory.d.ts +58 -0
  122. package/dist/orchestration-advisory.js +94 -0
  123. package/dist/orchestration-di.d.ts +48 -0
  124. package/dist/orchestration-di.js +57 -0
  125. package/dist/orchestration-rules.d.ts +57 -0
  126. package/dist/orchestration-rules.js +201 -0
  127. package/dist/orphan-detector.d.ts +131 -0
  128. package/dist/orphan-detector.js +226 -0
  129. package/dist/path-classifiers.d.ts +57 -0
  130. package/dist/path-classifiers.js +93 -0
  131. package/dist/piped-command-detector.d.ts +34 -0
  132. package/dist/piped-command-detector.js +64 -0
  133. package/dist/ports/dashboard-renderer.port.d.ts +112 -0
  134. package/dist/ports/dashboard-renderer.port.js +25 -0
  135. package/dist/ports/metrics-collector.port.d.ts +132 -0
  136. package/dist/ports/metrics-collector.port.js +26 -0
  137. package/dist/process-detector.d.ts +84 -0
  138. package/dist/process-detector.js +172 -0
  139. package/dist/prompt-linter.d.ts +72 -0
  140. package/dist/prompt-linter.js +312 -0
  141. package/dist/prompt-monitor.d.ts +15 -0
  142. package/dist/prompt-monitor.js +205 -0
  143. package/dist/rebase-artifact-cleanup.d.ts +145 -0
  144. package/dist/rebase-artifact-cleanup.js +433 -0
  145. package/dist/retry-strategy.d.ts +189 -0
  146. package/dist/retry-strategy.js +283 -0
  147. package/dist/risk-detector.d.ts +108 -0
  148. package/dist/risk-detector.js +252 -0
  149. package/dist/rollback-utils.d.ts +76 -0
  150. package/dist/rollback-utils.js +104 -0
  151. package/dist/section-headings.d.ts +43 -0
  152. package/dist/section-headings.js +49 -0
  153. package/dist/spawn-escalation.d.ts +90 -0
  154. package/dist/spawn-escalation.js +253 -0
  155. package/dist/spawn-monitor.d.ts +229 -0
  156. package/dist/spawn-monitor.js +672 -0
  157. package/dist/spawn-recovery.d.ts +82 -0
  158. package/dist/spawn-recovery.js +298 -0
  159. package/dist/spawn-registry-schema.d.ts +98 -0
  160. package/dist/spawn-registry-schema.js +108 -0
  161. package/dist/spawn-registry-store.d.ts +146 -0
  162. package/dist/spawn-registry-store.js +273 -0
  163. package/dist/spawn-tree.d.ts +121 -0
  164. package/dist/spawn-tree.js +285 -0
  165. package/dist/stamp-status-validator.d.ts +84 -0
  166. package/dist/stamp-status-validator.js +134 -0
  167. package/dist/stamp-utils.d.ts +100 -0
  168. package/dist/stamp-utils.js +229 -0
  169. package/dist/state-machine.d.ts +26 -0
  170. package/dist/state-machine.js +83 -0
  171. package/dist/system-map-validator.d.ts +80 -0
  172. package/dist/system-map-validator.js +272 -0
  173. package/dist/telemetry.d.ts +80 -0
  174. package/dist/telemetry.js +213 -0
  175. package/dist/token-counter.d.ts +51 -0
  176. package/dist/token-counter.js +145 -0
  177. package/dist/usecases/get-dashboard-data.usecase.d.ts +52 -0
  178. package/dist/usecases/get-dashboard-data.usecase.js +61 -0
  179. package/dist/usecases/get-suggestions.usecase.d.ts +100 -0
  180. package/dist/usecases/get-suggestions.usecase.js +153 -0
  181. package/dist/user-normalizer.d.ts +41 -0
  182. package/dist/user-normalizer.js +141 -0
  183. package/dist/validators/phi-constants.d.ts +97 -0
  184. package/dist/validators/phi-constants.js +152 -0
  185. package/dist/validators/phi-scanner.d.ts +58 -0
  186. package/dist/validators/phi-scanner.js +215 -0
  187. package/dist/worktree-ownership.d.ts +50 -0
  188. package/dist/worktree-ownership.js +74 -0
  189. package/dist/worktree-scanner.d.ts +103 -0
  190. package/dist/worktree-scanner.js +168 -0
  191. package/dist/worktree-symlink.d.ts +99 -0
  192. package/dist/worktree-symlink.js +359 -0
  193. package/dist/wu-backlog-updater.d.ts +17 -0
  194. package/dist/wu-backlog-updater.js +37 -0
  195. package/dist/wu-checkpoint.d.ts +124 -0
  196. package/dist/wu-checkpoint.js +233 -0
  197. package/dist/wu-claim-helpers.d.ts +26 -0
  198. package/dist/wu-claim-helpers.js +63 -0
  199. package/dist/wu-claim-resume.d.ts +106 -0
  200. package/dist/wu-claim-resume.js +276 -0
  201. package/dist/wu-consistency-checker.d.ts +95 -0
  202. package/dist/wu-consistency-checker.js +567 -0
  203. package/dist/wu-constants.d.ts +1275 -0
  204. package/dist/wu-constants.js +1382 -0
  205. package/dist/wu-create-validators.d.ts +42 -0
  206. package/dist/wu-create-validators.js +93 -0
  207. package/dist/wu-done-branch-only.d.ts +63 -0
  208. package/dist/wu-done-branch-only.js +191 -0
  209. package/dist/wu-done-messages.d.ts +119 -0
  210. package/dist/wu-done-messages.js +185 -0
  211. package/dist/wu-done-pr.d.ts +72 -0
  212. package/dist/wu-done-pr.js +174 -0
  213. package/dist/wu-done-retry-helpers.d.ts +85 -0
  214. package/dist/wu-done-retry-helpers.js +172 -0
  215. package/dist/wu-done-ui.d.ts +37 -0
  216. package/dist/wu-done-ui.js +69 -0
  217. package/dist/wu-done-validators.d.ts +411 -0
  218. package/dist/wu-done-validators.js +1229 -0
  219. package/dist/wu-done-worktree.d.ts +182 -0
  220. package/dist/wu-done-worktree.js +1097 -0
  221. package/dist/wu-helpers.d.ts +128 -0
  222. package/dist/wu-helpers.js +248 -0
  223. package/dist/wu-lint.d.ts +70 -0
  224. package/dist/wu-lint.js +234 -0
  225. package/dist/wu-paths.d.ts +171 -0
  226. package/dist/wu-paths.js +178 -0
  227. package/dist/wu-preflight-validators.d.ts +86 -0
  228. package/dist/wu-preflight-validators.js +251 -0
  229. package/dist/wu-recovery.d.ts +138 -0
  230. package/dist/wu-recovery.js +341 -0
  231. package/dist/wu-repair-core.d.ts +131 -0
  232. package/dist/wu-repair-core.js +669 -0
  233. package/dist/wu-schema-normalization.d.ts +17 -0
  234. package/dist/wu-schema-normalization.js +82 -0
  235. package/dist/wu-schema.d.ts +793 -0
  236. package/dist/wu-schema.js +881 -0
  237. package/dist/wu-spawn-helpers.d.ts +121 -0
  238. package/dist/wu-spawn-helpers.js +271 -0
  239. package/dist/wu-spawn.d.ts +158 -0
  240. package/dist/wu-spawn.js +1306 -0
  241. package/dist/wu-state-schema.d.ts +213 -0
  242. package/dist/wu-state-schema.js +156 -0
  243. package/dist/wu-state-store.d.ts +264 -0
  244. package/dist/wu-state-store.js +691 -0
  245. package/dist/wu-status-transition.d.ts +63 -0
  246. package/dist/wu-status-transition.js +382 -0
  247. package/dist/wu-status-updater.d.ts +25 -0
  248. package/dist/wu-status-updater.js +116 -0
  249. package/dist/wu-transaction-collectors.d.ts +116 -0
  250. package/dist/wu-transaction-collectors.js +272 -0
  251. package/dist/wu-transaction.d.ts +170 -0
  252. package/dist/wu-transaction.js +273 -0
  253. package/dist/wu-validation-constants.d.ts +60 -0
  254. package/dist/wu-validation-constants.js +66 -0
  255. package/dist/wu-validation.d.ts +118 -0
  256. package/dist/wu-validation.js +243 -0
  257. package/dist/wu-validator.d.ts +62 -0
  258. package/dist/wu-validator.js +325 -0
  259. package/dist/wu-yaml-fixer.d.ts +97 -0
  260. package/dist/wu-yaml-fixer.js +264 -0
  261. package/dist/wu-yaml.d.ts +86 -0
  262. package/dist/wu-yaml.js +222 -0
  263. package/package.json +114 -0
@@ -0,0 +1,337 @@
1
+ /**
2
+ * Terminal Dashboard Renderer Adapter
3
+ *
4
+ * Hexagonal Architecture - Infrastructure Layer
5
+ * Implements the DashboardRenderer port for terminal/CLI output.
6
+ *
7
+ * Follows Edward Tufte's data visualisation principles:
8
+ * - High data-ink ratio (minimal chartjunk)
9
+ * - Small multiples for comparison (agent metrics table)
10
+ * - 5-second scannable layout
11
+ * - Headline sentences for context
12
+ *
13
+ * Library-First Approach:
14
+ * - picocolors: Semantic ANSI colours (NOT raw escape codes)
15
+ * - cli-table3: ASCII table rendering
16
+ * - cli-progress: Progress bar rendering
17
+ *
18
+ * @module terminal-renderer.adapter
19
+ * @see {@link ../ports/dashboard-renderer.port.ts} - Port interface
20
+ * @see {@link ../domain/orchestration.types.ts} - Domain types
21
+ */
22
+ import picocolors from 'picocolors';
23
+ import Table from 'cli-table3';
24
+ // Constants for rendering (no magic strings)
25
+ const SECTION_SEPARATOR = '\n' + '─'.repeat(80) + '\n';
26
+ const HEADER_PREFIX = '▸';
27
+ const BULLET = '•';
28
+ const CHECK_MARK = '✓';
29
+ const CROSS_MARK = '✗';
30
+ const PENDING_MARK = '○';
31
+ const PROGRESS_BAR_WIDTH = 30;
32
+ // Severity colour mapping
33
+ const SEVERITY_COLOURS = {
34
+ high: picocolors.red,
35
+ medium: picocolors.yellow,
36
+ low: picocolors.cyan,
37
+ };
38
+ // Agent result colour mapping
39
+ const RESULT_COLOURS = {
40
+ pass: picocolors.green,
41
+ fail: picocolors.red,
42
+ pending: picocolors.yellow,
43
+ skipped: picocolors.gray,
44
+ };
45
+ // Event severity colour mapping
46
+ const EVENT_SEVERITY_COLOURS = {
47
+ info: picocolors.cyan,
48
+ warning: picocolors.yellow,
49
+ error: picocolors.red,
50
+ };
51
+ /**
52
+ * Terminal Dashboard Renderer
53
+ *
54
+ * Renders orchestration dashboard data to terminal using ANSI colours and ASCII tables.
55
+ *
56
+ * @example
57
+ * const renderer = new TerminalDashboardRenderer();
58
+ * const data = await metricsCollector.collect();
59
+ * renderer.render(data);
60
+ */
61
+ export class TerminalDashboardRenderer {
62
+ /**
63
+ * Render the complete dashboard with all 5 sections.
64
+ *
65
+ * Sections:
66
+ * 1. Global Status - High-level metrics
67
+ * 2. Agent Small Multiples - Per-agent comparison table
68
+ * 3. WU Progress - DoD progress bars with headlines
69
+ * 4. Timeline - Recent events
70
+ * 5. Alerts - Items requiring attention
71
+ *
72
+ * @param data - Complete dashboard data
73
+ */
74
+ render(data) {
75
+ this.clear();
76
+ console.log(picocolors.bold(picocolors.cyan('\n🎯 Agent Orchestration Dashboard\n')));
77
+ // Section 1: Global Status
78
+ this.renderGlobalStatus(data.globalStatus);
79
+ // Section 2: Agent Small Multiples
80
+ this.renderAgentMetrics(data.agentMetrics);
81
+ // Section 3: WU Progress
82
+ this.renderWUProgress(data.wuProgress);
83
+ // Section 4: Timeline
84
+ this.renderTimeline(data.timeline);
85
+ // Section 5: Alerts
86
+ this.renderAlerts(data.alerts);
87
+ console.log('\n');
88
+ }
89
+ /**
90
+ * Render prioritised suggestions.
91
+ *
92
+ * @param suggestions - Ordered suggestions (highest priority first)
93
+ */
94
+ renderSuggestions(suggestions) {
95
+ console.log(SECTION_SEPARATOR);
96
+ console.log(picocolors.bold(`${HEADER_PREFIX} Suggestions\n`));
97
+ if (suggestions.length === 0) {
98
+ console.log(picocolors.gray('No suggestions at this time.\n'));
99
+ return;
100
+ }
101
+ for (const suggestion of suggestions) {
102
+ const priorityColour = SEVERITY_COLOURS[suggestion.priority];
103
+ const priorityLabel = suggestion.priority.toUpperCase().padEnd(6);
104
+ console.log(`${BULLET} ${priorityColour(priorityLabel)} ${picocolors.bold(suggestion.action)}`);
105
+ console.log(` ${picocolors.gray('Reason:')} ${suggestion.reason}`);
106
+ console.log(` ${picocolors.gray('Command:')} ${picocolors.cyan(suggestion.command)}\n`);
107
+ }
108
+ }
109
+ /**
110
+ * Render execution plan and prompt for user approval.
111
+ *
112
+ * @param plan - Proposed execution plan
113
+ * @returns User's choice (approve/reject/edit)
114
+ */
115
+ async renderPlan(plan) {
116
+ console.log(SECTION_SEPARATOR);
117
+ console.log(picocolors.bold(`${HEADER_PREFIX} Execution Plan\n`));
118
+ console.log(`${picocolors.gray('WU:')} ${picocolors.cyan(plan.wuId)}`);
119
+ console.log(`${picocolors.gray('Estimated Tokens:')} ${picocolors.yellow(plan.estimatedTokens.toString())}\n`);
120
+ console.log(picocolors.bold('Steps:'));
121
+ for (const step of plan.steps) {
122
+ const label = 'agent' in step
123
+ ? `Run agent: ${step.agent}`
124
+ : 'action' in step
125
+ ? `Run: ${step.action}`
126
+ : 'Unknown step';
127
+ const statusIcon = step.status === 'pending' ? PENDING_MARK : CHECK_MARK;
128
+ console.log(` ${statusIcon} ${label}`);
129
+ }
130
+ console.log('');
131
+ // Prompt user (mocked in tests via promptUser)
132
+ return this.promptUser();
133
+ }
134
+ /**
135
+ * Clear terminal output.
136
+ *
137
+ * Uses ANSI escape sequence to clear screen.
138
+ */
139
+ clear() {
140
+ // ANSI escape sequence: clear screen and move cursor to top-left
141
+ console.log('\x1Bc');
142
+ }
143
+ /**
144
+ * Render global status section.
145
+ *
146
+ * @private
147
+ */
148
+ renderGlobalStatus(status) {
149
+ console.log(SECTION_SEPARATOR);
150
+ console.log(picocolors.bold(`${HEADER_PREFIX} Global Status\n`));
151
+ console.log(`${picocolors.gray('Active WUs:')} ${picocolors.cyan(status.activeWUs.toString())}`);
152
+ console.log(`${picocolors.gray('Completed (24h):')} ${picocolors.green(status.completed24h.toString())}`);
153
+ console.log(`${picocolors.gray('Blocked:')} ${status.blocked > 0 ? picocolors.yellow(status.blocked.toString()) : picocolors.gray(status.blocked.toString())}`);
154
+ console.log(`${picocolors.gray('Gates Failing:')} ${status.gatesFailing > 0 ? picocolors.red(status.gatesFailing.toString()) : picocolors.gray(status.gatesFailing.toString())}`);
155
+ if (status.longestRunning) {
156
+ const durationHours = Math.floor(status.longestRunning.durationMs / (1000 * 60 * 60));
157
+ const durationMinutes = Math.floor((status.longestRunning.durationMs % (1000 * 60 * 60)) / (1000 * 60));
158
+ console.log(`${picocolors.gray('Longest Running:')} ${picocolors.cyan(status.longestRunning.wuId)} ${picocolors.gray(`(${durationHours}h ${durationMinutes}m)`)}`);
159
+ }
160
+ if (status.pendingMandatory.length > 0) {
161
+ console.log(`\n${picocolors.yellow(BULLET)} ${picocolors.bold('Pending Mandatory Agents:')}`);
162
+ for (const pending of status.pendingMandatory) {
163
+ console.log(` ${picocolors.gray('-')} ${picocolors.cyan(pending.wuId)}: ${pending.agent}`);
164
+ }
165
+ }
166
+ // WU-1438: Display active agent session
167
+ if (status.activeSession) {
168
+ const session = status.activeSession;
169
+ const startTime = new Date(session.started);
170
+ const durationMs = Date.now() - startTime.getTime();
171
+ const durationMinutes = Math.floor(durationMs / (1000 * 60));
172
+ const durationSeconds = Math.floor((durationMs % (1000 * 60)) / 1000);
173
+ console.log(`\n${picocolors.green(BULLET)} ${picocolors.bold('Active Agent Session:')}`);
174
+ console.log(` ${picocolors.gray('Session ID:')} ${picocolors.cyan(session.sessionId.slice(0, 8))}...`);
175
+ console.log(` ${picocolors.gray('WU:')} ${picocolors.cyan(session.wuId)}`);
176
+ console.log(` ${picocolors.gray('Context Tier:')} ${session.contextTier}`);
177
+ console.log(` ${picocolors.gray('Duration:')} ${durationMinutes}m ${durationSeconds}s`);
178
+ console.log(` ${picocolors.gray('Incidents Logged:')} ${session.incidentsLogged}`);
179
+ }
180
+ else {
181
+ console.log(`\n${picocolors.gray(BULLET)} ${picocolors.gray('No active agent session')}`);
182
+ }
183
+ // WU-1748: Display worktrees with uncommitted changes
184
+ if (status.worktreesWithUncommittedChanges.length > 0) {
185
+ console.log(`\n${picocolors.yellow(BULLET)} ${picocolors.bold('Worktrees with Uncommitted Changes:')}`);
186
+ for (const wt of status.worktreesWithUncommittedChanges) {
187
+ const lastActivity = wt.lastActivityTimestamp
188
+ ? new Date(wt.lastActivityTimestamp).toLocaleString('en-GB')
189
+ : 'Unknown';
190
+ console.log(` ${picocolors.gray('-')} ${picocolors.cyan(wt.wuId)}: ${picocolors.yellow(wt.uncommittedFileCount.toString())} uncommitted files`);
191
+ console.log(` ${picocolors.gray('Last activity:')} ${lastActivity}`);
192
+ console.log(` ${picocolors.gray('Path:')} ${wt.worktreePath}`);
193
+ }
194
+ }
195
+ console.log('');
196
+ }
197
+ /**
198
+ * Render agent metrics as small multiples table.
199
+ *
200
+ * @private
201
+ */
202
+ renderAgentMetrics(metrics) {
203
+ console.log(SECTION_SEPARATOR);
204
+ console.log(picocolors.bold(`${HEADER_PREFIX} Agent Metrics\n`));
205
+ if (Object.keys(metrics).length === 0) {
206
+ console.log(picocolors.gray('No agent metrics available.\n'));
207
+ return;
208
+ }
209
+ const table = new Table({
210
+ head: ['Agent', 'Invoked', 'Pass Rate', 'Avg Duration', 'Last Run'],
211
+ style: {
212
+ head: ['cyan'],
213
+ border: ['gray'],
214
+ },
215
+ });
216
+ for (const [agentName, metric] of Object.entries(metrics)) {
217
+ const passRateColour = metric.passRate >= 90
218
+ ? picocolors.green
219
+ : metric.passRate >= 50
220
+ ? picocolors.yellow
221
+ : picocolors.red;
222
+ const avgDurationMs = metric.avgDurationMs;
223
+ const avgDurationMinutes = Math.floor(avgDurationMs / (1000 * 60));
224
+ const avgDurationSeconds = Math.floor((avgDurationMs % (1000 * 60)) / 1000);
225
+ const lastRunResult = metric.lastRun
226
+ ? RESULT_COLOURS[metric.lastRun.result](metric.lastRun.result)
227
+ : picocolors.gray('N/A');
228
+ table.push([
229
+ agentName,
230
+ metric.invoked.toString(),
231
+ passRateColour(`${metric.passRate}%`),
232
+ `${avgDurationMinutes}m ${avgDurationSeconds}s`,
233
+ lastRunResult,
234
+ ]);
235
+ }
236
+ console.log(table.toString());
237
+ console.log('');
238
+ }
239
+ /**
240
+ * Render WU progress with DoD bars and headlines.
241
+ *
242
+ * @private
243
+ */
244
+ renderWUProgress(progress) {
245
+ console.log(SECTION_SEPARATOR);
246
+ console.log(picocolors.bold(`${HEADER_PREFIX} WU Progress\n`));
247
+ if (progress.length === 0) {
248
+ console.log(picocolors.gray('No active WUs.\n'));
249
+ return;
250
+ }
251
+ for (const wu of progress) {
252
+ // WU header
253
+ console.log(`${picocolors.bold(picocolors.cyan(wu.wuId))} ${picocolors.gray('-')} ${wu.title}`);
254
+ console.log(`${picocolors.gray('Lane:')} ${wu.lane}`);
255
+ // DoD progress bar
256
+ const percentage = (wu.dodProgress / wu.dodTotal) * 100;
257
+ const filledWidth = Math.floor((percentage / 100) * PROGRESS_BAR_WIDTH);
258
+ const emptyWidth = PROGRESS_BAR_WIDTH - filledWidth;
259
+ const progressBar = picocolors.green('█'.repeat(filledWidth)) + picocolors.gray('░'.repeat(emptyWidth));
260
+ console.log(`${picocolors.gray('DoD:')} [${progressBar}] ${picocolors.cyan(`${wu.dodProgress}/${wu.dodTotal}`)}`);
261
+ // Agent status
262
+ const agentStatuses = Object.entries(wu.agents)
263
+ .map(([agent, status]) => {
264
+ const statusIcon = status === 'pass'
265
+ ? picocolors.green(CHECK_MARK)
266
+ : status === 'fail'
267
+ ? picocolors.red(CROSS_MARK)
268
+ : status === 'skipped'
269
+ ? picocolors.gray('-')
270
+ : picocolors.yellow(PENDING_MARK);
271
+ return `${statusIcon} ${agent}`;
272
+ })
273
+ .join(' ');
274
+ console.log(`${picocolors.gray('Agents:')} ${agentStatuses}`);
275
+ // Headline sentence (Tufte principle)
276
+ console.log(`${picocolors.italic(picocolors.gray(`"${wu.headline}"`))}\n`);
277
+ }
278
+ }
279
+ /**
280
+ * Render timeline of recent events.
281
+ *
282
+ * @private
283
+ */
284
+ renderTimeline(timeline) {
285
+ console.log(SECTION_SEPARATOR);
286
+ console.log(picocolors.bold(`${HEADER_PREFIX} Timeline\n`));
287
+ if (timeline.length === 0) {
288
+ console.log(picocolors.gray('No recent events.\n'));
289
+ return;
290
+ }
291
+ for (const event of timeline) {
292
+ const timestamp = new Date(event.timestamp).toLocaleTimeString('en-GB', {
293
+ hour: '2-digit',
294
+ minute: '2-digit',
295
+ });
296
+ const severityColour = EVENT_SEVERITY_COLOURS[event.severity];
297
+ console.log(`${picocolors.gray(timestamp)} ${severityColour(BULLET)} ${picocolors.cyan(event.wuId)} ${picocolors.gray('-')} ${event.detail}`);
298
+ }
299
+ console.log('');
300
+ }
301
+ /**
302
+ * Render alerts requiring attention.
303
+ *
304
+ * @private
305
+ */
306
+ renderAlerts(alerts) {
307
+ console.log(SECTION_SEPARATOR);
308
+ console.log(picocolors.bold(`${HEADER_PREFIX} Alerts\n`));
309
+ if (alerts.length === 0) {
310
+ console.log(picocolors.green(`${CHECK_MARK} No alerts - all clear.\n`));
311
+ return;
312
+ }
313
+ for (const alert of alerts) {
314
+ const severityColour = SEVERITY_COLOURS[alert.severity];
315
+ const severityLabel = alert.severity.toUpperCase().padEnd(6);
316
+ console.log(`${severityColour(BULLET)} ${severityColour(severityLabel)} ${picocolors.bold(alert.message)}`);
317
+ console.log(` ${picocolors.gray('WU:')} ${picocolors.cyan(alert.wuId)}`);
318
+ console.log(` ${picocolors.gray('Action:')} ${alert.action}\n`);
319
+ }
320
+ }
321
+ /**
322
+ * Prompt user for execution plan approval.
323
+ *
324
+ * This is a simplified implementation for testing.
325
+ * Production version would use @inquirer/prompts for interactive input.
326
+ *
327
+ * @private
328
+ */
329
+ async promptUser() {
330
+ // Mock implementation for testing
331
+ // Production: use @inquirer/prompts select + input
332
+ return {
333
+ choice: 'approve',
334
+ modifications: undefined,
335
+ };
336
+ }
337
+ }
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Predefined option configurations for WU management scripts.
3
+ * Each option has: name, flags, description, and optional default.
4
+ *
5
+ * Commander auto-converts kebab-case flags to camelCase in opts().
6
+ * Example: --branch-only becomes opts().branchOnly
7
+ *
8
+ * NOTE: Commander treats --no-* flags specially (negated booleans).
9
+ * --no-foo creates opts.foo = false (default true).
10
+ * We post-process to convert these to noFoo = true for backward compat.
11
+ */
12
+ /**
13
+ * WU option definition structure
14
+ */
15
+ interface WUOption {
16
+ name: string;
17
+ flags: string;
18
+ description: string;
19
+ default?: string | boolean | string[];
20
+ isNegated?: boolean;
21
+ isRepeatable?: boolean;
22
+ }
23
+ export declare const WU_OPTIONS: Record<string, WUOption>;
24
+ /**
25
+ * Create a commander-based CLI parser for a WU script.
26
+ *
27
+ * @param {object} config - Parser configuration
28
+ * @param {string} config.name - Script name (e.g., 'wu-claim')
29
+ * @param {string} config.description - Script description for help text
30
+ * @param {Array<object>} config.options - Array of option objects from WU_OPTIONS
31
+ * @param {Array<string>} [config.required=[]] - Array of option names that are required
32
+ * @param {boolean} [config.allowPositionalId=false] - Allow first positional arg as WU ID
33
+ * @param {string} [config.version='1.0.0'] - Script version
34
+ * @returns {object} Parsed options object (camelCase keys)
35
+ *
36
+ * @example
37
+ * const opts = createWUParser({
38
+ * name: 'wu-claim',
39
+ * description: 'Claim a work unit for a lane',
40
+ * options: [WU_OPTIONS.id, WU_OPTIONS.lane, WU_OPTIONS.branchOnly],
41
+ * required: ['id', 'lane'],
42
+ * });
43
+ * console.log(opts.id); // 'WU-123'
44
+ * console.log(opts.branchOnly); // true
45
+ */
46
+ export declare function createWUParser(config: any): import("commander").OptionValues;
47
+ /**
48
+ * Backward-compatible unified argument parser for WU management scripts.
49
+ * Uses commander internally but maintains the same return format.
50
+ *
51
+ * @deprecated Use createWUParser() for new scripts to get better help text.
52
+ *
53
+ * @param {string[]} argv - Process arguments (typically process.argv)
54
+ * @returns {object} Parsed arguments object (camelCase keys)
55
+ * @throws {Error} If unknown flag or missing required value
56
+ *
57
+ * @example
58
+ * const args = parseWUArgs(process.argv);
59
+ * console.log(args.id); // 'WU-123'
60
+ * console.log(args.branchOnly); // true
61
+ */
62
+ export declare function parseWUArgs(argv: any): import("commander").OptionValues;
63
+ export {};