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,630 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON Loader
|
|
3
|
+
*
|
|
4
|
+
* Loads project data directly from JSON files in data/ directory.
|
|
5
|
+
* JSON is source of truth, MD is generated for Claude.
|
|
6
|
+
*
|
|
7
|
+
* New Architecture:
|
|
8
|
+
* ~/.prjct-cli/projects/{projectId}/
|
|
9
|
+
* └── data/ # JSON source of truth
|
|
10
|
+
* ├── state.json # Current task
|
|
11
|
+
* ├── queue.json # Task queue
|
|
12
|
+
* ├── ideas.json # Ideas
|
|
13
|
+
* ├── roadmap.json # Features
|
|
14
|
+
* ├── shipped.json # Shipped items
|
|
15
|
+
* ├── metrics.json # Stats
|
|
16
|
+
* └── project.json # Metadata
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { promises as fs } from 'fs'
|
|
20
|
+
import { join } from 'path'
|
|
21
|
+
import { homedir } from 'os'
|
|
22
|
+
|
|
23
|
+
const GLOBAL_STORAGE = join(homedir(), '.prjct-cli', 'projects')
|
|
24
|
+
|
|
25
|
+
// ============================================
|
|
26
|
+
// TYPES - Match enriched schemas from migration.server.ts
|
|
27
|
+
// ============================================
|
|
28
|
+
|
|
29
|
+
export type Priority = 'low' | 'medium' | 'high' | 'critical'
|
|
30
|
+
export type TaskType = 'feature' | 'bug' | 'improvement' | 'chore'
|
|
31
|
+
export type TaskSection = 'active' | 'backlog' | 'previously_active'
|
|
32
|
+
|
|
33
|
+
// Duration object for parsed time strings like "13h 38m"
|
|
34
|
+
export interface Duration {
|
|
35
|
+
hours: number
|
|
36
|
+
minutes: number
|
|
37
|
+
totalMinutes: number
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Code metrics from "Files: 4 | +160/-31 | Commits: 0"
|
|
41
|
+
export interface CodeMetrics {
|
|
42
|
+
filesChanged?: number | null
|
|
43
|
+
linesAdded?: number | null
|
|
44
|
+
linesRemoved?: number | null
|
|
45
|
+
commits?: number | null
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Git commit information
|
|
49
|
+
export interface CommitInfo {
|
|
50
|
+
hash?: string
|
|
51
|
+
message?: string
|
|
52
|
+
branch?: string
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface CurrentTask {
|
|
56
|
+
id: string
|
|
57
|
+
description: string
|
|
58
|
+
startedAt: string
|
|
59
|
+
sessionId: string
|
|
60
|
+
featureId?: string
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface PreviousTask {
|
|
64
|
+
id: string
|
|
65
|
+
description: string
|
|
66
|
+
status: 'paused'
|
|
67
|
+
startedAt: string
|
|
68
|
+
pausedAt: string
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export interface StateJson {
|
|
72
|
+
currentTask: CurrentTask | null
|
|
73
|
+
previousTask?: PreviousTask | null
|
|
74
|
+
lastUpdated: string
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export interface QueueTask {
|
|
78
|
+
id: string
|
|
79
|
+
description: string
|
|
80
|
+
priority: Priority
|
|
81
|
+
type: TaskType
|
|
82
|
+
featureId?: string
|
|
83
|
+
originFeature?: string
|
|
84
|
+
completed: boolean
|
|
85
|
+
completedAt?: string
|
|
86
|
+
createdAt: string
|
|
87
|
+
section: TaskSection
|
|
88
|
+
// ZERO DATA LOSS fields
|
|
89
|
+
agent?: string // "fe", "be", "fe + be"
|
|
90
|
+
groupName?: string // "Sales Reports", "Stock Audits"
|
|
91
|
+
groupId?: string // For grouping related tasks
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export interface QueueJson {
|
|
95
|
+
tasks: QueueTask[]
|
|
96
|
+
lastUpdated: string
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export type IdeaPriority = 'low' | 'medium' | 'high'
|
|
100
|
+
export type IdeaStatus = 'pending' | 'converted' | 'completed' | 'archived'
|
|
101
|
+
|
|
102
|
+
export interface ImpactEffort {
|
|
103
|
+
impact: 'high' | 'medium' | 'low'
|
|
104
|
+
effort: 'high' | 'medium' | 'low'
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Tech stack definition for idea specs
|
|
108
|
+
export interface TechStack {
|
|
109
|
+
frontend?: string
|
|
110
|
+
backend?: string
|
|
111
|
+
payments?: string
|
|
112
|
+
ai?: string
|
|
113
|
+
deploy?: string
|
|
114
|
+
other?: string[]
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Module definition for complex ideas
|
|
118
|
+
export interface IdeaModule {
|
|
119
|
+
name: string
|
|
120
|
+
description: string
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Role definition
|
|
124
|
+
export interface IdeaRole {
|
|
125
|
+
name: string
|
|
126
|
+
description?: string
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export interface IdeaSchema {
|
|
130
|
+
id: string
|
|
131
|
+
text: string
|
|
132
|
+
details?: string
|
|
133
|
+
priority: IdeaPriority
|
|
134
|
+
status: IdeaStatus
|
|
135
|
+
tags: string[]
|
|
136
|
+
addedAt: string
|
|
137
|
+
completedAt?: string
|
|
138
|
+
convertedTo?: string
|
|
139
|
+
// Source documentation
|
|
140
|
+
source?: string
|
|
141
|
+
sourceFiles?: string[]
|
|
142
|
+
// Enriched fields from MD
|
|
143
|
+
painPoints?: string[]
|
|
144
|
+
solutions?: string[]
|
|
145
|
+
filesAffected?: string[]
|
|
146
|
+
impactEffort?: ImpactEffort
|
|
147
|
+
implementationNotes?: string
|
|
148
|
+
// Technical spec fields for ZERO DATA LOSS
|
|
149
|
+
stack?: TechStack
|
|
150
|
+
modules?: IdeaModule[]
|
|
151
|
+
roles?: IdeaRole[]
|
|
152
|
+
risks?: string[]
|
|
153
|
+
risksCount?: number
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export interface IdeasJson {
|
|
157
|
+
ideas: IdeaSchema[]
|
|
158
|
+
lastUpdated: string
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export type FeatureStatus = 'planned' | 'active' | 'completed' | 'shipped'
|
|
162
|
+
export type FeatureImpact = 'low' | 'medium' | 'high'
|
|
163
|
+
export type FeatureType = 'feature' | 'breaking_change' | 'refactor' | 'infrastructure'
|
|
164
|
+
|
|
165
|
+
export interface FeatureTask {
|
|
166
|
+
id: string
|
|
167
|
+
description: string
|
|
168
|
+
completed: boolean
|
|
169
|
+
completedAt?: string
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export interface RoadmapPhase {
|
|
173
|
+
id: string
|
|
174
|
+
name: string
|
|
175
|
+
status: 'completed' | 'active' | 'planned'
|
|
176
|
+
completedAt?: string
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export interface RoadmapStrategy {
|
|
180
|
+
goal: string
|
|
181
|
+
phases: RoadmapPhase[]
|
|
182
|
+
successMetrics?: string[]
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Duration for completed sprints/features
|
|
186
|
+
export interface FeatureDuration {
|
|
187
|
+
hours: number
|
|
188
|
+
minutes: number
|
|
189
|
+
totalMinutes: number
|
|
190
|
+
display?: string
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export interface FeatureSchema {
|
|
194
|
+
id: string
|
|
195
|
+
name: string
|
|
196
|
+
description?: string
|
|
197
|
+
date: string
|
|
198
|
+
status: FeatureStatus
|
|
199
|
+
impact: FeatureImpact
|
|
200
|
+
effort?: string
|
|
201
|
+
progress: number
|
|
202
|
+
// Enriched fields from MD
|
|
203
|
+
type?: FeatureType
|
|
204
|
+
roi?: number // 1-5 from star count
|
|
205
|
+
why?: string[]
|
|
206
|
+
technicalNotes?: string[]
|
|
207
|
+
compatibility?: string
|
|
208
|
+
phase?: string
|
|
209
|
+
tasks: FeatureTask[]
|
|
210
|
+
createdAt: string
|
|
211
|
+
shippedAt?: string
|
|
212
|
+
version?: string
|
|
213
|
+
// ZERO DATA LOSS - additional fields
|
|
214
|
+
duration?: FeatureDuration
|
|
215
|
+
taskCount?: number
|
|
216
|
+
agent?: string
|
|
217
|
+
sprintName?: string
|
|
218
|
+
completedDate?: string
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export interface RoadmapJson {
|
|
222
|
+
strategy?: RoadmapStrategy | null
|
|
223
|
+
features: FeatureSchema[]
|
|
224
|
+
backlog: string[]
|
|
225
|
+
lastUpdated: string
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
export type ShipType = 'feature' | 'fix' | 'improvement' | 'refactor'
|
|
229
|
+
export type CheckStatus = 'pass' | 'warning' | 'fail' | 'skipped'
|
|
230
|
+
|
|
231
|
+
export interface ShipChange {
|
|
232
|
+
description: string
|
|
233
|
+
type?: 'added' | 'changed' | 'fixed' | 'removed'
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
export interface QualityMetrics {
|
|
237
|
+
lintStatus?: CheckStatus | null
|
|
238
|
+
lintDetails?: string
|
|
239
|
+
testStatus?: CheckStatus | null
|
|
240
|
+
testDetails?: string
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
export type AgentType = 'fe' | 'be' | 'fe+be' | 'devops' | 'ai' | string
|
|
244
|
+
|
|
245
|
+
export interface ShippedItemSchema {
|
|
246
|
+
id: string
|
|
247
|
+
name: string
|
|
248
|
+
version?: string | null
|
|
249
|
+
type: ShipType
|
|
250
|
+
// Agent who worked on this
|
|
251
|
+
agent?: AgentType
|
|
252
|
+
// Full description (narrative text, not just bullet points)
|
|
253
|
+
description?: string
|
|
254
|
+
// Changelog from bullet points
|
|
255
|
+
changes: ShipChange[]
|
|
256
|
+
// Code snippets if any
|
|
257
|
+
codeSnippets?: string[]
|
|
258
|
+
// Git commit info
|
|
259
|
+
commit?: CommitInfo
|
|
260
|
+
// Enriched fields from MD
|
|
261
|
+
codeMetrics?: CodeMetrics
|
|
262
|
+
qualityMetrics?: QualityMetrics
|
|
263
|
+
quantitativeImpact?: string
|
|
264
|
+
duration?: Duration
|
|
265
|
+
tasksCompleted?: number | null
|
|
266
|
+
shippedAt: string
|
|
267
|
+
featureId?: string
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
export interface ShippedJson {
|
|
271
|
+
items: ShippedItemSchema[]
|
|
272
|
+
lastUpdated: string
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
export interface RecentActivity {
|
|
276
|
+
timestamp: string
|
|
277
|
+
action: 'started' | 'completed' | 'shipped' | 'paused'
|
|
278
|
+
description: string
|
|
279
|
+
duration?: { hours: number; minutes: number }
|
|
280
|
+
codeChanges?: CodeMetrics
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
export interface MetricsJson {
|
|
284
|
+
currentSprint: {
|
|
285
|
+
tasksStarted: number
|
|
286
|
+
tasksCompleted: number
|
|
287
|
+
inProgress: number
|
|
288
|
+
}
|
|
289
|
+
allTime: {
|
|
290
|
+
featuresShipped: number
|
|
291
|
+
tasksCompleted: number
|
|
292
|
+
totalTimeTracked: Duration
|
|
293
|
+
daysActive: number
|
|
294
|
+
}
|
|
295
|
+
velocity: {
|
|
296
|
+
featuresPerWeek: number
|
|
297
|
+
tasksPerDay: number
|
|
298
|
+
}
|
|
299
|
+
recentActivity: RecentActivity[]
|
|
300
|
+
lastUpdated: string
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
export interface ProjectJson {
|
|
304
|
+
projectId: string
|
|
305
|
+
name: string
|
|
306
|
+
repoPath: string
|
|
307
|
+
description?: string
|
|
308
|
+
version?: string
|
|
309
|
+
techStack: string[]
|
|
310
|
+
fileCount: number
|
|
311
|
+
commitCount: number
|
|
312
|
+
createdAt: string
|
|
313
|
+
lastSync: string
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
export interface AgentJson {
|
|
317
|
+
name: string
|
|
318
|
+
description: string
|
|
319
|
+
skills: string[]
|
|
320
|
+
patterns: string[]
|
|
321
|
+
filesOwned: string[]
|
|
322
|
+
successRate?: number
|
|
323
|
+
tasksCompleted?: number
|
|
324
|
+
bestFor: string[]
|
|
325
|
+
avoidFor: string[]
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
export interface AnalysisJson {
|
|
329
|
+
projectId: string
|
|
330
|
+
languages: string[]
|
|
331
|
+
frameworks: string[]
|
|
332
|
+
packageManager?: string
|
|
333
|
+
sourceDir?: string
|
|
334
|
+
testDir?: string
|
|
335
|
+
configFiles: string[]
|
|
336
|
+
fileCount: number
|
|
337
|
+
patterns: Array<{ name: string; description: string; location?: string }>
|
|
338
|
+
antiPatterns: Array<{ issue: string; file: string; suggestion: string }>
|
|
339
|
+
analyzedAt: string
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
export interface OutcomeJson {
|
|
343
|
+
id: string
|
|
344
|
+
taskId: string
|
|
345
|
+
description: string
|
|
346
|
+
estimatedDuration?: string
|
|
347
|
+
actualDuration: string
|
|
348
|
+
completedAsPlanned: boolean
|
|
349
|
+
qualityScore: 1 | 2 | 3 | 4 | 5
|
|
350
|
+
blockers: string[]
|
|
351
|
+
agentUsed?: string
|
|
352
|
+
completedAt: string
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// ============================================
|
|
356
|
+
// HELPERS
|
|
357
|
+
// ============================================
|
|
358
|
+
|
|
359
|
+
async function readJsonFile<T>(filePath: string, defaultValue: T): Promise<T> {
|
|
360
|
+
try {
|
|
361
|
+
const content = await fs.readFile(filePath, 'utf-8')
|
|
362
|
+
return JSON.parse(content) as T
|
|
363
|
+
} catch {
|
|
364
|
+
return defaultValue
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
async function fileExists(filePath: string): Promise<boolean> {
|
|
369
|
+
try {
|
|
370
|
+
await fs.access(filePath)
|
|
371
|
+
return true
|
|
372
|
+
} catch {
|
|
373
|
+
return false
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
function getDataPath(projectId: string): string {
|
|
378
|
+
return join(GLOBAL_STORAGE, projectId, 'data')
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
function getProjectPath(projectId: string): string {
|
|
382
|
+
return join(GLOBAL_STORAGE, projectId)
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
// ============================================
|
|
386
|
+
// LOADERS - Read from data/ directory
|
|
387
|
+
// ============================================
|
|
388
|
+
|
|
389
|
+
export async function loadState(projectId: string): Promise<StateJson | null> {
|
|
390
|
+
const filePath = join(getDataPath(projectId), 'state.json')
|
|
391
|
+
if (!await fileExists(filePath)) return null
|
|
392
|
+
return readJsonFile<StateJson>(filePath, null as unknown as StateJson)
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
export async function loadQueue(projectId: string): Promise<QueueJson | null> {
|
|
396
|
+
const filePath = join(getDataPath(projectId), 'queue.json')
|
|
397
|
+
if (!await fileExists(filePath)) return null
|
|
398
|
+
return readJsonFile<QueueJson>(filePath, null as unknown as QueueJson)
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
export async function loadIdeas(projectId: string): Promise<IdeasJson | null> {
|
|
402
|
+
const filePath = join(getDataPath(projectId), 'ideas.json')
|
|
403
|
+
if (!await fileExists(filePath)) return null
|
|
404
|
+
return readJsonFile<IdeasJson>(filePath, null as unknown as IdeasJson)
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
export async function loadRoadmap(projectId: string): Promise<RoadmapJson | null> {
|
|
408
|
+
const filePath = join(getDataPath(projectId), 'roadmap.json')
|
|
409
|
+
if (!await fileExists(filePath)) return null
|
|
410
|
+
return readJsonFile<RoadmapJson>(filePath, null as unknown as RoadmapJson)
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
export async function loadShipped(projectId: string): Promise<ShippedJson | null> {
|
|
414
|
+
const filePath = join(getDataPath(projectId), 'shipped.json')
|
|
415
|
+
if (!await fileExists(filePath)) return null
|
|
416
|
+
return readJsonFile<ShippedJson>(filePath, null as unknown as ShippedJson)
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
export async function loadMetrics(projectId: string): Promise<MetricsJson | null> {
|
|
420
|
+
const filePath = join(getDataPath(projectId), 'metrics.json')
|
|
421
|
+
if (!await fileExists(filePath)) return null
|
|
422
|
+
return readJsonFile<MetricsJson>(filePath, null as unknown as MetricsJson)
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
export async function loadProject(projectId: string): Promise<ProjectJson | null> {
|
|
426
|
+
// Try data/ first, then root for backwards compatibility
|
|
427
|
+
let filePath = join(getDataPath(projectId), 'project.json')
|
|
428
|
+
if (!await fileExists(filePath)) {
|
|
429
|
+
filePath = join(getProjectPath(projectId), 'project.json')
|
|
430
|
+
}
|
|
431
|
+
if (!await fileExists(filePath)) return null
|
|
432
|
+
return readJsonFile<ProjectJson>(filePath, null as unknown as ProjectJson)
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
export async function loadAgents(projectId: string): Promise<AgentJson[]> {
|
|
436
|
+
const filePath = join(getDataPath(projectId), 'agents.json')
|
|
437
|
+
return readJsonFile<AgentJson[]>(filePath, [])
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
export async function loadAnalysis(projectId: string): Promise<AnalysisJson | null> {
|
|
441
|
+
const filePath = join(getDataPath(projectId), 'analysis.json')
|
|
442
|
+
if (!await fileExists(filePath)) return null
|
|
443
|
+
return readJsonFile<AnalysisJson>(filePath, null as unknown as AnalysisJson)
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
export async function loadOutcomes(projectId: string): Promise<OutcomeJson[]> {
|
|
447
|
+
const filePath = join(getDataPath(projectId), 'outcomes.json')
|
|
448
|
+
return readJsonFile<OutcomeJson[]>(filePath, [])
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// ============================================
|
|
452
|
+
// UNIFIED LOADER
|
|
453
|
+
// ============================================
|
|
454
|
+
|
|
455
|
+
export interface UnifiedJsonData {
|
|
456
|
+
state: StateJson | null
|
|
457
|
+
queue: QueueJson | null
|
|
458
|
+
project: ProjectJson | null
|
|
459
|
+
agents: AgentJson[]
|
|
460
|
+
ideas: IdeasJson | null
|
|
461
|
+
roadmap: RoadmapJson | null
|
|
462
|
+
shipped: ShippedJson | null
|
|
463
|
+
metrics: MetricsJson | null
|
|
464
|
+
analysis: AnalysisJson | null
|
|
465
|
+
outcomes: OutcomeJson[]
|
|
466
|
+
// Computed
|
|
467
|
+
insights: ProjectInsights
|
|
468
|
+
hasJsonData: boolean
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
export interface ProjectInsights {
|
|
472
|
+
healthScore: number
|
|
473
|
+
estimateAccuracy: number
|
|
474
|
+
topBlockers: string[]
|
|
475
|
+
patternsDetected: string[]
|
|
476
|
+
recommendations: string[]
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
function computeInsights(data: {
|
|
480
|
+
state: StateJson | null
|
|
481
|
+
queue: QueueJson | null
|
|
482
|
+
metrics: MetricsJson | null
|
|
483
|
+
outcomes: OutcomeJson[]
|
|
484
|
+
agents: AgentJson[]
|
|
485
|
+
roadmap: RoadmapJson | null
|
|
486
|
+
}): ProjectInsights {
|
|
487
|
+
let healthScore = 50
|
|
488
|
+
|
|
489
|
+
// State-based scoring
|
|
490
|
+
if (data.state?.currentTask) {
|
|
491
|
+
healthScore += 10
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
// Metrics-based scoring
|
|
495
|
+
if (data.metrics) {
|
|
496
|
+
healthScore += Math.min(10, (data.metrics.velocity?.tasksPerDay || 0) * 2)
|
|
497
|
+
healthScore += Math.min(5, data.metrics.allTime?.daysActive || 0)
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
// Queue scoring
|
|
501
|
+
if (data.queue) {
|
|
502
|
+
const pendingTasks = data.queue.tasks.filter(t => !t.completed).length
|
|
503
|
+
if (pendingTasks > 15) healthScore -= 5
|
|
504
|
+
if (pendingTasks < 5 && pendingTasks > 0) healthScore += 5
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
// Outcomes-based scoring
|
|
508
|
+
const outcomes = data.outcomes
|
|
509
|
+
let estimateAccuracy = 0
|
|
510
|
+
const topBlockers: string[] = []
|
|
511
|
+
const patternsDetected: string[] = []
|
|
512
|
+
|
|
513
|
+
if (outcomes.length > 0) {
|
|
514
|
+
const avgQuality = outcomes.reduce((sum, o) => sum + o.qualityScore, 0) / outcomes.length
|
|
515
|
+
healthScore += Math.round(avgQuality * 2)
|
|
516
|
+
|
|
517
|
+
const completedAsPlanned = outcomes.filter(o => o.completedAsPlanned).length
|
|
518
|
+
estimateAccuracy = Math.round((completedAsPlanned / outcomes.length) * 100)
|
|
519
|
+
healthScore += Math.round(estimateAccuracy * 0.1)
|
|
520
|
+
|
|
521
|
+
// Count blockers
|
|
522
|
+
const blockerCounts = new Map<string, number>()
|
|
523
|
+
for (const o of outcomes) {
|
|
524
|
+
for (const b of o.blockers) {
|
|
525
|
+
blockerCounts.set(b, (blockerCounts.get(b) || 0) + 1)
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
topBlockers.push(
|
|
529
|
+
...Array.from(blockerCounts.entries())
|
|
530
|
+
.sort((a, b) => b[1] - a[1])
|
|
531
|
+
.slice(0, 5)
|
|
532
|
+
.map(([b]) => b)
|
|
533
|
+
)
|
|
534
|
+
|
|
535
|
+
// Detect patterns
|
|
536
|
+
const underestimated = outcomes.filter(o => !o.completedAsPlanned).length
|
|
537
|
+
if (underestimated / outcomes.length > 0.6) {
|
|
538
|
+
patternsDetected.push('Tasks often take longer than estimated')
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
// Agents-based scoring
|
|
543
|
+
if (data.agents.length > 0) {
|
|
544
|
+
const avgSuccess = data.agents
|
|
545
|
+
.filter(a => a.successRate !== undefined)
|
|
546
|
+
.reduce((sum, a) => sum + (a.successRate || 0), 0)
|
|
547
|
+
if (avgSuccess > 0) {
|
|
548
|
+
healthScore += Math.round(avgSuccess * 0.1 / data.agents.length)
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
// Roadmap progress
|
|
553
|
+
if (data.roadmap && data.roadmap.features.length > 0) {
|
|
554
|
+
const completed = data.roadmap.features.filter(f => f.status === 'completed' || f.status === 'shipped').length
|
|
555
|
+
const progress = Math.round((completed / data.roadmap.features.length) * 100)
|
|
556
|
+
if (progress > 50) healthScore += 5
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
healthScore = Math.max(0, Math.min(100, healthScore))
|
|
560
|
+
|
|
561
|
+
// Recommendations
|
|
562
|
+
const recommendations: string[] = []
|
|
563
|
+
if (!data.state?.currentTask) {
|
|
564
|
+
recommendations.push('Start a task with /p:now')
|
|
565
|
+
}
|
|
566
|
+
if (data.queue && data.queue.tasks.filter(t => !t.completed).length > 10) {
|
|
567
|
+
recommendations.push('Queue is large - prioritize tasks')
|
|
568
|
+
}
|
|
569
|
+
if (estimateAccuracy < 50 && outcomes.length > 5) {
|
|
570
|
+
recommendations.push('Add buffer to estimates')
|
|
571
|
+
}
|
|
572
|
+
if (data.agents.length === 0) {
|
|
573
|
+
recommendations.push('Run /p:sync to generate agents')
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
return {
|
|
577
|
+
healthScore,
|
|
578
|
+
estimateAccuracy,
|
|
579
|
+
topBlockers,
|
|
580
|
+
patternsDetected,
|
|
581
|
+
recommendations: recommendations.slice(0, 4)
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
export async function loadUnifiedJsonData(projectId: string): Promise<UnifiedJsonData> {
|
|
586
|
+
const [state, queue, project, agents, ideas, roadmap, shipped, metrics, analysis, outcomes] = await Promise.all([
|
|
587
|
+
loadState(projectId),
|
|
588
|
+
loadQueue(projectId),
|
|
589
|
+
loadProject(projectId),
|
|
590
|
+
loadAgents(projectId),
|
|
591
|
+
loadIdeas(projectId),
|
|
592
|
+
loadRoadmap(projectId),
|
|
593
|
+
loadShipped(projectId),
|
|
594
|
+
loadMetrics(projectId),
|
|
595
|
+
loadAnalysis(projectId),
|
|
596
|
+
loadOutcomes(projectId)
|
|
597
|
+
])
|
|
598
|
+
|
|
599
|
+
const insights = computeInsights({ state, queue, metrics, outcomes, agents, roadmap })
|
|
600
|
+
|
|
601
|
+
// Check if we have any JSON data
|
|
602
|
+
const hasJsonData = state !== null || project !== null || queue !== null
|
|
603
|
+
|
|
604
|
+
return {
|
|
605
|
+
state,
|
|
606
|
+
queue,
|
|
607
|
+
project,
|
|
608
|
+
agents,
|
|
609
|
+
ideas,
|
|
610
|
+
roadmap,
|
|
611
|
+
shipped,
|
|
612
|
+
metrics,
|
|
613
|
+
analysis,
|
|
614
|
+
outcomes,
|
|
615
|
+
insights,
|
|
616
|
+
hasJsonData
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
export async function hasJsonState(projectId: string): Promise<boolean> {
|
|
621
|
+
const statePath = join(getDataPath(projectId), 'state.json')
|
|
622
|
+
const projectPath = join(getDataPath(projectId), 'project.json')
|
|
623
|
+
|
|
624
|
+
const [hasState, hasProject] = await Promise.all([
|
|
625
|
+
fileExists(statePath),
|
|
626
|
+
fileExists(projectPath)
|
|
627
|
+
])
|
|
628
|
+
|
|
629
|
+
return hasState || hasProject
|
|
630
|
+
}
|