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
|
@@ -1,799 +0,0 @@
|
|
|
1
|
-
const fs = require('fs').promises
|
|
2
|
-
const path = require('path')
|
|
3
|
-
const pathManager = require('./path-manager')
|
|
4
|
-
const configManager = require('./config-manager')
|
|
5
|
-
const authorDetector = require('./author-detector')
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Migrator - Handles migrations between versions
|
|
9
|
-
*
|
|
10
|
-
* Migration process:
|
|
11
|
-
* 1. Detect legacy .prjct directory (v0.1.0 → v0.2.x)
|
|
12
|
-
* 2. Detect author information
|
|
13
|
-
* 3. Create prjct.config.json
|
|
14
|
-
* 4. Create global directory structure
|
|
15
|
-
* 5. Copy all files to global location
|
|
16
|
-
* 6. Move authors/version/created/lastSync to global config (v0.2.x → v0.3.0)
|
|
17
|
-
* 7. Validate migration
|
|
18
|
-
* 8. Optionally remove local .prjct
|
|
19
|
-
*
|
|
20
|
-
* @version 0.3.0
|
|
21
|
-
*/
|
|
22
|
-
class Migrator {
|
|
23
|
-
/**
|
|
24
|
-
* Check if a project needs migration
|
|
25
|
-
*
|
|
26
|
-
* @param {string} projectPath - Path to the project
|
|
27
|
-
* @returns {Promise<boolean>} - True if migration needed
|
|
28
|
-
*/
|
|
29
|
-
async needsMigration(projectPath) {
|
|
30
|
-
const structureMigration = await configManager.needsMigration(projectPath)
|
|
31
|
-
if (structureMigration) return true
|
|
32
|
-
|
|
33
|
-
const config = await configManager.readConfig(projectPath)
|
|
34
|
-
if (config && config.version && config.version.startsWith('0.2.')) {
|
|
35
|
-
return true
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
return false
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Migrate config from 0.2.x to 0.3.0 (move authors to global config)
|
|
43
|
-
*
|
|
44
|
-
* @param {string} projectPath - Path to the project
|
|
45
|
-
* @returns {Promise<Object>} - Migration result
|
|
46
|
-
*/
|
|
47
|
-
async migrateConfigTo030(projectPath) {
|
|
48
|
-
const result = {
|
|
49
|
-
success: false,
|
|
50
|
-
message: '',
|
|
51
|
-
oldVersion: null,
|
|
52
|
-
newVersion: '0.3.0',
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
try {
|
|
56
|
-
const localConfig = await configManager.readConfig(projectPath)
|
|
57
|
-
if (!localConfig) {
|
|
58
|
-
result.message = 'No config found'
|
|
59
|
-
return result
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
result.oldVersion = localConfig.version
|
|
63
|
-
const projectId = localConfig.projectId
|
|
64
|
-
|
|
65
|
-
const globalConfig = await configManager.readGlobalConfig(projectId)
|
|
66
|
-
if (globalConfig && globalConfig.authors && globalConfig.authors.length > 0) {
|
|
67
|
-
const needsCleanup =
|
|
68
|
-
localConfig.authors ||
|
|
69
|
-
localConfig.author ||
|
|
70
|
-
localConfig.version ||
|
|
71
|
-
localConfig.created ||
|
|
72
|
-
localConfig.lastSync
|
|
73
|
-
|
|
74
|
-
if (needsCleanup) {
|
|
75
|
-
delete localConfig.authors
|
|
76
|
-
delete localConfig.author
|
|
77
|
-
delete localConfig.version
|
|
78
|
-
delete localConfig.created
|
|
79
|
-
delete localConfig.lastSync
|
|
80
|
-
await configManager.writeConfig(projectPath, localConfig)
|
|
81
|
-
}
|
|
82
|
-
result.success = true
|
|
83
|
-
result.message = 'Authors already in global config, cleaned up local config'
|
|
84
|
-
return result
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
let authors = []
|
|
88
|
-
const now = new Date().toISOString()
|
|
89
|
-
|
|
90
|
-
if (localConfig.authors && Array.isArray(localConfig.authors)) {
|
|
91
|
-
authors = localConfig.authors
|
|
92
|
-
} else if (localConfig.author) {
|
|
93
|
-
authors = [
|
|
94
|
-
{
|
|
95
|
-
name: localConfig.author.name || 'Unknown',
|
|
96
|
-
email: localConfig.author.email || '',
|
|
97
|
-
github: localConfig.author.github || '',
|
|
98
|
-
firstContribution: localConfig.created || now,
|
|
99
|
-
lastActivity: localConfig.lastSync || now,
|
|
100
|
-
},
|
|
101
|
-
]
|
|
102
|
-
} else {
|
|
103
|
-
authors = [
|
|
104
|
-
{
|
|
105
|
-
name: 'Unknown',
|
|
106
|
-
email: '',
|
|
107
|
-
github: '',
|
|
108
|
-
firstContribution: now,
|
|
109
|
-
lastActivity: now,
|
|
110
|
-
},
|
|
111
|
-
]
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
const newGlobalConfig = {
|
|
115
|
-
projectId,
|
|
116
|
-
authors,
|
|
117
|
-
version: '0.3.0',
|
|
118
|
-
created: localConfig.created || now,
|
|
119
|
-
lastSync: now,
|
|
120
|
-
}
|
|
121
|
-
await configManager.writeGlobalConfig(projectId, newGlobalConfig)
|
|
122
|
-
|
|
123
|
-
delete localConfig.authors
|
|
124
|
-
delete localConfig.author
|
|
125
|
-
delete localConfig.version
|
|
126
|
-
delete localConfig.created
|
|
127
|
-
delete localConfig.lastSync
|
|
128
|
-
await configManager.writeConfig(projectPath, localConfig)
|
|
129
|
-
|
|
130
|
-
result.success = true
|
|
131
|
-
result.message = `Migrated ${authors.length} author(s) to global config`
|
|
132
|
-
return result
|
|
133
|
-
} catch (error) {
|
|
134
|
-
result.message = `Migration failed: ${error.message}`
|
|
135
|
-
return result
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Copy a directory recursively
|
|
141
|
-
*
|
|
142
|
-
* @param {string} source - Source directory
|
|
143
|
-
* @param {string} destination - Destination directory
|
|
144
|
-
* @returns {Promise<number>} - Number of files copied
|
|
145
|
-
* @private
|
|
146
|
-
*/
|
|
147
|
-
async copyDirectory(source, destination) {
|
|
148
|
-
let fileCount = 0
|
|
149
|
-
|
|
150
|
-
await fs.mkdir(destination, { recursive: true })
|
|
151
|
-
|
|
152
|
-
const entries = await fs.readdir(source, { withFileTypes: true })
|
|
153
|
-
|
|
154
|
-
for (const entry of entries) {
|
|
155
|
-
const sourcePath = path.join(source, entry.name)
|
|
156
|
-
const destPath = path.join(destination, entry.name)
|
|
157
|
-
|
|
158
|
-
if (entry.isDirectory()) {
|
|
159
|
-
fileCount += await this.copyDirectory(sourcePath, destPath)
|
|
160
|
-
} else {
|
|
161
|
-
await fs.copyFile(sourcePath, destPath)
|
|
162
|
-
fileCount++
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
return fileCount
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* Map legacy flat structure to new layered structure
|
|
171
|
-
*
|
|
172
|
-
* @param {string} filename - Name of the file
|
|
173
|
-
* @returns {Object} - {layer, filename}
|
|
174
|
-
* @private
|
|
175
|
-
*/
|
|
176
|
-
mapLegacyFile(filename) {
|
|
177
|
-
if (filename === 'now.md' || filename === 'next.md' || filename === 'context.md') {
|
|
178
|
-
return { layer: 'core', filename }
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
if (filename === 'shipped.md' || filename === 'metrics.md') {
|
|
182
|
-
return { layer: 'progress', filename }
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
if (filename === 'ideas.md' || filename === 'roadmap.md') {
|
|
186
|
-
return { layer: 'planning', filename }
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
if (
|
|
190
|
-
filename === 'memory.jsonl' ||
|
|
191
|
-
filename === 'context.jsonl' ||
|
|
192
|
-
filename === 'decisions.jsonl'
|
|
193
|
-
) {
|
|
194
|
-
return { layer: 'memory', filename }
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
if (filename === 'repo-summary.md') {
|
|
198
|
-
return { layer: 'analysis', filename }
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
return { layer: '.', filename }
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
/**
|
|
205
|
-
* Migrate files from legacy structure to new layered structure
|
|
206
|
-
*
|
|
207
|
-
* @param {string} legacyPath - Path to legacy .prjct directory
|
|
208
|
-
* @param {string} globalPath - Path to new global project directory
|
|
209
|
-
* @returns {Promise<{fileCount: number, layerCounts: Object}>}
|
|
210
|
-
* @private
|
|
211
|
-
*/
|
|
212
|
-
async migrateFiles(legacyPath, globalPath) {
|
|
213
|
-
let fileCount = 0
|
|
214
|
-
const layerCounts = {
|
|
215
|
-
core: 0,
|
|
216
|
-
progress: 0,
|
|
217
|
-
planning: 0,
|
|
218
|
-
analysis: 0,
|
|
219
|
-
memory: 0,
|
|
220
|
-
other: 0,
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
const validLayers = ['core', 'progress', 'planning', 'analysis', 'memory', 'sessions']
|
|
224
|
-
const entries = await fs.readdir(legacyPath, { withFileTypes: true })
|
|
225
|
-
|
|
226
|
-
for (const entry of entries) {
|
|
227
|
-
const sourcePath = path.join(legacyPath, entry.name)
|
|
228
|
-
|
|
229
|
-
if (entry.name === 'prjct.config.json' || entry.name.endsWith('.old')) {
|
|
230
|
-
continue
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
if (entry.isDirectory()) {
|
|
234
|
-
if (validLayers.includes(entry.name)) {
|
|
235
|
-
const destPath = path.join(globalPath, entry.name)
|
|
236
|
-
const count = await this.copyDirectory(sourcePath, destPath)
|
|
237
|
-
fileCount += count
|
|
238
|
-
if (Object.prototype.hasOwnProperty.call(layerCounts, entry.name)) {
|
|
239
|
-
layerCounts[entry.name] += count
|
|
240
|
-
} else {
|
|
241
|
-
layerCounts.other += count
|
|
242
|
-
}
|
|
243
|
-
} else {
|
|
244
|
-
const destPath = path.join(globalPath, 'planning', entry.name)
|
|
245
|
-
const count = await this.copyDirectory(sourcePath, destPath)
|
|
246
|
-
fileCount += count
|
|
247
|
-
layerCounts.planning += count
|
|
248
|
-
}
|
|
249
|
-
} else {
|
|
250
|
-
const mapping = this.mapLegacyFile(entry.name)
|
|
251
|
-
const destPath = path.join(globalPath, mapping.layer, mapping.filename)
|
|
252
|
-
|
|
253
|
-
await fs.mkdir(path.dirname(destPath), { recursive: true })
|
|
254
|
-
|
|
255
|
-
await fs.copyFile(sourcePath, destPath)
|
|
256
|
-
fileCount++
|
|
257
|
-
|
|
258
|
-
if (mapping.layer === '.') {
|
|
259
|
-
layerCounts.other++
|
|
260
|
-
} else {
|
|
261
|
-
layerCounts[mapping.layer] = (layerCounts[mapping.layer] || 0) + 1
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
return { fileCount, layerCounts }
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
/**
|
|
270
|
-
* Validate that migration was successful
|
|
271
|
-
*
|
|
272
|
-
* @param {string} projectId - Project ID
|
|
273
|
-
* @returns {Promise<{valid: boolean, issues: string[]}>}
|
|
274
|
-
* @private
|
|
275
|
-
*/
|
|
276
|
-
async validateMigration(projectId) {
|
|
277
|
-
const issues = []
|
|
278
|
-
|
|
279
|
-
const exists = await pathManager.projectExists(projectId)
|
|
280
|
-
if (!exists) {
|
|
281
|
-
issues.push('Global project directory not found')
|
|
282
|
-
return { valid: false, issues }
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
const globalPath = pathManager.getGlobalProjectPath(projectId)
|
|
286
|
-
const requiredLayers = ['core', 'progress', 'planning', 'analysis', 'memory']
|
|
287
|
-
|
|
288
|
-
for (const layer of requiredLayers) {
|
|
289
|
-
try {
|
|
290
|
-
await fs.access(path.join(globalPath, layer))
|
|
291
|
-
} catch {
|
|
292
|
-
issues.push(`Missing layer directory: ${layer}`)
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
try {
|
|
297
|
-
const coreFiles = await fs.readdir(path.join(globalPath, 'core'))
|
|
298
|
-
if (coreFiles.length === 0) {
|
|
299
|
-
issues.push('No files found in core directory')
|
|
300
|
-
}
|
|
301
|
-
} catch {
|
|
302
|
-
issues.push('Cannot read core directory')
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
return {
|
|
306
|
-
valid: issues.length === 0,
|
|
307
|
-
issues,
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
/**
|
|
312
|
-
* Cleanup legacy directories while preserving config
|
|
313
|
-
* Removes: analysis/, core/, memory/, planning/, progress/, sessions/
|
|
314
|
-
* Keeps: prjct.config.json
|
|
315
|
-
*
|
|
316
|
-
* @param {string} projectPath - Path to the project
|
|
317
|
-
* @returns {Promise<void>}
|
|
318
|
-
* @private
|
|
319
|
-
*/
|
|
320
|
-
async cleanupLegacyDirectories(projectPath) {
|
|
321
|
-
const legacyPath = pathManager.getLegacyPrjctPath(projectPath)
|
|
322
|
-
const layersToRemove = ['analysis', 'core', 'memory', 'planning', 'progress', 'sessions']
|
|
323
|
-
|
|
324
|
-
for (const layer of layersToRemove) {
|
|
325
|
-
const layerPath = path.join(legacyPath, layer)
|
|
326
|
-
try {
|
|
327
|
-
await fs.rm(layerPath, { recursive: true, force: true })
|
|
328
|
-
} catch {}
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
/**
|
|
333
|
-
* Perform the complete migration process
|
|
334
|
-
*
|
|
335
|
-
* @param {string} projectPath - Path to the project
|
|
336
|
-
* @param {Object} options - Migration options
|
|
337
|
-
* @param {boolean} options.removeLegacy - Remove legacy .prjct after migration completely
|
|
338
|
-
* @param {boolean} options.cleanupLegacy - Remove legacy directories but keep config
|
|
339
|
-
* @param {boolean} options.dryRun - Simulate migration without making changes
|
|
340
|
-
* @returns {Promise<Object>} - Migration result
|
|
341
|
-
*/
|
|
342
|
-
async migrate(projectPath, options = {}) {
|
|
343
|
-
const result = {
|
|
344
|
-
success: false,
|
|
345
|
-
projectId: null,
|
|
346
|
-
filescopied: 0,
|
|
347
|
-
layerCounts: {},
|
|
348
|
-
config: null,
|
|
349
|
-
author: null,
|
|
350
|
-
issues: [],
|
|
351
|
-
dryRun: options.dryRun || false,
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
try {
|
|
355
|
-
const config = await configManager.readConfig(projectPath)
|
|
356
|
-
if (config && config.version && config.version.startsWith('0.2.')) {
|
|
357
|
-
const versionMigration = await this.migrateConfigTo030(projectPath)
|
|
358
|
-
result.success = versionMigration.success
|
|
359
|
-
result.projectId = config.projectId
|
|
360
|
-
result.filesCopied = 0
|
|
361
|
-
result.issues = versionMigration.success ? [] : [versionMigration.message]
|
|
362
|
-
return result
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
const needsStructuralMigration = await configManager.needsMigration(projectPath)
|
|
366
|
-
if (!needsStructuralMigration) {
|
|
367
|
-
result.success = false
|
|
368
|
-
result.issues.push('No migration needed - either no legacy structure or already migrated')
|
|
369
|
-
return result
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
result.author = await authorDetector.detect()
|
|
373
|
-
|
|
374
|
-
const projectId = pathManager.generateProjectId(projectPath)
|
|
375
|
-
result.projectId = projectId
|
|
376
|
-
|
|
377
|
-
if (options.dryRun) {
|
|
378
|
-
result.success = true
|
|
379
|
-
result.issues.push('DRY RUN - No changes were made')
|
|
380
|
-
return result
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
await pathManager.ensureProjectStructure(projectId)
|
|
384
|
-
|
|
385
|
-
result.config = await configManager.createConfig(projectPath, result.author)
|
|
386
|
-
|
|
387
|
-
const legacyPath = pathManager.getLegacyPrjctPath(projectPath)
|
|
388
|
-
const globalPath = pathManager.getGlobalProjectPath(projectId)
|
|
389
|
-
|
|
390
|
-
const migrationStats = await this.migrateFiles(legacyPath, globalPath)
|
|
391
|
-
result.filesCopied = migrationStats.fileCount
|
|
392
|
-
result.layerCounts = migrationStats.layerCounts
|
|
393
|
-
|
|
394
|
-
const validation = await this.validateMigration(projectId)
|
|
395
|
-
result.issues = validation.issues
|
|
396
|
-
|
|
397
|
-
if (!validation.valid) {
|
|
398
|
-
result.success = false
|
|
399
|
-
return result
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
if (options.removeLegacy) {
|
|
403
|
-
await fs.rm(legacyPath, { recursive: true, force: true })
|
|
404
|
-
result.legacyRemoved = true
|
|
405
|
-
} else if (options.cleanupLegacy) {
|
|
406
|
-
await this.cleanupLegacyDirectories(projectPath)
|
|
407
|
-
result.legacyCleaned = true
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
result.success = true
|
|
411
|
-
return result
|
|
412
|
-
} catch (error) {
|
|
413
|
-
result.success = false
|
|
414
|
-
result.issues.push(`Migration error: ${error.message}`)
|
|
415
|
-
return result
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
/**
|
|
420
|
-
* Generate a migration report
|
|
421
|
-
*
|
|
422
|
-
* @param {Object} result - Migration result
|
|
423
|
-
* @returns {string} - Formatted report
|
|
424
|
-
*/
|
|
425
|
-
generateReport(result) {
|
|
426
|
-
const lines = []
|
|
427
|
-
|
|
428
|
-
lines.push('📦 Migration Report')
|
|
429
|
-
lines.push('━━━━━━━━━━━━━━━━━━━━━━━━━━━━')
|
|
430
|
-
|
|
431
|
-
if (result.dryRun) {
|
|
432
|
-
lines.push('⚠️ DRY RUN MODE - No changes were made')
|
|
433
|
-
lines.push('')
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
if (result.success) {
|
|
437
|
-
lines.push('✅ Migration successful!')
|
|
438
|
-
lines.push('')
|
|
439
|
-
lines.push(`📋 Project ID: ${result.projectId}`)
|
|
440
|
-
lines.push(`👤 Author: ${authorDetector.formatAuthor(result.author)}`)
|
|
441
|
-
lines.push(`📁 Files migrated: ${result.filesCopied}`)
|
|
442
|
-
lines.push('')
|
|
443
|
-
lines.push('📂 Files by layer:')
|
|
444
|
-
for (const [layer, count] of Object.entries(result.layerCounts)) {
|
|
445
|
-
if (count > 0) {
|
|
446
|
-
lines.push(` • ${layer}: ${count} files`)
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
lines.push('')
|
|
450
|
-
lines.push(`📍 Data location: ${result.config.dataPath}`)
|
|
451
|
-
|
|
452
|
-
if (result.legacyRemoved) {
|
|
453
|
-
lines.push('')
|
|
454
|
-
lines.push('🗑️ Legacy .prjct directory removed')
|
|
455
|
-
}
|
|
456
|
-
} else {
|
|
457
|
-
lines.push('❌ Migration failed!')
|
|
458
|
-
lines.push('')
|
|
459
|
-
if (result.issues.length > 0) {
|
|
460
|
-
lines.push('Issues:')
|
|
461
|
-
for (const issue of result.issues) {
|
|
462
|
-
lines.push(` • ${issue}`)
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
lines.push('━━━━━━━━━━━━━━━━━━━━━━━━━━━━')
|
|
468
|
-
|
|
469
|
-
return lines.join('\n')
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
/**
|
|
473
|
-
* Check migration status for a project
|
|
474
|
-
*
|
|
475
|
-
* @param {string} projectPath - Path to the project
|
|
476
|
-
* @returns {Promise<Object>} - Status information
|
|
477
|
-
*/
|
|
478
|
-
async checkStatus(projectPath) {
|
|
479
|
-
const hasLegacy = await pathManager.hasLegacyStructure(projectPath)
|
|
480
|
-
const hasConfig = await pathManager.hasConfig(projectPath)
|
|
481
|
-
const needsMigration = hasLegacy && !hasConfig
|
|
482
|
-
|
|
483
|
-
let status = 'unknown'
|
|
484
|
-
if (!hasLegacy && !hasConfig) {
|
|
485
|
-
status = 'new' // New project, not initialized
|
|
486
|
-
} else if (!hasLegacy && hasConfig) {
|
|
487
|
-
status = 'migrated' // Already migrated to v0.2.0
|
|
488
|
-
} else if (hasLegacy && !hasConfig) {
|
|
489
|
-
status = 'legacy' // v0.1.0, needs migration
|
|
490
|
-
} else if (hasLegacy && hasConfig) {
|
|
491
|
-
status = 'both' // Has both (migration incomplete or manual setup)
|
|
492
|
-
}
|
|
493
|
-
|
|
494
|
-
return {
|
|
495
|
-
status,
|
|
496
|
-
hasLegacy,
|
|
497
|
-
hasConfig,
|
|
498
|
-
needsMigration,
|
|
499
|
-
version: hasConfig ? '0.2.0' : hasLegacy ? '0.1.0' : 'none',
|
|
500
|
-
}
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
/**
|
|
504
|
-
* Find all projects with .prjct directories on the user's machine
|
|
505
|
-
*
|
|
506
|
-
* @param {Object} options - Search options
|
|
507
|
-
* @param {boolean} options.deepScan - Scan entire home directory (default: true for automatic migration)
|
|
508
|
-
* @returns {Promise<Array<string>>} - Array of project paths
|
|
509
|
-
*/
|
|
510
|
-
async findAllProjects(options = {}) {
|
|
511
|
-
const { deepScan = true } = options
|
|
512
|
-
const projectDirs = []
|
|
513
|
-
const os = require('os')
|
|
514
|
-
|
|
515
|
-
let searchPaths = []
|
|
516
|
-
if (deepScan) {
|
|
517
|
-
searchPaths = [os.homedir()]
|
|
518
|
-
} else {
|
|
519
|
-
const commonDirs = [
|
|
520
|
-
'Projects',
|
|
521
|
-
'Documents',
|
|
522
|
-
'Developer',
|
|
523
|
-
'Code',
|
|
524
|
-
'dev',
|
|
525
|
-
'workspace',
|
|
526
|
-
'repos',
|
|
527
|
-
'src',
|
|
528
|
-
'Apps',
|
|
529
|
-
]
|
|
530
|
-
searchPaths = commonDirs
|
|
531
|
-
.map((dir) => path.join(os.homedir(), dir))
|
|
532
|
-
.filter((dirPath) => {
|
|
533
|
-
try {
|
|
534
|
-
fs.accessSync(dirPath)
|
|
535
|
-
return true
|
|
536
|
-
} catch {
|
|
537
|
-
return false
|
|
538
|
-
}
|
|
539
|
-
})
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
const shouldSkip = (dirName) => {
|
|
543
|
-
const skipDirs = [
|
|
544
|
-
'node_modules',
|
|
545
|
-
'.git',
|
|
546
|
-
'.next',
|
|
547
|
-
'dist',
|
|
548
|
-
'build',
|
|
549
|
-
'.cache',
|
|
550
|
-
'coverage',
|
|
551
|
-
'.vscode',
|
|
552
|
-
'.idea',
|
|
553
|
-
'vendor',
|
|
554
|
-
'__pycache__',
|
|
555
|
-
]
|
|
556
|
-
return skipDirs.includes(dirName) || (dirName.startsWith('.') && dirName !== '.prjct')
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
const searchDirectory = async (dirPath, depth = 0) => {
|
|
560
|
-
if (depth > 10) return
|
|
561
|
-
|
|
562
|
-
try {
|
|
563
|
-
const entries = await fs.readdir(dirPath, { withFileTypes: true })
|
|
564
|
-
|
|
565
|
-
if (entries.some((entry) => entry.name === '.prjct' && entry.isDirectory())) {
|
|
566
|
-
projectDirs.push(dirPath)
|
|
567
|
-
return // Don't search subdirectories if we found a project
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
for (const entry of entries) {
|
|
571
|
-
if (entry.isDirectory() && !shouldSkip(entry.name)) {
|
|
572
|
-
const subPath = path.join(dirPath, entry.name)
|
|
573
|
-
await searchDirectory(subPath, depth + 1)
|
|
574
|
-
}
|
|
575
|
-
}
|
|
576
|
-
} catch (error) {}
|
|
577
|
-
}
|
|
578
|
-
|
|
579
|
-
for (const searchPath of searchPaths) {
|
|
580
|
-
await searchDirectory(searchPath)
|
|
581
|
-
}
|
|
582
|
-
|
|
583
|
-
return projectDirs
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
/**
|
|
587
|
-
* Migrate all projects with legacy .prjct directories
|
|
588
|
-
*
|
|
589
|
-
* @param {Object} options - Migration options
|
|
590
|
-
* @param {boolean} options.deepScan - Scan entire home directory
|
|
591
|
-
* @param {boolean} options.removeLegacy - Remove legacy .prjct after migration completely
|
|
592
|
-
* @param {boolean} options.cleanupLegacy - Remove legacy directories but keep config
|
|
593
|
-
* @param {boolean} options.dryRun - Simulate migration without making changes
|
|
594
|
-
* @param {boolean} options.interactive - Ask for confirmation before each migration
|
|
595
|
-
* @param {Function} options.onProgress - Callback for progress updates
|
|
596
|
-
* @returns {Promise<Object>} - Migration summary
|
|
597
|
-
*/
|
|
598
|
-
async migrateAll(options = {}) {
|
|
599
|
-
const {
|
|
600
|
-
deepScan = false,
|
|
601
|
-
removeLegacy = false,
|
|
602
|
-
cleanupLegacy = false,
|
|
603
|
-
dryRun = false,
|
|
604
|
-
interactive = false,
|
|
605
|
-
onProgress = null,
|
|
606
|
-
} = options
|
|
607
|
-
|
|
608
|
-
const summary = {
|
|
609
|
-
success: false,
|
|
610
|
-
totalFound: 0,
|
|
611
|
-
alreadyMigrated: 0,
|
|
612
|
-
successfullyMigrated: 0,
|
|
613
|
-
failed: 0,
|
|
614
|
-
skipped: 0,
|
|
615
|
-
projects: [],
|
|
616
|
-
errors: [],
|
|
617
|
-
dryRun,
|
|
618
|
-
}
|
|
619
|
-
|
|
620
|
-
try {
|
|
621
|
-
if (onProgress) onProgress({ phase: 'scanning', message: 'Searching for projects...' })
|
|
622
|
-
const projectPaths = await this.findAllProjects({ deepScan })
|
|
623
|
-
summary.totalFound = projectPaths.length
|
|
624
|
-
|
|
625
|
-
if (projectPaths.length === 0) {
|
|
626
|
-
summary.success = true
|
|
627
|
-
return summary
|
|
628
|
-
}
|
|
629
|
-
|
|
630
|
-
for (let i = 0; i < projectPaths.length; i++) {
|
|
631
|
-
const projectPath = projectPaths[i]
|
|
632
|
-
const projectName = path.basename(projectPath)
|
|
633
|
-
|
|
634
|
-
if (onProgress) {
|
|
635
|
-
onProgress({
|
|
636
|
-
phase: 'checking',
|
|
637
|
-
message: `Checking ${projectName} (${i + 1}/${projectPaths.length})`,
|
|
638
|
-
current: i + 1,
|
|
639
|
-
total: projectPaths.length,
|
|
640
|
-
})
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
try {
|
|
644
|
-
const status = await this.checkStatus(projectPath)
|
|
645
|
-
|
|
646
|
-
const projectInfo = {
|
|
647
|
-
path: projectPath,
|
|
648
|
-
name: projectName,
|
|
649
|
-
status: status.status,
|
|
650
|
-
}
|
|
651
|
-
|
|
652
|
-
if (status.status === 'migrated' || status.status === 'new') {
|
|
653
|
-
projectInfo.result = 'skipped'
|
|
654
|
-
projectInfo.reason =
|
|
655
|
-
status.status === 'migrated' ? 'Already migrated' : 'Not initialized'
|
|
656
|
-
summary.alreadyMigrated++
|
|
657
|
-
} else if (status.needsMigration) {
|
|
658
|
-
if (interactive && onProgress) {
|
|
659
|
-
const shouldMigrate = await onProgress({
|
|
660
|
-
phase: 'confirm',
|
|
661
|
-
message: `Migrate ${projectName}?`,
|
|
662
|
-
projectPath,
|
|
663
|
-
})
|
|
664
|
-
if (!shouldMigrate) {
|
|
665
|
-
projectInfo.result = 'skipped'
|
|
666
|
-
projectInfo.reason = 'User skipped'
|
|
667
|
-
summary.skipped++
|
|
668
|
-
summary.projects.push(projectInfo)
|
|
669
|
-
continue
|
|
670
|
-
}
|
|
671
|
-
}
|
|
672
|
-
|
|
673
|
-
if (onProgress) {
|
|
674
|
-
onProgress({
|
|
675
|
-
phase: 'migrating',
|
|
676
|
-
message: `Migrating ${projectName}...`,
|
|
677
|
-
current: i + 1,
|
|
678
|
-
total: projectPaths.length,
|
|
679
|
-
})
|
|
680
|
-
}
|
|
681
|
-
|
|
682
|
-
const migrationResult = await this.migrate(projectPath, {
|
|
683
|
-
removeLegacy,
|
|
684
|
-
cleanupLegacy,
|
|
685
|
-
dryRun,
|
|
686
|
-
})
|
|
687
|
-
|
|
688
|
-
projectInfo.projectId = migrationResult.projectId
|
|
689
|
-
projectInfo.filesCopied = migrationResult.filesCopied
|
|
690
|
-
projectInfo.layerCounts = migrationResult.layerCounts
|
|
691
|
-
|
|
692
|
-
if (migrationResult.success) {
|
|
693
|
-
projectInfo.result = 'success'
|
|
694
|
-
summary.successfullyMigrated++
|
|
695
|
-
} else {
|
|
696
|
-
projectInfo.result = 'failed'
|
|
697
|
-
projectInfo.errors = migrationResult.issues
|
|
698
|
-
summary.failed++
|
|
699
|
-
summary.errors.push({
|
|
700
|
-
project: projectName,
|
|
701
|
-
path: projectPath,
|
|
702
|
-
issues: migrationResult.issues,
|
|
703
|
-
})
|
|
704
|
-
}
|
|
705
|
-
}
|
|
706
|
-
|
|
707
|
-
summary.projects.push(projectInfo)
|
|
708
|
-
} catch (error) {
|
|
709
|
-
summary.failed++
|
|
710
|
-
summary.errors.push({
|
|
711
|
-
project: projectName,
|
|
712
|
-
path: projectPath,
|
|
713
|
-
issues: [error.message],
|
|
714
|
-
})
|
|
715
|
-
summary.projects.push({
|
|
716
|
-
path: projectPath,
|
|
717
|
-
name: projectName,
|
|
718
|
-
result: 'failed',
|
|
719
|
-
errors: [error.message],
|
|
720
|
-
})
|
|
721
|
-
}
|
|
722
|
-
}
|
|
723
|
-
|
|
724
|
-
summary.success = summary.failed === 0
|
|
725
|
-
return summary
|
|
726
|
-
} catch (error) {
|
|
727
|
-
summary.success = false
|
|
728
|
-
summary.errors.push({
|
|
729
|
-
project: 'global',
|
|
730
|
-
issues: [error.message],
|
|
731
|
-
})
|
|
732
|
-
return summary
|
|
733
|
-
}
|
|
734
|
-
}
|
|
735
|
-
|
|
736
|
-
/**
|
|
737
|
-
* Generate a summary report for migrateAll results
|
|
738
|
-
*
|
|
739
|
-
* @param {Object} summary - Migration summary from migrateAll
|
|
740
|
-
* @returns {string} - Formatted report
|
|
741
|
-
*/
|
|
742
|
-
generateMigrationSummary(summary) {
|
|
743
|
-
const lines = []
|
|
744
|
-
|
|
745
|
-
lines.push('📦 Global Migration Report')
|
|
746
|
-
lines.push('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')
|
|
747
|
-
|
|
748
|
-
if (summary.dryRun) {
|
|
749
|
-
lines.push('⚠️ DRY RUN MODE - No changes were made')
|
|
750
|
-
lines.push('')
|
|
751
|
-
}
|
|
752
|
-
|
|
753
|
-
lines.push(`🔍 Found: ${summary.totalFound} projects`)
|
|
754
|
-
lines.push(`✅ Successfully migrated: ${summary.successfullyMigrated}`)
|
|
755
|
-
lines.push(`⏭️ Already migrated: ${summary.alreadyMigrated}`)
|
|
756
|
-
if (summary.skipped > 0) {
|
|
757
|
-
lines.push(`⏸️ Skipped: ${summary.skipped}`)
|
|
758
|
-
}
|
|
759
|
-
if (summary.failed > 0) {
|
|
760
|
-
lines.push(`❌ Failed: ${summary.failed}`)
|
|
761
|
-
}
|
|
762
|
-
lines.push('')
|
|
763
|
-
|
|
764
|
-
if (summary.successfullyMigrated > 0) {
|
|
765
|
-
lines.push('✅ Successfully Migrated:')
|
|
766
|
-
summary.projects
|
|
767
|
-
.filter((p) => p.result === 'success')
|
|
768
|
-
.forEach((project) => {
|
|
769
|
-
lines.push(` • ${project.name}`)
|
|
770
|
-
lines.push(` Files: ${project.filesCopied} | ID: ${project.projectId}`)
|
|
771
|
-
})
|
|
772
|
-
lines.push('')
|
|
773
|
-
}
|
|
774
|
-
|
|
775
|
-
if (summary.errors.length > 0) {
|
|
776
|
-
lines.push('❌ Errors:')
|
|
777
|
-
summary.errors.forEach((error) => {
|
|
778
|
-
lines.push(` • ${error.project}`)
|
|
779
|
-
error.issues.forEach((issue) => lines.push(` - ${issue}`))
|
|
780
|
-
})
|
|
781
|
-
lines.push('')
|
|
782
|
-
}
|
|
783
|
-
|
|
784
|
-
if (summary.success && summary.successfullyMigrated > 0) {
|
|
785
|
-
lines.push('🎉 All projects migrated successfully!')
|
|
786
|
-
lines.push(`📍 Global data location: ${pathManager.getGlobalBasePath()}`)
|
|
787
|
-
} else if (summary.totalFound === 0) {
|
|
788
|
-
lines.push('ℹ️ No legacy projects found')
|
|
789
|
-
} else if (summary.alreadyMigrated === summary.totalFound) {
|
|
790
|
-
lines.push('ℹ️ All projects already migrated')
|
|
791
|
-
}
|
|
792
|
-
|
|
793
|
-
lines.push('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')
|
|
794
|
-
|
|
795
|
-
return lines.join('\n')
|
|
796
|
-
}
|
|
797
|
-
}
|
|
798
|
-
|
|
799
|
-
module.exports = new Migrator()
|