prjct-cli 0.11.5 → 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 +58 -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 +226 -50
- 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.js → date-helper.test.ts} +19 -30
- 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} +92 -81
- 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} +27 -16
- 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} +55 -19
- 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 +204 -163
- 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/{stats → BentoGrid}/BentoGrid.tsx +4 -8
- 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/{stats → EmptyState}/EmptyState.tsx +1 -10
- 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/{stats → IdeasCard}/IdeasCard.tsx +3 -14
- 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/{stats → ProgressRing}/ProgressRing.tsx +4 -27
- 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/{stats → RoadmapCard}/RoadmapCard.tsx +3 -23
- package/packages/web/components/RoadmapCard/RoadmapCard.types.ts +15 -0
- package/packages/web/components/RoadmapCard/index.ts +2 -0
- package/packages/web/components/{stats → ShipsCard}/ShipsCard.tsx +4 -22
- 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/{stats → SparklineChart}/SparklineChart.tsx +1 -7
- 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/{stats → StreakCard}/StreakCard.tsx +5 -11
- 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/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/package.json +10 -7
- 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 -140
- package/core/agentic/chain-of-thought.js +0 -578
- package/core/agentic/command-executor.js +0 -417
- 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 -845
- package/core/agentic/parallel-tools.js +0 -366
- package/core/agentic/plan-mode.js +0 -572
- package/core/agentic/prompt-builder.js +0 -352
- 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 -796
- 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/components/stats/ActivityTimeline.tsx +0 -201
- package/packages/web/components/stats/AgentsCard.tsx +0 -56
- package/packages/web/components/stats/BentoCard.tsx +0 -88
- package/packages/web/components/stats/HeroSection.tsx +0 -172
- package/packages/web/components/stats/NowCard.tsx +0 -71
- package/packages/web/components/stats/QueueCard.tsx +0 -58
- package/packages/web/components/stats/VelocityCard.tsx +0 -60
- package/packages/web/components/stats/index.ts +0 -17
- 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,307 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SessionManager Class
|
|
3
|
+
* Manages temporal fragmentation of logs and progress data.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import path from 'path'
|
|
7
|
+
import pathManager from '../path-manager'
|
|
8
|
+
import { VERSION } from '../../utils/version'
|
|
9
|
+
import * as dateHelper from '../../utils/date-helper'
|
|
10
|
+
import * as jsonlHelper from '../../utils/jsonl-helper'
|
|
11
|
+
import * as fileHelper from '../../utils/file-helper'
|
|
12
|
+
import { migrateLegacyJsonl, migrateLegacyMarkdown } from './migration'
|
|
13
|
+
import type { SessionEntry, SessionMetadata, SessionStats, MigrationResult } from './types'
|
|
14
|
+
|
|
15
|
+
export class SessionManager {
|
|
16
|
+
private currentSessionCache: Map<string, string>
|
|
17
|
+
private sessionMetadataCache: Map<string, SessionMetadata>
|
|
18
|
+
|
|
19
|
+
constructor() {
|
|
20
|
+
this.currentSessionCache = new Map()
|
|
21
|
+
this.sessionMetadataCache = new Map()
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Get or create current session directory for a project
|
|
26
|
+
*/
|
|
27
|
+
async getCurrentSession(projectId: string): Promise<string> {
|
|
28
|
+
const cacheKey = `${projectId}-${this._getTodayKey()}`
|
|
29
|
+
|
|
30
|
+
if (this.currentSessionCache.has(cacheKey)) {
|
|
31
|
+
return this.currentSessionCache.get(cacheKey)!
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const sessionPath = await pathManager.ensureSessionPath(projectId)
|
|
35
|
+
this.currentSessionCache.set(cacheKey, sessionPath)
|
|
36
|
+
|
|
37
|
+
await this._ensureSessionMetadata(sessionPath)
|
|
38
|
+
|
|
39
|
+
return sessionPath
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Write log entry to current session
|
|
44
|
+
*/
|
|
45
|
+
async writeToSession(
|
|
46
|
+
projectId: string,
|
|
47
|
+
entry: SessionEntry,
|
|
48
|
+
filename: string = 'context.jsonl'
|
|
49
|
+
): Promise<void> {
|
|
50
|
+
const sessionPath = await this.getCurrentSession(projectId)
|
|
51
|
+
const filePath = path.join(sessionPath, filename)
|
|
52
|
+
|
|
53
|
+
// Use automatic rotation to prevent large files (>10MB)
|
|
54
|
+
await jsonlHelper.appendJsonLineWithRotation(filePath, entry, 10)
|
|
55
|
+
|
|
56
|
+
await this._updateSessionMetadata(sessionPath, {
|
|
57
|
+
lastActivity: dateHelper.getTimestamp(),
|
|
58
|
+
entryCount: await jsonlHelper.countJsonLines(filePath),
|
|
59
|
+
})
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Append content to a session file (for markdown files like shipped.md)
|
|
64
|
+
*/
|
|
65
|
+
async appendToSession(projectId: string, content: string, filename: string): Promise<void> {
|
|
66
|
+
const sessionPath = await this.getCurrentSession(projectId)
|
|
67
|
+
const filePath = path.join(sessionPath, filename)
|
|
68
|
+
|
|
69
|
+
const exists = await fileHelper.fileExists(filePath)
|
|
70
|
+
if (!exists && filename === 'shipped.md') {
|
|
71
|
+
await fileHelper.writeFile(filePath, '# SHIPPED 🚀\n\n' + content)
|
|
72
|
+
} else {
|
|
73
|
+
await fileHelper.appendToFile(filePath, content)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
await this._updateSessionMetadata(sessionPath, {
|
|
77
|
+
lastActivity: dateHelper.getTimestamp(),
|
|
78
|
+
})
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Read logs from current session
|
|
83
|
+
* Uses streaming for large files (>50MB)
|
|
84
|
+
*/
|
|
85
|
+
async readCurrentSession<T = SessionEntry>(
|
|
86
|
+
projectId: string,
|
|
87
|
+
filename: string = 'context.jsonl',
|
|
88
|
+
maxLines: number = 1000
|
|
89
|
+
): Promise<T[]> {
|
|
90
|
+
const sessionPath = await this.getCurrentSession(projectId)
|
|
91
|
+
const filePath = path.join(sessionPath, filename)
|
|
92
|
+
|
|
93
|
+
// Check file size and warn if large
|
|
94
|
+
const { isLarge } = await jsonlHelper.checkFileSizeWarning(filePath, 50)
|
|
95
|
+
|
|
96
|
+
if (isLarge) {
|
|
97
|
+
// Use streaming for large files
|
|
98
|
+
return (await jsonlHelper.readJsonLinesStreaming(filePath, maxLines)) as T[]
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Use normal read for small files
|
|
102
|
+
return (await jsonlHelper.readJsonLines(filePath)) as T[]
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Read logs from a specific date range
|
|
107
|
+
*/
|
|
108
|
+
async readSessionRange<T = SessionEntry>(
|
|
109
|
+
projectId: string,
|
|
110
|
+
fromDate: Date,
|
|
111
|
+
toDate: Date = new Date(),
|
|
112
|
+
filename: string = 'context.jsonl'
|
|
113
|
+
): Promise<T[]> {
|
|
114
|
+
const sessions = await pathManager.getSessionsInRange(projectId, fromDate, toDate)
|
|
115
|
+
const allEntries: T[] = []
|
|
116
|
+
|
|
117
|
+
for (const session of sessions) {
|
|
118
|
+
const filePath = path.join(session.path, filename)
|
|
119
|
+
const entries = (await jsonlHelper.readJsonLines(filePath)) as (T & { _sessionDate?: Date })[]
|
|
120
|
+
|
|
121
|
+
entries.forEach((entry) => {
|
|
122
|
+
entry._sessionDate = session.date
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
allEntries.push(...entries)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return allEntries
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Read markdown content from sessions in date range
|
|
133
|
+
*/
|
|
134
|
+
async readMarkdownRange(
|
|
135
|
+
projectId: string,
|
|
136
|
+
fromDate: Date,
|
|
137
|
+
toDate: Date,
|
|
138
|
+
filename: string
|
|
139
|
+
): Promise<string> {
|
|
140
|
+
const sessions = await pathManager.getSessionsInRange(projectId, fromDate, toDate)
|
|
141
|
+
const allContent: string[] = []
|
|
142
|
+
|
|
143
|
+
for (const session of sessions) {
|
|
144
|
+
const filePath = path.join(session.path, filename)
|
|
145
|
+
const content = await fileHelper.readFile(filePath, '')
|
|
146
|
+
|
|
147
|
+
if (content.trim()) {
|
|
148
|
+
allContent.push(`## Session: ${session.year}-${session.month}-${session.day}\n\n${content}`)
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return allContent.join('\n---\n\n')
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Get recent logs (last N days)
|
|
157
|
+
*/
|
|
158
|
+
async getRecentLogs<T = SessionEntry>(
|
|
159
|
+
projectId: string,
|
|
160
|
+
days: number = 7,
|
|
161
|
+
filename: string = 'context.jsonl'
|
|
162
|
+
): Promise<T[]> {
|
|
163
|
+
const toDate = new Date()
|
|
164
|
+
const fromDate = dateHelper.getDaysAgo(days)
|
|
165
|
+
|
|
166
|
+
return await this.readSessionRange<T>(projectId, fromDate, toDate, filename)
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Get session statistics
|
|
171
|
+
*/
|
|
172
|
+
async getSessionStats(projectId: string, fromDate: Date, toDate: Date): Promise<SessionStats> {
|
|
173
|
+
const sessions = await pathManager.getSessionsInRange(projectId, fromDate, toDate)
|
|
174
|
+
|
|
175
|
+
let totalEntries = 0
|
|
176
|
+
let totalShips = 0
|
|
177
|
+
let activeDays = 0
|
|
178
|
+
|
|
179
|
+
for (const session of sessions) {
|
|
180
|
+
const metadata = await this._getSessionMetadata(session.path)
|
|
181
|
+
if (metadata) {
|
|
182
|
+
totalEntries += metadata.entryCount || 0
|
|
183
|
+
totalShips += metadata.shipCount || 0
|
|
184
|
+
if (metadata.entryCount && metadata.entryCount > 0) {
|
|
185
|
+
activeDays++
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return {
|
|
191
|
+
totalSessions: sessions.length,
|
|
192
|
+
activeDays,
|
|
193
|
+
totalEntries,
|
|
194
|
+
totalShips,
|
|
195
|
+
averageEntriesPerDay: activeDays > 0 ? Math.round(totalEntries / activeDays) : 0,
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Migrate legacy single-file logs to session structure
|
|
201
|
+
*/
|
|
202
|
+
async migrateLegacyLogs(
|
|
203
|
+
projectId: string,
|
|
204
|
+
legacyFilePath: string,
|
|
205
|
+
sessionFilename: string
|
|
206
|
+
): Promise<MigrationResult> {
|
|
207
|
+
try {
|
|
208
|
+
const content = await fileHelper.readFile(legacyFilePath)
|
|
209
|
+
|
|
210
|
+
if (sessionFilename.endsWith('.jsonl')) {
|
|
211
|
+
return await migrateLegacyJsonl(
|
|
212
|
+
projectId,
|
|
213
|
+
content,
|
|
214
|
+
sessionFilename,
|
|
215
|
+
(sp, u) => this._updateSessionMetadata(sp, u),
|
|
216
|
+
(sp) => this._ensureSessionMetadata(sp)
|
|
217
|
+
)
|
|
218
|
+
} else {
|
|
219
|
+
const sessionPath = await this.getCurrentSession(projectId)
|
|
220
|
+
return await migrateLegacyMarkdown(
|
|
221
|
+
sessionPath,
|
|
222
|
+
content,
|
|
223
|
+
sessionFilename,
|
|
224
|
+
(sp, u) => this._updateSessionMetadata(sp, u)
|
|
225
|
+
)
|
|
226
|
+
}
|
|
227
|
+
} catch (error) {
|
|
228
|
+
return {
|
|
229
|
+
success: false,
|
|
230
|
+
message: `Migration failed: ${(error as Error).message}`,
|
|
231
|
+
entriesMigrated: 0,
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Get session metadata
|
|
238
|
+
*/
|
|
239
|
+
private async _getSessionMetadata(sessionPath: string): Promise<SessionMetadata | null> {
|
|
240
|
+
const metadataPath = path.join(sessionPath, 'session-meta.json')
|
|
241
|
+
|
|
242
|
+
if (this.sessionMetadataCache.has(sessionPath)) {
|
|
243
|
+
return this.sessionMetadataCache.get(sessionPath)!
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
const metadata = await fileHelper.readJson<SessionMetadata>(metadataPath, null)
|
|
247
|
+
if (metadata) {
|
|
248
|
+
this.sessionMetadataCache.set(sessionPath, metadata)
|
|
249
|
+
}
|
|
250
|
+
return metadata
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Ensure session metadata exists
|
|
255
|
+
*/
|
|
256
|
+
private async _ensureSessionMetadata(sessionPath: string): Promise<void> {
|
|
257
|
+
const metadataPath = path.join(sessionPath, 'session-meta.json')
|
|
258
|
+
|
|
259
|
+
const exists = await fileHelper.fileExists(metadataPath)
|
|
260
|
+
if (!exists) {
|
|
261
|
+
const metadata: SessionMetadata = {
|
|
262
|
+
created: dateHelper.getTimestamp(),
|
|
263
|
+
lastActivity: dateHelper.getTimestamp(),
|
|
264
|
+
entryCount: 0,
|
|
265
|
+
shipCount: 0,
|
|
266
|
+
version: VERSION,
|
|
267
|
+
}
|
|
268
|
+
await fileHelper.writeJson(metadataPath, metadata)
|
|
269
|
+
this.sessionMetadataCache.set(sessionPath, metadata)
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Update session metadata
|
|
275
|
+
*/
|
|
276
|
+
private async _updateSessionMetadata(
|
|
277
|
+
sessionPath: string,
|
|
278
|
+
updates: Partial<SessionMetadata>
|
|
279
|
+
): Promise<void> {
|
|
280
|
+
const metadata = (await this._getSessionMetadata(sessionPath)) || {}
|
|
281
|
+
Object.assign(metadata, updates)
|
|
282
|
+
|
|
283
|
+
const metadataPath = path.join(sessionPath, 'session-meta.json')
|
|
284
|
+
await fileHelper.writeJson(metadataPath, metadata)
|
|
285
|
+
|
|
286
|
+
this.sessionMetadataCache.set(sessionPath, metadata)
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Get today's date key (YYYY-MM-DD)
|
|
291
|
+
*/
|
|
292
|
+
private _getTodayKey(): string {
|
|
293
|
+
return dateHelper.getTodayKey()
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Get date key for any date (YYYY-MM-DD)
|
|
298
|
+
*/
|
|
299
|
+
private _getDateKey(date: Date): string {
|
|
300
|
+
return dateHelper.getDateKey(date)
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
clearCache(): void {
|
|
304
|
+
this.currentSessionCache.clear()
|
|
305
|
+
this.sessionMetadataCache.clear()
|
|
306
|
+
}
|
|
307
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session Manager Types
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export interface SessionEntry {
|
|
6
|
+
timestamp?: string
|
|
7
|
+
data?: {
|
|
8
|
+
timestamp?: string
|
|
9
|
+
}
|
|
10
|
+
_sessionDate?: Date
|
|
11
|
+
[key: string]: unknown
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface SessionMetadata {
|
|
15
|
+
created?: string
|
|
16
|
+
lastActivity?: string
|
|
17
|
+
entryCount?: number
|
|
18
|
+
shipCount?: number
|
|
19
|
+
version?: string
|
|
20
|
+
migrated?: boolean
|
|
21
|
+
migratedAt?: string
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface SessionStats {
|
|
25
|
+
totalSessions: number
|
|
26
|
+
activeDays: number
|
|
27
|
+
totalEntries: number
|
|
28
|
+
totalShips: number
|
|
29
|
+
averageEntriesPerDay: number
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface MigrationResult {
|
|
33
|
+
success: boolean
|
|
34
|
+
message: string
|
|
35
|
+
entriesMigrated: number
|
|
36
|
+
sessionsCreated?: number
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface SessionInfo {
|
|
40
|
+
path: string
|
|
41
|
+
date: Date
|
|
42
|
+
year: string
|
|
43
|
+
month: string
|
|
44
|
+
day: string
|
|
45
|
+
}
|
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
const { execSync } = require('child_process')
|
|
2
|
-
const installer = require('./command-installer')
|
|
3
|
-
const migrator = require('./migrator')
|
|
4
|
-
const legacyDetector = require('./legacy-installer-detector')
|
|
5
|
-
const editorsConfig = require('./editors-config')
|
|
6
|
-
const { VERSION } = require('../utils/version')
|
|
7
|
-
|
|
8
1
|
/**
|
|
9
2
|
* Setup Module - Core installation logic
|
|
10
3
|
*
|
|
@@ -23,18 +16,33 @@ const { VERSION } = require('../utils/version')
|
|
|
23
16
|
* @version 0.8.8
|
|
24
17
|
*/
|
|
25
18
|
|
|
19
|
+
import { execSync } from 'child_process'
|
|
20
|
+
import installer from './command-installer'
|
|
21
|
+
import migrator from './migrator'
|
|
22
|
+
import legacyDetector from './legacy-installer-detector'
|
|
23
|
+
import editorsConfig from './editors-config'
|
|
24
|
+
import { VERSION } from '../utils/version'
|
|
25
|
+
|
|
26
26
|
// Colors
|
|
27
27
|
const GREEN = '\x1b[32m'
|
|
28
28
|
const YELLOW = '\x1b[33m'
|
|
29
|
-
const MAGENTA = '\x1b[35m'
|
|
30
|
-
const BOLD = '\x1b[1m'
|
|
31
29
|
const DIM = '\x1b[2m'
|
|
32
30
|
const NC = '\x1b[0m'
|
|
33
31
|
|
|
32
|
+
interface SetupResults {
|
|
33
|
+
legacyCleaned: boolean
|
|
34
|
+
legacyProjectsMigrated: number
|
|
35
|
+
claudeInstalled: boolean
|
|
36
|
+
commandsAdded: number
|
|
37
|
+
commandsUpdated: number
|
|
38
|
+
configAction: string | null
|
|
39
|
+
projectsMigrated: number
|
|
40
|
+
}
|
|
41
|
+
|
|
34
42
|
/**
|
|
35
43
|
* Check if Claude Code CLI is installed
|
|
36
44
|
*/
|
|
37
|
-
async function hasClaudeCodeCLI() {
|
|
45
|
+
async function hasClaudeCodeCLI(): Promise<boolean> {
|
|
38
46
|
try {
|
|
39
47
|
execSync('which claude', { stdio: 'ignore' })
|
|
40
48
|
return true
|
|
@@ -46,7 +54,7 @@ async function hasClaudeCodeCLI() {
|
|
|
46
54
|
/**
|
|
47
55
|
* Install Claude Code CLI
|
|
48
56
|
*/
|
|
49
|
-
async function installClaudeCode() {
|
|
57
|
+
async function installClaudeCode(): Promise<boolean> {
|
|
50
58
|
try {
|
|
51
59
|
console.log(`${YELLOW}📦 Claude Code not found. Installing...${NC}`)
|
|
52
60
|
console.log('')
|
|
@@ -56,7 +64,7 @@ async function installClaudeCode() {
|
|
|
56
64
|
console.log('')
|
|
57
65
|
return true
|
|
58
66
|
} catch (error) {
|
|
59
|
-
console.log(`${YELLOW}⚠️ Failed to install Claude Code: ${error.message}${NC}`)
|
|
67
|
+
console.log(`${YELLOW}⚠️ Failed to install Claude Code: ${(error as Error).message}${NC}`)
|
|
60
68
|
console.log(`${DIM}Please install manually: npm install -g @anthropic-ai/claude-code${NC}`)
|
|
61
69
|
console.log('')
|
|
62
70
|
return false
|
|
@@ -66,15 +74,15 @@ async function installClaudeCode() {
|
|
|
66
74
|
/**
|
|
67
75
|
* Main setup function
|
|
68
76
|
*/
|
|
69
|
-
async function run() {
|
|
70
|
-
const results = {
|
|
77
|
+
export async function run(): Promise<SetupResults> {
|
|
78
|
+
const results: SetupResults = {
|
|
71
79
|
legacyCleaned: false,
|
|
72
80
|
legacyProjectsMigrated: 0,
|
|
73
81
|
claudeInstalled: false,
|
|
74
82
|
commandsAdded: 0,
|
|
75
83
|
commandsUpdated: 0,
|
|
76
84
|
configAction: null,
|
|
77
|
-
projectsMigrated: 0
|
|
85
|
+
projectsMigrated: 0,
|
|
78
86
|
}
|
|
79
87
|
|
|
80
88
|
// Step 0: Detect and clean legacy curl installation
|
|
@@ -120,7 +128,7 @@ async function run() {
|
|
|
120
128
|
const migrationResult = await migrator.migrateAll({
|
|
121
129
|
deepScan: false,
|
|
122
130
|
cleanupLegacy: true,
|
|
123
|
-
dryRun: false
|
|
131
|
+
dryRun: false,
|
|
124
132
|
})
|
|
125
133
|
|
|
126
134
|
if (migrationResult.successfullyMigrated > 0) {
|
|
@@ -140,14 +148,16 @@ async function run() {
|
|
|
140
148
|
/**
|
|
141
149
|
* Show setup results
|
|
142
150
|
*/
|
|
143
|
-
function showResults(results) {
|
|
151
|
+
function showResults(results: SetupResults): void {
|
|
144
152
|
console.log('')
|
|
145
153
|
|
|
146
154
|
// Show what was done
|
|
147
155
|
if (results.legacyCleaned) {
|
|
148
156
|
console.log(` ${GREEN}✓${NC} Legacy curl installation cleaned up`)
|
|
149
157
|
if (results.legacyProjectsMigrated > 0) {
|
|
150
|
-
console.log(
|
|
158
|
+
console.log(
|
|
159
|
+
` ${GREEN}✓${NC} ${results.legacyProjectsMigrated} project(s) migrated from legacy`
|
|
160
|
+
)
|
|
151
161
|
}
|
|
152
162
|
}
|
|
153
163
|
|
|
@@ -159,7 +169,7 @@ function showResults(results) {
|
|
|
159
169
|
|
|
160
170
|
const totalCommands = results.commandsAdded + results.commandsUpdated
|
|
161
171
|
if (totalCommands > 0) {
|
|
162
|
-
const parts = []
|
|
172
|
+
const parts: string[] = []
|
|
163
173
|
if (results.commandsAdded > 0) parts.push(`${results.commandsAdded} new`)
|
|
164
174
|
if (results.commandsUpdated > 0) parts.push(`${results.commandsUpdated} updated`)
|
|
165
175
|
console.log(` ${GREEN}✓${NC} Commands synced (${parts.join(', ')})`)
|
|
@@ -181,5 +191,3 @@ function showResults(results) {
|
|
|
181
191
|
|
|
182
192
|
console.log('')
|
|
183
193
|
}
|
|
184
|
-
|
|
185
|
-
module.exports = { run }
|
|
@@ -1,9 +1,32 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
/**
|
|
2
|
+
* UpdateChecker - Checks for package updates from npm registry
|
|
3
|
+
*
|
|
4
|
+
* @version 0.5.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import https from 'https'
|
|
8
|
+
import fs from 'fs'
|
|
9
|
+
import path from 'path'
|
|
10
|
+
import os from 'os'
|
|
11
|
+
import chalk from 'chalk'
|
|
12
|
+
|
|
13
|
+
interface UpdateCache {
|
|
14
|
+
lastCheck: number
|
|
15
|
+
latestVersion: string
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface UpdateResult {
|
|
19
|
+
updateAvailable: boolean
|
|
20
|
+
currentVersion: string
|
|
21
|
+
latestVersion: string
|
|
22
|
+
}
|
|
5
23
|
|
|
6
24
|
class UpdateChecker {
|
|
25
|
+
packageName: string
|
|
26
|
+
cacheDir: string
|
|
27
|
+
cacheFile: string
|
|
28
|
+
checkInterval: number
|
|
29
|
+
|
|
7
30
|
constructor() {
|
|
8
31
|
this.packageName = 'prjct-cli'
|
|
9
32
|
this.cacheDir = path.join(os.homedir(), '.prjct-cli', 'config')
|
|
@@ -14,13 +37,13 @@ class UpdateChecker {
|
|
|
14
37
|
/**
|
|
15
38
|
* Get current installed version from package.json
|
|
16
39
|
*/
|
|
17
|
-
getCurrentVersion() {
|
|
40
|
+
getCurrentVersion(): string | null {
|
|
18
41
|
try {
|
|
19
42
|
const packageJsonPath = path.join(__dirname, '..', '..', 'package.json')
|
|
20
43
|
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'))
|
|
21
44
|
return packageJson.version
|
|
22
45
|
} catch (error) {
|
|
23
|
-
console.error('Error reading package version:', error.message)
|
|
46
|
+
console.error('Error reading package version:', (error as Error).message)
|
|
24
47
|
return null
|
|
25
48
|
}
|
|
26
49
|
}
|
|
@@ -28,7 +51,7 @@ class UpdateChecker {
|
|
|
28
51
|
/**
|
|
29
52
|
* Fetch latest version from npm registry
|
|
30
53
|
*/
|
|
31
|
-
async getLatestVersion() {
|
|
54
|
+
async getLatestVersion(): Promise<string> {
|
|
32
55
|
return new Promise((resolve, reject) => {
|
|
33
56
|
const options = {
|
|
34
57
|
hostname: 'registry.npmjs.org',
|
|
@@ -78,7 +101,7 @@ class UpdateChecker {
|
|
|
78
101
|
* Compare two semantic versions
|
|
79
102
|
* Returns: 1 if v1 > v2, -1 if v1 < v2, 0 if equal
|
|
80
103
|
*/
|
|
81
|
-
compareVersions(v1, v2) {
|
|
104
|
+
compareVersions(v1: string, v2: string): number {
|
|
82
105
|
const parts1 = v1.split('.').map(Number)
|
|
83
106
|
const parts2 = v2.split('.').map(Number)
|
|
84
107
|
|
|
@@ -96,13 +119,13 @@ class UpdateChecker {
|
|
|
96
119
|
/**
|
|
97
120
|
* Read cache file
|
|
98
121
|
*/
|
|
99
|
-
readCache() {
|
|
122
|
+
readCache(): UpdateCache | null {
|
|
100
123
|
try {
|
|
101
124
|
if (fs.existsSync(this.cacheFile)) {
|
|
102
125
|
const cache = JSON.parse(fs.readFileSync(this.cacheFile, 'utf8'))
|
|
103
126
|
return cache
|
|
104
127
|
}
|
|
105
|
-
} catch
|
|
128
|
+
} catch {
|
|
106
129
|
// Cache file doesn't exist or is corrupted, ignore
|
|
107
130
|
}
|
|
108
131
|
return null
|
|
@@ -111,7 +134,7 @@ class UpdateChecker {
|
|
|
111
134
|
/**
|
|
112
135
|
* Write cache file
|
|
113
136
|
*/
|
|
114
|
-
writeCache(data) {
|
|
137
|
+
writeCache(data: UpdateCache): void {
|
|
115
138
|
try {
|
|
116
139
|
// Ensure cache directory exists
|
|
117
140
|
if (!fs.existsSync(this.cacheDir)) {
|
|
@@ -119,7 +142,7 @@ class UpdateChecker {
|
|
|
119
142
|
}
|
|
120
143
|
|
|
121
144
|
fs.writeFileSync(this.cacheFile, JSON.stringify(data, null, 2), 'utf8')
|
|
122
|
-
} catch
|
|
145
|
+
} catch {
|
|
123
146
|
// Fail silently - cache is not critical
|
|
124
147
|
}
|
|
125
148
|
}
|
|
@@ -128,7 +151,7 @@ class UpdateChecker {
|
|
|
128
151
|
* Check if update is available (respects 24-hour cache)
|
|
129
152
|
* Returns: { updateAvailable: boolean, currentVersion: string, latestVersion: string } or null
|
|
130
153
|
*/
|
|
131
|
-
async checkForUpdates() {
|
|
154
|
+
async checkForUpdates(): Promise<UpdateResult | null> {
|
|
132
155
|
try {
|
|
133
156
|
const currentVersion = this.getCurrentVersion()
|
|
134
157
|
if (!currentVersion) {
|
|
@@ -172,7 +195,7 @@ class UpdateChecker {
|
|
|
172
195
|
currentVersion,
|
|
173
196
|
latestVersion,
|
|
174
197
|
}
|
|
175
|
-
} catch
|
|
198
|
+
} catch {
|
|
176
199
|
// Network error or other issue - fail silently
|
|
177
200
|
// Return null to indicate check couldn't be performed
|
|
178
201
|
return null
|
|
@@ -182,15 +205,13 @@ class UpdateChecker {
|
|
|
182
205
|
/**
|
|
183
206
|
* Get formatted update notification message
|
|
184
207
|
*/
|
|
185
|
-
async getUpdateNotification() {
|
|
208
|
+
async getUpdateNotification(): Promise<string | null> {
|
|
186
209
|
const result = await this.checkForUpdates()
|
|
187
210
|
|
|
188
211
|
if (!result || !result.updateAvailable) {
|
|
189
212
|
return null
|
|
190
213
|
}
|
|
191
214
|
|
|
192
|
-
const chalk = require('chalk')
|
|
193
|
-
|
|
194
215
|
return (
|
|
195
216
|
'\n' +
|
|
196
217
|
chalk.yellow('┌───────────────────────────────────────────────────────────┐') +
|
|
@@ -219,4 +240,5 @@ class UpdateChecker {
|
|
|
219
240
|
}
|
|
220
241
|
}
|
|
221
242
|
|
|
222
|
-
|
|
243
|
+
export default UpdateChecker
|
|
244
|
+
export { UpdateChecker }
|