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,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ideas Manager
|
|
3
|
+
*
|
|
4
|
+
* Manages ideas.json - idea backlog.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { ArrayManager } from './base-manager'
|
|
8
|
+
import type { IdeaSchema, IdeasSchema, IdeaPriority } from '../schemas'
|
|
9
|
+
import { DEFAULT_IDEA } from '../schemas'
|
|
10
|
+
|
|
11
|
+
class IdeasManager extends ArrayManager<IdeaSchema> {
|
|
12
|
+
constructor() {
|
|
13
|
+
super('ideas.json')
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async getIdeas(projectId: string): Promise<IdeasSchema> {
|
|
17
|
+
return this.read(projectId)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async getPendingIdeas(projectId: string): Promise<IdeasSchema> {
|
|
21
|
+
const ideas = await this.read(projectId)
|
|
22
|
+
return ideas.filter((idea) => idea.status === 'pending')
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async getIdea(projectId: string, id: string): Promise<IdeaSchema | undefined> {
|
|
26
|
+
return this.find(projectId, (idea) => idea.id === id)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async addIdea(
|
|
30
|
+
projectId: string,
|
|
31
|
+
content: string,
|
|
32
|
+
options?: Partial<Omit<IdeaSchema, 'id' | 'content' | 'createdAt'>>
|
|
33
|
+
): Promise<IdeasSchema> {
|
|
34
|
+
const idea: IdeaSchema = {
|
|
35
|
+
...DEFAULT_IDEA,
|
|
36
|
+
...options,
|
|
37
|
+
id: `idea_${Date.now()}`,
|
|
38
|
+
content,
|
|
39
|
+
createdAt: new Date().toISOString()
|
|
40
|
+
}
|
|
41
|
+
return this.add(projectId, idea)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async updateIdea(
|
|
45
|
+
projectId: string,
|
|
46
|
+
id: string,
|
|
47
|
+
updates: Partial<Omit<IdeaSchema, 'id' | 'createdAt'>>
|
|
48
|
+
): Promise<IdeasSchema> {
|
|
49
|
+
return this.updateItem(
|
|
50
|
+
projectId,
|
|
51
|
+
(idea) => idea.id === id,
|
|
52
|
+
(idea) => ({ ...idea, ...updates })
|
|
53
|
+
)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async archiveIdea(projectId: string, id: string): Promise<IdeasSchema> {
|
|
57
|
+
return this.updateIdea(projectId, id, {
|
|
58
|
+
status: 'archived',
|
|
59
|
+
archivedAt: new Date().toISOString()
|
|
60
|
+
})
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async convertToFeature(projectId: string, id: string): Promise<IdeasSchema> {
|
|
64
|
+
return this.updateIdea(projectId, id, { status: 'converted' })
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async setPriority(
|
|
68
|
+
projectId: string,
|
|
69
|
+
id: string,
|
|
70
|
+
priority: IdeaPriority
|
|
71
|
+
): Promise<IdeasSchema> {
|
|
72
|
+
return this.updateIdea(projectId, id, { priority })
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async removeIdea(projectId: string, id: string): Promise<IdeasSchema> {
|
|
76
|
+
return this.remove(projectId, (idea) => idea.id === id)
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export const ideasManager = new IdeasManager()
|
|
81
|
+
export default ideasManager
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Data Module
|
|
3
|
+
*
|
|
4
|
+
* JSON file managers for all project data types.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// Base
|
|
8
|
+
export { BaseManager, ArrayManager } from './base-manager'
|
|
9
|
+
|
|
10
|
+
// Managers
|
|
11
|
+
export { stateManager, default as stateManagerDefault } from './state-manager'
|
|
12
|
+
export { projectManager, default as projectManagerDefault } from './project-manager'
|
|
13
|
+
export { agentsManager, default as agentsManagerDefault } from './agents-manager'
|
|
14
|
+
export { ideasManager, default as ideasManagerDefault } from './ideas-manager'
|
|
15
|
+
export { roadmapManager, default as roadmapManagerDefault } from './roadmap-manager'
|
|
16
|
+
export { shippedManager, default as shippedManagerDefault } from './shipped-manager'
|
|
17
|
+
export { analysisManager, default as analysisManagerDefault } from './analysis-manager'
|
|
18
|
+
export { outcomesManager, default as outcomesManagerDefault } from './outcomes-manager'
|
|
19
|
+
|
|
20
|
+
// Convenience object with all managers
|
|
21
|
+
export const dataManagers = {
|
|
22
|
+
state: require('./state-manager').stateManager,
|
|
23
|
+
project: require('./project-manager').projectManager,
|
|
24
|
+
agents: require('./agents-manager').agentsManager,
|
|
25
|
+
ideas: require('./ideas-manager').ideasManager,
|
|
26
|
+
roadmap: require('./roadmap-manager').roadmapManager,
|
|
27
|
+
shipped: require('./shipped-manager').shippedManager,
|
|
28
|
+
analysis: require('./analysis-manager').analysisManager,
|
|
29
|
+
outcomes: require('./outcomes-manager').outcomesManager
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export default dataManagers
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Outcomes Manager
|
|
3
|
+
*
|
|
4
|
+
* Manages outcomes.json - task completion metrics and history.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { ArrayManager } from './base-manager'
|
|
8
|
+
import type { OutcomeSchema, OutcomesSchema, QualityScore } from '../schemas'
|
|
9
|
+
|
|
10
|
+
class OutcomesManager extends ArrayManager<OutcomeSchema> {
|
|
11
|
+
constructor() {
|
|
12
|
+
super('outcomes.json')
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
async getOutcomes(projectId: string): Promise<OutcomesSchema> {
|
|
16
|
+
return this.read(projectId)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async getRecentOutcomes(projectId: string, limit = 20): Promise<OutcomesSchema> {
|
|
20
|
+
const outcomes = await this.read(projectId)
|
|
21
|
+
return outcomes
|
|
22
|
+
.sort((a, b) => new Date(b.completedAt).getTime() - new Date(a.completedAt).getTime())
|
|
23
|
+
.slice(0, limit)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async addOutcome(
|
|
27
|
+
projectId: string,
|
|
28
|
+
outcome: Omit<OutcomeSchema, 'id' | 'completedAt'>
|
|
29
|
+
): Promise<OutcomesSchema> {
|
|
30
|
+
const fullOutcome: OutcomeSchema = {
|
|
31
|
+
...outcome,
|
|
32
|
+
id: `outcome_${Date.now()}`,
|
|
33
|
+
completedAt: new Date().toISOString()
|
|
34
|
+
}
|
|
35
|
+
return this.add(projectId, fullOutcome)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async getByAgent(projectId: string, agentName: string): Promise<OutcomesSchema> {
|
|
39
|
+
const outcomes = await this.read(projectId)
|
|
40
|
+
return outcomes.filter((o) => o.agentUsed === agentName)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async getAverageQuality(projectId: string): Promise<number> {
|
|
44
|
+
const outcomes = await this.read(projectId)
|
|
45
|
+
if (outcomes.length === 0) return 0
|
|
46
|
+
const sum = outcomes.reduce((acc, o) => acc + o.qualityScore, 0)
|
|
47
|
+
return Math.round((sum / outcomes.length) * 10) / 10
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async getCompletionRate(projectId: string): Promise<number> {
|
|
51
|
+
const outcomes = await this.read(projectId)
|
|
52
|
+
if (outcomes.length === 0) return 0
|
|
53
|
+
const completed = outcomes.filter((o) => o.completedAsPlanned).length
|
|
54
|
+
return Math.round((completed / outcomes.length) * 100)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async getTopBlockers(projectId: string, limit = 5): Promise<string[]> {
|
|
58
|
+
const outcomes = await this.read(projectId)
|
|
59
|
+
const blockerCounts = new Map<string, number>()
|
|
60
|
+
|
|
61
|
+
for (const outcome of outcomes) {
|
|
62
|
+
for (const blocker of outcome.blockers) {
|
|
63
|
+
blockerCounts.set(blocker, (blockerCounts.get(blocker) || 0) + 1)
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return Array.from(blockerCounts.entries())
|
|
68
|
+
.sort((a, b) => b[1] - a[1])
|
|
69
|
+
.slice(0, limit)
|
|
70
|
+
.map(([blocker]) => blocker)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async getAgentStats(
|
|
74
|
+
projectId: string,
|
|
75
|
+
agentName: string
|
|
76
|
+
): Promise<{ count: number; avgQuality: number; successRate: number }> {
|
|
77
|
+
const agentOutcomes = await this.getByAgent(projectId, agentName)
|
|
78
|
+
if (agentOutcomes.length === 0) {
|
|
79
|
+
return { count: 0, avgQuality: 0, successRate: 0 }
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const avgQuality =
|
|
83
|
+
agentOutcomes.reduce((acc, o) => acc + o.qualityScore, 0) / agentOutcomes.length
|
|
84
|
+
const successRate =
|
|
85
|
+
(agentOutcomes.filter((o) => o.completedAsPlanned).length / agentOutcomes.length) * 100
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
count: agentOutcomes.length,
|
|
89
|
+
avgQuality: Math.round(avgQuality * 10) / 10,
|
|
90
|
+
successRate: Math.round(successRate)
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export const outcomesManager = new OutcomesManager()
|
|
96
|
+
export default outcomesManager
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project Manager
|
|
3
|
+
*
|
|
4
|
+
* Manages project.json - project metadata.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { BaseManager } from './base-manager'
|
|
8
|
+
import type { ProjectSchema } from '../schemas'
|
|
9
|
+
import { DEFAULT_PROJECT } from '../schemas'
|
|
10
|
+
|
|
11
|
+
class ProjectManager extends BaseManager<ProjectSchema> {
|
|
12
|
+
constructor() {
|
|
13
|
+
super('project.json')
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
protected getDefault(projectId: string): ProjectSchema {
|
|
17
|
+
return {
|
|
18
|
+
...DEFAULT_PROJECT,
|
|
19
|
+
projectId,
|
|
20
|
+
name: '',
|
|
21
|
+
repoPath: '',
|
|
22
|
+
createdAt: new Date().toISOString(),
|
|
23
|
+
lastSync: new Date().toISOString()
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async getProject(projectId: string): Promise<ProjectSchema> {
|
|
28
|
+
return this.read(projectId)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async updateProject(
|
|
32
|
+
projectId: string,
|
|
33
|
+
updates: Partial<Omit<ProjectSchema, 'projectId'>>
|
|
34
|
+
): Promise<ProjectSchema> {
|
|
35
|
+
return this.update(projectId, (project) => ({
|
|
36
|
+
...project,
|
|
37
|
+
...updates,
|
|
38
|
+
lastSync: new Date().toISOString()
|
|
39
|
+
}))
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async setTechStack(projectId: string, techStack: string[]): Promise<ProjectSchema> {
|
|
43
|
+
return this.updateProject(projectId, { techStack })
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async setFileCount(projectId: string, fileCount: number): Promise<ProjectSchema> {
|
|
47
|
+
return this.updateProject(projectId, { fileCount })
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async setCommitCount(projectId: string, commitCount: number): Promise<ProjectSchema> {
|
|
51
|
+
return this.updateProject(projectId, { commitCount })
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async initializeProject(
|
|
55
|
+
projectId: string,
|
|
56
|
+
name: string,
|
|
57
|
+
repoPath: string,
|
|
58
|
+
options?: Partial<ProjectSchema>
|
|
59
|
+
): Promise<ProjectSchema> {
|
|
60
|
+
const project: ProjectSchema = {
|
|
61
|
+
...DEFAULT_PROJECT,
|
|
62
|
+
...options,
|
|
63
|
+
projectId,
|
|
64
|
+
name,
|
|
65
|
+
repoPath,
|
|
66
|
+
createdAt: new Date().toISOString(),
|
|
67
|
+
lastSync: new Date().toISOString()
|
|
68
|
+
}
|
|
69
|
+
await this.write(projectId, project)
|
|
70
|
+
return project
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export const projectManager = new ProjectManager()
|
|
75
|
+
export default projectManager
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Roadmap Manager
|
|
3
|
+
*
|
|
4
|
+
* Manages roadmap.json - feature roadmap.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { ArrayManager } from './base-manager'
|
|
8
|
+
import type {
|
|
9
|
+
FeatureSchema,
|
|
10
|
+
RoadmapSchema,
|
|
11
|
+
FeatureStatus,
|
|
12
|
+
FeatureTask
|
|
13
|
+
} from '../schemas'
|
|
14
|
+
import { DEFAULT_FEATURE } from '../schemas'
|
|
15
|
+
|
|
16
|
+
class RoadmapManager extends ArrayManager<FeatureSchema> {
|
|
17
|
+
constructor() {
|
|
18
|
+
super('roadmap.json')
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async getFeatures(projectId: string): Promise<RoadmapSchema> {
|
|
22
|
+
return this.read(projectId)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async getActiveFeatures(projectId: string): Promise<RoadmapSchema> {
|
|
26
|
+
const features = await this.read(projectId)
|
|
27
|
+
return features.filter((f) => f.status === 'in_progress')
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async getFeature(projectId: string, id: string): Promise<FeatureSchema | undefined> {
|
|
31
|
+
return this.find(projectId, (feature) => feature.id === id)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async addFeature(
|
|
35
|
+
projectId: string,
|
|
36
|
+
name: string,
|
|
37
|
+
options?: Partial<Omit<FeatureSchema, 'id' | 'name' | 'createdAt'>>
|
|
38
|
+
): Promise<RoadmapSchema> {
|
|
39
|
+
const feature: FeatureSchema = {
|
|
40
|
+
...DEFAULT_FEATURE,
|
|
41
|
+
...options,
|
|
42
|
+
id: `feature_${Date.now()}`,
|
|
43
|
+
name,
|
|
44
|
+
createdAt: new Date().toISOString()
|
|
45
|
+
}
|
|
46
|
+
return this.add(projectId, feature)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async updateFeature(
|
|
50
|
+
projectId: string,
|
|
51
|
+
id: string,
|
|
52
|
+
updates: Partial<Omit<FeatureSchema, 'id' | 'createdAt'>>
|
|
53
|
+
): Promise<RoadmapSchema> {
|
|
54
|
+
return this.updateItem(
|
|
55
|
+
projectId,
|
|
56
|
+
(feature) => feature.id === id,
|
|
57
|
+
(feature) => ({ ...feature, ...updates })
|
|
58
|
+
)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
async setStatus(
|
|
62
|
+
projectId: string,
|
|
63
|
+
id: string,
|
|
64
|
+
status: FeatureStatus
|
|
65
|
+
): Promise<RoadmapSchema> {
|
|
66
|
+
const updates: Partial<FeatureSchema> = { status }
|
|
67
|
+
if (status === 'completed' || status === 'shipped') {
|
|
68
|
+
updates.completedAt = new Date().toISOString()
|
|
69
|
+
}
|
|
70
|
+
return this.updateFeature(projectId, id, updates)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async addTask(
|
|
74
|
+
projectId: string,
|
|
75
|
+
featureId: string,
|
|
76
|
+
task: FeatureTask
|
|
77
|
+
): Promise<RoadmapSchema> {
|
|
78
|
+
return this.updateItem(
|
|
79
|
+
projectId,
|
|
80
|
+
(feature) => feature.id === featureId,
|
|
81
|
+
(feature) => ({
|
|
82
|
+
...feature,
|
|
83
|
+
tasks: [...feature.tasks, task]
|
|
84
|
+
})
|
|
85
|
+
)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async completeTask(
|
|
89
|
+
projectId: string,
|
|
90
|
+
featureId: string,
|
|
91
|
+
taskIndex: number
|
|
92
|
+
): Promise<RoadmapSchema> {
|
|
93
|
+
return this.updateItem(
|
|
94
|
+
projectId,
|
|
95
|
+
(feature) => feature.id === featureId,
|
|
96
|
+
(feature) => ({
|
|
97
|
+
...feature,
|
|
98
|
+
tasks: feature.tasks.map((task, i) =>
|
|
99
|
+
i === taskIndex ? { ...task, completed: true } : task
|
|
100
|
+
)
|
|
101
|
+
})
|
|
102
|
+
)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
async removeFeature(projectId: string, id: string): Promise<RoadmapSchema> {
|
|
106
|
+
return this.remove(projectId, (feature) => feature.id === id)
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
async getProgress(projectId: string, featureId: string): Promise<number> {
|
|
110
|
+
const feature = await this.getFeature(projectId, featureId)
|
|
111
|
+
if (!feature || feature.tasks.length === 0) return 0
|
|
112
|
+
const completed = feature.tasks.filter((t) => t.completed).length
|
|
113
|
+
return Math.round((completed / feature.tasks.length) * 100)
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export const roadmapManager = new RoadmapManager()
|
|
118
|
+
export default roadmapManager
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shipped Manager
|
|
3
|
+
*
|
|
4
|
+
* Manages shipped.json - completed/shipped items history.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { ArrayManager } from './base-manager'
|
|
8
|
+
import type { ShippedItemSchema, ShippedSchema } from '../schemas'
|
|
9
|
+
|
|
10
|
+
class ShippedManager extends ArrayManager<ShippedItemSchema> {
|
|
11
|
+
constructor() {
|
|
12
|
+
super('shipped.json')
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
async getShipped(projectId: string): Promise<ShippedSchema> {
|
|
16
|
+
return this.read(projectId)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async getRecentShipped(projectId: string, limit = 10): Promise<ShippedSchema> {
|
|
20
|
+
const shipped = await this.read(projectId)
|
|
21
|
+
return shipped
|
|
22
|
+
.sort((a, b) => new Date(b.shippedAt).getTime() - new Date(a.shippedAt).getTime())
|
|
23
|
+
.slice(0, limit)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async addShipped(
|
|
27
|
+
projectId: string,
|
|
28
|
+
item: Omit<ShippedItemSchema, 'id' | 'shippedAt'>
|
|
29
|
+
): Promise<ShippedSchema> {
|
|
30
|
+
const shippedItem: ShippedItemSchema = {
|
|
31
|
+
...item,
|
|
32
|
+
id: `shipped_${Date.now()}`,
|
|
33
|
+
shippedAt: new Date().toISOString()
|
|
34
|
+
}
|
|
35
|
+
return this.add(projectId, shippedItem)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async getByFeature(projectId: string, featureId: string): Promise<ShippedSchema> {
|
|
39
|
+
const shipped = await this.read(projectId)
|
|
40
|
+
return shipped.filter((item) => item.featureId === featureId)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async getTotalDuration(projectId: string): Promise<string> {
|
|
44
|
+
const shipped = await this.read(projectId)
|
|
45
|
+
// Parse durations and sum (simplified - assumes format like "2h 30m")
|
|
46
|
+
let totalMinutes = 0
|
|
47
|
+
for (const item of shipped) {
|
|
48
|
+
const hours = item.duration.match(/(\d+)h/)
|
|
49
|
+
const minutes = item.duration.match(/(\d+)m/)
|
|
50
|
+
if (hours) totalMinutes += parseInt(hours[1]) * 60
|
|
51
|
+
if (minutes) totalMinutes += parseInt(minutes[1])
|
|
52
|
+
}
|
|
53
|
+
const h = Math.floor(totalMinutes / 60)
|
|
54
|
+
const m = totalMinutes % 60
|
|
55
|
+
return h > 0 ? `${h}h ${m}m` : `${m}m`
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async getCount(projectId: string): Promise<number> {
|
|
59
|
+
const shipped = await this.read(projectId)
|
|
60
|
+
return shipped.length
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export const shippedManager = new ShippedManager()
|
|
65
|
+
export default shippedManager
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* State Manager
|
|
3
|
+
*
|
|
4
|
+
* Manages state.json - the unified project state.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { BaseManager } from './base-manager'
|
|
8
|
+
import type {
|
|
9
|
+
StateSchema,
|
|
10
|
+
CurrentTask,
|
|
11
|
+
QueuedTask,
|
|
12
|
+
RecentActivity,
|
|
13
|
+
Stats
|
|
14
|
+
} from '../schemas'
|
|
15
|
+
import { DEFAULT_STATE, DEFAULT_STATS } from '../schemas'
|
|
16
|
+
|
|
17
|
+
const MAX_RECENT_ACTIVITY = 10
|
|
18
|
+
|
|
19
|
+
class StateManager extends BaseManager<StateSchema> {
|
|
20
|
+
constructor() {
|
|
21
|
+
super('state.json')
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
protected getDefault(projectId: string): StateSchema {
|
|
25
|
+
return {
|
|
26
|
+
...DEFAULT_STATE,
|
|
27
|
+
projectId,
|
|
28
|
+
lastSync: new Date().toISOString()
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// =========== Current Task ===========
|
|
33
|
+
|
|
34
|
+
async getCurrentTask(projectId: string): Promise<CurrentTask | null> {
|
|
35
|
+
const state = await this.read(projectId)
|
|
36
|
+
return state.currentTask
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async setCurrentTask(projectId: string, task: CurrentTask | null): Promise<StateSchema> {
|
|
40
|
+
return this.update(projectId, (state) => ({
|
|
41
|
+
...state,
|
|
42
|
+
currentTask: task,
|
|
43
|
+
lastSync: new Date().toISOString()
|
|
44
|
+
}))
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async startTask(
|
|
48
|
+
projectId: string,
|
|
49
|
+
task: Omit<CurrentTask, 'startedAt'>
|
|
50
|
+
): Promise<StateSchema> {
|
|
51
|
+
const currentTask: CurrentTask = {
|
|
52
|
+
...task,
|
|
53
|
+
startedAt: new Date().toISOString()
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return this.update(projectId, (state) => ({
|
|
57
|
+
...state,
|
|
58
|
+
currentTask,
|
|
59
|
+
recentActivity: [
|
|
60
|
+
{
|
|
61
|
+
type: 'session_started' as const,
|
|
62
|
+
description: task.description,
|
|
63
|
+
timestamp: new Date().toISOString()
|
|
64
|
+
},
|
|
65
|
+
...state.recentActivity
|
|
66
|
+
].slice(0, MAX_RECENT_ACTIVITY),
|
|
67
|
+
lastSync: new Date().toISOString()
|
|
68
|
+
}))
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async completeTask(projectId: string, duration: string): Promise<StateSchema> {
|
|
72
|
+
const state = await this.read(projectId)
|
|
73
|
+
if (!state.currentTask) {
|
|
74
|
+
throw new Error('No active task to complete')
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const activity: RecentActivity = {
|
|
78
|
+
type: 'task_completed',
|
|
79
|
+
description: state.currentTask.description,
|
|
80
|
+
timestamp: new Date().toISOString(),
|
|
81
|
+
duration
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return this.update(projectId, (s) => ({
|
|
85
|
+
...s,
|
|
86
|
+
currentTask: null,
|
|
87
|
+
recentActivity: [activity, ...s.recentActivity].slice(0, MAX_RECENT_ACTIVITY),
|
|
88
|
+
stats: {
|
|
89
|
+
...s.stats,
|
|
90
|
+
tasksToday: s.stats.tasksToday + 1
|
|
91
|
+
},
|
|
92
|
+
lastSync: new Date().toISOString()
|
|
93
|
+
}))
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
async pauseTask(projectId: string, reason?: string): Promise<StateSchema> {
|
|
97
|
+
const state = await this.read(projectId)
|
|
98
|
+
if (!state.currentTask) {
|
|
99
|
+
throw new Error('No active task to pause')
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return this.update(projectId, (s) => ({
|
|
103
|
+
...s,
|
|
104
|
+
currentTask: s.currentTask
|
|
105
|
+
? {
|
|
106
|
+
...s.currentTask,
|
|
107
|
+
pausedAt: new Date().toISOString(),
|
|
108
|
+
pauseReason: reason
|
|
109
|
+
}
|
|
110
|
+
: null,
|
|
111
|
+
lastSync: new Date().toISOString()
|
|
112
|
+
}))
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async resumeTask(projectId: string): Promise<StateSchema> {
|
|
116
|
+
const state = await this.read(projectId)
|
|
117
|
+
if (!state.currentTask?.pausedAt) {
|
|
118
|
+
throw new Error('No paused task to resume')
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return this.update(projectId, (s) => ({
|
|
122
|
+
...s,
|
|
123
|
+
currentTask: s.currentTask
|
|
124
|
+
? {
|
|
125
|
+
...s.currentTask,
|
|
126
|
+
pausedAt: undefined,
|
|
127
|
+
pauseReason: undefined
|
|
128
|
+
}
|
|
129
|
+
: null,
|
|
130
|
+
lastSync: new Date().toISOString()
|
|
131
|
+
}))
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// =========== Queue ===========
|
|
135
|
+
|
|
136
|
+
async getQueue(projectId: string): Promise<QueuedTask[]> {
|
|
137
|
+
const state = await this.read(projectId)
|
|
138
|
+
return state.queue
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
async addToQueue(
|
|
142
|
+
projectId: string,
|
|
143
|
+
task: Omit<QueuedTask, 'id' | 'createdAt'>
|
|
144
|
+
): Promise<StateSchema> {
|
|
145
|
+
const queuedTask: QueuedTask = {
|
|
146
|
+
...task,
|
|
147
|
+
id: `task_${Date.now()}`,
|
|
148
|
+
createdAt: new Date().toISOString()
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return this.update(projectId, (state) => ({
|
|
152
|
+
...state,
|
|
153
|
+
queue: [...state.queue, queuedTask].sort((a, b) => {
|
|
154
|
+
const priorityOrder = { critical: 0, high: 1, medium: 2, low: 3 }
|
|
155
|
+
return priorityOrder[a.priority] - priorityOrder[b.priority]
|
|
156
|
+
}),
|
|
157
|
+
lastSync: new Date().toISOString()
|
|
158
|
+
}))
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
async removeFromQueue(projectId: string, taskId: string): Promise<StateSchema> {
|
|
162
|
+
return this.update(projectId, (state) => ({
|
|
163
|
+
...state,
|
|
164
|
+
queue: state.queue.filter((t) => t.id !== taskId),
|
|
165
|
+
lastSync: new Date().toISOString()
|
|
166
|
+
}))
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
async getNextTask(projectId: string): Promise<QueuedTask | null> {
|
|
170
|
+
const state = await this.read(projectId)
|
|
171
|
+
return state.queue.find((t) => !t.blockedReason) || null
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// =========== Stats ===========
|
|
175
|
+
|
|
176
|
+
async getStats(projectId: string): Promise<Stats> {
|
|
177
|
+
const state = await this.read(projectId)
|
|
178
|
+
return state.stats
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
async updateStats(projectId: string, stats: Partial<Stats>): Promise<StateSchema> {
|
|
182
|
+
return this.update(projectId, (state) => ({
|
|
183
|
+
...state,
|
|
184
|
+
stats: { ...state.stats, ...stats },
|
|
185
|
+
lastSync: new Date().toISOString()
|
|
186
|
+
}))
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
async resetDailyStats(projectId: string): Promise<StateSchema> {
|
|
190
|
+
return this.update(projectId, (state) => ({
|
|
191
|
+
...state,
|
|
192
|
+
stats: { ...state.stats, tasksToday: 0 },
|
|
193
|
+
lastSync: new Date().toISOString()
|
|
194
|
+
}))
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// =========== Activity ===========
|
|
198
|
+
|
|
199
|
+
async addActivity(projectId: string, activity: RecentActivity): Promise<StateSchema> {
|
|
200
|
+
return this.update(projectId, (state) => ({
|
|
201
|
+
...state,
|
|
202
|
+
recentActivity: [activity, ...state.recentActivity].slice(0, MAX_RECENT_ACTIVITY),
|
|
203
|
+
lastSync: new Date().toISOString()
|
|
204
|
+
}))
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
async getRecentActivity(projectId: string): Promise<RecentActivity[]> {
|
|
208
|
+
const state = await this.read(projectId)
|
|
209
|
+
return state.recentActivity
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export const stateManager = new StateManager()
|
|
214
|
+
export default stateManager
|