@pennyfarthing/core 11.3.7 → 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.
- package/README.md +1 -1
- package/package.json +17 -16
- package/packages/core/dist/public/css/react.css +1 -1
- package/packages/core/dist/public/js/react/react.js +24 -24
- package/packages/core/src/public/App.tsx +356 -0
- package/packages/core/src/public/components/AgentLoadDialog.tsx +202 -0
- package/packages/core/src/public/components/AgentPopup.tsx +308 -0
- package/packages/core/src/public/components/ApprovalModal/ApprovalModal.css +35 -0
- package/packages/core/src/public/components/ApprovalModal/index.tsx +632 -0
- package/packages/core/src/public/components/BikeRackIndex.tsx +53 -0
- package/packages/core/src/public/components/BikeRackWorkspace.tsx +217 -0
- package/packages/core/src/public/components/CommandPalette.tsx +554 -0
- package/packages/core/src/public/components/ConfirmDialog.tsx +168 -0
- package/packages/core/src/public/components/ContextIndicator/ContextIndicator.css +85 -0
- package/packages/core/src/public/components/ContextIndicator/index.tsx +330 -0
- package/packages/core/src/public/components/ContextSparkline.tsx +56 -0
- package/packages/core/src/public/components/ControlBar.tsx +636 -0
- package/packages/core/src/public/components/DeadCodeDialog.tsx +169 -0
- package/packages/core/src/public/components/DiffViewer.tsx +585 -0
- package/packages/core/src/public/components/DockviewWorkspace.tsx +749 -0
- package/packages/core/src/public/components/Editor.tsx +630 -0
- package/packages/core/src/public/components/ErrorBoundary.tsx +67 -0
- package/packages/core/src/public/components/FileTree.tsx +379 -0
- package/packages/core/src/public/components/FontPicker/FontPicker.css +276 -0
- package/packages/core/src/public/components/FontPicker/index.tsx +430 -0
- package/packages/core/src/public/components/FullFileTree.tsx +237 -0
- package/packages/core/src/public/components/HealthGauge.tsx +181 -0
- package/packages/core/src/public/components/Message.tsx +225 -0
- package/packages/core/src/public/components/MessageList.tsx +98 -0
- package/packages/core/src/public/components/MessageView.tsx +400 -0
- package/packages/core/src/public/components/ModeSwitch/ModeSwitch.css +165 -0
- package/packages/core/src/public/components/ModeSwitch/index.tsx +372 -0
- package/packages/core/src/public/components/PersonaHeader.tsx +242 -0
- package/packages/core/src/public/components/ProjectInfoBar.tsx +45 -0
- package/packages/core/src/public/components/QuickActions.tsx +267 -0
- package/packages/core/src/public/components/SpanTimeline.tsx +352 -0
- package/packages/core/src/public/components/StandalonePanel.tsx +82 -0
- package/packages/core/src/public/components/StatsStrip.tsx +162 -0
- package/packages/core/src/public/components/StreamingContent.tsx +77 -0
- package/packages/core/src/public/components/SubagentSpan.tsx +180 -0
- package/packages/core/src/public/components/TandemPortrait.tsx +72 -0
- package/packages/core/src/public/components/ThemePalette/ThemePalette.css +179 -0
- package/packages/core/src/public/components/ThemePalette/index.tsx +326 -0
- package/packages/core/src/public/components/ToolCallBlock.tsx +252 -0
- package/packages/core/src/public/components/ToolStack.tsx +209 -0
- package/packages/core/src/public/components/ToolStatus.tsx +57 -0
- package/packages/core/src/public/components/dialogs/CodeMarkersDialog.tsx +169 -0
- package/packages/core/src/public/components/dialogs/ComplexityDialog.tsx +163 -0
- package/packages/core/src/public/components/dialogs/DependenciesDialog.tsx +120 -0
- package/packages/core/src/public/components/dialogs/HotspotsDialog.tsx +451 -0
- package/packages/core/src/public/components/dialogs/ToolDialog.tsx +43 -0
- package/packages/core/src/public/components/panel-registry.ts +13 -0
- package/packages/core/src/public/components/panels/ACPanel.tsx +93 -0
- package/packages/core/src/public/components/panels/AcceptanceCriteriaPanel.tsx +104 -0
- package/packages/core/src/public/components/panels/AuditLogPanel.tsx +489 -0
- package/packages/core/src/public/components/panels/BackgroundPanel.tsx +115 -0
- package/packages/core/src/public/components/panels/BikeLanePanel.tsx +214 -0
- package/packages/core/src/public/components/panels/DebugPanel.tsx +344 -0
- package/packages/core/src/public/components/panels/DiffView.tsx +109 -0
- package/packages/core/src/public/components/panels/DiffsPanel.tsx +56 -0
- package/packages/core/src/public/components/panels/GitPanel.tsx +260 -0
- package/packages/core/src/public/components/panels/HotspotsPanel.tsx +365 -0
- package/packages/core/src/public/components/panels/MessageFeed.tsx +39 -0
- package/packages/core/src/public/components/panels/MessagePanel.tsx +497 -0
- package/packages/core/src/public/components/panels/ProgressPanel.tsx +189 -0
- package/packages/core/src/public/components/panels/SettingsPanel.tsx +361 -0
- package/packages/core/src/public/components/panels/SprintPanel.tsx +723 -0
- package/packages/core/src/public/components/panels/TandemPanel.tsx +104 -0
- package/packages/core/src/public/components/panels/TaskTracker.tsx +48 -0
- package/packages/core/src/public/components/panels/TeamPanel.tsx +64 -0
- package/packages/core/src/public/components/panels/TeamRoster.tsx +67 -0
- package/packages/core/src/public/components/panels/TodoPanel.tsx +142 -0
- package/packages/core/src/public/components/panels/WorkflowPanel.tsx +224 -0
- package/packages/core/src/public/components/panels/index.ts +24 -0
- package/packages/core/src/public/components/ui/alert-dialog.tsx +139 -0
- package/packages/core/src/public/components/ui/badge.tsx +36 -0
- package/packages/core/src/public/components/ui/button.tsx +57 -0
- package/packages/core/src/public/components/ui/checkbox.tsx +28 -0
- package/packages/core/src/public/components/ui/collapsible.tsx +9 -0
- package/packages/core/src/public/components/ui/command.tsx +151 -0
- package/packages/core/src/public/components/ui/dialog.tsx +120 -0
- package/packages/core/src/public/components/ui/popover.tsx +31 -0
- package/packages/core/src/public/components/ui/progress.tsx +28 -0
- package/packages/core/src/public/components/ui/scroll-area.tsx +46 -0
- package/packages/core/src/public/components/ui/select.tsx +157 -0
- package/packages/core/src/public/components/ui/separator.tsx +29 -0
- package/packages/core/src/public/components/ui/skeleton.tsx +15 -0
- package/packages/core/src/public/components/ui/switch.tsx +27 -0
- package/packages/core/src/public/components/ui/toggle-group.tsx +59 -0
- package/packages/core/src/public/components/ui/toggle.tsx +43 -0
- package/packages/core/src/public/components/ui/tooltip.tsx +30 -0
- package/packages/core/src/public/contexts/ClaudeContext.tsx +311 -0
- package/packages/core/src/public/contexts/MessageQueueContext.tsx +143 -0
- package/packages/core/src/public/css/theme-browser.css +550 -0
- package/packages/core/src/public/css/theme-system.css +630 -0
- package/packages/core/src/public/hooks/index.ts +49 -0
- package/packages/core/src/public/hooks/useAgentLoad.ts +105 -0
- package/packages/core/src/public/hooks/useBackgroundTasks.ts +131 -0
- package/packages/core/src/public/hooks/useClaude.ts +234 -0
- package/packages/core/src/public/hooks/useCodeMarkers.ts +101 -0
- package/packages/core/src/public/hooks/useColorScheme.ts +42 -0
- package/packages/core/src/public/hooks/useCommandHistory.ts +99 -0
- package/packages/core/src/public/hooks/useComplexity.ts +80 -0
- package/packages/core/src/public/hooks/useDeadCode.ts +99 -0
- package/packages/core/src/public/hooks/useDependencies.ts +82 -0
- package/packages/core/src/public/hooks/useDiffs.ts +143 -0
- package/packages/core/src/public/hooks/useFileBrowser.ts +73 -0
- package/packages/core/src/public/hooks/useFocusPanel.ts +137 -0
- package/packages/core/src/public/hooks/useGitStatus.ts +233 -0
- package/packages/core/src/public/hooks/useHealthScore.ts +71 -0
- package/packages/core/src/public/hooks/useHotspots.ts +123 -0
- package/packages/core/src/public/hooks/useLayoutPersistence.ts +141 -0
- package/packages/core/src/public/hooks/useMarkdownParser.ts +36 -0
- package/packages/core/src/public/hooks/useMarkerActions.ts +234 -0
- package/packages/core/src/public/hooks/useMessageQueue.ts +380 -0
- package/packages/core/src/public/hooks/useMessageStream.ts +131 -0
- package/packages/core/src/public/hooks/usePersona.ts +112 -0
- package/packages/core/src/public/hooks/usePlanModeExit.ts +105 -0
- package/packages/core/src/public/hooks/useResponsiveLayout.ts +173 -0
- package/packages/core/src/public/hooks/useSprint.ts +157 -0
- package/packages/core/src/public/hooks/useStatsStrip.ts +204 -0
- package/packages/core/src/public/hooks/useStory.ts +135 -0
- package/packages/core/src/public/hooks/useSubagentHelper.ts +64 -0
- package/packages/core/src/public/hooks/useSyntaxHighlighter.ts +52 -0
- package/packages/core/src/public/hooks/useTabCompletion.ts +124 -0
- package/packages/core/src/public/hooks/useTandemObservations.ts +165 -0
- package/packages/core/src/public/hooks/useTeamMembers.ts +273 -0
- package/packages/core/src/public/hooks/useTodos.ts +93 -0
- package/packages/core/src/public/hooks/useUserAvatar.ts +54 -0
- package/packages/core/src/public/images/cyclist-dark.png +0 -0
- package/packages/core/src/public/images/cyclist-light.png +0 -0
- package/packages/core/src/public/index.html +14 -0
- package/packages/core/src/public/index.tsx +10 -0
- package/packages/core/src/public/lib/utils.ts +6 -0
- package/packages/core/src/public/styles/dockview-theme.css +376 -0
- package/packages/core/src/public/styles/tailwind.css +4454 -0
- package/packages/core/src/public/types/message.ts +51 -0
- package/packages/core/src/public/utils/avatar-service.ts +73 -0
- package/packages/core/src/public/utils/color-presets.ts +940 -0
- package/packages/core/src/public/utils/font-presets.ts +362 -0
- package/packages/core/src/public/utils/formatDuration.ts +14 -0
- package/packages/core/src/public/utils/markdown.ts +249 -0
- package/packages/core/src/public/utils/messageFilters.ts +128 -0
- package/packages/core/src/public/utils/slash-commands.ts +341 -0
- package/packages/core/src/public/utils/subagent-display.ts +146 -0
- package/packages/core/src/public/utils/syntax.ts +219 -0
- package/packages/core/src/public/utils/toolIntentSummarizer.ts +199 -0
- package/packages/core/src/public/utils/toolStackGrouper.ts +106 -0
- package/packages/core/src/public/utils/toolTypeColors.ts +45 -0
- package/pennyfarthing-dist/pf/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/__pycache__/context.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/bc/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/bc/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/bc/__pycache__/focus.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/bc/__pycache__/split.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/bc/cli.py +0 -1
- package/pennyfarthing-dist/pf/bc/focus.py +0 -1
- package/pennyfarthing-dist/pf/bikerack/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/bikerack/__pycache__/base_panel.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/bikerack/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/bikerack/__pycache__/git_panel.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/bikerack/__pycache__/launcher.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/bikerack/__pycache__/portrait_resolver.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/bikerack/__pycache__/sprint_panel.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/bikerack/__pycache__/story_detail_data.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/bikerack/__pycache__/story_detail_screen.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/bikerack/__pycache__/tui.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/bikerack/base_panel.py +0 -1
- package/pennyfarthing-dist/pf/bikerack/events.py +1 -7
- package/pennyfarthing-dist/pf/bikerack/git_panel.py +273 -10
- package/pennyfarthing-dist/pf/bikerack/portrait_resolver.py +21 -0
- package/pennyfarthing-dist/pf/bikerack/sprint_panel.py +58 -1
- package/pennyfarthing-dist/pf/bikerack/tui.py +5 -20
- package/pennyfarthing-dist/pf/bmad/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/bmad/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/bmad/__pycache__/parser.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/bmad/parser.py +15 -9
- package/pennyfarthing-dist/pf/codemarkers/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/codemarkers/__pycache__/analyze.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/codemarkers/__pycache__/models.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/common/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/common/__pycache__/config.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/common/__pycache__/output.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/common/__pycache__/pr_config.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/common/__pycache__/themes.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/common/pr_config.py +27 -2
- package/pennyfarthing-dist/pf/complexity/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/complexity/__pycache__/analyze.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/complexity/__pycache__/models.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/consultation/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/consultation/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/deadcode/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/deadcode/__pycache__/analyze.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/deadcode/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/deadcode/__pycache__/models.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/dependencies/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/dependencies/__pycache__/analyze.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/dependencies/__pycache__/models.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/epic/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/epic/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/git_group/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/git_group/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/handoff/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/handoff/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/handoff/__pycache__/complete_phase.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/handoff/__pycache__/marker.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/handoff/__pycache__/phase_check.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/handoff/__pycache__/resolve_gate.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/healthscore/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/healthscore/__pycache__/__main__.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/healthscore/__pycache__/analyze.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/healthscore/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/healthscore/__pycache__/formatters.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/healthscore/__pycache__/models.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/hooks/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/hooks/__pycache__/bell_mode.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/hooks/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/hooks/__pycache__/context_breaker.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/hooks/__pycache__/context_warning.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/hooks/__pycache__/cyclist_pretooluse.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/hooks/__pycache__/pre_edit_check.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/hooks/__pycache__/reflector_check.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/hooks/__pycache__/schema_validation.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/hooks/__pycache__/session_start.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/hooks/__pycache__/session_stop.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/hooks/__pycache__/sprint_yaml_validation.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/hooks/__pycache__/statusline.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/hooks/cyclist-pretooluse-hook.sh +0 -0
- package/pennyfarthing-dist/pf/hotspots/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/hotspots/__pycache__/analyze.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/hotspots/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/hotspots/__pycache__/models.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/jira/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/jira/__pycache__/bidirectional.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/jira/__pycache__/claim.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/jira/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/jira/__pycache__/client.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/jira/__pycache__/create.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/jira/__pycache__/epic.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/jira/__pycache__/operations.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/jira/__pycache__/reconcile.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/jira/__pycache__/story.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/jira/__pycache__/sync.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/launch/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/launch/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/prime/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/prime/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/prime/__pycache__/loader.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/prime/__pycache__/models.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/prime/__pycache__/persona.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/prime/__pycache__/session.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/prime/__pycache__/tiers.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/prime/__pycache__/workflow.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/session/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/session/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/settings/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/settings/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/settings/__pycache__/settings.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/settings/settings.py +44 -8
- package/pennyfarthing-dist/pf/sprint/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/sprint/__pycache__/archive.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/sprint/__pycache__/archive_epic.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/sprint/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/sprint/__pycache__/epic_add.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/sprint/__pycache__/epic_update.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/sprint/__pycache__/loader.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/sprint/__pycache__/status.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/sprint/__pycache__/story_add.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/sprint/__pycache__/story_finish.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/sprint/__pycache__/story_update.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/sprint/__pycache__/validate_cmd.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/sprint/__pycache__/validator.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/sprint/__pycache__/work.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/sprint/__pycache__/yaml_io.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/sprint/story_finish.py +14 -2
- package/pennyfarthing-dist/pf/sprint/validator.py +7 -7
- package/pennyfarthing-dist/pf/tests/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/tests/__pycache__/conftest.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing-dist/pf/tests/__pycache__/test_sprint_validator.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing-dist/pf/tests/test_sprint_validator.py +44 -0
- package/pennyfarthing-dist/pf/theme/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/theme/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/validate/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/validate/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/workflow/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/workflow/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/workflow/__pycache__/helpers.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/workflow/__pycache__/scale.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/pf/workflow/__pycache__/state.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/scripts/core/agent-session.sh +0 -0
- package/pennyfarthing-dist/scripts/core/check-context.sh +0 -0
- package/pennyfarthing-dist/scripts/core/dialogue-manager.sh +0 -0
- package/pennyfarthing-dist/scripts/core/pf.sh +0 -0
- package/pennyfarthing-dist/scripts/core/phase-check-start.sh +0 -0
- package/pennyfarthing-dist/scripts/core/prime.sh +0 -0
- package/pennyfarthing-dist/scripts/cyclist/is-cyclist.sh +0 -0
- package/pennyfarthing-dist/scripts/git/create-feature-branches.sh +0 -0
- package/pennyfarthing-dist/scripts/git/git-status-all.sh +0 -0
- package/pennyfarthing-dist/scripts/git/install-git-hooks.sh +0 -0
- package/pennyfarthing-dist/scripts/git/release.sh +0 -0
- package/pennyfarthing-dist/scripts/git/worktree-manager.sh +0 -0
- package/pennyfarthing-dist/scripts/health/drift-detection.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/bell-mode-hook.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/context-circuit-breaker.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/context-warning.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/cyclist-pretooluse-hook.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/dispatcher-template.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/otel-auto-config.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/post-merge.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/pre-commit.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/pre-edit-check.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/pre-push.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/question-reflector-check.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/question_reflector_check.py +0 -0
- package/pennyfarthing-dist/scripts/hooks/schema-validation.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/session-start.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/session-stop.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/sprint-yaml-validation.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/welcome-hook.sh +0 -0
- package/pennyfarthing-dist/scripts/jira/create-jira-epic.sh +0 -0
- package/pennyfarthing-dist/scripts/jira/create-jira-story.sh +0 -0
- package/pennyfarthing-dist/scripts/jira/jira-claim-story.sh +0 -0
- package/pennyfarthing-dist/scripts/jira/jira-reconcile.sh +0 -0
- package/pennyfarthing-dist/scripts/jira/jira-sync-story.sh +0 -0
- package/pennyfarthing-dist/scripts/jira/sync-epic-jira.sh +0 -0
- package/pennyfarthing-dist/scripts/lib/background-tasks.sh +0 -0
- package/pennyfarthing-dist/scripts/lib/checkpoint.sh +0 -0
- package/pennyfarthing-dist/scripts/lib/common.sh +0 -0
- package/pennyfarthing-dist/scripts/lib/env.sh +0 -0
- package/pennyfarthing-dist/scripts/lib/file-lock.sh +0 -0
- package/pennyfarthing-dist/scripts/lib/find-root.sh +1 -1
- package/pennyfarthing-dist/scripts/lib/logging.sh +0 -0
- package/pennyfarthing-dist/scripts/lib/retry.sh +0 -0
- package/pennyfarthing-dist/scripts/lib/run-pf.sh +0 -0
- package/pennyfarthing-dist/scripts/maintenance/migrate-theme-schema.mjs +0 -0
- package/pennyfarthing-dist/scripts/maintenance/sidecar-health.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/add-short-names.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/add_short_names.py +0 -0
- package/pennyfarthing-dist/scripts/misc/backlog.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/check-status.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/find-related-work.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/generate-skill-docs.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/log-skill-usage.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/migrate-bmad-workflow.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/migrate_bmad_workflow.py +0 -1
- package/pennyfarthing-dist/scripts/misc/repo-scan.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/repo-utils.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/run-ci.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/run-timestamp.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/session-cleanup.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/skill-usage-report.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/statusline.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/uninstall.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/validate-subagent-frontmatter.sh +0 -0
- package/pennyfarthing-dist/scripts/portraits/generate-portraits.py +13 -13
- package/pennyfarthing-dist/scripts/portraits/generate-portraits.sh +0 -0
- package/pennyfarthing-dist/scripts/portraits/generate-tandem-portraits.sh +0 -0
- package/pennyfarthing-dist/scripts/story/create-story.sh +0 -0
- package/pennyfarthing-dist/scripts/story/size-story.sh +0 -0
- package/pennyfarthing-dist/scripts/story/story-template.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/check.test.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/dev-story-workflow-import.test.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/epics-and-stories-workflow-import.test.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/handoff-phase-update.test.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/implementation-readiness-workflow-import.test.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/migrate-bmad-workflow.test.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/prd-workflow-import.test.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/project-context-workflow-import.test.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/test-character-voice.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/test-drift-detection.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/test-post-merge-hook.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/test-session-checkpoint.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/test-solo-command.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/ux-design-workflow-import.test.sh +0 -0
- package/pennyfarthing-dist/scripts/theme/list-themes.sh +0 -0
- package/pennyfarthing-dist/scripts/validation/validate-agent-schema.sh +0 -0
- package/pennyfarthing-dist/scripts/workflow/check.py +4 -6
- package/pennyfarthing-dist/scripts/workflow/check.sh +0 -0
- package/pennyfarthing-dist/scripts/workflow/complete-step.py +2 -2
- package/pennyfarthing-dist/scripts/workflow/finish-story.sh +0 -0
- package/pennyfarthing-dist/scripts/workflow/fix-session-phase.sh +0 -0
- package/pennyfarthing-dist/scripts/workflow/get-workflow-type.py +0 -0
- package/pennyfarthing-dist/scripts/workflow/get-workflow-type.sh +0 -0
- package/pennyfarthing-dist/scripts/workflow/list-workflows.sh +0 -0
- package/pennyfarthing-dist/scripts/workflow/phase-owner.sh +0 -0
- package/pennyfarthing-dist/scripts/workflow/resume-workflow.sh +0 -0
- package/pennyfarthing-dist/scripts/workflow/show-workflow.sh +0 -0
- package/pennyfarthing-dist/scripts/workflow/start-workflow.sh +0 -0
- package/pennyfarthing-dist/scripts/workflow/workflow-status.sh +0 -0
- package/pennyfarthing-dist/skills/pf-story/scripts/create-story.sh +0 -0
- package/pennyfarthing-dist/skills/pf-story/scripts/size-story.sh +0 -0
- package/pennyfarthing-dist/skills/pf-story/scripts/story-template.sh +0 -0
- package/pennyfarthing-dist/skills/skill-registry.yaml +19 -0
- package/pennyfarthing-dist/workflows/release/steps/step-10-publish.md +41 -9
- package/pennyfarthing-dist/workflows/tdd-tandem.yaml +15 -2
- package/packages/core/dist/workflow/__test_context_watch__/.session/.tandem-turn-counter +0 -1
- package/packages/core/dist/workflow/__test_context_watch__/.session/95-6-session.md +0 -3
- package/packages/core/dist/workflow/__test_context_watch__/.session/95-6-tandem-architect.md +0 -6
- package/packages/core/dist/workflow/__test_file_watch__/.session/95-4-tandem-architect.md +0 -6
- package/packages/core/dist/workflow/__test_file_watch__/workdir/trigger.ts +0 -1
- package/packages/core/dist/workflow/__test_tool_watch__/.session/95-5-tandem-architect.md +0 -6
- package/packages/core/dist/workflow/__test_tool_watch__/.session/95-5-tandem-toolcalls.jsonl +0 -1
- package/pennyfarthing-dist/pf/bikerack/changed_panel.py +0 -201
- package/scripts/README.md +0 -41
|
@@ -0,0 +1,497 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MessagePanel - Center panel containing MessageView and Editor
|
|
3
|
+
*
|
|
4
|
+
* Story MSSCI-12717 - React Migration
|
|
5
|
+
*
|
|
6
|
+
* This panel wraps the message display and editor input in a single
|
|
7
|
+
* component for the docking workspace center region.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import React, { useState, useEffect, useCallback, useRef } from 'react';
|
|
11
|
+
import MessageView from '../MessageView';
|
|
12
|
+
import Editor, { PastedImage } from '../Editor';
|
|
13
|
+
import { ControlBar, useControlBar } from '../ControlBar';
|
|
14
|
+
import PersonaHeader from '../PersonaHeader';
|
|
15
|
+
import StatsStrip from '../StatsStrip';
|
|
16
|
+
import { useMessageQueueContext, QueuedMessage, InjectDependencies } from '../../contexts/MessageQueueContext';
|
|
17
|
+
import { useClaudeContext } from '../../contexts/ClaudeContext';
|
|
18
|
+
import { usePersona } from '../../hooks/usePersona';
|
|
19
|
+
import type { ClaudeMessage } from '../../hooks/useClaude';
|
|
20
|
+
import type { MessageData } from '../../types/message';
|
|
21
|
+
|
|
22
|
+
// Content block types from SDK nested format (AC5: Story 75-5)
|
|
23
|
+
interface SDKTextBlock {
|
|
24
|
+
type: 'text';
|
|
25
|
+
text: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface SDKToolUseBlock {
|
|
29
|
+
type: 'tool_use';
|
|
30
|
+
id?: string;
|
|
31
|
+
name?: string;
|
|
32
|
+
input?: Record<string, unknown>;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
interface SDKToolResultBlock {
|
|
36
|
+
type: 'tool_result';
|
|
37
|
+
tool_use_id?: string;
|
|
38
|
+
content?: string;
|
|
39
|
+
is_error?: boolean;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
type SDKContentBlock = SDKTextBlock | SDKToolUseBlock | SDKToolResultBlock | { type: string; text?: string };
|
|
43
|
+
|
|
44
|
+
interface SDKMessage {
|
|
45
|
+
type: string;
|
|
46
|
+
message?: {
|
|
47
|
+
content?: Array<SDKContentBlock>;
|
|
48
|
+
};
|
|
49
|
+
content?: string | Array<SDKContentBlock>;
|
|
50
|
+
tool_name?: string;
|
|
51
|
+
tool_id?: string;
|
|
52
|
+
input?: Record<string, unknown>;
|
|
53
|
+
output?: string;
|
|
54
|
+
is_error?: boolean;
|
|
55
|
+
/** Duration in milliseconds for tool execution (MSSCI-13402) */
|
|
56
|
+
durationMs?: number;
|
|
57
|
+
parent_tool_use_id?: string | null;
|
|
58
|
+
subagent_type?: string;
|
|
59
|
+
subagent_name?: string;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// =============================================================================
|
|
63
|
+
// Message Transform
|
|
64
|
+
// =============================================================================
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Check if content is Stop hook feedback that should be hidden.
|
|
68
|
+
* Stop hook feedback messages are internal enforcement messages, not user-facing content.
|
|
69
|
+
* Example: "Stop hook feedback:\nMissing CYCLIST marker..."
|
|
70
|
+
*/
|
|
71
|
+
function isStopHookFeedback(content: string): boolean {
|
|
72
|
+
return content.startsWith('Stop hook feedback:');
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Transform SDK message to MessageData.
|
|
77
|
+
* Returns an array because nested SDK format may contain both text and tool_use blocks.
|
|
78
|
+
* (AC5: Story 75-5 - Extract tool_use from nested SDK format)
|
|
79
|
+
*/
|
|
80
|
+
function transformMessage(sdkMessage: SDKMessage): MessageData[] {
|
|
81
|
+
const timestamp = Date.now();
|
|
82
|
+
// Map parent_tool_use_id to parent_id for subagent grouping
|
|
83
|
+
const parent_id = sdkMessage.parent_tool_use_id || undefined;
|
|
84
|
+
const subagent_type = sdkMessage.subagent_type;
|
|
85
|
+
const subagent_name = sdkMessage.subagent_name;
|
|
86
|
+
|
|
87
|
+
const results: MessageData[] = [];
|
|
88
|
+
|
|
89
|
+
// Handle assistant/message type
|
|
90
|
+
if (sdkMessage.type === 'assistant' || sdkMessage.type === 'message') {
|
|
91
|
+
const contentArray = sdkMessage.message?.content || sdkMessage.content;
|
|
92
|
+
|
|
93
|
+
if (Array.isArray(contentArray)) {
|
|
94
|
+
// Extract text blocks
|
|
95
|
+
const textContent = contentArray
|
|
96
|
+
.filter((block): block is SDKTextBlock =>
|
|
97
|
+
block.type === 'text' && typeof (block as SDKTextBlock).text === 'string'
|
|
98
|
+
)
|
|
99
|
+
.map(block => block.text)
|
|
100
|
+
.join('');
|
|
101
|
+
|
|
102
|
+
// Add text message if we have content (AC5: only if >= 3 chars)
|
|
103
|
+
// Filter out Stop hook feedback messages - they're internal enforcement, not user content
|
|
104
|
+
if (textContent && textContent.trim().length >= 3 && !isStopHookFeedback(textContent.trim())) {
|
|
105
|
+
results.push({
|
|
106
|
+
type: 'agent',
|
|
107
|
+
content: textContent,
|
|
108
|
+
timestamp,
|
|
109
|
+
isStreaming: true,
|
|
110
|
+
parent_id,
|
|
111
|
+
subagent_type,
|
|
112
|
+
subagent_name,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Extract tool_use blocks from nested SDK format (AC5: Story 75-5)
|
|
117
|
+
const toolUseBlocks = contentArray.filter(
|
|
118
|
+
(block): block is SDKToolUseBlock => block.type === 'tool_use'
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
for (const toolBlock of toolUseBlocks) {
|
|
122
|
+
results.push({
|
|
123
|
+
type: 'tool_use',
|
|
124
|
+
tool_name: toolBlock.name,
|
|
125
|
+
tool_id: toolBlock.id,
|
|
126
|
+
input: toolBlock.input,
|
|
127
|
+
timestamp,
|
|
128
|
+
parent_id,
|
|
129
|
+
subagent_type,
|
|
130
|
+
subagent_name,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
} else if (typeof contentArray === 'string') {
|
|
134
|
+
// Filter out Stop hook feedback messages - they're internal enforcement, not user content
|
|
135
|
+
if (contentArray.trim().length >= 3 && !isStopHookFeedback(contentArray.trim())) {
|
|
136
|
+
results.push({
|
|
137
|
+
type: 'agent',
|
|
138
|
+
content: contentArray,
|
|
139
|
+
timestamp,
|
|
140
|
+
isStreaming: true,
|
|
141
|
+
parent_id,
|
|
142
|
+
subagent_type,
|
|
143
|
+
subagent_name,
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return results;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Handle user messages (may contain tool_result blocks for completed Task tools)
|
|
152
|
+
if (sdkMessage.type === 'user') {
|
|
153
|
+
let content = '';
|
|
154
|
+
const contentArray = sdkMessage.message?.content || sdkMessage.content;
|
|
155
|
+
if (Array.isArray(contentArray)) {
|
|
156
|
+
content = contentArray
|
|
157
|
+
.filter((block): block is SDKTextBlock =>
|
|
158
|
+
block.type === 'text' && typeof (block as SDKTextBlock).text === 'string'
|
|
159
|
+
)
|
|
160
|
+
.map(block => block.text)
|
|
161
|
+
.join('');
|
|
162
|
+
|
|
163
|
+
// MSSCI-14394: Extract tool_result blocks from user messages.
|
|
164
|
+
// The SDK delivers tool results inside user-type messages with tool_use_id
|
|
165
|
+
// matching the original tool_use's tool_id. Without extracting these,
|
|
166
|
+
// the subagent cleanup code never fires and spans accumulate forever.
|
|
167
|
+
const toolResultBlocks = contentArray.filter(
|
|
168
|
+
(block): block is SDKToolResultBlock => block.type === 'tool_result'
|
|
169
|
+
);
|
|
170
|
+
for (const resultBlock of toolResultBlocks) {
|
|
171
|
+
results.push({
|
|
172
|
+
type: 'tool_result',
|
|
173
|
+
tool_id: resultBlock.tool_use_id,
|
|
174
|
+
content: typeof resultBlock.content === 'string' ? resultBlock.content : '',
|
|
175
|
+
timestamp,
|
|
176
|
+
is_error: resultBlock.is_error,
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
} else if (typeof contentArray === 'string') {
|
|
180
|
+
content = contentArray;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (content) {
|
|
184
|
+
results.push({
|
|
185
|
+
type: 'user',
|
|
186
|
+
content,
|
|
187
|
+
timestamp,
|
|
188
|
+
parent_id,
|
|
189
|
+
subagent_type,
|
|
190
|
+
subagent_name,
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return results;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Handle discrete tool_use (not nested in assistant message)
|
|
198
|
+
if (sdkMessage.type === 'tool_use') {
|
|
199
|
+
results.push({
|
|
200
|
+
type: 'tool_use',
|
|
201
|
+
tool_name: sdkMessage.tool_name,
|
|
202
|
+
tool_id: sdkMessage.tool_id,
|
|
203
|
+
input: sdkMessage.input,
|
|
204
|
+
timestamp,
|
|
205
|
+
parent_id,
|
|
206
|
+
subagent_type,
|
|
207
|
+
subagent_name,
|
|
208
|
+
});
|
|
209
|
+
return results;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Handle tool_result (MSSCI-13402: include is_error and durationMs)
|
|
213
|
+
if (sdkMessage.type === 'tool_result') {
|
|
214
|
+
results.push({
|
|
215
|
+
type: 'tool_result',
|
|
216
|
+
tool_id: sdkMessage.tool_id,
|
|
217
|
+
content: typeof sdkMessage.output === 'string' ? sdkMessage.output : '',
|
|
218
|
+
timestamp,
|
|
219
|
+
parent_id,
|
|
220
|
+
subagent_type,
|
|
221
|
+
subagent_name,
|
|
222
|
+
is_error: sdkMessage.is_error,
|
|
223
|
+
durationMs: sdkMessage.durationMs,
|
|
224
|
+
});
|
|
225
|
+
return results;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return results;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// =============================================================================
|
|
232
|
+
// MessagePanel Component
|
|
233
|
+
// =============================================================================
|
|
234
|
+
|
|
235
|
+
export function MessagePanel(): React.ReactElement {
|
|
236
|
+
const [messages, setMessages] = useState<MessageData[]>([]);
|
|
237
|
+
const [isProcessing, setIsProcessing] = useState(false);
|
|
238
|
+
const {
|
|
239
|
+
isRunning,
|
|
240
|
+
isStopping,
|
|
241
|
+
bellMode,
|
|
242
|
+
relayMode,
|
|
243
|
+
contextPercent,
|
|
244
|
+
currentAgent,
|
|
245
|
+
handleStop,
|
|
246
|
+
handleForceStop,
|
|
247
|
+
handleReset,
|
|
248
|
+
handleBellModeChange,
|
|
249
|
+
handleRelayModeChange,
|
|
250
|
+
handleTirePump,
|
|
251
|
+
handleAgentSwitch,
|
|
252
|
+
} = useControlBar();
|
|
253
|
+
|
|
254
|
+
// Claude context for WebSocket communication
|
|
255
|
+
const { send, abort, onMessage, onComplete, onError, onUserMessage, onClear, isConnected } = useClaudeContext();
|
|
256
|
+
|
|
257
|
+
// Persona context - capture current persona to stamp on agent messages
|
|
258
|
+
const { persona } = usePersona();
|
|
259
|
+
const personaRef = useRef(persona);
|
|
260
|
+
personaRef.current = persona;
|
|
261
|
+
|
|
262
|
+
// Message queue context for turn complete handling and bell mode (shared with Editor)
|
|
263
|
+
const { handleTurnComplete, pauseQueue, onBellConsumed, injectMessage } = useMessageQueueContext();
|
|
264
|
+
|
|
265
|
+
// Ref to track the submit function for turn complete
|
|
266
|
+
const submitRef = useRef<(text: string, images: QueuedMessage['images']) => void>();
|
|
267
|
+
|
|
268
|
+
// Subscribe to bell-consumed events to display injected messages
|
|
269
|
+
useEffect(() => {
|
|
270
|
+
const unsubscribe = onBellConsumed((consumedMessage) => {
|
|
271
|
+
// Add bell-injected message to the message view
|
|
272
|
+
setMessages(prev => [...prev, {
|
|
273
|
+
type: 'bell_injected',
|
|
274
|
+
content: consumedMessage.text,
|
|
275
|
+
timestamp: Date.now(),
|
|
276
|
+
imageCount: consumedMessage.images.length > 0 ? consumedMessage.images.length : undefined,
|
|
277
|
+
}]);
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
return unsubscribe;
|
|
281
|
+
}, [onBellConsumed]);
|
|
282
|
+
|
|
283
|
+
// Create inject dependencies for "Send Now" button
|
|
284
|
+
const injectDeps: InjectDependencies = {
|
|
285
|
+
abort,
|
|
286
|
+
submit: (text, images) => {
|
|
287
|
+
// User message display is handled by onUserMessage subscription
|
|
288
|
+
setIsProcessing(true);
|
|
289
|
+
send(text, images);
|
|
290
|
+
},
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
// Handle incoming SDK message - stamp current persona on agent messages
|
|
294
|
+
const handleSDKMessage = useCallback((sdkMessage: ClaudeMessage) => {
|
|
295
|
+
const transformed = transformMessage(sdkMessage as SDKMessage);
|
|
296
|
+
if (transformed.length > 0) {
|
|
297
|
+
const p = personaRef.current;
|
|
298
|
+
const stamped = transformed.map(msg =>
|
|
299
|
+
msg.type === 'agent' && p
|
|
300
|
+
? { ...msg, agentSlug: p.slug ?? undefined, agentTheme: p.theme ?? undefined, agentCharacter: p.character ?? undefined }
|
|
301
|
+
: msg
|
|
302
|
+
);
|
|
303
|
+
|
|
304
|
+
// MSSCI-14394: When tool_results arrive for completed Task tools, remove their
|
|
305
|
+
// subagent messages from the view (they have parent_id matching the tool_result's tool_id).
|
|
306
|
+
const completedTaskIds = stamped
|
|
307
|
+
.filter(m => m.type === 'tool_result' && !m.parent_id && m.tool_id)
|
|
308
|
+
.map(m => m.tool_id!);
|
|
309
|
+
|
|
310
|
+
if (completedTaskIds.length > 0) {
|
|
311
|
+
setMessages(prev => {
|
|
312
|
+
const idsToRemove = new Set(completedTaskIds.filter(id =>
|
|
313
|
+
prev.some(m => m.parent_id === id)
|
|
314
|
+
));
|
|
315
|
+
if (idsToRemove.size > 0) {
|
|
316
|
+
return [...prev.filter(m => !m.parent_id || !idsToRemove.has(m.parent_id)), ...stamped];
|
|
317
|
+
}
|
|
318
|
+
return [...prev, ...stamped];
|
|
319
|
+
});
|
|
320
|
+
} else {
|
|
321
|
+
setMessages(prev => [...prev, ...stamped]);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}, []);
|
|
325
|
+
|
|
326
|
+
// Handle query completion
|
|
327
|
+
const handleComplete = useCallback(() => {
|
|
328
|
+
setIsProcessing(false);
|
|
329
|
+
// Mark ALL agent messages as no longer streaming
|
|
330
|
+
setMessages(prev => prev.map(msg =>
|
|
331
|
+
msg.type === 'agent' && msg.isStreaming
|
|
332
|
+
? { ...msg, isStreaming: false }
|
|
333
|
+
: msg
|
|
334
|
+
));
|
|
335
|
+
|
|
336
|
+
// MSSCI-12450: Process queued messages on turn complete
|
|
337
|
+
// Uses the submit function via ref to send queued messages
|
|
338
|
+
if (submitRef.current) {
|
|
339
|
+
handleTurnComplete(submitRef.current);
|
|
340
|
+
}
|
|
341
|
+
}, [handleTurnComplete]);
|
|
342
|
+
|
|
343
|
+
// Handle SDK error
|
|
344
|
+
const handleError = useCallback((error: string) => {
|
|
345
|
+
setIsProcessing(false);
|
|
346
|
+
setMessages(prev => [...prev, {
|
|
347
|
+
type: 'agent',
|
|
348
|
+
content: `Error: ${error}`,
|
|
349
|
+
timestamp: Date.now(),
|
|
350
|
+
}]);
|
|
351
|
+
}, []);
|
|
352
|
+
|
|
353
|
+
// Subscribe to user messages sent via send() - displays ALL user messages
|
|
354
|
+
// regardless of origin (Editor, QuickActions, GitPanel, etc.)
|
|
355
|
+
useEffect(() => {
|
|
356
|
+
const cleanup = onUserMessage((userMessage) => {
|
|
357
|
+
setMessages(prev => [...prev, {
|
|
358
|
+
type: 'user',
|
|
359
|
+
content: userMessage.prompt,
|
|
360
|
+
timestamp: userMessage.timestamp,
|
|
361
|
+
imageCount: userMessage.images.length > 0 ? userMessage.images.length : undefined,
|
|
362
|
+
}]);
|
|
363
|
+
});
|
|
364
|
+
return cleanup;
|
|
365
|
+
}, [onUserMessage]);
|
|
366
|
+
|
|
367
|
+
// Subscribe to clear events — insert a divider message
|
|
368
|
+
useEffect(() => {
|
|
369
|
+
const cleanup = onClear(() => {
|
|
370
|
+
setMessages(prev => [...prev, {
|
|
371
|
+
type: 'context_cleared',
|
|
372
|
+
content: 'Context cleared',
|
|
373
|
+
timestamp: Date.now(),
|
|
374
|
+
}]);
|
|
375
|
+
setIsProcessing(false);
|
|
376
|
+
});
|
|
377
|
+
return cleanup;
|
|
378
|
+
}, [onClear]);
|
|
379
|
+
|
|
380
|
+
// Connect to Claude events via WebSocket context
|
|
381
|
+
useEffect(() => {
|
|
382
|
+
if (!isConnected) {
|
|
383
|
+
console.log('[MessagePanel] Claude WebSocket not connected');
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
const cleanupMessage = onMessage(handleSDKMessage);
|
|
388
|
+
const cleanupComplete = onComplete(handleComplete);
|
|
389
|
+
const cleanupError = onError(handleError);
|
|
390
|
+
|
|
391
|
+
// Cleanup listeners on unmount or dependency change to prevent duplicates
|
|
392
|
+
return () => {
|
|
393
|
+
cleanupMessage();
|
|
394
|
+
cleanupComplete();
|
|
395
|
+
cleanupError();
|
|
396
|
+
};
|
|
397
|
+
}, [isConnected, onMessage, onComplete, onError, handleSDKMessage, handleComplete, handleError]);
|
|
398
|
+
|
|
399
|
+
// Handle editor submit
|
|
400
|
+
const handleSubmit = useCallback((text: string, images: PastedImage[]) => {
|
|
401
|
+
// User message display is handled by onUserMessage subscription
|
|
402
|
+
setIsProcessing(true);
|
|
403
|
+
|
|
404
|
+
// Send to Claude via WebSocket
|
|
405
|
+
send(text, images);
|
|
406
|
+
}, [send]);
|
|
407
|
+
|
|
408
|
+
// Update submit ref for turn complete
|
|
409
|
+
useEffect(() => {
|
|
410
|
+
submitRef.current = handleSubmit;
|
|
411
|
+
}, [handleSubmit]);
|
|
412
|
+
|
|
413
|
+
// Pause queue on stop (prevent auto-advance after abort)
|
|
414
|
+
const handleStopWithPause = useCallback(() => {
|
|
415
|
+
pauseQueue();
|
|
416
|
+
handleStop();
|
|
417
|
+
}, [pauseQueue, handleStop]);
|
|
418
|
+
|
|
419
|
+
// Resizable editor panel
|
|
420
|
+
const [editorHeight, setEditorHeight] = useState<number | null>(null);
|
|
421
|
+
const panelRef = useRef<HTMLDivElement>(null);
|
|
422
|
+
const isDragging = useRef(false);
|
|
423
|
+
|
|
424
|
+
const handleResizeStart = useCallback((e: React.MouseEvent) => {
|
|
425
|
+
e.preventDefault();
|
|
426
|
+
isDragging.current = true;
|
|
427
|
+
const startY = e.clientY;
|
|
428
|
+
const panelEl = panelRef.current;
|
|
429
|
+
if (!panelEl) return;
|
|
430
|
+
const panelRect = panelEl.getBoundingClientRect();
|
|
431
|
+
const startEditorHeight = editorHeight ?? panelEl.querySelector('.message-panel-editor')?.getBoundingClientRect().height ?? 150;
|
|
432
|
+
|
|
433
|
+
const onMouseMove = (ev: MouseEvent) => {
|
|
434
|
+
if (!isDragging.current) return;
|
|
435
|
+
const delta = startY - ev.clientY;
|
|
436
|
+
const newHeight = Math.max(80, Math.min(startEditorHeight + delta, panelRect.height * 0.7));
|
|
437
|
+
setEditorHeight(newHeight);
|
|
438
|
+
};
|
|
439
|
+
const onMouseUp = () => {
|
|
440
|
+
isDragging.current = false;
|
|
441
|
+
document.removeEventListener('mousemove', onMouseMove);
|
|
442
|
+
document.removeEventListener('mouseup', onMouseUp);
|
|
443
|
+
document.body.style.cursor = '';
|
|
444
|
+
document.body.style.userSelect = '';
|
|
445
|
+
};
|
|
446
|
+
document.addEventListener('mousemove', onMouseMove);
|
|
447
|
+
document.addEventListener('mouseup', onMouseUp);
|
|
448
|
+
document.body.style.cursor = 'row-resize';
|
|
449
|
+
document.body.style.userSelect = 'none';
|
|
450
|
+
}, [editorHeight]);
|
|
451
|
+
|
|
452
|
+
return (
|
|
453
|
+
<div className="message-panel" data-testid="message-panel" ref={panelRef}>
|
|
454
|
+
<PersonaHeader />
|
|
455
|
+
<div className="message-panel-content">
|
|
456
|
+
<MessageView messages={messages} />
|
|
457
|
+
</div>
|
|
458
|
+
<div
|
|
459
|
+
className="message-panel-resize-handle"
|
|
460
|
+
onMouseDown={handleResizeStart}
|
|
461
|
+
/>
|
|
462
|
+
<div
|
|
463
|
+
className="message-panel-editor"
|
|
464
|
+
style={editorHeight != null ? { height: editorHeight, flexShrink: 0 } : undefined}
|
|
465
|
+
>
|
|
466
|
+
<div className="editor-with-controls">
|
|
467
|
+
<div className="editor-area">
|
|
468
|
+
<Editor
|
|
469
|
+
onSubmit={handleSubmit}
|
|
470
|
+
isProcessing={isProcessing || isRunning}
|
|
471
|
+
placeholder="Send a message..."
|
|
472
|
+
onInject={(index) => injectMessage(index, injectDeps)}
|
|
473
|
+
/>
|
|
474
|
+
</div>
|
|
475
|
+
<ControlBar
|
|
476
|
+
isRunning={isRunning || isProcessing}
|
|
477
|
+
isStopping={isStopping}
|
|
478
|
+
onStop={handleStopWithPause}
|
|
479
|
+
onForceStop={handleForceStop}
|
|
480
|
+
onReset={handleReset}
|
|
481
|
+
bellMode={bellMode}
|
|
482
|
+
relayMode={relayMode}
|
|
483
|
+
onBellModeChange={handleBellModeChange}
|
|
484
|
+
onRelayModeChange={handleRelayModeChange}
|
|
485
|
+
contextPercent={contextPercent}
|
|
486
|
+
currentAgent={currentAgent}
|
|
487
|
+
onTirePump={handleTirePump}
|
|
488
|
+
onAgentSwitch={handleAgentSwitch}
|
|
489
|
+
/>
|
|
490
|
+
</div>
|
|
491
|
+
</div>
|
|
492
|
+
<StatsStrip />
|
|
493
|
+
</div>
|
|
494
|
+
);
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
export default MessagePanel;
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ProgressPanel - At-a-glance story dashboard
|
|
3
|
+
*
|
|
4
|
+
* Unified panel combining story context, workflow phase, AC completion,
|
|
5
|
+
* todo status, git changes, and context window usage.
|
|
6
|
+
*
|
|
7
|
+
* Story: MSSCI-14966 / 103-11
|
|
8
|
+
* Epic: 103 - BikeRack TUI
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import React from 'react';
|
|
12
|
+
import { useStory } from '../../hooks/useStory';
|
|
13
|
+
import { useSprint } from '../../hooks/useSprint';
|
|
14
|
+
import { useTodos } from '../../hooks/useTodos';
|
|
15
|
+
import { useGitStatus } from '../../hooks/useGitStatus';
|
|
16
|
+
import { useStatsStrip } from '../../hooks/useStatsStrip';
|
|
17
|
+
|
|
18
|
+
export function ProgressPanel(): React.ReactElement {
|
|
19
|
+
const { story, isLoading: storyLoading, error: storyError } = useStory();
|
|
20
|
+
const { data: sprintData, isLoading: sprintLoading } = useSprint();
|
|
21
|
+
const { todos } = useTodos();
|
|
22
|
+
const { gitStatus } = useGitStatus();
|
|
23
|
+
const { context } = useStatsStrip();
|
|
24
|
+
|
|
25
|
+
// Loading state
|
|
26
|
+
if (storyLoading || sprintLoading) {
|
|
27
|
+
return (
|
|
28
|
+
<div className="progress-panel loading" data-testid="progress-panel">
|
|
29
|
+
<div className="progress-loading">Loading...</div>
|
|
30
|
+
</div>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Error state
|
|
35
|
+
if (storyError) {
|
|
36
|
+
return (
|
|
37
|
+
<div className="progress-panel" data-testid="progress-panel">
|
|
38
|
+
<div className="error-message">{storyError.message}</div>
|
|
39
|
+
</div>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Empty state
|
|
44
|
+
const currentStory = sprintData?.currentStory;
|
|
45
|
+
if (!story && !currentStory) {
|
|
46
|
+
return (
|
|
47
|
+
<div className="progress-panel" data-testid="progress-panel">
|
|
48
|
+
<div className="empty-state">
|
|
49
|
+
<div>No active story</div>
|
|
50
|
+
<div className="empty-hint">Run /sprint work to start</div>
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Merge data from story + sprint hooks
|
|
57
|
+
const storyId = story?.id ?? currentStory?.id ?? '';
|
|
58
|
+
const storyTitle = story?.title ?? currentStory?.title ?? '';
|
|
59
|
+
const storyPoints = story?.points ?? currentStory?.points ?? 0;
|
|
60
|
+
const jiraKey = currentStory?.jiraKey ?? '';
|
|
61
|
+
const storyStatus = story?.status ?? currentStory?.status ?? '';
|
|
62
|
+
const epic = story?.epic ?? currentStory?.epic ?? '';
|
|
63
|
+
const displayStatus = storyStatus.replace(/_/g, ' ');
|
|
64
|
+
|
|
65
|
+
// Workflow
|
|
66
|
+
const workflowType = story?.workflow ?? null;
|
|
67
|
+
const phases = story?.workflowPhases ?? null;
|
|
68
|
+
const hasWorkflow = workflowType || (phases && phases.length > 0);
|
|
69
|
+
|
|
70
|
+
// AC
|
|
71
|
+
const criteria = story?.criteria ?? null;
|
|
72
|
+
const hasCriteria = criteria != null && criteria.length > 0;
|
|
73
|
+
const completedAC = hasCriteria ? criteria.filter((c: any) => c.completed).length : 0;
|
|
74
|
+
const totalAC = hasCriteria ? criteria.length : 0;
|
|
75
|
+
const acPercent = totalAC > 0 ? Math.round((completedAC / totalAC) * 100) : 0;
|
|
76
|
+
|
|
77
|
+
// Todos
|
|
78
|
+
const hasTodos = todos && todos.length > 0;
|
|
79
|
+
const completedTodos = hasTodos ? todos.filter((t: any) => t.status === 'completed').length : 0;
|
|
80
|
+
const totalTodos = hasTodos ? todos.length : 0;
|
|
81
|
+
const activeTodo = hasTodos ? todos.find((t: any) => t.status === 'in_progress') : null;
|
|
82
|
+
|
|
83
|
+
// Git
|
|
84
|
+
const branch = gitStatus?.branch ?? '';
|
|
85
|
+
const modified = gitStatus?.modified ?? 0;
|
|
86
|
+
const untracked = gitStatus?.untracked ?? 0;
|
|
87
|
+
const ahead = gitStatus?.ahead ?? 0;
|
|
88
|
+
const behind = gitStatus?.behind ?? 0;
|
|
89
|
+
|
|
90
|
+
// Context
|
|
91
|
+
const contextPercent = context?.percent ?? 0;
|
|
92
|
+
|
|
93
|
+
return (
|
|
94
|
+
<div className="progress-panel" data-testid="progress-panel">
|
|
95
|
+
{/* Story Header (AC3) */}
|
|
96
|
+
<div className="progress-section" data-testid="progress-story-header">
|
|
97
|
+
<div className="story-header-row">
|
|
98
|
+
<span className="story-id">{storyId}</span>
|
|
99
|
+
<span className="story-points">{storyPoints}pt</span>
|
|
100
|
+
<span className="story-status">{displayStatus}</span>
|
|
101
|
+
</div>
|
|
102
|
+
<div className="story-title">{storyTitle}</div>
|
|
103
|
+
<div className="story-meta">
|
|
104
|
+
<span className="story-jira">{jiraKey}</span>
|
|
105
|
+
<span className="story-epic">{epic}</span>
|
|
106
|
+
</div>
|
|
107
|
+
</div>
|
|
108
|
+
|
|
109
|
+
{/* Workflow Row (AC4) */}
|
|
110
|
+
{hasWorkflow && (
|
|
111
|
+
<div className="progress-section" data-testid="progress-workflow-row">
|
|
112
|
+
{workflowType && (
|
|
113
|
+
<span className="workflow-badge">
|
|
114
|
+
{workflowType.toUpperCase() === 'TDD' || workflowType.toUpperCase() === 'BDD'
|
|
115
|
+
? workflowType.toUpperCase()
|
|
116
|
+
: workflowType.charAt(0).toUpperCase() + workflowType.slice(1)}
|
|
117
|
+
</span>
|
|
118
|
+
)}
|
|
119
|
+
{phases && phases.length > 0 && (
|
|
120
|
+
<div className="phase-progress">
|
|
121
|
+
{phases.map((phase: any) => (
|
|
122
|
+
<div key={phase.name} className={`phase-step ${phase.status}`}>
|
|
123
|
+
<span className="phase-label">{phase.label}</span>
|
|
124
|
+
</div>
|
|
125
|
+
))}
|
|
126
|
+
</div>
|
|
127
|
+
)}
|
|
128
|
+
</div>
|
|
129
|
+
)}
|
|
130
|
+
|
|
131
|
+
{/* AC Row (AC5) */}
|
|
132
|
+
{hasCriteria && (
|
|
133
|
+
<div className="progress-section" data-testid="progress-ac-row">
|
|
134
|
+
<span className="row-label">AC</span>
|
|
135
|
+
<span className="progress-count">{completedAC}/{totalAC}</span>
|
|
136
|
+
<div
|
|
137
|
+
className="progress-bar-container"
|
|
138
|
+
role="progressbar"
|
|
139
|
+
aria-valuenow={completedAC}
|
|
140
|
+
aria-valuemin={0}
|
|
141
|
+
aria-valuemax={totalAC}
|
|
142
|
+
>
|
|
143
|
+
<div className="progress-bar" style={{ width: `${acPercent}%` }} />
|
|
144
|
+
</div>
|
|
145
|
+
</div>
|
|
146
|
+
)}
|
|
147
|
+
|
|
148
|
+
{/* Todo Row (AC6) */}
|
|
149
|
+
{hasTodos && (
|
|
150
|
+
<div className="progress-section" data-testid="progress-todo-row">
|
|
151
|
+
<span className="row-label">Tasks</span>
|
|
152
|
+
<span className="progress-count">{completedTodos}/{totalTodos}</span>
|
|
153
|
+
<div className="progress-bar-container">
|
|
154
|
+
<div
|
|
155
|
+
className="progress-bar"
|
|
156
|
+
style={{ width: `${totalTodos > 0 ? Math.round((completedTodos / totalTodos) * 100) : 0}%` }}
|
|
157
|
+
/>
|
|
158
|
+
</div>
|
|
159
|
+
{activeTodo && (
|
|
160
|
+
<span className="active-task">{activeTodo.activeForm || activeTodo.content}</span>
|
|
161
|
+
)}
|
|
162
|
+
</div>
|
|
163
|
+
)}
|
|
164
|
+
|
|
165
|
+
{/* Git Row (AC7) */}
|
|
166
|
+
<div className="progress-section" data-testid="progress-git-row">
|
|
167
|
+
<span className="git-branch">{branch}</span>
|
|
168
|
+
<span className="git-stats">{modified}M {untracked}U ↑{ahead} ↓{behind}</span>
|
|
169
|
+
</div>
|
|
170
|
+
|
|
171
|
+
{/* Context Row (AC8) */}
|
|
172
|
+
<div className="progress-section" data-testid="progress-context-row">
|
|
173
|
+
<span className="row-label">Context</span>
|
|
174
|
+
<span className="context-percent">{contextPercent}%</span>
|
|
175
|
+
<div
|
|
176
|
+
className="progress-bar-container"
|
|
177
|
+
role="progressbar"
|
|
178
|
+
aria-valuenow={contextPercent}
|
|
179
|
+
aria-valuemin={0}
|
|
180
|
+
aria-valuemax={100}
|
|
181
|
+
>
|
|
182
|
+
<div className="progress-bar" style={{ width: `${contextPercent}%` }} />
|
|
183
|
+
</div>
|
|
184
|
+
</div>
|
|
185
|
+
</div>
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export default ProgressPanel;
|