@titan-design/react-ui 0.12.1 → 0.14.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 (531) hide show
  1. package/README.md +60 -47
  2. package/dist/bodymap.js +856 -736
  3. package/dist/bodymap.js.map +1 -1
  4. package/dist/bodymap.mjs +858 -738
  5. package/dist/bodymap.mjs.map +1 -1
  6. package/dist/index.d.mts +1431 -237
  7. package/dist/index.d.ts +1431 -237
  8. package/dist/index.js +6506 -4781
  9. package/dist/index.js.map +1 -1
  10. package/dist/index.mjs +6280 -4642
  11. package/dist/index.mjs.map +1 -1
  12. package/dist/{pages-B1hqnGIC.d.ts → pages-CsjsUn0G.d.ts} +51 -16
  13. package/dist/{pages-CvsFqNtx.d.mts → pages-ZbT_pD_U.d.mts} +51 -16
  14. package/dist/pages.d.mts +1 -1
  15. package/dist/pages.d.ts +1 -1
  16. package/dist/pages.js +1919 -1937
  17. package/dist/pages.js.map +1 -1
  18. package/dist/pages.mjs +1927 -1945
  19. package/dist/pages.mjs.map +1 -1
  20. package/dist/theme/index.d.mts +225 -140
  21. package/dist/theme/index.d.ts +225 -140
  22. package/dist/theme/index.js +298 -319
  23. package/dist/theme/index.js.map +1 -1
  24. package/dist/theme/index.mjs +283 -315
  25. package/dist/theme/index.mjs.map +1 -1
  26. package/dist/theme/tokens-css.js +145 -24
  27. package/dist/theme/tokens-css.js.map +1 -1
  28. package/dist/theme/tokens-css.mjs +145 -24
  29. package/dist/theme/tokens-css.mjs.map +1 -1
  30. package/dist/theme/tokens.d.mts +128 -11
  31. package/dist/theme/tokens.d.ts +128 -11
  32. package/dist/theme/tokens.js +126 -26
  33. package/dist/theme/tokens.js.map +1 -1
  34. package/dist/theme/tokens.mjs +124 -27
  35. package/dist/theme/tokens.mjs.map +1 -1
  36. package/docs/audits/2026-09-08-critique-addenda.md +51 -0
  37. package/docs/audits/2026-09-08-library-critique.md +212 -0
  38. package/docs/library-roadmap.md +99 -0
  39. package/docs/render-testing-pattern.md +130 -0
  40. package/package.json +1 -1
  41. package/src/arch/Architecture.stories.tsx +3 -1
  42. package/src/arch/arch-graph.freshness.test.ts +52 -0
  43. package/src/arch/arch-graph.json +4989 -1583
  44. package/src/components/custom/ActiveWork/CoChangeChip.stories.tsx +44 -0
  45. package/src/components/custom/ActiveWork/CoChangeChip.test.tsx +29 -0
  46. package/src/components/custom/ActiveWork/CoChangeChip.tsx +48 -0
  47. package/src/components/custom/ActiveWork/Eyebrow.stories.tsx +25 -0
  48. package/src/components/custom/ActiveWork/Eyebrow.test.tsx +16 -0
  49. package/src/components/custom/ActiveWork/Eyebrow.tsx +26 -0
  50. package/src/components/custom/ActiveWork/FileActivityDetail.stories.tsx +50 -0
  51. package/src/components/custom/ActiveWork/FileActivityDetail.test.tsx +66 -0
  52. package/src/components/custom/ActiveWork/FileActivityDetail.tsx +202 -0
  53. package/src/components/custom/ActiveWork/FileActivityRow.stories.tsx +70 -0
  54. package/src/components/custom/ActiveWork/FileActivityRow.test.tsx +67 -0
  55. package/src/components/custom/ActiveWork/FileActivityRow.tsx +130 -0
  56. package/src/components/custom/ActiveWork/FileHistoryExplorer.stories.tsx +84 -0
  57. package/src/components/custom/ActiveWork/FileHistoryExplorer.test.tsx +99 -0
  58. package/src/components/custom/ActiveWork/FileHistoryExplorer.tsx +138 -0
  59. package/src/components/custom/ActiveWork/FilePathLabel.stories.tsx +39 -0
  60. package/src/components/custom/ActiveWork/FilePathLabel.test.tsx +53 -0
  61. package/src/components/custom/ActiveWork/FilePathLabel.tsx +63 -0
  62. package/src/components/custom/ActiveWork/InitiativeBrief.stories.tsx +50 -0
  63. package/src/components/custom/ActiveWork/InitiativeBrief.test.tsx +62 -0
  64. package/src/components/custom/ActiveWork/InitiativeBrief.tsx +182 -0
  65. package/src/components/custom/ActiveWork/InitiativeCard.stories.tsx +73 -0
  66. package/src/components/custom/ActiveWork/InitiativeCard.test.tsx +68 -0
  67. package/src/components/custom/ActiveWork/InitiativeCard.tsx +136 -0
  68. package/src/components/custom/ActiveWork/InitiativeHeader.stories.tsx +59 -0
  69. package/src/components/custom/ActiveWork/InitiativeHeader.test.tsx +40 -0
  70. package/src/components/custom/ActiveWork/InitiativeHeader.tsx +73 -0
  71. package/src/components/custom/ActiveWork/InitiativeReader.stories.tsx +145 -0
  72. package/src/components/custom/ActiveWork/OpenLoops.stories.tsx +58 -0
  73. package/src/components/custom/ActiveWork/OpenLoops.test.tsx +61 -0
  74. package/src/components/custom/ActiveWork/OpenLoops.tsx +107 -0
  75. package/src/components/custom/ActiveWork/PortfolioOverview.stories.tsx +101 -0
  76. package/src/components/custom/ActiveWork/PortfolioOverview.test.tsx +81 -0
  77. package/src/components/custom/ActiveWork/PortfolioOverview.tsx +83 -0
  78. package/src/components/custom/ActiveWork/README.md +305 -0
  79. package/src/components/custom/ActiveWork/SessionDetail.stories.tsx +71 -0
  80. package/src/components/custom/ActiveWork/SessionDetail.test.tsx +84 -0
  81. package/src/components/custom/ActiveWork/SessionDetail.tsx +180 -0
  82. package/src/components/custom/ActiveWork/SessionList.stories.tsx +69 -0
  83. package/src/components/custom/ActiveWork/SessionList.test.tsx +78 -0
  84. package/src/components/custom/ActiveWork/SessionList.tsx +103 -0
  85. package/src/components/custom/ActiveWork/SessionListItem.stories.tsx +64 -0
  86. package/src/components/custom/ActiveWork/SessionListItem.test.tsx +62 -0
  87. package/src/components/custom/ActiveWork/SessionListItem.tsx +152 -0
  88. package/src/components/custom/ActiveWork/SessionReader.stories.tsx +113 -0
  89. package/src/components/custom/ActiveWork/SeverityLabel.stories.tsx +51 -0
  90. package/src/components/custom/ActiveWork/SeverityLabel.test.tsx +68 -0
  91. package/src/components/custom/ActiveWork/SeverityLabel.tsx +97 -0
  92. package/src/components/custom/ActiveWork/TaskRow.stories.tsx +63 -0
  93. package/src/components/custom/ActiveWork/TaskRow.test.tsx +112 -0
  94. package/src/components/custom/ActiveWork/TaskRow.tsx +176 -0
  95. package/src/components/custom/ActiveWork/TaskTable.stories.tsx +123 -0
  96. package/src/components/custom/ActiveWork/TaskTable.test.tsx +233 -0
  97. package/src/components/custom/ActiveWork/TaskTable.tsx +321 -0
  98. package/src/components/custom/ActiveWork/active-work-depth.test.tsx +102 -0
  99. package/src/components/custom/ActiveWork/file-history-fixture.ts +91 -0
  100. package/src/components/custom/ActiveWork/format-time.test.ts +23 -0
  101. package/src/components/custom/ActiveWork/format-time.ts +32 -0
  102. package/src/components/custom/ActiveWork/index.ts +19 -0
  103. package/src/components/custom/ActiveWork/initiative-fixture.ts +104 -0
  104. package/src/components/custom/ActiveWork/session-fixture.ts +267 -0
  105. package/src/components/custom/ActiveWork/session-linkers.ts +56 -0
  106. package/src/components/custom/ActiveWork/task-list-fixture.ts +97 -0
  107. package/src/components/custom/CircularTimer/CircularTimer.stories.tsx +12 -6
  108. package/src/components/custom/DateTime/DateTime.stories.tsx +2 -1
  109. package/src/components/custom/DateTime/DateTime.test.tsx +3 -1
  110. package/src/components/custom/EmptyState/EmptyState.stories.tsx +22 -9
  111. package/src/components/custom/EmptyState/EmptyState.test.tsx +7 -13
  112. package/src/components/custom/EmptyState/EmptyState.tsx +4 -18
  113. package/src/components/custom/Fatigue/DualGhostSpark.stories.tsx +4 -3
  114. package/src/components/custom/Fatigue/FatigueLights.stories.tsx +2 -2
  115. package/src/components/custom/Fatigue/GhostSpark.stories.tsx +4 -3
  116. package/src/components/custom/Fatigue/LiveFatigueCard.stories.tsx +2 -2
  117. package/src/components/custom/Fatigue/LiveFatigueCard.tsx +8 -4
  118. package/src/components/custom/Fatigue/LiveFatiguePanel.stories.tsx +116 -6
  119. package/src/components/custom/Fatigue/LiveFatiguePanel.test.tsx +134 -0
  120. package/src/components/custom/Fatigue/LiveFatiguePanel.tsx +54 -83
  121. package/src/components/custom/Fatigue/README.md +40 -3
  122. package/src/components/custom/Fatigue/RomProgressionChart.stories.tsx +2 -2
  123. package/src/components/custom/Fatigue/SilverRedPalette.stories.tsx +2 -1
  124. package/src/components/custom/Fatigue/VelocityHero.stories.tsx +4 -3
  125. package/src/components/custom/Fatigue/VerdictHero.stories.tsx +2 -2
  126. package/src/components/custom/Fatigue/fatigue-mock.test.ts +0 -5
  127. package/src/components/custom/Fatigue/fatigue-mock.ts +2 -10
  128. package/src/components/custom/Fatigue/fatigue-tokens.ts +12 -0
  129. package/src/components/custom/Fatigue/index.ts +17 -5
  130. package/src/components/custom/Fatigue/panel-layout.test.ts +149 -0
  131. package/src/components/custom/Fatigue/panel-layout.ts +185 -0
  132. package/src/components/custom/Gauge/Gauge.stories.tsx +6 -3
  133. package/src/components/custom/Gauge/Gauge.test.tsx +1 -1
  134. package/src/components/custom/Gauge/Gauge.tsx +7 -2
  135. package/src/components/custom/Metric/Metric.stories.tsx +10 -1
  136. package/src/components/custom/Metric/Metric.test.tsx +1 -3
  137. package/src/components/custom/Metric/Metric.tsx +5 -20
  138. package/src/components/custom/Prose/MarkdownProse.stories.tsx +88 -0
  139. package/src/components/custom/Prose/MarkdownProse.test.tsx +87 -0
  140. package/src/components/custom/Prose/MarkdownProse.tsx +201 -0
  141. package/src/components/custom/Prose/README.md +58 -0
  142. package/src/components/custom/Prose/index.ts +1 -0
  143. package/src/components/custom/Scatter/Scatter.stories.tsx +55 -14
  144. package/src/components/custom/Scatter/Scatter.test.tsx +2 -2
  145. package/src/components/custom/Scatter/Scatter.tsx +122 -18
  146. package/src/components/custom/Sidebar/Sidebar.stories.tsx +41 -8
  147. package/src/components/custom/Sidebar/Sidebar.test.tsx +5 -1
  148. package/src/components/custom/Sidebar/Sidebar.tsx +16 -33
  149. package/src/components/custom/Table/Table.stories.tsx +99 -16
  150. package/src/components/custom/Table/Table.test.tsx +273 -86
  151. package/src/components/custom/Table/Table.tsx +159 -67
  152. package/src/components/custom/Table/column-fit.test.ts +75 -0
  153. package/src/components/custom/Table/column-fit.ts +116 -0
  154. package/src/components/custom/Table/index.ts +9 -0
  155. package/src/components/custom/TimerReadout/TimerReadout.stories.tsx +8 -6
  156. package/src/components/custom/Treemap/Treemap.stories.tsx +15 -12
  157. package/src/components/custom/Treemap/Treemap.test.tsx +1 -1
  158. package/src/components/custom/Treemap/Treemap.tsx +11 -3
  159. package/src/components/custom/Typography/Typography.stories.tsx +28 -1
  160. package/src/components/custom/Typography/Typography.test.tsx +34 -0
  161. package/src/components/custom/Typography/Typography.tsx +6 -0
  162. package/src/components/custom/Typography/index.ts +1 -8
  163. package/src/components/custom/Workout/ActiveWorkoutPage.stories.tsx +11 -2
  164. package/src/components/custom/Workout/BaseBadge.stories.tsx +27 -11
  165. package/src/components/custom/Workout/BaseBadge.test.tsx +31 -11
  166. package/src/components/custom/Workout/BaseBadge.tsx +6 -2
  167. package/src/components/custom/Workout/BodyMap.stories.tsx +4 -1
  168. package/src/components/custom/Workout/BodyMap.tsx +8 -4
  169. package/src/components/custom/Workout/BodyMapDetailPanel.stories.tsx +28 -6
  170. package/src/components/custom/Workout/BodyMapDetailPanel.test.tsx +11 -15
  171. package/src/components/custom/Workout/BodyMapDetailPanel.tsx +50 -12
  172. package/src/components/custom/Workout/CapacityBandChart.stories.tsx +12 -9
  173. package/src/components/custom/Workout/CapacityBandChart.test.tsx +24 -51
  174. package/src/components/custom/Workout/CapacityBandChart.tsx +144 -111
  175. package/src/components/custom/Workout/DeviationBar.stories.tsx +1 -1
  176. package/src/components/custom/Workout/DeviationBar.test.tsx +10 -4
  177. package/src/components/custom/Workout/DeviationBar.tsx +24 -16
  178. package/src/components/custom/Workout/DualVelocityStrip.stories.tsx +183 -0
  179. package/src/components/custom/Workout/DualVelocityStrip.test.tsx +32 -18
  180. package/src/components/custom/Workout/ExerciseCard.stories.tsx +12 -11
  181. package/src/components/custom/Workout/ExerciseCard.test.tsx +52 -22
  182. package/src/components/custom/Workout/ExerciseCard.tsx +99 -183
  183. package/src/components/custom/Workout/ExerciseCardHeading.stories.tsx +95 -12
  184. package/src/components/custom/Workout/ExerciseCardHeading.test.tsx +189 -1
  185. package/src/components/custom/Workout/ExerciseCardHeading.tsx +167 -18
  186. package/src/components/custom/Workout/ExerciseDetailPage.stories.tsx +9 -1
  187. package/src/components/custom/Workout/ExerciseDetailPage.tsx +3 -2
  188. package/src/components/custom/Workout/ExerciseHeading.stories.tsx +8 -8
  189. package/src/components/custom/Workout/ExerciseHeading.tsx +194 -46
  190. package/src/components/custom/Workout/ExerciseIndicator.stories.tsx +12 -9
  191. package/src/components/custom/Workout/ExerciseIndicator.test.tsx +27 -11
  192. package/src/components/custom/Workout/ExerciseIndicator.tsx +14 -15
  193. package/src/components/custom/Workout/FatigueMeter.stories.tsx +5 -5
  194. package/src/components/custom/Workout/InputBar.stories.tsx +4 -5
  195. package/src/components/custom/Workout/InputBar.tsx +4 -2
  196. package/src/components/custom/Workout/IntensityBar.stories.tsx +1 -1
  197. package/src/components/custom/Workout/IntensityBar.test.tsx +5 -1
  198. package/src/components/custom/Workout/IntensityBar.tsx +8 -3
  199. package/src/components/custom/Workout/LiveAuraFrame.stories.tsx +5 -4
  200. package/src/components/custom/Workout/MesoCard.stories.tsx +4 -1
  201. package/src/components/custom/Workout/MesoCard.test.tsx +7 -18
  202. package/src/components/custom/Workout/MesoCard.tsx +14 -10
  203. package/src/components/custom/Workout/MesoProgressBar.stories.tsx +1 -1
  204. package/src/components/custom/Workout/MesoProgressBar.test.tsx +18 -11
  205. package/src/components/custom/Workout/MesoProgressBar.tsx +15 -13
  206. package/src/components/custom/Workout/MesoStatusCard.stories.tsx +2 -1
  207. package/src/components/custom/Workout/MesoStatusCard.test.tsx +14 -44
  208. package/src/components/custom/Workout/MesoStatusCard.tsx +20 -33
  209. package/src/components/custom/Workout/MetricTiles.stories.tsx +3 -2
  210. package/src/components/custom/Workout/MuscleGroupChip.stories.tsx +2 -8
  211. package/src/components/custom/Workout/MuscleGroupChip.test.tsx +23 -31
  212. package/src/components/custom/Workout/MuscleGroupChip.tsx +28 -67
  213. package/src/components/custom/Workout/PlaceholderStrip.stories.tsx +9 -4
  214. package/src/components/custom/Workout/PlaceholderStrip.test.tsx +17 -10
  215. package/src/components/custom/Workout/PlaceholderStrip.tsx +9 -8
  216. package/src/components/custom/Workout/PrBadge.stories.tsx +2 -1
  217. package/src/components/custom/Workout/PrBadge.test.tsx +3 -9
  218. package/src/components/custom/Workout/PrBadge.tsx +13 -17
  219. package/src/components/custom/Workout/PrHistoryModal.stories.tsx +16 -3
  220. package/src/components/custom/Workout/PrHistoryModal.test.tsx +13 -36
  221. package/src/components/custom/Workout/PrHistoryModal.tsx +8 -4
  222. package/src/components/custom/Workout/ProgramPlanningPage.stories.tsx +6 -1
  223. package/src/components/custom/Workout/README.md +68 -17
  224. package/src/components/custom/Workout/ReadinessCheck.stories.tsx +3 -2
  225. package/src/components/custom/Workout/ReadinessCheck.test.tsx +12 -18
  226. package/src/components/custom/Workout/ReadinessCheck.tsx +22 -4
  227. package/src/components/custom/Workout/RestTimer.stories.tsx +16 -4
  228. package/src/components/custom/Workout/RestTimer.tsx +4 -2
  229. package/src/components/custom/Workout/ScheduleTiles.stories.tsx +3 -2
  230. package/src/components/custom/Workout/ScheduleTiles.test.tsx +3 -4
  231. package/src/components/custom/Workout/ScheduleTiles.tsx +4 -7
  232. package/src/components/custom/Workout/SegmentedBar.stories.tsx +21 -17
  233. package/src/components/custom/Workout/SegmentedBar.tsx +10 -5
  234. package/src/components/custom/Workout/SegmentedProgressBar.stories.tsx +5 -5
  235. package/src/components/custom/Workout/SessionHeader.stories.tsx +6 -6
  236. package/src/components/custom/Workout/SessionHeader.tsx +12 -12
  237. package/src/components/custom/Workout/SessionRail.stories.tsx +12 -11
  238. package/src/components/custom/Workout/SessionRail.tsx +7 -9
  239. package/src/components/custom/Workout/SetBar.stories.tsx +10 -6
  240. package/src/components/custom/Workout/SetBar.test.tsx +49 -4
  241. package/src/components/custom/Workout/SetBar.tsx +38 -12
  242. package/src/components/custom/Workout/SetRow.stories.tsx +3 -2
  243. package/src/components/custom/Workout/SetRow.test.tsx +16 -2
  244. package/src/components/custom/Workout/SetRow.tsx +61 -23
  245. package/src/components/custom/Workout/SetStrip.stories.tsx +63 -7
  246. package/src/components/custom/Workout/SetStrip.test.tsx +25 -0
  247. package/src/components/custom/Workout/SetStrip.tsx +24 -4
  248. package/src/components/custom/Workout/SetTableHeader.stories.tsx +6 -6
  249. package/src/components/custom/Workout/SetTableHeader.tsx +9 -12
  250. package/src/components/custom/Workout/SetsRepsLoad.stories.tsx +7 -7
  251. package/src/components/custom/Workout/SetsRepsLoad.tsx +24 -12
  252. package/src/components/custom/Workout/Sparkline.stories.tsx +14 -11
  253. package/src/components/custom/Workout/Sparkline.test.tsx +37 -19
  254. package/src/components/custom/Workout/Sparkline.tsx +14 -18
  255. package/src/components/custom/Workout/StatusDot.stories.tsx +1 -1
  256. package/src/components/custom/Workout/StatusDot.test.tsx +44 -5
  257. package/src/components/custom/Workout/StatusDot.tsx +93 -63
  258. package/src/components/custom/Workout/StatusPill.stories.tsx +1 -1
  259. package/src/components/custom/Workout/StatusPill.test.tsx +6 -15
  260. package/src/components/custom/Workout/StatusPill.tsx +27 -38
  261. package/src/components/custom/Workout/StrengthTrendChart.stories.tsx +11 -4
  262. package/src/components/custom/Workout/StrengthTrendChart.test.tsx +15 -37
  263. package/src/components/custom/Workout/StrengthTrendChart.tsx +39 -36
  264. package/src/components/custom/Workout/SupersetWrapper.stories.tsx +27 -64
  265. package/src/components/custom/Workout/SupersetWrapper.test.tsx +16 -14
  266. package/src/components/custom/Workout/SupersetWrapper.tsx +17 -21
  267. package/src/components/custom/Workout/TempoDisplay.stories.tsx +26 -10
  268. package/src/components/custom/Workout/TempoDisplay.test.tsx +18 -4
  269. package/src/components/custom/Workout/TempoDisplay.tsx +2 -0
  270. package/src/components/custom/Workout/TrainingStatusPage.stories.tsx +9 -1
  271. package/src/components/custom/Workout/VelocityStrip.compact.stories.tsx +4 -1
  272. package/src/components/custom/Workout/VelocityStrip.dual.stories.tsx +10 -6
  273. package/src/components/custom/Workout/VelocityStrip.expanded.stories.tsx +5 -2
  274. package/src/components/custom/Workout/VelocityStrip.hero.stories.tsx +44 -1
  275. package/src/components/custom/Workout/VelocityStrip.stories.tsx +12 -6
  276. package/src/components/custom/Workout/VelocityStrip.test.tsx +48 -6
  277. package/src/components/custom/Workout/VelocityStrip.tsx +26 -14
  278. package/src/components/custom/Workout/VolumeLandmarkBar.stories.tsx +6 -7
  279. package/src/components/custom/Workout/VolumeLandmarkBar.tsx +15 -6
  280. package/src/components/custom/Workout/WeekRow.stories.tsx +4 -1
  281. package/src/components/custom/Workout/WeekRow.test.tsx +18 -15
  282. package/src/components/custom/Workout/WeekRow.tsx +23 -16
  283. package/src/components/custom/Workout/WeightBadge.stories.tsx +2 -1
  284. package/src/components/custom/Workout/WeightBadge.test.tsx +50 -19
  285. package/src/components/custom/Workout/WeightBadge.tsx +28 -27
  286. package/src/components/custom/Workout/WorkoutCard.stories.tsx +6 -1
  287. package/src/components/custom/Workout/WorkoutCard.test.tsx +18 -0
  288. package/src/components/custom/Workout/WorkoutCard.tsx +35 -57
  289. package/src/components/custom/Workout/WorkoutPill.stories.tsx +5 -2
  290. package/src/components/custom/Workout/WorkoutPill.test.tsx +39 -7
  291. package/src/components/custom/Workout/WorkoutPill.tsx +88 -57
  292. package/src/components/custom/Workout/ZoneTrack.stories.tsx +10 -7
  293. package/src/components/custom/Workout/ZoneTrack.tsx +10 -9
  294. package/src/components/custom/Workout/exerciseRowState.ts +29 -0
  295. package/src/components/custom/Workout/index.ts +17 -2
  296. package/src/components/custom/Workout/metricText.stories.tsx +15 -13
  297. package/src/components/custom/Workout/metricText.tsx +8 -2
  298. package/src/components/custom/Workout/setHeadingKit.tsx +219 -36
  299. package/src/components/custom/Workout/velocity-story-kit.tsx +2 -2
  300. package/src/components/custom/charts/README.md +66 -0
  301. package/src/components/custom/charts/SetBarChart.test.tsx +46 -1
  302. package/src/components/custom/charts/SetBarChart.tsx +56 -9
  303. package/src/components/custom/charts/SparkBars.stories.tsx +55 -0
  304. package/src/components/custom/charts/SparkBars.test.tsx +69 -0
  305. package/src/components/custom/charts/SparkBars.tsx +85 -0
  306. package/src/components/custom/charts/flatBarGeometry.test.ts +41 -0
  307. package/src/components/custom/charts/flatBarGeometry.ts +32 -0
  308. package/src/components/custom/charts/index.ts +3 -0
  309. package/src/components/custom/index.ts +3 -0
  310. package/src/components/custom/stepper/Stepper.stories.tsx +13 -10
  311. package/src/components/custom/stepper/Stepper.test.tsx +1 -7
  312. package/src/components/custom/stepper/Stepper.tsx +21 -34
  313. package/src/components/icons/icons.stories.tsx +1 -1
  314. package/src/components/icons/icons.tsx +51 -0
  315. package/src/components/shell/AppShell.stories.tsx +150 -0
  316. package/src/components/shell/AppShell.test.tsx +70 -0
  317. package/src/components/shell/AppShell.tsx +90 -0
  318. package/src/components/shell/BrandLockup.stories.tsx +66 -5
  319. package/src/components/shell/BrandLockup.test.tsx +34 -1
  320. package/src/components/shell/BrandLockup.tsx +27 -11
  321. package/src/components/shell/NavItem.stories.tsx +4 -4
  322. package/src/components/shell/NavItem.test.tsx +17 -0
  323. package/src/components/shell/NavItem.tsx +17 -5
  324. package/src/components/shell/README.md +89 -26
  325. package/src/components/shell/SideNav.stories.tsx +38 -7
  326. package/src/components/shell/SideNav.test.tsx +16 -8
  327. package/src/components/shell/SideNav.tsx +17 -17
  328. package/src/components/shell/TopBar.stories.tsx +44 -19
  329. package/src/components/shell/TopBar.test.tsx +34 -12
  330. package/src/components/shell/TopBar.tsx +61 -40
  331. package/src/components/shell/brands.tsx +66 -0
  332. package/src/components/shell/index.ts +9 -8
  333. package/src/components/shell/{DeviceIndicator.stories.tsx → workout/DeviceIndicator.stories.tsx} +2 -2
  334. package/src/components/shell/{DeviceIndicator.tsx → workout/DeviceIndicator.tsx} +2 -2
  335. package/src/components/shell/{DeviceMenu.stories.tsx → workout/DeviceMenu.stories.tsx} +2 -2
  336. package/src/components/shell/{DeviceMenu.tsx → workout/DeviceMenu.tsx} +3 -3
  337. package/src/components/shell/{DeviceRow.stories.tsx → workout/DeviceRow.stories.tsx} +2 -2
  338. package/src/components/shell/{DeviceRow.tsx → workout/DeviceRow.tsx} +3 -3
  339. package/src/components/shell/{SessionStatePill.stories.tsx → workout/SessionStatePill.stories.tsx} +2 -2
  340. package/src/components/shell/{SessionStatePill.tsx → workout/SessionStatePill.tsx} +5 -3
  341. package/src/components/shell/workout/WorkoutShell.stories.tsx +71 -0
  342. package/src/components/shell/{DashboardShell.test.tsx → workout/WorkoutShell.test.tsx} +19 -8
  343. package/src/components/shell/workout/WorkoutShell.tsx +77 -0
  344. package/src/components/shell/workout/WorkoutTopBar.stories.tsx +58 -0
  345. package/src/components/shell/workout/WorkoutTopBar.test.tsx +39 -0
  346. package/src/components/shell/workout/WorkoutTopBar.tsx +52 -0
  347. package/src/components/shell/workout/index.ts +9 -0
  348. package/src/components/shell/workout/workoutNavItems.tsx +16 -0
  349. package/src/components/ui/README.md +110 -0
  350. package/src/components/ui/alert/Alert.stories.tsx +15 -5
  351. package/src/components/ui/alert/Alert.tsx +24 -3
  352. package/src/components/ui/autocomplete/Autocomplete.stories.tsx +11 -13
  353. package/src/components/ui/autocomplete/Autocomplete.test.tsx +7 -25
  354. package/src/components/ui/autocomplete/Autocomplete.tsx +21 -28
  355. package/src/components/ui/avatar/Avatar.stories.tsx +1 -1
  356. package/src/components/ui/avatar/Avatar.tsx +2 -10
  357. package/src/components/ui/badge/Badge.stories.tsx +83 -28
  358. package/src/components/ui/badge/Badge.test.tsx +19 -3
  359. package/src/components/ui/badge/Badge.tsx +48 -55
  360. package/src/components/ui/breadcrumbs/Breadcrumbs.stories.tsx +1 -1
  361. package/src/components/ui/breadcrumbs/Breadcrumbs.tsx +4 -16
  362. package/src/components/ui/button/Button.stories.tsx +46 -12
  363. package/src/components/ui/button/Button.tsx +44 -37
  364. package/src/components/ui/card/Card.stories.tsx +90 -94
  365. package/src/components/ui/card/Card.test.tsx +80 -6
  366. package/src/components/ui/card/Card.tsx +150 -203
  367. package/src/components/ui/checkbox/Checkbox.stories.tsx +1 -1
  368. package/src/components/ui/checkbox/Checkbox.tsx +7 -27
  369. package/src/components/ui/chip/Chip.stories.tsx +37 -13
  370. package/src/components/ui/chip/Chip.test.tsx +10 -6
  371. package/src/components/ui/chip/Chip.tsx +76 -91
  372. package/src/components/ui/collapse/Collapse.stories.tsx +23 -23
  373. package/src/components/ui/collapse/Collapse.tsx +6 -11
  374. package/src/components/ui/data-row/DataRow.stories.tsx +14 -3
  375. package/src/components/ui/data-row/DataRow.test.tsx +5 -15
  376. package/src/components/ui/data-row/DataRow.tsx +18 -7
  377. package/src/components/ui/divider/Divider.stories.tsx +1 -1
  378. package/src/components/ui/divider/Divider.tsx +1 -5
  379. package/src/components/ui/drawer/Drawer.stories.tsx +5 -16
  380. package/src/components/ui/drawer/Drawer.tsx +13 -27
  381. package/src/components/ui/floating-overlay-depth.test.tsx +143 -0
  382. package/src/components/ui/form-field/FormField.stories.tsx +6 -20
  383. package/src/components/ui/form-field/FormField.test.tsx +1 -5
  384. package/src/components/ui/form-field/FormField.tsx +10 -46
  385. package/src/components/ui/help-tip/HelpTip.stories.tsx +8 -19
  386. package/src/components/ui/help-tip/HelpTip.test.tsx +1 -3
  387. package/src/components/ui/help-tip/HelpTip.tsx +21 -22
  388. package/src/components/ui/help-tip/index.ts +7 -1
  389. package/src/components/ui/icon-box/IconBox.stories.tsx +1 -1
  390. package/src/components/ui/icon-box/IconBox.test.tsx +1 -7
  391. package/src/components/ui/icon-box/IconBox.tsx +10 -18
  392. package/src/components/ui/indicator/Indicator.stories.tsx +5 -4
  393. package/src/components/ui/indicator/Indicator.tsx +20 -14
  394. package/src/components/ui/input/Input.stories.tsx +3 -11
  395. package/src/components/ui/input/Input.test.tsx +2 -10
  396. package/src/components/ui/input/Input.tsx +10 -25
  397. package/src/components/ui/input/index.ts +7 -1
  398. package/src/components/ui/link/Link.stories.tsx +19 -7
  399. package/src/components/ui/list-item/ListItem.stories.tsx +17 -5
  400. package/src/components/ui/list-item/ListItem.tsx +2 -9
  401. package/src/components/ui/menu/Menu.stories.tsx +21 -15
  402. package/src/components/ui/menu/Menu.test.tsx +2 -11
  403. package/src/components/ui/menu/Menu.tsx +12 -14
  404. package/src/components/ui/menu/index.ts +8 -1
  405. package/src/components/ui/modal/Modal.stories.tsx +2 -2
  406. package/src/components/ui/modal/Modal.tsx +31 -19
  407. package/src/components/ui/pill/Pill.stories.tsx +111 -23
  408. package/src/components/ui/pill/Pill.test.tsx +101 -3
  409. package/src/components/ui/pill/Pill.tsx +168 -49
  410. package/src/components/ui/pill/index.ts +1 -1
  411. package/src/components/ui/popover/Popover.stories.tsx +6 -8
  412. package/src/components/ui/popover/Popover.test.tsx +1 -6
  413. package/src/components/ui/popover/Popover.tsx +20 -15
  414. package/src/components/ui/popover/index.ts +7 -1
  415. package/src/components/ui/progress/Progress.stories.tsx +3 -12
  416. package/src/components/ui/progress/Progress.test.tsx +1 -5
  417. package/src/components/ui/progress/Progress.tsx +9 -6
  418. package/src/components/ui/radio/Radio.stories.tsx +42 -21
  419. package/src/components/ui/radio/Radio.test.tsx +6 -2
  420. package/src/components/ui/radio/Radio.tsx +23 -22
  421. package/src/components/ui/section/Section.stories.tsx +12 -21
  422. package/src/components/ui/section/Section.test.tsx +1 -6
  423. package/src/components/ui/section/Section.tsx +1 -3
  424. package/src/components/ui/section/index.ts +1 -5
  425. package/src/components/ui/select/Select.stories.tsx +3 -13
  426. package/src/components/ui/select/Select.test.tsx +2 -11
  427. package/src/components/ui/select/Select.tsx +16 -15
  428. package/src/components/ui/skeleton/Skeleton.stories.tsx +3 -11
  429. package/src/components/ui/skeleton/Skeleton.tsx +3 -14
  430. package/src/components/ui/skeleton/index.ts +1 -7
  431. package/src/components/ui/spinner/Spinner.stories.tsx +1 -1
  432. package/src/components/ui/spinner/Spinner.tsx +4 -5
  433. package/src/components/ui/stack/Stack.stories.tsx +8 -8
  434. package/src/components/ui/stack/Stack.tsx +1 -1
  435. package/src/components/ui/surface/Surface.stories.tsx +92 -33
  436. package/src/components/ui/surface/Surface.test.tsx +88 -28
  437. package/src/components/ui/surface/Surface.tsx +37 -87
  438. package/src/components/ui/surface/SurfaceContext.ts +22 -62
  439. package/src/components/ui/surface/index.ts +8 -0
  440. package/src/components/ui/surface/resolveSurface.ts +98 -0
  441. package/src/components/ui/surface/surface.contract.test.ts +6 -1
  442. package/src/components/ui/switch/Switch.stories.tsx +1 -1
  443. package/src/components/ui/switch/Switch.tsx +7 -6
  444. package/src/components/ui/tabs/Tabs.stories.tsx +1 -1
  445. package/src/components/ui/tabs/Tabs.tsx +8 -21
  446. package/src/components/ui/tabs/index.ts +1 -7
  447. package/src/components/ui/tile/Tile.stories.tsx +1 -1
  448. package/src/components/ui/tile/Tile.tsx +3 -0
  449. package/src/components/ui/toast/Toast.stories.tsx +1 -1
  450. package/src/components/ui/toast/Toast.test.tsx +2 -8
  451. package/src/components/ui/toast/Toast.tsx +49 -57
  452. package/src/components/ui/toast/index.ts +0 -1
  453. package/src/components/ui/toolbar-button/ToolbarButton.stories.tsx +92 -71
  454. package/src/components/ui/toolbar-button/ToolbarButton.test.tsx +3 -18
  455. package/src/components/ui/toolbar-button/ToolbarButton.tsx +38 -49
  456. package/src/components/ui/tooltip/Tooltip.stories.tsx +12 -3
  457. package/src/components/ui/tooltip/Tooltip.test.tsx +21 -3
  458. package/src/components/ui/tooltip/Tooltip.tsx +55 -36
  459. package/src/components/ui/tooltip/index.ts +1 -1
  460. package/src/components/ui/trigger/TriggerSurface.test.tsx +215 -0
  461. package/src/components/ui/trigger/TriggerSurface.tsx +81 -0
  462. package/src/components/ui/trigger/index.ts +2 -0
  463. package/src/stories/PresetShowcase.stories.tsx +101 -48
  464. package/src/test/no-device-internals.test.ts +3 -3
  465. package/src/test/no-raw-color.test.ts +39 -0
  466. package/src/theme/Alpha.stories.tsx +103 -0
  467. package/src/theme/ChoosingTokens.stories.tsx +48 -0
  468. package/src/theme/ColorPalettes.stories.tsx +62 -45
  469. package/src/theme/ColorPrimitives.stories.tsx +35 -35
  470. package/src/theme/Depth.stories.tsx +132 -65
  471. package/src/theme/DepthCalibration.stories.tsx +23 -21
  472. package/src/theme/ProposedTokensVW82.stories.tsx +414 -0
  473. package/src/theme/ThemeProvider.test.tsx +4 -4
  474. package/src/theme/barrel.ts +7 -6
  475. package/src/theme/color-stories.coverage.test.ts +1 -1
  476. package/src/theme/color-utils.ts +41 -29
  477. package/src/theme/config.completeness.test.ts +1 -1
  478. package/src/theme/config.ts +40 -0
  479. package/src/theme/elevation.test.ts +82 -56
  480. package/src/theme/elevation.ts +77 -561
  481. package/src/theme/global.css +45 -5
  482. package/src/theme/grey-ramp.test.ts +24 -8
  483. package/src/theme/lift.test.ts +39 -0
  484. package/src/theme/lift.ts +102 -0
  485. package/src/theme/materials.test.ts +5 -2
  486. package/src/theme/materials.ts +38 -4
  487. package/src/theme/native-theming-guard.test.ts +5 -5
  488. package/src/theme/presets/apply.ts +4 -0
  489. package/src/theme/presets/audiobook.ts +5 -2
  490. package/src/theme/presets/default.ts +4 -0
  491. package/src/theme/presets/index.ts +14 -1
  492. package/src/theme/presets/types.ts +1 -1
  493. package/src/theme/semantic-contrast.test.ts +13 -4
  494. package/src/theme/status-distinctness.test.ts +66 -0
  495. package/src/theme/subtle-tone-weight.test.ts +163 -0
  496. package/src/theme/surface-planes.test.ts +37 -0
  497. package/src/theme/surface-planes.ts +68 -0
  498. package/src/theme/tailwind-var-opacity.test.ts +163 -0
  499. package/src/theme/token-export-guard.test.ts +1 -3
  500. package/src/theme/tokens/primitives.test.ts +15 -7
  501. package/src/theme/tokens/primitives.ts +98 -33
  502. package/src/theme/tokens/semantic-hex-guard.test.ts +322 -0
  503. package/src/theme/tokens/semantic.ts +124 -54
  504. package/src/theme/wash-ladder.test.ts +58 -0
  505. package/src/theme/workout-tokens.ts +1 -7
  506. package/src/types/jest-axe.d.ts +2 -6
  507. package/src/types/raw-md.d.ts +5 -0
  508. package/src/utils/colors.alpha-adoption.test.ts +408 -0
  509. package/src/utils/colors.ts +4 -4
  510. package/src/utils/form.ts +1 -3
  511. package/src/utils/index.ts +2 -7
  512. package/src/utils/number-format.ts +17 -0
  513. package/src/utils/workout-format.ts +15 -6
  514. package/src/web-jsx/jsx-runtime.ts +1 -5
  515. package/tailwind.config.js +55 -9
  516. package/src/components/custom/Workout/ExerciseCardUnified.stories.tsx +0 -151
  517. package/src/components/custom/Workout/RowInventory.stories.tsx +0 -408
  518. package/src/components/custom/Workout/S3FullRail.stories.tsx +0 -46
  519. package/src/components/custom/Workout/S3SessionPace.stories.tsx +0 -95
  520. package/src/components/custom/Workout/S3SessionRailHeading.stories.tsx +0 -61
  521. package/src/components/custom/Workout/S3SetTypes.stories.tsx +0 -176
  522. package/src/components/custom/Workout/S3WorkoutExpansion.stories.tsx +0 -240
  523. package/src/components/shell/DashboardShell.stories.tsx +0 -65
  524. package/src/components/shell/DashboardShell.tsx +0 -75
  525. package/src/components/shell/SessionRailSpecimen.stories.tsx +0 -753
  526. package/src/theme/elevation.stories.tsx +0 -346
  527. package/src/utils/useTheme.ts +0 -72
  528. /package/src/components/shell/{DeviceIndicator.test.tsx → workout/DeviceIndicator.test.tsx} +0 -0
  529. /package/src/components/shell/{DeviceMenu.test.tsx → workout/DeviceMenu.test.tsx} +0 -0
  530. /package/src/components/shell/{DeviceRow.test.tsx → workout/DeviceRow.test.tsx} +0 -0
  531. /package/src/components/shell/{SessionStatePill.test.tsx → workout/SessionStatePill.test.tsx} +0 -0
@@ -0,0 +1,104 @@
1
+ import type { InitiativeBriefData } from './InitiativeBrief'
2
+ import type { OpenLoop } from './OpenLoops'
3
+ import type { TaskListItem } from './TaskRow'
4
+ /**
5
+ * Real initiative state for the reader stories and tests, with fixed values
6
+ * (no `Date.now()`) so visual baselines stay deterministic; pair it with
7
+ * {@link INITIATIVE_NOW}. The brief is this initiative's own v0.1 brief, the
8
+ * open loops are the five it carried into 2026-09-03, and the tasks are the
9
+ * open ones at the time of the export.
10
+ */
11
+ export const INITIATIVE_BRIEF_FIXTURE: InitiativeBriefData = {
12
+ slug: 'active-work',
13
+ title: 'active-work \u2014 durable workspace state',
14
+ state: 'focused',
15
+ rank: 1,
16
+ shipTarget: '2026-Q3',
17
+ updated: '2026-07-12',
18
+ body: "# active-work — durable workspace state\n\n## Why this exists\n\nEngineering work spans days; Claude Code sessions don't. Every handoff between sessions, machines, or agents loses context unless something durable holds it. `active-work` is that something — plain files per initiative (brief, handoff, tasks, sessions, artifacts) under `$XDG_DATA_HOME/active-work/<slug>/`, exposed through a CLI (`aw`), an MCP server, an HTTP daemon, and a Claude skill so any surface reads or writes the same source of truth.\n\n## v0.1 architecture (what shipped this session)\n\n- **Single npm package** `@hjewkes/active-work` (scoped, public, MIT)\n- **Shared zod-typed command registry** — CLI dispatcher (commander), MCP server (`@modelcontextprotocol/sdk`), and HTTP daemon (hono) all consume the same `src/registry/` module\n- **36 commands** across lifecycle / focus-pause / tasks / sessions / sources / artifacts / discover / open / edit / lint / mcp lifecycle / setup / uninstall\n- **Long-running daemon** (`aw mcp serve`) — REST `/rpc/:name`, MCP-over-HTTP `/mcp`, `/health`, `/version`, single-file React dashboard at `/ui` (203KB gzip 64KB), bound to `127.0.0.1:7400`\n- **Skill auto-installed** to `~/.claude/skills/active-work/` via `scripts/postinstall.js`\n- **Schemas** for brief / task / session / artifacts validated on every write; `coerceDates` at the gray-matter and yaml-io seams normalizes YAML 1.2 timestamp coercion\n\n## Major decisions made this session\n\n- **Drop INDEX.md** — picker enumerates `<activeRoot>/*/brief.md` directly; `aw list` formats on demand\n- **Split the old monolithic handoff** into brief.md (frontmatter + slow prose), handoff.md (current-state prose), tasks/*.yml (per-file structured), sessions/*.md (one per session), artifacts.yml (PRs/branches/stashes)\n- **Drop `kind`, `priority`, `health`, `depends_on`** — state enum collapsed to `focused (with rank) | backburner | paused | done`; severity is per-task; health surfaces via task notes; workstreams are independent\n- **Tasks are per-file YAML** with sequential per-initiative IDs (Jira-style: `AW-1`, `AW-2`)\n- **Sessions are per-file** in `sessions/`; bootstrap reads the most recent canonical\n- **Mixed edit policy** — prose docs editable directly; structured files (tasks, artifacts, brief frontmatter) CLI-only\n- **Discover non-interactive** — emits JSON list; Claude orchestrates triage via `aw fold/drop/track`\n- **Daemon supervision opt-in** — `--detach` for now; launchd plist deferred (AW-2)\n- **Concurrency** — atomic write + flock per-initiative; one Claude session per initiative\n\n## What got cut from v0.1\n\n- WebSocket file-event broadcasts to dashboard (AW-3)\n- launchd plist install/uninstall (AW-2)\n- Linux/Windows support (AW-1 covers Linux)\n- Auto-archive of done tasks (AW-8)\n\n## Stakeholders\n\n- @hjewkes — owner / sole user\n\n## Open questions / risks\n\n\n…",
19
+ }
20
+
21
+ export const INITIATIVE_LOOPS_FIXTURE: OpenLoop[] = [
22
+ {
23
+ ref: '2026-08-28-1244-2026-08-28-loop-verification-and-branch-sweep#n1',
24
+ kind: 'prose',
25
+ text: 'Decide the fate of the 7 independent unmerged titan-design lines of work: feat/TD-velocity-primitives (29 commits, subsumes 7 branches), feat/TD-unified-lab (47, subsumes surface-exploration-stories), lab/active-work-dashboard (10 / 39k lines, worktree-backed), chore/TD-arch-graph-refresh (1), feat/TD-velocity-strip-set-types (1), fix/TD-color-stories-current-system (1, PR #102 closed), agent/TD-07/design-pass (7, PR #135 closed). The 8 contained branches can be deleted losing nothing.',
26
+ sessionFile: '2026-08-28-1244-2026-08-28-loop-verification-and-branch-sweep',
27
+ openedAt: '2026-08-28T13:21:27Z',
28
+ },
29
+ {
30
+ ref: '2026-08-28-1244-2026-08-28-loop-verification-and-branch-sweep#n3',
31
+ kind: 'pr',
32
+ text: 'Four other titan-design PRs sit open and unreviewed: #100 TD-maturity-taxonomy, #101 TD-mobile-candidates, #103 TD-r2-s4s5-candidates, #116 live-wall-empty-states. All MERGEABLE, all REVIEW_REQUIRED.',
33
+ sessionFile: '2026-08-28-1244-2026-08-28-loop-verification-and-branch-sweep',
34
+ openedAt: '2026-08-28T13:21:27Z',
35
+ },
36
+ {
37
+ ref: '2026-08-28-1244-2026-08-28-loop-verification-and-branch-sweep#n4',
38
+ kind: 'task',
39
+ targetRef: 'AW-116',
40
+ text: 'AW-116: artifacts.yml still carries a worktree path that artifact status reports present:false and no CLI command can remove.',
41
+ sessionFile: '2026-08-28-1244-2026-08-28-loop-verification-and-branch-sweep',
42
+ openedAt: '2026-08-28T13:21:27Z',
43
+ },
44
+ {
45
+ ref: '2026-08-29-0850-2026-08-29-aw22-f1-pr157-merge#n1',
46
+ kind: 'task',
47
+ targetRef: 'AW-22',
48
+ text: 'AW-22 needs T2 Task List, M1 Session Reader and M2 Initiative Reader hardened into packages/ui before it can close — F1 and T1 have landed, the other three specimens are still lab-only.',
49
+ sessionFile: '2026-08-29-0850-2026-08-29-aw22-f1-pr157-merge',
50
+ openedAt: '2026-08-29T12:59:33Z',
51
+ },
52
+ {
53
+ ref: '2026-08-29-0850-2026-08-29-aw22-f1-pr157-merge#n2',
54
+ kind: 'task',
55
+ targetRef: 'AW-117',
56
+ text: 'AW-117: titan-design main is 194 files prettier-unclean and its ci.yml Format Check is continue-on-error:true. Sequence the reformat after the unmerged-branch triage, since it will collide with every open branch.',
57
+ sessionFile: '2026-08-29-0850-2026-08-29-aw22-f1-pr157-merge',
58
+ openedAt: '2026-08-29T12:59:33Z',
59
+ },
60
+ ]
61
+
62
+ export const INITIATIVE_TASKS_FIXTURE: TaskListItem[] = [
63
+ {
64
+ slug: 'active-work',
65
+ id: 'AW-6',
66
+ title: 'Linear / Jira / Slack discovery sources',
67
+ priority: 6,
68
+ severity: 'low',
69
+ estimate: 13,
70
+ updated: '2026-05-12',
71
+ },
72
+ {
73
+ slug: 'active-work',
74
+ id: 'AW-7',
75
+ title: 'Read-write dashboard (mark tasks done from /ui, reorder via drag)',
76
+ priority: 7,
77
+ severity: 'low',
78
+ estimate: 8,
79
+ updated: '2026-05-12',
80
+ },
81
+ {
82
+ slug: 'active-work',
83
+ id: 'AW-13',
84
+ title:
85
+ 'First npm publish: trigger release.yml; verify @hjewkes/active-work@0.1.0 installable via npm i -g',
86
+ priority: 13,
87
+ severity: 'high',
88
+ estimate: 1,
89
+ updated: '2026-07-02',
90
+ },
91
+ {
92
+ slug: 'active-work',
93
+ id: 'AW-22',
94
+ title:
95
+ 'Read-only dashboard prototypes (titan specimens): portfolio, task list, session reader, initiative reader, file-history explorer',
96
+ priority: 20,
97
+ severity: 'low',
98
+ estimate: 8,
99
+ updated: '2026-07-12',
100
+ },
101
+ ]
102
+
103
+ /** The reference instant the stories and tests measure ages from (2026-09-03 12:00Z). */
104
+ export const INITIATIVE_NOW = new Date('2026-09-03T12:00:00Z').getTime()
@@ -0,0 +1,267 @@
1
+ import type { SessionSummary } from './SessionListItem'
2
+ import type { TaskListItem } from './TaskRow'
3
+ /**
4
+ * A hand-trimmed slice of real active-work session logs, used by the session
5
+ * reader stories and tests. Fixed values (no `Date.now()`) so visual baselines
6
+ * stay deterministic; pair it with {@link SESSION_NOW}.
7
+ *
8
+ * Five canonical sessions of varied length (six minutes to fifteen hours), plus
9
+ * one synthesized ad-hoc session (second in the list) so the track's other
10
+ * state renders. Ids
11
+ * are the 8-character prefixes the session files use. The bodies are the real
12
+ * markdown, so the auto-linker meets real `AW-nn`, `[[name]]`, `#123`, bold and
13
+ * code spans.
14
+ */
15
+ export const SESSION_FIXTURE: SessionSummary[] = [
16
+ {
17
+ id: '34db5555',
18
+ filename: '2026-07-12-1347-34db5555-1.md',
19
+ started: '2026-07-12T13:47:56Z',
20
+ ended: '2026-07-12T14:52:21Z',
21
+ track: 'canonical',
22
+ title:
23
+ 'Shipped AW-17 + AW-18 + AW-19 + AW-20 — cwd→initiative resolution, worktree registration, mid-session prompt re-seed, and ad-hoc session framing',
24
+ body: "# Shipped AW-17 + AW-18 + AW-19 + AW-20 — cwd→initiative resolution, worktree registration, mid-session prompt re-seed, and ad-hoc session framing\n\nUser redirected from the owner-gated backlog (AW-1 Ubuntu smoke-test, AW-13 npm\npublish) to a new feature: make `aw` / `active-work open` figure out which\ninitiative to bootstrap from the current directory instead of always showing the\npicker. Built, reviewed, fixed, merged (#49). Then closed the follow-up gap it\nexposed (no CLI to register a worktree on an existing initiative) with AW-18\n(#50), and dogfooded it on this initiative. `main` green (535/535), no open PRs.\n\n## What shipped (AW-17, PR #49)\nThe inverse of the existing `resolveCwdHint` (initiative → cwd): now cwd →\ninitiative. With no slug, `open` matches the caller's cwd against every brief's\n`worktrees[*].path` and bootstraps the containing initiative; nested worktrees\nresolve to the deepest match; no match or a cross-initiative tie falls back to\nthe picker.\n\n- `open --cwd <dir>` sets the resolution dir; `--pick` (on both `open` and `aw`)\n forces the picker. Result carries `resolved_from: \"slug\" | \"cwd\"`; `aw` prints\n a dim \"matched current directory\" note.\n\n## Review-driven fixes (2nd commit, before merge)\nAn Explore-agent review of the diff caught four real issues, all fixed:\n1. **`aw --pick` was documented but errored** — the launcher rejects any\n `-`-prefixed arg and `runOpen` never forwarded flags. Launcher now parses\n `--pick` and forwards it.\n2. **Daemon/MCP footgun** — the command read ambient `process.cwd()`, so a no-arg\n MCP `open` would match against the *daemon's* cwd. Moved the cwd source to\n `CommandContext.cwd`, populated only by the CLI dispatcher and `aw` launcher\n (the user's shell cwd). Daemon/http leave it undefined → no-arg reverts to\n picker; MCP callers opt in by passing `cwd`.\n3. **Symlinks** — `process.cwd()` returns the realpath on macOS (`/var` →\n `/private/var`) while briefs store the un-resolved form, so lexical matching\n missed (caught in my own E2E). Now `canonicalize()` (realpath, lexical\n fallback for nonexistent paths) runs on both sides.\n4. **Wrong launch dir** — a cwd-resolved open still used the brief's *default*\n worktree as `cwd_hint`. Now it launches in the matched worktree.\n Also: relative worktree paths are skipped (can't compare to an absolute cwd).\n\nConfirmed sound by the review: deepest-match/tie logic (`canonical.length` depth\nproxy is valid since all matches are ancestors of cwd), `isInside` (no\n`/foo/bar` vs `/foo/barbaz` false positive), `'picker' in result` narrowing.\n\n## Tests / verification\n9 new `open` tests (auto-resolve, ctx-cwd path, nested subdir, symlink, no-match\n+ daemon-no-cwd fallbacks, `--pick`, slug tagging, deepest-match, ambiguous-tie).\nFull suite 531 green. Verified E2E against the built CLI: cwd-through-symlink\nresolves, unrelated cwd → picker, `--pick` → picker.\n\n## AW-18 (PR #50) — `active-work worktree set`\nThe dogfood exposed a real gap: worktrees could only be recorded at creation\n(`new --worktree`) or via `track --worktree` — no way to add one to an existing\ninitiative. New command: `worktree set <slug> <path> [--label <label>]\n[--default]`. First worktree → default automatically; updating a\nalready-default label keeps it default (no silent demote); `--default` promotes\nand clears others. 4 tests, E2E-verified. Registered as `worktreeSet` in the\ncommand index; dotted name → `active-work worktree set` on the CLI.\n\n## Dogfood done\nRegistered this initiative's worktree:\n`active-work worktree set active-work /Users/hjewkes/Documents/projects/active-work`.\nVerified: `active-work open` (no slug) from inside the repo (even a subdir) now\nresolves `slug: active-work, resolved_from: cwd`. So `aw` from anywhere in\n`~/Documents/projects/active-work` auto-opens this initiative. The installed\n`~/.local/bin/active-work` is a symlink to the repo `dist/cli.js`, so a local\n`npm run build` is enough to pick up new commands.\n\n## AW-19 (PR #51) — `active-work prompt` + `/aw-prompt` slash command\nUser asked for a short command to print the startup prompt inside a running\nsession. `open` was unfit (JSON envelope + archive side effect). New:\n- `active-work prompt [slug]` — prints the bootstrap prompt as PLAIN TEXT,\n cwd-resolved, side-effect-free (no archiveStaleTasks). Needed a `cli.ts` tweak:\n a bare-string command result prints raw in human mode (only `prompt` returns a\n string, verified). `--json` wraps it in the envelope.\n- `/aw-prompt` slash command (`claude-commands/aw-prompt.md`, `!`active-work\n prompt $ARGUMENTS`` + `disable-model-invocation`) installs to\n `~/.claude/commands/` via postinstall + `setup` (stepInstallCommand), removed\n by `uninstall` (uninstallCommand). Bundled in package `files`.\n- Refactor: extracted resolveSlug/resolveSlugFromCwd/listInitiativeSlugs from\n open.ts into `src/commands/_open-helpers.ts` so open + prompt share one impl.\n7 tests (incl. side-effect guard). Explore review: sound; fixed the flagged\npostinstall skill-source gate that also blocked command install, commented the\ndeliberate overwrite policy. Dogfood: ran postinstall → `/aw-prompt` live at\n`~/.claude/commands/aw-prompt.md`, skill refreshed. NOTE: a new slash command\nmay need a session reload to appear.\n\nSlash-command spec (for future reference): `.claude/commands/<name>.md` →\n`/<name>`; frontmatter `allowed-tools: Bash(cmd:*)`, `disable-model-invocation`;\n`` !`cmd` `` injects stdout at expansion time.\n\n## AW-20 (PR #52) — `--adhoc` session framing\n\n…",
25
+ },
26
+ {
27
+ id: 'adhoc-9f3c2a10',
28
+ filename: '2026-07-10-1602-9f3c2a10-adhoc-doc-pass.md',
29
+ started: '2026-07-10T16:02:00Z',
30
+ ended: '2026-07-10T16:31:00Z',
31
+ track: 'adhoc',
32
+ title: 'Ad-hoc: README pass while AW-17 was in review',
33
+ body: '# Ad-hoc: README pass while AW-17 was in review\n\nTightened the install section and re-linked [[setup-walkthrough]]. No task moved; AW-17 stays with its reviewer.\n\n- `active-work setup` copy now names the launchd step\n- Dropped a stale reference to #42',
34
+ },
35
+ {
36
+ id: '1c51749e',
37
+ filename: '2026-07-02-0453-1c51749e-1.md',
38
+ started: '2026-07-02T04:53:48Z',
39
+ ended: '2026-07-02T20:09:05Z',
40
+ track: 'canonical',
41
+ title: 'Shipped AW-3 + AW-5, aligned repo config, reworked merge permissions',
42
+ body: '# Shipped AW-3 + AW-5, aligned repo config, reworked merge permissions\n\nA long session: two backlog features merged, plus a chunk of GitHub/harness\nworkflow setup. `main` clean, 521/521 green, no open PRs.\n\n## Features shipped\n- **AW-3 (#47) — live-reload dashboard.** SSE (`GET /events`) over raw WebSockets\n — one-way push, zero new deps, native `EventSource` reconnect (keeps AW-11\'s\n dep trim). Daemon `EventHub` fans `watchTree` (portable manual-recursive\n `fs.watch`, sync initial attach) file events to `/ui`, which refetches within\n ~1s; sidebar live dot. **Bonus fix:** `dashboardDir` assumed a `dist/server/`\n layout `tsup` never emits, so packaged installs had *always* served the "not\n built" placeholder — `/ui` never rendered the real dashboard. Now probes\n bundled/legacy/dev layouts. Verified via integration test + manual prod run.\n- **AW-5 (#48) — `active-work sync`.** Auto-commit dirty tree → `git pull\n --rebase` → `git push`. Guards not-a-repo/no-upstream/detached-HEAD; conflicts\n surface with file list + continue/abort commands, left in place (local work\n committed first). `rebased` derived from HEAD movement, not git wording.\n Verified end-to-end with a bare remote + two clones (commit+push, clean\n rebase-integrate, conflict + `rebase --abort` recovery). Also de-flaked the\n AW-3 file-watch late-created-dir test (fixed sleeps → poll-until-observed; 8\n clean full-suite runs after).\n\nBoth merged via `gh pr merge --squash --admin --delete-branch` (owner authorized;\n#47 was blocked by the auto-mode classifier first, then merged on explicit ask).\n\n## GitHub repo config aligned to `brain`\nBranch protection on `active-work` main now matches the house policy: required\nstrict `check`, no required reviews, admins overridable, no force-push (only diff\nwas a redundant 0-approval review block, removed). Workflow perms were already\nuniform (read / no-PR-creation) across all repos. Saved\n`github-repo-config-standard` memory (template repo: brain).\n\n## Merge permissions + mode rework\n- Root-caused the self-merge block: `permissions.allow` already had `Bash(*)`, so\n the block was the **auto-mode classifier** (`defaultMode: auto`), not the\n permission layer.\n- Owner then chose to **turn auto mode OFF**: `~/.claude/settings.json` now\n `defaultMode: "default"` with a broadened allow list (`Bash(*)`, Edit, Write,\n Read, WebFetch, WebSearch, active-work + brain MCP). Removed the dead\n snake_case `default_mode: bypassPermissions` key.\n- **"Only when green" is now structural** — branch protection\'s required strict\n `check` means a plain `gh pr merge --squash --delete-branch` is rejected unless\n CI is green, independent of mode. `--admin` bypasses it → behavioral restraint\n only (use on explicit request). Tradeoff flagged: with the classifier off,\n `Bash(*)` is fully unguarded.\n- `autoMode.allow` merge rules kept but now only apply in plan mode\n (`useAutoModeDuringPlan` defaults true).\n\n## AW-13 decision\nOwner chose to keep Actions perms at the house default (no auto-PR-creation), so\nthe changesets Version PR won\'t auto-create. Publish path = **local one-time\nbootstrap** (`npm login` → `pnpm build` → `npm publish`), then configure the\nnpmjs.com trusted publisher for future OIDC. Task note + handoff updated.\n\n## State for next session\n- AW-3, AW-5 **done**. main clean, 521 green.\n- Open: AW-13 (owner bootstrap publish), AW-1 (Ubuntu smoke-test — can\'t do on\n macOS), AW-7 (read-write dashboard), AW-6 (external discovery, needs tokens).\n- Reload Claude Code (or `/config`) for the permission-mode change to fully take.',
43
+ },
44
+ {
45
+ id: '151ef7a2',
46
+ filename: '2026-07-01-1833-151ef7a2.md',
47
+ started: '2026-07-01T18:33:01Z',
48
+ ended: '2026-07-02T04:45:35Z',
49
+ track: 'canonical',
50
+ title: 'Backlog blitz — shipped 10 tasks, cleared PR backlog, prepped npm publish',
51
+ body: '# Backlog blitz — shipped 10 tasks, cleared PR backlog, prepped npm publish\n\nA long, high-throughput session: cleared the open-PR backlog, then shipped the\nbulk of the backlog. 13 PRs merged (#34–#46); main is clean, no open PRs or\nstray branches. Tests grew 440 → 498.\n\n## Merged / closed this session\n- **Backlog PRs**: #34 (session.record --body-file) and #35 (channels flag) reviewed + merged.\n- **AW-16** closed — resolved by #34 (reject-both instead of the spec\'s "body-file wins"; deliberate).\n- **AW-15** (#36) — live PR/branch artifact state; dropped stale `prs[]`; v1→v2 migrator logs dropped PRs to `.migrations.log` (does NOT fold into notes — deliberate divergence from done_when, flagged).\n- **AW-1** (#37) — Linux systemd user-unit supervision. Engineering LANDED but task stays OPEN pending Ubuntu 24.04 smoke-test (can\'t run on macOS). CI caught a Linux-only bug: supervision failure was aborting `setup`; fixed to degrade to a non-fatal warning.\n- **AW-9** (#38) — HOME sandbox setupFile + CI sandbox so no test can touch the real home. Key gotcha: under Vitest\'s threads pool a runtime `process.env.HOME` write does NOT reach libuv\'s `os.homedir()`; fixed by overriding `os.homedir()` to read `process.env.HOME` dynamically.\n- **AW-2** (#39) — macOS launchd supervision, mirroring AW-1. Added a `getSupervisor(platform)` dispatcher (systemd | launchd). Smoke-tested end-to-end on this Mac (launchctl loads agent → daemon serves /health → uninstall clean). NOTE: the HOME sandbox does NOT cover the per-user launchd domain, so all launchd tests inject a fake spawn and the setup E2E is pinned to a supervisor-less platform.\n- **AW-4** (#40) — `active-work doctor` health-check (node/active-root/daemon/mcp-registration/skill/supervision). Smoke test caught a false "not registered" — the check now accepts both `@hjewkes/active-work` and `active-work` mcpServers keys.\n- **AW-11** (#41) — trimmed runtime deps 23 → 13 (moved react/react-dom/react-native-web to devDeps; removed @titan-design/react-ui, lucide-react, mustache, uuid, chokidar, @commander-js/extra-typings, zod-to-json-schema). Verified via `--omit=dev` tarball install.\n- **AW-14** (#43) — `gen:cli-reference` npm script.\n- **AW-12** (#44) — root-caused the "cli.test.ts flaky on first CI run" as tsx cold-start (CI ran Test before Build → pickRunner fell back to tsx). Fixed: build the CLI before the integration suite in CI so it uses dist deterministically.\n- **AW-8** (#45) — bootstrap auto-archives done tasks older than 30 days into `tasks/archive/` (preserved, out of active list); ids surfaced as a housekeeping note. Inert until tasks age.\n- **AW-10** (#46) — removed redundant `normalizeDates`/`normalizeDateFields` workarounds (readRawFrontmatter already coerces); migrated audit/_focus-helpers/worktree-set-default to `readFrontmatter`. `readRawFrontmatter` kept for lint/set/touch/task-add.\n\n## AW-13 (npm publish) — PREPPED, owner actions remain\nSwitched to **npm OIDC trusted publishing** (PR #42) instead of an NPM_TOKEN secret. `release.yml` now drops NPM_TOKEN, adds `npm install -g npm@latest` (needs npm ≥ 11.5.1), and `publishConfig.provenance` removed (automatic under trusted publishing; also unblocks local bootstrap). Artifact verified: build clean, tarball 17 files/240kB, clean `--omit=dev` install runs the CLI.\n\nOwner actions (in AW-13 notes):\n1. Bootstrap once — a trusted publisher can\'t be registered for a package that doesn\'t exist yet: `npm login` → `pnpm build` → `npm publish`.\n2. Configure trusted publisher on npmjs.com (org HJewkes, repo active-work, workflow release.yml, action `npm publish`).\n3. Enable Settings → Actions → General → "Allow GitHub Actions to create and approve pull requests" (the changesets Version PR step currently fails without it — independent of publishing).\nThen push to main → auto "Version Packages" PR → merge publishes via OIDC. Version will be 0.2.0 (three pending changesets from 0.1.0), unless a local bootstrap publishes 0.1.0 first.\n\n## Open tasks remaining\n- AW-1 (smoke-test gate), AW-13 (owner actions), and four large low-priority features: AW-3 (WebSocket broadcasts), AW-5 (aw sync), AW-6 (Linear/Jira/Slack discovery), AW-7 (read-write dashboard).\n\n## Method note\nManual review + smoke tests repeatedly caught defects that green CI alone missed: the AW-15 migration mismatch, the AW-1 Linux-only setup abort, launchd test-hygiene (real launchd domain), the doctor false-negative, and the dependency bloat.',
52
+ },
53
+ {
54
+ id: '874f2d4e',
55
+ filename: '2026-07-01-1617-874f2d4e.md',
56
+ started: '2026-07-01T16:17:40.917Z',
57
+ ended: '2026-07-01T16:51:35Z',
58
+ track: 'canonical',
59
+ title: 'Fix: channels flag swallowing the bootstrap prompt',
60
+ body: '# Fix: channels flag swallowing the bootstrap prompt\n\nDebugged and fixed the broken "channels" support in the `aw` launcher.\n\n## Symptom\n`aw voltras-workspace` collided the channel name with the bootstrap prompt and\nfailed to start Claude Code.\n\n## Root cause\n`aw` spawned `claude --dangerously-load-development-channels <target> <prompt>`.\nThe flag is real but hidden from `--help`; its value is **variadic**\n(`<servers...>`), confirmed in the v2.1.197 binary strings. A variadic option\ngreedily consumes every following non-`-` token, so it ate the channel target\n*and the trailing prompt* as channel targets — leaving the real `[prompt]`\npositional empty and treating the prompt text as a bogus channel name.\n\nAn earlier `-p` probe appeared to "work" only because `-p` (leading `-`) halted\nthe variadic before the prompt; real interactive launches have no such stop.\n\n## Fix (branch `fix/aw-channels-prompt-collision`, commit 3ab6d4e → rebased to fcca639; PR #35)\n- Assemble argv as `[<flag> ...targets, \'--\', prompt]` — the `--` terminator\n stops the variadic so the prompt is parsed as the positional `[prompt]`.\n- Collapse to a single variadic flag carrying all targets.\n- Extracted argv assembly into side-effect-free `src/launcher-args.ts`\n (`buildChannelArgs`, `buildClaudeArgs`) — `aw.ts` runs `main()` on import, so\n importing it in a test would fire the launcher.\n- Committed the previously-uncommitted channels wiring too: brief schema\n `channelTarget` + `open` command emitting `channels`.\n\n## Verification\n- New regression test `__tests__/aw-launcher.test.ts` (7 cases, incl. the\n `--`-terminator regression).\n- `typecheck` clean; `eslint` clean on changed files; full unit suite 420 passed.\n- `build:cli` rebuilt `dist/aw.js` (installed binary) — fix confirmed present.\n- Verified `claude ... -- "<prompt>"` honors `--` as an option terminator.\n\n## Session-record bugs — already fixed elsewhere\nWhile recording this session, `active-work session record` rejected `--body-file`\n(advertised but never wired; schema required `body`) and required an explicit\n`--track` (help claimed a `canonical` default the schema lacked). I re-derived a\nfix, then found the identical fix already existed on branch\n`fix/session-record-body-file-and-track-default` (commit 83e1fa1) with more tests\n— so I **discarded my duplicate** rather than commit it.\n\n## PR reshuffle (Approach B — drop-gate)\nDiscovered local `main` was 2 commits ahead of `origin/main`, unpushed:\n`80634b0` (aw launcher split — a real dependency of the channels fix) and\n`9cf1165` (always invoke main / drop isDirectRun gate). `9cf1165` was a\n*competing* resolution of the direct-run problem vs open PR #33\n(`fix/cli-direct-run-symlinks`, `2bcb071`, bin-shim symlink detection) — both\ntouch `src/cli.ts`; only one can land. Owner chose **Approach B (drop-gate)**.\n\nActions taken:\n- Owner pushed local `main` → `origin/main` (`b727b6b..9cf1165`). Safety\n classifier blocks me from pushing the default branch, so this was manual.\n- **PR #35** — channels fix. Rebased off the AW-15 stack onto `main`\n (`3ab6d4e` → `fcca639`); cherry-picked cleanly (open.ts auto-merged). Now a\n single clean commit, no AW-15 baggage. base=main, MERGEABLE.\n- **PR #34** — session-record fix. Rebased onto `main`, dropping the superseded\n `2bcb071` symlink commit (`83e1fa1` → `9a65e31`), force-pushed, base switched\n from the #33 branch to `main`. Single commit, MERGEABLE. 12 session tests green.\n- **PR #33** — closed as superseded by `9cf1165` (drop-gate), with a comment.\n\n## Not done / follow-up\n- **Live smoke-test:** after #35 merges, owner should run `aw voltras-workspace`\n — I can\'t execute `--dangerously-load-development-channels` (safety classifier).\n- **CI gate:** required status check `check` must go green on #34 and #35 before\n merge (branch protection).\n- The AW-15 launcher commits `80634b0`/`9cf1165` are now on `main` outside of a\n PR (pushed directly, bypassing review) — noted for the record.',
61
+ },
62
+ {
63
+ id: 'aw-1-sys',
64
+ filename: '2026-05-13-1927-aw-1-sys.md',
65
+ started: '2026-05-13T19:27:21Z',
66
+ ended: '2026-05-13T19:33:13Z',
67
+ track: 'canonical',
68
+ title: 'AW-1 — Linux systemd supervision (engineering complete)',
69
+ body: '# AW-1 — Linux systemd supervision (engineering complete)\n\nImplemented user-level systemd supervision for the `active-work` daemon. All\nunit tests pass; Ubuntu 24.04 smoke-test is the only remaining gate before\nclosing AW-1.\n\n## What changed\n\n- **New module `src/setup/supervision-systemd.ts`** — single home for the\n unit template, install/uninstall steps, and the `isUnitActive` probe.\n - `renderUnit({ cliEntry, port?, nodeBin? })` emits a `Type=simple` unit\n (`[Unit]/[Service]/[Install]`) with `Restart=on-failure`,\n `RestartSec=5`, `WantedBy=default.target`, and `ExecStart=<node>\n <cli> mcp serve [--port N]`. Paths with whitespace get quoted.\n - `stepInstallSupervision` writes the unit to\n `~/.config/systemd/user/active-work.service`, then runs\n `systemctl --user daemon-reload` + `systemctl --user enable --now\n active-work.service`. Idempotent: same content → `done:false /\n refreshed`. systemctl-missing returns a soft-skip with manual\n instructions; daemon-reload exit ≠ 0 is a hard failure.\n - `uninstallSupervision` runs `disable --now`, removes the unit file,\n then `daemon-reload`. Tolerates systemctl missing.\n - `isUnitActive` probes `systemctl --user is-active --quiet`. Returns\n false on non-Linux without spawning anything.\n\n- **Wired into `src/setup/steps.ts`**:\n - New `stepSupervision` wraps the install with the `--yes`/confirm\n prompt pattern other setup steps use; on non-Linux returns a\n platform-aware skip.\n - Inserted into `runSetup` between MCP register and daemon start.\n - `stepStartDaemon` now first checks `isUnitActive(deps)` on Linux and\n skips the `--detach` spawn when systemd already owns the daemon.\n - `runUninstall` calls `uninstallSupervision` (Linux-gated) before the\n daemon-stop step, with its own confirm prompt.\n - `STEP_NAMES.SUPERVISION` exported alongside the other step names.\n\n- **Tests**:\n - New `__tests__/setup/supervision-systemd.test.ts` (16 tests):\n `renderUnit` shape + port + space-quoting, `getUnitPath`,\n `stepInstallSupervision` darwin no-op / linux write+reload+enable /\n idempotent refresh / systemctl-missing fallback / daemon-reload\n failure, `uninstallSupervision` darwin no-op / absent / disable+remove,\n `isUnitActive` non-linux / 0 / non-zero.\n - Extended `__tests__/setup-steps.test.ts` with `stepSupervision` darwin\n no-op + linux cancel paths, and a `stepStartDaemon` test confirming\n it issues only the `systemctl is-active` probe (and no execPath spawn)\n when the unit is active.\n\n- **Run shape**: full suite 448/448 pass, lint clean, typecheck clean\n (`pnpm test`, `pnpm lint`, `pnpm typecheck`).\n\n## What\'s still gating AW-1\n\n- **Ubuntu 24.04 smoke-test of `active-work setup` end-to-end.** AW-1\'s\n `done_when` calls for "smoke-tested on Ubuntu 24.04"; that requires a\n Linux box and was not exercised from this macOS dev host. The unit\n template was modelled after the standard user-unit spec but should be\n verified with `systemd-analyze verify ~/.config/systemd/user/active-work.service`\n on a real Ubuntu 24.04 install before closing the task.\n\n## Design notes worth remembering\n\n- The unit runs the daemon in the **foreground** (`mcp serve`, not\n `mcp serve --detach`) because `Type=simple` expects the main process\n to stay alive — `--detach` would immediately exit and systemd would\n mark the service failed.\n- Decision: keep AW-2 (launchd plist for macOS) as a separate task even\n though the install/uninstall shape is symmetric. AW-1 doesn\'t drag in\n the plist work; the supervision module is namespaced\n `supervision-systemd.ts` so a future `supervision-launchd.ts` slots in\n alongside.\n- `stepStartDaemon` checking `isUnitActive` is the right seam (rather\n than threading a flag through `runSetup`) because the question\n "should we manually spawn?" is exactly "is the daemon already\n managed?" — the probe answers it regardless of which step earlier\n in the wizard installed the supervision.\n\n## Files touched\n\n- `src/setup/supervision-systemd.ts` (new)\n- `src/setup/steps.ts` (added `stepSupervision`, wired into\n `runSetup`/`runUninstall`, taught `stepStartDaemon` about systemd)\n- `__tests__/setup/supervision-systemd.test.ts` (new)\n- `__tests__/setup-steps.test.ts` (added supervision + daemon-detection\n describes)',
70
+ },
71
+ ]
72
+
73
+ /** The reference instant the stories and tests measure ages from (2026-07-14 09:00Z). */
74
+ export const SESSION_NOW = new Date('2026-07-14T09:00:00Z').getTime()
75
+
76
+ /**
77
+ * The real task rows behind every id the fixture sessions mention, for the
78
+ * detail pane's tasks-touched table. A host resolves these from its task store;
79
+ * the story does the same lookup against this list.
80
+ */
81
+ export const SESSION_TASK_FIXTURE: TaskListItem[] = [
82
+ {
83
+ slug: 'active-work',
84
+ id: 'AW-1',
85
+ title: 'Add Linux support: systemd unit for daemon supervision',
86
+ priority: 1,
87
+ severity: 'medium',
88
+ estimate: 5,
89
+ updated: '2026-07-12',
90
+ },
91
+ {
92
+ slug: 'active-work',
93
+ id: 'AW-2',
94
+ title: 'Add launchd plist install/uninstall to setup wizard (macOS)',
95
+ priority: 2,
96
+ severity: 'medium',
97
+ estimate: 3,
98
+ updated: '2026-07-01',
99
+ },
100
+ {
101
+ slug: 'active-work',
102
+ id: 'AW-3',
103
+ title: 'WebSocket file-event broadcasts from daemon to dashboard',
104
+ priority: 3,
105
+ severity: 'low',
106
+ estimate: 5,
107
+ updated: '2026-07-02',
108
+ },
109
+ {
110
+ slug: 'active-work',
111
+ id: 'AW-4',
112
+ title: 'aw doctor: health-check command (verify deps, daemon, MCP registration, skill install)',
113
+ priority: 4,
114
+ severity: 'medium',
115
+ estimate: 3,
116
+ updated: '2026-07-01',
117
+ },
118
+ {
119
+ slug: 'active-work',
120
+ id: 'AW-5',
121
+ title: 'Multi-machine git-backed sync wrapper (aw sync)',
122
+ priority: 5,
123
+ severity: 'low',
124
+ estimate: 8,
125
+ updated: '2026-07-02',
126
+ },
127
+ {
128
+ slug: 'active-work',
129
+ id: 'AW-6',
130
+ title: 'Linear / Jira / Slack discovery sources',
131
+ priority: 6,
132
+ severity: 'low',
133
+ estimate: 13,
134
+ updated: '2026-05-12',
135
+ },
136
+ {
137
+ slug: 'active-work',
138
+ id: 'AW-7',
139
+ title: 'Read-write dashboard (mark tasks done from /ui, reorder via drag)',
140
+ priority: 7,
141
+ severity: 'low',
142
+ estimate: 8,
143
+ updated: '2026-05-12',
144
+ },
145
+ {
146
+ slug: 'active-work',
147
+ id: 'AW-8',
148
+ title: 'Auto-archive done tasks older than N days during bootstrap',
149
+ priority: 8,
150
+ severity: 'low',
151
+ estimate: 2,
152
+ updated: '2026-07-01',
153
+ },
154
+ {
155
+ slug: 'active-work',
156
+ id: 'AW-9',
157
+ title: "Audit tests for unsafe HOME/filesystem mocking; ensure all use vi.spyOn(os, 'homedir')",
158
+ priority: 9,
159
+ severity: 'high',
160
+ estimate: 2,
161
+ updated: '2026-07-01',
162
+ },
163
+ {
164
+ slug: 'active-work',
165
+ id: 'AW-10',
166
+ title:
167
+ 'Clean up readRawFrontmatter workarounds in commands now that gray-matter-io coerces dates',
168
+ priority: 10,
169
+ severity: 'low',
170
+ estimate: 2,
171
+ updated: '2026-07-01',
172
+ },
173
+ {
174
+ slug: 'active-work',
175
+ id: 'AW-11',
176
+ title: 'Remove @titan-design/react-ui dep — dashboard agent ended up not using it',
177
+ priority: 11,
178
+ severity: 'low',
179
+ estimate: 1,
180
+ updated: '2026-07-01',
181
+ },
182
+ {
183
+ slug: 'active-work',
184
+ id: 'AW-12',
185
+ title:
186
+ 'Investigate occasional integration-test flakes (cli.test.ts had 5 failures on first merged run, clean on retry)',
187
+ priority: 12,
188
+ severity: 'medium',
189
+ estimate: 3,
190
+ updated: '2026-07-01',
191
+ },
192
+ {
193
+ slug: 'active-work',
194
+ id: 'AW-13',
195
+ title:
196
+ 'First npm publish: trigger release.yml; verify @hjewkes/active-work@0.1.0 installable via npm i -g',
197
+ priority: 13,
198
+ severity: 'high',
199
+ estimate: 1,
200
+ updated: '2026-07-02',
201
+ },
202
+ {
203
+ slug: 'active-work',
204
+ id: 'AW-14',
205
+ title:
206
+ 'Add gen:cli-reference script entry to package.json (generator script exists; just needs npm-run wiring)',
207
+ priority: 14,
208
+ severity: 'low',
209
+ estimate: 1,
210
+ updated: '2026-07-01',
211
+ },
212
+ {
213
+ slug: 'active-work',
214
+ id: 'AW-15',
215
+ title: 'Simplify artifacts.yml: branches/stashes only; live-pull PR + branch state',
216
+ priority: 1,
217
+ severity: 'medium',
218
+ estimate: 8,
219
+ updated: '2026-07-01',
220
+ },
221
+ {
222
+ slug: 'active-work',
223
+ id: 'AW-16',
224
+ title: 'session record --body-file passes validation when --body is omitted',
225
+ priority: 6,
226
+ severity: 'low',
227
+ estimate: 1,
228
+ tags: ['polish', 'cli'],
229
+ updated: '2026-07-01',
230
+ },
231
+ {
232
+ slug: 'active-work',
233
+ id: 'AW-17',
234
+ title: 'open/aw: resolve initiative from cwd when no slug given',
235
+ priority: 15,
236
+ severity: 'medium',
237
+ estimate: 3,
238
+ updated: '2026-07-12',
239
+ },
240
+ {
241
+ slug: 'active-work',
242
+ id: 'AW-18',
243
+ title: 'worktree.set: register/update a worktree on an existing initiative',
244
+ priority: 16,
245
+ severity: 'low',
246
+ estimate: 2,
247
+ updated: '2026-07-12',
248
+ },
249
+ {
250
+ slug: 'active-work',
251
+ id: 'AW-19',
252
+ title: 'active-work prompt + /aw-prompt slash command for mid-session context re-seed',
253
+ priority: 17,
254
+ severity: 'low',
255
+ estimate: 3,
256
+ updated: '2026-07-12',
257
+ },
258
+ {
259
+ slug: 'active-work',
260
+ id: 'AW-20',
261
+ title: 'aw/open --adhoc: frame bootstrap prompt as ad-hoc work, not handoff continuation',
262
+ priority: 18,
263
+ severity: 'low',
264
+ estimate: 2,
265
+ updated: '2026-07-12',
266
+ },
267
+ ]
@@ -0,0 +1,56 @@
1
+ import type { ProseLinker } from '../Prose'
2
+
3
+ /** A per-initiative task id such as `AW-22` or `TD-07.14`. */
4
+ export const TASK_REF_PATTERN = /\b[A-Z]{2,}-\d+(?:\.\d+)?\b/
5
+ /** An Obsidian-style `[[name]]` link into notes or memory. */
6
+ export const WIKI_LINK_PATTERN = /\[\[[^\]]+\]\]/
7
+ /** A bare `#123` pull-request or issue number. */
8
+ export const PR_REF_PATTERN = /#\d+\b/
9
+
10
+ /** Every distinct task id in a body, in first-seen order. */
11
+ export function extractTaskRefs(body: string): string[] {
12
+ const all = body.match(new RegExp(TASK_REF_PATTERN.source, 'g')) ?? []
13
+ return Array.from(new Set(all))
14
+ }
15
+
16
+ /** Task ids read in the brand colour and, when a handler is given, open the task. */
17
+ export function taskRefLinker(onPress?: (id: string) => void): ProseLinker {
18
+ return { id: 'task', pattern: TASK_REF_PATTERN, tone: 'brand', onPress }
19
+ }
20
+
21
+ /** `[[name]]` links drop their brackets and read as links; the handler receives the bare name. */
22
+ export function wikiLinkLinker(onPress?: (name: string) => void): ProseLinker {
23
+ const strip = (ref: string) => ref.slice(2, -2)
24
+ return {
25
+ id: 'wiki',
26
+ pattern: WIKI_LINK_PATTERN,
27
+ tone: 'link',
28
+ label: strip,
29
+ onPress: onPress ? (ref) => onPress(strip(ref)) : undefined,
30
+ }
31
+ }
32
+
33
+ /** PR numbers recede rather than compete with task ids; the handler receives the number. */
34
+ export function prRefLinker(onPress?: (number: number) => void): ProseLinker {
35
+ return {
36
+ id: 'pr',
37
+ pattern: PR_REF_PATTERN,
38
+ tone: 'muted',
39
+ onPress: onPress ? (ref) => onPress(Number(ref.slice(1))) : undefined,
40
+ }
41
+ }
42
+
43
+ export interface SessionLinkHandlers {
44
+ onPressTask?: (id: string) => void
45
+ onPressLink?: (name: string) => void
46
+ onPressPr?: (number: number) => void
47
+ }
48
+
49
+ /** The three linkers a session log needs, in the order they should win a match. */
50
+ export function sessionLinkers(handlers: SessionLinkHandlers = {}): ProseLinker[] {
51
+ return [
52
+ taskRefLinker(handlers.onPressTask),
53
+ wikiLinkLinker(handlers.onPressLink),
54
+ prRefLinker(handlers.onPressPr),
55
+ ]
56
+ }
@@ -0,0 +1,97 @@
1
+ import type { TaskListItem } from './TaskRow'
2
+
3
+ /**
4
+ * A hand-trimmed slice of a real active-work backlog, used by the task-list
5
+ * stories and tests. Fixed values (no `Date.now()`, no randomness) so visual
6
+ * baselines stay deterministic — pair it with {@link TASK_LIST_NOW}.
7
+ *
8
+ * Deliberately covers the awkward rows, not just the tidy ones: an unset
9
+ * severity, an unset estimate, a task with more tags than the row shows, a
10
+ * title long enough to clip, and two tasks sharing a priority so tie-breaks are
11
+ * exercised.
12
+ */
13
+ export const TASK_LIST_FIXTURE: TaskListItem[] = [
14
+ {
15
+ slug: 'active-work',
16
+ id: 'AW-22',
17
+ title: 'Read-only dashboard prototypes (titan specimens): portfolio, task list, session reader',
18
+ severity: 'low',
19
+ priority: 20,
20
+ estimate: 8,
21
+ tags: ['dashboard', 'titan'],
22
+ updated: '2026-08-29T10:00:00Z',
23
+ },
24
+ {
25
+ slug: 'active-work',
26
+ id: 'AW-86',
27
+ title: 'Design spike: notes-supersession (rescoped)',
28
+ severity: 'low',
29
+ priority: 20,
30
+ tags: ['spike'],
31
+ updated: '2026-08-11T09:00:00Z',
32
+ },
33
+ {
34
+ slug: 'relay',
35
+ id: 'RL-14',
36
+ title: 'Voice dispatch drops the initiative when the daemon restarts mid-utterance',
37
+ severity: 'critical',
38
+ priority: 3,
39
+ estimate: 5,
40
+ tags: ['voice', 'daemon', 'reliability', 'p0'],
41
+ updated: '2026-08-30T07:30:00Z',
42
+ },
43
+ {
44
+ slug: 'codewatch',
45
+ id: 'C-92',
46
+ title: 'Plugin injection delivery, evidence-framed by the injection eval',
47
+ severity: 'high',
48
+ priority: 7,
49
+ estimate: 13,
50
+ tags: ['plugin'],
51
+ updated: '2026-07-30T12:00:00Z',
52
+ },
53
+ {
54
+ slug: 'codewatch',
55
+ id: 'C-6',
56
+ title: 'npm publish the packaged distribution',
57
+ severity: 'medium',
58
+ priority: 11,
59
+ estimate: 2,
60
+ updated: '2026-06-18T16:20:00Z',
61
+ },
62
+ {
63
+ slug: 'titan-platform',
64
+ id: 'TP-16',
65
+ title: 'Nativewind-free token-only export subpath',
66
+ priority: 14,
67
+ estimate: 3,
68
+ tags: ['tokens'],
69
+ updated: '2026-08-01T04:01:00Z',
70
+ },
71
+ {
72
+ slug: 'home-assistant',
73
+ id: 'HA-3',
74
+ title: 'Rebuild the bedroom automation after the Zigbee coordinator swap',
75
+ severity: 'medium',
76
+ priority: 25,
77
+ estimate: 5,
78
+ tags: ['zigbee'],
79
+ updated: '2026-05-12T00:00:00Z',
80
+ },
81
+ {
82
+ slug: 'brain',
83
+ id: 'BR-41',
84
+ title: 'Collapse the duplicate embedding path',
85
+ severity: 'high',
86
+ priority: 9,
87
+ estimate: 8,
88
+ tags: ['perf', 'index'],
89
+ updated: '2026-08-27T18:45:00Z',
90
+ },
91
+ ]
92
+
93
+ /**
94
+ * Fixed reference "now" for the fixture (2026-08-30T12:00:00Z). Pass to
95
+ * `TaskTable`'s `now` so every age label is stable across runs.
96
+ */
97
+ export const TASK_LIST_NOW = new Date('2026-08-30T12:00:00Z').getTime()
@@ -1,11 +1,16 @@
1
1
  import type { Decorator, Meta, StoryObj } from '@storybook/react-vite'
2
2
  import { View, Text, Pressable } from 'react-native'
3
3
  import { CircularTimer } from './CircularTimer'
4
+ import { greyRamp, primitiveColors } from '../../../theme/tokens/primitives'
5
+ import { getSemanticColors } from '../../../theme/tokens/semantic'
6
+ import { alpha } from '../../../utils/colors'
7
+
8
+ const t = getSemanticColors('dark')
4
9
 
5
10
  const meta: Meta<typeof CircularTimer> = {
6
- title: 'Custom/CircularTimer',
11
+ title: 'Components/Molecules/CircularTimer',
7
12
  component: CircularTimer,
8
- tags: ['autodocs'],
13
+ tags: ['autodocs', 'status:candidate', '!status:review'],
9
14
  parameters: {
10
15
  docs: {
11
16
  description: {
@@ -15,7 +20,8 @@ const meta: Meta<typeof CircularTimer> = {
15
20
  '`durationMs` + `elapsedMs`) and composes `CircularProgress` for the arc (`down` drains, ' +
16
21
  '`up` fills). On completion a `down` timer with a `doneLabel` fills fully in `doneColor` ' +
17
22
  'and reads the label (e.g. "GO"). Pass `controls` to render buttons below the ring, or ' +
18
- "`fill` to make it responsive to its container. `RestTimer`'s `ring` variant wraps this.",
23
+ "`fill` to make it responsive to its container. `RestTimer`'s `ring` variant wraps this." +
24
+ '\n\nComposes **CircularProgress** over the `useTimer` hook.',
19
25
  },
20
26
  },
21
27
  },
@@ -31,7 +37,7 @@ export default meta
31
37
  type Story = StoryObj<typeof CircularTimer>
32
38
 
33
39
  const dark: Decorator = (Story) => (
34
- <View style={{ padding: 32, alignItems: 'center', backgroundColor: '#0E0E0E' }}>
40
+ <View style={{ padding: 32, alignItems: 'center', backgroundColor: t['background-frame'] }}>
35
41
  <Story />
36
42
  </View>
37
43
  )
@@ -63,13 +69,13 @@ export const DoneWithLabel: Story = {
63
69
  const DemoButton = ({ label }: { label: string }) => (
64
70
  <Pressable
65
71
  style={{
66
- backgroundColor: 'rgba(255,255,255,0.06)',
72
+ backgroundColor: alpha(primitiveColors.white, 0.06),
67
73
  paddingVertical: 8,
68
74
  paddingHorizontal: 20,
69
75
  borderRadius: 8,
70
76
  }}
71
77
  >
72
- <Text style={{ color: '#DADADA', fontSize: 11, fontWeight: '600' }}>{label}</Text>
78
+ <Text style={{ color: greyRamp[200], fontSize: 11, fontWeight: '600' }}>{label}</Text>
73
79
  </Pressable>
74
80
  )
75
81
 
@@ -5,7 +5,8 @@ import { DateTime, type DateTimeFormat } from './DateTime'
5
5
  const meta: Meta<typeof DateTime> = {
6
6
  title: 'Components/Molecules/DateTime',
7
7
  component: DateTime,
8
- tags: ['autodocs'],
8
+ parameters: { docs: { description: { component: 'Composes **Typography**.' } } },
9
+ tags: ['autodocs', 'status:candidate', '!status:review'],
9
10
  argTypes: {
10
11
  format: {
11
12
  control: 'select',
@@ -56,7 +56,9 @@ describe('DateTime', () => {
56
56
  })
57
57
 
58
58
  it('includes seconds when seconds is set', () => {
59
- render(<DateTime value={new Date(2024, 0, 1, 16, 12, 7)} format="time" hour12={false} seconds />)
59
+ render(
60
+ <DateTime value={new Date(2024, 0, 1, 16, 12, 7)} format="time" hour12={false} seconds />
61
+ )
60
62
  expect(screen.getByText('16:12:07')).toBeInTheDocument()
61
63
  })
62
64