prjct-cli 0.11.5 → 0.12.1
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 +190 -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 +600 -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 +58 -8
- 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,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ground Truth Verification
|
|
3
|
+
* Verifies actual state before critical operations
|
|
4
|
+
*
|
|
5
|
+
* OPTIMIZATION (P1.3): Anti-Hallucination Pattern
|
|
6
|
+
* - Reads actual files before assuming state
|
|
7
|
+
* - Compares expected vs actual state
|
|
8
|
+
* - Provides specific warnings for mismatches
|
|
9
|
+
* - Logs verification results for debugging
|
|
10
|
+
*
|
|
11
|
+
* Source: Devin, Cursor, Augment Code patterns
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import type { Context, VerificationResult } from './types'
|
|
15
|
+
import { verifiers } from './verifiers'
|
|
16
|
+
import { formatWarnings } from './utils'
|
|
17
|
+
|
|
18
|
+
export type { Context, VerificationResult, Verifier } from './types'
|
|
19
|
+
export { verifiers } from './verifiers'
|
|
20
|
+
export { formatDuration, escapeRegex, formatWarnings } from './utils'
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Verify ground truth before command execution
|
|
24
|
+
*/
|
|
25
|
+
async function verify(commandName: string, context: Context, state: unknown): Promise<VerificationResult> {
|
|
26
|
+
const verifier = verifiers[commandName]
|
|
27
|
+
|
|
28
|
+
if (!verifier) {
|
|
29
|
+
// No specific verification needed
|
|
30
|
+
return {
|
|
31
|
+
verified: true,
|
|
32
|
+
actual: {},
|
|
33
|
+
warnings: [],
|
|
34
|
+
recommendations: [],
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
try {
|
|
39
|
+
return await verifier(context, state)
|
|
40
|
+
} catch (error) {
|
|
41
|
+
return {
|
|
42
|
+
verified: false,
|
|
43
|
+
actual: {},
|
|
44
|
+
warnings: [`Verification error: ${(error as Error).message}`],
|
|
45
|
+
recommendations: ['Check file permissions and project configuration'],
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Prepare command by verifying ground truth
|
|
52
|
+
* Returns enhanced context with verification results
|
|
53
|
+
*/
|
|
54
|
+
async function prepareCommand(commandName: string, context: Context, state: unknown) {
|
|
55
|
+
const verification = await verify(commandName, context, state)
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
...context,
|
|
59
|
+
groundTruth: {
|
|
60
|
+
...verification,
|
|
61
|
+
verifiedAt: new Date().toISOString(),
|
|
62
|
+
command: commandName,
|
|
63
|
+
},
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Check if command requires ground truth verification
|
|
69
|
+
*/
|
|
70
|
+
function requiresVerification(commandName: string): boolean {
|
|
71
|
+
// ANTI-HALLUCINATION: Expanded verification for more commands
|
|
72
|
+
return ['done', 'ship', 'feature', 'spec', 'now', 'init', 'sync', 'analyze'].includes(commandName)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export { verify, prepareCommand, requiresVerification }
|
|
76
|
+
export default { verify, prepareCommand, requiresVerification, formatWarnings, verifiers }
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ground Truth Types
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export interface Context {
|
|
6
|
+
projectPath: string
|
|
7
|
+
projectId?: string | null
|
|
8
|
+
paths: {
|
|
9
|
+
now: string
|
|
10
|
+
next: string
|
|
11
|
+
metrics: string
|
|
12
|
+
shipped: string
|
|
13
|
+
roadmap: string
|
|
14
|
+
specs: string
|
|
15
|
+
[key: string]: string
|
|
16
|
+
}
|
|
17
|
+
params: {
|
|
18
|
+
feature?: string
|
|
19
|
+
description?: string
|
|
20
|
+
task?: string
|
|
21
|
+
name?: string
|
|
22
|
+
[key: string]: unknown
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface VerificationResult {
|
|
27
|
+
verified: boolean
|
|
28
|
+
actual: Record<string, unknown>
|
|
29
|
+
warnings: string[]
|
|
30
|
+
recommendations: string[]
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export type Verifier = (context: Context, state: unknown) => Promise<VerificationResult>
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ground Truth Utilities
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { VerificationResult } from './types'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Format duration from milliseconds to human-readable string
|
|
9
|
+
*/
|
|
10
|
+
export function formatDuration(ms: number): string {
|
|
11
|
+
const hours = Math.floor(ms / (1000 * 60 * 60))
|
|
12
|
+
const minutes = Math.floor((ms % (1000 * 60 * 60)) / (1000 * 60))
|
|
13
|
+
|
|
14
|
+
if (hours > 0) {
|
|
15
|
+
return `${hours}h ${minutes}m`
|
|
16
|
+
}
|
|
17
|
+
return `${minutes}m`
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Escape special regex characters in a string
|
|
22
|
+
*/
|
|
23
|
+
export function escapeRegex(string: string): string {
|
|
24
|
+
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Format verification warnings for display
|
|
29
|
+
*/
|
|
30
|
+
export function formatWarnings(result: VerificationResult): string | null {
|
|
31
|
+
if (result.verified || result.warnings.length === 0) {
|
|
32
|
+
return null
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
let output = '⚠️ Ground Truth Warnings:\n'
|
|
36
|
+
result.warnings.forEach((w) => {
|
|
37
|
+
output += ` • ${w}\n`
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
if (result.recommendations.length > 0) {
|
|
41
|
+
output += '\nRecommendations:\n'
|
|
42
|
+
result.recommendations.forEach((r) => {
|
|
43
|
+
output += ` → ${r}\n`
|
|
44
|
+
})
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return output
|
|
48
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Analyze Command Verifier
|
|
3
|
+
* Verify analysis can proceed
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import fs from 'fs/promises'
|
|
7
|
+
import path from 'path'
|
|
8
|
+
import type { Context, VerificationResult } from '../types'
|
|
9
|
+
|
|
10
|
+
export async function verifyAnalyze(context: Context): Promise<VerificationResult> {
|
|
11
|
+
const warnings: string[] = []
|
|
12
|
+
const recommendations: string[] = []
|
|
13
|
+
const actual: Record<string, unknown> = {}
|
|
14
|
+
|
|
15
|
+
// 1. Check if project has recognizable structure
|
|
16
|
+
const files = ['package.json', 'Cargo.toml', 'go.mod', 'requirements.txt', 'Gemfile', 'pom.xml']
|
|
17
|
+
actual.detectedFiles = []
|
|
18
|
+
|
|
19
|
+
for (const file of files) {
|
|
20
|
+
try {
|
|
21
|
+
await fs.access(path.join(context.projectPath, file))
|
|
22
|
+
;(actual.detectedFiles as string[]).push(file)
|
|
23
|
+
} catch {
|
|
24
|
+
// File doesn't exist
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if ((actual.detectedFiles as string[]).length === 0) {
|
|
29
|
+
warnings.push('No recognizable project files detected')
|
|
30
|
+
recommendations.push('Analysis may be limited without package.json or similar')
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// 2. Check for source directories
|
|
34
|
+
const srcDirs = ['src', 'lib', 'app', 'core', 'components']
|
|
35
|
+
actual.detectedSrcDirs = []
|
|
36
|
+
|
|
37
|
+
for (const dir of srcDirs) {
|
|
38
|
+
try {
|
|
39
|
+
const stat = await fs.stat(path.join(context.projectPath, dir))
|
|
40
|
+
if (stat.isDirectory()) {
|
|
41
|
+
;(actual.detectedSrcDirs as string[]).push(dir)
|
|
42
|
+
}
|
|
43
|
+
} catch {
|
|
44
|
+
// Directory doesn't exist
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
verified: true, // Analysis can always proceed, even with warnings
|
|
50
|
+
actual,
|
|
51
|
+
warnings,
|
|
52
|
+
recommendations,
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Done Command Verifier
|
|
3
|
+
* Verify task is actually complete-able
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import fs from 'fs/promises'
|
|
7
|
+
import path from 'path'
|
|
8
|
+
import type { Context, VerificationResult } from '../types'
|
|
9
|
+
import { formatDuration } from '../utils'
|
|
10
|
+
|
|
11
|
+
export async function verifyDone(context: Context): Promise<VerificationResult> {
|
|
12
|
+
const warnings: string[] = []
|
|
13
|
+
const recommendations: string[] = []
|
|
14
|
+
const actual: Record<string, unknown> = {}
|
|
15
|
+
|
|
16
|
+
// 1. Verify now.md exists and has real content
|
|
17
|
+
const nowPath = context.paths.now
|
|
18
|
+
try {
|
|
19
|
+
const nowContent = await fs.readFile(nowPath, 'utf-8')
|
|
20
|
+
actual.nowExists = true
|
|
21
|
+
actual.nowContent = nowContent.trim()
|
|
22
|
+
actual.nowLength = nowContent.length
|
|
23
|
+
|
|
24
|
+
// Check for placeholder content
|
|
25
|
+
if (nowContent.includes('No current task') || nowContent.match(/^#\s*NOW\s*$/m)) {
|
|
26
|
+
warnings.push('now.md appears to be empty or placeholder')
|
|
27
|
+
recommendations.push('Start a task first with /p:now "task"')
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Check for task metadata (started time)
|
|
31
|
+
const startedMatch = nowContent.match(/Started:\s*(.+)/i)
|
|
32
|
+
if (startedMatch) {
|
|
33
|
+
actual.startedAt = startedMatch[1]
|
|
34
|
+
// Calculate duration
|
|
35
|
+
const startTime = new Date(startedMatch[1])
|
|
36
|
+
if (!isNaN(startTime.getTime())) {
|
|
37
|
+
actual.durationMs = Date.now() - startTime.getTime()
|
|
38
|
+
actual.durationFormatted = formatDuration(actual.durationMs as number)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
} catch {
|
|
42
|
+
actual.nowExists = false
|
|
43
|
+
warnings.push('now.md does not exist')
|
|
44
|
+
recommendations.push('Create a task with /p:now "task"')
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// 2. Verify next.md for auto-start
|
|
48
|
+
const nextPath = context.paths.next
|
|
49
|
+
try {
|
|
50
|
+
const nextContent = await fs.readFile(nextPath, 'utf-8')
|
|
51
|
+
actual.nextExists = true
|
|
52
|
+
const tasks = nextContent.match(/- \[ \]/g) || []
|
|
53
|
+
actual.pendingTasks = tasks.length
|
|
54
|
+
} catch {
|
|
55
|
+
actual.nextExists = false
|
|
56
|
+
actual.pendingTasks = 0
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// 3. Verify metrics.md is writable
|
|
60
|
+
const metricsPath = context.paths.metrics
|
|
61
|
+
try {
|
|
62
|
+
await fs.access(path.dirname(metricsPath), fs.constants.W_OK)
|
|
63
|
+
actual.metricsWritable = true
|
|
64
|
+
} catch {
|
|
65
|
+
actual.metricsWritable = false
|
|
66
|
+
warnings.push('Cannot write to metrics directory')
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return {
|
|
70
|
+
verified: warnings.length === 0,
|
|
71
|
+
actual,
|
|
72
|
+
warnings,
|
|
73
|
+
recommendations,
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Feature Command Verifier
|
|
3
|
+
* Verify feature can be added
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import fs from 'fs/promises'
|
|
7
|
+
import type { Context, VerificationResult } from '../types'
|
|
8
|
+
import { escapeRegex } from '../utils'
|
|
9
|
+
|
|
10
|
+
export async function verifyFeature(context: Context): Promise<VerificationResult> {
|
|
11
|
+
const warnings: string[] = []
|
|
12
|
+
const recommendations: string[] = []
|
|
13
|
+
const actual: Record<string, unknown> = {}
|
|
14
|
+
|
|
15
|
+
// 1. Check next.md capacity
|
|
16
|
+
const nextPath = context.paths.next
|
|
17
|
+
try {
|
|
18
|
+
const nextContent = await fs.readFile(nextPath, 'utf-8')
|
|
19
|
+
actual.nextExists = true
|
|
20
|
+
const tasks = nextContent.match(/- \[[ x]\]/g) || []
|
|
21
|
+
actual.taskCount = tasks.length
|
|
22
|
+
actual.pendingTasks = (nextContent.match(/- \[ \]/g) || []).length
|
|
23
|
+
|
|
24
|
+
if ((actual.taskCount as number) >= 90) {
|
|
25
|
+
warnings.push(`Queue nearly full (${actual.taskCount}/100 tasks)`)
|
|
26
|
+
recommendations.push('Complete some tasks before adding more')
|
|
27
|
+
}
|
|
28
|
+
} catch {
|
|
29
|
+
actual.nextExists = false
|
|
30
|
+
actual.taskCount = 0
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// 2. Check roadmap.md for duplicate features
|
|
34
|
+
const roadmapPath = context.paths.roadmap
|
|
35
|
+
try {
|
|
36
|
+
const roadmapContent = await fs.readFile(roadmapPath, 'utf-8')
|
|
37
|
+
actual.roadmapExists = true
|
|
38
|
+
|
|
39
|
+
const featureName = context.params.description || context.params.feature
|
|
40
|
+
if (featureName) {
|
|
41
|
+
const featurePattern = new RegExp(escapeRegex(featureName), 'i')
|
|
42
|
+
if (featurePattern.test(roadmapContent)) {
|
|
43
|
+
warnings.push(`Feature "${featureName}" may already exist in roadmap`)
|
|
44
|
+
recommendations.push('Check roadmap for duplicates with /p:roadmap')
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
} catch {
|
|
48
|
+
actual.roadmapExists = false
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// 3. Check if there's an active task (should complete first?)
|
|
52
|
+
const nowPath = context.paths.now
|
|
53
|
+
try {
|
|
54
|
+
const nowContent = await fs.readFile(nowPath, 'utf-8')
|
|
55
|
+
actual.hasActiveTask = nowContent.trim().length > 0 && !nowContent.includes('No current task')
|
|
56
|
+
|
|
57
|
+
if (actual.hasActiveTask) {
|
|
58
|
+
recommendations.push('Consider completing current task first with /p:done')
|
|
59
|
+
}
|
|
60
|
+
} catch {
|
|
61
|
+
actual.hasActiveTask = false
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
verified: warnings.length === 0,
|
|
66
|
+
actual,
|
|
67
|
+
warnings,
|
|
68
|
+
recommendations,
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ground Truth Verifiers Index
|
|
3
|
+
* Re-exports all command verifiers
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { Verifier } from '../types'
|
|
7
|
+
import { verifyDone } from './done'
|
|
8
|
+
import { verifyShip } from './ship'
|
|
9
|
+
import { verifyFeature } from './feature'
|
|
10
|
+
import { verifyNow } from './now'
|
|
11
|
+
import { verifyInit } from './init'
|
|
12
|
+
import { verifySync } from './sync'
|
|
13
|
+
import { verifyAnalyze } from './analyze'
|
|
14
|
+
import { verifySpec } from './spec'
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Command-specific ground truth verifiers
|
|
18
|
+
*/
|
|
19
|
+
export const verifiers: Record<string, Verifier> = {
|
|
20
|
+
done: verifyDone,
|
|
21
|
+
ship: verifyShip,
|
|
22
|
+
feature: verifyFeature,
|
|
23
|
+
now: verifyNow,
|
|
24
|
+
init: verifyInit,
|
|
25
|
+
sync: verifySync,
|
|
26
|
+
analyze: verifyAnalyze,
|
|
27
|
+
spec: verifySpec,
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export { verifyDone } from './done'
|
|
31
|
+
export { verifyShip } from './ship'
|
|
32
|
+
export { verifyFeature } from './feature'
|
|
33
|
+
export { verifyNow } from './now'
|
|
34
|
+
export { verifyInit } from './init'
|
|
35
|
+
export { verifySync } from './sync'
|
|
36
|
+
export { verifyAnalyze } from './analyze'
|
|
37
|
+
export { verifySpec } from './spec'
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Init Command Verifier
|
|
3
|
+
* Verify project can be initialized
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import fs from 'fs/promises'
|
|
7
|
+
import path from 'path'
|
|
8
|
+
import os from 'os'
|
|
9
|
+
import type { Context, VerificationResult } from '../types'
|
|
10
|
+
|
|
11
|
+
export async function verifyInit(context: Context): Promise<VerificationResult> {
|
|
12
|
+
const warnings: string[] = []
|
|
13
|
+
const recommendations: string[] = []
|
|
14
|
+
const actual: Record<string, unknown> = {}
|
|
15
|
+
|
|
16
|
+
// 1. Check if already initialized
|
|
17
|
+
const configPath = path.join(context.projectPath, '.prjct/prjct.config.json')
|
|
18
|
+
try {
|
|
19
|
+
const configContent = await fs.readFile(configPath, 'utf-8')
|
|
20
|
+
actual.alreadyInitialized = true
|
|
21
|
+
actual.existingConfig = JSON.parse(configContent)
|
|
22
|
+
warnings.push('Project already initialized')
|
|
23
|
+
recommendations.push('Use /p:analyze to refresh analysis or delete .prjct/ to reinitialize')
|
|
24
|
+
} catch {
|
|
25
|
+
actual.alreadyInitialized = false
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// 2. Check if global storage path is writable
|
|
29
|
+
const globalPath = path.join(os.homedir(), '.prjct-cli')
|
|
30
|
+
try {
|
|
31
|
+
await fs.access(globalPath, fs.constants.W_OK)
|
|
32
|
+
actual.globalPathWritable = true
|
|
33
|
+
} catch {
|
|
34
|
+
try {
|
|
35
|
+
// Try to create it
|
|
36
|
+
await fs.mkdir(globalPath, { recursive: true })
|
|
37
|
+
actual.globalPathWritable = true
|
|
38
|
+
actual.globalPathCreated = true
|
|
39
|
+
} catch {
|
|
40
|
+
actual.globalPathWritable = false
|
|
41
|
+
warnings.push('Cannot write to ~/.prjct-cli')
|
|
42
|
+
recommendations.push('Check directory permissions')
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
verified: warnings.length === 0,
|
|
48
|
+
actual,
|
|
49
|
+
warnings,
|
|
50
|
+
recommendations,
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Now Command Verifier
|
|
3
|
+
* Verify task can be set (anti-hallucination: warn if replacing)
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import fs from 'fs/promises'
|
|
7
|
+
import type { Context, VerificationResult } from '../types'
|
|
8
|
+
|
|
9
|
+
export async function verifyNow(context: Context): Promise<VerificationResult> {
|
|
10
|
+
const warnings: string[] = []
|
|
11
|
+
const recommendations: string[] = []
|
|
12
|
+
const actual: Record<string, unknown> = {}
|
|
13
|
+
|
|
14
|
+
// 1. Check if there's already an active task
|
|
15
|
+
const nowPath = context.paths.now
|
|
16
|
+
try {
|
|
17
|
+
const nowContent = await fs.readFile(nowPath, 'utf-8')
|
|
18
|
+
actual.nowExists = true
|
|
19
|
+
actual.nowContent = nowContent.trim()
|
|
20
|
+
|
|
21
|
+
const hasRealTask =
|
|
22
|
+
nowContent.trim().length > 0 && !nowContent.includes('No current task') && !nowContent.match(/^#\s*NOW\s*$/m)
|
|
23
|
+
|
|
24
|
+
actual.hasActiveTask = hasRealTask
|
|
25
|
+
|
|
26
|
+
// ANTI-HALLUCINATION: Warn if replacing existing task
|
|
27
|
+
if (hasRealTask && context.params.task) {
|
|
28
|
+
const taskPreview = nowContent.substring(0, 50).replace(/\n/g, ' ')
|
|
29
|
+
warnings.push(`Replacing existing task: "${taskPreview}..."`)
|
|
30
|
+
recommendations.push('Use /p:done first to track completion')
|
|
31
|
+
}
|
|
32
|
+
} catch {
|
|
33
|
+
actual.nowExists = false
|
|
34
|
+
actual.hasActiveTask = false
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// 2. Check next.md for available tasks
|
|
38
|
+
const nextPath = context.paths.next
|
|
39
|
+
try {
|
|
40
|
+
const nextContent = await fs.readFile(nextPath, 'utf-8')
|
|
41
|
+
const pendingTasks = (nextContent.match(/- \[ \]/g) || []).length
|
|
42
|
+
actual.pendingTasks = pendingTasks
|
|
43
|
+
|
|
44
|
+
if (!context.params.task && pendingTasks > 0) {
|
|
45
|
+
recommendations.push(`${pendingTasks} tasks available in queue`)
|
|
46
|
+
}
|
|
47
|
+
} catch {
|
|
48
|
+
actual.pendingTasks = 0
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return {
|
|
52
|
+
verified: warnings.length === 0,
|
|
53
|
+
actual,
|
|
54
|
+
warnings,
|
|
55
|
+
recommendations,
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ship Command Verifier
|
|
3
|
+
* Verify feature is ready to ship
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import fs from 'fs/promises'
|
|
7
|
+
import path from 'path'
|
|
8
|
+
import { execSync } from 'child_process'
|
|
9
|
+
import type { Context, VerificationResult } from '../types'
|
|
10
|
+
import { escapeRegex } from '../utils'
|
|
11
|
+
|
|
12
|
+
export async function verifyShip(context: Context): Promise<VerificationResult> {
|
|
13
|
+
const warnings: string[] = []
|
|
14
|
+
const recommendations: string[] = []
|
|
15
|
+
const actual: Record<string, unknown> = {}
|
|
16
|
+
|
|
17
|
+
// 1. Check for uncommitted changes
|
|
18
|
+
try {
|
|
19
|
+
const gitStatus = execSync('git status --porcelain', {
|
|
20
|
+
cwd: context.projectPath,
|
|
21
|
+
encoding: 'utf-8',
|
|
22
|
+
})
|
|
23
|
+
actual.hasUncommittedChanges = gitStatus.trim().length > 0
|
|
24
|
+
actual.uncommittedFiles = gitStatus.trim().split('\n').filter(Boolean).length
|
|
25
|
+
|
|
26
|
+
if (actual.hasUncommittedChanges) {
|
|
27
|
+
warnings.push(`${actual.uncommittedFiles} uncommitted file(s)`)
|
|
28
|
+
recommendations.push('Commit changes before shipping')
|
|
29
|
+
}
|
|
30
|
+
} catch {
|
|
31
|
+
actual.gitAvailable = false
|
|
32
|
+
// Not a git repo or git not available - not a blocker
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// 2. Check for package.json version (if exists)
|
|
36
|
+
const pkgPath = path.join(context.projectPath, 'package.json')
|
|
37
|
+
try {
|
|
38
|
+
const pkgContent = await fs.readFile(pkgPath, 'utf-8')
|
|
39
|
+
const pkg = JSON.parse(pkgContent)
|
|
40
|
+
actual.currentVersion = pkg.version
|
|
41
|
+
actual.hasPackageJson = true
|
|
42
|
+
} catch {
|
|
43
|
+
actual.hasPackageJson = false
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// 3. Check shipped.md for duplicate feature names
|
|
47
|
+
const shippedPath = context.paths.shipped
|
|
48
|
+
try {
|
|
49
|
+
const shippedContent = await fs.readFile(shippedPath, 'utf-8')
|
|
50
|
+
actual.shippedExists = true
|
|
51
|
+
|
|
52
|
+
// Check if feature name already shipped today
|
|
53
|
+
const featureName = context.params.feature || context.params.description
|
|
54
|
+
if (featureName) {
|
|
55
|
+
const today = new Date().toISOString().split('T')[0]
|
|
56
|
+
const todayPattern = new RegExp(`${today}.*${escapeRegex(featureName)}`, 'i')
|
|
57
|
+
if (todayPattern.test(shippedContent)) {
|
|
58
|
+
warnings.push(`Feature "${featureName}" already shipped today`)
|
|
59
|
+
recommendations.push('Use a different feature name or skip /p:ship')
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
} catch {
|
|
63
|
+
actual.shippedExists = false
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// 4. Check for test failures (if test script exists)
|
|
67
|
+
if (actual.hasPackageJson) {
|
|
68
|
+
try {
|
|
69
|
+
const pkgContent = await fs.readFile(pkgPath, 'utf-8')
|
|
70
|
+
const pkg = JSON.parse(pkgContent)
|
|
71
|
+
actual.hasTestScript = !!pkg.scripts?.test
|
|
72
|
+
// Note: We don't run tests here, just check if they exist
|
|
73
|
+
// Running tests is the user's responsibility
|
|
74
|
+
} catch {
|
|
75
|
+
actual.hasTestScript = false
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
verified: warnings.length === 0,
|
|
81
|
+
actual,
|
|
82
|
+
warnings,
|
|
83
|
+
recommendations,
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Spec Command Verifier
|
|
3
|
+
* Verify spec can be created
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import fs from 'fs/promises'
|
|
7
|
+
import type { Context, VerificationResult } from '../types'
|
|
8
|
+
|
|
9
|
+
export async function verifySpec(context: Context): Promise<VerificationResult> {
|
|
10
|
+
const warnings: string[] = []
|
|
11
|
+
const recommendations: string[] = []
|
|
12
|
+
const actual: Record<string, unknown> = {}
|
|
13
|
+
|
|
14
|
+
// 1. Check specs directory exists
|
|
15
|
+
const specsPath = context.paths.specs
|
|
16
|
+
try {
|
|
17
|
+
await fs.access(specsPath)
|
|
18
|
+
actual.specsExists = true
|
|
19
|
+
|
|
20
|
+
// List existing specs
|
|
21
|
+
const files = await fs.readdir(specsPath)
|
|
22
|
+
actual.existingSpecs = files.filter((f) => f.endsWith('.md'))
|
|
23
|
+
actual.specCount = (actual.existingSpecs as string[]).length
|
|
24
|
+
} catch {
|
|
25
|
+
actual.specsExists = false
|
|
26
|
+
actual.specCount = 0
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// 2. Check for duplicate spec name
|
|
30
|
+
const featureName = context.params.feature || context.params.name || context.params.description
|
|
31
|
+
if (featureName && actual.existingSpecs) {
|
|
32
|
+
const slug = featureName.toLowerCase().replace(/\s+/g, '-')
|
|
33
|
+
if ((actual.existingSpecs as string[]).includes(`${slug}.md`)) {
|
|
34
|
+
warnings.push(`Spec "${featureName}" already exists`)
|
|
35
|
+
recommendations.push('Use a different name or edit existing spec')
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return {
|
|
40
|
+
verified: warnings.length === 0,
|
|
41
|
+
actual,
|
|
42
|
+
warnings,
|
|
43
|
+
recommendations,
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sync Command Verifier
|
|
3
|
+
* Verify sync can proceed
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import fs from 'fs/promises'
|
|
7
|
+
import path from 'path'
|
|
8
|
+
import os from 'os'
|
|
9
|
+
import type { Context, VerificationResult } from '../types'
|
|
10
|
+
|
|
11
|
+
export async function verifySync(context: Context): Promise<VerificationResult> {
|
|
12
|
+
const warnings: string[] = []
|
|
13
|
+
const recommendations: string[] = []
|
|
14
|
+
const actual: Record<string, unknown> = {}
|
|
15
|
+
|
|
16
|
+
// 1. Check if project is initialized
|
|
17
|
+
const configPath = path.join(context.projectPath, '.prjct/prjct.config.json')
|
|
18
|
+
try {
|
|
19
|
+
const configContent = await fs.readFile(configPath, 'utf-8')
|
|
20
|
+
actual.hasConfig = true
|
|
21
|
+
actual.config = JSON.parse(configContent)
|
|
22
|
+
} catch {
|
|
23
|
+
actual.hasConfig = false
|
|
24
|
+
warnings.push('Project not initialized')
|
|
25
|
+
recommendations.push('Run /p:init first')
|
|
26
|
+
return { verified: false, actual, warnings, recommendations }
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// 2. Check if global storage exists
|
|
30
|
+
const projectId = (actual.config as { projectId?: string })?.projectId
|
|
31
|
+
const globalProjectPath = path.join(os.homedir(), '.prjct-cli/projects', projectId || '')
|
|
32
|
+
try {
|
|
33
|
+
await fs.access(globalProjectPath)
|
|
34
|
+
actual.globalStorageExists = true
|
|
35
|
+
} catch {
|
|
36
|
+
actual.globalStorageExists = false
|
|
37
|
+
warnings.push('Global storage missing')
|
|
38
|
+
recommendations.push('Run /p:init to recreate')
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
verified: warnings.length === 0,
|
|
43
|
+
actual,
|
|
44
|
+
warnings,
|
|
45
|
+
recommendations,
|
|
46
|
+
}
|
|
47
|
+
}
|