prjct-cli 0.11.4 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +72 -0
- package/README.md +81 -25
- package/bin/dev.js +1 -1
- package/bin/generate-views.js +209 -0
- package/bin/migrate-to-json.js +742 -0
- package/bin/prjct +5 -5
- package/bin/serve.js +246 -54
- package/core/__tests__/agentic/{memory-system.test.js → memory-system.test.ts} +12 -23
- package/core/__tests__/agentic/{plan-mode.test.js → plan-mode.test.ts} +26 -24
- package/core/__tests__/agentic/{prompt-builder.test.js → prompt-builder.test.ts} +3 -8
- package/core/__tests__/utils/date-helper.test.ts +405 -0
- package/core/__tests__/utils/{output.test.js → output.test.ts} +12 -24
- package/core/agentic/agent-router.ts +137 -0
- package/core/agentic/chain-of-thought.ts +228 -0
- package/core/agentic/command-executor/command-executor.ts +384 -0
- package/core/agentic/command-executor/index.ts +16 -0
- package/core/agentic/command-executor/status-signal.ts +38 -0
- package/core/agentic/command-executor/types.ts +79 -0
- package/core/agentic/command-executor.ts +8 -0
- package/core/agentic/{context-builder.js → context-builder.ts} +99 -89
- package/core/agentic/context-filter.ts +365 -0
- package/core/agentic/ground-truth/index.ts +76 -0
- package/core/agentic/ground-truth/types.ts +33 -0
- package/core/agentic/ground-truth/utils.ts +48 -0
- package/core/agentic/ground-truth/verifiers/analyze.ts +54 -0
- package/core/agentic/ground-truth/verifiers/done.ts +75 -0
- package/core/agentic/ground-truth/verifiers/feature.ts +70 -0
- package/core/agentic/ground-truth/verifiers/index.ts +37 -0
- package/core/agentic/ground-truth/verifiers/init.ts +52 -0
- package/core/agentic/ground-truth/verifiers/now.ts +57 -0
- package/core/agentic/ground-truth/verifiers/ship.ts +85 -0
- package/core/agentic/ground-truth/verifiers/spec.ts +45 -0
- package/core/agentic/ground-truth/verifiers/sync.ts +47 -0
- package/core/agentic/ground-truth/verifiers.ts +6 -0
- package/core/agentic/ground-truth.ts +8 -0
- package/core/agentic/loop-detector/error-analysis.ts +97 -0
- package/core/agentic/loop-detector/hallucination.ts +71 -0
- package/core/agentic/loop-detector/index.ts +41 -0
- package/core/agentic/loop-detector/loop-detector.ts +222 -0
- package/core/agentic/loop-detector/types.ts +66 -0
- package/core/agentic/loop-detector.ts +8 -0
- package/core/agentic/memory-system/history.ts +53 -0
- package/core/agentic/memory-system/index.ts +192 -0
- package/core/agentic/memory-system/patterns.ts +156 -0
- package/core/agentic/memory-system/semantic-memories.ts +277 -0
- package/core/agentic/memory-system/session.ts +21 -0
- package/core/agentic/memory-system/types.ts +159 -0
- package/core/agentic/memory-system.ts +8 -0
- package/core/agentic/parallel-tools.ts +165 -0
- package/core/agentic/plan-mode/approval.ts +57 -0
- package/core/agentic/plan-mode/constants.ts +44 -0
- package/core/agentic/plan-mode/index.ts +28 -0
- package/core/agentic/plan-mode/plan-mode.ts +406 -0
- package/core/agentic/plan-mode/types.ts +193 -0
- package/core/agentic/plan-mode.ts +8 -0
- package/core/agentic/prompt-builder.ts +566 -0
- package/core/agentic/response-templates.ts +164 -0
- package/core/agentic/semantic-compression.ts +273 -0
- package/core/agentic/services.ts +206 -0
- package/core/agentic/smart-context.ts +476 -0
- package/core/agentic/{template-loader.js → template-loader.ts} +35 -18
- package/core/agentic/think-blocks.ts +202 -0
- package/core/agentic/tool-registry.ts +119 -0
- package/core/agentic/validation-rules.ts +313 -0
- package/core/agents/index.ts +28 -0
- package/core/agents/performance.ts +444 -0
- package/core/agents/types.ts +126 -0
- package/core/bus/{index.js → index.ts} +57 -61
- package/core/command-registry/categories.ts +23 -0
- package/core/command-registry/commands.ts +15 -0
- package/core/command-registry/core-commands.ts +319 -0
- package/core/command-registry/index.ts +158 -0
- package/core/command-registry/optional-commands.ts +119 -0
- package/core/command-registry/setup-commands.ts +53 -0
- package/core/command-registry/types.ts +59 -0
- package/core/command-registry.ts +9 -0
- package/core/commands/analysis.ts +298 -0
- package/core/commands/analytics.ts +288 -0
- package/core/commands/base.ts +273 -0
- package/core/commands/index.ts +211 -0
- package/core/commands/maintenance.ts +226 -0
- package/core/commands/planning.ts +311 -0
- package/core/commands/setup.ts +309 -0
- package/core/commands/shipping.ts +188 -0
- package/core/commands/types.ts +183 -0
- package/core/commands/workflow.ts +226 -0
- package/core/commands.ts +11 -0
- package/core/constants/formats.ts +187 -0
- package/core/constants/index.ts +7 -0
- package/core/{context-sync.js → context-sync.ts} +59 -26
- package/core/data/agents-manager.ts +76 -0
- package/core/data/analysis-manager.ts +83 -0
- package/core/data/base-manager.ts +156 -0
- package/core/data/ideas-manager.ts +81 -0
- package/core/data/index.ts +32 -0
- package/core/data/outcomes-manager.ts +96 -0
- package/core/data/project-manager.ts +75 -0
- package/core/data/roadmap-manager.ts +118 -0
- package/core/data/shipped-manager.ts +65 -0
- package/core/data/state-manager.ts +214 -0
- package/core/domain/{agent-generator.js → agent-generator.ts} +77 -57
- package/core/domain/{agent-loader.js → agent-loader.ts} +65 -56
- package/core/domain/{agent-matcher.js → agent-matcher.ts} +51 -24
- package/core/domain/{agent-validator.js → agent-validator.ts} +70 -37
- package/core/domain/{analyzer.js → analyzer.ts} +91 -85
- package/core/domain/{architect-session.js → architect-session.ts} +49 -34
- package/core/domain/{architecture-generator.js → architecture-generator.ts} +25 -13
- package/core/domain/{context-estimator.js → context-estimator.ts} +57 -36
- package/core/domain/{product-standards.js → product-standards.ts} +40 -26
- package/core/domain/{smart-cache.js → smart-cache.ts} +39 -30
- package/core/domain/{snapshot-manager.js → snapshot-manager.ts} +103 -100
- package/core/domain/{task-analyzer.js → task-analyzer.ts} +82 -43
- package/core/domain/task-stack/index.ts +19 -0
- package/core/domain/task-stack/parser.ts +86 -0
- package/core/domain/task-stack/storage.ts +123 -0
- package/core/domain/task-stack/task-stack.ts +340 -0
- package/core/domain/task-stack/types.ts +51 -0
- package/core/domain/task-stack.ts +8 -0
- package/core/{index.js → index.ts} +61 -18
- package/core/infrastructure/{agent-detector.js → agent-detector.ts} +62 -23
- package/core/infrastructure/agents/{claude-agent.js → claude-agent.ts} +61 -21
- package/core/infrastructure/{author-detector.js → author-detector.ts} +42 -49
- package/core/infrastructure/{capability-installer.js → capability-installer.ts} +51 -27
- package/core/infrastructure/{command-installer.js → command-installer/command-installer.ts} +43 -144
- package/core/infrastructure/command-installer/global-config.ts +106 -0
- package/core/infrastructure/command-installer/index.ts +25 -0
- package/core/infrastructure/command-installer/types.ts +41 -0
- package/core/infrastructure/command-installer.ts +8 -0
- package/core/infrastructure/{config-manager.js → config-manager.ts} +60 -80
- package/core/infrastructure/{editors-config.js → editors-config.ts} +33 -31
- package/core/infrastructure/legacy-installer-detector/cleanup.ts +216 -0
- package/core/infrastructure/legacy-installer-detector/detection.ts +95 -0
- package/core/infrastructure/legacy-installer-detector/index.ts +171 -0
- package/core/infrastructure/legacy-installer-detector/migration.ts +87 -0
- package/core/infrastructure/legacy-installer-detector/types.ts +42 -0
- package/core/infrastructure/legacy-installer-detector.ts +7 -0
- package/core/infrastructure/migrator/file-operations.ts +125 -0
- package/core/infrastructure/migrator/index.ts +288 -0
- package/core/infrastructure/migrator/project-scanner.ts +89 -0
- package/core/infrastructure/migrator/reports.ts +117 -0
- package/core/infrastructure/migrator/types.ts +124 -0
- package/core/infrastructure/migrator/validation.ts +94 -0
- package/core/infrastructure/migrator/version-migration.ts +117 -0
- package/core/infrastructure/migrator.ts +10 -0
- package/core/infrastructure/{path-manager.js → path-manager.ts} +51 -91
- package/core/infrastructure/session-manager/index.ts +23 -0
- package/core/infrastructure/session-manager/migration.ts +88 -0
- package/core/infrastructure/session-manager/session-manager.ts +307 -0
- package/core/infrastructure/session-manager/types.ts +45 -0
- package/core/infrastructure/session-manager.ts +8 -0
- package/core/infrastructure/{setup.js → setup.ts} +29 -21
- package/core/infrastructure/{update-checker.js → update-checker.ts} +40 -18
- package/core/outcomes/analyzer.ts +333 -0
- package/core/outcomes/index.ts +34 -0
- package/core/outcomes/recorder.ts +194 -0
- package/core/outcomes/types.ts +145 -0
- package/core/plugin/{hooks.js → hooks.ts} +56 -58
- package/core/plugin/{index.js → index.ts} +19 -8
- package/core/plugin/{loader.js → loader.ts} +87 -69
- package/core/plugin/{registry.js → registry.ts} +49 -45
- package/core/plugins/{webhook.js → webhook.ts} +43 -27
- package/core/schemas/agents.ts +27 -0
- package/core/schemas/analysis.ts +41 -0
- package/core/schemas/ideas.ts +83 -0
- package/core/schemas/index.ts +73 -0
- package/core/schemas/outcomes.ts +22 -0
- package/core/schemas/project.ts +26 -0
- package/core/schemas/roadmap.ts +90 -0
- package/core/schemas/shipped.ts +82 -0
- package/core/schemas/state.ts +107 -0
- package/core/session/index.ts +17 -0
- package/core/session/{metrics.js → metrics.ts} +64 -46
- package/core/session/{index.js → session-manager.ts} +51 -117
- package/core/session/types.ts +29 -0
- package/core/session/utils.ts +57 -0
- package/core/state/index.ts +25 -0
- package/core/state/manager.ts +376 -0
- package/core/state/types.ts +185 -0
- package/core/tsconfig.json +22 -0
- package/core/types/index.ts +506 -0
- package/core/utils/{animations.js → animations.ts} +74 -28
- package/core/utils/{branding.js → branding.ts} +29 -4
- package/core/utils/{date-helper.js → date-helper.ts} +31 -74
- package/core/utils/file-helper.ts +262 -0
- package/core/utils/{jsonl-helper.js → jsonl-helper.ts} +71 -107
- package/core/utils/{logger.js → logger.ts} +24 -12
- package/core/utils/{output.js → output.ts} +25 -13
- package/core/utils/{project-capabilities.js → project-capabilities.ts} +31 -18
- package/core/utils/{session-helper.js → session-helper.ts} +79 -66
- package/core/utils/{version.js → version.ts} +23 -31
- package/core/view-generator.ts +536 -0
- package/package.json +23 -17
- package/packages/shared/.turbo/turbo-build.log +14 -0
- package/packages/shared/dist/index.d.ts +8 -613
- package/packages/shared/dist/index.d.ts.map +1 -0
- package/packages/shared/dist/index.js +4110 -118
- package/packages/shared/dist/schemas.d.ts +408 -0
- package/packages/shared/dist/schemas.d.ts.map +1 -0
- package/packages/shared/dist/types.d.ts +144 -0
- package/packages/shared/dist/types.d.ts.map +1 -0
- package/packages/shared/dist/unified.d.ts +139 -0
- package/packages/shared/dist/unified.d.ts.map +1 -0
- package/packages/shared/dist/utils.d.ts +60 -0
- package/packages/shared/dist/utils.d.ts.map +1 -0
- package/packages/shared/package.json +4 -4
- package/packages/shared/src/index.ts +1 -0
- package/packages/shared/src/unified.ts +174 -0
- package/packages/web/app/api/claude/sessions/route.ts +1 -1
- package/packages/web/app/api/claude/status/route.ts +1 -1
- package/packages/web/app/api/migrate/route.ts +46 -0
- package/packages/web/app/api/projects/[id]/route.ts +1 -1
- package/packages/web/app/api/projects/[id]/stats/route.ts +30 -2
- package/packages/web/app/api/projects/[id]/status/route.ts +1 -1
- package/packages/web/app/api/projects/route.ts +1 -1
- package/packages/web/app/api/settings/route.ts +97 -0
- package/packages/web/app/api/v2/projects/[id]/unified/route.ts +57 -0
- package/packages/web/app/globals.css +38 -0
- package/packages/web/app/layout.tsx +10 -2
- package/packages/web/app/page.tsx +9 -224
- package/packages/web/app/project/[id]/page.tsx +191 -63
- package/packages/web/app/project/[id]/stats/loading.tsx +43 -0
- package/packages/web/app/project/[id]/stats/page.tsx +203 -403
- package/packages/web/app/settings/page.tsx +222 -2
- package/packages/web/components/ActivityTimeline/ActivityTimeline.constants.ts +2 -0
- package/packages/web/components/ActivityTimeline/ActivityTimeline.tsx +50 -0
- package/packages/web/components/ActivityTimeline/ActivityTimeline.types.ts +8 -0
- package/packages/web/components/ActivityTimeline/hooks/index.ts +2 -0
- package/packages/web/components/ActivityTimeline/hooks/useExpandable.ts +9 -0
- package/packages/web/components/ActivityTimeline/hooks/useGroupedEvents.ts +23 -0
- package/packages/web/components/ActivityTimeline/index.ts +2 -0
- package/packages/web/components/AgentsCard/AgentsCard.tsx +63 -0
- package/packages/web/components/AgentsCard/AgentsCard.types.ts +13 -0
- package/packages/web/components/AgentsCard/index.ts +2 -0
- package/packages/web/components/AppSidebar/AppSidebar.tsx +134 -0
- package/packages/web/components/AppSidebar/index.ts +1 -0
- package/packages/web/components/BackLink/BackLink.tsx +18 -0
- package/packages/web/components/BackLink/BackLink.types.ts +5 -0
- package/packages/web/components/BackLink/index.ts +2 -0
- package/packages/web/components/BentoCard/BentoCard.constants.ts +16 -0
- package/packages/web/components/BentoCard/BentoCard.tsx +47 -0
- package/packages/web/components/BentoCard/BentoCard.types.ts +15 -0
- package/packages/web/components/BentoCard/index.ts +2 -0
- package/packages/web/components/BentoCardSkeleton/BentoCardSkeleton.constants.ts +9 -0
- package/packages/web/components/BentoCardSkeleton/BentoCardSkeleton.tsx +18 -0
- package/packages/web/components/BentoCardSkeleton/BentoCardSkeleton.types.ts +5 -0
- package/packages/web/components/BentoCardSkeleton/index.ts +2 -0
- package/packages/web/components/BentoGrid/BentoGrid.tsx +18 -0
- package/packages/web/components/BentoGrid/BentoGrid.types.ts +4 -0
- package/packages/web/components/BentoGrid/index.ts +2 -0
- package/packages/web/components/CommandButton/index.ts +1 -0
- package/packages/web/components/ConnectionStatus/index.ts +1 -0
- package/packages/web/components/DashboardContent/DashboardContent.tsx +254 -0
- package/packages/web/components/DashboardContent/index.ts +1 -0
- package/packages/web/components/DateGroup/DateGroup.tsx +18 -0
- package/packages/web/components/DateGroup/DateGroup.types.ts +6 -0
- package/packages/web/components/DateGroup/DateGroup.utils.ts +11 -0
- package/packages/web/components/DateGroup/index.ts +2 -0
- package/packages/web/components/EmptyState/EmptyState.tsx +58 -0
- package/packages/web/components/EmptyState/EmptyState.types.ts +10 -0
- package/packages/web/components/EmptyState/index.ts +2 -0
- package/packages/web/components/EventRow/EventRow.constants.ts +10 -0
- package/packages/web/components/EventRow/EventRow.tsx +49 -0
- package/packages/web/components/EventRow/EventRow.types.ts +7 -0
- package/packages/web/components/EventRow/EventRow.utils.ts +49 -0
- package/packages/web/components/EventRow/index.ts +2 -0
- package/packages/web/components/ExpandButton/ExpandButton.tsx +18 -0
- package/packages/web/components/ExpandButton/ExpandButton.types.ts +6 -0
- package/packages/web/components/ExpandButton/index.ts +2 -0
- package/packages/web/components/HealthGradientBackground/HealthGradientBackground.tsx +14 -0
- package/packages/web/components/HealthGradientBackground/HealthGradientBackground.types.ts +5 -0
- package/packages/web/components/HealthGradientBackground/HealthGradientBackground.utils.ts +13 -0
- package/packages/web/components/HealthGradientBackground/index.ts +2 -0
- package/packages/web/components/HeroSection/HeroSection.tsx +55 -0
- package/packages/web/components/HeroSection/HeroSection.types.ts +14 -0
- package/packages/web/components/HeroSection/HeroSection.utils.ts +7 -0
- package/packages/web/components/HeroSection/hooks/index.ts +2 -0
- package/packages/web/components/HeroSection/hooks/useCountUp.ts +45 -0
- package/packages/web/components/HeroSection/hooks/useWeeklyActivity.ts +18 -0
- package/packages/web/components/HeroSection/index.ts +2 -0
- package/packages/web/components/IdeasCard/IdeasCard.tsx +48 -0
- package/packages/web/components/IdeasCard/IdeasCard.types.ts +9 -0
- package/packages/web/components/IdeasCard/index.ts +2 -0
- package/packages/web/components/InsightMessage/InsightMessage.tsx +9 -0
- package/packages/web/components/InsightMessage/InsightMessage.types.ts +3 -0
- package/packages/web/components/InsightMessage/index.ts +2 -0
- package/packages/web/components/Logo/index.ts +1 -0
- package/packages/web/components/MarkdownContent/index.ts +1 -0
- package/packages/web/components/NowCard/NowCard.tsx +93 -0
- package/packages/web/components/NowCard/NowCard.types.ts +15 -0
- package/packages/web/components/NowCard/index.ts +2 -0
- package/packages/web/components/ProgressRing/ProgressRing.constants.ts +20 -0
- package/packages/web/components/ProgressRing/ProgressRing.tsx +51 -0
- package/packages/web/components/ProgressRing/ProgressRing.types.ts +11 -0
- package/packages/web/components/ProgressRing/index.ts +2 -0
- package/packages/web/components/ProjectAvatar/index.ts +1 -0
- package/packages/web/components/Providers/index.ts +1 -0
- package/packages/web/components/QueueCard/QueueCard.tsx +72 -0
- package/packages/web/components/QueueCard/QueueCard.types.ts +11 -0
- package/packages/web/components/QueueCard/QueueCard.utils.ts +12 -0
- package/packages/web/components/QueueCard/index.ts +2 -0
- package/packages/web/components/RoadmapCard/RoadmapCard.tsx +77 -0
- package/packages/web/components/RoadmapCard/RoadmapCard.types.ts +15 -0
- package/packages/web/components/RoadmapCard/index.ts +2 -0
- package/packages/web/components/ShipsCard/ShipsCard.tsx +52 -0
- package/packages/web/components/ShipsCard/ShipsCard.types.ts +12 -0
- package/packages/web/components/ShipsCard/ShipsCard.utils.ts +4 -0
- package/packages/web/components/ShipsCard/index.ts +2 -0
- package/packages/web/components/SparklineChart/SparklineChart.tsx +38 -0
- package/packages/web/components/SparklineChart/SparklineChart.types.ts +6 -0
- package/packages/web/components/SparklineChart/index.ts +2 -0
- package/packages/web/components/StreakCard/StreakCard.constants.ts +2 -0
- package/packages/web/components/StreakCard/StreakCard.tsx +53 -0
- package/packages/web/components/StreakCard/StreakCard.types.ts +4 -0
- package/packages/web/components/StreakCard/index.ts +2 -0
- package/packages/web/components/TasksCounter/TasksCounter.tsx +14 -0
- package/packages/web/components/TasksCounter/TasksCounter.types.ts +3 -0
- package/packages/web/components/TasksCounter/index.ts +2 -0
- package/packages/web/components/TechStackBadges/index.ts +1 -0
- package/packages/web/components/{TerminalTab.tsx → TerminalTabs/TerminalTab.tsx} +11 -0
- package/packages/web/components/{TerminalTabs.tsx → TerminalTabs/TerminalTabs.tsx} +29 -28
- package/packages/web/components/TerminalTabs/index.ts +1 -0
- package/packages/web/components/VelocityBadge/VelocityBadge.tsx +27 -0
- package/packages/web/components/VelocityBadge/VelocityBadge.types.ts +3 -0
- package/packages/web/components/VelocityBadge/index.ts +2 -0
- package/packages/web/components/VelocityCard/VelocityCard.tsx +71 -0
- package/packages/web/components/VelocityCard/VelocityCard.types.ts +7 -0
- package/packages/web/components/VelocityCard/index.ts +2 -0
- package/packages/web/components/WeeklySparkline/WeeklySparkline.tsx +13 -0
- package/packages/web/components/WeeklySparkline/WeeklySparkline.types.ts +3 -0
- package/packages/web/components/WeeklySparkline/index.ts +2 -0
- package/packages/web/components/ui/input.tsx +21 -0
- package/packages/web/components/ui/tooltip.tsx +2 -2
- package/packages/web/context/TerminalTabsContext.tsx +46 -1
- package/packages/web/hooks/useClaudeTerminal.ts +71 -21
- package/packages/web/hooks/useProjectStats.ts +55 -0
- package/packages/web/hooks/useProjects.ts +6 -6
- package/packages/web/lib/actions/projects.ts +15 -0
- package/packages/web/lib/json-loader.ts +630 -0
- package/packages/web/lib/services/index.ts +9 -0
- package/packages/web/lib/services/migration.server.ts +598 -0
- package/packages/web/lib/services/projects.server.ts +52 -0
- package/packages/web/lib/services/stats.server.ts +264 -0
- package/packages/web/lib/unified-loader.ts +396 -0
- package/packages/web/next-env.d.ts +1 -1
- package/packages/web/package.json +10 -6
- package/packages/web/server.ts +36 -6
- package/templates/commands/done.md +76 -32
- package/templates/commands/feature.md +121 -47
- package/templates/commands/idea.md +81 -8
- package/templates/commands/now.md +41 -17
- package/templates/commands/ship.md +64 -25
- package/templates/commands/sync.md +28 -3
- package/core/agentic/agent-router.js +0 -128
- package/core/agentic/chain-of-thought.js +0 -578
- package/core/agentic/command-executor.js +0 -421
- package/core/agentic/context-filter.js +0 -354
- package/core/agentic/ground-truth.js +0 -591
- package/core/agentic/loop-detector.js +0 -406
- package/core/agentic/memory-system.js +0 -850
- package/core/agentic/parallel-tools.js +0 -366
- package/core/agentic/plan-mode.js +0 -572
- package/core/agentic/prompt-builder.js +0 -338
- package/core/agentic/response-templates.js +0 -290
- package/core/agentic/semantic-compression.js +0 -517
- package/core/agentic/think-blocks.js +0 -657
- package/core/agentic/tool-registry.js +0 -184
- package/core/agentic/validation-rules.js +0 -380
- package/core/command-registry.js +0 -698
- package/core/commands.js +0 -2237
- package/core/domain/task-stack.js +0 -497
- package/core/infrastructure/legacy-installer-detector.js +0 -546
- package/core/infrastructure/migrator.js +0 -799
- package/core/infrastructure/session-manager.js +0 -390
- package/core/utils/file-helper.js +0 -329
- package/packages/web/app/api/projects/[id]/delete/route.ts +0 -21
- package/packages/web/app/api/stats/route.ts +0 -38
- package/packages/web/components/AppSidebar.tsx +0 -113
- package/packages/web/hooks/useStats.ts +0 -28
- /package/packages/web/components/{CommandButton.tsx → CommandButton/CommandButton.tsx} +0 -0
- /package/packages/web/components/{ConnectionStatus.tsx → ConnectionStatus/ConnectionStatus.tsx} +0 -0
- /package/packages/web/components/{Logo.tsx → Logo/Logo.tsx} +0 -0
- /package/packages/web/components/{MarkdownContent.tsx → MarkdownContent/MarkdownContent.tsx} +0 -0
- /package/packages/web/components/{ProjectAvatar.tsx → ProjectAvatar/ProjectAvatar.tsx} +0 -0
- /package/packages/web/components/{providers.tsx → Providers/Providers.tsx} +0 -0
- /package/packages/web/components/{TechStackBadges.tsx → TechStackBadges/TechStackBadges.tsx} +0 -0
|
@@ -0,0 +1,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
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error Analysis
|
|
3
|
+
* Pattern detection and suggestion generation for errors
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { ErrorEntry, ErrorPattern } from './types'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Check if two errors are similar
|
|
10
|
+
*/
|
|
11
|
+
export function isSimilarError(error1: string, error2: string): boolean {
|
|
12
|
+
if (!error1 || !error2) return false
|
|
13
|
+
|
|
14
|
+
// Normalize errors
|
|
15
|
+
const normalize = (e: string) =>
|
|
16
|
+
e
|
|
17
|
+
.toLowerCase()
|
|
18
|
+
.replace(/[0-9]+/g, 'N') // Replace numbers
|
|
19
|
+
.replace(/['"`]/g, '') // Remove quotes
|
|
20
|
+
.replace(/\s+/g, ' ') // Normalize whitespace
|
|
21
|
+
.trim()
|
|
22
|
+
|
|
23
|
+
return normalize(error1) === normalize(error2)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Analyze error pattern from history
|
|
28
|
+
*/
|
|
29
|
+
export function analyzeErrorPattern(errors: ErrorEntry[]): ErrorPattern {
|
|
30
|
+
if (!errors || errors.length === 0) {
|
|
31
|
+
return { type: 'unknown', description: 'No error information' }
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const lastError = errors[errors.length - 1]?.message?.toLowerCase() || ''
|
|
35
|
+
|
|
36
|
+
// Detect common patterns (ORDER MATTERS - more specific patterns first)
|
|
37
|
+
if (lastError.includes('permission') || lastError.includes('access denied')) {
|
|
38
|
+
return { type: 'permission', description: 'File or directory permission issue' }
|
|
39
|
+
}
|
|
40
|
+
if (lastError.includes('not found') || lastError.includes('no such file')) {
|
|
41
|
+
return { type: 'not_found', description: 'File or resource not found' }
|
|
42
|
+
}
|
|
43
|
+
if (lastError.includes('syntax') || lastError.includes('parse')) {
|
|
44
|
+
return { type: 'syntax', description: 'Syntax or parsing error' }
|
|
45
|
+
}
|
|
46
|
+
if (lastError.includes('timeout') || lastError.includes('timed out')) {
|
|
47
|
+
return { type: 'timeout', description: 'Operation timed out' }
|
|
48
|
+
}
|
|
49
|
+
if (lastError.includes('network') || lastError.includes('connection')) {
|
|
50
|
+
return { type: 'network', description: 'Network or connection issue' }
|
|
51
|
+
}
|
|
52
|
+
// Config pattern MUST be checked before validation (since "invalid config" contains both)
|
|
53
|
+
if (lastError.includes('config') || lastError.includes('configuration')) {
|
|
54
|
+
return { type: 'config', description: 'Configuration issue' }
|
|
55
|
+
}
|
|
56
|
+
if (lastError.includes('validation') || lastError.includes('invalid')) {
|
|
57
|
+
return { type: 'validation', description: 'Validation failed' }
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return { type: 'unknown', description: 'Unrecognized error pattern' }
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Generate user-friendly escalation message
|
|
65
|
+
*/
|
|
66
|
+
export function generateEscalationMessage(command: string, errorPattern: ErrorPattern, maxAttempts: number): string {
|
|
67
|
+
const messages: Record<string, string> = {
|
|
68
|
+
permission: `I've tried ${command} ${maxAttempts} times but keep hitting permission issues.`,
|
|
69
|
+
not_found: `After ${maxAttempts} attempts, I still can't find the required file or resource.`,
|
|
70
|
+
syntax: `I'm encountering repeated syntax errors with ${command}.`,
|
|
71
|
+
timeout: `The operation keeps timing out after ${maxAttempts} attempts.`,
|
|
72
|
+
network: `Network issues are preventing ${command} from completing.`,
|
|
73
|
+
validation: `Validation keeps failing for ${command}.`,
|
|
74
|
+
config: `There seems to be a configuration issue affecting ${command}.`,
|
|
75
|
+
unknown: `I've tried ${command} ${maxAttempts} times without success.`,
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return messages[errorPattern.type] || messages.unknown
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Generate actionable suggestion based on error pattern
|
|
83
|
+
*/
|
|
84
|
+
export function generateSuggestion(errorPattern: ErrorPattern): string {
|
|
85
|
+
const suggestions: Record<string, string> = {
|
|
86
|
+
permission: 'Check file permissions. Try: chmod -R u+w ~/.prjct-cli/',
|
|
87
|
+
not_found: 'Verify the file path exists. Run /p:init if project not initialized.',
|
|
88
|
+
syntax: 'Check the file format. There may be invalid JSON or markdown.',
|
|
89
|
+
timeout: 'Check your network connection or try again in a moment.',
|
|
90
|
+
network: 'Verify internet connection and try again.',
|
|
91
|
+
validation: 'Review the input parameters and try with different values.',
|
|
92
|
+
config: 'Check .prjct/prjct.config.json for issues. Try /p:init to reinitialize.',
|
|
93
|
+
unknown: 'Can you check the issue manually and provide more context?',
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return suggestions[errorPattern.type] || suggestions.unknown
|
|
97
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hallucination Detection
|
|
3
|
+
* ANTI-HALLUCINATION: Patterns that indicate Claude may be hallucinating
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { HallucinationPattern, HallucinationResult } from './types'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* ANTI-HALLUCINATION: Patterns that indicate Claude may be hallucinating
|
|
10
|
+
* These patterns detect contradictory or impossible statements
|
|
11
|
+
*/
|
|
12
|
+
export const HALLUCINATION_PATTERNS: HallucinationPattern[] = [
|
|
13
|
+
// Contradictory file operations
|
|
14
|
+
{ pattern: /file.*not found.*created/i, type: 'contradiction', description: 'Claims file created but also not found' },
|
|
15
|
+
{ pattern: /created.*but.*error/i, type: 'contradiction', description: 'Claims success but also error' },
|
|
16
|
+
{ pattern: /successfully.*failed/i, type: 'contradiction', description: 'Contradictory success/failure' },
|
|
17
|
+
|
|
18
|
+
// Impossible task states
|
|
19
|
+
{
|
|
20
|
+
pattern: /already.*completed.*completing/i,
|
|
21
|
+
type: 'state',
|
|
22
|
+
description: 'Completing already-completed task',
|
|
23
|
+
},
|
|
24
|
+
{ pattern: /no task.*marking complete/i, type: 'state', description: 'Completing non-existent task' },
|
|
25
|
+
{ pattern: /no.*active.*done with/i, type: 'state', description: 'Finishing task that doesnt exist' },
|
|
26
|
+
|
|
27
|
+
// Invented data
|
|
28
|
+
{
|
|
29
|
+
pattern: /version.*updated.*no package/i,
|
|
30
|
+
type: 'invented',
|
|
31
|
+
description: 'Version update without package.json',
|
|
32
|
+
},
|
|
33
|
+
{ pattern: /committed.*nothing to commit/i, type: 'invented', description: 'Commit without changes' },
|
|
34
|
+
{ pattern: /pushed.*no remote/i, type: 'invented', description: 'Push without remote' },
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Get suggestion for handling detected hallucination
|
|
39
|
+
*/
|
|
40
|
+
export function getHallucinationSuggestion(type: string): string {
|
|
41
|
+
const suggestions: Record<string, string> = {
|
|
42
|
+
contradiction: 'Verify file/resource state before reporting. Use Read tool to check actual state.',
|
|
43
|
+
state: 'Check current task state from now.md before assuming completion.',
|
|
44
|
+
invented: 'Verify prerequisites exist (package.json, git remote) before claiming actions.',
|
|
45
|
+
}
|
|
46
|
+
return suggestions[type] || 'Verify actual state before proceeding.'
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Detect potential hallucination patterns in output
|
|
51
|
+
*/
|
|
52
|
+
export function detectHallucination(output: string): HallucinationResult {
|
|
53
|
+
if (!output || typeof output !== 'string') {
|
|
54
|
+
return { detected: false }
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
for (const { pattern, type, description } of HALLUCINATION_PATTERNS) {
|
|
58
|
+
if (pattern.test(output)) {
|
|
59
|
+
return {
|
|
60
|
+
detected: true,
|
|
61
|
+
type,
|
|
62
|
+
pattern: pattern.source,
|
|
63
|
+
description,
|
|
64
|
+
message: `Potential hallucination detected: ${description}`,
|
|
65
|
+
suggestion: getHallucinationSuggestion(type),
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return { detected: false }
|
|
71
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Loop Detection & User Escalation
|
|
3
|
+
*
|
|
4
|
+
* Detects when commands are failing repeatedly and escalates to user
|
|
5
|
+
* instead of continuing in infinite loops.
|
|
6
|
+
*
|
|
7
|
+
* OPTIMIZATION (P2.4): Loop Detection
|
|
8
|
+
* - Track attempt counts per command/error type
|
|
9
|
+
* - Auto-escalate after 3 failed attempts
|
|
10
|
+
* - Provide specific help based on error patterns
|
|
11
|
+
*
|
|
12
|
+
* ANTI-HALLUCINATION: Detects contradictory/impossible outputs
|
|
13
|
+
* - Patterns that indicate Claude is hallucinating (saying file exists when it doesn't)
|
|
14
|
+
* - Contradictory statements in same response
|
|
15
|
+
* - Completing tasks that were never started
|
|
16
|
+
*
|
|
17
|
+
* Source: Augment Code pattern
|
|
18
|
+
* "If you notice yourself going around in circles... ask the user for help"
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
export type {
|
|
22
|
+
ErrorEntry,
|
|
23
|
+
AttemptRecord,
|
|
24
|
+
ErrorPattern,
|
|
25
|
+
EscalationInfo,
|
|
26
|
+
AttemptResult,
|
|
27
|
+
AttemptInfo,
|
|
28
|
+
HallucinationPattern,
|
|
29
|
+
HallucinationResult,
|
|
30
|
+
OutputAnalysis,
|
|
31
|
+
} from './types'
|
|
32
|
+
|
|
33
|
+
export { HALLUCINATION_PATTERNS, detectHallucination, getHallucinationSuggestion } from './hallucination'
|
|
34
|
+
export { isSimilarError, analyzeErrorPattern, generateEscalationMessage, generateSuggestion } from './error-analysis'
|
|
35
|
+
export { LoopDetector } from './loop-detector'
|
|
36
|
+
|
|
37
|
+
import { LoopDetector } from './loop-detector'
|
|
38
|
+
|
|
39
|
+
// Singleton instance
|
|
40
|
+
const loopDetector = new LoopDetector()
|
|
41
|
+
export default loopDetector
|