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,184 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tool Registry
|
|
3
|
-
* Maps allowed-tools from templates to actual functions
|
|
4
|
-
* Simple I/O operations - NO business logic, NO if/else
|
|
5
|
-
*
|
|
6
|
-
* P3.2: Added parallelization hints for multi-tool execution
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
const fs = require('fs').promises
|
|
10
|
-
const path = require('path')
|
|
11
|
-
const { promisify } = require('util')
|
|
12
|
-
const { exec: execCallback } = require('child_process')
|
|
13
|
-
const exec = promisify(execCallback)
|
|
14
|
-
const dateHelper = require('../utils/date-helper')
|
|
15
|
-
|
|
16
|
-
class ToolRegistry {
|
|
17
|
-
constructor() {
|
|
18
|
-
this.tools = {
|
|
19
|
-
Read: this.read.bind(this),
|
|
20
|
-
Write: this.write.bind(this),
|
|
21
|
-
Bash: this.bash.bind(this),
|
|
22
|
-
Exec: this.bash.bind(this), // Alias
|
|
23
|
-
GetTimestamp: this.getTimestamp.bind(this),
|
|
24
|
-
GetDate: this.getDate.bind(this),
|
|
25
|
-
GetDateTime: this.getDateTime.bind(this),
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// P3.2: Parallelization hints
|
|
29
|
-
// Used by parallel-tools.js to optimize execution
|
|
30
|
-
this.parallelHints = {
|
|
31
|
-
Read: { parallel: true, category: 'read' },
|
|
32
|
-
Write: { parallel: false, category: 'write' },
|
|
33
|
-
Bash: { parallel: false, category: 'execute' },
|
|
34
|
-
Exec: { parallel: false, category: 'execute' },
|
|
35
|
-
GetTimestamp: { parallel: true, category: 'read' },
|
|
36
|
-
GetDate: { parallel: true, category: 'read' },
|
|
37
|
-
GetDateTime: { parallel: true, category: 'read' },
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* P3.2: Check if tool can be parallelized
|
|
43
|
-
* @param {string} toolName
|
|
44
|
-
* @returns {boolean}
|
|
45
|
-
*/
|
|
46
|
-
canParallelize(toolName) {
|
|
47
|
-
return this.parallelHints[toolName]?.parallel ?? false
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* P3.2: Get tool category (read/write/execute)
|
|
52
|
-
* @param {string} toolName
|
|
53
|
-
* @returns {string}
|
|
54
|
-
*/
|
|
55
|
-
getCategory(toolName) {
|
|
56
|
-
return this.parallelHints[toolName]?.category ?? 'unknown'
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Get tool function by name
|
|
61
|
-
* @param {string} toolName - Tool name (e.g., 'Read', 'Write')
|
|
62
|
-
* @returns {Function}
|
|
63
|
-
*/
|
|
64
|
-
get(toolName) {
|
|
65
|
-
const tool = this.tools[toolName]
|
|
66
|
-
if (!tool) {
|
|
67
|
-
throw new Error(`Unknown tool: ${toolName}`)
|
|
68
|
-
}
|
|
69
|
-
return tool
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Check if tool is allowed
|
|
74
|
-
* @param {string} toolName - Tool name
|
|
75
|
-
* @param {string[]} allowedTools - List of allowed tools
|
|
76
|
-
* @returns {boolean}
|
|
77
|
-
*/
|
|
78
|
-
isAllowed(toolName, allowedTools) {
|
|
79
|
-
return allowedTools.includes(toolName)
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Read file
|
|
84
|
-
* @param {string} filePath - File path
|
|
85
|
-
* @returns {Promise<string>}
|
|
86
|
-
*/
|
|
87
|
-
async read(filePath) {
|
|
88
|
-
try {
|
|
89
|
-
return await fs.readFile(filePath, 'utf-8')
|
|
90
|
-
} catch (error) {
|
|
91
|
-
return null
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Write file
|
|
97
|
-
* @param {string} filePath - File path
|
|
98
|
-
* @param {string} content - Content to write
|
|
99
|
-
* @returns {Promise<void>}
|
|
100
|
-
*/
|
|
101
|
-
async write(filePath, content) {
|
|
102
|
-
// Ensure directory exists
|
|
103
|
-
await fs.mkdir(path.dirname(filePath), { recursive: true })
|
|
104
|
-
await fs.writeFile(filePath, content, 'utf-8')
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* Execute bash command
|
|
109
|
-
* @param {string} command - Command to execute
|
|
110
|
-
* @returns {Promise<{stdout: string, stderr: string}>}
|
|
111
|
-
*/
|
|
112
|
-
async bash(command) {
|
|
113
|
-
try {
|
|
114
|
-
const { stdout, stderr } = await exec(command)
|
|
115
|
-
return { stdout, stderr }
|
|
116
|
-
} catch (error) {
|
|
117
|
-
return {
|
|
118
|
-
stdout: '',
|
|
119
|
-
stderr: error.message,
|
|
120
|
-
error: true,
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* Check if file exists
|
|
127
|
-
* @param {string} filePath - File path
|
|
128
|
-
* @returns {Promise<boolean>}
|
|
129
|
-
*/
|
|
130
|
-
async exists(filePath) {
|
|
131
|
-
try {
|
|
132
|
-
await fs.access(filePath)
|
|
133
|
-
return true
|
|
134
|
-
} catch {
|
|
135
|
-
return false
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* List directory
|
|
141
|
-
* @param {string} dirPath - Directory path
|
|
142
|
-
* @returns {Promise<string[]>}
|
|
143
|
-
*/
|
|
144
|
-
async list(dirPath) {
|
|
145
|
-
try {
|
|
146
|
-
return await fs.readdir(dirPath)
|
|
147
|
-
} catch {
|
|
148
|
-
return []
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* Get current system timestamp (ISO format)
|
|
154
|
-
* LLM MUST use this instead of generating timestamps
|
|
155
|
-
* @returns {Promise<string>} ISO timestamp (e.g., "2025-10-07T14:30:00.000Z")
|
|
156
|
-
*/
|
|
157
|
-
async getTimestamp() {
|
|
158
|
-
return dateHelper.getTimestamp()
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* Get current system date (YYYY-MM-DD)
|
|
163
|
-
* LLM MUST use this instead of generating dates
|
|
164
|
-
* @returns {Promise<string>} Date string (e.g., "2025-10-07")
|
|
165
|
-
*/
|
|
166
|
-
async getDate() {
|
|
167
|
-
return dateHelper.getTodayKey()
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
/**
|
|
171
|
-
* Get current system date/time components
|
|
172
|
-
* @returns {Promise<Object>} Date components {timestamp, date, year, month, day}
|
|
173
|
-
*/
|
|
174
|
-
async getDateTime() {
|
|
175
|
-
const now = new Date()
|
|
176
|
-
return {
|
|
177
|
-
timestamp: dateHelper.getTimestamp(),
|
|
178
|
-
date: dateHelper.getTodayKey(),
|
|
179
|
-
...dateHelper.getYearMonthDay(now),
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
module.exports = new ToolRegistry()
|
|
@@ -1,380 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Validation Rules
|
|
3
|
-
* Explicit pre-flight checks for each command
|
|
4
|
-
* Returns SPECIFIC error messages, never generic failures
|
|
5
|
-
*
|
|
6
|
-
* OPTIMIZATION (P0.2): Anti-Hallucination Pattern
|
|
7
|
-
* - Ground truth verification before actions
|
|
8
|
-
* - Specific error messages for each failure mode
|
|
9
|
-
* - Actionable suggestions in every error
|
|
10
|
-
*
|
|
11
|
-
* Source: Claude Code, Devin, Augment Code patterns
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
const contextBuilder = require('./context-builder')
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Validation result structure
|
|
18
|
-
* @typedef {Object} ValidationResult
|
|
19
|
-
* @property {boolean} valid - Whether validation passed
|
|
20
|
-
* @property {string|null} error - Specific error message if invalid
|
|
21
|
-
* @property {string|null} suggestion - Actionable next step
|
|
22
|
-
* @property {Object} state - Pre-loaded state for command execution
|
|
23
|
-
*/
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Command-specific validation rules
|
|
27
|
-
* Each rule returns { valid, error, suggestion, state }
|
|
28
|
-
*/
|
|
29
|
-
const validationRules = {
|
|
30
|
-
/**
|
|
31
|
-
* /p:done - Complete current task
|
|
32
|
-
*/
|
|
33
|
-
async done(context) {
|
|
34
|
-
const state = await contextBuilder.loadStateForCommand(context, 'done')
|
|
35
|
-
|
|
36
|
-
// Check 1: now.md exists and has content
|
|
37
|
-
if (!state.now || state.now.trim() === '') {
|
|
38
|
-
return {
|
|
39
|
-
valid: false,
|
|
40
|
-
error: 'No active task to complete',
|
|
41
|
-
suggestion: 'Start a task first with /p:now "task description"',
|
|
42
|
-
state
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// Check 2: Task is not a placeholder/comment
|
|
47
|
-
const content = state.now.trim()
|
|
48
|
-
if (content.startsWith('#') && content.split('\n').length === 1) {
|
|
49
|
-
return {
|
|
50
|
-
valid: false,
|
|
51
|
-
error: 'now.md contains only a header, no task description',
|
|
52
|
-
suggestion: 'Add task details or start fresh with /p:now "task"',
|
|
53
|
-
state
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// Check 3: Task is not blocked
|
|
58
|
-
if (content.toLowerCase().includes('blocked') ||
|
|
59
|
-
content.toLowerCase().includes('waiting for')) {
|
|
60
|
-
return {
|
|
61
|
-
valid: false,
|
|
62
|
-
error: 'Task appears to be blocked',
|
|
63
|
-
suggestion: 'Resolve the blocker first or use /p:pause to save progress',
|
|
64
|
-
state
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
return { valid: true, error: null, suggestion: null, state }
|
|
69
|
-
},
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* /p:ship - Ship a feature
|
|
73
|
-
*/
|
|
74
|
-
async ship(context) {
|
|
75
|
-
const state = await contextBuilder.loadStateForCommand(context, 'ship')
|
|
76
|
-
|
|
77
|
-
// Check 1: Has something to ship (now.md or recent shipped items)
|
|
78
|
-
const hasCurrentTask = state.now && state.now.trim() !== ''
|
|
79
|
-
const hasRecentShips = state.shipped && state.shipped.trim() !== ''
|
|
80
|
-
|
|
81
|
-
if (!hasCurrentTask && !hasRecentShips) {
|
|
82
|
-
return {
|
|
83
|
-
valid: false,
|
|
84
|
-
error: 'Nothing to ship yet',
|
|
85
|
-
suggestion: 'Build something first with /p:now "feature name"',
|
|
86
|
-
state
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// Check 2: Feature name provided (from params)
|
|
91
|
-
if (!context.params.feature && !context.params.description) {
|
|
92
|
-
// Try to extract from now.md
|
|
93
|
-
if (hasCurrentTask) {
|
|
94
|
-
// Auto-extract feature name - this is OK
|
|
95
|
-
return { valid: true, error: null, suggestion: null, state }
|
|
96
|
-
}
|
|
97
|
-
return {
|
|
98
|
-
valid: false,
|
|
99
|
-
error: 'No feature name specified',
|
|
100
|
-
suggestion: 'Specify what to ship: /p:ship "feature name"',
|
|
101
|
-
state
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
return { valid: true, error: null, suggestion: null, state }
|
|
106
|
-
},
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* /p:now - Set or show current task
|
|
110
|
-
*/
|
|
111
|
-
async now(context) {
|
|
112
|
-
const state = await contextBuilder.loadStateForCommand(context, 'now')
|
|
113
|
-
|
|
114
|
-
// If no task param, this is a "show" request - always valid
|
|
115
|
-
if (!context.params.task && !context.params.description) {
|
|
116
|
-
return { valid: true, error: null, suggestion: null, state }
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// Check: If setting new task, warn if one exists
|
|
120
|
-
if (state.now && state.now.trim() !== '') {
|
|
121
|
-
return {
|
|
122
|
-
valid: true, // Still valid, but with warning
|
|
123
|
-
error: null,
|
|
124
|
-
suggestion: `Note: Replacing current task. Use /p:done first to track completion.`,
|
|
125
|
-
state
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
return { valid: true, error: null, suggestion: null, state }
|
|
130
|
-
},
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* /p:next - Show priority queue
|
|
134
|
-
*/
|
|
135
|
-
async next(context) {
|
|
136
|
-
const state = await contextBuilder.loadStateForCommand(context, 'next')
|
|
137
|
-
|
|
138
|
-
if (!state.next || state.next.trim() === '' ||
|
|
139
|
-
!state.next.includes('- [')) {
|
|
140
|
-
return {
|
|
141
|
-
valid: true, // Valid but empty
|
|
142
|
-
error: null,
|
|
143
|
-
suggestion: 'Queue is empty. Add tasks with /p:feature or /p:idea',
|
|
144
|
-
state
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
return { valid: true, error: null, suggestion: null, state }
|
|
149
|
-
},
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* /p:idea - Capture an idea
|
|
153
|
-
*/
|
|
154
|
-
async idea(context) {
|
|
155
|
-
const state = await contextBuilder.loadStateForCommand(context, 'idea')
|
|
156
|
-
|
|
157
|
-
// Check: Idea text provided
|
|
158
|
-
if (!context.params.text && !context.params.description) {
|
|
159
|
-
return {
|
|
160
|
-
valid: false,
|
|
161
|
-
error: 'No idea text provided',
|
|
162
|
-
suggestion: 'Provide your idea: /p:idea "your idea here"',
|
|
163
|
-
state
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
return { valid: true, error: null, suggestion: null, state }
|
|
168
|
-
},
|
|
169
|
-
|
|
170
|
-
/**
|
|
171
|
-
* /p:feature - Add a new feature
|
|
172
|
-
*/
|
|
173
|
-
async feature(context) {
|
|
174
|
-
const state = await contextBuilder.loadStateForCommand(context, 'feature')
|
|
175
|
-
|
|
176
|
-
// If no description, show interactive template - valid
|
|
177
|
-
if (!context.params.description && !context.params.feature) {
|
|
178
|
-
return { valid: true, error: null, suggestion: null, state }
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
return { valid: true, error: null, suggestion: null, state }
|
|
182
|
-
},
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* /p:pause - Pause current task
|
|
186
|
-
*/
|
|
187
|
-
async pause(context) {
|
|
188
|
-
const state = await contextBuilder.loadStateForCommand(context, 'now')
|
|
189
|
-
|
|
190
|
-
if (!state.now || state.now.trim() === '') {
|
|
191
|
-
return {
|
|
192
|
-
valid: false,
|
|
193
|
-
error: 'No active task to pause',
|
|
194
|
-
suggestion: 'Start a task first with /p:now "task"',
|
|
195
|
-
state
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
return { valid: true, error: null, suggestion: null, state }
|
|
200
|
-
},
|
|
201
|
-
|
|
202
|
-
/**
|
|
203
|
-
* /p:resume - Resume paused task
|
|
204
|
-
*/
|
|
205
|
-
async resume(context) {
|
|
206
|
-
const state = await contextBuilder.loadState(context, ['now'])
|
|
207
|
-
|
|
208
|
-
// Check if there's a paused state to resume
|
|
209
|
-
// This would need to check a paused.md or similar
|
|
210
|
-
return { valid: true, error: null, suggestion: null, state }
|
|
211
|
-
},
|
|
212
|
-
|
|
213
|
-
/**
|
|
214
|
-
* /p:recap - Show project overview
|
|
215
|
-
*/
|
|
216
|
-
async recap(context) {
|
|
217
|
-
const state = await contextBuilder.loadStateForCommand(context, 'recap')
|
|
218
|
-
return { valid: true, error: null, suggestion: null, state }
|
|
219
|
-
},
|
|
220
|
-
|
|
221
|
-
/**
|
|
222
|
-
* /p:progress - Show progress metrics
|
|
223
|
-
*/
|
|
224
|
-
async progress(context) {
|
|
225
|
-
const state = await contextBuilder.loadStateForCommand(context, 'progress')
|
|
226
|
-
return { valid: true, error: null, suggestion: null, state }
|
|
227
|
-
},
|
|
228
|
-
|
|
229
|
-
/**
|
|
230
|
-
* /p:analyze - Analyze repository
|
|
231
|
-
*/
|
|
232
|
-
async analyze(context) {
|
|
233
|
-
const state = await contextBuilder.loadStateForCommand(context, 'analyze')
|
|
234
|
-
return { valid: true, error: null, suggestion: null, state }
|
|
235
|
-
},
|
|
236
|
-
|
|
237
|
-
/**
|
|
238
|
-
* /p:sync - Sync project state
|
|
239
|
-
*/
|
|
240
|
-
async sync(context) {
|
|
241
|
-
const state = await contextBuilder.loadStateForCommand(context, 'sync')
|
|
242
|
-
return { valid: true, error: null, suggestion: null, state }
|
|
243
|
-
},
|
|
244
|
-
|
|
245
|
-
/**
|
|
246
|
-
* /p:bug - Report a bug
|
|
247
|
-
*/
|
|
248
|
-
async bug(context) {
|
|
249
|
-
const state = await contextBuilder.loadState(context, ['next'])
|
|
250
|
-
|
|
251
|
-
if (!context.params.description && !context.params.bug) {
|
|
252
|
-
return {
|
|
253
|
-
valid: false,
|
|
254
|
-
error: 'No bug description provided',
|
|
255
|
-
suggestion: 'Describe the bug: /p:bug "description of the issue"',
|
|
256
|
-
state
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
return { valid: true, error: null, suggestion: null, state }
|
|
261
|
-
},
|
|
262
|
-
|
|
263
|
-
/**
|
|
264
|
-
* /p:help - Show help
|
|
265
|
-
*/
|
|
266
|
-
async help(context) {
|
|
267
|
-
const state = await contextBuilder.loadStateForCommand(context, 'now')
|
|
268
|
-
return { valid: true, error: null, suggestion: null, state }
|
|
269
|
-
},
|
|
270
|
-
|
|
271
|
-
/**
|
|
272
|
-
* /p:ask - Intent translator
|
|
273
|
-
*/
|
|
274
|
-
async ask(context) {
|
|
275
|
-
if (!context.params.query && !context.params.question) {
|
|
276
|
-
return {
|
|
277
|
-
valid: false,
|
|
278
|
-
error: 'No question provided',
|
|
279
|
-
suggestion: 'Ask what you want to do: /p:ask "how do I..."',
|
|
280
|
-
state: {}
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
return { valid: true, error: null, suggestion: null, state: {} }
|
|
285
|
-
},
|
|
286
|
-
|
|
287
|
-
/**
|
|
288
|
-
* /p:suggest - Smart suggestions
|
|
289
|
-
*/
|
|
290
|
-
async suggest(context) {
|
|
291
|
-
const state = await contextBuilder.loadState(context, ['now', 'next', 'shipped', 'metrics'])
|
|
292
|
-
return { valid: true, error: null, suggestion: null, state }
|
|
293
|
-
},
|
|
294
|
-
|
|
295
|
-
/**
|
|
296
|
-
* /p:spec - Spec-driven development
|
|
297
|
-
*/
|
|
298
|
-
async spec(context) {
|
|
299
|
-
const state = await contextBuilder.loadState(context, ['roadmap', 'next'])
|
|
300
|
-
|
|
301
|
-
// If no feature name, this is a "show template" request - always valid
|
|
302
|
-
if (!context.params.feature && !context.params.name && !context.params.description) {
|
|
303
|
-
return {
|
|
304
|
-
valid: true,
|
|
305
|
-
error: null,
|
|
306
|
-
suggestion: 'Provide a feature name to create a spec',
|
|
307
|
-
state
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
// Check queue capacity for new tasks
|
|
312
|
-
const queueContent = state.next || ''
|
|
313
|
-
const taskCount = (queueContent.match(/- \[[ x]\]/g) || []).length
|
|
314
|
-
if (taskCount >= 95) {
|
|
315
|
-
return {
|
|
316
|
-
valid: false,
|
|
317
|
-
error: 'Queue almost full (95+ tasks)',
|
|
318
|
-
suggestion: 'Complete some tasks before creating a new spec. Use /p:done',
|
|
319
|
-
state
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
return { valid: true, error: null, suggestion: null, state }
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
/**
|
|
328
|
-
* Validate command before execution
|
|
329
|
-
*
|
|
330
|
-
* @param {string} commandName - Command to validate
|
|
331
|
-
* @param {Object} context - Built context from contextBuilder
|
|
332
|
-
* @returns {Promise<ValidationResult>}
|
|
333
|
-
*/
|
|
334
|
-
async function validate(commandName, context) {
|
|
335
|
-
const validator = validationRules[commandName]
|
|
336
|
-
|
|
337
|
-
if (!validator) {
|
|
338
|
-
// No specific validation - default to valid
|
|
339
|
-
return {
|
|
340
|
-
valid: true,
|
|
341
|
-
error: null,
|
|
342
|
-
suggestion: null,
|
|
343
|
-
state: await contextBuilder.loadState(context)
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
try {
|
|
348
|
-
return await validator(context)
|
|
349
|
-
} catch (error) {
|
|
350
|
-
return {
|
|
351
|
-
valid: false,
|
|
352
|
-
error: `Validation error: ${error.message}`,
|
|
353
|
-
suggestion: 'Check file permissions and project configuration',
|
|
354
|
-
state: {}
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
/**
|
|
360
|
-
* Format validation error for display
|
|
361
|
-
* Minimal, actionable output
|
|
362
|
-
*
|
|
363
|
-
* @param {ValidationResult} result - Validation result
|
|
364
|
-
* @returns {string} Formatted error message
|
|
365
|
-
*/
|
|
366
|
-
function formatError(result) {
|
|
367
|
-
if (result.valid) return null
|
|
368
|
-
|
|
369
|
-
let output = `❌ ${result.error}`
|
|
370
|
-
if (result.suggestion) {
|
|
371
|
-
output += `\n→ ${result.suggestion}`
|
|
372
|
-
}
|
|
373
|
-
return output
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
module.exports = {
|
|
377
|
-
validate,
|
|
378
|
-
formatError,
|
|
379
|
-
validationRules
|
|
380
|
-
}
|