@pennyfarthing/core 11.3.8 → 11.4.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 (304) hide show
  1. package/README.md +1 -1
  2. package/package.json +4 -1
  3. package/packages/core/dist/public/css/react.css +1 -1
  4. package/packages/core/dist/public/js/react/react.js +24 -24
  5. package/packages/core/src/public/App.tsx +356 -0
  6. package/packages/core/src/public/components/AgentLoadDialog.tsx +202 -0
  7. package/packages/core/src/public/components/AgentPopup.tsx +308 -0
  8. package/packages/core/src/public/components/ApprovalModal/ApprovalModal.css +35 -0
  9. package/packages/core/src/public/components/ApprovalModal/index.tsx +632 -0
  10. package/packages/core/src/public/components/BikeRackIndex.tsx +53 -0
  11. package/packages/core/src/public/components/BikeRackWorkspace.tsx +217 -0
  12. package/packages/core/src/public/components/CommandPalette.tsx +554 -0
  13. package/packages/core/src/public/components/ConfirmDialog.tsx +168 -0
  14. package/packages/core/src/public/components/ContextIndicator/ContextIndicator.css +85 -0
  15. package/packages/core/src/public/components/ContextIndicator/index.tsx +330 -0
  16. package/packages/core/src/public/components/ContextSparkline.tsx +56 -0
  17. package/packages/core/src/public/components/ControlBar.tsx +636 -0
  18. package/packages/core/src/public/components/DeadCodeDialog.tsx +169 -0
  19. package/packages/core/src/public/components/DiffViewer.tsx +585 -0
  20. package/packages/core/src/public/components/DockviewWorkspace.tsx +749 -0
  21. package/packages/core/src/public/components/Editor.tsx +630 -0
  22. package/packages/core/src/public/components/ErrorBoundary.tsx +67 -0
  23. package/packages/core/src/public/components/FileTree.tsx +379 -0
  24. package/packages/core/src/public/components/FontPicker/FontPicker.css +276 -0
  25. package/packages/core/src/public/components/FontPicker/index.tsx +430 -0
  26. package/packages/core/src/public/components/FullFileTree.tsx +237 -0
  27. package/packages/core/src/public/components/HealthGauge.tsx +181 -0
  28. package/packages/core/src/public/components/Message.tsx +225 -0
  29. package/packages/core/src/public/components/MessageList.tsx +98 -0
  30. package/packages/core/src/public/components/MessageView.tsx +400 -0
  31. package/packages/core/src/public/components/ModeSwitch/ModeSwitch.css +165 -0
  32. package/packages/core/src/public/components/ModeSwitch/index.tsx +372 -0
  33. package/packages/core/src/public/components/PersonaHeader.tsx +242 -0
  34. package/packages/core/src/public/components/ProjectInfoBar.tsx +45 -0
  35. package/packages/core/src/public/components/QuickActions.tsx +267 -0
  36. package/packages/core/src/public/components/SpanTimeline.tsx +352 -0
  37. package/packages/core/src/public/components/StandalonePanel.tsx +82 -0
  38. package/packages/core/src/public/components/StatsStrip.tsx +162 -0
  39. package/packages/core/src/public/components/StreamingContent.tsx +77 -0
  40. package/packages/core/src/public/components/SubagentSpan.tsx +180 -0
  41. package/packages/core/src/public/components/TandemPortrait.tsx +72 -0
  42. package/packages/core/src/public/components/ThemePalette/ThemePalette.css +179 -0
  43. package/packages/core/src/public/components/ThemePalette/index.tsx +326 -0
  44. package/packages/core/src/public/components/ToolCallBlock.tsx +252 -0
  45. package/packages/core/src/public/components/ToolStack.tsx +209 -0
  46. package/packages/core/src/public/components/ToolStatus.tsx +57 -0
  47. package/packages/core/src/public/components/dialogs/CodeMarkersDialog.tsx +169 -0
  48. package/packages/core/src/public/components/dialogs/ComplexityDialog.tsx +163 -0
  49. package/packages/core/src/public/components/dialogs/DependenciesDialog.tsx +120 -0
  50. package/packages/core/src/public/components/dialogs/HotspotsDialog.tsx +451 -0
  51. package/packages/core/src/public/components/dialogs/ToolDialog.tsx +43 -0
  52. package/packages/core/src/public/components/panel-registry.ts +13 -0
  53. package/packages/core/src/public/components/panels/ACPanel.tsx +93 -0
  54. package/packages/core/src/public/components/panels/AcceptanceCriteriaPanel.tsx +104 -0
  55. package/packages/core/src/public/components/panels/AuditLogPanel.tsx +489 -0
  56. package/packages/core/src/public/components/panels/BackgroundPanel.tsx +115 -0
  57. package/packages/core/src/public/components/panels/BikeLanePanel.tsx +214 -0
  58. package/packages/core/src/public/components/panels/DebugPanel.tsx +344 -0
  59. package/packages/core/src/public/components/panels/DiffView.tsx +109 -0
  60. package/packages/core/src/public/components/panels/DiffsPanel.tsx +56 -0
  61. package/packages/core/src/public/components/panels/GitPanel.tsx +260 -0
  62. package/packages/core/src/public/components/panels/HotspotsPanel.tsx +365 -0
  63. package/packages/core/src/public/components/panels/MessageFeed.tsx +39 -0
  64. package/packages/core/src/public/components/panels/MessagePanel.tsx +497 -0
  65. package/packages/core/src/public/components/panels/ProgressPanel.tsx +189 -0
  66. package/packages/core/src/public/components/panels/SettingsPanel.tsx +361 -0
  67. package/packages/core/src/public/components/panels/SprintPanel.tsx +723 -0
  68. package/packages/core/src/public/components/panels/TandemPanel.tsx +104 -0
  69. package/packages/core/src/public/components/panels/TaskTracker.tsx +48 -0
  70. package/packages/core/src/public/components/panels/TeamPanel.tsx +64 -0
  71. package/packages/core/src/public/components/panels/TeamRoster.tsx +67 -0
  72. package/packages/core/src/public/components/panels/TodoPanel.tsx +142 -0
  73. package/packages/core/src/public/components/panels/WorkflowPanel.tsx +224 -0
  74. package/packages/core/src/public/components/panels/index.ts +24 -0
  75. package/packages/core/src/public/components/ui/alert-dialog.tsx +139 -0
  76. package/packages/core/src/public/components/ui/badge.tsx +36 -0
  77. package/packages/core/src/public/components/ui/button.tsx +57 -0
  78. package/packages/core/src/public/components/ui/checkbox.tsx +28 -0
  79. package/packages/core/src/public/components/ui/collapsible.tsx +9 -0
  80. package/packages/core/src/public/components/ui/command.tsx +151 -0
  81. package/packages/core/src/public/components/ui/dialog.tsx +120 -0
  82. package/packages/core/src/public/components/ui/popover.tsx +31 -0
  83. package/packages/core/src/public/components/ui/progress.tsx +28 -0
  84. package/packages/core/src/public/components/ui/scroll-area.tsx +46 -0
  85. package/packages/core/src/public/components/ui/select.tsx +157 -0
  86. package/packages/core/src/public/components/ui/separator.tsx +29 -0
  87. package/packages/core/src/public/components/ui/skeleton.tsx +15 -0
  88. package/packages/core/src/public/components/ui/switch.tsx +27 -0
  89. package/packages/core/src/public/components/ui/toggle-group.tsx +59 -0
  90. package/packages/core/src/public/components/ui/toggle.tsx +43 -0
  91. package/packages/core/src/public/components/ui/tooltip.tsx +30 -0
  92. package/packages/core/src/public/contexts/ClaudeContext.tsx +311 -0
  93. package/packages/core/src/public/contexts/MessageQueueContext.tsx +143 -0
  94. package/packages/core/src/public/css/theme-browser.css +550 -0
  95. package/packages/core/src/public/css/theme-system.css +630 -0
  96. package/packages/core/src/public/hooks/index.ts +49 -0
  97. package/packages/core/src/public/hooks/useAgentLoad.ts +105 -0
  98. package/packages/core/src/public/hooks/useBackgroundTasks.ts +131 -0
  99. package/packages/core/src/public/hooks/useClaude.ts +234 -0
  100. package/packages/core/src/public/hooks/useCodeMarkers.ts +101 -0
  101. package/packages/core/src/public/hooks/useColorScheme.ts +42 -0
  102. package/packages/core/src/public/hooks/useCommandHistory.ts +99 -0
  103. package/packages/core/src/public/hooks/useComplexity.ts +80 -0
  104. package/packages/core/src/public/hooks/useDeadCode.ts +99 -0
  105. package/packages/core/src/public/hooks/useDependencies.ts +82 -0
  106. package/packages/core/src/public/hooks/useDiffs.ts +143 -0
  107. package/packages/core/src/public/hooks/useFileBrowser.ts +73 -0
  108. package/packages/core/src/public/hooks/useFocusPanel.ts +137 -0
  109. package/packages/core/src/public/hooks/useGitStatus.ts +233 -0
  110. package/packages/core/src/public/hooks/useHealthScore.ts +71 -0
  111. package/packages/core/src/public/hooks/useHotspots.ts +123 -0
  112. package/packages/core/src/public/hooks/useLayoutPersistence.ts +141 -0
  113. package/packages/core/src/public/hooks/useMarkdownParser.ts +36 -0
  114. package/packages/core/src/public/hooks/useMarkerActions.ts +234 -0
  115. package/packages/core/src/public/hooks/useMessageQueue.ts +380 -0
  116. package/packages/core/src/public/hooks/useMessageStream.ts +131 -0
  117. package/packages/core/src/public/hooks/usePersona.ts +112 -0
  118. package/packages/core/src/public/hooks/usePlanModeExit.ts +105 -0
  119. package/packages/core/src/public/hooks/useResponsiveLayout.ts +173 -0
  120. package/packages/core/src/public/hooks/useSprint.ts +157 -0
  121. package/packages/core/src/public/hooks/useStatsStrip.ts +204 -0
  122. package/packages/core/src/public/hooks/useStory.ts +135 -0
  123. package/packages/core/src/public/hooks/useSubagentHelper.ts +64 -0
  124. package/packages/core/src/public/hooks/useSyntaxHighlighter.ts +52 -0
  125. package/packages/core/src/public/hooks/useTabCompletion.ts +124 -0
  126. package/packages/core/src/public/hooks/useTandemObservations.ts +165 -0
  127. package/packages/core/src/public/hooks/useTeamMembers.ts +273 -0
  128. package/packages/core/src/public/hooks/useTodos.ts +93 -0
  129. package/packages/core/src/public/hooks/useUserAvatar.ts +54 -0
  130. package/packages/core/src/public/images/cyclist-dark.png +0 -0
  131. package/packages/core/src/public/images/cyclist-light.png +0 -0
  132. package/packages/core/src/public/index.html +14 -0
  133. package/packages/core/src/public/index.tsx +10 -0
  134. package/packages/core/src/public/lib/utils.ts +6 -0
  135. package/packages/core/src/public/styles/dockview-theme.css +376 -0
  136. package/packages/core/src/public/styles/tailwind.css +4454 -0
  137. package/packages/core/src/public/types/message.ts +51 -0
  138. package/packages/core/src/public/utils/avatar-service.ts +73 -0
  139. package/packages/core/src/public/utils/color-presets.ts +940 -0
  140. package/packages/core/src/public/utils/font-presets.ts +362 -0
  141. package/packages/core/src/public/utils/formatDuration.ts +14 -0
  142. package/packages/core/src/public/utils/markdown.ts +249 -0
  143. package/packages/core/src/public/utils/messageFilters.ts +128 -0
  144. package/packages/core/src/public/utils/slash-commands.ts +341 -0
  145. package/packages/core/src/public/utils/subagent-display.ts +146 -0
  146. package/packages/core/src/public/utils/syntax.ts +219 -0
  147. package/packages/core/src/public/utils/toolIntentSummarizer.ts +199 -0
  148. package/packages/core/src/public/utils/toolStackGrouper.ts +106 -0
  149. package/packages/core/src/public/utils/toolTypeColors.ts +45 -0
  150. package/pennyfarthing-dist/pf/__pycache__/__init__.cpython-314.pyc +0 -0
  151. package/pennyfarthing-dist/pf/__pycache__/cli.cpython-314.pyc +0 -0
  152. package/pennyfarthing-dist/pf/__pycache__/context.cpython-314.pyc +0 -0
  153. package/pennyfarthing-dist/pf/bc/__pycache__/__init__.cpython-314.pyc +0 -0
  154. package/pennyfarthing-dist/pf/bc/__pycache__/cli.cpython-314.pyc +0 -0
  155. package/pennyfarthing-dist/pf/bc/__pycache__/focus.cpython-314.pyc +0 -0
  156. package/pennyfarthing-dist/pf/bc/__pycache__/split.cpython-314.pyc +0 -0
  157. package/pennyfarthing-dist/pf/bc/cli.py +0 -1
  158. package/pennyfarthing-dist/pf/bc/focus.py +0 -1
  159. package/pennyfarthing-dist/pf/bikerack/__pycache__/__init__.cpython-314.pyc +0 -0
  160. package/pennyfarthing-dist/pf/bikerack/__pycache__/base_panel.cpython-314.pyc +0 -0
  161. package/pennyfarthing-dist/pf/bikerack/__pycache__/cli.cpython-314.pyc +0 -0
  162. package/pennyfarthing-dist/pf/bikerack/__pycache__/git_panel.cpython-314.pyc +0 -0
  163. package/pennyfarthing-dist/pf/bikerack/__pycache__/launcher.cpython-314.pyc +0 -0
  164. package/pennyfarthing-dist/pf/bikerack/__pycache__/portrait_resolver.cpython-314.pyc +0 -0
  165. package/pennyfarthing-dist/pf/bikerack/__pycache__/sprint_panel.cpython-314.pyc +0 -0
  166. package/pennyfarthing-dist/pf/bikerack/__pycache__/story_detail_data.cpython-314.pyc +0 -0
  167. package/pennyfarthing-dist/pf/bikerack/__pycache__/story_detail_screen.cpython-314.pyc +0 -0
  168. package/pennyfarthing-dist/pf/bikerack/__pycache__/tui.cpython-314.pyc +0 -0
  169. package/pennyfarthing-dist/pf/bikerack/base_panel.py +0 -1
  170. package/pennyfarthing-dist/pf/bikerack/events.py +1 -7
  171. package/pennyfarthing-dist/pf/bikerack/git_panel.py +273 -10
  172. package/pennyfarthing-dist/pf/bikerack/portrait_resolver.py +21 -0
  173. package/pennyfarthing-dist/pf/bikerack/sprint_panel.py +58 -1
  174. package/pennyfarthing-dist/pf/bikerack/tui.py +5 -20
  175. package/pennyfarthing-dist/pf/bmad/__pycache__/__init__.cpython-314.pyc +0 -0
  176. package/pennyfarthing-dist/pf/bmad/__pycache__/cli.cpython-314.pyc +0 -0
  177. package/pennyfarthing-dist/pf/bmad/__pycache__/parser.cpython-314.pyc +0 -0
  178. package/pennyfarthing-dist/pf/bmad/parser.py +15 -9
  179. package/pennyfarthing-dist/pf/codemarkers/__pycache__/__init__.cpython-314.pyc +0 -0
  180. package/pennyfarthing-dist/pf/codemarkers/__pycache__/analyze.cpython-314.pyc +0 -0
  181. package/pennyfarthing-dist/pf/codemarkers/__pycache__/models.cpython-314.pyc +0 -0
  182. package/pennyfarthing-dist/pf/common/__pycache__/__init__.cpython-314.pyc +0 -0
  183. package/pennyfarthing-dist/pf/common/__pycache__/config.cpython-314.pyc +0 -0
  184. package/pennyfarthing-dist/pf/common/__pycache__/output.cpython-314.pyc +0 -0
  185. package/pennyfarthing-dist/pf/common/__pycache__/pr_config.cpython-314.pyc +0 -0
  186. package/pennyfarthing-dist/pf/common/__pycache__/themes.cpython-314.pyc +0 -0
  187. package/pennyfarthing-dist/pf/common/pr_config.py +27 -2
  188. package/pennyfarthing-dist/pf/complexity/__pycache__/__init__.cpython-314.pyc +0 -0
  189. package/pennyfarthing-dist/pf/complexity/__pycache__/analyze.cpython-314.pyc +0 -0
  190. package/pennyfarthing-dist/pf/complexity/__pycache__/models.cpython-314.pyc +0 -0
  191. package/pennyfarthing-dist/pf/consultation/__pycache__/__init__.cpython-314.pyc +0 -0
  192. package/pennyfarthing-dist/pf/consultation/__pycache__/cli.cpython-314.pyc +0 -0
  193. package/pennyfarthing-dist/pf/deadcode/__pycache__/__init__.cpython-314.pyc +0 -0
  194. package/pennyfarthing-dist/pf/deadcode/__pycache__/analyze.cpython-314.pyc +0 -0
  195. package/pennyfarthing-dist/pf/deadcode/__pycache__/cli.cpython-314.pyc +0 -0
  196. package/pennyfarthing-dist/pf/deadcode/__pycache__/models.cpython-314.pyc +0 -0
  197. package/pennyfarthing-dist/pf/dependencies/__pycache__/__init__.cpython-314.pyc +0 -0
  198. package/pennyfarthing-dist/pf/dependencies/__pycache__/analyze.cpython-314.pyc +0 -0
  199. package/pennyfarthing-dist/pf/dependencies/__pycache__/models.cpython-314.pyc +0 -0
  200. package/pennyfarthing-dist/pf/epic/__pycache__/__init__.cpython-314.pyc +0 -0
  201. package/pennyfarthing-dist/pf/epic/__pycache__/cli.cpython-314.pyc +0 -0
  202. package/pennyfarthing-dist/pf/git_group/__pycache__/__init__.cpython-314.pyc +0 -0
  203. package/pennyfarthing-dist/pf/git_group/__pycache__/cli.cpython-314.pyc +0 -0
  204. package/pennyfarthing-dist/pf/handoff/__pycache__/__init__.cpython-314.pyc +0 -0
  205. package/pennyfarthing-dist/pf/handoff/__pycache__/cli.cpython-314.pyc +0 -0
  206. package/pennyfarthing-dist/pf/handoff/__pycache__/complete_phase.cpython-314.pyc +0 -0
  207. package/pennyfarthing-dist/pf/handoff/__pycache__/marker.cpython-314.pyc +0 -0
  208. package/pennyfarthing-dist/pf/handoff/__pycache__/phase_check.cpython-314.pyc +0 -0
  209. package/pennyfarthing-dist/pf/handoff/__pycache__/resolve_gate.cpython-314.pyc +0 -0
  210. package/pennyfarthing-dist/pf/healthscore/__pycache__/__init__.cpython-314.pyc +0 -0
  211. package/pennyfarthing-dist/pf/healthscore/__pycache__/__main__.cpython-314.pyc +0 -0
  212. package/pennyfarthing-dist/pf/healthscore/__pycache__/analyze.cpython-314.pyc +0 -0
  213. package/pennyfarthing-dist/pf/healthscore/__pycache__/cli.cpython-314.pyc +0 -0
  214. package/pennyfarthing-dist/pf/healthscore/__pycache__/formatters.cpython-314.pyc +0 -0
  215. package/pennyfarthing-dist/pf/healthscore/__pycache__/models.cpython-314.pyc +0 -0
  216. package/pennyfarthing-dist/pf/hooks/__pycache__/__init__.cpython-314.pyc +0 -0
  217. package/pennyfarthing-dist/pf/hooks/__pycache__/bell_mode.cpython-314.pyc +0 -0
  218. package/pennyfarthing-dist/pf/hooks/__pycache__/cli.cpython-314.pyc +0 -0
  219. package/pennyfarthing-dist/pf/hooks/__pycache__/context_breaker.cpython-314.pyc +0 -0
  220. package/pennyfarthing-dist/pf/hooks/__pycache__/context_warning.cpython-314.pyc +0 -0
  221. package/pennyfarthing-dist/pf/hooks/__pycache__/cyclist_pretooluse.cpython-314.pyc +0 -0
  222. package/pennyfarthing-dist/pf/hooks/__pycache__/pre_edit_check.cpython-314.pyc +0 -0
  223. package/pennyfarthing-dist/pf/hooks/__pycache__/reflector_check.cpython-314.pyc +0 -0
  224. package/pennyfarthing-dist/pf/hooks/__pycache__/schema_validation.cpython-314.pyc +0 -0
  225. package/pennyfarthing-dist/pf/hooks/__pycache__/session_start.cpython-314.pyc +0 -0
  226. package/pennyfarthing-dist/pf/hooks/__pycache__/session_stop.cpython-314.pyc +0 -0
  227. package/pennyfarthing-dist/pf/hooks/__pycache__/sprint_yaml_validation.cpython-314.pyc +0 -0
  228. package/pennyfarthing-dist/pf/hooks/__pycache__/statusline.cpython-314.pyc +0 -0
  229. package/pennyfarthing-dist/pf/hotspots/__pycache__/__init__.cpython-314.pyc +0 -0
  230. package/pennyfarthing-dist/pf/hotspots/__pycache__/analyze.cpython-314.pyc +0 -0
  231. package/pennyfarthing-dist/pf/hotspots/__pycache__/cli.cpython-314.pyc +0 -0
  232. package/pennyfarthing-dist/pf/hotspots/__pycache__/models.cpython-314.pyc +0 -0
  233. package/pennyfarthing-dist/pf/jira/__pycache__/__init__.cpython-314.pyc +0 -0
  234. package/pennyfarthing-dist/pf/jira/__pycache__/bidirectional.cpython-314.pyc +0 -0
  235. package/pennyfarthing-dist/pf/jira/__pycache__/claim.cpython-314.pyc +0 -0
  236. package/pennyfarthing-dist/pf/jira/__pycache__/cli.cpython-314.pyc +0 -0
  237. package/pennyfarthing-dist/pf/jira/__pycache__/client.cpython-314.pyc +0 -0
  238. package/pennyfarthing-dist/pf/jira/__pycache__/create.cpython-314.pyc +0 -0
  239. package/pennyfarthing-dist/pf/jira/__pycache__/epic.cpython-314.pyc +0 -0
  240. package/pennyfarthing-dist/pf/jira/__pycache__/operations.cpython-314.pyc +0 -0
  241. package/pennyfarthing-dist/pf/jira/__pycache__/reconcile.cpython-314.pyc +0 -0
  242. package/pennyfarthing-dist/pf/jira/__pycache__/story.cpython-314.pyc +0 -0
  243. package/pennyfarthing-dist/pf/jira/__pycache__/sync.cpython-314.pyc +0 -0
  244. package/pennyfarthing-dist/pf/launch/__pycache__/__init__.cpython-314.pyc +0 -0
  245. package/pennyfarthing-dist/pf/launch/__pycache__/cli.cpython-314.pyc +0 -0
  246. package/pennyfarthing-dist/pf/prime/__pycache__/__init__.cpython-314.pyc +0 -0
  247. package/pennyfarthing-dist/pf/prime/__pycache__/cli.cpython-314.pyc +0 -0
  248. package/pennyfarthing-dist/pf/prime/__pycache__/loader.cpython-314.pyc +0 -0
  249. package/pennyfarthing-dist/pf/prime/__pycache__/models.cpython-314.pyc +0 -0
  250. package/pennyfarthing-dist/pf/prime/__pycache__/persona.cpython-314.pyc +0 -0
  251. package/pennyfarthing-dist/pf/prime/__pycache__/session.cpython-314.pyc +0 -0
  252. package/pennyfarthing-dist/pf/prime/__pycache__/tiers.cpython-314.pyc +0 -0
  253. package/pennyfarthing-dist/pf/prime/__pycache__/workflow.cpython-314.pyc +0 -0
  254. package/pennyfarthing-dist/pf/session/__pycache__/__init__.cpython-314.pyc +0 -0
  255. package/pennyfarthing-dist/pf/session/__pycache__/cli.cpython-314.pyc +0 -0
  256. package/pennyfarthing-dist/pf/settings/__pycache__/__init__.cpython-314.pyc +0 -0
  257. package/pennyfarthing-dist/pf/settings/__pycache__/cli.cpython-314.pyc +0 -0
  258. package/pennyfarthing-dist/pf/settings/__pycache__/settings.cpython-314.pyc +0 -0
  259. package/pennyfarthing-dist/pf/settings/settings.py +44 -8
  260. package/pennyfarthing-dist/pf/sprint/__pycache__/__init__.cpython-314.pyc +0 -0
  261. package/pennyfarthing-dist/pf/sprint/__pycache__/archive.cpython-314.pyc +0 -0
  262. package/pennyfarthing-dist/pf/sprint/__pycache__/archive_epic.cpython-314.pyc +0 -0
  263. package/pennyfarthing-dist/pf/sprint/__pycache__/cli.cpython-314.pyc +0 -0
  264. package/pennyfarthing-dist/pf/sprint/__pycache__/epic_add.cpython-314.pyc +0 -0
  265. package/pennyfarthing-dist/pf/sprint/__pycache__/epic_update.cpython-314.pyc +0 -0
  266. package/pennyfarthing-dist/pf/sprint/__pycache__/loader.cpython-314.pyc +0 -0
  267. package/pennyfarthing-dist/pf/sprint/__pycache__/status.cpython-314.pyc +0 -0
  268. package/pennyfarthing-dist/pf/sprint/__pycache__/story_add.cpython-314.pyc +0 -0
  269. package/pennyfarthing-dist/pf/sprint/__pycache__/story_finish.cpython-314.pyc +0 -0
  270. package/pennyfarthing-dist/pf/sprint/__pycache__/story_update.cpython-314.pyc +0 -0
  271. package/pennyfarthing-dist/pf/sprint/__pycache__/validate_cmd.cpython-314.pyc +0 -0
  272. package/pennyfarthing-dist/pf/sprint/__pycache__/validator.cpython-314.pyc +0 -0
  273. package/pennyfarthing-dist/pf/sprint/__pycache__/work.cpython-314.pyc +0 -0
  274. package/pennyfarthing-dist/pf/sprint/__pycache__/yaml_io.cpython-314.pyc +0 -0
  275. package/pennyfarthing-dist/pf/sprint/story_finish.py +14 -2
  276. package/pennyfarthing-dist/pf/sprint/validator.py +7 -7
  277. package/pennyfarthing-dist/pf/tests/__pycache__/__init__.cpython-314.pyc +0 -0
  278. package/pennyfarthing-dist/pf/tests/__pycache__/conftest.cpython-314-pytest-9.0.2.pyc +0 -0
  279. package/pennyfarthing-dist/pf/tests/__pycache__/test_sprint_validator.cpython-314-pytest-9.0.2.pyc +0 -0
  280. package/pennyfarthing-dist/pf/tests/test_sprint_validator.py +44 -0
  281. package/pennyfarthing-dist/pf/theme/__pycache__/__init__.cpython-314.pyc +0 -0
  282. package/pennyfarthing-dist/pf/theme/__pycache__/cli.cpython-314.pyc +0 -0
  283. package/pennyfarthing-dist/pf/validate/__pycache__/__init__.cpython-314.pyc +0 -0
  284. package/pennyfarthing-dist/pf/validate/__pycache__/cli.cpython-314.pyc +0 -0
  285. package/pennyfarthing-dist/pf/workflow/__pycache__/__init__.cpython-314.pyc +0 -0
  286. package/pennyfarthing-dist/pf/workflow/__pycache__/cli.cpython-314.pyc +0 -0
  287. package/pennyfarthing-dist/pf/workflow/__pycache__/helpers.cpython-314.pyc +0 -0
  288. package/pennyfarthing-dist/pf/workflow/__pycache__/scale.cpython-314.pyc +0 -0
  289. package/pennyfarthing-dist/pf/workflow/__pycache__/state.cpython-314.pyc +0 -0
  290. package/pennyfarthing-dist/scripts/lib/find-root.sh +1 -1
  291. package/pennyfarthing-dist/scripts/misc/migrate_bmad_workflow.py +0 -1
  292. package/pennyfarthing-dist/scripts/portraits/generate-portraits.py +13 -13
  293. package/pennyfarthing-dist/scripts/workflow/check.py +4 -6
  294. package/pennyfarthing-dist/scripts/workflow/complete-step.py +2 -2
  295. package/pennyfarthing-dist/skills/skill-registry.yaml +19 -0
  296. package/pennyfarthing-dist/workflows/tdd-tandem.yaml +15 -2
  297. package/packages/core/dist/workflow/__test_context_watch__/.session/.tandem-turn-counter +0 -1
  298. package/packages/core/dist/workflow/__test_context_watch__/.session/95-6-session.md +0 -3
  299. package/packages/core/dist/workflow/__test_context_watch__/.session/95-6-tandem-architect.md +0 -6
  300. package/packages/core/dist/workflow/__test_file_watch__/.session/95-4-tandem-architect.md +0 -6
  301. package/packages/core/dist/workflow/__test_file_watch__/workdir/trigger.ts +0 -1
  302. package/packages/core/dist/workflow/__test_tool_watch__/.session/95-5-tandem-architect.md +0 -6
  303. package/packages/core/dist/workflow/__test_tool_watch__/.session/95-5-tandem-toolcalls.jsonl +0 -1
  304. package/pennyfarthing-dist/pf/bikerack/changed_panel.py +0 -201
@@ -0,0 +1,554 @@
1
+ /**
2
+ * CommandPalette Component
3
+ *
4
+ * Story MSSCI-12721 - Command Palette for keyboard-driven navigation
5
+ *
6
+ * Features:
7
+ * - Cmd+Shift+P (Mac) / Ctrl+Shift+P (Windows) to open
8
+ * - Fuzzy search filtering (via cmdk)
9
+ * - Category grouping (Panels, Navigation, Settings, Agents)
10
+ * - Keyboard shortcuts display
11
+ * - Recent commands tracking
12
+ *
13
+ * Built on shadcn Command (cmdk) + Dialog primitives.
14
+ */
15
+
16
+ import React, { createContext, useContext, useState, useCallback, useEffect } from 'react';
17
+ import {
18
+ Command as CommandPrimitive,
19
+ CommandInput,
20
+ CommandList,
21
+ CommandGroup,
22
+ CommandItem as ShadcnCommandItem,
23
+ CommandEmpty,
24
+ CommandShortcut,
25
+ } from '@/components/ui/command';
26
+ import { Dialog, DialogContent } from '@/components/ui/dialog';
27
+
28
+ // =============================================================================
29
+ // Types
30
+ // =============================================================================
31
+
32
+ export interface Command {
33
+ id: string;
34
+ name: string;
35
+ category: string;
36
+ shortcut?: string;
37
+ handler?: () => void;
38
+ }
39
+
40
+ export type CommandRegistry = Map<string, Command>;
41
+
42
+ // Runtime exports for testing (TypeScript interfaces don't exist at runtime)
43
+ export const Command = {} as const;
44
+ export const CommandRegistry = {} as const;
45
+
46
+ // =============================================================================
47
+ // Constants
48
+ // =============================================================================
49
+
50
+ export const COMMAND_PALETTE_TRIGGER = {
51
+ key: 'p',
52
+ metaKey: true,
53
+ shiftKey: true,
54
+ };
55
+
56
+ export const COMMAND_CATEGORIES = ['Panels', 'Navigation', 'Settings', 'Agents'] as const;
57
+
58
+ export const MODAL_OVERLAY_CLASS = 'command-palette-overlay';
59
+ export const SEARCH_INPUT_ID = 'command-palette-search';
60
+ export const RESULTS_LIST_ID = 'command-palette-results';
61
+ export const CATEGORY_HEADER_CLASS = 'command-palette-category-header';
62
+ export const SHORTCUT_DISPLAY_CLASS = 'command-palette-shortcut';
63
+ export const RECENT_SECTION_CLASS = 'command-palette-recent';
64
+ export const RECENT_COMMANDS_KEY = 'cyclist:recent-commands';
65
+ export const MAX_RECENT_COMMANDS = 5;
66
+
67
+ // =============================================================================
68
+ // Default Commands
69
+ // =============================================================================
70
+
71
+ export const DEFAULT_COMMANDS: Command[] = [
72
+ // Panels
73
+ { id: 'toggle-diffs-panel', name: 'Toggle Diffs', category: 'Panels', shortcut: 'Cmd+Shift+1' },
74
+ { id: 'toggle-message-panel', name: 'Toggle Messages', category: 'Panels', shortcut: 'Cmd+Shift+3' },
75
+ { id: 'toggle-debug-panel', name: 'Toggle Debug', category: 'Panels' },
76
+
77
+ // Navigation
78
+ { id: 'focus-input', name: 'Focus Input', category: 'Navigation', shortcut: 'Cmd+L' },
79
+ { id: 'scroll-to-bottom', name: 'Scroll to Bottom', category: 'Navigation', shortcut: 'Cmd+End' },
80
+ { id: 'scroll-to-top', name: 'Scroll to Top', category: 'Navigation', shortcut: 'Cmd+Home' },
81
+
82
+ // Settings
83
+ { id: 'open-settings', name: 'Open Settings', category: 'Settings', shortcut: 'Cmd+,' },
84
+ { id: 'toggle-theme', name: 'Toggle Theme', category: 'Settings' },
85
+
86
+ // Agents
87
+ { id: 'run-sm', name: 'Start Scrum Master', category: 'Agents' },
88
+ { id: 'run-tea', name: 'Start TEA', category: 'Agents' },
89
+ { id: 'run-dev', name: 'Start Dev', category: 'Agents' },
90
+ { id: 'run-reviewer', name: 'Start Reviewer', category: 'Agents' },
91
+ ];
92
+
93
+ // =============================================================================
94
+ // Selection State (module-level for imperative access)
95
+ // =============================================================================
96
+
97
+ let selectedIndex = 0;
98
+
99
+ export function getSelectedIndex(): number {
100
+ return selectedIndex;
101
+ }
102
+
103
+ export function setSelectedIndex(index: number): void {
104
+ selectedIndex = index;
105
+ }
106
+
107
+ export function handleArrowDown(listLength: number): void {
108
+ selectedIndex = (selectedIndex + 1) % listLength;
109
+ }
110
+
111
+ export function handleArrowUp(listLength: number): void {
112
+ selectedIndex = selectedIndex === 0 ? listLength - 1 : selectedIndex - 1;
113
+ }
114
+
115
+ export function scrollSelectedIntoView(): void {
116
+ const selectedEl = document.querySelector(`[data-command-index="${selectedIndex}"]`);
117
+ selectedEl?.scrollIntoView({ block: 'nearest' });
118
+ }
119
+
120
+ // =============================================================================
121
+ // Platform Detection
122
+ // =============================================================================
123
+
124
+ export function detectPlatform(): 'mac' | 'windows' | 'linux' {
125
+ if (typeof navigator === 'undefined') return 'mac';
126
+ const platform = navigator.platform?.toLowerCase() || '';
127
+ if (platform.includes('mac')) return 'mac';
128
+ if (platform.includes('win')) return 'windows';
129
+ return 'linux';
130
+ }
131
+
132
+ // =============================================================================
133
+ // Keyboard Trigger Detection
134
+ // =============================================================================
135
+
136
+ export function isCommandPaletteTrigger(event: KeyboardEvent): boolean {
137
+ const isP = event.key.toLowerCase() === 'p';
138
+ const hasModifier = event.metaKey || event.ctrlKey;
139
+ const hasShift = event.shiftKey;
140
+ return isP && hasModifier && hasShift;
141
+ }
142
+
143
+ // =============================================================================
144
+ // Shortcut Formatting
145
+ // =============================================================================
146
+
147
+ export function formatShortcut(shortcut: string, platform: 'mac' | 'windows' | 'linux'): string {
148
+ if (platform === 'mac') {
149
+ return shortcut
150
+ .replace(/Cmd/g, '\u2318')
151
+ .replace(/Shift/g, '\u21E7')
152
+ .replace(/Alt/g, '\u2325')
153
+ .replace(/Ctrl/g, '\u2303')
154
+ .replace(/\+/g, '');
155
+ }
156
+ // Windows/Linux: Keep text but replace Cmd with Ctrl
157
+ return shortcut.replace(/Cmd/g, 'Ctrl');
158
+ }
159
+
160
+ // =============================================================================
161
+ // Command Filtering
162
+ // =============================================================================
163
+
164
+ export function filterCommands(commands: Command[], query: string): Command[] {
165
+ if (!query.trim()) return commands;
166
+
167
+ const lowerQuery = query.toLowerCase();
168
+
169
+ // Score each command for fuzzy matching
170
+ const scored = commands.map(cmd => {
171
+ const lowerName = cmd.name.toLowerCase();
172
+ const lowerId = cmd.id.toLowerCase();
173
+
174
+ // Exact match in name or id
175
+ if (lowerName.includes(lowerQuery) || lowerId.includes(lowerQuery)) {
176
+ // Prioritize matches at start
177
+ const startsWithBonus = lowerName.startsWith(lowerQuery) ? 100 : 0;
178
+ return { cmd, score: 50 + startsWithBonus };
179
+ }
180
+
181
+ // Fuzzy match: check if all query chars appear in order
182
+ let queryIdx = 0;
183
+ let consecutiveBonus = 0;
184
+ let lastMatchIdx = -1;
185
+
186
+ for (let i = 0; i < lowerName.length && queryIdx < lowerQuery.length; i++) {
187
+ if (lowerName[i] === lowerQuery[queryIdx]) {
188
+ if (lastMatchIdx === i - 1) consecutiveBonus += 5;
189
+ lastMatchIdx = i;
190
+ queryIdx++;
191
+ }
192
+ }
193
+
194
+ if (queryIdx === lowerQuery.length) {
195
+ return { cmd, score: 10 + consecutiveBonus };
196
+ }
197
+
198
+ return { cmd, score: 0 };
199
+ });
200
+
201
+ return scored
202
+ .filter(s => s.score > 0)
203
+ .sort((a, b) => b.score - a.score)
204
+ .map(s => s.cmd);
205
+ }
206
+
207
+ export function highlightMatch(text: string, query: string): string {
208
+ if (!query) return text;
209
+
210
+ const lowerText = text.toLowerCase();
211
+ const lowerQuery = query.toLowerCase();
212
+ let result = '';
213
+ let queryIdx = 0;
214
+
215
+ for (let i = 0; i < text.length; i++) {
216
+ if (queryIdx < lowerQuery.length && lowerText[i] === lowerQuery[queryIdx]) {
217
+ result += `<mark>${text[i]}</mark>`;
218
+ queryIdx++;
219
+ } else {
220
+ result += text[i];
221
+ }
222
+ }
223
+
224
+ return result;
225
+ }
226
+
227
+ // =============================================================================
228
+ // Category Functions
229
+ // =============================================================================
230
+
231
+ export function groupByCategory(commands: Command[]): Record<string, Command[]> {
232
+ const grouped: Record<string, Command[]> = {};
233
+ for (const cmd of commands) {
234
+ if (!grouped[cmd.category]) {
235
+ grouped[cmd.category] = [];
236
+ }
237
+ grouped[cmd.category].push(cmd);
238
+ }
239
+ return grouped;
240
+ }
241
+
242
+ export function filterByCategory(commands: Command[], category: string): Command[] {
243
+ return commands.filter(cmd => cmd.category === category);
244
+ }
245
+
246
+ // =============================================================================
247
+ // Command Validation
248
+ // =============================================================================
249
+
250
+ export function validateCommand(cmd: unknown): boolean {
251
+ if (!cmd || typeof cmd !== 'object') return false;
252
+ const c = cmd as Record<string, unknown>;
253
+ return (
254
+ typeof c.id === 'string' &&
255
+ typeof c.name === 'string' &&
256
+ typeof c.category === 'string'
257
+ );
258
+ }
259
+
260
+ // =============================================================================
261
+ // Command Execution
262
+ // =============================================================================
263
+
264
+ export function executeCommand(command: Command): void {
265
+ addToRecent(command.id);
266
+ if (command.handler) {
267
+ command.handler();
268
+ }
269
+ }
270
+
271
+ // =============================================================================
272
+ // Recent Commands (localStorage)
273
+ // =============================================================================
274
+
275
+ export function getRecentCommands(): string[] {
276
+ if (typeof localStorage === 'undefined') return [];
277
+ try {
278
+ const stored = localStorage.getItem(RECENT_COMMANDS_KEY);
279
+ return stored ? JSON.parse(stored) : [];
280
+ } catch {
281
+ return [];
282
+ }
283
+ }
284
+
285
+ export function addToRecent(commandId: string): void {
286
+ if (typeof localStorage === 'undefined') return;
287
+ const recent = getRecentCommands().filter(id => id !== commandId);
288
+ recent.unshift(commandId);
289
+ const trimmed = recent.slice(0, MAX_RECENT_COMMANDS);
290
+ localStorage.setItem(RECENT_COMMANDS_KEY, JSON.stringify(trimmed));
291
+ }
292
+
293
+ export function clearRecentCommands(): void {
294
+ if (typeof localStorage === 'undefined') return;
295
+ localStorage.removeItem(RECENT_COMMANDS_KEY);
296
+ }
297
+
298
+ export function sortWithRecentFirst(commands: Command[]): Command[] {
299
+ const recent = getRecentCommands();
300
+ const recentSet = new Set(recent);
301
+
302
+ const recentCmds = commands.filter(c => recentSet.has(c.id));
303
+ const otherCmds = commands.filter(c => !recentSet.has(c.id));
304
+
305
+ // Sort recent commands by their order in recent list
306
+ recentCmds.sort((a, b) => recent.indexOf(a.id) - recent.indexOf(b.id));
307
+
308
+ return [...recentCmds, ...otherCmds];
309
+ }
310
+
311
+ // =============================================================================
312
+ // Command Registry
313
+ // =============================================================================
314
+
315
+ const commandRegistry: CommandRegistry = new Map();
316
+
317
+ export function registerCommand(command: Command): void {
318
+ commandRegistry.set(command.id, command);
319
+ }
320
+
321
+ // Initialize default commands
322
+ DEFAULT_COMMANDS.forEach(cmd => registerCommand(cmd));
323
+
324
+ // =============================================================================
325
+ // Context and Provider
326
+ // =============================================================================
327
+
328
+ interface CommandPaletteContextValue {
329
+ isOpen: boolean;
330
+ open: () => void;
331
+ close: () => void;
332
+ toggle: () => void;
333
+ }
334
+
335
+ const CommandPaletteContext = createContext<CommandPaletteContextValue | null>(null);
336
+
337
+ export function useCommandPaletteContext(): CommandPaletteContextValue {
338
+ const ctx = useContext(CommandPaletteContext);
339
+ if (!ctx) {
340
+ throw new Error('useCommandPaletteContext must be used within CommandPaletteProvider');
341
+ }
342
+ return ctx;
343
+ }
344
+
345
+ export function useCommandPalette() {
346
+ const [isOpen, setIsOpen] = useState(false);
347
+ const [commands] = useState<Command[]>(DEFAULT_COMMANDS);
348
+
349
+ const open = useCallback(() => {
350
+ setIsOpen(true);
351
+ setSelectedIndex(0);
352
+ }, []);
353
+
354
+ const close = useCallback(() => {
355
+ setIsOpen(false);
356
+ }, []);
357
+
358
+ const toggle = useCallback(() => {
359
+ if (isOpen) close();
360
+ else open();
361
+ }, [isOpen, open, close]);
362
+
363
+ return {
364
+ isOpen,
365
+ open,
366
+ close,
367
+ toggle,
368
+ commands,
369
+ selectedIndex: getSelectedIndex(),
370
+ };
371
+ }
372
+
373
+ // =============================================================================
374
+ // Global Keyboard Listener
375
+ // =============================================================================
376
+
377
+ let globalListenerSetup = false;
378
+ let globalOpenCallback: (() => void) | null = null;
379
+
380
+ export function setupGlobalKeyboardListener(openCallback: () => void): () => void {
381
+ globalOpenCallback = openCallback;
382
+
383
+ if (!globalListenerSetup) {
384
+ const handler = (event: KeyboardEvent) => {
385
+ if (isCommandPaletteTrigger(event)) {
386
+ event.preventDefault();
387
+ globalOpenCallback?.();
388
+ }
389
+ };
390
+
391
+ document.addEventListener('keydown', handler);
392
+ globalListenerSetup = true;
393
+
394
+ return () => {
395
+ document.removeEventListener('keydown', handler);
396
+ globalListenerSetup = false;
397
+ globalOpenCallback = null;
398
+ };
399
+ }
400
+
401
+ return () => {
402
+ globalOpenCallback = null;
403
+ };
404
+ }
405
+
406
+ export function focusSearchInput(): void {
407
+ const input = document.getElementById(SEARCH_INPUT_ID);
408
+ input?.focus();
409
+ }
410
+
411
+ export function closePalette(): void {
412
+ // This is called imperatively; the actual close is handled by the component
413
+ const event = new CustomEvent('cyclist:close-command-palette');
414
+ document.dispatchEvent(event);
415
+ }
416
+
417
+ // =============================================================================
418
+ // Provider Component
419
+ // =============================================================================
420
+
421
+ export function CommandPaletteProvider({ children }: { children: React.ReactNode }) {
422
+ const palette = useCommandPalette();
423
+
424
+ useEffect(() => {
425
+ const cleanup = setupGlobalKeyboardListener(palette.open);
426
+ return cleanup;
427
+ }, [palette.open]);
428
+
429
+ useEffect(() => {
430
+ const handleClose = () => palette.close();
431
+ document.addEventListener('cyclist:close-command-palette', handleClose);
432
+ return () => document.removeEventListener('cyclist:close-command-palette', handleClose);
433
+ }, [palette.close]);
434
+
435
+ const handleExecute = useCallback((cmd: Command) => {
436
+ executeCommand(cmd);
437
+ palette.close();
438
+ }, [palette.close]);
439
+
440
+ const value: CommandPaletteContextValue = {
441
+ isOpen: palette.isOpen,
442
+ open: palette.open,
443
+ close: palette.close,
444
+ toggle: palette.toggle,
445
+ };
446
+
447
+ return (
448
+ <CommandPaletteContext.Provider value={value}>
449
+ {children}
450
+ <CommandPalette
451
+ commands={palette.commands}
452
+ isOpen={palette.isOpen}
453
+ onClose={palette.close}
454
+ onExecute={handleExecute}
455
+ />
456
+ </CommandPaletteContext.Provider>
457
+ );
458
+ }
459
+
460
+ // =============================================================================
461
+ // CommandPalette Component (shadcn CommandDialog)
462
+ // =============================================================================
463
+
464
+ interface CommandPaletteProps {
465
+ query?: string;
466
+ setQuery?: (q: string) => void;
467
+ commands: Command[];
468
+ onClose: () => void;
469
+ onExecute: (cmd: Command) => void;
470
+ isOpen?: boolean;
471
+ }
472
+
473
+ function CommandPalette({
474
+ commands,
475
+ onClose,
476
+ onExecute,
477
+ isOpen = true,
478
+ }: CommandPaletteProps): React.ReactElement {
479
+ const platform = detectPlatform();
480
+ const recentIds = getRecentCommands();
481
+ const grouped = groupByCategory(commands);
482
+ const recentCommands = commands.filter(c => recentIds.includes(c.id));
483
+
484
+ return (
485
+ <Dialog open={isOpen} onOpenChange={(open) => { if (!open) onClose(); }}>
486
+ <DialogContent
487
+ className="overflow-hidden p-0"
488
+ aria-label="Command palette"
489
+ >
490
+ <CommandPrimitive className="[&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-2 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5">
491
+ <CommandInput
492
+ placeholder="Type a command..."
493
+ id={SEARCH_INPUT_ID}
494
+ aria-label="Search commands"
495
+ />
496
+ <CommandList id={RESULTS_LIST_ID}>
497
+ <CommandEmpty>No matching commands</CommandEmpty>
498
+
499
+ {/* Recent Section */}
500
+ {recentCommands.length > 0 && (
501
+ <CommandGroup heading="Recent" className={RECENT_SECTION_CLASS}>
502
+ {recentCommands.map((cmd) => (
503
+ <ShadcnCommandItem
504
+ key={`recent-${cmd.id}`}
505
+ value={cmd.name}
506
+ onSelect={() => onExecute(cmd)}
507
+ className="command-palette-item"
508
+ >
509
+ <span>{cmd.name}</span>
510
+ {cmd.shortcut && (
511
+ <CommandShortcut className={SHORTCUT_DISPLAY_CLASS}>
512
+ {formatShortcut(cmd.shortcut, platform)}
513
+ </CommandShortcut>
514
+ )}
515
+ </ShadcnCommandItem>
516
+ ))}
517
+ </CommandGroup>
518
+ )}
519
+
520
+ {/* Grouped by Category */}
521
+ {COMMAND_CATEGORIES.map(category => {
522
+ const categoryCommands = grouped[category];
523
+ if (!categoryCommands?.length) return null;
524
+
525
+ return (
526
+ <CommandGroup key={category} heading={category}>
527
+ {categoryCommands.map((cmd) => (
528
+ <ShadcnCommandItem
529
+ key={cmd.id}
530
+ value={cmd.name}
531
+ onSelect={() => onExecute(cmd)}
532
+ className="command-palette-item"
533
+ >
534
+ <span>{cmd.name}</span>
535
+ {cmd.shortcut && (
536
+ <CommandShortcut className={SHORTCUT_DISPLAY_CLASS}>
537
+ {formatShortcut(cmd.shortcut, platform)}
538
+ </CommandShortcut>
539
+ )}
540
+ </ShadcnCommandItem>
541
+ ))}
542
+ </CommandGroup>
543
+ );
544
+ })}
545
+ </CommandList>
546
+ </CommandPrimitive>
547
+ </DialogContent>
548
+ </Dialog>
549
+ );
550
+ }
551
+
552
+ // Named and default exports
553
+ export { CommandPalette };
554
+ export default CommandPalette;