prjct-cli 0.11.5 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +58 -0
- package/README.md +81 -25
- package/bin/dev.js +1 -1
- package/bin/generate-views.js +209 -0
- package/bin/migrate-to-json.js +742 -0
- package/bin/prjct +5 -5
- package/bin/serve.js +226 -50
- package/core/__tests__/agentic/{memory-system.test.js → memory-system.test.ts} +12 -23
- package/core/__tests__/agentic/{plan-mode.test.js → plan-mode.test.ts} +26 -24
- package/core/__tests__/agentic/{prompt-builder.test.js → prompt-builder.test.ts} +3 -8
- package/core/__tests__/utils/{date-helper.test.js → date-helper.test.ts} +19 -30
- package/core/__tests__/utils/{output.test.js → output.test.ts} +12 -24
- package/core/agentic/agent-router.ts +137 -0
- package/core/agentic/chain-of-thought.ts +228 -0
- package/core/agentic/command-executor/command-executor.ts +384 -0
- package/core/agentic/command-executor/index.ts +16 -0
- package/core/agentic/command-executor/status-signal.ts +38 -0
- package/core/agentic/command-executor/types.ts +79 -0
- package/core/agentic/command-executor.ts +8 -0
- package/core/agentic/{context-builder.js → context-builder.ts} +92 -81
- package/core/agentic/context-filter.ts +365 -0
- package/core/agentic/ground-truth/index.ts +76 -0
- package/core/agentic/ground-truth/types.ts +33 -0
- package/core/agentic/ground-truth/utils.ts +48 -0
- package/core/agentic/ground-truth/verifiers/analyze.ts +54 -0
- package/core/agentic/ground-truth/verifiers/done.ts +75 -0
- package/core/agentic/ground-truth/verifiers/feature.ts +70 -0
- package/core/agentic/ground-truth/verifiers/index.ts +37 -0
- package/core/agentic/ground-truth/verifiers/init.ts +52 -0
- package/core/agentic/ground-truth/verifiers/now.ts +57 -0
- package/core/agentic/ground-truth/verifiers/ship.ts +85 -0
- package/core/agentic/ground-truth/verifiers/spec.ts +45 -0
- package/core/agentic/ground-truth/verifiers/sync.ts +47 -0
- package/core/agentic/ground-truth/verifiers.ts +6 -0
- package/core/agentic/ground-truth.ts +8 -0
- package/core/agentic/loop-detector/error-analysis.ts +97 -0
- package/core/agentic/loop-detector/hallucination.ts +71 -0
- package/core/agentic/loop-detector/index.ts +41 -0
- package/core/agentic/loop-detector/loop-detector.ts +222 -0
- package/core/agentic/loop-detector/types.ts +66 -0
- package/core/agentic/loop-detector.ts +8 -0
- package/core/agentic/memory-system/history.ts +53 -0
- package/core/agentic/memory-system/index.ts +192 -0
- package/core/agentic/memory-system/patterns.ts +156 -0
- package/core/agentic/memory-system/semantic-memories.ts +277 -0
- package/core/agentic/memory-system/session.ts +21 -0
- package/core/agentic/memory-system/types.ts +159 -0
- package/core/agentic/memory-system.ts +8 -0
- package/core/agentic/parallel-tools.ts +165 -0
- package/core/agentic/plan-mode/approval.ts +57 -0
- package/core/agentic/plan-mode/constants.ts +44 -0
- package/core/agentic/plan-mode/index.ts +28 -0
- package/core/agentic/plan-mode/plan-mode.ts +406 -0
- package/core/agentic/plan-mode/types.ts +193 -0
- package/core/agentic/plan-mode.ts +8 -0
- package/core/agentic/prompt-builder.ts +566 -0
- package/core/agentic/response-templates.ts +164 -0
- package/core/agentic/semantic-compression.ts +273 -0
- package/core/agentic/services.ts +206 -0
- package/core/agentic/smart-context.ts +476 -0
- package/core/agentic/{template-loader.js → template-loader.ts} +27 -16
- package/core/agentic/think-blocks.ts +202 -0
- package/core/agentic/tool-registry.ts +119 -0
- package/core/agentic/validation-rules.ts +313 -0
- package/core/agents/index.ts +28 -0
- package/core/agents/performance.ts +444 -0
- package/core/agents/types.ts +126 -0
- package/core/bus/{index.js → index.ts} +57 -61
- package/core/command-registry/categories.ts +23 -0
- package/core/command-registry/commands.ts +15 -0
- package/core/command-registry/core-commands.ts +319 -0
- package/core/command-registry/index.ts +158 -0
- package/core/command-registry/optional-commands.ts +119 -0
- package/core/command-registry/setup-commands.ts +53 -0
- package/core/command-registry/types.ts +59 -0
- package/core/command-registry.ts +9 -0
- package/core/commands/analysis.ts +298 -0
- package/core/commands/analytics.ts +288 -0
- package/core/commands/base.ts +273 -0
- package/core/commands/index.ts +211 -0
- package/core/commands/maintenance.ts +226 -0
- package/core/commands/planning.ts +311 -0
- package/core/commands/setup.ts +309 -0
- package/core/commands/shipping.ts +188 -0
- package/core/commands/types.ts +183 -0
- package/core/commands/workflow.ts +226 -0
- package/core/commands.ts +11 -0
- package/core/constants/formats.ts +187 -0
- package/core/constants/index.ts +7 -0
- package/core/{context-sync.js → context-sync.ts} +59 -26
- package/core/data/agents-manager.ts +76 -0
- package/core/data/analysis-manager.ts +83 -0
- package/core/data/base-manager.ts +156 -0
- package/core/data/ideas-manager.ts +81 -0
- package/core/data/index.ts +32 -0
- package/core/data/outcomes-manager.ts +96 -0
- package/core/data/project-manager.ts +75 -0
- package/core/data/roadmap-manager.ts +118 -0
- package/core/data/shipped-manager.ts +65 -0
- package/core/data/state-manager.ts +214 -0
- package/core/domain/{agent-generator.js → agent-generator.ts} +77 -57
- package/core/domain/{agent-loader.js → agent-loader.ts} +65 -56
- package/core/domain/{agent-matcher.js → agent-matcher.ts} +51 -24
- package/core/domain/{agent-validator.js → agent-validator.ts} +70 -37
- package/core/domain/{analyzer.js → analyzer.ts} +91 -85
- package/core/domain/{architect-session.js → architect-session.ts} +49 -34
- package/core/domain/{architecture-generator.js → architecture-generator.ts} +25 -13
- package/core/domain/{context-estimator.js → context-estimator.ts} +57 -36
- package/core/domain/{product-standards.js → product-standards.ts} +40 -26
- package/core/domain/{smart-cache.js → smart-cache.ts} +39 -30
- package/core/domain/{snapshot-manager.js → snapshot-manager.ts} +103 -100
- package/core/domain/{task-analyzer.js → task-analyzer.ts} +82 -43
- package/core/domain/task-stack/index.ts +19 -0
- package/core/domain/task-stack/parser.ts +86 -0
- package/core/domain/task-stack/storage.ts +123 -0
- package/core/domain/task-stack/task-stack.ts +340 -0
- package/core/domain/task-stack/types.ts +51 -0
- package/core/domain/task-stack.ts +8 -0
- package/core/{index.js → index.ts} +61 -18
- package/core/infrastructure/{agent-detector.js → agent-detector.ts} +55 -19
- package/core/infrastructure/agents/{claude-agent.js → claude-agent.ts} +61 -21
- package/core/infrastructure/{author-detector.js → author-detector.ts} +42 -49
- package/core/infrastructure/{capability-installer.js → capability-installer.ts} +51 -27
- package/core/infrastructure/{command-installer.js → command-installer/command-installer.ts} +43 -144
- package/core/infrastructure/command-installer/global-config.ts +106 -0
- package/core/infrastructure/command-installer/index.ts +25 -0
- package/core/infrastructure/command-installer/types.ts +41 -0
- package/core/infrastructure/command-installer.ts +8 -0
- package/core/infrastructure/{config-manager.js → config-manager.ts} +60 -80
- package/core/infrastructure/{editors-config.js → editors-config.ts} +33 -31
- package/core/infrastructure/legacy-installer-detector/cleanup.ts +216 -0
- package/core/infrastructure/legacy-installer-detector/detection.ts +95 -0
- package/core/infrastructure/legacy-installer-detector/index.ts +171 -0
- package/core/infrastructure/legacy-installer-detector/migration.ts +87 -0
- package/core/infrastructure/legacy-installer-detector/types.ts +42 -0
- package/core/infrastructure/legacy-installer-detector.ts +7 -0
- package/core/infrastructure/migrator/file-operations.ts +125 -0
- package/core/infrastructure/migrator/index.ts +288 -0
- package/core/infrastructure/migrator/project-scanner.ts +89 -0
- package/core/infrastructure/migrator/reports.ts +117 -0
- package/core/infrastructure/migrator/types.ts +124 -0
- package/core/infrastructure/migrator/validation.ts +94 -0
- package/core/infrastructure/migrator/version-migration.ts +117 -0
- package/core/infrastructure/migrator.ts +10 -0
- package/core/infrastructure/{path-manager.js → path-manager.ts} +51 -91
- package/core/infrastructure/session-manager/index.ts +23 -0
- package/core/infrastructure/session-manager/migration.ts +88 -0
- package/core/infrastructure/session-manager/session-manager.ts +307 -0
- package/core/infrastructure/session-manager/types.ts +45 -0
- package/core/infrastructure/session-manager.ts +8 -0
- package/core/infrastructure/{setup.js → setup.ts} +29 -21
- package/core/infrastructure/{update-checker.js → update-checker.ts} +40 -18
- package/core/outcomes/analyzer.ts +333 -0
- package/core/outcomes/index.ts +34 -0
- package/core/outcomes/recorder.ts +194 -0
- package/core/outcomes/types.ts +145 -0
- package/core/plugin/{hooks.js → hooks.ts} +56 -58
- package/core/plugin/{index.js → index.ts} +19 -8
- package/core/plugin/{loader.js → loader.ts} +87 -69
- package/core/plugin/{registry.js → registry.ts} +49 -45
- package/core/plugins/{webhook.js → webhook.ts} +43 -27
- package/core/schemas/agents.ts +27 -0
- package/core/schemas/analysis.ts +41 -0
- package/core/schemas/ideas.ts +83 -0
- package/core/schemas/index.ts +73 -0
- package/core/schemas/outcomes.ts +22 -0
- package/core/schemas/project.ts +26 -0
- package/core/schemas/roadmap.ts +90 -0
- package/core/schemas/shipped.ts +82 -0
- package/core/schemas/state.ts +107 -0
- package/core/session/index.ts +17 -0
- package/core/session/{metrics.js → metrics.ts} +64 -46
- package/core/session/{index.js → session-manager.ts} +51 -117
- package/core/session/types.ts +29 -0
- package/core/session/utils.ts +57 -0
- package/core/state/index.ts +25 -0
- package/core/state/manager.ts +376 -0
- package/core/state/types.ts +185 -0
- package/core/tsconfig.json +22 -0
- package/core/types/index.ts +506 -0
- package/core/utils/{animations.js → animations.ts} +74 -28
- package/core/utils/{branding.js → branding.ts} +29 -4
- package/core/utils/{date-helper.js → date-helper.ts} +31 -74
- package/core/utils/file-helper.ts +262 -0
- package/core/utils/{jsonl-helper.js → jsonl-helper.ts} +71 -107
- package/core/utils/{logger.js → logger.ts} +24 -12
- package/core/utils/{output.js → output.ts} +25 -13
- package/core/utils/{project-capabilities.js → project-capabilities.ts} +31 -18
- package/core/utils/{session-helper.js → session-helper.ts} +79 -66
- package/core/utils/{version.js → version.ts} +23 -31
- package/core/view-generator.ts +536 -0
- package/package.json +23 -17
- package/packages/shared/.turbo/turbo-build.log +14 -0
- package/packages/shared/dist/index.d.ts +8 -613
- package/packages/shared/dist/index.d.ts.map +1 -0
- package/packages/shared/dist/index.js +4110 -118
- package/packages/shared/dist/schemas.d.ts +408 -0
- package/packages/shared/dist/schemas.d.ts.map +1 -0
- package/packages/shared/dist/types.d.ts +144 -0
- package/packages/shared/dist/types.d.ts.map +1 -0
- package/packages/shared/dist/unified.d.ts +139 -0
- package/packages/shared/dist/unified.d.ts.map +1 -0
- package/packages/shared/dist/utils.d.ts +60 -0
- package/packages/shared/dist/utils.d.ts.map +1 -0
- package/packages/shared/package.json +4 -4
- package/packages/shared/src/index.ts +1 -0
- package/packages/shared/src/unified.ts +174 -0
- package/packages/web/app/api/claude/sessions/route.ts +1 -1
- package/packages/web/app/api/claude/status/route.ts +1 -1
- package/packages/web/app/api/migrate/route.ts +46 -0
- package/packages/web/app/api/projects/[id]/route.ts +1 -1
- package/packages/web/app/api/projects/[id]/stats/route.ts +30 -2
- package/packages/web/app/api/projects/[id]/status/route.ts +1 -1
- package/packages/web/app/api/projects/route.ts +1 -1
- package/packages/web/app/api/settings/route.ts +97 -0
- package/packages/web/app/api/v2/projects/[id]/unified/route.ts +57 -0
- package/packages/web/app/globals.css +38 -0
- package/packages/web/app/layout.tsx +10 -2
- package/packages/web/app/page.tsx +9 -224
- package/packages/web/app/project/[id]/page.tsx +191 -63
- package/packages/web/app/project/[id]/stats/loading.tsx +43 -0
- package/packages/web/app/project/[id]/stats/page.tsx +204 -163
- package/packages/web/app/settings/page.tsx +222 -2
- package/packages/web/components/ActivityTimeline/ActivityTimeline.constants.ts +2 -0
- package/packages/web/components/ActivityTimeline/ActivityTimeline.tsx +50 -0
- package/packages/web/components/ActivityTimeline/ActivityTimeline.types.ts +8 -0
- package/packages/web/components/ActivityTimeline/hooks/index.ts +2 -0
- package/packages/web/components/ActivityTimeline/hooks/useExpandable.ts +9 -0
- package/packages/web/components/ActivityTimeline/hooks/useGroupedEvents.ts +23 -0
- package/packages/web/components/ActivityTimeline/index.ts +2 -0
- package/packages/web/components/AgentsCard/AgentsCard.tsx +63 -0
- package/packages/web/components/AgentsCard/AgentsCard.types.ts +13 -0
- package/packages/web/components/AgentsCard/index.ts +2 -0
- package/packages/web/components/AppSidebar/AppSidebar.tsx +134 -0
- package/packages/web/components/AppSidebar/index.ts +1 -0
- package/packages/web/components/BackLink/BackLink.tsx +18 -0
- package/packages/web/components/BackLink/BackLink.types.ts +5 -0
- package/packages/web/components/BackLink/index.ts +2 -0
- package/packages/web/components/BentoCard/BentoCard.constants.ts +16 -0
- package/packages/web/components/BentoCard/BentoCard.tsx +47 -0
- package/packages/web/components/BentoCard/BentoCard.types.ts +15 -0
- package/packages/web/components/BentoCard/index.ts +2 -0
- package/packages/web/components/BentoCardSkeleton/BentoCardSkeleton.constants.ts +9 -0
- package/packages/web/components/BentoCardSkeleton/BentoCardSkeleton.tsx +18 -0
- package/packages/web/components/BentoCardSkeleton/BentoCardSkeleton.types.ts +5 -0
- package/packages/web/components/BentoCardSkeleton/index.ts +2 -0
- package/packages/web/components/{stats → BentoGrid}/BentoGrid.tsx +4 -8
- package/packages/web/components/BentoGrid/BentoGrid.types.ts +4 -0
- package/packages/web/components/BentoGrid/index.ts +2 -0
- package/packages/web/components/CommandButton/index.ts +1 -0
- package/packages/web/components/ConnectionStatus/index.ts +1 -0
- package/packages/web/components/DashboardContent/DashboardContent.tsx +254 -0
- package/packages/web/components/DashboardContent/index.ts +1 -0
- package/packages/web/components/DateGroup/DateGroup.tsx +18 -0
- package/packages/web/components/DateGroup/DateGroup.types.ts +6 -0
- package/packages/web/components/DateGroup/DateGroup.utils.ts +11 -0
- package/packages/web/components/DateGroup/index.ts +2 -0
- package/packages/web/components/{stats → EmptyState}/EmptyState.tsx +1 -10
- package/packages/web/components/EmptyState/EmptyState.types.ts +10 -0
- package/packages/web/components/EmptyState/index.ts +2 -0
- package/packages/web/components/EventRow/EventRow.constants.ts +10 -0
- package/packages/web/components/EventRow/EventRow.tsx +49 -0
- package/packages/web/components/EventRow/EventRow.types.ts +7 -0
- package/packages/web/components/EventRow/EventRow.utils.ts +49 -0
- package/packages/web/components/EventRow/index.ts +2 -0
- package/packages/web/components/ExpandButton/ExpandButton.tsx +18 -0
- package/packages/web/components/ExpandButton/ExpandButton.types.ts +6 -0
- package/packages/web/components/ExpandButton/index.ts +2 -0
- package/packages/web/components/HealthGradientBackground/HealthGradientBackground.tsx +14 -0
- package/packages/web/components/HealthGradientBackground/HealthGradientBackground.types.ts +5 -0
- package/packages/web/components/HealthGradientBackground/HealthGradientBackground.utils.ts +13 -0
- package/packages/web/components/HealthGradientBackground/index.ts +2 -0
- package/packages/web/components/HeroSection/HeroSection.tsx +55 -0
- package/packages/web/components/HeroSection/HeroSection.types.ts +14 -0
- package/packages/web/components/HeroSection/HeroSection.utils.ts +7 -0
- package/packages/web/components/HeroSection/hooks/index.ts +2 -0
- package/packages/web/components/HeroSection/hooks/useCountUp.ts +45 -0
- package/packages/web/components/HeroSection/hooks/useWeeklyActivity.ts +18 -0
- package/packages/web/components/HeroSection/index.ts +2 -0
- package/packages/web/components/{stats → IdeasCard}/IdeasCard.tsx +3 -14
- package/packages/web/components/IdeasCard/IdeasCard.types.ts +9 -0
- package/packages/web/components/IdeasCard/index.ts +2 -0
- package/packages/web/components/InsightMessage/InsightMessage.tsx +9 -0
- package/packages/web/components/InsightMessage/InsightMessage.types.ts +3 -0
- package/packages/web/components/InsightMessage/index.ts +2 -0
- package/packages/web/components/Logo/index.ts +1 -0
- package/packages/web/components/MarkdownContent/index.ts +1 -0
- package/packages/web/components/NowCard/NowCard.tsx +93 -0
- package/packages/web/components/NowCard/NowCard.types.ts +15 -0
- package/packages/web/components/NowCard/index.ts +2 -0
- package/packages/web/components/ProgressRing/ProgressRing.constants.ts +20 -0
- package/packages/web/components/{stats → ProgressRing}/ProgressRing.tsx +4 -27
- package/packages/web/components/ProgressRing/ProgressRing.types.ts +11 -0
- package/packages/web/components/ProgressRing/index.ts +2 -0
- package/packages/web/components/ProjectAvatar/index.ts +1 -0
- package/packages/web/components/Providers/index.ts +1 -0
- package/packages/web/components/QueueCard/QueueCard.tsx +72 -0
- package/packages/web/components/QueueCard/QueueCard.types.ts +11 -0
- package/packages/web/components/QueueCard/QueueCard.utils.ts +12 -0
- package/packages/web/components/QueueCard/index.ts +2 -0
- package/packages/web/components/{stats → RoadmapCard}/RoadmapCard.tsx +3 -23
- package/packages/web/components/RoadmapCard/RoadmapCard.types.ts +15 -0
- package/packages/web/components/RoadmapCard/index.ts +2 -0
- package/packages/web/components/{stats → ShipsCard}/ShipsCard.tsx +4 -22
- package/packages/web/components/ShipsCard/ShipsCard.types.ts +12 -0
- package/packages/web/components/ShipsCard/ShipsCard.utils.ts +4 -0
- package/packages/web/components/ShipsCard/index.ts +2 -0
- package/packages/web/components/{stats → SparklineChart}/SparklineChart.tsx +1 -7
- package/packages/web/components/SparklineChart/SparklineChart.types.ts +6 -0
- package/packages/web/components/SparklineChart/index.ts +2 -0
- package/packages/web/components/StreakCard/StreakCard.constants.ts +2 -0
- package/packages/web/components/{stats → StreakCard}/StreakCard.tsx +5 -11
- package/packages/web/components/StreakCard/StreakCard.types.ts +4 -0
- package/packages/web/components/StreakCard/index.ts +2 -0
- package/packages/web/components/TasksCounter/TasksCounter.tsx +14 -0
- package/packages/web/components/TasksCounter/TasksCounter.types.ts +3 -0
- package/packages/web/components/TasksCounter/index.ts +2 -0
- package/packages/web/components/TechStackBadges/index.ts +1 -0
- package/packages/web/components/{TerminalTab.tsx → TerminalTabs/TerminalTab.tsx} +11 -0
- package/packages/web/components/{TerminalTabs.tsx → TerminalTabs/TerminalTabs.tsx} +29 -28
- package/packages/web/components/TerminalTabs/index.ts +1 -0
- package/packages/web/components/VelocityBadge/VelocityBadge.tsx +27 -0
- package/packages/web/components/VelocityBadge/VelocityBadge.types.ts +3 -0
- package/packages/web/components/VelocityBadge/index.ts +2 -0
- package/packages/web/components/VelocityCard/VelocityCard.tsx +71 -0
- package/packages/web/components/VelocityCard/VelocityCard.types.ts +7 -0
- package/packages/web/components/VelocityCard/index.ts +2 -0
- package/packages/web/components/WeeklySparkline/WeeklySparkline.tsx +13 -0
- package/packages/web/components/WeeklySparkline/WeeklySparkline.types.ts +3 -0
- package/packages/web/components/WeeklySparkline/index.ts +2 -0
- package/packages/web/components/ui/input.tsx +21 -0
- package/packages/web/context/TerminalTabsContext.tsx +46 -1
- package/packages/web/hooks/useClaudeTerminal.ts +71 -21
- package/packages/web/hooks/useProjectStats.ts +55 -0
- package/packages/web/hooks/useProjects.ts +6 -6
- package/packages/web/lib/actions/projects.ts +15 -0
- package/packages/web/lib/json-loader.ts +630 -0
- package/packages/web/lib/services/index.ts +9 -0
- package/packages/web/lib/services/migration.server.ts +598 -0
- package/packages/web/lib/services/projects.server.ts +52 -0
- package/packages/web/lib/services/stats.server.ts +264 -0
- package/packages/web/lib/unified-loader.ts +396 -0
- package/packages/web/package.json +10 -7
- package/packages/web/server.ts +36 -6
- package/templates/commands/done.md +76 -32
- package/templates/commands/feature.md +121 -47
- package/templates/commands/idea.md +81 -8
- package/templates/commands/now.md +41 -17
- package/templates/commands/ship.md +64 -25
- package/templates/commands/sync.md +28 -3
- package/core/agentic/agent-router.js +0 -140
- package/core/agentic/chain-of-thought.js +0 -578
- package/core/agentic/command-executor.js +0 -417
- package/core/agentic/context-filter.js +0 -354
- package/core/agentic/ground-truth.js +0 -591
- package/core/agentic/loop-detector.js +0 -406
- package/core/agentic/memory-system.js +0 -845
- package/core/agentic/parallel-tools.js +0 -366
- package/core/agentic/plan-mode.js +0 -572
- package/core/agentic/prompt-builder.js +0 -352
- package/core/agentic/response-templates.js +0 -290
- package/core/agentic/semantic-compression.js +0 -517
- package/core/agentic/think-blocks.js +0 -657
- package/core/agentic/tool-registry.js +0 -184
- package/core/agentic/validation-rules.js +0 -380
- package/core/command-registry.js +0 -698
- package/core/commands.js +0 -2237
- package/core/domain/task-stack.js +0 -497
- package/core/infrastructure/legacy-installer-detector.js +0 -546
- package/core/infrastructure/migrator.js +0 -796
- package/core/infrastructure/session-manager.js +0 -390
- package/core/utils/file-helper.js +0 -329
- package/packages/web/app/api/projects/[id]/delete/route.ts +0 -21
- package/packages/web/app/api/stats/route.ts +0 -38
- package/packages/web/components/AppSidebar.tsx +0 -113
- package/packages/web/components/stats/ActivityTimeline.tsx +0 -201
- package/packages/web/components/stats/AgentsCard.tsx +0 -56
- package/packages/web/components/stats/BentoCard.tsx +0 -88
- package/packages/web/components/stats/HeroSection.tsx +0 -172
- package/packages/web/components/stats/NowCard.tsx +0 -71
- package/packages/web/components/stats/QueueCard.tsx +0 -58
- package/packages/web/components/stats/VelocityCard.tsx +0 -60
- package/packages/web/components/stats/index.ts +0 -17
- package/packages/web/hooks/useStats.ts +0 -28
- /package/packages/web/components/{CommandButton.tsx → CommandButton/CommandButton.tsx} +0 -0
- /package/packages/web/components/{ConnectionStatus.tsx → ConnectionStatus/ConnectionStatus.tsx} +0 -0
- /package/packages/web/components/{Logo.tsx → Logo/Logo.tsx} +0 -0
- /package/packages/web/components/{MarkdownContent.tsx → MarkdownContent/MarkdownContent.tsx} +0 -0
- /package/packages/web/components/{ProjectAvatar.tsx → ProjectAvatar/ProjectAvatar.tsx} +0 -0
- /package/packages/web/components/{providers.tsx → Providers/Providers.tsx} +0 -0
- /package/packages/web/components/{TechStackBadges.tsx → TechStackBadges/TechStackBadges.tsx} +0 -0
|
@@ -6,15 +6,49 @@
|
|
|
6
6
|
* @version 0.1
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
import fs from 'fs/promises'
|
|
10
|
+
import pathManager from '../infrastructure/path-manager'
|
|
11
|
+
import configManager from '../infrastructure/config-manager'
|
|
12
|
+
|
|
13
|
+
interface Paths {
|
|
14
|
+
now: string
|
|
15
|
+
next: string
|
|
16
|
+
context: string
|
|
17
|
+
shipped: string
|
|
18
|
+
metrics: string
|
|
19
|
+
ideas: string
|
|
20
|
+
roadmap: string
|
|
21
|
+
specs: string
|
|
22
|
+
memory: string
|
|
23
|
+
patterns: string
|
|
24
|
+
analysis: string
|
|
25
|
+
codePatterns: string
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface Context {
|
|
29
|
+
projectId: string | null
|
|
30
|
+
projectPath: string
|
|
31
|
+
globalPath: string
|
|
32
|
+
paths: Paths
|
|
33
|
+
params: Record<string, unknown>
|
|
34
|
+
timestamp: string
|
|
35
|
+
date: string
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
interface State {
|
|
39
|
+
[key: string]: string | null
|
|
40
|
+
}
|
|
12
41
|
|
|
13
42
|
/**
|
|
14
43
|
* Builds and caches project context for Claude decisions.
|
|
15
44
|
* Features parallel reads, selective loading, and anti-hallucination mtime checks.
|
|
16
45
|
*/
|
|
17
46
|
class ContextBuilder {
|
|
47
|
+
private _cache: Map<string, string | null>
|
|
48
|
+
private _cacheTimeout: number
|
|
49
|
+
private _lastCacheTime: number | null
|
|
50
|
+
private _mtimes: Map<string, number>
|
|
51
|
+
|
|
18
52
|
constructor() {
|
|
19
53
|
// Session cache - cleared between commands or after timeout
|
|
20
54
|
this._cache = new Map()
|
|
@@ -27,11 +61,9 @@ class ContextBuilder {
|
|
|
27
61
|
|
|
28
62
|
/**
|
|
29
63
|
* Clear cache if stale or force clear
|
|
30
|
-
* @param {boolean} force - Force clear regardless of timeout
|
|
31
64
|
*/
|
|
32
|
-
_clearCacheIfStale(force = false) {
|
|
33
|
-
if (force || !this._lastCacheTime ||
|
|
34
|
-
Date.now() - this._lastCacheTime > this._cacheTimeout) {
|
|
65
|
+
private _clearCacheIfStale(force: boolean = false): void {
|
|
66
|
+
if (force || !this._lastCacheTime || Date.now() - this._lastCacheTime > this._cacheTimeout) {
|
|
35
67
|
this._cache.clear()
|
|
36
68
|
this._lastCacheTime = Date.now()
|
|
37
69
|
}
|
|
@@ -39,13 +71,10 @@ class ContextBuilder {
|
|
|
39
71
|
|
|
40
72
|
/**
|
|
41
73
|
* Build full project context for Claude
|
|
42
|
-
* @param {string} projectPath - Local project path
|
|
43
|
-
* @param {Object} commandParams - Command-specific parameters
|
|
44
|
-
* @returns {Promise<Object>} Context object
|
|
45
74
|
*/
|
|
46
|
-
async build(projectPath, commandParams = {}) {
|
|
75
|
+
async build(projectPath: string, commandParams: Record<string, unknown> = {}): Promise<Context> {
|
|
47
76
|
const projectId = await configManager.getProjectId(projectPath)
|
|
48
|
-
const globalPath = pathManager.getGlobalProjectPath(projectId)
|
|
77
|
+
const globalPath = pathManager.getGlobalProjectPath(projectId!)
|
|
49
78
|
|
|
50
79
|
return {
|
|
51
80
|
// Project identification
|
|
@@ -55,18 +84,18 @@ class ContextBuilder {
|
|
|
55
84
|
|
|
56
85
|
// File paths
|
|
57
86
|
paths: {
|
|
58
|
-
now: pathManager.getFilePath(projectId
|
|
59
|
-
next: pathManager.getFilePath(projectId
|
|
60
|
-
context: pathManager.getFilePath(projectId
|
|
61
|
-
shipped: pathManager.getFilePath(projectId
|
|
62
|
-
metrics: pathManager.getFilePath(projectId
|
|
63
|
-
ideas: pathManager.getFilePath(projectId
|
|
64
|
-
roadmap: pathManager.getFilePath(projectId
|
|
65
|
-
specs: pathManager.getFilePath(projectId
|
|
66
|
-
memory: pathManager.getFilePath(projectId
|
|
67
|
-
patterns: pathManager.getFilePath(projectId
|
|
68
|
-
analysis: pathManager.getFilePath(projectId
|
|
69
|
-
codePatterns: pathManager.getFilePath(projectId
|
|
87
|
+
now: pathManager.getFilePath(projectId!, 'core', 'now.md'),
|
|
88
|
+
next: pathManager.getFilePath(projectId!, 'core', 'next.md'),
|
|
89
|
+
context: pathManager.getFilePath(projectId!, 'core', 'context.md'),
|
|
90
|
+
shipped: pathManager.getFilePath(projectId!, 'progress', 'shipped.md'),
|
|
91
|
+
metrics: pathManager.getFilePath(projectId!, 'progress', 'metrics.md'),
|
|
92
|
+
ideas: pathManager.getFilePath(projectId!, 'planning', 'ideas.md'),
|
|
93
|
+
roadmap: pathManager.getFilePath(projectId!, 'planning', 'roadmap.md'),
|
|
94
|
+
specs: pathManager.getFilePath(projectId!, 'planning', 'specs'),
|
|
95
|
+
memory: pathManager.getFilePath(projectId!, 'memory', 'context.jsonl'),
|
|
96
|
+
patterns: pathManager.getFilePath(projectId!, 'memory', 'patterns.json'),
|
|
97
|
+
analysis: pathManager.getFilePath(projectId!, 'analysis', 'repo-summary.md'),
|
|
98
|
+
codePatterns: pathManager.getFilePath(projectId!, 'analysis', 'patterns.md'),
|
|
70
99
|
},
|
|
71
100
|
|
|
72
101
|
// Command parameters
|
|
@@ -82,21 +111,15 @@ class ContextBuilder {
|
|
|
82
111
|
/**
|
|
83
112
|
* Load current project state - PARALLEL VERSION
|
|
84
113
|
* Uses Promise.all() for 40-60% faster file I/O
|
|
85
|
-
*
|
|
86
|
-
* @param {Object} context - Context from build()
|
|
87
|
-
* @param {string[]} onlyKeys - Optional: only load specific keys (selective loading)
|
|
88
|
-
* @returns {Promise<Object>} Current state
|
|
89
114
|
*/
|
|
90
|
-
async loadState(context, onlyKeys = null) {
|
|
115
|
+
async loadState(context: Context, onlyKeys: string[] | null = null): Promise<State> {
|
|
91
116
|
this._clearCacheIfStale()
|
|
92
117
|
|
|
93
|
-
const state = {}
|
|
118
|
+
const state: State = {}
|
|
94
119
|
const entries = Object.entries(context.paths)
|
|
95
120
|
|
|
96
121
|
// Filter to only requested keys if specified
|
|
97
|
-
const filteredEntries = onlyKeys
|
|
98
|
-
? entries.filter(([key]) => onlyKeys.includes(key))
|
|
99
|
-
: entries
|
|
122
|
+
const filteredEntries = onlyKeys ? entries.filter(([key]) => onlyKeys.includes(key)) : entries
|
|
100
123
|
|
|
101
124
|
// ANTI-HALLUCINATION: Verify mtime before trusting cache
|
|
102
125
|
// Files can change between commands - stale cache causes hallucinations
|
|
@@ -119,10 +142,10 @@ class ContextBuilder {
|
|
|
119
142
|
}
|
|
120
143
|
|
|
121
144
|
// Separate cached vs uncached files
|
|
122
|
-
const uncachedEntries = []
|
|
145
|
+
const uncachedEntries: [string, string][] = []
|
|
123
146
|
for (const [key, filePath] of filteredEntries) {
|
|
124
147
|
if (this._cache.has(filePath)) {
|
|
125
|
-
state[key] = this._cache.get(filePath)
|
|
148
|
+
state[key] = this._cache.get(filePath)!
|
|
126
149
|
} else {
|
|
127
150
|
uncachedEntries.push([key, filePath])
|
|
128
151
|
}
|
|
@@ -132,10 +155,7 @@ class ContextBuilder {
|
|
|
132
155
|
if (uncachedEntries.length > 0) {
|
|
133
156
|
const readPromises = uncachedEntries.map(async ([key, filePath]) => {
|
|
134
157
|
try {
|
|
135
|
-
const [content, stat] = await Promise.all([
|
|
136
|
-
fs.readFile(filePath, 'utf-8'),
|
|
137
|
-
fs.stat(filePath)
|
|
138
|
-
])
|
|
158
|
+
const [content, stat] = await Promise.all([fs.readFile(filePath, 'utf-8'), fs.stat(filePath)])
|
|
139
159
|
return { key, filePath, content, mtime: stat.mtimeMs }
|
|
140
160
|
} catch {
|
|
141
161
|
return { key, filePath, content: null, mtime: null }
|
|
@@ -160,46 +180,42 @@ class ContextBuilder {
|
|
|
160
180
|
/**
|
|
161
181
|
* Load state for specific command - optimized selective loading
|
|
162
182
|
* Each command only loads what it needs
|
|
163
|
-
*
|
|
164
|
-
* @param {Object} context - Context from build()
|
|
165
|
-
* @param {string} commandName - Command name for selective loading
|
|
166
|
-
* @returns {Promise<Object>} Current state (filtered)
|
|
167
183
|
*/
|
|
168
|
-
async loadStateForCommand(context, commandName) {
|
|
184
|
+
async loadStateForCommand(context: Context, commandName: string): Promise<State> {
|
|
169
185
|
// Command-specific file requirements
|
|
170
186
|
// Minimizes context window usage
|
|
171
187
|
// CRITICAL: Include 'codePatterns' for ALL code-modifying commands
|
|
172
|
-
const commandFileMap = {
|
|
188
|
+
const commandFileMap: Record<string, string[]> = {
|
|
173
189
|
// Core workflow
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
190
|
+
now: ['now', 'next', 'analysis', 'codePatterns'],
|
|
191
|
+
done: ['now', 'next', 'metrics', 'analysis'],
|
|
192
|
+
next: ['next', 'analysis'],
|
|
177
193
|
|
|
178
194
|
// Progress
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
195
|
+
ship: ['now', 'shipped', 'metrics', 'analysis'],
|
|
196
|
+
recap: ['shipped', 'metrics', 'now', 'analysis'],
|
|
197
|
+
progress: ['shipped', 'metrics', 'analysis'],
|
|
182
198
|
|
|
183
199
|
// Planning
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
200
|
+
idea: ['ideas', 'next', 'analysis'],
|
|
201
|
+
feature: ['roadmap', 'next', 'ideas', 'analysis', 'codePatterns'],
|
|
202
|
+
roadmap: ['roadmap', 'analysis'],
|
|
203
|
+
spec: ['roadmap', 'next', 'specs', 'analysis', 'codePatterns'],
|
|
188
204
|
|
|
189
205
|
// Analysis
|
|
190
|
-
|
|
191
|
-
|
|
206
|
+
analyze: ['analysis', 'context', 'codePatterns'],
|
|
207
|
+
sync: ['analysis', 'context', 'now', 'codePatterns'],
|
|
192
208
|
|
|
193
209
|
// Code modification commands - ALWAYS need codePatterns
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
210
|
+
work: ['now', 'next', 'analysis', 'context', 'codePatterns'],
|
|
211
|
+
build: ['now', 'next', 'analysis', 'context', 'codePatterns'],
|
|
212
|
+
design: ['analysis', 'context', 'codePatterns'],
|
|
213
|
+
cleanup: ['analysis', 'context', 'codePatterns'],
|
|
214
|
+
fix: ['analysis', 'context', 'codePatterns'],
|
|
215
|
+
test: ['analysis', 'context', 'codePatterns'],
|
|
200
216
|
|
|
201
217
|
// All files (fallback) - include codePatterns for any code work
|
|
202
|
-
|
|
218
|
+
default: ['analysis', 'codePatterns'],
|
|
203
219
|
}
|
|
204
220
|
|
|
205
221
|
const requiredFiles = commandFileMap[commandName] || commandFileMap.default
|
|
@@ -209,20 +225,17 @@ class ContextBuilder {
|
|
|
209
225
|
/**
|
|
210
226
|
* Batch read multiple files in parallel
|
|
211
227
|
* Utility for custom file sets
|
|
212
|
-
*
|
|
213
|
-
* @param {string[]} filePaths - Array of file paths
|
|
214
|
-
* @returns {Promise<Map<string, string|null>>} Map of path -> content
|
|
215
228
|
*/
|
|
216
|
-
async batchRead(filePaths) {
|
|
229
|
+
async batchRead(filePaths: string[]): Promise<Map<string, string | null>> {
|
|
217
230
|
this._clearCacheIfStale()
|
|
218
231
|
|
|
219
|
-
const results = new Map()
|
|
220
|
-
const uncachedPaths = []
|
|
232
|
+
const results = new Map<string, string | null>()
|
|
233
|
+
const uncachedPaths: string[] = []
|
|
221
234
|
|
|
222
235
|
// Check cache first
|
|
223
236
|
for (const filePath of filePaths) {
|
|
224
237
|
if (this._cache.has(filePath)) {
|
|
225
|
-
results.set(filePath, this._cache.get(filePath))
|
|
238
|
+
results.set(filePath, this._cache.get(filePath)!)
|
|
226
239
|
} else {
|
|
227
240
|
uncachedPaths.push(filePath)
|
|
228
241
|
}
|
|
@@ -252,25 +265,22 @@ class ContextBuilder {
|
|
|
252
265
|
|
|
253
266
|
/**
|
|
254
267
|
* Invalidate cache for specific file (after write)
|
|
255
|
-
* @param {string} filePath - File that was written
|
|
256
268
|
*/
|
|
257
|
-
invalidateCache(filePath) {
|
|
269
|
+
invalidateCache(filePath: string): void {
|
|
258
270
|
this._cache.delete(filePath)
|
|
259
271
|
}
|
|
260
272
|
|
|
261
273
|
/**
|
|
262
274
|
* Force clear entire cache
|
|
263
275
|
*/
|
|
264
|
-
clearCache() {
|
|
276
|
+
clearCache(): void {
|
|
265
277
|
this._clearCacheIfStale(true)
|
|
266
278
|
}
|
|
267
279
|
|
|
268
280
|
/**
|
|
269
281
|
* Check file existence
|
|
270
|
-
* @param {string} filePath - File path
|
|
271
|
-
* @returns {Promise<boolean>}
|
|
272
282
|
*/
|
|
273
|
-
async fileExists(filePath) {
|
|
283
|
+
async fileExists(filePath: string): Promise<boolean> {
|
|
274
284
|
try {
|
|
275
285
|
await fs.access(filePath)
|
|
276
286
|
return true
|
|
@@ -281,15 +291,16 @@ class ContextBuilder {
|
|
|
281
291
|
|
|
282
292
|
/**
|
|
283
293
|
* Get cache stats (for debugging/metrics)
|
|
284
|
-
* @returns {Object} Cache statistics
|
|
285
294
|
*/
|
|
286
|
-
getCacheStats() {
|
|
295
|
+
getCacheStats(): { size: number; lastRefresh: number | null; timeout: number } {
|
|
287
296
|
return {
|
|
288
297
|
size: this._cache.size,
|
|
289
298
|
lastRefresh: this._lastCacheTime,
|
|
290
|
-
timeout: this._cacheTimeout
|
|
299
|
+
timeout: this._cacheTimeout,
|
|
291
300
|
}
|
|
292
301
|
}
|
|
293
302
|
}
|
|
294
303
|
|
|
295
|
-
|
|
304
|
+
const contextBuilder = new ContextBuilder()
|
|
305
|
+
export default contextBuilder
|
|
306
|
+
export { ContextBuilder }
|
|
@@ -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
|