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.
Files changed (391) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/README.md +81 -25
  3. package/bin/dev.js +1 -1
  4. package/bin/generate-views.js +209 -0
  5. package/bin/migrate-to-json.js +742 -0
  6. package/bin/prjct +5 -5
  7. package/bin/serve.js +226 -50
  8. package/core/__tests__/agentic/{memory-system.test.js → memory-system.test.ts} +12 -23
  9. package/core/__tests__/agentic/{plan-mode.test.js → plan-mode.test.ts} +26 -24
  10. package/core/__tests__/agentic/{prompt-builder.test.js → prompt-builder.test.ts} +3 -8
  11. package/core/__tests__/utils/{date-helper.test.js → date-helper.test.ts} +19 -30
  12. package/core/__tests__/utils/{output.test.js → output.test.ts} +12 -24
  13. package/core/agentic/agent-router.ts +137 -0
  14. package/core/agentic/chain-of-thought.ts +228 -0
  15. package/core/agentic/command-executor/command-executor.ts +384 -0
  16. package/core/agentic/command-executor/index.ts +16 -0
  17. package/core/agentic/command-executor/status-signal.ts +38 -0
  18. package/core/agentic/command-executor/types.ts +79 -0
  19. package/core/agentic/command-executor.ts +8 -0
  20. package/core/agentic/{context-builder.js → context-builder.ts} +92 -81
  21. package/core/agentic/context-filter.ts +365 -0
  22. package/core/agentic/ground-truth/index.ts +76 -0
  23. package/core/agentic/ground-truth/types.ts +33 -0
  24. package/core/agentic/ground-truth/utils.ts +48 -0
  25. package/core/agentic/ground-truth/verifiers/analyze.ts +54 -0
  26. package/core/agentic/ground-truth/verifiers/done.ts +75 -0
  27. package/core/agentic/ground-truth/verifiers/feature.ts +70 -0
  28. package/core/agentic/ground-truth/verifiers/index.ts +37 -0
  29. package/core/agentic/ground-truth/verifiers/init.ts +52 -0
  30. package/core/agentic/ground-truth/verifiers/now.ts +57 -0
  31. package/core/agentic/ground-truth/verifiers/ship.ts +85 -0
  32. package/core/agentic/ground-truth/verifiers/spec.ts +45 -0
  33. package/core/agentic/ground-truth/verifiers/sync.ts +47 -0
  34. package/core/agentic/ground-truth/verifiers.ts +6 -0
  35. package/core/agentic/ground-truth.ts +8 -0
  36. package/core/agentic/loop-detector/error-analysis.ts +97 -0
  37. package/core/agentic/loop-detector/hallucination.ts +71 -0
  38. package/core/agentic/loop-detector/index.ts +41 -0
  39. package/core/agentic/loop-detector/loop-detector.ts +222 -0
  40. package/core/agentic/loop-detector/types.ts +66 -0
  41. package/core/agentic/loop-detector.ts +8 -0
  42. package/core/agentic/memory-system/history.ts +53 -0
  43. package/core/agentic/memory-system/index.ts +192 -0
  44. package/core/agentic/memory-system/patterns.ts +156 -0
  45. package/core/agentic/memory-system/semantic-memories.ts +277 -0
  46. package/core/agentic/memory-system/session.ts +21 -0
  47. package/core/agentic/memory-system/types.ts +159 -0
  48. package/core/agentic/memory-system.ts +8 -0
  49. package/core/agentic/parallel-tools.ts +165 -0
  50. package/core/agentic/plan-mode/approval.ts +57 -0
  51. package/core/agentic/plan-mode/constants.ts +44 -0
  52. package/core/agentic/plan-mode/index.ts +28 -0
  53. package/core/agentic/plan-mode/plan-mode.ts +406 -0
  54. package/core/agentic/plan-mode/types.ts +193 -0
  55. package/core/agentic/plan-mode.ts +8 -0
  56. package/core/agentic/prompt-builder.ts +566 -0
  57. package/core/agentic/response-templates.ts +164 -0
  58. package/core/agentic/semantic-compression.ts +273 -0
  59. package/core/agentic/services.ts +206 -0
  60. package/core/agentic/smart-context.ts +476 -0
  61. package/core/agentic/{template-loader.js → template-loader.ts} +27 -16
  62. package/core/agentic/think-blocks.ts +202 -0
  63. package/core/agentic/tool-registry.ts +119 -0
  64. package/core/agentic/validation-rules.ts +313 -0
  65. package/core/agents/index.ts +28 -0
  66. package/core/agents/performance.ts +444 -0
  67. package/core/agents/types.ts +126 -0
  68. package/core/bus/{index.js → index.ts} +57 -61
  69. package/core/command-registry/categories.ts +23 -0
  70. package/core/command-registry/commands.ts +15 -0
  71. package/core/command-registry/core-commands.ts +319 -0
  72. package/core/command-registry/index.ts +158 -0
  73. package/core/command-registry/optional-commands.ts +119 -0
  74. package/core/command-registry/setup-commands.ts +53 -0
  75. package/core/command-registry/types.ts +59 -0
  76. package/core/command-registry.ts +9 -0
  77. package/core/commands/analysis.ts +298 -0
  78. package/core/commands/analytics.ts +288 -0
  79. package/core/commands/base.ts +273 -0
  80. package/core/commands/index.ts +211 -0
  81. package/core/commands/maintenance.ts +226 -0
  82. package/core/commands/planning.ts +311 -0
  83. package/core/commands/setup.ts +309 -0
  84. package/core/commands/shipping.ts +188 -0
  85. package/core/commands/types.ts +183 -0
  86. package/core/commands/workflow.ts +226 -0
  87. package/core/commands.ts +11 -0
  88. package/core/constants/formats.ts +187 -0
  89. package/core/constants/index.ts +7 -0
  90. package/core/{context-sync.js → context-sync.ts} +59 -26
  91. package/core/data/agents-manager.ts +76 -0
  92. package/core/data/analysis-manager.ts +83 -0
  93. package/core/data/base-manager.ts +156 -0
  94. package/core/data/ideas-manager.ts +81 -0
  95. package/core/data/index.ts +32 -0
  96. package/core/data/outcomes-manager.ts +96 -0
  97. package/core/data/project-manager.ts +75 -0
  98. package/core/data/roadmap-manager.ts +118 -0
  99. package/core/data/shipped-manager.ts +65 -0
  100. package/core/data/state-manager.ts +214 -0
  101. package/core/domain/{agent-generator.js → agent-generator.ts} +77 -57
  102. package/core/domain/{agent-loader.js → agent-loader.ts} +65 -56
  103. package/core/domain/{agent-matcher.js → agent-matcher.ts} +51 -24
  104. package/core/domain/{agent-validator.js → agent-validator.ts} +70 -37
  105. package/core/domain/{analyzer.js → analyzer.ts} +91 -85
  106. package/core/domain/{architect-session.js → architect-session.ts} +49 -34
  107. package/core/domain/{architecture-generator.js → architecture-generator.ts} +25 -13
  108. package/core/domain/{context-estimator.js → context-estimator.ts} +57 -36
  109. package/core/domain/{product-standards.js → product-standards.ts} +40 -26
  110. package/core/domain/{smart-cache.js → smart-cache.ts} +39 -30
  111. package/core/domain/{snapshot-manager.js → snapshot-manager.ts} +103 -100
  112. package/core/domain/{task-analyzer.js → task-analyzer.ts} +82 -43
  113. package/core/domain/task-stack/index.ts +19 -0
  114. package/core/domain/task-stack/parser.ts +86 -0
  115. package/core/domain/task-stack/storage.ts +123 -0
  116. package/core/domain/task-stack/task-stack.ts +340 -0
  117. package/core/domain/task-stack/types.ts +51 -0
  118. package/core/domain/task-stack.ts +8 -0
  119. package/core/{index.js → index.ts} +61 -18
  120. package/core/infrastructure/{agent-detector.js → agent-detector.ts} +55 -19
  121. package/core/infrastructure/agents/{claude-agent.js → claude-agent.ts} +61 -21
  122. package/core/infrastructure/{author-detector.js → author-detector.ts} +42 -49
  123. package/core/infrastructure/{capability-installer.js → capability-installer.ts} +51 -27
  124. package/core/infrastructure/{command-installer.js → command-installer/command-installer.ts} +43 -144
  125. package/core/infrastructure/command-installer/global-config.ts +106 -0
  126. package/core/infrastructure/command-installer/index.ts +25 -0
  127. package/core/infrastructure/command-installer/types.ts +41 -0
  128. package/core/infrastructure/command-installer.ts +8 -0
  129. package/core/infrastructure/{config-manager.js → config-manager.ts} +60 -80
  130. package/core/infrastructure/{editors-config.js → editors-config.ts} +33 -31
  131. package/core/infrastructure/legacy-installer-detector/cleanup.ts +216 -0
  132. package/core/infrastructure/legacy-installer-detector/detection.ts +95 -0
  133. package/core/infrastructure/legacy-installer-detector/index.ts +171 -0
  134. package/core/infrastructure/legacy-installer-detector/migration.ts +87 -0
  135. package/core/infrastructure/legacy-installer-detector/types.ts +42 -0
  136. package/core/infrastructure/legacy-installer-detector.ts +7 -0
  137. package/core/infrastructure/migrator/file-operations.ts +125 -0
  138. package/core/infrastructure/migrator/index.ts +288 -0
  139. package/core/infrastructure/migrator/project-scanner.ts +89 -0
  140. package/core/infrastructure/migrator/reports.ts +117 -0
  141. package/core/infrastructure/migrator/types.ts +124 -0
  142. package/core/infrastructure/migrator/validation.ts +94 -0
  143. package/core/infrastructure/migrator/version-migration.ts +117 -0
  144. package/core/infrastructure/migrator.ts +10 -0
  145. package/core/infrastructure/{path-manager.js → path-manager.ts} +51 -91
  146. package/core/infrastructure/session-manager/index.ts +23 -0
  147. package/core/infrastructure/session-manager/migration.ts +88 -0
  148. package/core/infrastructure/session-manager/session-manager.ts +307 -0
  149. package/core/infrastructure/session-manager/types.ts +45 -0
  150. package/core/infrastructure/session-manager.ts +8 -0
  151. package/core/infrastructure/{setup.js → setup.ts} +29 -21
  152. package/core/infrastructure/{update-checker.js → update-checker.ts} +40 -18
  153. package/core/outcomes/analyzer.ts +333 -0
  154. package/core/outcomes/index.ts +34 -0
  155. package/core/outcomes/recorder.ts +194 -0
  156. package/core/outcomes/types.ts +145 -0
  157. package/core/plugin/{hooks.js → hooks.ts} +56 -58
  158. package/core/plugin/{index.js → index.ts} +19 -8
  159. package/core/plugin/{loader.js → loader.ts} +87 -69
  160. package/core/plugin/{registry.js → registry.ts} +49 -45
  161. package/core/plugins/{webhook.js → webhook.ts} +43 -27
  162. package/core/schemas/agents.ts +27 -0
  163. package/core/schemas/analysis.ts +41 -0
  164. package/core/schemas/ideas.ts +83 -0
  165. package/core/schemas/index.ts +73 -0
  166. package/core/schemas/outcomes.ts +22 -0
  167. package/core/schemas/project.ts +26 -0
  168. package/core/schemas/roadmap.ts +90 -0
  169. package/core/schemas/shipped.ts +82 -0
  170. package/core/schemas/state.ts +107 -0
  171. package/core/session/index.ts +17 -0
  172. package/core/session/{metrics.js → metrics.ts} +64 -46
  173. package/core/session/{index.js → session-manager.ts} +51 -117
  174. package/core/session/types.ts +29 -0
  175. package/core/session/utils.ts +57 -0
  176. package/core/state/index.ts +25 -0
  177. package/core/state/manager.ts +376 -0
  178. package/core/state/types.ts +185 -0
  179. package/core/tsconfig.json +22 -0
  180. package/core/types/index.ts +506 -0
  181. package/core/utils/{animations.js → animations.ts} +74 -28
  182. package/core/utils/{branding.js → branding.ts} +29 -4
  183. package/core/utils/{date-helper.js → date-helper.ts} +31 -74
  184. package/core/utils/file-helper.ts +262 -0
  185. package/core/utils/{jsonl-helper.js → jsonl-helper.ts} +71 -107
  186. package/core/utils/{logger.js → logger.ts} +24 -12
  187. package/core/utils/{output.js → output.ts} +25 -13
  188. package/core/utils/{project-capabilities.js → project-capabilities.ts} +31 -18
  189. package/core/utils/{session-helper.js → session-helper.ts} +79 -66
  190. package/core/utils/{version.js → version.ts} +23 -31
  191. package/core/view-generator.ts +536 -0
  192. package/package.json +23 -17
  193. package/packages/shared/.turbo/turbo-build.log +14 -0
  194. package/packages/shared/dist/index.d.ts +8 -613
  195. package/packages/shared/dist/index.d.ts.map +1 -0
  196. package/packages/shared/dist/index.js +4110 -118
  197. package/packages/shared/dist/schemas.d.ts +408 -0
  198. package/packages/shared/dist/schemas.d.ts.map +1 -0
  199. package/packages/shared/dist/types.d.ts +144 -0
  200. package/packages/shared/dist/types.d.ts.map +1 -0
  201. package/packages/shared/dist/unified.d.ts +139 -0
  202. package/packages/shared/dist/unified.d.ts.map +1 -0
  203. package/packages/shared/dist/utils.d.ts +60 -0
  204. package/packages/shared/dist/utils.d.ts.map +1 -0
  205. package/packages/shared/package.json +4 -4
  206. package/packages/shared/src/index.ts +1 -0
  207. package/packages/shared/src/unified.ts +174 -0
  208. package/packages/web/app/api/claude/sessions/route.ts +1 -1
  209. package/packages/web/app/api/claude/status/route.ts +1 -1
  210. package/packages/web/app/api/migrate/route.ts +46 -0
  211. package/packages/web/app/api/projects/[id]/route.ts +1 -1
  212. package/packages/web/app/api/projects/[id]/stats/route.ts +30 -2
  213. package/packages/web/app/api/projects/[id]/status/route.ts +1 -1
  214. package/packages/web/app/api/projects/route.ts +1 -1
  215. package/packages/web/app/api/settings/route.ts +97 -0
  216. package/packages/web/app/api/v2/projects/[id]/unified/route.ts +57 -0
  217. package/packages/web/app/globals.css +38 -0
  218. package/packages/web/app/layout.tsx +10 -2
  219. package/packages/web/app/page.tsx +9 -224
  220. package/packages/web/app/project/[id]/page.tsx +191 -63
  221. package/packages/web/app/project/[id]/stats/loading.tsx +43 -0
  222. package/packages/web/app/project/[id]/stats/page.tsx +204 -163
  223. package/packages/web/app/settings/page.tsx +222 -2
  224. package/packages/web/components/ActivityTimeline/ActivityTimeline.constants.ts +2 -0
  225. package/packages/web/components/ActivityTimeline/ActivityTimeline.tsx +50 -0
  226. package/packages/web/components/ActivityTimeline/ActivityTimeline.types.ts +8 -0
  227. package/packages/web/components/ActivityTimeline/hooks/index.ts +2 -0
  228. package/packages/web/components/ActivityTimeline/hooks/useExpandable.ts +9 -0
  229. package/packages/web/components/ActivityTimeline/hooks/useGroupedEvents.ts +23 -0
  230. package/packages/web/components/ActivityTimeline/index.ts +2 -0
  231. package/packages/web/components/AgentsCard/AgentsCard.tsx +63 -0
  232. package/packages/web/components/AgentsCard/AgentsCard.types.ts +13 -0
  233. package/packages/web/components/AgentsCard/index.ts +2 -0
  234. package/packages/web/components/AppSidebar/AppSidebar.tsx +134 -0
  235. package/packages/web/components/AppSidebar/index.ts +1 -0
  236. package/packages/web/components/BackLink/BackLink.tsx +18 -0
  237. package/packages/web/components/BackLink/BackLink.types.ts +5 -0
  238. package/packages/web/components/BackLink/index.ts +2 -0
  239. package/packages/web/components/BentoCard/BentoCard.constants.ts +16 -0
  240. package/packages/web/components/BentoCard/BentoCard.tsx +47 -0
  241. package/packages/web/components/BentoCard/BentoCard.types.ts +15 -0
  242. package/packages/web/components/BentoCard/index.ts +2 -0
  243. package/packages/web/components/BentoCardSkeleton/BentoCardSkeleton.constants.ts +9 -0
  244. package/packages/web/components/BentoCardSkeleton/BentoCardSkeleton.tsx +18 -0
  245. package/packages/web/components/BentoCardSkeleton/BentoCardSkeleton.types.ts +5 -0
  246. package/packages/web/components/BentoCardSkeleton/index.ts +2 -0
  247. package/packages/web/components/{stats → BentoGrid}/BentoGrid.tsx +4 -8
  248. package/packages/web/components/BentoGrid/BentoGrid.types.ts +4 -0
  249. package/packages/web/components/BentoGrid/index.ts +2 -0
  250. package/packages/web/components/CommandButton/index.ts +1 -0
  251. package/packages/web/components/ConnectionStatus/index.ts +1 -0
  252. package/packages/web/components/DashboardContent/DashboardContent.tsx +254 -0
  253. package/packages/web/components/DashboardContent/index.ts +1 -0
  254. package/packages/web/components/DateGroup/DateGroup.tsx +18 -0
  255. package/packages/web/components/DateGroup/DateGroup.types.ts +6 -0
  256. package/packages/web/components/DateGroup/DateGroup.utils.ts +11 -0
  257. package/packages/web/components/DateGroup/index.ts +2 -0
  258. package/packages/web/components/{stats → EmptyState}/EmptyState.tsx +1 -10
  259. package/packages/web/components/EmptyState/EmptyState.types.ts +10 -0
  260. package/packages/web/components/EmptyState/index.ts +2 -0
  261. package/packages/web/components/EventRow/EventRow.constants.ts +10 -0
  262. package/packages/web/components/EventRow/EventRow.tsx +49 -0
  263. package/packages/web/components/EventRow/EventRow.types.ts +7 -0
  264. package/packages/web/components/EventRow/EventRow.utils.ts +49 -0
  265. package/packages/web/components/EventRow/index.ts +2 -0
  266. package/packages/web/components/ExpandButton/ExpandButton.tsx +18 -0
  267. package/packages/web/components/ExpandButton/ExpandButton.types.ts +6 -0
  268. package/packages/web/components/ExpandButton/index.ts +2 -0
  269. package/packages/web/components/HealthGradientBackground/HealthGradientBackground.tsx +14 -0
  270. package/packages/web/components/HealthGradientBackground/HealthGradientBackground.types.ts +5 -0
  271. package/packages/web/components/HealthGradientBackground/HealthGradientBackground.utils.ts +13 -0
  272. package/packages/web/components/HealthGradientBackground/index.ts +2 -0
  273. package/packages/web/components/HeroSection/HeroSection.tsx +55 -0
  274. package/packages/web/components/HeroSection/HeroSection.types.ts +14 -0
  275. package/packages/web/components/HeroSection/HeroSection.utils.ts +7 -0
  276. package/packages/web/components/HeroSection/hooks/index.ts +2 -0
  277. package/packages/web/components/HeroSection/hooks/useCountUp.ts +45 -0
  278. package/packages/web/components/HeroSection/hooks/useWeeklyActivity.ts +18 -0
  279. package/packages/web/components/HeroSection/index.ts +2 -0
  280. package/packages/web/components/{stats → IdeasCard}/IdeasCard.tsx +3 -14
  281. package/packages/web/components/IdeasCard/IdeasCard.types.ts +9 -0
  282. package/packages/web/components/IdeasCard/index.ts +2 -0
  283. package/packages/web/components/InsightMessage/InsightMessage.tsx +9 -0
  284. package/packages/web/components/InsightMessage/InsightMessage.types.ts +3 -0
  285. package/packages/web/components/InsightMessage/index.ts +2 -0
  286. package/packages/web/components/Logo/index.ts +1 -0
  287. package/packages/web/components/MarkdownContent/index.ts +1 -0
  288. package/packages/web/components/NowCard/NowCard.tsx +93 -0
  289. package/packages/web/components/NowCard/NowCard.types.ts +15 -0
  290. package/packages/web/components/NowCard/index.ts +2 -0
  291. package/packages/web/components/ProgressRing/ProgressRing.constants.ts +20 -0
  292. package/packages/web/components/{stats → ProgressRing}/ProgressRing.tsx +4 -27
  293. package/packages/web/components/ProgressRing/ProgressRing.types.ts +11 -0
  294. package/packages/web/components/ProgressRing/index.ts +2 -0
  295. package/packages/web/components/ProjectAvatar/index.ts +1 -0
  296. package/packages/web/components/Providers/index.ts +1 -0
  297. package/packages/web/components/QueueCard/QueueCard.tsx +72 -0
  298. package/packages/web/components/QueueCard/QueueCard.types.ts +11 -0
  299. package/packages/web/components/QueueCard/QueueCard.utils.ts +12 -0
  300. package/packages/web/components/QueueCard/index.ts +2 -0
  301. package/packages/web/components/{stats → RoadmapCard}/RoadmapCard.tsx +3 -23
  302. package/packages/web/components/RoadmapCard/RoadmapCard.types.ts +15 -0
  303. package/packages/web/components/RoadmapCard/index.ts +2 -0
  304. package/packages/web/components/{stats → ShipsCard}/ShipsCard.tsx +4 -22
  305. package/packages/web/components/ShipsCard/ShipsCard.types.ts +12 -0
  306. package/packages/web/components/ShipsCard/ShipsCard.utils.ts +4 -0
  307. package/packages/web/components/ShipsCard/index.ts +2 -0
  308. package/packages/web/components/{stats → SparklineChart}/SparklineChart.tsx +1 -7
  309. package/packages/web/components/SparklineChart/SparklineChart.types.ts +6 -0
  310. package/packages/web/components/SparklineChart/index.ts +2 -0
  311. package/packages/web/components/StreakCard/StreakCard.constants.ts +2 -0
  312. package/packages/web/components/{stats → StreakCard}/StreakCard.tsx +5 -11
  313. package/packages/web/components/StreakCard/StreakCard.types.ts +4 -0
  314. package/packages/web/components/StreakCard/index.ts +2 -0
  315. package/packages/web/components/TasksCounter/TasksCounter.tsx +14 -0
  316. package/packages/web/components/TasksCounter/TasksCounter.types.ts +3 -0
  317. package/packages/web/components/TasksCounter/index.ts +2 -0
  318. package/packages/web/components/TechStackBadges/index.ts +1 -0
  319. package/packages/web/components/{TerminalTab.tsx → TerminalTabs/TerminalTab.tsx} +11 -0
  320. package/packages/web/components/{TerminalTabs.tsx → TerminalTabs/TerminalTabs.tsx} +29 -28
  321. package/packages/web/components/TerminalTabs/index.ts +1 -0
  322. package/packages/web/components/VelocityBadge/VelocityBadge.tsx +27 -0
  323. package/packages/web/components/VelocityBadge/VelocityBadge.types.ts +3 -0
  324. package/packages/web/components/VelocityBadge/index.ts +2 -0
  325. package/packages/web/components/VelocityCard/VelocityCard.tsx +71 -0
  326. package/packages/web/components/VelocityCard/VelocityCard.types.ts +7 -0
  327. package/packages/web/components/VelocityCard/index.ts +2 -0
  328. package/packages/web/components/WeeklySparkline/WeeklySparkline.tsx +13 -0
  329. package/packages/web/components/WeeklySparkline/WeeklySparkline.types.ts +3 -0
  330. package/packages/web/components/WeeklySparkline/index.ts +2 -0
  331. package/packages/web/components/ui/input.tsx +21 -0
  332. package/packages/web/context/TerminalTabsContext.tsx +46 -1
  333. package/packages/web/hooks/useClaudeTerminal.ts +71 -21
  334. package/packages/web/hooks/useProjectStats.ts +55 -0
  335. package/packages/web/hooks/useProjects.ts +6 -6
  336. package/packages/web/lib/actions/projects.ts +15 -0
  337. package/packages/web/lib/json-loader.ts +630 -0
  338. package/packages/web/lib/services/index.ts +9 -0
  339. package/packages/web/lib/services/migration.server.ts +598 -0
  340. package/packages/web/lib/services/projects.server.ts +52 -0
  341. package/packages/web/lib/services/stats.server.ts +264 -0
  342. package/packages/web/lib/unified-loader.ts +396 -0
  343. package/packages/web/package.json +10 -7
  344. package/packages/web/server.ts +36 -6
  345. package/templates/commands/done.md +76 -32
  346. package/templates/commands/feature.md +121 -47
  347. package/templates/commands/idea.md +81 -8
  348. package/templates/commands/now.md +41 -17
  349. package/templates/commands/ship.md +64 -25
  350. package/templates/commands/sync.md +28 -3
  351. package/core/agentic/agent-router.js +0 -140
  352. package/core/agentic/chain-of-thought.js +0 -578
  353. package/core/agentic/command-executor.js +0 -417
  354. package/core/agentic/context-filter.js +0 -354
  355. package/core/agentic/ground-truth.js +0 -591
  356. package/core/agentic/loop-detector.js +0 -406
  357. package/core/agentic/memory-system.js +0 -845
  358. package/core/agentic/parallel-tools.js +0 -366
  359. package/core/agentic/plan-mode.js +0 -572
  360. package/core/agentic/prompt-builder.js +0 -352
  361. package/core/agentic/response-templates.js +0 -290
  362. package/core/agentic/semantic-compression.js +0 -517
  363. package/core/agentic/think-blocks.js +0 -657
  364. package/core/agentic/tool-registry.js +0 -184
  365. package/core/agentic/validation-rules.js +0 -380
  366. package/core/command-registry.js +0 -698
  367. package/core/commands.js +0 -2237
  368. package/core/domain/task-stack.js +0 -497
  369. package/core/infrastructure/legacy-installer-detector.js +0 -546
  370. package/core/infrastructure/migrator.js +0 -796
  371. package/core/infrastructure/session-manager.js +0 -390
  372. package/core/utils/file-helper.js +0 -329
  373. package/packages/web/app/api/projects/[id]/delete/route.ts +0 -21
  374. package/packages/web/app/api/stats/route.ts +0 -38
  375. package/packages/web/components/AppSidebar.tsx +0 -113
  376. package/packages/web/components/stats/ActivityTimeline.tsx +0 -201
  377. package/packages/web/components/stats/AgentsCard.tsx +0 -56
  378. package/packages/web/components/stats/BentoCard.tsx +0 -88
  379. package/packages/web/components/stats/HeroSection.tsx +0 -172
  380. package/packages/web/components/stats/NowCard.tsx +0 -71
  381. package/packages/web/components/stats/QueueCard.tsx +0 -58
  382. package/packages/web/components/stats/VelocityCard.tsx +0 -60
  383. package/packages/web/components/stats/index.ts +0 -17
  384. package/packages/web/hooks/useStats.ts +0 -28
  385. /package/packages/web/components/{CommandButton.tsx → CommandButton/CommandButton.tsx} +0 -0
  386. /package/packages/web/components/{ConnectionStatus.tsx → ConnectionStatus/ConnectionStatus.tsx} +0 -0
  387. /package/packages/web/components/{Logo.tsx → Logo/Logo.tsx} +0 -0
  388. /package/packages/web/components/{MarkdownContent.tsx → MarkdownContent/MarkdownContent.tsx} +0 -0
  389. /package/packages/web/components/{ProjectAvatar.tsx → ProjectAvatar/ProjectAvatar.tsx} +0 -0
  390. /package/packages/web/components/{providers.tsx → Providers/Providers.tsx} +0 -0
  391. /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
- const fs = require('fs').promises
10
- const pathManager = require('../infrastructure/path-manager')
11
- const configManager = require('../infrastructure/config-manager')
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, 'core', 'now.md'),
59
- next: pathManager.getFilePath(projectId, 'core', 'next.md'),
60
- context: pathManager.getFilePath(projectId, 'core', 'context.md'),
61
- shipped: pathManager.getFilePath(projectId, 'progress', 'shipped.md'),
62
- metrics: pathManager.getFilePath(projectId, 'progress', 'metrics.md'),
63
- ideas: pathManager.getFilePath(projectId, 'planning', 'ideas.md'),
64
- roadmap: pathManager.getFilePath(projectId, 'planning', 'roadmap.md'),
65
- specs: pathManager.getFilePath(projectId, 'planning', 'specs'),
66
- memory: pathManager.getFilePath(projectId, 'memory', 'context.jsonl'),
67
- patterns: pathManager.getFilePath(projectId, 'memory', 'patterns.json'),
68
- analysis: pathManager.getFilePath(projectId, 'analysis', 'repo-summary.md'),
69
- codePatterns: pathManager.getFilePath(projectId, 'analysis', 'patterns.md'),
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
- 'now': ['now', 'next', 'analysis', 'codePatterns'],
175
- 'done': ['now', 'next', 'metrics', 'analysis'],
176
- 'next': ['next', 'analysis'],
190
+ now: ['now', 'next', 'analysis', 'codePatterns'],
191
+ done: ['now', 'next', 'metrics', 'analysis'],
192
+ next: ['next', 'analysis'],
177
193
 
178
194
  // Progress
179
- 'ship': ['now', 'shipped', 'metrics', 'analysis'],
180
- 'recap': ['shipped', 'metrics', 'now', 'analysis'],
181
- 'progress': ['shipped', 'metrics', 'analysis'],
195
+ ship: ['now', 'shipped', 'metrics', 'analysis'],
196
+ recap: ['shipped', 'metrics', 'now', 'analysis'],
197
+ progress: ['shipped', 'metrics', 'analysis'],
182
198
 
183
199
  // Planning
184
- 'idea': ['ideas', 'next', 'analysis'],
185
- 'feature': ['roadmap', 'next', 'ideas', 'analysis', 'codePatterns'],
186
- 'roadmap': ['roadmap', 'analysis'],
187
- 'spec': ['roadmap', 'next', 'specs', 'analysis', 'codePatterns'],
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
- 'analyze': ['analysis', 'context', 'codePatterns'],
191
- 'sync': ['analysis', 'context', 'now', 'codePatterns'],
206
+ analyze: ['analysis', 'context', 'codePatterns'],
207
+ sync: ['analysis', 'context', 'now', 'codePatterns'],
192
208
 
193
209
  // Code modification commands - ALWAYS need codePatterns
194
- 'work': ['now', 'next', 'analysis', 'context', 'codePatterns'],
195
- 'build': ['now', 'next', 'analysis', 'context', 'codePatterns'],
196
- 'design': ['analysis', 'context', 'codePatterns'],
197
- 'cleanup': ['analysis', 'context', 'codePatterns'],
198
- 'fix': ['analysis', 'context', 'codePatterns'],
199
- 'test': ['analysis', 'context', 'codePatterns'],
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
- 'default': ['analysis', 'codePatterns']
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
- module.exports = new ContextBuilder()
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