prjct-cli 0.11.4 → 0.12.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/CHANGELOG.md +72 -0
- package/README.md +81 -25
- package/bin/dev.js +1 -1
- package/bin/generate-views.js +209 -0
- package/bin/migrate-to-json.js +742 -0
- package/bin/prjct +5 -5
- package/bin/serve.js +246 -54
- package/core/__tests__/agentic/{memory-system.test.js → memory-system.test.ts} +12 -23
- package/core/__tests__/agentic/{plan-mode.test.js → plan-mode.test.ts} +26 -24
- package/core/__tests__/agentic/{prompt-builder.test.js → prompt-builder.test.ts} +3 -8
- package/core/__tests__/utils/date-helper.test.ts +405 -0
- package/core/__tests__/utils/{output.test.js → output.test.ts} +12 -24
- package/core/agentic/agent-router.ts +137 -0
- package/core/agentic/chain-of-thought.ts +228 -0
- package/core/agentic/command-executor/command-executor.ts +384 -0
- package/core/agentic/command-executor/index.ts +16 -0
- package/core/agentic/command-executor/status-signal.ts +38 -0
- package/core/agentic/command-executor/types.ts +79 -0
- package/core/agentic/command-executor.ts +8 -0
- package/core/agentic/{context-builder.js → context-builder.ts} +99 -89
- package/core/agentic/context-filter.ts +365 -0
- package/core/agentic/ground-truth/index.ts +76 -0
- package/core/agentic/ground-truth/types.ts +33 -0
- package/core/agentic/ground-truth/utils.ts +48 -0
- package/core/agentic/ground-truth/verifiers/analyze.ts +54 -0
- package/core/agentic/ground-truth/verifiers/done.ts +75 -0
- package/core/agentic/ground-truth/verifiers/feature.ts +70 -0
- package/core/agentic/ground-truth/verifiers/index.ts +37 -0
- package/core/agentic/ground-truth/verifiers/init.ts +52 -0
- package/core/agentic/ground-truth/verifiers/now.ts +57 -0
- package/core/agentic/ground-truth/verifiers/ship.ts +85 -0
- package/core/agentic/ground-truth/verifiers/spec.ts +45 -0
- package/core/agentic/ground-truth/verifiers/sync.ts +47 -0
- package/core/agentic/ground-truth/verifiers.ts +6 -0
- package/core/agentic/ground-truth.ts +8 -0
- package/core/agentic/loop-detector/error-analysis.ts +97 -0
- package/core/agentic/loop-detector/hallucination.ts +71 -0
- package/core/agentic/loop-detector/index.ts +41 -0
- package/core/agentic/loop-detector/loop-detector.ts +222 -0
- package/core/agentic/loop-detector/types.ts +66 -0
- package/core/agentic/loop-detector.ts +8 -0
- package/core/agentic/memory-system/history.ts +53 -0
- package/core/agentic/memory-system/index.ts +192 -0
- package/core/agentic/memory-system/patterns.ts +156 -0
- package/core/agentic/memory-system/semantic-memories.ts +277 -0
- package/core/agentic/memory-system/session.ts +21 -0
- package/core/agentic/memory-system/types.ts +159 -0
- package/core/agentic/memory-system.ts +8 -0
- package/core/agentic/parallel-tools.ts +165 -0
- package/core/agentic/plan-mode/approval.ts +57 -0
- package/core/agentic/plan-mode/constants.ts +44 -0
- package/core/agentic/plan-mode/index.ts +28 -0
- package/core/agentic/plan-mode/plan-mode.ts +406 -0
- package/core/agentic/plan-mode/types.ts +193 -0
- package/core/agentic/plan-mode.ts +8 -0
- package/core/agentic/prompt-builder.ts +566 -0
- package/core/agentic/response-templates.ts +164 -0
- package/core/agentic/semantic-compression.ts +273 -0
- package/core/agentic/services.ts +206 -0
- package/core/agentic/smart-context.ts +476 -0
- package/core/agentic/{template-loader.js → template-loader.ts} +35 -18
- package/core/agentic/think-blocks.ts +202 -0
- package/core/agentic/tool-registry.ts +119 -0
- package/core/agentic/validation-rules.ts +313 -0
- package/core/agents/index.ts +28 -0
- package/core/agents/performance.ts +444 -0
- package/core/agents/types.ts +126 -0
- package/core/bus/{index.js → index.ts} +57 -61
- package/core/command-registry/categories.ts +23 -0
- package/core/command-registry/commands.ts +15 -0
- package/core/command-registry/core-commands.ts +319 -0
- package/core/command-registry/index.ts +158 -0
- package/core/command-registry/optional-commands.ts +119 -0
- package/core/command-registry/setup-commands.ts +53 -0
- package/core/command-registry/types.ts +59 -0
- package/core/command-registry.ts +9 -0
- package/core/commands/analysis.ts +298 -0
- package/core/commands/analytics.ts +288 -0
- package/core/commands/base.ts +273 -0
- package/core/commands/index.ts +211 -0
- package/core/commands/maintenance.ts +226 -0
- package/core/commands/planning.ts +311 -0
- package/core/commands/setup.ts +309 -0
- package/core/commands/shipping.ts +188 -0
- package/core/commands/types.ts +183 -0
- package/core/commands/workflow.ts +226 -0
- package/core/commands.ts +11 -0
- package/core/constants/formats.ts +187 -0
- package/core/constants/index.ts +7 -0
- package/core/{context-sync.js → context-sync.ts} +59 -26
- package/core/data/agents-manager.ts +76 -0
- package/core/data/analysis-manager.ts +83 -0
- package/core/data/base-manager.ts +156 -0
- package/core/data/ideas-manager.ts +81 -0
- package/core/data/index.ts +32 -0
- package/core/data/outcomes-manager.ts +96 -0
- package/core/data/project-manager.ts +75 -0
- package/core/data/roadmap-manager.ts +118 -0
- package/core/data/shipped-manager.ts +65 -0
- package/core/data/state-manager.ts +214 -0
- package/core/domain/{agent-generator.js → agent-generator.ts} +77 -57
- package/core/domain/{agent-loader.js → agent-loader.ts} +65 -56
- package/core/domain/{agent-matcher.js → agent-matcher.ts} +51 -24
- package/core/domain/{agent-validator.js → agent-validator.ts} +70 -37
- package/core/domain/{analyzer.js → analyzer.ts} +91 -85
- package/core/domain/{architect-session.js → architect-session.ts} +49 -34
- package/core/domain/{architecture-generator.js → architecture-generator.ts} +25 -13
- package/core/domain/{context-estimator.js → context-estimator.ts} +57 -36
- package/core/domain/{product-standards.js → product-standards.ts} +40 -26
- package/core/domain/{smart-cache.js → smart-cache.ts} +39 -30
- package/core/domain/{snapshot-manager.js → snapshot-manager.ts} +103 -100
- package/core/domain/{task-analyzer.js → task-analyzer.ts} +82 -43
- package/core/domain/task-stack/index.ts +19 -0
- package/core/domain/task-stack/parser.ts +86 -0
- package/core/domain/task-stack/storage.ts +123 -0
- package/core/domain/task-stack/task-stack.ts +340 -0
- package/core/domain/task-stack/types.ts +51 -0
- package/core/domain/task-stack.ts +8 -0
- package/core/{index.js → index.ts} +61 -18
- package/core/infrastructure/{agent-detector.js → agent-detector.ts} +62 -23
- package/core/infrastructure/agents/{claude-agent.js → claude-agent.ts} +61 -21
- package/core/infrastructure/{author-detector.js → author-detector.ts} +42 -49
- package/core/infrastructure/{capability-installer.js → capability-installer.ts} +51 -27
- package/core/infrastructure/{command-installer.js → command-installer/command-installer.ts} +43 -144
- package/core/infrastructure/command-installer/global-config.ts +106 -0
- package/core/infrastructure/command-installer/index.ts +25 -0
- package/core/infrastructure/command-installer/types.ts +41 -0
- package/core/infrastructure/command-installer.ts +8 -0
- package/core/infrastructure/{config-manager.js → config-manager.ts} +60 -80
- package/core/infrastructure/{editors-config.js → editors-config.ts} +33 -31
- package/core/infrastructure/legacy-installer-detector/cleanup.ts +216 -0
- package/core/infrastructure/legacy-installer-detector/detection.ts +95 -0
- package/core/infrastructure/legacy-installer-detector/index.ts +171 -0
- package/core/infrastructure/legacy-installer-detector/migration.ts +87 -0
- package/core/infrastructure/legacy-installer-detector/types.ts +42 -0
- package/core/infrastructure/legacy-installer-detector.ts +7 -0
- package/core/infrastructure/migrator/file-operations.ts +125 -0
- package/core/infrastructure/migrator/index.ts +288 -0
- package/core/infrastructure/migrator/project-scanner.ts +89 -0
- package/core/infrastructure/migrator/reports.ts +117 -0
- package/core/infrastructure/migrator/types.ts +124 -0
- package/core/infrastructure/migrator/validation.ts +94 -0
- package/core/infrastructure/migrator/version-migration.ts +117 -0
- package/core/infrastructure/migrator.ts +10 -0
- package/core/infrastructure/{path-manager.js → path-manager.ts} +51 -91
- package/core/infrastructure/session-manager/index.ts +23 -0
- package/core/infrastructure/session-manager/migration.ts +88 -0
- package/core/infrastructure/session-manager/session-manager.ts +307 -0
- package/core/infrastructure/session-manager/types.ts +45 -0
- package/core/infrastructure/session-manager.ts +8 -0
- package/core/infrastructure/{setup.js → setup.ts} +29 -21
- package/core/infrastructure/{update-checker.js → update-checker.ts} +40 -18
- package/core/outcomes/analyzer.ts +333 -0
- package/core/outcomes/index.ts +34 -0
- package/core/outcomes/recorder.ts +194 -0
- package/core/outcomes/types.ts +145 -0
- package/core/plugin/{hooks.js → hooks.ts} +56 -58
- package/core/plugin/{index.js → index.ts} +19 -8
- package/core/plugin/{loader.js → loader.ts} +87 -69
- package/core/plugin/{registry.js → registry.ts} +49 -45
- package/core/plugins/{webhook.js → webhook.ts} +43 -27
- package/core/schemas/agents.ts +27 -0
- package/core/schemas/analysis.ts +41 -0
- package/core/schemas/ideas.ts +83 -0
- package/core/schemas/index.ts +73 -0
- package/core/schemas/outcomes.ts +22 -0
- package/core/schemas/project.ts +26 -0
- package/core/schemas/roadmap.ts +90 -0
- package/core/schemas/shipped.ts +82 -0
- package/core/schemas/state.ts +107 -0
- package/core/session/index.ts +17 -0
- package/core/session/{metrics.js → metrics.ts} +64 -46
- package/core/session/{index.js → session-manager.ts} +51 -117
- package/core/session/types.ts +29 -0
- package/core/session/utils.ts +57 -0
- package/core/state/index.ts +25 -0
- package/core/state/manager.ts +376 -0
- package/core/state/types.ts +185 -0
- package/core/tsconfig.json +22 -0
- package/core/types/index.ts +506 -0
- package/core/utils/{animations.js → animations.ts} +74 -28
- package/core/utils/{branding.js → branding.ts} +29 -4
- package/core/utils/{date-helper.js → date-helper.ts} +31 -74
- package/core/utils/file-helper.ts +262 -0
- package/core/utils/{jsonl-helper.js → jsonl-helper.ts} +71 -107
- package/core/utils/{logger.js → logger.ts} +24 -12
- package/core/utils/{output.js → output.ts} +25 -13
- package/core/utils/{project-capabilities.js → project-capabilities.ts} +31 -18
- package/core/utils/{session-helper.js → session-helper.ts} +79 -66
- package/core/utils/{version.js → version.ts} +23 -31
- package/core/view-generator.ts +536 -0
- package/package.json +23 -17
- package/packages/shared/.turbo/turbo-build.log +14 -0
- package/packages/shared/dist/index.d.ts +8 -613
- package/packages/shared/dist/index.d.ts.map +1 -0
- package/packages/shared/dist/index.js +4110 -118
- package/packages/shared/dist/schemas.d.ts +408 -0
- package/packages/shared/dist/schemas.d.ts.map +1 -0
- package/packages/shared/dist/types.d.ts +144 -0
- package/packages/shared/dist/types.d.ts.map +1 -0
- package/packages/shared/dist/unified.d.ts +139 -0
- package/packages/shared/dist/unified.d.ts.map +1 -0
- package/packages/shared/dist/utils.d.ts +60 -0
- package/packages/shared/dist/utils.d.ts.map +1 -0
- package/packages/shared/package.json +4 -4
- package/packages/shared/src/index.ts +1 -0
- package/packages/shared/src/unified.ts +174 -0
- package/packages/web/app/api/claude/sessions/route.ts +1 -1
- package/packages/web/app/api/claude/status/route.ts +1 -1
- package/packages/web/app/api/migrate/route.ts +46 -0
- package/packages/web/app/api/projects/[id]/route.ts +1 -1
- package/packages/web/app/api/projects/[id]/stats/route.ts +30 -2
- package/packages/web/app/api/projects/[id]/status/route.ts +1 -1
- package/packages/web/app/api/projects/route.ts +1 -1
- package/packages/web/app/api/settings/route.ts +97 -0
- package/packages/web/app/api/v2/projects/[id]/unified/route.ts +57 -0
- package/packages/web/app/globals.css +38 -0
- package/packages/web/app/layout.tsx +10 -2
- package/packages/web/app/page.tsx +9 -224
- package/packages/web/app/project/[id]/page.tsx +191 -63
- package/packages/web/app/project/[id]/stats/loading.tsx +43 -0
- package/packages/web/app/project/[id]/stats/page.tsx +203 -403
- package/packages/web/app/settings/page.tsx +222 -2
- package/packages/web/components/ActivityTimeline/ActivityTimeline.constants.ts +2 -0
- package/packages/web/components/ActivityTimeline/ActivityTimeline.tsx +50 -0
- package/packages/web/components/ActivityTimeline/ActivityTimeline.types.ts +8 -0
- package/packages/web/components/ActivityTimeline/hooks/index.ts +2 -0
- package/packages/web/components/ActivityTimeline/hooks/useExpandable.ts +9 -0
- package/packages/web/components/ActivityTimeline/hooks/useGroupedEvents.ts +23 -0
- package/packages/web/components/ActivityTimeline/index.ts +2 -0
- package/packages/web/components/AgentsCard/AgentsCard.tsx +63 -0
- package/packages/web/components/AgentsCard/AgentsCard.types.ts +13 -0
- package/packages/web/components/AgentsCard/index.ts +2 -0
- package/packages/web/components/AppSidebar/AppSidebar.tsx +134 -0
- package/packages/web/components/AppSidebar/index.ts +1 -0
- package/packages/web/components/BackLink/BackLink.tsx +18 -0
- package/packages/web/components/BackLink/BackLink.types.ts +5 -0
- package/packages/web/components/BackLink/index.ts +2 -0
- package/packages/web/components/BentoCard/BentoCard.constants.ts +16 -0
- package/packages/web/components/BentoCard/BentoCard.tsx +47 -0
- package/packages/web/components/BentoCard/BentoCard.types.ts +15 -0
- package/packages/web/components/BentoCard/index.ts +2 -0
- package/packages/web/components/BentoCardSkeleton/BentoCardSkeleton.constants.ts +9 -0
- package/packages/web/components/BentoCardSkeleton/BentoCardSkeleton.tsx +18 -0
- package/packages/web/components/BentoCardSkeleton/BentoCardSkeleton.types.ts +5 -0
- package/packages/web/components/BentoCardSkeleton/index.ts +2 -0
- package/packages/web/components/BentoGrid/BentoGrid.tsx +18 -0
- package/packages/web/components/BentoGrid/BentoGrid.types.ts +4 -0
- package/packages/web/components/BentoGrid/index.ts +2 -0
- package/packages/web/components/CommandButton/index.ts +1 -0
- package/packages/web/components/ConnectionStatus/index.ts +1 -0
- package/packages/web/components/DashboardContent/DashboardContent.tsx +254 -0
- package/packages/web/components/DashboardContent/index.ts +1 -0
- package/packages/web/components/DateGroup/DateGroup.tsx +18 -0
- package/packages/web/components/DateGroup/DateGroup.types.ts +6 -0
- package/packages/web/components/DateGroup/DateGroup.utils.ts +11 -0
- package/packages/web/components/DateGroup/index.ts +2 -0
- package/packages/web/components/EmptyState/EmptyState.tsx +58 -0
- package/packages/web/components/EmptyState/EmptyState.types.ts +10 -0
- package/packages/web/components/EmptyState/index.ts +2 -0
- package/packages/web/components/EventRow/EventRow.constants.ts +10 -0
- package/packages/web/components/EventRow/EventRow.tsx +49 -0
- package/packages/web/components/EventRow/EventRow.types.ts +7 -0
- package/packages/web/components/EventRow/EventRow.utils.ts +49 -0
- package/packages/web/components/EventRow/index.ts +2 -0
- package/packages/web/components/ExpandButton/ExpandButton.tsx +18 -0
- package/packages/web/components/ExpandButton/ExpandButton.types.ts +6 -0
- package/packages/web/components/ExpandButton/index.ts +2 -0
- package/packages/web/components/HealthGradientBackground/HealthGradientBackground.tsx +14 -0
- package/packages/web/components/HealthGradientBackground/HealthGradientBackground.types.ts +5 -0
- package/packages/web/components/HealthGradientBackground/HealthGradientBackground.utils.ts +13 -0
- package/packages/web/components/HealthGradientBackground/index.ts +2 -0
- package/packages/web/components/HeroSection/HeroSection.tsx +55 -0
- package/packages/web/components/HeroSection/HeroSection.types.ts +14 -0
- package/packages/web/components/HeroSection/HeroSection.utils.ts +7 -0
- package/packages/web/components/HeroSection/hooks/index.ts +2 -0
- package/packages/web/components/HeroSection/hooks/useCountUp.ts +45 -0
- package/packages/web/components/HeroSection/hooks/useWeeklyActivity.ts +18 -0
- package/packages/web/components/HeroSection/index.ts +2 -0
- package/packages/web/components/IdeasCard/IdeasCard.tsx +48 -0
- package/packages/web/components/IdeasCard/IdeasCard.types.ts +9 -0
- package/packages/web/components/IdeasCard/index.ts +2 -0
- package/packages/web/components/InsightMessage/InsightMessage.tsx +9 -0
- package/packages/web/components/InsightMessage/InsightMessage.types.ts +3 -0
- package/packages/web/components/InsightMessage/index.ts +2 -0
- package/packages/web/components/Logo/index.ts +1 -0
- package/packages/web/components/MarkdownContent/index.ts +1 -0
- package/packages/web/components/NowCard/NowCard.tsx +93 -0
- package/packages/web/components/NowCard/NowCard.types.ts +15 -0
- package/packages/web/components/NowCard/index.ts +2 -0
- package/packages/web/components/ProgressRing/ProgressRing.constants.ts +20 -0
- package/packages/web/components/ProgressRing/ProgressRing.tsx +51 -0
- package/packages/web/components/ProgressRing/ProgressRing.types.ts +11 -0
- package/packages/web/components/ProgressRing/index.ts +2 -0
- package/packages/web/components/ProjectAvatar/index.ts +1 -0
- package/packages/web/components/Providers/index.ts +1 -0
- package/packages/web/components/QueueCard/QueueCard.tsx +72 -0
- package/packages/web/components/QueueCard/QueueCard.types.ts +11 -0
- package/packages/web/components/QueueCard/QueueCard.utils.ts +12 -0
- package/packages/web/components/QueueCard/index.ts +2 -0
- package/packages/web/components/RoadmapCard/RoadmapCard.tsx +77 -0
- package/packages/web/components/RoadmapCard/RoadmapCard.types.ts +15 -0
- package/packages/web/components/RoadmapCard/index.ts +2 -0
- package/packages/web/components/ShipsCard/ShipsCard.tsx +52 -0
- package/packages/web/components/ShipsCard/ShipsCard.types.ts +12 -0
- package/packages/web/components/ShipsCard/ShipsCard.utils.ts +4 -0
- package/packages/web/components/ShipsCard/index.ts +2 -0
- package/packages/web/components/SparklineChart/SparklineChart.tsx +38 -0
- package/packages/web/components/SparklineChart/SparklineChart.types.ts +6 -0
- package/packages/web/components/SparklineChart/index.ts +2 -0
- package/packages/web/components/StreakCard/StreakCard.constants.ts +2 -0
- package/packages/web/components/StreakCard/StreakCard.tsx +53 -0
- package/packages/web/components/StreakCard/StreakCard.types.ts +4 -0
- package/packages/web/components/StreakCard/index.ts +2 -0
- package/packages/web/components/TasksCounter/TasksCounter.tsx +14 -0
- package/packages/web/components/TasksCounter/TasksCounter.types.ts +3 -0
- package/packages/web/components/TasksCounter/index.ts +2 -0
- package/packages/web/components/TechStackBadges/index.ts +1 -0
- package/packages/web/components/{TerminalTab.tsx → TerminalTabs/TerminalTab.tsx} +11 -0
- package/packages/web/components/{TerminalTabs.tsx → TerminalTabs/TerminalTabs.tsx} +29 -28
- package/packages/web/components/TerminalTabs/index.ts +1 -0
- package/packages/web/components/VelocityBadge/VelocityBadge.tsx +27 -0
- package/packages/web/components/VelocityBadge/VelocityBadge.types.ts +3 -0
- package/packages/web/components/VelocityBadge/index.ts +2 -0
- package/packages/web/components/VelocityCard/VelocityCard.tsx +71 -0
- package/packages/web/components/VelocityCard/VelocityCard.types.ts +7 -0
- package/packages/web/components/VelocityCard/index.ts +2 -0
- package/packages/web/components/WeeklySparkline/WeeklySparkline.tsx +13 -0
- package/packages/web/components/WeeklySparkline/WeeklySparkline.types.ts +3 -0
- package/packages/web/components/WeeklySparkline/index.ts +2 -0
- package/packages/web/components/ui/input.tsx +21 -0
- package/packages/web/components/ui/tooltip.tsx +2 -2
- package/packages/web/context/TerminalTabsContext.tsx +46 -1
- package/packages/web/hooks/useClaudeTerminal.ts +71 -21
- package/packages/web/hooks/useProjectStats.ts +55 -0
- package/packages/web/hooks/useProjects.ts +6 -6
- package/packages/web/lib/actions/projects.ts +15 -0
- package/packages/web/lib/json-loader.ts +630 -0
- package/packages/web/lib/services/index.ts +9 -0
- package/packages/web/lib/services/migration.server.ts +598 -0
- package/packages/web/lib/services/projects.server.ts +52 -0
- package/packages/web/lib/services/stats.server.ts +264 -0
- package/packages/web/lib/unified-loader.ts +396 -0
- package/packages/web/next-env.d.ts +1 -1
- package/packages/web/package.json +10 -6
- package/packages/web/server.ts +36 -6
- package/templates/commands/done.md +76 -32
- package/templates/commands/feature.md +121 -47
- package/templates/commands/idea.md +81 -8
- package/templates/commands/now.md +41 -17
- package/templates/commands/ship.md +64 -25
- package/templates/commands/sync.md +28 -3
- package/core/agentic/agent-router.js +0 -128
- package/core/agentic/chain-of-thought.js +0 -578
- package/core/agentic/command-executor.js +0 -421
- package/core/agentic/context-filter.js +0 -354
- package/core/agentic/ground-truth.js +0 -591
- package/core/agentic/loop-detector.js +0 -406
- package/core/agentic/memory-system.js +0 -850
- package/core/agentic/parallel-tools.js +0 -366
- package/core/agentic/plan-mode.js +0 -572
- package/core/agentic/prompt-builder.js +0 -338
- package/core/agentic/response-templates.js +0 -290
- package/core/agentic/semantic-compression.js +0 -517
- package/core/agentic/think-blocks.js +0 -657
- package/core/agentic/tool-registry.js +0 -184
- package/core/agentic/validation-rules.js +0 -380
- package/core/command-registry.js +0 -698
- package/core/commands.js +0 -2237
- package/core/domain/task-stack.js +0 -497
- package/core/infrastructure/legacy-installer-detector.js +0 -546
- package/core/infrastructure/migrator.js +0 -799
- package/core/infrastructure/session-manager.js +0 -390
- package/core/utils/file-helper.js +0 -329
- package/packages/web/app/api/projects/[id]/delete/route.ts +0 -21
- package/packages/web/app/api/stats/route.ts +0 -38
- package/packages/web/components/AppSidebar.tsx +0 -113
- package/packages/web/hooks/useStats.ts +0 -28
- /package/packages/web/components/{CommandButton.tsx → CommandButton/CommandButton.tsx} +0 -0
- /package/packages/web/components/{ConnectionStatus.tsx → ConnectionStatus/ConnectionStatus.tsx} +0 -0
- /package/packages/web/components/{Logo.tsx → Logo/Logo.tsx} +0 -0
- /package/packages/web/components/{MarkdownContent.tsx → MarkdownContent/MarkdownContent.tsx} +0 -0
- /package/packages/web/components/{ProjectAvatar.tsx → ProjectAvatar/ProjectAvatar.tsx} +0 -0
- /package/packages/web/components/{providers.tsx → Providers/Providers.tsx} +0 -0
- /package/packages/web/components/{TechStackBadges.tsx → TechStackBadges/TechStackBadges.tsx} +0 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface RoadmapPhase {
|
|
2
|
+
name: string
|
|
3
|
+
progress: number
|
|
4
|
+
features?: Array<{ name: string; status: string }>
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export interface RoadmapData {
|
|
8
|
+
phases: RoadmapPhase[]
|
|
9
|
+
progress: number
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface RoadmapCardProps {
|
|
13
|
+
roadmap: RoadmapData | null
|
|
14
|
+
className?: string
|
|
15
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { BentoCard } from '@/components/BentoCard'
|
|
2
|
+
import { EmptyState } from '@/components/EmptyState'
|
|
3
|
+
import { Rocket } from 'lucide-react'
|
|
4
|
+
import { Badge } from '@/components/ui/badge'
|
|
5
|
+
import { formatShipDate } from './ShipsCard.utils'
|
|
6
|
+
import type { ShipsCardProps } from './ShipsCard.types'
|
|
7
|
+
|
|
8
|
+
export function ShipsCard({ ships, totalShips = 0, className }: ShipsCardProps) {
|
|
9
|
+
const displayShips = ships.slice(0, 4)
|
|
10
|
+
|
|
11
|
+
return (
|
|
12
|
+
<BentoCard
|
|
13
|
+
size="1x2"
|
|
14
|
+
title="Ships"
|
|
15
|
+
icon={Rocket}
|
|
16
|
+
count={totalShips}
|
|
17
|
+
accentColor={ships.length > 0 ? 'success' : 'default'}
|
|
18
|
+
className={className}
|
|
19
|
+
>
|
|
20
|
+
{ships.length === 0 ? (
|
|
21
|
+
<EmptyState
|
|
22
|
+
icon={Rocket}
|
|
23
|
+
title="Nothing shipped yet"
|
|
24
|
+
description="Ship your first feature"
|
|
25
|
+
command="/p:ship"
|
|
26
|
+
compact
|
|
27
|
+
/>
|
|
28
|
+
) : (
|
|
29
|
+
<div className="space-y-3">
|
|
30
|
+
{displayShips.map((ship, i) => (
|
|
31
|
+
<div key={i} className="group">
|
|
32
|
+
<div className="flex items-center gap-2">
|
|
33
|
+
{ship.version && (
|
|
34
|
+
<Badge variant="outline" className="text-[10px] px-1.5 py-0 font-mono shrink-0">
|
|
35
|
+
{ship.version}
|
|
36
|
+
</Badge>
|
|
37
|
+
)}
|
|
38
|
+
<p className="text-sm font-medium truncate group-hover:text-foreground transition-colors">
|
|
39
|
+
{ship.name}
|
|
40
|
+
</p>
|
|
41
|
+
</div>
|
|
42
|
+
<p className="text-[10px] text-muted-foreground mt-0.5">
|
|
43
|
+
{formatShipDate(ship.date)}
|
|
44
|
+
{ship.duration && ` · ${ship.duration}`}
|
|
45
|
+
</p>
|
|
46
|
+
</div>
|
|
47
|
+
))}
|
|
48
|
+
</div>
|
|
49
|
+
)}
|
|
50
|
+
</BentoCard>
|
|
51
|
+
)
|
|
52
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { Area, AreaChart, ResponsiveContainer } from 'recharts'
|
|
4
|
+
import type { SparklineChartProps } from './SparklineChart.types'
|
|
5
|
+
|
|
6
|
+
export function SparklineChart({
|
|
7
|
+
data,
|
|
8
|
+
color = 'currentColor',
|
|
9
|
+
height = 32,
|
|
10
|
+
showArea = true,
|
|
11
|
+
}: SparklineChartProps) {
|
|
12
|
+
const chartData = data.map((value, index) => ({ index, value }))
|
|
13
|
+
|
|
14
|
+
if (data.length === 0) {
|
|
15
|
+
return <div style={{ height }} className="w-full" />
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<ResponsiveContainer width="100%" height={height}>
|
|
20
|
+
<AreaChart data={chartData} margin={{ top: 0, right: 0, bottom: 0, left: 0 }}>
|
|
21
|
+
<defs>
|
|
22
|
+
<linearGradient id="sparklineGradient" x1="0" y1="0" x2="0" y2="1">
|
|
23
|
+
<stop offset="0%" stopColor={color} stopOpacity={0.3} />
|
|
24
|
+
<stop offset="100%" stopColor={color} stopOpacity={0} />
|
|
25
|
+
</linearGradient>
|
|
26
|
+
</defs>
|
|
27
|
+
<Area
|
|
28
|
+
type="monotone"
|
|
29
|
+
dataKey="value"
|
|
30
|
+
stroke={color}
|
|
31
|
+
strokeWidth={1.5}
|
|
32
|
+
fill={showArea ? 'url(#sparklineGradient)' : 'none'}
|
|
33
|
+
isAnimationActive={false}
|
|
34
|
+
/>
|
|
35
|
+
</AreaChart>
|
|
36
|
+
</ResponsiveContainer>
|
|
37
|
+
)
|
|
38
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { BentoCard } from '@/components/BentoCard'
|
|
2
|
+
import { Flame } from 'lucide-react'
|
|
3
|
+
import { cn } from '@/lib/utils'
|
|
4
|
+
import { STREAK_HOT_THRESHOLD, STREAK_ON_FIRE_THRESHOLD } from './StreakCard.constants'
|
|
5
|
+
import type { StreakCardProps } from './StreakCard.types'
|
|
6
|
+
|
|
7
|
+
export function StreakCard({ streak, className }: StreakCardProps) {
|
|
8
|
+
const isHot = streak >= STREAK_HOT_THRESHOLD
|
|
9
|
+
const isOnFire = streak >= STREAK_ON_FIRE_THRESHOLD
|
|
10
|
+
|
|
11
|
+
return (
|
|
12
|
+
<BentoCard
|
|
13
|
+
size="1x1"
|
|
14
|
+
title="Streak"
|
|
15
|
+
icon={Flame}
|
|
16
|
+
accentColor={isOnFire ? 'warning' : 'default'}
|
|
17
|
+
className={className}
|
|
18
|
+
>
|
|
19
|
+
<div className="flex flex-col h-full justify-between">
|
|
20
|
+
<div className="flex items-center gap-3">
|
|
21
|
+
<Flame
|
|
22
|
+
className={cn(
|
|
23
|
+
'h-8 w-8 transition-colors',
|
|
24
|
+
isOnFire ? 'text-orange-500' : isHot ? 'text-amber-500' : 'text-muted-foreground'
|
|
25
|
+
)}
|
|
26
|
+
/>
|
|
27
|
+
<div>
|
|
28
|
+
<p className="text-3xl font-bold tabular-nums">{streak}</p>
|
|
29
|
+
<p className="text-xs text-muted-foreground">day{streak !== 1 ? 's' : ''}</p>
|
|
30
|
+
</div>
|
|
31
|
+
</div>
|
|
32
|
+
|
|
33
|
+
<div className="flex gap-1 mt-3">
|
|
34
|
+
{Array.from({ length: 7 }).map((_, i) => (
|
|
35
|
+
<div
|
|
36
|
+
key={i}
|
|
37
|
+
className={cn(
|
|
38
|
+
'h-1.5 flex-1 rounded-full transition-colors',
|
|
39
|
+
i < streak
|
|
40
|
+
? isOnFire
|
|
41
|
+
? 'bg-orange-500'
|
|
42
|
+
: isHot
|
|
43
|
+
? 'bg-amber-500'
|
|
44
|
+
: 'bg-foreground'
|
|
45
|
+
: 'bg-muted'
|
|
46
|
+
)}
|
|
47
|
+
/>
|
|
48
|
+
))}
|
|
49
|
+
</div>
|
|
50
|
+
</div>
|
|
51
|
+
</BentoCard>
|
|
52
|
+
)
|
|
53
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { TasksCounterProps } from './TasksCounter.types'
|
|
2
|
+
|
|
3
|
+
export function TasksCounter({ count }: TasksCounterProps) {
|
|
4
|
+
return (
|
|
5
|
+
<div className="flex flex-col sm:flex-row sm:items-baseline gap-1 sm:gap-3">
|
|
6
|
+
<span className="text-5xl sm:text-6xl md:text-7xl font-bold tracking-tighter tabular-nums">
|
|
7
|
+
{count}
|
|
8
|
+
</span>
|
|
9
|
+
<span className="text-sm sm:text-base md:text-lg text-muted-foreground">
|
|
10
|
+
tasks completed
|
|
11
|
+
</span>
|
|
12
|
+
</div>
|
|
13
|
+
)
|
|
14
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { TechStackBadges } from './TechStackBadges'
|
|
@@ -35,6 +35,7 @@ export function TerminalTab({ session, projectDir, isActive }: TerminalTabProps)
|
|
|
35
35
|
disconnect,
|
|
36
36
|
sendInput,
|
|
37
37
|
focusTerminal,
|
|
38
|
+
fit,
|
|
38
39
|
} = useClaudeTerminal({
|
|
39
40
|
sessionId: session.id,
|
|
40
41
|
projectDir,
|
|
@@ -57,6 +58,16 @@ export function TerminalTab({ session, projectDir, isActive }: TerminalTabProps)
|
|
|
57
58
|
}
|
|
58
59
|
}, []) // Empty deps - run only on mount
|
|
59
60
|
|
|
61
|
+
// Re-fit terminal when tab becomes active (fixes resize issues when tab was hidden)
|
|
62
|
+
useEffect(() => {
|
|
63
|
+
if (isActive && hasInitializedRef.current) {
|
|
64
|
+
// Use requestAnimationFrame to ensure container is fully visible
|
|
65
|
+
requestAnimationFrame(() => {
|
|
66
|
+
fit()
|
|
67
|
+
})
|
|
68
|
+
}
|
|
69
|
+
}, [isActive, fit])
|
|
70
|
+
|
|
60
71
|
// Register sendInput and focusTerminal for this session
|
|
61
72
|
useEffect(() => {
|
|
62
73
|
registerSendInput(session.id, sendInput)
|
|
@@ -90,8 +90,8 @@ export function TerminalTabs({ projectDir }: TerminalTabsProps) {
|
|
|
90
90
|
|
|
91
91
|
return (
|
|
92
92
|
<div className="flex flex-col h-full">
|
|
93
|
-
{/* Tab bar */}
|
|
94
|
-
<div className="flex items-center gap-1 px-2 py-1 bg-card border-b border-border min-h-[40px]">
|
|
93
|
+
{/* Tab bar - scrollable on mobile */}
|
|
94
|
+
<div className="flex items-center gap-1 px-2 py-1.5 bg-card border-b border-border min-h-[44px] md:min-h-[40px] overflow-x-auto scrollbar-hide">
|
|
95
95
|
{sessions.map(session => (
|
|
96
96
|
<div
|
|
97
97
|
key={session.id}
|
|
@@ -101,22 +101,23 @@ export function TerminalTabs({ projectDir }: TerminalTabsProps) {
|
|
|
101
101
|
tabIndex={0}
|
|
102
102
|
onKeyDown={(e) => e.key === 'Enter' && setActiveSession(session.id)}
|
|
103
103
|
className={cn(
|
|
104
|
-
'flex items-center gap-2 px-3 py-1.5 rounded-md text-sm transition-colors cursor-pointer',
|
|
105
|
-
'hover:bg-muted',
|
|
104
|
+
'flex items-center gap-2 px-3 py-2 md:py-1.5 rounded-md text-sm transition-colors cursor-pointer shrink-0',
|
|
105
|
+
'hover:bg-muted active:bg-muted/80',
|
|
106
|
+
'min-h-[36px] md:min-h-0', // Touch-friendly height on mobile
|
|
106
107
|
session.id === activeSessionId
|
|
107
108
|
? 'bg-muted text-foreground'
|
|
108
109
|
: 'text-muted-foreground'
|
|
109
110
|
)}
|
|
110
111
|
>
|
|
111
112
|
{session.isLoading ? (
|
|
112
|
-
<Loader2 className="w-3.5 h-3.5 animate-spin" />
|
|
113
|
+
<Loader2 className="w-3.5 h-3.5 animate-spin shrink-0" />
|
|
113
114
|
) : session.isConnected ? (
|
|
114
|
-
<span className="relative flex h-2 w-2">
|
|
115
|
+
<span className="relative flex h-2.5 w-2.5 shrink-0">
|
|
115
116
|
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-green-400 opacity-75" />
|
|
116
|
-
<span className="relative inline-flex rounded-full h-2 w-2 bg-green-500" />
|
|
117
|
+
<span className="relative inline-flex rounded-full h-2.5 w-2.5 bg-green-500" />
|
|
117
118
|
</span>
|
|
118
119
|
) : (
|
|
119
|
-
<span className="h-2 w-2 rounded-full bg-muted-foreground/50" />
|
|
120
|
+
<span className="h-2.5 w-2.5 rounded-full bg-muted-foreground/50 shrink-0" />
|
|
120
121
|
)}
|
|
121
122
|
{editingSessionId === session.id ? (
|
|
122
123
|
<input
|
|
@@ -130,41 +131,41 @@ export function TerminalTabs({ projectDir }: TerminalTabsProps) {
|
|
|
130
131
|
className="w-[100px] bg-background border border-border rounded px-1 py-0.5 text-sm outline-none focus:ring-1 focus:ring-ring"
|
|
131
132
|
/>
|
|
132
133
|
) : (
|
|
133
|
-
<span className="truncate max-w-[100px]">{session.label}</span>
|
|
134
|
+
<span className="truncate max-w-[80px] md:max-w-[100px]">{session.label}</span>
|
|
134
135
|
)}
|
|
135
136
|
<button
|
|
136
137
|
onClick={(e) => handleCloseTab(session.id, e)}
|
|
137
|
-
className="p-0.5 rounded hover:bg-background/50 text-muted-foreground hover:text-foreground"
|
|
138
|
+
className="p-1 md:p-0.5 rounded hover:bg-background/50 text-muted-foreground hover:text-foreground shrink-0"
|
|
138
139
|
>
|
|
139
|
-
<X className="w-3 h-3" />
|
|
140
|
+
<X className="w-4 h-4 md:w-3 md:h-3" />
|
|
140
141
|
</button>
|
|
141
142
|
</div>
|
|
142
143
|
))}
|
|
143
144
|
|
|
144
|
-
{/* New tab button */}
|
|
145
|
+
{/* New tab button - larger touch target on mobile */}
|
|
145
146
|
<Button
|
|
146
147
|
variant="ghost"
|
|
147
148
|
size="icon"
|
|
148
|
-
className="h-7 w-7 ml-1"
|
|
149
|
+
className="h-9 w-9 md:h-7 md:w-7 ml-1 shrink-0"
|
|
149
150
|
onClick={createSession}
|
|
150
151
|
>
|
|
151
|
-
<Plus className="w-4 h-4" />
|
|
152
|
+
<Plus className="w-5 h-5 md:w-4 md:h-4" />
|
|
152
153
|
</Button>
|
|
153
154
|
</div>
|
|
154
155
|
|
|
155
156
|
{/* Terminal area */}
|
|
156
157
|
<div className="flex-1 relative">
|
|
157
158
|
{hasNoSessions ? (
|
|
158
|
-
<div className="absolute inset-0 flex items-center justify-center bg-background">
|
|
159
|
-
<div className="text-center">
|
|
160
|
-
<div className="w-16 h-16 rounded-full bg-muted flex items-center justify-center mx-auto mb-4">
|
|
161
|
-
<TerminalIcon className="w-8 h-8 text-muted-foreground" />
|
|
159
|
+
<div className="absolute inset-0 flex items-center justify-center bg-background p-4">
|
|
160
|
+
<div className="text-center max-w-xs">
|
|
161
|
+
<div className="w-14 h-14 md:w-16 md:h-16 rounded-full bg-muted flex items-center justify-center mx-auto mb-3 md:mb-4">
|
|
162
|
+
<TerminalIcon className="w-7 h-7 md:w-8 md:h-8 text-muted-foreground" />
|
|
162
163
|
</div>
|
|
163
|
-
<h2 className="text-lg font-medium mb-2">No active sessions</h2>
|
|
164
|
-
<p className="text-muted-foreground text-sm mb-4">
|
|
165
|
-
|
|
164
|
+
<h2 className="text-base md:text-lg font-medium mb-1.5 md:mb-2">No active sessions</h2>
|
|
165
|
+
<p className="text-muted-foreground text-sm mb-3 md:mb-4">
|
|
166
|
+
Tap + to create a new terminal
|
|
166
167
|
</p>
|
|
167
|
-
<Button onClick={createSession}>
|
|
168
|
+
<Button onClick={createSession} className="min-h-[44px]">
|
|
168
169
|
<Plus className="w-4 h-4 mr-2" />
|
|
169
170
|
New Terminal
|
|
170
171
|
</Button>
|
|
@@ -182,23 +183,23 @@ export function TerminalTabs({ projectDir }: TerminalTabsProps) {
|
|
|
182
183
|
)}
|
|
183
184
|
</div>
|
|
184
185
|
|
|
185
|
-
{/* Close confirmation dialog */}
|
|
186
|
+
{/* Close confirmation dialog - responsive */}
|
|
186
187
|
<AlertDialog open={!!sessionToClose} onOpenChange={(open: boolean) => !open && setSessionToClose(null)}>
|
|
187
|
-
<AlertDialogContent>
|
|
188
|
+
<AlertDialogContent className="max-w-[calc(100vw-2rem)] sm:max-w-lg">
|
|
188
189
|
<AlertDialogHeader>
|
|
189
190
|
<AlertDialogTitle className="flex items-center gap-2">
|
|
190
|
-
<AlertTriangle className="w-5 h-5 text-destructive" />
|
|
191
|
+
<AlertTriangle className="w-5 h-5 text-destructive shrink-0" />
|
|
191
192
|
Close Terminal?
|
|
192
193
|
</AlertDialogTitle>
|
|
193
194
|
<AlertDialogDescription>
|
|
194
195
|
This terminal has an active session. Closing it will terminate the connection.
|
|
195
196
|
</AlertDialogDescription>
|
|
196
197
|
</AlertDialogHeader>
|
|
197
|
-
<AlertDialogFooter>
|
|
198
|
-
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
|
198
|
+
<AlertDialogFooter className="flex-col sm:flex-row gap-2">
|
|
199
|
+
<AlertDialogCancel className="w-full sm:w-auto">Cancel</AlertDialogCancel>
|
|
199
200
|
<AlertDialogAction
|
|
200
201
|
onClick={handleConfirmClose}
|
|
201
|
-
className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
|
|
202
|
+
className="bg-destructive text-destructive-foreground hover:bg-destructive/90 w-full sm:w-auto"
|
|
202
203
|
>
|
|
203
204
|
Close Terminal
|
|
204
205
|
</AlertDialogAction>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { TerminalTabs } from './TerminalTabs'
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { TrendingUp, TrendingDown } from 'lucide-react'
|
|
2
|
+
import { cn } from '@/lib/utils'
|
|
3
|
+
import type { VelocityBadgeProps } from './VelocityBadge.types'
|
|
4
|
+
|
|
5
|
+
export function VelocityBadge({ change }: VelocityBadgeProps) {
|
|
6
|
+
if (change === 0) return null
|
|
7
|
+
|
|
8
|
+
const isPositive = change >= 0
|
|
9
|
+
const Icon = isPositive ? TrendingUp : TrendingDown
|
|
10
|
+
|
|
11
|
+
return (
|
|
12
|
+
<div className="flex items-center gap-2 mt-2">
|
|
13
|
+
<span
|
|
14
|
+
className={cn(
|
|
15
|
+
'inline-flex items-center gap-1 text-xs sm:text-sm font-medium px-2 py-0.5 rounded-md',
|
|
16
|
+
isPositive
|
|
17
|
+
? 'bg-emerald-500/10 text-emerald-600 dark:text-emerald-400'
|
|
18
|
+
: 'bg-muted text-muted-foreground'
|
|
19
|
+
)}
|
|
20
|
+
>
|
|
21
|
+
<Icon className="h-3 w-3 sm:h-3.5 sm:w-3.5" />
|
|
22
|
+
{isPositive ? '+' : ''}{change}%
|
|
23
|
+
</span>
|
|
24
|
+
<span className="text-xs sm:text-sm text-muted-foreground">vs last week</span>
|
|
25
|
+
</div>
|
|
26
|
+
)
|
|
27
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { BentoCard } from '@/components/BentoCard'
|
|
2
|
+
import { SparklineChart } from '@/components/SparklineChart'
|
|
3
|
+
import { Zap, TrendingUp, TrendingDown, Target } from 'lucide-react'
|
|
4
|
+
import { cn } from '@/lib/utils'
|
|
5
|
+
import type { VelocityCardProps } from './VelocityCard.types'
|
|
6
|
+
|
|
7
|
+
export function VelocityCard({
|
|
8
|
+
tasksPerDay,
|
|
9
|
+
weeklyData = [],
|
|
10
|
+
change = 0,
|
|
11
|
+
estimateAccuracy,
|
|
12
|
+
className,
|
|
13
|
+
}: VelocityCardProps) {
|
|
14
|
+
return (
|
|
15
|
+
<BentoCard
|
|
16
|
+
size="1x1"
|
|
17
|
+
title="Velocity"
|
|
18
|
+
icon={Zap}
|
|
19
|
+
className={className}
|
|
20
|
+
>
|
|
21
|
+
<div className="flex flex-col h-full justify-between">
|
|
22
|
+
<div>
|
|
23
|
+
<p className="text-3xl font-bold tabular-nums">{tasksPerDay}</p>
|
|
24
|
+
<p className="text-xs text-muted-foreground">tasks/day</p>
|
|
25
|
+
</div>
|
|
26
|
+
|
|
27
|
+
{weeklyData.length > 0 && (
|
|
28
|
+
<div className="mt-2">
|
|
29
|
+
<SparklineChart data={weeklyData} height={28} />
|
|
30
|
+
</div>
|
|
31
|
+
)}
|
|
32
|
+
|
|
33
|
+
<div className="flex items-center justify-between mt-2">
|
|
34
|
+
{change !== 0 && (
|
|
35
|
+
<div className="flex items-center gap-1">
|
|
36
|
+
{change >= 0 ? (
|
|
37
|
+
<TrendingUp className="h-3 w-3 text-emerald-500" />
|
|
38
|
+
) : (
|
|
39
|
+
<TrendingDown className="h-3 w-3 text-muted-foreground" />
|
|
40
|
+
)}
|
|
41
|
+
<span
|
|
42
|
+
className={cn(
|
|
43
|
+
'text-xs font-medium',
|
|
44
|
+
change >= 0 ? 'text-emerald-600 dark:text-emerald-400' : 'text-muted-foreground'
|
|
45
|
+
)}
|
|
46
|
+
>
|
|
47
|
+
{change >= 0 ? '+' : ''}{change}%
|
|
48
|
+
</span>
|
|
49
|
+
</div>
|
|
50
|
+
)}
|
|
51
|
+
|
|
52
|
+
{estimateAccuracy !== undefined && estimateAccuracy > 0 && (
|
|
53
|
+
<div className="flex items-center gap-1">
|
|
54
|
+
<Target className="h-3 w-3 text-muted-foreground" />
|
|
55
|
+
<span
|
|
56
|
+
className={cn(
|
|
57
|
+
'text-xs font-medium',
|
|
58
|
+
estimateAccuracy >= 70 ? 'text-emerald-600 dark:text-emerald-400' :
|
|
59
|
+
estimateAccuracy >= 40 ? 'text-amber-600 dark:text-amber-400' :
|
|
60
|
+
'text-muted-foreground'
|
|
61
|
+
)}
|
|
62
|
+
>
|
|
63
|
+
{estimateAccuracy}% acc
|
|
64
|
+
</span>
|
|
65
|
+
</div>
|
|
66
|
+
)}
|
|
67
|
+
</div>
|
|
68
|
+
</div>
|
|
69
|
+
</BentoCard>
|
|
70
|
+
)
|
|
71
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { SparklineChart } from '@/components/SparklineChart'
|
|
2
|
+
import type { WeeklySparklineProps } from './WeeklySparkline.types'
|
|
3
|
+
|
|
4
|
+
export function WeeklySparkline({ data }: WeeklySparklineProps) {
|
|
5
|
+
return (
|
|
6
|
+
<div className="w-full sm:w-32">
|
|
7
|
+
<p className="text-[10px] uppercase tracking-wider text-muted-foreground mb-1 md:text-right">
|
|
8
|
+
7-day activity
|
|
9
|
+
</p>
|
|
10
|
+
<SparklineChart data={data} height={40} />
|
|
11
|
+
</div>
|
|
12
|
+
)
|
|
13
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
|
|
3
|
+
import { cn } from "@/lib/utils"
|
|
4
|
+
|
|
5
|
+
function Input({ className, type, ...props }: React.ComponentProps<"input">) {
|
|
6
|
+
return (
|
|
7
|
+
<input
|
|
8
|
+
type={type}
|
|
9
|
+
data-slot="input"
|
|
10
|
+
className={cn(
|
|
11
|
+
"file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
|
12
|
+
"focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
|
|
13
|
+
"aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
|
|
14
|
+
className
|
|
15
|
+
)}
|
|
16
|
+
{...props}
|
|
17
|
+
/>
|
|
18
|
+
)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export { Input }
|
|
@@ -46,13 +46,13 @@ function TooltipContent({
|
|
|
46
46
|
data-slot="tooltip-content"
|
|
47
47
|
sideOffset={sideOffset}
|
|
48
48
|
className={cn(
|
|
49
|
-
"bg-
|
|
49
|
+
"bg-popover text-popover-foreground border shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit origin-(--radix-tooltip-content-transform-origin) rounded-md px-3 py-1.5 text-xs text-balance",
|
|
50
50
|
className
|
|
51
51
|
)}
|
|
52
52
|
{...props}
|
|
53
53
|
>
|
|
54
54
|
{children}
|
|
55
|
-
<TooltipPrimitive.Arrow className="bg-
|
|
55
|
+
<TooltipPrimitive.Arrow className="bg-popover fill-popover z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]" />
|
|
56
56
|
</TooltipPrimitive.Content>
|
|
57
57
|
</TooltipPrimitive.Portal>
|
|
58
58
|
)
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Terminal Tabs Context - Manage multiple terminal sessions
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { createContext, useContext, useCallback, useState, useRef, ReactNode } from 'react'
|
|
7
|
+
import { createContext, useContext, useCallback, useState, useRef, useEffect, ReactNode } from 'react'
|
|
8
8
|
|
|
9
9
|
export interface TerminalSession {
|
|
10
10
|
id: string
|
|
@@ -108,6 +108,51 @@ export function TerminalTabsProvider({ children, projectId }: { children: ReactN
|
|
|
108
108
|
}
|
|
109
109
|
}, [activeSessionId, sessions])
|
|
110
110
|
|
|
111
|
+
// Check if any session is connected
|
|
112
|
+
const hasConnectedSessions = sessions.some(s => s.isConnected)
|
|
113
|
+
|
|
114
|
+
// Prevent page unload when terminal sessions are active
|
|
115
|
+
useEffect(() => {
|
|
116
|
+
if (!hasConnectedSessions) return
|
|
117
|
+
|
|
118
|
+
const handleBeforeUnload = (e: BeforeUnloadEvent) => {
|
|
119
|
+
e.preventDefault()
|
|
120
|
+
// Modern browsers require returnValue to be set
|
|
121
|
+
e.returnValue = 'You have active terminal sessions. Are you sure you want to leave?'
|
|
122
|
+
return e.returnValue
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
window.addEventListener('beforeunload', handleBeforeUnload)
|
|
126
|
+
return () => window.removeEventListener('beforeunload', handleBeforeUnload)
|
|
127
|
+
}, [hasConnectedSessions])
|
|
128
|
+
|
|
129
|
+
// Prevent back/forward navigation when terminal sessions are active
|
|
130
|
+
useEffect(() => {
|
|
131
|
+
if (!hasConnectedSessions) return
|
|
132
|
+
|
|
133
|
+
// Push a state to history so we can intercept back navigation
|
|
134
|
+
const currentPath = window.location.pathname + window.location.search
|
|
135
|
+
window.history.pushState({ terminalActive: true }, '', currentPath)
|
|
136
|
+
|
|
137
|
+
const handlePopState = (e: PopStateEvent) => {
|
|
138
|
+
// User pressed back/forward
|
|
139
|
+
const confirmLeave = window.confirm(
|
|
140
|
+
'You have active terminal sessions. Leaving will terminate them. Are you sure?'
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
if (!confirmLeave) {
|
|
144
|
+
// Cancel navigation by pushing state back
|
|
145
|
+
window.history.pushState({ terminalActive: true }, '', currentPath)
|
|
146
|
+
}
|
|
147
|
+
// If confirmed, let the navigation happen naturally
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
window.addEventListener('popstate', handlePopState)
|
|
151
|
+
return () => {
|
|
152
|
+
window.removeEventListener('popstate', handlePopState)
|
|
153
|
+
}
|
|
154
|
+
}, [hasConnectedSessions])
|
|
155
|
+
|
|
111
156
|
return (
|
|
112
157
|
<TerminalTabsContext.Provider value={{
|
|
113
158
|
sessions,
|