prjct-cli 0.11.4 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (385) hide show
  1. package/CHANGELOG.md +72 -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 +246 -54
  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.ts +405 -0
  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} +99 -89
  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} +35 -18
  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} +62 -23
  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 +203 -403
  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/BentoGrid/BentoGrid.tsx +18 -0
  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/EmptyState/EmptyState.tsx +58 -0
  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/IdeasCard/IdeasCard.tsx +48 -0
  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/ProgressRing/ProgressRing.tsx +51 -0
  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/RoadmapCard/RoadmapCard.tsx +77 -0
  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/ShipsCard/ShipsCard.tsx +52 -0
  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/SparklineChart/SparklineChart.tsx +38 -0
  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/StreakCard/StreakCard.tsx +53 -0
  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/components/ui/tooltip.tsx +2 -2
  333. package/packages/web/context/TerminalTabsContext.tsx +46 -1
  334. package/packages/web/hooks/useClaudeTerminal.ts +71 -21
  335. package/packages/web/hooks/useProjectStats.ts +55 -0
  336. package/packages/web/hooks/useProjects.ts +6 -6
  337. package/packages/web/lib/actions/projects.ts +15 -0
  338. package/packages/web/lib/json-loader.ts +630 -0
  339. package/packages/web/lib/services/index.ts +9 -0
  340. package/packages/web/lib/services/migration.server.ts +598 -0
  341. package/packages/web/lib/services/projects.server.ts +52 -0
  342. package/packages/web/lib/services/stats.server.ts +264 -0
  343. package/packages/web/lib/unified-loader.ts +396 -0
  344. package/packages/web/next-env.d.ts +1 -1
  345. package/packages/web/package.json +10 -6
  346. package/packages/web/server.ts +36 -6
  347. package/templates/commands/done.md +76 -32
  348. package/templates/commands/feature.md +121 -47
  349. package/templates/commands/idea.md +81 -8
  350. package/templates/commands/now.md +41 -17
  351. package/templates/commands/ship.md +64 -25
  352. package/templates/commands/sync.md +28 -3
  353. package/core/agentic/agent-router.js +0 -128
  354. package/core/agentic/chain-of-thought.js +0 -578
  355. package/core/agentic/command-executor.js +0 -421
  356. package/core/agentic/context-filter.js +0 -354
  357. package/core/agentic/ground-truth.js +0 -591
  358. package/core/agentic/loop-detector.js +0 -406
  359. package/core/agentic/memory-system.js +0 -850
  360. package/core/agentic/parallel-tools.js +0 -366
  361. package/core/agentic/plan-mode.js +0 -572
  362. package/core/agentic/prompt-builder.js +0 -338
  363. package/core/agentic/response-templates.js +0 -290
  364. package/core/agentic/semantic-compression.js +0 -517
  365. package/core/agentic/think-blocks.js +0 -657
  366. package/core/agentic/tool-registry.js +0 -184
  367. package/core/agentic/validation-rules.js +0 -380
  368. package/core/command-registry.js +0 -698
  369. package/core/commands.js +0 -2237
  370. package/core/domain/task-stack.js +0 -497
  371. package/core/infrastructure/legacy-installer-detector.js +0 -546
  372. package/core/infrastructure/migrator.js +0 -799
  373. package/core/infrastructure/session-manager.js +0 -390
  374. package/core/utils/file-helper.js +0 -329
  375. package/packages/web/app/api/projects/[id]/delete/route.ts +0 -21
  376. package/packages/web/app/api/stats/route.ts +0 -38
  377. package/packages/web/components/AppSidebar.tsx +0 -113
  378. package/packages/web/hooks/useStats.ts +0 -28
  379. /package/packages/web/components/{CommandButton.tsx → CommandButton/CommandButton.tsx} +0 -0
  380. /package/packages/web/components/{ConnectionStatus.tsx → ConnectionStatus/ConnectionStatus.tsx} +0 -0
  381. /package/packages/web/components/{Logo.tsx → Logo/Logo.tsx} +0 -0
  382. /package/packages/web/components/{MarkdownContent.tsx → MarkdownContent/MarkdownContent.tsx} +0 -0
  383. /package/packages/web/components/{ProjectAvatar.tsx → ProjectAvatar/ProjectAvatar.tsx} +0 -0
  384. /package/packages/web/components/{providers.tsx → Providers/Providers.tsx} +0 -0
  385. /package/packages/web/components/{TechStackBadges.tsx → TechStackBadges/TechStackBadges.tsx} +0 -0
@@ -0,0 +1,222 @@
1
+ /**
2
+ * Loop Detector Class
3
+ * Core loop detection and user escalation functionality
4
+ */
5
+
6
+ import type { AttemptRecord, EscalationInfo, AttemptResult, AttemptInfo, OutputAnalysis } from './types'
7
+ import { isSimilarError, analyzeErrorPattern, generateEscalationMessage, generateSuggestion } from './error-analysis'
8
+ import { detectHallucination } from './hallucination'
9
+
10
+ export class LoopDetector {
11
+ private _attempts: Map<string, AttemptRecord>
12
+ private _errorPatterns: Map<string, unknown>
13
+ maxAttempts: number
14
+ sessionTimeout: number
15
+
16
+ constructor() {
17
+ // Track attempts per command session
18
+ this._attempts = new Map()
19
+
20
+ // Track error patterns
21
+ this._errorPatterns = new Map()
22
+
23
+ // Configuration
24
+ this.maxAttempts = 3
25
+ this.sessionTimeout = 5 * 60 * 1000 // 5 minutes
26
+ }
27
+
28
+ /**
29
+ * Generate a unique key for tracking attempts
30
+ */
31
+ private _getKey(command: string, context: string = ''): string {
32
+ return `${command}:${context}`.toLowerCase()
33
+ }
34
+
35
+ /**
36
+ * Record an attempt for a command
37
+ */
38
+ recordAttempt(command: string, context: string = '', result: AttemptResult = {}): AttemptInfo {
39
+ const key = this._getKey(command, context)
40
+ const now = Date.now()
41
+
42
+ // Get or create attempt record
43
+ let record = this._attempts.get(key)
44
+
45
+ if (!record || now - record.lastAttempt > this.sessionTimeout) {
46
+ // New session or timed out
47
+ record = {
48
+ command,
49
+ context,
50
+ attempts: 0,
51
+ errors: [],
52
+ firstAttempt: now,
53
+ lastAttempt: now,
54
+ success: false,
55
+ }
56
+ }
57
+
58
+ // Update record
59
+ record.attempts++
60
+ record.lastAttempt = now
61
+ record.success = result.success || false
62
+
63
+ if (result.error) {
64
+ record.errors.push({
65
+ message: result.error,
66
+ timestamp: now,
67
+ })
68
+ }
69
+
70
+ this._attempts.set(key, record)
71
+
72
+ return {
73
+ attemptNumber: record.attempts,
74
+ isLooping: this.isLooping(command, context),
75
+ shouldEscalate: this.shouldEscalate(command, context),
76
+ }
77
+ }
78
+
79
+ /**
80
+ * Check if a command is in a loop (repeated failures)
81
+ */
82
+ isLooping(command: string, context: string = ''): boolean {
83
+ const key = this._getKey(command, context)
84
+ const record = this._attempts.get(key)
85
+
86
+ if (!record) return false
87
+
88
+ // Check if multiple failures with same error
89
+ if (record.attempts >= 2 && !record.success) {
90
+ const recentErrors = record.errors.slice(-3)
91
+ if (recentErrors.length >= 2) {
92
+ // Check if errors are similar
93
+ const firstError = recentErrors[0]?.message || ''
94
+ const sameError = recentErrors.every((e) => isSimilarError(e.message, firstError))
95
+ return sameError
96
+ }
97
+ }
98
+
99
+ return false
100
+ }
101
+
102
+ /**
103
+ * Check if we should escalate to user
104
+ */
105
+ shouldEscalate(command: string, context: string = ''): boolean {
106
+ const key = this._getKey(command, context)
107
+ const record = this._attempts.get(key)
108
+
109
+ if (!record) return false
110
+
111
+ // Escalate after max attempts without success
112
+ return record.attempts >= this.maxAttempts && !record.success
113
+ }
114
+
115
+ /**
116
+ * Get escalation message for user
117
+ */
118
+ getEscalationInfo(command: string, context: string = ''): EscalationInfo | null {
119
+ const key = this._getKey(command, context)
120
+ const record = this._attempts.get(key)
121
+
122
+ if (!record) {
123
+ return null
124
+ }
125
+
126
+ // Analyze error pattern
127
+ const errorPattern = analyzeErrorPattern(record.errors)
128
+
129
+ return {
130
+ status: 'BLOCKED',
131
+ command,
132
+ context,
133
+ attempts: record.attempts,
134
+ duration: record.lastAttempt - record.firstAttempt,
135
+ errorPattern,
136
+ message: generateEscalationMessage(command, errorPattern, this.maxAttempts),
137
+ suggestion: generateSuggestion(errorPattern),
138
+ lastError: record.errors[record.errors.length - 1]?.message || null,
139
+ }
140
+ }
141
+
142
+ /**
143
+ * Mark a command as successful (resets tracking)
144
+ */
145
+ recordSuccess(command: string, context: string = ''): void {
146
+ const key = this._getKey(command, context)
147
+ const record = this._attempts.get(key)
148
+
149
+ if (record) {
150
+ record.success = true
151
+ record.attempts = 0
152
+ record.errors = []
153
+ this._attempts.set(key, record)
154
+ }
155
+ }
156
+
157
+ /**
158
+ * Clear all tracking for a command
159
+ */
160
+ clearTracking(command: string, context: string = ''): void {
161
+ const key = this._getKey(command, context)
162
+ this._attempts.delete(key)
163
+ }
164
+
165
+ /**
166
+ * Clear all tracking data
167
+ */
168
+ clearAll(): void {
169
+ this._attempts.clear()
170
+ this._errorPatterns.clear()
171
+ }
172
+
173
+ /**
174
+ * Get statistics for debugging
175
+ */
176
+ getStats(): { activeTracking: number; commands: Record<string, unknown> } {
177
+ const stats: { activeTracking: number; commands: Record<string, unknown> } = {
178
+ activeTracking: this._attempts.size,
179
+ commands: {},
180
+ }
181
+
182
+ for (const [key, record] of this._attempts) {
183
+ stats.commands[key] = {
184
+ attempts: record.attempts,
185
+ success: record.success,
186
+ errorCount: record.errors.length,
187
+ }
188
+ }
189
+
190
+ return stats
191
+ }
192
+
193
+ /**
194
+ * ANTI-HALLUCINATION: Detect potential hallucination patterns in output
195
+ */
196
+ detectHallucination(output: string) {
197
+ return detectHallucination(output)
198
+ }
199
+
200
+ /**
201
+ * Analyze output and record if hallucination detected
202
+ */
203
+ analyzeOutput(command: string, output: string): OutputAnalysis {
204
+ const hallucination = this.detectHallucination(output)
205
+
206
+ if (hallucination.detected) {
207
+ // Record as a special type of error
208
+ this.recordAttempt(command, 'hallucination', {
209
+ success: false,
210
+ error: `HALLUCINATION: ${hallucination.description}`,
211
+ })
212
+
213
+ return {
214
+ ...hallucination,
215
+ shouldBlock: true,
216
+ action: 'VERIFY_STATE',
217
+ }
218
+ }
219
+
220
+ return { detected: false, shouldBlock: false }
221
+ }
222
+ }
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Loop Detector Types
3
+ */
4
+
5
+ export interface ErrorEntry {
6
+ message: string
7
+ timestamp: number
8
+ }
9
+
10
+ export interface AttemptRecord {
11
+ command: string
12
+ context: string
13
+ attempts: number
14
+ errors: ErrorEntry[]
15
+ firstAttempt: number
16
+ lastAttempt: number
17
+ success: boolean
18
+ }
19
+
20
+ export interface ErrorPattern {
21
+ type: string
22
+ description: string
23
+ }
24
+
25
+ export interface EscalationInfo {
26
+ status: string
27
+ command: string
28
+ context: string
29
+ attempts: number
30
+ duration: number
31
+ errorPattern: ErrorPattern
32
+ message: string
33
+ suggestion: string
34
+ lastError: string | null
35
+ }
36
+
37
+ export interface AttemptResult {
38
+ success?: boolean
39
+ error?: string
40
+ }
41
+
42
+ export interface AttemptInfo {
43
+ attemptNumber: number
44
+ isLooping: boolean
45
+ shouldEscalate: boolean
46
+ }
47
+
48
+ export interface HallucinationPattern {
49
+ pattern: RegExp
50
+ type: string
51
+ description: string
52
+ }
53
+
54
+ export interface HallucinationResult {
55
+ detected: boolean
56
+ type?: string
57
+ pattern?: string
58
+ description?: string
59
+ message?: string
60
+ suggestion?: string
61
+ }
62
+
63
+ export interface OutputAnalysis extends HallucinationResult {
64
+ shouldBlock: boolean
65
+ action?: string
66
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Loop Detection & User Escalation
3
+ * Re-exports from loop-detector/index.ts for backwards compatibility.
4
+ */
5
+
6
+ import loopDetector from './loop-detector/index'
7
+ export * from './loop-detector/index'
8
+ export default loopDetector
@@ -0,0 +1,53 @@
1
+ /**
2
+ * History - Tier 3
3
+ * Append-only JSONL audit log.
4
+ */
5
+
6
+ import fs from 'fs/promises'
7
+ import path from 'path'
8
+ import pathManager from '../../infrastructure/path-manager'
9
+ import type { HistoryEntry } from './types'
10
+
11
+ export class HistoryStore {
12
+ private _getSessionPath(projectId: string): string {
13
+ const now = new Date()
14
+ const yearMonth = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}`
15
+ const day = now.toISOString().split('T')[0]
16
+
17
+ return path.join(pathManager.getGlobalProjectPath(projectId), 'memory', 'sessions', yearMonth, `${day}.jsonl`)
18
+ }
19
+
20
+ async appendHistory(projectId: string, entry: Record<string, unknown>): Promise<void> {
21
+ const sessionPath = this._getSessionPath(projectId)
22
+ await fs.mkdir(path.dirname(sessionPath), { recursive: true })
23
+
24
+ const logEntry: HistoryEntry = {
25
+ ts: new Date().toISOString(),
26
+ type: entry.type as string,
27
+ ...entry,
28
+ }
29
+
30
+ await fs.appendFile(sessionPath, JSON.stringify(logEntry) + '\n', 'utf-8')
31
+ }
32
+
33
+ async getRecentHistory(projectId: string, limit: number = 20): Promise<HistoryEntry[]> {
34
+ try {
35
+ const sessionPath = this._getSessionPath(projectId)
36
+ const content = await fs.readFile(sessionPath, 'utf-8')
37
+ const lines = content.trim().split('\n').filter(Boolean)
38
+
39
+ return lines
40
+ .slice(-limit)
41
+ .map((line) => {
42
+ try {
43
+ return JSON.parse(line)
44
+ } catch {
45
+ return null
46
+ }
47
+ })
48
+ .filter((entry): entry is HistoryEntry => entry !== null)
49
+ } catch {
50
+ return []
51
+ }
52
+ }
53
+ }
@@ -0,0 +1,192 @@
1
+ /**
2
+ * Layered Memory System
3
+ * Three-tier memory for learning user patterns and preferences.
4
+ *
5
+ * @module agentic/memory-system
6
+ * @version 3.3
7
+ */
8
+
9
+ import { SemanticMemories } from './semantic-memories'
10
+ import { PatternStore } from './patterns'
11
+ import { HistoryStore } from './history'
12
+ import { SessionStore } from './session'
13
+ import type { Memory, Context, Workflow } from './types'
14
+ export { MEMORY_TAGS } from './types'
15
+
16
+ /**
17
+ * Three-tier memory system for learning user patterns.
18
+ * Tier 1: Session (ephemeral), Tier 2: Patterns (persistent), Tier 3: History (JSONL)
19
+ */
20
+ class MemorySystem {
21
+ private _semanticMemories: SemanticMemories
22
+ private _patternStore: PatternStore
23
+ private _historyStore: HistoryStore
24
+ private _sessionStore: SessionStore
25
+
26
+ constructor() {
27
+ this._semanticMemories = new SemanticMemories()
28
+ this._patternStore = new PatternStore()
29
+ this._historyStore = new HistoryStore()
30
+ this._sessionStore = new SessionStore()
31
+ }
32
+
33
+ // ═══════════════════════════════════════════════════════════
34
+ // P3.3: SEMANTIC MEMORIES
35
+ // ═══════════════════════════════════════════════════════════
36
+
37
+ loadMemories(projectId: string) {
38
+ return this._semanticMemories.loadMemories(projectId)
39
+ }
40
+
41
+ saveMemories(projectId: string) {
42
+ return this._semanticMemories.saveMemories(projectId)
43
+ }
44
+
45
+ createMemory(
46
+ projectId: string,
47
+ options: { title: string; content: string; tags?: string[]; userTriggered?: boolean }
48
+ ): Promise<string> {
49
+ return this._semanticMemories.createMemory(projectId, options)
50
+ }
51
+
52
+ updateMemory(
53
+ projectId: string,
54
+ memoryId: string,
55
+ updates: { title?: string; content?: string; tags?: string[] }
56
+ ): Promise<boolean> {
57
+ return this._semanticMemories.updateMemory(projectId, memoryId, updates)
58
+ }
59
+
60
+ deleteMemory(projectId: string, memoryId: string): Promise<boolean> {
61
+ return this._semanticMemories.deleteMemory(projectId, memoryId)
62
+ }
63
+
64
+ findByTags(projectId: string, tags: string[], matchAll?: boolean): Promise<Memory[]> {
65
+ return this._semanticMemories.findByTags(projectId, tags, matchAll)
66
+ }
67
+
68
+ searchMemories(projectId: string, query: string): Promise<Memory[]> {
69
+ return this._semanticMemories.searchMemories(projectId, query)
70
+ }
71
+
72
+ getRelevantMemories(projectId: string, context: Context, limit?: number): Promise<Memory[]> {
73
+ return this._semanticMemories.getRelevantMemories(projectId, context, limit)
74
+ }
75
+
76
+ autoRemember(projectId: string, decisionType: string, value: string, context?: string): Promise<void> {
77
+ return this._semanticMemories.autoRemember(projectId, decisionType, value, context)
78
+ }
79
+
80
+ getAllMemories(projectId: string): Promise<Memory[]> {
81
+ return this._semanticMemories.getAllMemories(projectId)
82
+ }
83
+
84
+ getMemoryStats(projectId: string) {
85
+ return this._semanticMemories.getMemoryStats(projectId)
86
+ }
87
+
88
+ // ═══════════════════════════════════════════════════════════
89
+ // TIER 1: Session Memory
90
+ // ═══════════════════════════════════════════════════════════
91
+
92
+ setSession(key: string, value: unknown): void {
93
+ this._sessionStore.setSession(key, value)
94
+ }
95
+
96
+ getSession(key: string): unknown {
97
+ return this._sessionStore.getSession(key)
98
+ }
99
+
100
+ clearSession(): void {
101
+ this._sessionStore.clearSession()
102
+ }
103
+
104
+ // ═══════════════════════════════════════════════════════════
105
+ // TIER 2: Patterns
106
+ // ═══════════════════════════════════════════════════════════
107
+
108
+ loadPatterns(projectId: string) {
109
+ return this._patternStore.loadPatterns(projectId)
110
+ }
111
+
112
+ savePatterns(projectId: string) {
113
+ return this._patternStore.savePatterns(projectId)
114
+ }
115
+
116
+ recordDecision(projectId: string, key: string, value: string, context?: string): Promise<void> {
117
+ return this._patternStore.recordDecision(projectId, key, value, context)
118
+ }
119
+
120
+ getDecision(projectId: string, key: string): Promise<{ value: string; confidence: string } | null> {
121
+ return this._patternStore.getDecision(projectId, key)
122
+ }
123
+
124
+ hasPattern(projectId: string, key: string): Promise<boolean> {
125
+ return this._patternStore.hasPattern(projectId, key)
126
+ }
127
+
128
+ recordWorkflow(projectId: string, workflowName: string, pattern: Record<string, unknown>): Promise<void> {
129
+ return this._patternStore.recordWorkflow(projectId, workflowName, pattern)
130
+ }
131
+
132
+ getWorkflow(projectId: string, workflowName: string): Promise<Workflow | null> {
133
+ return this._patternStore.getWorkflow(projectId, workflowName)
134
+ }
135
+
136
+ setPreference(projectId: string, key: string, value: unknown): Promise<void> {
137
+ return this._patternStore.setPreference(projectId, key, value)
138
+ }
139
+
140
+ getPreference(projectId: string, key: string, defaultValue?: unknown): Promise<unknown> {
141
+ return this._patternStore.getPreference(projectId, key, defaultValue)
142
+ }
143
+
144
+ getPatternsSummary(projectId: string) {
145
+ return this._patternStore.getPatternsSummary(projectId)
146
+ }
147
+
148
+ // ═══════════════════════════════════════════════════════════
149
+ // TIER 3: History
150
+ // ═══════════════════════════════════════════════════════════
151
+
152
+ appendHistory(projectId: string, entry: Record<string, unknown>): Promise<void> {
153
+ return this._historyStore.appendHistory(projectId, entry)
154
+ }
155
+
156
+ getRecentHistory(projectId: string, limit?: number) {
157
+ return this._historyStore.getRecentHistory(projectId, limit)
158
+ }
159
+
160
+ // ═══════════════════════════════════════════════════════════
161
+ // CONVENIENCE: Combined operations
162
+ // ═══════════════════════════════════════════════════════════
163
+
164
+ async getSmartDecision(projectId: string, key: string): Promise<string | null> {
165
+ const sessionValue = this.getSession(`decision:${key}`)
166
+ if (sessionValue !== undefined) return sessionValue as string
167
+
168
+ const pattern = await this.getDecision(projectId, key)
169
+ if (pattern) return pattern.value
170
+
171
+ return null
172
+ }
173
+
174
+ async learnDecision(projectId: string, key: string, value: string, context: string = ''): Promise<void> {
175
+ this.setSession(`decision:${key}`, value)
176
+ await this.recordDecision(projectId, key, value, context)
177
+ await this.appendHistory(projectId, { type: 'decision', key, value, context })
178
+ }
179
+
180
+ /**
181
+ * Reset internal state (for testing)
182
+ */
183
+ resetState(): void {
184
+ this._sessionStore.clearSession()
185
+ this._semanticMemories.reset()
186
+ this._patternStore.reset()
187
+ }
188
+ }
189
+
190
+ const memorySystem = new MemorySystem()
191
+ export default memorySystem
192
+ export { MemorySystem }
@@ -0,0 +1,156 @@
1
+ /**
2
+ * Patterns - Tier 2
3
+ * Persistent learned preferences and decisions.
4
+ */
5
+
6
+ import fs from 'fs/promises'
7
+ import path from 'path'
8
+ import pathManager from '../../infrastructure/path-manager'
9
+ import type { Patterns, Decision, Workflow } from './types'
10
+
11
+ export class PatternStore {
12
+ private _patterns: Patterns | null = null
13
+ private _patternsLoaded: boolean = false
14
+
15
+ private _getPatternsPath(projectId: string): string {
16
+ return path.join(pathManager.getGlobalProjectPath(projectId), 'memory', 'patterns.json')
17
+ }
18
+
19
+ async loadPatterns(projectId: string): Promise<Patterns> {
20
+ if (this._patternsLoaded && this._patterns) {
21
+ return this._patterns
22
+ }
23
+
24
+ try {
25
+ const patternsPath = this._getPatternsPath(projectId)
26
+ const content = await fs.readFile(patternsPath, 'utf-8')
27
+ this._patterns = JSON.parse(content)
28
+ this._patternsLoaded = true
29
+ return this._patterns!
30
+ } catch {
31
+ this._patterns = {
32
+ version: 1,
33
+ decisions: {},
34
+ preferences: {},
35
+ workflows: {},
36
+ counters: {},
37
+ }
38
+ this._patternsLoaded = true
39
+ return this._patterns
40
+ }
41
+ }
42
+
43
+ async savePatterns(projectId: string): Promise<void> {
44
+ if (!this._patterns) return
45
+
46
+ const patternsPath = this._getPatternsPath(projectId)
47
+ await fs.mkdir(path.dirname(patternsPath), { recursive: true })
48
+ await fs.writeFile(patternsPath, JSON.stringify(this._patterns, null, 2), 'utf-8')
49
+ }
50
+
51
+ async recordDecision(projectId: string, key: string, value: string, context: string = ''): Promise<void> {
52
+ const patterns = await this.loadPatterns(projectId)
53
+
54
+ if (!patterns.decisions[key]) {
55
+ patterns.decisions[key] = {
56
+ value,
57
+ count: 1,
58
+ firstSeen: new Date().toISOString(),
59
+ lastSeen: new Date().toISOString(),
60
+ confidence: 'low',
61
+ contexts: [context].filter(Boolean),
62
+ }
63
+ } else {
64
+ const decision = patterns.decisions[key]
65
+
66
+ if (decision.value === value) {
67
+ decision.count++
68
+ decision.lastSeen = new Date().toISOString()
69
+ if (context && !decision.contexts.includes(context)) {
70
+ decision.contexts.push(context)
71
+ }
72
+
73
+ if (decision.count >= 5) {
74
+ decision.confidence = 'high'
75
+ } else if (decision.count >= 3) {
76
+ decision.confidence = 'medium'
77
+ }
78
+ } else {
79
+ decision.value = value
80
+ decision.count = 1
81
+ decision.lastSeen = new Date().toISOString()
82
+ decision.confidence = 'low'
83
+ }
84
+ }
85
+
86
+ await this.savePatterns(projectId)
87
+ }
88
+
89
+ async getDecision(projectId: string, key: string): Promise<{ value: string; confidence: string } | null> {
90
+ const patterns = await this.loadPatterns(projectId)
91
+ const decision = patterns.decisions[key]
92
+
93
+ if (!decision) return null
94
+ if (decision.confidence === 'low') return null
95
+
96
+ return { value: decision.value, confidence: decision.confidence }
97
+ }
98
+
99
+ async hasPattern(projectId: string, key: string): Promise<boolean> {
100
+ const decision = await this.getDecision(projectId, key)
101
+ return decision !== null
102
+ }
103
+
104
+ async recordWorkflow(projectId: string, workflowName: string, pattern: Record<string, unknown>): Promise<void> {
105
+ const patterns = await this.loadPatterns(projectId)
106
+
107
+ if (!patterns.workflows[workflowName]) {
108
+ patterns.workflows[workflowName] = {
109
+ ...pattern,
110
+ count: 1,
111
+ firstSeen: new Date().toISOString(),
112
+ lastSeen: new Date().toISOString(),
113
+ }
114
+ } else {
115
+ patterns.workflows[workflowName].count++
116
+ patterns.workflows[workflowName].lastSeen = new Date().toISOString()
117
+ }
118
+
119
+ await this.savePatterns(projectId)
120
+ }
121
+
122
+ async getWorkflow(projectId: string, workflowName: string): Promise<Workflow | null> {
123
+ const patterns = await this.loadPatterns(projectId)
124
+ const workflow = patterns.workflows[workflowName]
125
+
126
+ if (!workflow || workflow.count < 3) return null
127
+ return workflow
128
+ }
129
+
130
+ async setPreference(projectId: string, key: string, value: unknown): Promise<void> {
131
+ const patterns = await this.loadPatterns(projectId)
132
+ patterns.preferences[key] = { value, updatedAt: new Date().toISOString() }
133
+ await this.savePatterns(projectId)
134
+ }
135
+
136
+ async getPreference(projectId: string, key: string, defaultValue: unknown = null): Promise<unknown> {
137
+ const patterns = await this.loadPatterns(projectId)
138
+ return patterns.preferences[key]?.value ?? defaultValue
139
+ }
140
+
141
+ async getPatternsSummary(projectId: string) {
142
+ const patterns = await this.loadPatterns(projectId)
143
+
144
+ return {
145
+ decisions: Object.keys(patterns.decisions).length,
146
+ learnedDecisions: Object.values(patterns.decisions).filter((d) => d.confidence !== 'low').length,
147
+ workflows: Object.keys(patterns.workflows).length,
148
+ preferences: Object.keys(patterns.preferences).length,
149
+ }
150
+ }
151
+
152
+ reset(): void {
153
+ this._patterns = null
154
+ this._patternsLoaded = false
155
+ }
156
+ }