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,365 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Intelligent Context Filtering System
|
|
3
|
+
*
|
|
4
|
+
* Reduces context window usage by 70-90% by loading only
|
|
5
|
+
* relevant files for each specialized agent
|
|
6
|
+
*
|
|
7
|
+
* @version 1.0.0
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import fs from 'fs/promises'
|
|
11
|
+
import path from 'path'
|
|
12
|
+
import { glob } from 'glob'
|
|
13
|
+
import log from '../utils/logger'
|
|
14
|
+
|
|
15
|
+
interface Agent {
|
|
16
|
+
name: string
|
|
17
|
+
[key: string]: unknown
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
interface Task {
|
|
21
|
+
[key: string]: unknown
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface FullContext {
|
|
25
|
+
estimatedFiles?: string[]
|
|
26
|
+
fileCount?: number
|
|
27
|
+
[key: string]: unknown
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
interface Patterns {
|
|
31
|
+
include: string[]
|
|
32
|
+
exclude: string[]
|
|
33
|
+
realExtensions?: Record<string, number>
|
|
34
|
+
projectStructure?: string[]
|
|
35
|
+
configFiles?: string[]
|
|
36
|
+
detectedTech?: Record<string, unknown>
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
interface Metrics {
|
|
40
|
+
originalFiles: number
|
|
41
|
+
filteredFiles: number
|
|
42
|
+
reductionPercent: number
|
|
43
|
+
processingTime: number
|
|
44
|
+
effectiveness: string
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
interface FilterResult {
|
|
48
|
+
files: string[]
|
|
49
|
+
patterns: {
|
|
50
|
+
preEstimated?: boolean
|
|
51
|
+
detectedTech?: Record<string, unknown>
|
|
52
|
+
projectStructure?: string[]
|
|
53
|
+
agentic?: boolean
|
|
54
|
+
}
|
|
55
|
+
metrics: Metrics
|
|
56
|
+
agent: string
|
|
57
|
+
filtered: boolean
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
class ContextFilter {
|
|
61
|
+
fileCache: Map<string, unknown>
|
|
62
|
+
|
|
63
|
+
constructor() {
|
|
64
|
+
// Cache for file analysis
|
|
65
|
+
this.fileCache = new Map()
|
|
66
|
+
// NO HARDCODED PATTERNS - Everything is agentic
|
|
67
|
+
// Claude decides what files are needed based on analysis
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Main entry point - filters context based on agent and task
|
|
72
|
+
* IMPROVED: Supports pre-estimated files for lazy loading
|
|
73
|
+
*/
|
|
74
|
+
async filterForAgent(
|
|
75
|
+
agent: Agent,
|
|
76
|
+
task: Task,
|
|
77
|
+
projectPath: string,
|
|
78
|
+
fullContext: FullContext = {}
|
|
79
|
+
): Promise<FilterResult> {
|
|
80
|
+
const startTime = Date.now()
|
|
81
|
+
|
|
82
|
+
// If files were pre-estimated (lazy loading), use them
|
|
83
|
+
if (fullContext.estimatedFiles && fullContext.estimatedFiles.length > 0) {
|
|
84
|
+
const filteredFiles = fullContext.estimatedFiles
|
|
85
|
+
|
|
86
|
+
const metrics = this.calculateMetrics(fullContext.fileCount || filteredFiles.length, filteredFiles.length, startTime)
|
|
87
|
+
|
|
88
|
+
return {
|
|
89
|
+
files: filteredFiles,
|
|
90
|
+
patterns: { preEstimated: true },
|
|
91
|
+
metrics,
|
|
92
|
+
agent: agent.name,
|
|
93
|
+
filtered: true,
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Fallback to traditional filtering if no pre-estimation
|
|
98
|
+
// Determine what files this agent needs
|
|
99
|
+
const relevantPatterns = await this.determineRelevantPatterns(agent, task, projectPath)
|
|
100
|
+
|
|
101
|
+
// Load only relevant files
|
|
102
|
+
const filteredFiles = await this.loadRelevantFiles(projectPath, relevantPatterns)
|
|
103
|
+
|
|
104
|
+
// Calculate reduction metrics
|
|
105
|
+
const metrics = this.calculateMetrics(
|
|
106
|
+
fullContext.fileCount || 1000, // estimate if not provided
|
|
107
|
+
filteredFiles.length,
|
|
108
|
+
startTime
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
return {
|
|
112
|
+
files: filteredFiles,
|
|
113
|
+
patterns: {
|
|
114
|
+
detectedTech: relevantPatterns.detectedTech,
|
|
115
|
+
projectStructure: relevantPatterns.projectStructure,
|
|
116
|
+
agentic: true, // Flag indicating this was agentic, not hardcoded
|
|
117
|
+
},
|
|
118
|
+
metrics,
|
|
119
|
+
agent: agent.name,
|
|
120
|
+
filtered: true,
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Determine which patterns to use based on agent and task
|
|
126
|
+
*
|
|
127
|
+
* 100% AGENTIC: Uses analyzer for I/O, no hardcoded tech detection.
|
|
128
|
+
* Claude decides what files matter based on actual project analysis.
|
|
129
|
+
*/
|
|
130
|
+
async determineRelevantPatterns(_agent: Agent, _task: Task, projectPath: string): Promise<Patterns> {
|
|
131
|
+
const { default: analyzer } = await import('../domain/analyzer')
|
|
132
|
+
analyzer.init(projectPath)
|
|
133
|
+
|
|
134
|
+
// Get REAL file extensions from project (not assumed)
|
|
135
|
+
const realExtensions = await analyzer.getFileExtensions()
|
|
136
|
+
|
|
137
|
+
// Get REAL directory structure (not assumed)
|
|
138
|
+
const projectStructure = await analyzer.listDirectories()
|
|
139
|
+
|
|
140
|
+
// Get config files that exist (not hardcoded list)
|
|
141
|
+
const configFiles = await analyzer.listConfigFiles()
|
|
142
|
+
|
|
143
|
+
// Build patterns from ACTUAL project data
|
|
144
|
+
const patterns: Patterns = {
|
|
145
|
+
include: [],
|
|
146
|
+
exclude: ['node_modules', '.git', 'dist', 'build', 'coverage', '.next', '.nuxt', 'target', 'vendor'],
|
|
147
|
+
realExtensions, // Actual extensions found in project
|
|
148
|
+
projectStructure, // Actual directories
|
|
149
|
+
configFiles, // Actual config files
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return patterns
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Detect actual project structure (no assumptions)
|
|
157
|
+
*/
|
|
158
|
+
async detectProjectStructure(projectPath: string): Promise<string[]> {
|
|
159
|
+
try {
|
|
160
|
+
const entries = await fs.readdir(projectPath, { withFileTypes: true })
|
|
161
|
+
const directories = entries.filter((e) => e.isDirectory() && !e.name.startsWith('.')).map((e) => e.name)
|
|
162
|
+
return directories
|
|
163
|
+
} catch {
|
|
164
|
+
return []
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Detect technologies used in the project
|
|
170
|
+
*
|
|
171
|
+
* 100% AGENTIC: Uses analyzer for raw data.
|
|
172
|
+
* No categorization - Claude decides what's relevant.
|
|
173
|
+
*/
|
|
174
|
+
async detectProjectTechnologies(
|
|
175
|
+
projectPath: string
|
|
176
|
+
): Promise<{ extensions: Record<string, number>; directories: string[]; configFiles: string[] }> {
|
|
177
|
+
try {
|
|
178
|
+
const { default: analyzer } = await import('../domain/analyzer')
|
|
179
|
+
analyzer.init(projectPath)
|
|
180
|
+
|
|
181
|
+
// Return raw data for Claude to analyze
|
|
182
|
+
return {
|
|
183
|
+
extensions: await analyzer.getFileExtensions(),
|
|
184
|
+
directories: await analyzer.listDirectories(),
|
|
185
|
+
configFiles: await analyzer.listConfigFiles(),
|
|
186
|
+
}
|
|
187
|
+
} catch (error) {
|
|
188
|
+
log.error('Error detecting project data:', (error as Error).message)
|
|
189
|
+
return { extensions: {}, directories: [], configFiles: [] }
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Load only relevant files based on patterns
|
|
195
|
+
*/
|
|
196
|
+
async loadRelevantFiles(projectPath: string, patterns: Patterns): Promise<string[]> {
|
|
197
|
+
const files: string[] = []
|
|
198
|
+
|
|
199
|
+
try {
|
|
200
|
+
// Build glob patterns
|
|
201
|
+
const globPatterns = this.buildGlobPatterns(patterns)
|
|
202
|
+
|
|
203
|
+
// Execute glob searches
|
|
204
|
+
for (const pattern of globPatterns) {
|
|
205
|
+
const matches = await glob(pattern, {
|
|
206
|
+
cwd: projectPath,
|
|
207
|
+
ignore: patterns.exclude.map((ex) => `**/${ex}/**`),
|
|
208
|
+
nodir: true,
|
|
209
|
+
follow: false,
|
|
210
|
+
})
|
|
211
|
+
|
|
212
|
+
// Ensure matches is always an array (glob v10+ returns array, but be defensive)
|
|
213
|
+
if (Array.isArray(matches)) {
|
|
214
|
+
files.push(...matches)
|
|
215
|
+
} else if (matches) {
|
|
216
|
+
// Convert iterable to array if needed
|
|
217
|
+
files.push(...Array.from(matches as Iterable<string>))
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Remove duplicates and sort
|
|
222
|
+
const uniqueFiles = [...new Set(files)].sort()
|
|
223
|
+
|
|
224
|
+
// Limit to reasonable number
|
|
225
|
+
const maxFiles = 300
|
|
226
|
+
if (uniqueFiles.length > maxFiles) {
|
|
227
|
+
log.debug(`Limiting context to ${maxFiles} files`)
|
|
228
|
+
return uniqueFiles.slice(0, maxFiles)
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Expand context with related files
|
|
232
|
+
const expandedFiles = await this.expandContext(uniqueFiles, projectPath)
|
|
233
|
+
|
|
234
|
+
return expandedFiles.slice(0, maxFiles)
|
|
235
|
+
} catch (error) {
|
|
236
|
+
log.error('Error loading files:', (error as Error).message)
|
|
237
|
+
return []
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Build glob patterns from pattern configuration
|
|
243
|
+
*
|
|
244
|
+
* 100% AGENTIC: Uses REAL extensions from project, not hardcoded mapping.
|
|
245
|
+
* No language→extension assumptions.
|
|
246
|
+
*/
|
|
247
|
+
buildGlobPatterns(patterns: Patterns): string[] {
|
|
248
|
+
const globs: string[] = []
|
|
249
|
+
|
|
250
|
+
// Use REAL extensions found in project (no hardcoded mapping)
|
|
251
|
+
if (patterns.realExtensions && Object.keys(patterns.realExtensions).length > 0) {
|
|
252
|
+
// Get extensions that actually exist in this project
|
|
253
|
+
const extensions = Object.keys(patterns.realExtensions)
|
|
254
|
+
.filter((ext) => ext.startsWith('.')) // Only valid extensions
|
|
255
|
+
.slice(0, 20) // Limit to top 20 most common
|
|
256
|
+
|
|
257
|
+
if (extensions.length > 0) {
|
|
258
|
+
globs.push(`**/*{${extensions.join(',')}}`)
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Use REAL project structure (no assumptions)
|
|
263
|
+
if (patterns.projectStructure && patterns.projectStructure.length > 0) {
|
|
264
|
+
patterns.projectStructure.forEach((dir) => {
|
|
265
|
+
// Exclude universal noise directories
|
|
266
|
+
if (!patterns.exclude.includes(dir)) {
|
|
267
|
+
globs.push(`${dir}/**/*`)
|
|
268
|
+
}
|
|
269
|
+
})
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// Include REAL config files that exist (not hardcoded list)
|
|
273
|
+
if (patterns.configFiles && patterns.configFiles.length > 0) {
|
|
274
|
+
patterns.configFiles.forEach((file) => {
|
|
275
|
+
globs.push(file)
|
|
276
|
+
})
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// Fallback: if no patterns detected, include all source-like files
|
|
280
|
+
if (globs.length === 0) {
|
|
281
|
+
globs.push('**/*')
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
return globs
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Calculate metrics for context reduction
|
|
289
|
+
*/
|
|
290
|
+
calculateMetrics(originalCount: number, filteredCount: number, startTime: number): Metrics {
|
|
291
|
+
const reduction = originalCount > 0 ? Math.round(((originalCount - filteredCount) / originalCount) * 100) : 0
|
|
292
|
+
|
|
293
|
+
return {
|
|
294
|
+
originalFiles: originalCount,
|
|
295
|
+
filteredFiles: filteredCount,
|
|
296
|
+
reductionPercent: reduction,
|
|
297
|
+
processingTime: Date.now() - startTime,
|
|
298
|
+
effectiveness: reduction > 70 ? 'high' : reduction > 40 ? 'medium' : 'low',
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Check if file exists
|
|
304
|
+
*/
|
|
305
|
+
async fileExists(filePath: string): Promise<boolean> {
|
|
306
|
+
try {
|
|
307
|
+
await fs.access(filePath)
|
|
308
|
+
return true
|
|
309
|
+
} catch {
|
|
310
|
+
return false
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Expand context with related files (tests, styles, etc.)
|
|
316
|
+
*/
|
|
317
|
+
async expandContext(files: string[], _projectPath?: string): Promise<string[]> {
|
|
318
|
+
const expanded = new Set(files)
|
|
319
|
+
|
|
320
|
+
for (const file of files) {
|
|
321
|
+
const ext = path.extname(file)
|
|
322
|
+
const basename = path.basename(file, ext)
|
|
323
|
+
const dirname = path.dirname(file)
|
|
324
|
+
|
|
325
|
+
// 1. Look for test files
|
|
326
|
+
const testPatterns = [
|
|
327
|
+
path.join(dirname, `${basename}.test${ext}`),
|
|
328
|
+
path.join(dirname, `${basename}.spec${ext}`),
|
|
329
|
+
path.join(dirname, '__tests__', `${basename}.test${ext}`),
|
|
330
|
+
path.join(dirname, 'tests', `${basename}.test${ext}`),
|
|
331
|
+
]
|
|
332
|
+
|
|
333
|
+
// 2. Look for style files (for UI components)
|
|
334
|
+
const stylePatterns = [
|
|
335
|
+
path.join(dirname, `${basename}.css`),
|
|
336
|
+
path.join(dirname, `${basename}.scss`),
|
|
337
|
+
path.join(dirname, `${basename}.module.css`),
|
|
338
|
+
path.join(dirname, `${basename}.module.scss`),
|
|
339
|
+
]
|
|
340
|
+
|
|
341
|
+
// Check if these related files exist
|
|
342
|
+
const potentialFiles = [...testPatterns, ...stylePatterns]
|
|
343
|
+
|
|
344
|
+
for (const potential of potentialFiles) {
|
|
345
|
+
if (!expanded.has(potential) && (await this.fileExists(potential))) {
|
|
346
|
+
expanded.add(potential)
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
return Array.from(expanded).sort()
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* Get filter statistics
|
|
356
|
+
*/
|
|
357
|
+
getStatistics(): { cachedFiles: number; agentic: boolean } {
|
|
358
|
+
return {
|
|
359
|
+
cachedFiles: this.fileCache.size,
|
|
360
|
+
agentic: true, // All filtering is now agentic, no hardcoded patterns
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
export default ContextFilter
|
|
@@ -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
|
+
}
|