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
@@ -1,845 +0,0 @@
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
- const fs = require('fs').promises
10
- const path = require('path')
11
- const pathManager = require('../infrastructure/path-manager')
12
-
13
- /**
14
- * Semantic tags for memory categorization
15
- * @enum {string}
16
- */
17
- const MEMORY_TAGS = {
18
- // Code preferences
19
- CODE_STYLE: 'code_style',
20
- NAMING_CONVENTION: 'naming_convention',
21
- FILE_STRUCTURE: 'file_structure',
22
-
23
- // Workflow preferences
24
- COMMIT_STYLE: 'commit_style',
25
- BRANCH_NAMING: 'branch_naming',
26
- TEST_BEHAVIOR: 'test_behavior',
27
- SHIP_WORKFLOW: 'ship_workflow',
28
-
29
- // Project context
30
- TECH_STACK: 'tech_stack',
31
- ARCHITECTURE: 'architecture',
32
- DEPENDENCIES: 'dependencies',
33
-
34
- // User preferences
35
- OUTPUT_VERBOSITY: 'output_verbosity',
36
- CONFIRMATION_LEVEL: 'confirmation_level',
37
- AGENT_PREFERENCE: 'agent_preference'
38
- }
39
-
40
- /**
41
- * Three-tier memory system for learning user patterns.
42
- * Tier 1: Session (ephemeral), Tier 2: Patterns (persistent), Tier 3: History (JSONL)
43
- */
44
- class MemorySystem {
45
- constructor() {
46
- /** @type {Map<string, {value: any, timestamp: number}>} */
47
- this._sessionMemory = new Map()
48
- /** @type {Object|null} */
49
- this._patterns = null
50
- /** @type {boolean} */
51
- this._patternsLoaded = false
52
- /** @type {Object|null} */
53
- this._memories = null
54
- /** @type {boolean} */
55
- this._memoriesLoaded = false
56
- }
57
-
58
- // ═══════════════════════════════════════════════════════════
59
- // P3.3: SEMANTIC MEMORIES (tagged, searchable, CRUD)
60
- // ═══════════════════════════════════════════════════════════
61
-
62
- /**
63
- * Get path to memories database
64
- * @param {string} projectId
65
- * @returns {string}
66
- */
67
- _getMemoriesPath(projectId) {
68
- return path.join(
69
- pathManager.getGlobalProjectPath(projectId),
70
- 'memory',
71
- 'memories.json'
72
- )
73
- }
74
-
75
- /**
76
- * Load memories database
77
- * @param {string} projectId
78
- * @returns {Promise<Object>}
79
- */
80
- async loadMemories(projectId) {
81
- if (this._memoriesLoaded && this._memories) {
82
- return this._memories
83
- }
84
-
85
- try {
86
- const memoriesPath = this._getMemoriesPath(projectId)
87
- const content = await fs.readFile(memoriesPath, 'utf-8')
88
- this._memories = JSON.parse(content)
89
- this._memoriesLoaded = true
90
- return this._memories
91
- } catch {
92
- this._memories = {
93
- version: 1,
94
- memories: [], // Array of memory entries
95
- index: {} // Tag -> memory IDs index
96
- }
97
- this._memoriesLoaded = true
98
- return this._memories
99
- }
100
- }
101
-
102
- /**
103
- * Save memories database
104
- * @param {string} projectId
105
- */
106
- async saveMemories(projectId) {
107
- if (!this._memories) return
108
-
109
- const memoriesPath = this._getMemoriesPath(projectId)
110
- await fs.mkdir(path.dirname(memoriesPath), { recursive: true })
111
- await fs.writeFile(
112
- memoriesPath,
113
- JSON.stringify(this._memories, null, 2),
114
- 'utf-8'
115
- )
116
- }
117
-
118
- /**
119
- * Create a new memory (Windsurf pattern)
120
- *
121
- * @param {string} projectId
122
- * @param {Object} memory
123
- * @param {string} memory.title - Short title
124
- * @param {string} memory.content - Memory content
125
- * @param {string[]} memory.tags - Semantic tags
126
- * @param {boolean} memory.userTriggered - If user explicitly asked
127
- * @returns {Promise<string>} Memory ID
128
- */
129
- async createMemory(projectId, { title, content, tags = [], userTriggered = false }) {
130
- const db = await this.loadMemories(projectId)
131
-
132
- const memory = {
133
- id: `mem_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
134
- title,
135
- content,
136
- tags,
137
- userTriggered,
138
- createdAt: new Date().toISOString(),
139
- updatedAt: new Date().toISOString()
140
- }
141
-
142
- db.memories.push(memory)
143
-
144
- // Update tag index
145
- for (const tag of tags) {
146
- if (!db.index[tag]) db.index[tag] = []
147
- db.index[tag].push(memory.id)
148
- }
149
-
150
- await this.saveMemories(projectId)
151
-
152
- // Log to history
153
- await this.appendHistory(projectId, {
154
- type: 'memory_create',
155
- memoryId: memory.id,
156
- title,
157
- tags,
158
- userTriggered
159
- })
160
-
161
- return memory.id
162
- }
163
-
164
- /**
165
- * Update an existing memory
166
- *
167
- * @param {string} projectId
168
- * @param {string} memoryId
169
- * @param {Object} updates
170
- * @returns {Promise<boolean>}
171
- */
172
- async updateMemory(projectId, memoryId, updates) {
173
- const db = await this.loadMemories(projectId)
174
-
175
- const index = db.memories.findIndex(m => m.id === memoryId)
176
- if (index === -1) return false
177
-
178
- const memory = db.memories[index]
179
- const oldTags = memory.tags || []
180
-
181
- // Apply updates
182
- if (updates.title) memory.title = updates.title
183
- if (updates.content) memory.content = updates.content
184
- if (updates.tags) {
185
- // Update tag index
186
- for (const tag of oldTags) {
187
- if (db.index[tag]) {
188
- db.index[tag] = db.index[tag].filter(id => id !== memoryId)
189
- }
190
- }
191
- for (const tag of updates.tags) {
192
- if (!db.index[tag]) db.index[tag] = []
193
- db.index[tag].push(memoryId)
194
- }
195
- memory.tags = updates.tags
196
- }
197
-
198
- memory.updatedAt = new Date().toISOString()
199
-
200
- await this.saveMemories(projectId)
201
-
202
- await this.appendHistory(projectId, {
203
- type: 'memory_update',
204
- memoryId,
205
- updates: Object.keys(updates)
206
- })
207
-
208
- return true
209
- }
210
-
211
- /**
212
- * Delete a memory
213
- *
214
- * @param {string} projectId
215
- * @param {string} memoryId
216
- * @returns {Promise<boolean>}
217
- */
218
- async deleteMemory(projectId, memoryId) {
219
- const db = await this.loadMemories(projectId)
220
-
221
- const index = db.memories.findIndex(m => m.id === memoryId)
222
- if (index === -1) return false
223
-
224
- const memory = db.memories[index]
225
-
226
- // Remove from tag index
227
- for (const tag of memory.tags || []) {
228
- if (db.index[tag]) {
229
- db.index[tag] = db.index[tag].filter(id => id !== memoryId)
230
- }
231
- }
232
-
233
- // Remove memory
234
- db.memories.splice(index, 1)
235
-
236
- await this.saveMemories(projectId)
237
-
238
- await this.appendHistory(projectId, {
239
- type: 'memory_delete',
240
- memoryId,
241
- title: memory.title
242
- })
243
-
244
- return true
245
- }
246
-
247
- /**
248
- * Find memories by tags
249
- *
250
- * @param {string} projectId
251
- * @param {string[]} tags - Tags to search for
252
- * @param {boolean} matchAll - If true, memory must have ALL tags
253
- * @returns {Promise<Object[]>}
254
- */
255
- async findByTags(projectId, tags, matchAll = false) {
256
- const db = await this.loadMemories(projectId)
257
-
258
- if (matchAll) {
259
- // Memory must have ALL tags
260
- return db.memories.filter(m =>
261
- tags.every(tag => (m.tags || []).includes(tag))
262
- )
263
- } else {
264
- // Memory must have ANY tag
265
- const matchingIds = new Set()
266
- for (const tag of tags) {
267
- const ids = db.index[tag] || []
268
- ids.forEach(id => matchingIds.add(id))
269
- }
270
- return db.memories.filter(m => matchingIds.has(m.id))
271
- }
272
- }
273
-
274
- /**
275
- * Search memories by content (simple text match)
276
- *
277
- * @param {string} projectId
278
- * @param {string} query
279
- * @returns {Promise<Object[]>}
280
- */
281
- async searchMemories(projectId, query) {
282
- const db = await this.loadMemories(projectId)
283
- const queryLower = query.toLowerCase()
284
-
285
- return db.memories.filter(m =>
286
- m.title.toLowerCase().includes(queryLower) ||
287
- m.content.toLowerCase().includes(queryLower)
288
- )
289
- }
290
-
291
- /**
292
- * Get relevant memories for current context
293
- * Scores memories by relevance to context
294
- *
295
- * @param {string} projectId
296
- * @param {Object} context - Current execution context
297
- * @param {number} limit - Max memories to return
298
- * @returns {Promise<Object[]>}
299
- */
300
- async getRelevantMemories(projectId, context, limit = 5) {
301
- const db = await this.loadMemories(projectId)
302
-
303
- // Score each memory by relevance
304
- const scored = db.memories.map(memory => {
305
- let score = 0
306
-
307
- // Tag relevance
308
- const contextTags = this._extractContextTags(context)
309
- for (const tag of memory.tags || []) {
310
- if (contextTags.includes(tag)) score += 10
311
- }
312
-
313
- // Recency boost (more recent = higher score)
314
- const age = Date.now() - new Date(memory.updatedAt).getTime()
315
- const daysSinceUpdate = age / (1000 * 60 * 60 * 24)
316
- score += Math.max(0, 5 - daysSinceUpdate) // Up to 5 points for recent
317
-
318
- // User triggered memories are more important
319
- if (memory.userTriggered) score += 5
320
-
321
- // Content keyword match
322
- const keywords = this._extractKeywords(context)
323
- for (const keyword of keywords) {
324
- if (memory.content.toLowerCase().includes(keyword)) score += 2
325
- if (memory.title.toLowerCase().includes(keyword)) score += 3
326
- }
327
-
328
- return { ...memory, _score: score }
329
- })
330
-
331
- // Sort by score and return top N
332
- return scored
333
- .filter(m => m._score > 0)
334
- .sort((a, b) => b._score - a._score)
335
- .slice(0, limit)
336
- .map(({ _score, ...memory }) => memory)
337
- }
338
-
339
- /**
340
- * Extract relevant tags from context
341
- * @private
342
- */
343
- _extractContextTags(context) {
344
- const tags = []
345
-
346
- // Command-based tags
347
- const commandTags = {
348
- ship: [MEMORY_TAGS.COMMIT_STYLE, MEMORY_TAGS.SHIP_WORKFLOW, MEMORY_TAGS.TEST_BEHAVIOR],
349
- feature: [MEMORY_TAGS.ARCHITECTURE, MEMORY_TAGS.CODE_STYLE],
350
- done: [MEMORY_TAGS.SHIP_WORKFLOW],
351
- analyze: [MEMORY_TAGS.TECH_STACK, MEMORY_TAGS.ARCHITECTURE],
352
- spec: [MEMORY_TAGS.ARCHITECTURE, MEMORY_TAGS.CODE_STYLE]
353
- }
354
-
355
- if (context.commandName && commandTags[context.commandName]) {
356
- tags.push(...commandTags[context.commandName])
357
- }
358
-
359
- return tags
360
- }
361
-
362
- /**
363
- * Extract keywords from context for matching
364
- * @private
365
- */
366
- _extractKeywords(context) {
367
- const keywords = []
368
-
369
- // From params
370
- if (context.params?.description) {
371
- keywords.push(...context.params.description.toLowerCase().split(/\s+/))
372
- }
373
- if (context.params?.feature) {
374
- keywords.push(...context.params.feature.toLowerCase().split(/\s+/))
375
- }
376
-
377
- // Filter common words
378
- const stopWords = ['the', 'a', 'an', 'is', 'are', 'to', 'for', 'and', 'or', 'in']
379
- return keywords.filter(k => k.length > 2 && !stopWords.includes(k))
380
- }
381
-
382
- /**
383
- * Auto-create memory from user decision
384
- * Called when user explicitly chooses something
385
- *
386
- * @param {string} projectId
387
- * @param {string} decisionType - Type of decision
388
- * @param {string} value - Chosen value
389
- * @param {string} context - Context of decision
390
- */
391
- async autoRemember(projectId, decisionType, value, context = '') {
392
- // Map decision types to tags
393
- const tagMap = {
394
- commit_footer: [MEMORY_TAGS.COMMIT_STYLE],
395
- branch_naming: [MEMORY_TAGS.BRANCH_NAMING],
396
- test_before_ship: [MEMORY_TAGS.TEST_BEHAVIOR, MEMORY_TAGS.SHIP_WORKFLOW],
397
- preferred_agent: [MEMORY_TAGS.AGENT_PREFERENCE],
398
- code_style: [MEMORY_TAGS.CODE_STYLE],
399
- verbosity: [MEMORY_TAGS.OUTPUT_VERBOSITY]
400
- }
401
-
402
- const tags = tagMap[decisionType] || []
403
-
404
- // Check if similar memory exists
405
- const existing = await this.searchMemories(projectId, decisionType)
406
- if (existing.length > 0) {
407
- // Update existing
408
- await this.updateMemory(projectId, existing[0].id, {
409
- content: `${decisionType}: ${value}`,
410
- tags
411
- })
412
- } else {
413
- // Create new
414
- await this.createMemory(projectId, {
415
- title: `Preference: ${decisionType}`,
416
- content: `${decisionType}: ${value}${context ? `\nContext: ${context}` : ''}`,
417
- tags,
418
- userTriggered: true
419
- })
420
- }
421
- }
422
-
423
- /**
424
- * Get all memories (for debugging/display)
425
- * @param {string} projectId
426
- * @returns {Promise<Object[]>}
427
- */
428
- async getAllMemories(projectId) {
429
- const db = await this.loadMemories(projectId)
430
- return db.memories
431
- }
432
-
433
- /**
434
- * Get memory stats
435
- * @param {string} projectId
436
- * @returns {Promise<Object>}
437
- */
438
- async getMemoryStats(projectId) {
439
- const db = await this.loadMemories(projectId)
440
-
441
- const tagCounts = {}
442
- for (const [tag, ids] of Object.entries(db.index)) {
443
- tagCounts[tag] = ids.length
444
- }
445
-
446
- return {
447
- totalMemories: db.memories.length,
448
- userTriggered: db.memories.filter(m => m.userTriggered).length,
449
- tagCounts,
450
- oldestMemory: db.memories[0]?.createdAt,
451
- newestMemory: db.memories[db.memories.length - 1]?.createdAt
452
- }
453
- }
454
-
455
- // ═══════════════════════════════════════════════════════════
456
- // TIER 1: Session Memory (ephemeral, single command context)
457
- // ═══════════════════════════════════════════════════════════
458
-
459
- /**
460
- * Store value in session memory
461
- * @param {string} key - Memory key
462
- * @param {any} value - Value to store
463
- */
464
- setSession(key, value) {
465
- this._sessionMemory.set(key, {
466
- value,
467
- timestamp: Date.now()
468
- })
469
- }
470
-
471
- /**
472
- * Get value from session memory
473
- * @param {string} key - Memory key
474
- * @returns {any} Stored value or undefined
475
- */
476
- getSession(key) {
477
- const entry = this._sessionMemory.get(key)
478
- return entry?.value
479
- }
480
-
481
- /**
482
- * Clear session memory
483
- */
484
- clearSession() {
485
- this._sessionMemory.clear()
486
- }
487
-
488
- // ═══════════════════════════════════════════════════════════
489
- // TIER 2: Patterns (persistent, learned preferences)
490
- // ═══════════════════════════════════════════════════════════
491
-
492
- /**
493
- * Get path to patterns file
494
- * @param {string} projectId - Project ID
495
- * @returns {string} Path to patterns.json
496
- */
497
- _getPatternsPath(projectId) {
498
- return path.join(
499
- pathManager.getGlobalProjectPath(projectId),
500
- 'memory',
501
- 'patterns.json'
502
- )
503
- }
504
-
505
- /**
506
- * Load patterns from disk
507
- * @param {string} projectId - Project ID
508
- * @returns {Promise<Object>} Patterns object
509
- */
510
- async loadPatterns(projectId) {
511
- if (this._patternsLoaded && this._patterns) {
512
- return this._patterns
513
- }
514
-
515
- try {
516
- const patternsPath = this._getPatternsPath(projectId)
517
- const content = await fs.readFile(patternsPath, 'utf-8')
518
- this._patterns = JSON.parse(content)
519
- this._patternsLoaded = true
520
- return this._patterns
521
- } catch {
522
- // Initialize empty patterns
523
- this._patterns = {
524
- version: 1,
525
- decisions: {}, // Key decisions (e.g., commit_footer, branch_naming)
526
- preferences: {}, // User preferences (e.g., output_verbosity)
527
- workflows: {}, // Workflow patterns (e.g., quick_ship for small changes)
528
- counters: {} // Usage counters for learning
529
- }
530
- this._patternsLoaded = true
531
- return this._patterns
532
- }
533
- }
534
-
535
- /**
536
- * Save patterns to disk
537
- * @param {string} projectId - Project ID
538
- */
539
- async savePatterns(projectId) {
540
- if (!this._patterns) return
541
-
542
- const patternsPath = this._getPatternsPath(projectId)
543
-
544
- // Ensure directory exists
545
- await fs.mkdir(path.dirname(patternsPath), { recursive: true })
546
-
547
- await fs.writeFile(
548
- patternsPath,
549
- JSON.stringify(this._patterns, null, 2),
550
- 'utf-8'
551
- )
552
- }
553
-
554
- /**
555
- * Record a decision pattern
556
- * After 3 consistent uses, pattern becomes "learned"
557
- *
558
- * @param {string} projectId - Project ID
559
- * @param {string} key - Decision key (e.g., "commit_footer")
560
- * @param {string} value - Decision value
561
- * @param {string} context - Context where decision was made
562
- */
563
- async recordDecision(projectId, key, value, context = '') {
564
- const patterns = await this.loadPatterns(projectId)
565
-
566
- // Initialize or update decision
567
- if (!patterns.decisions[key]) {
568
- patterns.decisions[key] = {
569
- value,
570
- count: 1,
571
- firstSeen: new Date().toISOString(),
572
- lastSeen: new Date().toISOString(),
573
- confidence: 'low',
574
- contexts: [context].filter(Boolean)
575
- }
576
- } else {
577
- const decision = patterns.decisions[key]
578
-
579
- if (decision.value === value) {
580
- // Same value - increase confidence
581
- decision.count++
582
- decision.lastSeen = new Date().toISOString()
583
- if (context && !decision.contexts.includes(context)) {
584
- decision.contexts.push(context)
585
- }
586
-
587
- // Update confidence based on count
588
- if (decision.count >= 5) {
589
- decision.confidence = 'high'
590
- } else if (decision.count >= 3) {
591
- decision.confidence = 'medium'
592
- }
593
- } else {
594
- // Different value - reset if new value is used more
595
- decision.value = value
596
- decision.count = 1
597
- decision.lastSeen = new Date().toISOString()
598
- decision.confidence = 'low'
599
- }
600
- }
601
-
602
- await this.savePatterns(projectId)
603
- }
604
-
605
- /**
606
- * Get a learned decision
607
- * Returns null if not learned (confidence < medium)
608
- *
609
- * @param {string} projectId - Project ID
610
- * @param {string} key - Decision key
611
- * @returns {Promise<{value: string, confidence: string}|null>}
612
- */
613
- async getDecision(projectId, key) {
614
- const patterns = await this.loadPatterns(projectId)
615
- const decision = patterns.decisions[key]
616
-
617
- if (!decision) return null
618
-
619
- // Only return if confidence is at least medium
620
- if (decision.confidence === 'low') return null
621
-
622
- return {
623
- value: decision.value,
624
- confidence: decision.confidence
625
- }
626
- }
627
-
628
- /**
629
- * Check if a pattern exists (for quick checks)
630
- * @param {string} projectId - Project ID
631
- * @param {string} key - Pattern key
632
- * @returns {Promise<boolean>}
633
- */
634
- async hasPattern(projectId, key) {
635
- const decision = await this.getDecision(projectId, key)
636
- return decision !== null
637
- }
638
-
639
- /**
640
- * Record a workflow pattern
641
- * E.g., "user ships docs changes without running tests"
642
- *
643
- * @param {string} projectId - Project ID
644
- * @param {string} workflowName - Workflow identifier
645
- * @param {Object} pattern - Workflow pattern details
646
- */
647
- async recordWorkflow(projectId, workflowName, pattern) {
648
- const patterns = await this.loadPatterns(projectId)
649
-
650
- if (!patterns.workflows[workflowName]) {
651
- patterns.workflows[workflowName] = {
652
- ...pattern,
653
- count: 1,
654
- firstSeen: new Date().toISOString(),
655
- lastSeen: new Date().toISOString()
656
- }
657
- } else {
658
- patterns.workflows[workflowName].count++
659
- patterns.workflows[workflowName].lastSeen = new Date().toISOString()
660
- }
661
-
662
- await this.savePatterns(projectId)
663
- }
664
-
665
- /**
666
- * Get workflow pattern if learned
667
- * @param {string} projectId - Project ID
668
- * @param {string} workflowName - Workflow identifier
669
- * @returns {Promise<Object|null>}
670
- */
671
- async getWorkflow(projectId, workflowName) {
672
- const patterns = await this.loadPatterns(projectId)
673
- const workflow = patterns.workflows[workflowName]
674
-
675
- if (!workflow || workflow.count < 3) return null
676
-
677
- return workflow
678
- }
679
-
680
- /**
681
- * Set user preference
682
- * @param {string} projectId - Project ID
683
- * @param {string} key - Preference key
684
- * @param {any} value - Preference value
685
- */
686
- async setPreference(projectId, key, value) {
687
- const patterns = await this.loadPatterns(projectId)
688
- patterns.preferences[key] = {
689
- value,
690
- updatedAt: new Date().toISOString()
691
- }
692
- await this.savePatterns(projectId)
693
- }
694
-
695
- /**
696
- * Get user preference
697
- * @param {string} projectId - Project ID
698
- * @param {string} key - Preference key
699
- * @param {any} defaultValue - Default if not set
700
- * @returns {Promise<any>}
701
- */
702
- async getPreference(projectId, key, defaultValue = null) {
703
- const patterns = await this.loadPatterns(projectId)
704
- return patterns.preferences[key]?.value ?? defaultValue
705
- }
706
-
707
- // ═══════════════════════════════════════════════════════════
708
- // TIER 3: History (append-only JSONL audit log)
709
- // ═══════════════════════════════════════════════════════════
710
-
711
- /**
712
- * Get path to today's session file
713
- * @param {string} projectId - Project ID
714
- * @returns {string} Path to session JSONL
715
- */
716
- _getSessionPath(projectId) {
717
- const now = new Date()
718
- const yearMonth = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}`
719
- const day = now.toISOString().split('T')[0]
720
-
721
- return path.join(
722
- pathManager.getGlobalProjectPath(projectId),
723
- 'memory',
724
- 'sessions',
725
- yearMonth,
726
- `${day}.jsonl`
727
- )
728
- }
729
-
730
- /**
731
- * Append entry to history (JSONL)
732
- * @param {string} projectId - Project ID
733
- * @param {Object} entry - Entry to log
734
- */
735
- async appendHistory(projectId, entry) {
736
- const sessionPath = this._getSessionPath(projectId)
737
-
738
- // Ensure directory exists
739
- await fs.mkdir(path.dirname(sessionPath), { recursive: true })
740
-
741
- const logEntry = {
742
- ts: new Date().toISOString(),
743
- ...entry
744
- }
745
-
746
- await fs.appendFile(
747
- sessionPath,
748
- JSON.stringify(logEntry) + '\n',
749
- 'utf-8'
750
- )
751
- }
752
-
753
- /**
754
- * Read recent history entries
755
- * @param {string} projectId - Project ID
756
- * @param {number} limit - Max entries to return
757
- * @returns {Promise<Object[]>}
758
- */
759
- async getRecentHistory(projectId, limit = 20) {
760
- try {
761
- const sessionPath = this._getSessionPath(projectId)
762
- const content = await fs.readFile(sessionPath, 'utf-8')
763
- const lines = content.trim().split('\n').filter(Boolean)
764
-
765
- return lines
766
- .slice(-limit)
767
- .map(line => {
768
- try {
769
- return JSON.parse(line)
770
- } catch {
771
- return null
772
- }
773
- })
774
- .filter(Boolean)
775
- } catch {
776
- return []
777
- }
778
- }
779
-
780
- // ═══════════════════════════════════════════════════════════
781
- // CONVENIENCE: Combined operations
782
- // ═══════════════════════════════════════════════════════════
783
-
784
- /**
785
- * Smart decision: Check pattern first, ask user only if unknown
786
- * Returns existing pattern or null (caller should ask user)
787
- *
788
- * @param {string} projectId - Project ID
789
- * @param {string} key - Decision key
790
- * @returns {Promise<string|null>} Known value or null
791
- */
792
- async getSmartDecision(projectId, key) {
793
- // Check session first (most recent)
794
- const sessionValue = this.getSession(`decision:${key}`)
795
- if (sessionValue !== undefined) return sessionValue
796
-
797
- // Check learned patterns
798
- const pattern = await this.getDecision(projectId, key)
799
- if (pattern) return pattern.value
800
-
801
- return null
802
- }
803
-
804
- /**
805
- * Record decision and store in session
806
- * @param {string} projectId - Project ID
807
- * @param {string} key - Decision key
808
- * @param {string} value - Decision value
809
- * @param {string} context - Context
810
- */
811
- async learnDecision(projectId, key, value, context = '') {
812
- // Store in session for immediate reuse
813
- this.setSession(`decision:${key}`, value)
814
-
815
- // Record in patterns for future sessions
816
- await this.recordDecision(projectId, key, value, context)
817
-
818
- // Log to history
819
- await this.appendHistory(projectId, {
820
- type: 'decision',
821
- key,
822
- value,
823
- context
824
- })
825
- }
826
-
827
- /**
828
- * Get all patterns summary (for debugging/display)
829
- * @param {string} projectId - Project ID
830
- * @returns {Promise<Object>}
831
- */
832
- async getPatternsSummary(projectId) {
833
- const patterns = await this.loadPatterns(projectId)
834
-
835
- return {
836
- decisions: Object.keys(patterns.decisions).length,
837
- learnedDecisions: Object.values(patterns.decisions)
838
- .filter(d => d.confidence !== 'low').length,
839
- workflows: Object.keys(patterns.workflows).length,
840
- preferences: Object.keys(patterns.preferences).length
841
- }
842
- }
843
- }
844
-
845
- module.exports = new MemorySystem()