prjct-cli 1.21.0 → 1.23.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 (447) hide show
  1. package/CHANGELOG.md +244 -0
  2. package/README.md +41 -0
  3. package/bin/prjct +30 -13
  4. package/dist/bin/prjct.mjs +919 -35601
  5. package/dist/bin/prjct.mjs.map +7 -0
  6. package/dist/cli/linear.mjs +16 -0
  7. package/dist/cli/linear.mjs.map +7 -0
  8. package/dist/templates.json +1 -0
  9. package/package.json +4 -5
  10. package/bin/prjct.ts +0 -342
  11. package/core/__tests__/agentic/analysis-injection.test.ts +0 -377
  12. package/core/__tests__/agentic/cache-eviction.test.ts +0 -294
  13. package/core/__tests__/agentic/command-context.test.ts +0 -281
  14. package/core/__tests__/agentic/command-executor.test.ts +0 -659
  15. package/core/__tests__/agentic/domain-classifier.test.ts +0 -330
  16. package/core/__tests__/agentic/injection-validator.test.ts +0 -255
  17. package/core/__tests__/agentic/memory-system.test.ts +0 -281
  18. package/core/__tests__/agentic/plan-mode.test.ts +0 -386
  19. package/core/__tests__/agentic/prompt-assembly.test.ts +0 -298
  20. package/core/__tests__/agentic/prompt-builder.test.ts +0 -243
  21. package/core/__tests__/agentic/response-validator.test.ts +0 -263
  22. package/core/__tests__/agentic/semantic-matching.test.ts +0 -131
  23. package/core/__tests__/agentic/smart-context.test.ts +0 -372
  24. package/core/__tests__/agentic/tech-normalizer.test.ts +0 -136
  25. package/core/__tests__/agentic/token-budget.test.ts +0 -294
  26. package/core/__tests__/ai-tools/formatters.test.ts +0 -476
  27. package/core/__tests__/domain/bm25.test.ts +0 -225
  28. package/core/__tests__/domain/change-propagator.test.ts +0 -100
  29. package/core/__tests__/domain/fibonacci.test.ts +0 -113
  30. package/core/__tests__/domain/file-hasher.test.ts +0 -146
  31. package/core/__tests__/domain/file-ranker.test.ts +0 -169
  32. package/core/__tests__/domain/git-cochange.test.ts +0 -121
  33. package/core/__tests__/domain/import-graph.test.ts +0 -156
  34. package/core/__tests__/domain/velocity.test.ts +0 -623
  35. package/core/__tests__/infrastructure/performance-tracker.test.ts +0 -328
  36. package/core/__tests__/schemas/model.test.ts +0 -272
  37. package/core/__tests__/services/dependency-validator.test.ts +0 -175
  38. package/core/__tests__/services/hierarchical-agent-resolver.test.ts +0 -359
  39. package/core/__tests__/services/nested-context-resolver.test.ts +0 -443
  40. package/core/__tests__/services/project-index.test.ts +0 -355
  41. package/core/__tests__/services/staleness-checker.test.ts +0 -204
  42. package/core/__tests__/storage/analysis-storage.test.ts +0 -641
  43. package/core/__tests__/storage/archive-storage.test.ts +0 -455
  44. package/core/__tests__/storage/safe-reader.test.ts +0 -262
  45. package/core/__tests__/storage/sqlite-migration.test.ts +0 -1016
  46. package/core/__tests__/storage/storage-manager.test.ts +0 -383
  47. package/core/__tests__/storage/subtask-handoff.test.ts +0 -237
  48. package/core/__tests__/types/fs.test.ts +0 -125
  49. package/core/__tests__/utils/date-helper.test.ts +0 -449
  50. package/core/__tests__/utils/output.test.ts +0 -278
  51. package/core/__tests__/utils/preserve-sections.test.ts +0 -216
  52. package/core/__tests__/utils/project-commands.test.ts +0 -71
  53. package/core/__tests__/utils/retry.test.ts +0 -381
  54. package/core/__tests__/workflow/state-machine.test.ts +0 -216
  55. package/core/agentic/agent-router.ts +0 -150
  56. package/core/agentic/anti-hallucination.ts +0 -141
  57. package/core/agentic/chain-of-thought.ts +0 -234
  58. package/core/agentic/command-classifier.ts +0 -141
  59. package/core/agentic/command-context.ts +0 -168
  60. package/core/agentic/command-executor.ts +0 -471
  61. package/core/agentic/context-builder.ts +0 -285
  62. package/core/agentic/domain-classifier.ts +0 -525
  63. package/core/agentic/environment-block.ts +0 -102
  64. package/core/agentic/ground-truth.ts +0 -706
  65. package/core/agentic/index.ts +0 -193
  66. package/core/agentic/injection-validator.ts +0 -208
  67. package/core/agentic/loop-detector.ts +0 -451
  68. package/core/agentic/memory-system.ts +0 -1547
  69. package/core/agentic/orchestrator-executor.ts +0 -579
  70. package/core/agentic/plan-mode.ts +0 -525
  71. package/core/agentic/prompt-builder.ts +0 -1069
  72. package/core/agentic/response-validator.ts +0 -98
  73. package/core/agentic/services.ts +0 -167
  74. package/core/agentic/skill-loader.ts +0 -106
  75. package/core/agentic/smart-context.ts +0 -393
  76. package/core/agentic/tech-normalizer.ts +0 -167
  77. package/core/agentic/template-executor.ts +0 -272
  78. package/core/agentic/template-loader.ts +0 -109
  79. package/core/agentic/token-budget.ts +0 -226
  80. package/core/agentic/tool-registry.ts +0 -146
  81. package/core/agents/index.ts +0 -28
  82. package/core/agents/performance.ts +0 -429
  83. package/core/ai-tools/formatters.ts +0 -341
  84. package/core/ai-tools/generator.ts +0 -144
  85. package/core/ai-tools/index.ts +0 -15
  86. package/core/ai-tools/registry.ts +0 -201
  87. package/core/bus/bus.ts +0 -314
  88. package/core/bus/index.ts +0 -8
  89. package/core/cli/linear.ts +0 -500
  90. package/core/cli/lint-meta-commentary.ts +0 -177
  91. package/core/cli/start.ts +0 -386
  92. package/core/commands/analysis.ts +0 -1274
  93. package/core/commands/analytics.ts +0 -342
  94. package/core/commands/base.ts +0 -118
  95. package/core/commands/cleanup.ts +0 -157
  96. package/core/commands/command-data.ts +0 -463
  97. package/core/commands/commands.ts +0 -306
  98. package/core/commands/context.ts +0 -238
  99. package/core/commands/design.ts +0 -77
  100. package/core/commands/index.ts +0 -19
  101. package/core/commands/maintenance.ts +0 -77
  102. package/core/commands/performance.ts +0 -114
  103. package/core/commands/planning.ts +0 -662
  104. package/core/commands/register.ts +0 -127
  105. package/core/commands/registry.ts +0 -444
  106. package/core/commands/setup.ts +0 -280
  107. package/core/commands/shipping.ts +0 -267
  108. package/core/commands/snapshots.ts +0 -297
  109. package/core/commands/uninstall.ts +0 -542
  110. package/core/commands/velocity.ts +0 -149
  111. package/core/commands/workflow.ts +0 -502
  112. package/core/config/command-context.config.json +0 -66
  113. package/core/constants/index.ts +0 -379
  114. package/core/context/generator.ts +0 -368
  115. package/core/context-tools/files-tool.ts +0 -577
  116. package/core/context-tools/imports-tool.ts +0 -400
  117. package/core/context-tools/index.ts +0 -434
  118. package/core/context-tools/recent-tool.ts +0 -301
  119. package/core/context-tools/signatures-tool.ts +0 -495
  120. package/core/context-tools/summary-tool.ts +0 -301
  121. package/core/context-tools/token-counter.ts +0 -273
  122. package/core/context-tools/types.ts +0 -253
  123. package/core/domain/agent-generator.ts +0 -186
  124. package/core/domain/agent-loader.ts +0 -419
  125. package/core/domain/analyzer.ts +0 -387
  126. package/core/domain/architecture-generator.ts +0 -108
  127. package/core/domain/bm25.ts +0 -525
  128. package/core/domain/change-propagator.ts +0 -162
  129. package/core/domain/context-estimator.ts +0 -175
  130. package/core/domain/fibonacci.ts +0 -128
  131. package/core/domain/file-hasher.ts +0 -296
  132. package/core/domain/file-ranker.ts +0 -151
  133. package/core/domain/git-cochange.ts +0 -250
  134. package/core/domain/import-graph.ts +0 -315
  135. package/core/domain/snapshot-manager.ts +0 -415
  136. package/core/domain/task-stack.ts +0 -578
  137. package/core/domain/velocity.ts +0 -470
  138. package/core/errors.ts +0 -335
  139. package/core/events/events.ts +0 -85
  140. package/core/events/index.ts +0 -8
  141. package/core/index.ts +0 -481
  142. package/core/infrastructure/agent-detector.ts +0 -135
  143. package/core/infrastructure/ai-provider.ts +0 -578
  144. package/core/infrastructure/author-detector.ts +0 -133
  145. package/core/infrastructure/capability-installer.ts +0 -76
  146. package/core/infrastructure/claude-agent.ts +0 -297
  147. package/core/infrastructure/command-installer.ts +0 -752
  148. package/core/infrastructure/config-manager.ts +0 -364
  149. package/core/infrastructure/editors-config.ts +0 -172
  150. package/core/infrastructure/path-manager.ts +0 -571
  151. package/core/infrastructure/performance-tracker.ts +0 -326
  152. package/core/infrastructure/permission-manager.ts +0 -289
  153. package/core/infrastructure/setup.ts +0 -1061
  154. package/core/infrastructure/update-checker.ts +0 -246
  155. package/core/integrations/issue-tracker/enricher.ts +0 -271
  156. package/core/integrations/issue-tracker/index.ts +0 -8
  157. package/core/integrations/issue-tracker/manager.ts +0 -286
  158. package/core/integrations/issue-tracker/types.ts +0 -310
  159. package/core/integrations/jira/cache.ts +0 -57
  160. package/core/integrations/jira/client.ts +0 -688
  161. package/core/integrations/jira/index.ts +0 -23
  162. package/core/integrations/jira/service.ts +0 -244
  163. package/core/integrations/linear/cache.ts +0 -68
  164. package/core/integrations/linear/client.ts +0 -436
  165. package/core/integrations/linear/index.ts +0 -20
  166. package/core/integrations/linear/service.ts +0 -260
  167. package/core/integrations/linear/sync.ts +0 -314
  168. package/core/outcomes/analyzer.ts +0 -286
  169. package/core/outcomes/index.ts +0 -34
  170. package/core/outcomes/recorder.ts +0 -195
  171. package/core/plugin/builtin/webhook.ts +0 -148
  172. package/core/plugin/hooks.ts +0 -315
  173. package/core/plugin/index.ts +0 -50
  174. package/core/plugin/loader.ts +0 -354
  175. package/core/plugin/registry.ts +0 -326
  176. package/core/schemas/agents.ts +0 -27
  177. package/core/schemas/analysis.ts +0 -530
  178. package/core/schemas/classification.ts +0 -91
  179. package/core/schemas/command-context.ts +0 -29
  180. package/core/schemas/enriched-task.ts +0 -291
  181. package/core/schemas/ideas.ts +0 -114
  182. package/core/schemas/index.ts +0 -53
  183. package/core/schemas/issues.ts +0 -159
  184. package/core/schemas/llm-output.ts +0 -170
  185. package/core/schemas/metrics.ts +0 -143
  186. package/core/schemas/model.ts +0 -153
  187. package/core/schemas/outcomes.ts +0 -487
  188. package/core/schemas/performance.ts +0 -128
  189. package/core/schemas/permissions.ts +0 -180
  190. package/core/schemas/prd.ts +0 -450
  191. package/core/schemas/project.ts +0 -57
  192. package/core/schemas/roadmap.ts +0 -322
  193. package/core/schemas/schemas.ts +0 -38
  194. package/core/schemas/shipped.ts +0 -109
  195. package/core/schemas/state.ts +0 -241
  196. package/core/schemas/velocity.ts +0 -103
  197. package/core/server/index.ts +0 -21
  198. package/core/server/routes-extended.ts +0 -566
  199. package/core/server/routes.ts +0 -176
  200. package/core/server/server.ts +0 -149
  201. package/core/server/sse.ts +0 -192
  202. package/core/services/agent-generator.ts +0 -316
  203. package/core/services/agent-service.ts +0 -168
  204. package/core/services/breakdown-service.ts +0 -124
  205. package/core/services/context-generator.ts +0 -445
  206. package/core/services/context-selector.ts +0 -429
  207. package/core/services/dependency-validator.ts +0 -318
  208. package/core/services/diff-generator.ts +0 -313
  209. package/core/services/doctor-service.ts +0 -423
  210. package/core/services/file-categorizer.ts +0 -448
  211. package/core/services/file-scorer.ts +0 -270
  212. package/core/services/git-analyzer.ts +0 -293
  213. package/core/services/hierarchical-agent-resolver.ts +0 -236
  214. package/core/services/hooks-service.ts +0 -685
  215. package/core/services/index.ts +0 -46
  216. package/core/services/local-state-generator.ts +0 -158
  217. package/core/services/memory-service.ts +0 -181
  218. package/core/services/nested-context-resolver.ts +0 -842
  219. package/core/services/project-index.ts +0 -911
  220. package/core/services/project-service.ts +0 -155
  221. package/core/services/session-tracker.ts +0 -287
  222. package/core/services/skill-installer.ts +0 -447
  223. package/core/services/skill-lock.ts +0 -132
  224. package/core/services/skill-service.ts +0 -306
  225. package/core/services/stack-detector.ts +0 -229
  226. package/core/services/staleness-checker.ts +0 -327
  227. package/core/services/sync-service.ts +0 -1404
  228. package/core/services/sync-verifier.ts +0 -253
  229. package/core/services/watch-service.ts +0 -312
  230. package/core/session/compaction.ts +0 -248
  231. package/core/session/index.ts +0 -35
  232. package/core/session/log-migration.ts +0 -88
  233. package/core/session/metrics.ts +0 -323
  234. package/core/session/session-log-manager.ts +0 -307
  235. package/core/session/task-session-manager.ts +0 -404
  236. package/core/session/utils.ts +0 -51
  237. package/core/storage/analysis-storage.ts +0 -373
  238. package/core/storage/archive-storage.ts +0 -205
  239. package/core/storage/database.ts +0 -575
  240. package/core/storage/ideas-storage.ts +0 -298
  241. package/core/storage/index-storage.ts +0 -523
  242. package/core/storage/index.ts +0 -79
  243. package/core/storage/metrics-storage.ts +0 -321
  244. package/core/storage/migrate-json.ts +0 -720
  245. package/core/storage/queue-storage.ts +0 -336
  246. package/core/storage/safe-reader.ts +0 -105
  247. package/core/storage/shipped-storage.ts +0 -253
  248. package/core/storage/state-storage.ts +0 -848
  249. package/core/storage/storage-manager.ts +0 -205
  250. package/core/storage/storage.ts +0 -177
  251. package/core/storage/velocity-storage.ts +0 -149
  252. package/core/sync/auth-config.ts +0 -138
  253. package/core/sync/index.ts +0 -31
  254. package/core/sync/oauth-handler.ts +0 -143
  255. package/core/sync/sync-client.ts +0 -251
  256. package/core/sync/sync-manager.ts +0 -327
  257. package/core/tsconfig.json +0 -22
  258. package/core/types/agentic.ts +0 -760
  259. package/core/types/agents.ts +0 -150
  260. package/core/types/bus.ts +0 -193
  261. package/core/types/citations.ts +0 -22
  262. package/core/types/commands.ts +0 -399
  263. package/core/types/config.ts +0 -92
  264. package/core/types/core.ts +0 -96
  265. package/core/types/diff.ts +0 -41
  266. package/core/types/domain.ts +0 -71
  267. package/core/types/errors.ts +0 -111
  268. package/core/types/events.ts +0 -42
  269. package/core/types/fs.ts +0 -72
  270. package/core/types/index.ts +0 -510
  271. package/core/types/infrastructure.ts +0 -210
  272. package/core/types/integrations.ts +0 -31
  273. package/core/types/jira.ts +0 -51
  274. package/core/types/logger.ts +0 -17
  275. package/core/types/memory.ts +0 -313
  276. package/core/types/outcomes.ts +0 -190
  277. package/core/types/output.ts +0 -47
  278. package/core/types/plugin.ts +0 -25
  279. package/core/types/project-sync.ts +0 -129
  280. package/core/types/provider.ts +0 -163
  281. package/core/types/server.ts +0 -71
  282. package/core/types/services.ts +0 -84
  283. package/core/types/session.ts +0 -135
  284. package/core/types/stack.ts +0 -19
  285. package/core/types/storage.ts +0 -318
  286. package/core/types/sync-verifier.ts +0 -33
  287. package/core/types/sync.ts +0 -121
  288. package/core/types/task.ts +0 -72
  289. package/core/types/template.ts +0 -24
  290. package/core/types/utils.ts +0 -92
  291. package/core/types/workflow.ts +0 -23
  292. package/core/utils/agent-stream.ts +0 -140
  293. package/core/utils/animations.ts +0 -251
  294. package/core/utils/branding.ts +0 -88
  295. package/core/utils/cache.ts +0 -187
  296. package/core/utils/citations.ts +0 -39
  297. package/core/utils/collection-filters.ts +0 -209
  298. package/core/utils/date-helper.ts +0 -176
  299. package/core/utils/error-messages.ts +0 -38
  300. package/core/utils/file-helper.ts +0 -277
  301. package/core/utils/fs-helpers.ts +0 -14
  302. package/core/utils/help.ts +0 -314
  303. package/core/utils/jsonl-helper.ts +0 -290
  304. package/core/utils/keychain.ts +0 -127
  305. package/core/utils/logger.ts +0 -77
  306. package/core/utils/markdown-builder.ts +0 -280
  307. package/core/utils/next-steps.ts +0 -95
  308. package/core/utils/output.ts +0 -403
  309. package/core/utils/preserve-sections.ts +0 -218
  310. package/core/utils/project-commands.ts +0 -126
  311. package/core/utils/project-credentials.ts +0 -143
  312. package/core/utils/provider-cache.ts +0 -49
  313. package/core/utils/retry.ts +0 -318
  314. package/core/utils/runtime.ts +0 -108
  315. package/core/utils/session-helper.ts +0 -278
  316. package/core/utils/subtask-table.ts +0 -227
  317. package/core/utils/version.ts +0 -128
  318. package/core/wizard/index.ts +0 -13
  319. package/core/wizard/onboarding.ts +0 -633
  320. package/core/workflow/index.ts +0 -7
  321. package/core/workflow/state-machine.ts +0 -198
  322. package/core/workflow/workflow-preferences.ts +0 -294
  323. package/dist/core/infrastructure/command-installer.js +0 -1141
  324. package/dist/core/infrastructure/editors-config.js +0 -177
  325. package/dist/core/infrastructure/setup.js +0 -2244
  326. package/dist/core/utils/version.js +0 -141
  327. package/templates/agentic/agent-routing.md +0 -45
  328. package/templates/agentic/agents/uxui.md +0 -63
  329. package/templates/agentic/checklist-routing.md +0 -98
  330. package/templates/agentic/orchestrator.md +0 -68
  331. package/templates/agentic/task-fragmentation.md +0 -89
  332. package/templates/agents/AGENTS.md +0 -68
  333. package/templates/analysis/analyze.md +0 -84
  334. package/templates/analysis/patterns.md +0 -60
  335. package/templates/antigravity/SKILL.md +0 -39
  336. package/templates/architect/discovery.md +0 -67
  337. package/templates/architect/phases.md +0 -59
  338. package/templates/checklists/architecture.md +0 -28
  339. package/templates/checklists/code-quality.md +0 -28
  340. package/templates/checklists/data.md +0 -33
  341. package/templates/checklists/documentation.md +0 -33
  342. package/templates/checklists/infrastructure.md +0 -33
  343. package/templates/checklists/performance.md +0 -33
  344. package/templates/checklists/security.md +0 -33
  345. package/templates/checklists/testing.md +0 -33
  346. package/templates/checklists/ux-ui.md +0 -37
  347. package/templates/commands/analyze.md +0 -56
  348. package/templates/commands/auth.md +0 -234
  349. package/templates/commands/bug.md +0 -163
  350. package/templates/commands/cleanup.md +0 -19
  351. package/templates/commands/dash.md +0 -99
  352. package/templates/commands/design.md +0 -15
  353. package/templates/commands/done.md +0 -291
  354. package/templates/commands/enrich.md +0 -174
  355. package/templates/commands/git.md +0 -295
  356. package/templates/commands/history.md +0 -389
  357. package/templates/commands/idea.md +0 -88
  358. package/templates/commands/impact.md +0 -864
  359. package/templates/commands/init.md +0 -54
  360. package/templates/commands/jira.md +0 -278
  361. package/templates/commands/linear.md +0 -288
  362. package/templates/commands/merge.md +0 -206
  363. package/templates/commands/next.md +0 -80
  364. package/templates/commands/p.md +0 -67
  365. package/templates/commands/p.toml +0 -37
  366. package/templates/commands/pause.md +0 -136
  367. package/templates/commands/plan.md +0 -696
  368. package/templates/commands/prd.md +0 -356
  369. package/templates/commands/resume.md +0 -171
  370. package/templates/commands/review.md +0 -276
  371. package/templates/commands/serve.md +0 -118
  372. package/templates/commands/setup.md +0 -91
  373. package/templates/commands/ship.md +0 -475
  374. package/templates/commands/skill.md +0 -259
  375. package/templates/commands/spec.md +0 -218
  376. package/templates/commands/status.md +0 -207
  377. package/templates/commands/sync.md +0 -104
  378. package/templates/commands/task.md +0 -312
  379. package/templates/commands/test.md +0 -93
  380. package/templates/commands/update.md +0 -63
  381. package/templates/commands/verify.md +0 -204
  382. package/templates/commands/workflow.md +0 -150
  383. package/templates/config/skill-mappings.json +0 -82
  384. package/templates/context/dashboard.md +0 -256
  385. package/templates/context/roadmap.md +0 -221
  386. package/templates/cursor/commands/bug.md +0 -8
  387. package/templates/cursor/commands/done.md +0 -4
  388. package/templates/cursor/commands/pause.md +0 -6
  389. package/templates/cursor/commands/resume.md +0 -4
  390. package/templates/cursor/commands/ship.md +0 -8
  391. package/templates/cursor/commands/sync.md +0 -4
  392. package/templates/cursor/commands/task.md +0 -8
  393. package/templates/cursor/p.md +0 -29
  394. package/templates/cursor/router.mdc +0 -28
  395. package/templates/design/api.md +0 -95
  396. package/templates/design/architecture.md +0 -77
  397. package/templates/design/component.md +0 -89
  398. package/templates/design/database.md +0 -78
  399. package/templates/design/flow.md +0 -94
  400. package/templates/global/ANTIGRAVITY.md +0 -254
  401. package/templates/global/CLAUDE.md +0 -497
  402. package/templates/global/CURSOR.mdc +0 -266
  403. package/templates/global/GEMINI.md +0 -293
  404. package/templates/global/STORAGE-SPEC.md +0 -391
  405. package/templates/global/WINDSURF.md +0 -266
  406. package/templates/global/modules/CLAUDE-commands.md +0 -70
  407. package/templates/global/modules/CLAUDE-core.md +0 -105
  408. package/templates/global/modules/CLAUDE-git.md +0 -50
  409. package/templates/global/modules/CLAUDE-intelligence.md +0 -92
  410. package/templates/global/modules/CLAUDE-storage.md +0 -50
  411. package/templates/global/modules/module-config.json +0 -36
  412. package/templates/mcp-config.json +0 -19
  413. package/templates/permissions/default.jsonc +0 -60
  414. package/templates/permissions/permissive.jsonc +0 -49
  415. package/templates/permissions/strict.jsonc +0 -58
  416. package/templates/planning-methodology.md +0 -195
  417. package/templates/skills/code-review.md +0 -47
  418. package/templates/skills/debug.md +0 -61
  419. package/templates/skills/refactor.md +0 -47
  420. package/templates/subagents/agent-base.md +0 -20
  421. package/templates/subagents/domain/backend.md +0 -109
  422. package/templates/subagents/domain/database.md +0 -121
  423. package/templates/subagents/domain/devops.md +0 -152
  424. package/templates/subagents/domain/frontend.md +0 -103
  425. package/templates/subagents/domain/testing.md +0 -169
  426. package/templates/subagents/pm-expert.md +0 -366
  427. package/templates/subagents/workflow/chief-architect.md +0 -657
  428. package/templates/subagents/workflow/prjct-planner.md +0 -159
  429. package/templates/subagents/workflow/prjct-shipper.md +0 -188
  430. package/templates/subagents/workflow/prjct-workflow.md +0 -98
  431. package/templates/tools/bash.txt +0 -22
  432. package/templates/tools/edit.txt +0 -18
  433. package/templates/tools/glob.txt +0 -19
  434. package/templates/tools/grep.txt +0 -21
  435. package/templates/tools/read.txt +0 -14
  436. package/templates/tools/task.txt +0 -20
  437. package/templates/tools/webfetch.txt +0 -16
  438. package/templates/tools/websearch.txt +0 -18
  439. package/templates/tools/write.txt +0 -17
  440. package/templates/windsurf/router.md +0 -28
  441. package/templates/windsurf/workflows/bug.md +0 -8
  442. package/templates/windsurf/workflows/done.md +0 -4
  443. package/templates/windsurf/workflows/pause.md +0 -4
  444. package/templates/windsurf/workflows/resume.md +0 -4
  445. package/templates/windsurf/workflows/ship.md +0 -8
  446. package/templates/windsurf/workflows/sync.md +0 -4
  447. package/templates/windsurf/workflows/task.md +0 -8
@@ -1,1547 +0,0 @@
1
- /**
2
- * Memory System
3
- * Tracks user preferences, decisions, and learned patterns.
4
- *
5
- * Three-tier memory system:
6
- * - Tier 1: Session (ephemeral) - single command context
7
- * - Tier 2: Patterns (persistent) - learned preferences and decisions
8
- * - Tier 3: History (JSONL) - append-only audit log
9
- *
10
- * @module agentic/memory-system
11
- * @version 3.3
12
- */
13
-
14
- import fs from 'node:fs/promises'
15
- import path from 'node:path'
16
- import pathManager from '../infrastructure/path-manager'
17
- import { generateUUID } from '../schemas'
18
- import { isNotFoundError } from '../types/fs'
19
- import { getTimestamp, getTodayKey } from '../utils/date-helper'
20
- import { ensureDir } from '../utils/file-helper'
21
- import { appendJsonLine, getLastJsonLines } from '../utils/jsonl-helper'
22
-
23
- // Re-export types from canonical location
24
- export type {
25
- ConfidenceLevel,
26
- Decision,
27
- HistoryEntry,
28
- HistoryEventType,
29
- KnownDomain,
30
- Memory,
31
- MemoryContext,
32
- MemoryContextParams,
33
- MemoryDatabase,
34
- MemoryRetrievalResult,
35
- MemoryTag,
36
- Patterns,
37
- Preference,
38
- RelevantMemoryQuery,
39
- ScoredMemory,
40
- TaskDomain,
41
- Workflow,
42
- } from '../types/memory'
43
-
44
- export { calculateConfidence, KNOWN_DOMAINS, MEMORY_TAGS } from '../types/memory'
45
-
46
- import type {
47
- HistoryEntry,
48
- HistoryEventType,
49
- KnownDomain,
50
- Memory,
51
- MemoryContext,
52
- MemoryDatabase,
53
- MemoryRetrievalResult,
54
- MemoryTag,
55
- Patterns,
56
- Preference,
57
- RelevantMemoryQuery,
58
- ScoredMemory,
59
- TaskDomain,
60
- Workflow,
61
- } from '../types/memory'
62
-
63
- import { calculateConfidence, KNOWN_DOMAINS, MEMORY_TAGS } from '../types/memory'
64
-
65
- // =============================================================================
66
- // Semantic Domain Mapping (PRJ-300)
67
- // =============================================================================
68
-
69
- /**
70
- * Map each known domain to its relevant MEMORY_TAGS.
71
- * More comprehensive than the previous mapping — includes TECH_STACK and
72
- * DEPENDENCIES where they apply.
73
- */
74
- export const DOMAIN_TAG_MAP: Record<string, MemoryTag[]> = {
75
- frontend: [
76
- MEMORY_TAGS.CODE_STYLE,
77
- MEMORY_TAGS.FILE_STRUCTURE,
78
- MEMORY_TAGS.ARCHITECTURE,
79
- MEMORY_TAGS.TECH_STACK,
80
- ],
81
- backend: [
82
- MEMORY_TAGS.CODE_STYLE,
83
- MEMORY_TAGS.ARCHITECTURE,
84
- MEMORY_TAGS.DEPENDENCIES,
85
- MEMORY_TAGS.TECH_STACK,
86
- ],
87
- devops: [
88
- MEMORY_TAGS.SHIP_WORKFLOW,
89
- MEMORY_TAGS.TEST_BEHAVIOR,
90
- MEMORY_TAGS.DEPENDENCIES,
91
- MEMORY_TAGS.ARCHITECTURE,
92
- ],
93
- docs: [MEMORY_TAGS.CODE_STYLE, MEMORY_TAGS.NAMING_CONVENTION, MEMORY_TAGS.FILE_STRUCTURE],
94
- testing: [MEMORY_TAGS.TEST_BEHAVIOR, MEMORY_TAGS.CODE_STYLE, MEMORY_TAGS.DEPENDENCIES],
95
- database: [
96
- MEMORY_TAGS.ARCHITECTURE,
97
- MEMORY_TAGS.NAMING_CONVENTION,
98
- MEMORY_TAGS.TECH_STACK,
99
- MEMORY_TAGS.DEPENDENCIES,
100
- ],
101
- general: Object.values(MEMORY_TAGS) as MemoryTag[],
102
- }
103
-
104
- /**
105
- * Semantic keywords for each domain.
106
- * Used to resolve unknown domain strings (e.g., "uxui" → frontend)
107
- * and for partial scoring when memory tags relate semantically.
108
- * @see PRJ-300
109
- */
110
- export const SEMANTIC_DOMAIN_KEYWORDS: Record<string, string[]> = {
111
- frontend: [
112
- 'ui',
113
- 'ux',
114
- 'uxui',
115
- 'css',
116
- 'styling',
117
- 'component',
118
- 'layout',
119
- 'design',
120
- 'responsive',
121
- 'react',
122
- 'vue',
123
- 'svelte',
124
- 'angular',
125
- 'html',
126
- 'tailwind',
127
- 'sass',
128
- 'web',
129
- 'accessibility',
130
- 'a11y',
131
- ],
132
- backend: [
133
- 'api',
134
- 'server',
135
- 'route',
136
- 'endpoint',
137
- 'rest',
138
- 'graphql',
139
- 'middleware',
140
- 'worker',
141
- 'queue',
142
- 'auth',
143
- 'hono',
144
- 'express',
145
- 'service',
146
- 'microservice',
147
- ],
148
- devops: [
149
- 'ci',
150
- 'cd',
151
- 'docker',
152
- 'kubernetes',
153
- 'deploy',
154
- 'infra',
155
- 'infrastructure',
156
- 'monitoring',
157
- 'cloud',
158
- 'aws',
159
- 'gcp',
160
- 'azure',
161
- 'pipeline',
162
- 'helm',
163
- 'terraform',
164
- ],
165
- docs: ['documentation', 'readme', 'guide', 'tutorial', 'wiki', 'changelog', 'jsdoc', 'typedoc'],
166
- testing: [
167
- 'test',
168
- 'spec',
169
- 'e2e',
170
- 'unit',
171
- 'integration',
172
- 'coverage',
173
- 'mock',
174
- 'vitest',
175
- 'jest',
176
- 'playwright',
177
- 'cypress',
178
- ],
179
- database: [
180
- 'db',
181
- 'sql',
182
- 'schema',
183
- 'migration',
184
- 'query',
185
- 'orm',
186
- 'prisma',
187
- 'mongo',
188
- 'postgres',
189
- 'redis',
190
- 'drizzle',
191
- 'sqlite',
192
- ],
193
- general: [],
194
- }
195
-
196
- /**
197
- * Resolve a domain string to canonical known domain(s).
198
- * Known domains pass through; unknown domains are matched via semantic keywords.
199
- * Exported for testing.
200
- * @see PRJ-300
201
- */
202
- export function resolveCanonicalDomains(domain: string): KnownDomain[] {
203
- // Exact match
204
- if ((KNOWN_DOMAINS as readonly string[]).includes(domain)) {
205
- return [domain as KnownDomain]
206
- }
207
-
208
- // Semantic resolution — find canonical domains whose keywords match
209
- const normalized = domain.toLowerCase().replace(/[-_\s]/g, '')
210
- const matches: KnownDomain[] = []
211
-
212
- for (const [canonical, keywords] of Object.entries(SEMANTIC_DOMAIN_KEYWORDS)) {
213
- if (canonical === 'general') continue
214
- for (const kw of keywords) {
215
- if (normalized.includes(kw) || kw.includes(normalized)) {
216
- matches.push(canonical as KnownDomain)
217
- break
218
- }
219
- }
220
- }
221
-
222
- return matches.length > 0 ? matches : ['general']
223
- }
224
-
225
- // =============================================================================
226
- // Base Store
227
- // =============================================================================
228
-
229
- /**
230
- * Abstract base class for project-scoped, disk-backed stores with in-memory caching.
231
- *
232
- * Provides lazy loading, automatic directory creation on save, and project-scoped
233
- * cache invalidation. Subclasses only need to define the filename, default data
234
- * structure, and optionally a subdirectory or post-load normalization hook.
235
- *
236
- * Extended by {@link PatternStore} and {@link SemanticMemories}.
237
- *
238
- * @typeParam T - The shape of the stored data (e.g., `Patterns`, `MemoryDatabase`)
239
- *
240
- * @example
241
- * ```ts
242
- * class MyStore extends CachedStore<MyData> {
243
- * protected getFilename() { return 'my-data.json' }
244
- * protected getDefault() { return { items: [] } }
245
- * }
246
- *
247
- * const store = new MyStore()
248
- * const data = await store.load('project-id')
249
- * ```
250
- */
251
- export abstract class CachedStore<T> {
252
- private _data: T | null = null
253
- private _loaded: boolean = false
254
- private _projectId: string | null = null
255
-
256
- /**
257
- * Return the filename for this store (e.g., `'patterns.json'`).
258
- * @returns The JSON filename used for disk persistence
259
- */
260
- protected abstract getFilename(): string
261
-
262
- /**
263
- * Return the default data structure when the file does not exist on disk.
264
- * @returns A fresh default instance of `T`
265
- */
266
- protected abstract getDefault(): T
267
-
268
- /**
269
- * Optional subdirectory within the project's `memory/` folder.
270
- * Override to nest the store file under a subfolder.
271
- *
272
- * @returns Subdirectory name, or `null` to store directly in `memory/`
273
- */
274
- protected getSubdirectory(): string | null {
275
- return null
276
- }
277
-
278
- /**
279
- * Build the full filesystem path for this store's JSON file.
280
- *
281
- * @param projectId - The project identifier used for path resolution
282
- * @returns Absolute path to the store file
283
- * (e.g., `~/.prjct-cli/projects/{id}/memory/patterns.json`)
284
- */
285
- protected getPath(projectId: string): string {
286
- const basePath = path.join(pathManager.getGlobalProjectPath(projectId), 'memory')
287
-
288
- const subdir = this.getSubdirectory()
289
- if (subdir) {
290
- return path.join(basePath, subdir, this.getFilename())
291
- }
292
-
293
- return path.join(basePath, this.getFilename())
294
- }
295
-
296
- /**
297
- * Load data from disk with project-scoped caching.
298
- *
299
- * Returns cached data immediately if already loaded for the same project.
300
- * Otherwise reads from disk, falling back to {@link getDefault} when the
301
- * file does not exist. Calls {@link afterLoad} after a successful disk read.
302
- *
303
- * @param projectId - The project identifier
304
- * @returns The loaded (or cached) data
305
- * @throws {Error} If the file read fails for reasons other than ENOENT
306
- *
307
- * @example
308
- * ```ts
309
- * const patterns = await patternStore.load('my-project-id')
310
- * ```
311
- */
312
- async load(projectId: string): Promise<T> {
313
- // Return cached if same project and loaded
314
- if (this._loaded && this._data && this._projectId === projectId) {
315
- return this._data
316
- }
317
-
318
- // Load from disk
319
- const filePath = this.getPath(projectId)
320
-
321
- try {
322
- const content = await fs.readFile(filePath, 'utf-8')
323
- this._data = JSON.parse(content) as T
324
- // Allow subclasses to normalize data after load
325
- this.afterLoad(this._data)
326
- } catch (error) {
327
- if (isNotFoundError(error)) {
328
- this._data = this.getDefault()
329
- } else {
330
- throw error
331
- }
332
- }
333
-
334
- this._loaded = true
335
- this._projectId = projectId
336
-
337
- return this._data
338
- }
339
-
340
- /**
341
- * Hook for subclasses to normalize or migrate data after loading from disk.
342
- *
343
- * Called once per disk read (not on cache hits). Override to ensure
344
- * structural invariants — e.g., adding missing index keys.
345
- *
346
- * @param _data - The freshly loaded data to normalize (mutate in place)
347
- */
348
- protected afterLoad(_data: T): void {
349
- // Override in subclass if needed
350
- }
351
-
352
- /**
353
- * Persist the current in-memory data to disk.
354
- *
355
- * Creates parent directories automatically if they don't exist.
356
- * No-op if no data has been loaded yet.
357
- *
358
- * @param projectId - The project identifier for path resolution
359
- * @throws {Error} If the file write fails
360
- */
361
- async save(projectId: string): Promise<void> {
362
- if (!this._data) return
363
-
364
- const filePath = this.getPath(projectId)
365
- await fs.mkdir(path.dirname(filePath), { recursive: true })
366
- await fs.writeFile(filePath, JSON.stringify(this._data, null, 2), 'utf-8')
367
- }
368
-
369
- /**
370
- * Access the cached data without triggering a disk read.
371
- *
372
- * @returns The cached data, or `null` if nothing has been loaded
373
- */
374
- protected getData(): T | null {
375
- return this._data
376
- }
377
-
378
- /**
379
- * Replace the in-memory data directly. Does not persist to disk —
380
- * call {@link save} afterwards if persistence is needed.
381
- *
382
- * @param data - The new data to cache
383
- */
384
- protected setData(data: T): void {
385
- this._data = data
386
- }
387
-
388
- /**
389
- * Atomically load, transform, and save data in one operation.
390
- *
391
- * @param projectId - The project identifier
392
- * @param updater - Pure function that receives current data and returns updated data
393
- * @returns The updated data after saving
394
- * @throws {Error} If load or save fails
395
- *
396
- * @example
397
- * ```ts
398
- * await store.update('my-project', (data) => ({
399
- * ...data,
400
- * count: data.count + 1,
401
- * }))
402
- * ```
403
- */
404
- async update(projectId: string, updater: (data: T) => T): Promise<T> {
405
- const data = await this.load(projectId)
406
- const updated = updater(data)
407
- this._data = updated
408
- await this.save(projectId)
409
- return updated
410
- }
411
-
412
- /**
413
- * Check whether data has been loaded into the cache.
414
- *
415
- * @param projectId - If provided, checks that data is loaded for this specific project.
416
- * If omitted, returns `true` if any project's data is cached.
417
- * @returns `true` if data is loaded (and matches the project, when specified)
418
- */
419
- isLoaded(projectId?: string): boolean {
420
- if (projectId) {
421
- return this._loaded && this._projectId === projectId
422
- }
423
- return this._loaded
424
- }
425
-
426
- /**
427
- * Clear the in-memory cache, forcing a fresh disk read on the next {@link load} call.
428
- * Does not delete or modify the file on disk.
429
- */
430
- reset(): void {
431
- this._data = null
432
- this._loaded = false
433
- this._projectId = null
434
- }
435
- }
436
-
437
- // =============================================================================
438
- // Session Store (Tier 1)
439
- // =============================================================================
440
-
441
- /**
442
- * Session Memory - Tier 1
443
- * Ephemeral, single command context.
444
- */
445
- export class SessionStore {
446
- private _sessionMemory: Map<string, { value: unknown; timestamp: number }> = new Map()
447
-
448
- setSession(key: string, value: unknown): void {
449
- this._sessionMemory.set(key, { value, timestamp: Date.now() })
450
- }
451
-
452
- getSession(key: string): unknown {
453
- const entry = this._sessionMemory.get(key)
454
- return entry?.value
455
- }
456
-
457
- clearSession(): void {
458
- this._sessionMemory.clear()
459
- }
460
- }
461
-
462
- // =============================================================================
463
- // History Store (Tier 3)
464
- // =============================================================================
465
-
466
- /**
467
- * History - Tier 3
468
- * Append-only JSONL audit log with temporal fragmentation.
469
- */
470
- export class HistoryStore {
471
- private _getSessionPath(projectId: string): string {
472
- const now = new Date()
473
- const yearMonth = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}`
474
- const day = getTodayKey()
475
-
476
- return path.join(
477
- pathManager.getGlobalProjectPath(projectId),
478
- 'memory',
479
- 'sessions',
480
- yearMonth,
481
- `${day}.jsonl`
482
- )
483
- }
484
-
485
- async appendHistory(
486
- projectId: string,
487
- entry: Record<string, unknown> & { type: HistoryEventType }
488
- ): Promise<void> {
489
- const sessionPath = this._getSessionPath(projectId)
490
- await ensureDir(path.dirname(sessionPath))
491
-
492
- const logEntry: HistoryEntry = {
493
- ts: getTimestamp(),
494
- ...entry,
495
- type: entry.type,
496
- }
497
-
498
- await appendJsonLine(sessionPath, logEntry)
499
- }
500
-
501
- async getRecentHistory(projectId: string, limit: number = 20): Promise<HistoryEntry[]> {
502
- const sessionPath = this._getSessionPath(projectId)
503
- return getLastJsonLines<HistoryEntry>(sessionPath, limit)
504
- }
505
- }
506
-
507
- // =============================================================================
508
- // Pattern Store (Tier 2)
509
- // =============================================================================
510
-
511
- /**
512
- * Patterns - Tier 2
513
- * Persistent learned preferences and decisions.
514
- */
515
- export class PatternStore extends CachedStore<Patterns> {
516
- private static readonly MAX_CONTEXTS = 20
517
- private static readonly ARCHIVE_AGE_DAYS = 90
518
-
519
- protected getFilename(): string {
520
- return 'patterns.json'
521
- }
522
-
523
- protected getDefault(): Patterns {
524
- return {
525
- version: 1,
526
- decisions: {},
527
- preferences: {},
528
- workflows: {},
529
- counters: {},
530
- }
531
- }
532
-
533
- protected afterLoad(patterns: Patterns): void {
534
- for (const decision of Object.values(patterns.decisions)) {
535
- if (decision.contexts.length > PatternStore.MAX_CONTEXTS) {
536
- decision.contexts = decision.contexts.slice(-PatternStore.MAX_CONTEXTS)
537
- }
538
- }
539
- }
540
-
541
- // Convenience alias for backward compatibility
542
- async loadPatterns(projectId: string): Promise<Patterns> {
543
- return this.load(projectId)
544
- }
545
-
546
- async savePatterns(projectId: string): Promise<void> {
547
- return this.save(projectId)
548
- }
549
-
550
- async recordDecision(
551
- projectId: string,
552
- key: string,
553
- value: string,
554
- context: string = '',
555
- options: { userConfirmed?: boolean } = {}
556
- ): Promise<void> {
557
- const patterns = await this.load(projectId)
558
- const now = getTimestamp()
559
-
560
- if (!patterns.decisions[key]) {
561
- patterns.decisions[key] = {
562
- value,
563
- count: 1,
564
- firstSeen: now,
565
- lastSeen: now,
566
- confidence: options.userConfirmed ? 'high' : 'low',
567
- contexts: [context].filter(Boolean),
568
- userConfirmed: options.userConfirmed || false,
569
- } as Patterns['decisions'][string]
570
- } else {
571
- const decision = patterns.decisions[key] as Patterns['decisions'][string] & {
572
- userConfirmed?: boolean
573
- }
574
-
575
- if (decision.value === value) {
576
- decision.count++
577
- decision.lastSeen = now
578
- if (context && !decision.contexts.includes(context)) {
579
- decision.contexts.push(context)
580
- if (decision.contexts.length > PatternStore.MAX_CONTEXTS) {
581
- decision.contexts = decision.contexts.slice(-PatternStore.MAX_CONTEXTS)
582
- }
583
- }
584
- if (options.userConfirmed) {
585
- decision.userConfirmed = true
586
- }
587
- decision.confidence = calculateConfidence(decision.count, decision.userConfirmed)
588
- } else {
589
- decision.value = value
590
- decision.count = 1
591
- decision.lastSeen = now
592
- decision.userConfirmed = options.userConfirmed || false
593
- decision.confidence = options.userConfirmed ? 'high' : 'low'
594
- }
595
- }
596
-
597
- await this.save(projectId)
598
- }
599
-
600
- async confirmDecision(projectId: string, key: string): Promise<boolean> {
601
- const patterns = await this.load(projectId)
602
- const decision = patterns.decisions[key] as
603
- | (Patterns['decisions'][string] & { userConfirmed?: boolean })
604
- | undefined
605
- if (!decision) return false
606
-
607
- decision.userConfirmed = true
608
- decision.confidence = 'high'
609
- decision.lastSeen = getTimestamp()
610
- await this.save(projectId)
611
- return true
612
- }
613
-
614
- async getDecision(
615
- projectId: string,
616
- key: string
617
- ): Promise<{ value: string; confidence: string } | null> {
618
- const patterns = await this.load(projectId)
619
- const decision = patterns.decisions[key]
620
-
621
- if (!decision) return null
622
- if (decision.confidence === 'low') return null
623
-
624
- return { value: decision.value, confidence: decision.confidence }
625
- }
626
-
627
- async hasPattern(projectId: string, key: string): Promise<boolean> {
628
- const decision = await this.getDecision(projectId, key)
629
- return decision !== null
630
- }
631
-
632
- async recordWorkflow(
633
- projectId: string,
634
- workflowName: string,
635
- pattern: Record<string, unknown>
636
- ): Promise<void> {
637
- const patterns = await this.load(projectId)
638
- const now = getTimestamp()
639
-
640
- if (!patterns.workflows[workflowName]) {
641
- patterns.workflows[workflowName] = {
642
- ...pattern,
643
- count: 1,
644
- firstSeen: now,
645
- lastSeen: now,
646
- confidence: 'low',
647
- userConfirmed: false,
648
- }
649
- } else {
650
- const workflow = patterns.workflows[workflowName]
651
- workflow.count++
652
- workflow.lastSeen = now
653
- workflow.confidence = calculateConfidence(workflow.count, workflow.userConfirmed)
654
- }
655
-
656
- await this.save(projectId)
657
- }
658
-
659
- async confirmWorkflow(projectId: string, workflowName: string): Promise<boolean> {
660
- const patterns = await this.load(projectId)
661
- const workflow = patterns.workflows[workflowName]
662
- if (!workflow) return false
663
-
664
- workflow.userConfirmed = true
665
- workflow.confidence = 'high'
666
- workflow.lastSeen = getTimestamp()
667
- await this.save(projectId)
668
- return true
669
- }
670
-
671
- async getWorkflow(projectId: string, workflowName: string): Promise<Workflow | null> {
672
- const patterns = await this.load(projectId)
673
- const workflow = patterns.workflows[workflowName]
674
-
675
- if (!workflow || workflow.count < 3) return null
676
- return workflow
677
- }
678
-
679
- async setPreference(
680
- projectId: string,
681
- key: string,
682
- value: Preference['value'],
683
- options: { userConfirmed?: boolean } = {}
684
- ): Promise<void> {
685
- const patterns = await this.load(projectId)
686
- const existing = patterns.preferences[key]
687
- const observationCount = existing ? existing.observationCount + 1 : 1
688
- const userConfirmed = options.userConfirmed || existing?.userConfirmed || false
689
-
690
- patterns.preferences[key] = {
691
- value,
692
- updatedAt: getTimestamp(),
693
- confidence: calculateConfidence(observationCount, userConfirmed),
694
- observationCount,
695
- userConfirmed,
696
- }
697
- await this.save(projectId)
698
- }
699
-
700
- async confirmPreference(projectId: string, key: string): Promise<boolean> {
701
- const patterns = await this.load(projectId)
702
- const pref = patterns.preferences[key]
703
- if (!pref) return false
704
-
705
- pref.userConfirmed = true
706
- pref.confidence = 'high'
707
- pref.updatedAt = getTimestamp()
708
- await this.save(projectId)
709
- return true
710
- }
711
-
712
- async getPreference(
713
- projectId: string,
714
- key: string,
715
- defaultValue: unknown = null
716
- ): Promise<unknown> {
717
- const patterns = await this.load(projectId)
718
- return patterns.preferences[key]?.value ?? defaultValue
719
- }
720
-
721
- async getPatternsSummary(projectId: string) {
722
- const patterns = await this.load(projectId)
723
-
724
- return {
725
- decisions: Object.keys(patterns.decisions).length,
726
- learnedDecisions: Object.values(patterns.decisions).filter((d) => d.confidence !== 'low')
727
- .length,
728
- workflows: Object.keys(patterns.workflows).length,
729
- preferences: Object.keys(patterns.preferences).length,
730
- }
731
- }
732
-
733
- private _getArchivePath(projectId: string): string {
734
- const basePath = path.join(pathManager.getGlobalProjectPath(projectId), 'memory')
735
- return path.join(basePath, 'patterns-archive.json')
736
- }
737
-
738
- async archiveStaleDecisions(projectId: string): Promise<number> {
739
- const patterns = await this.load(projectId)
740
- const now = Date.now()
741
- const cutoff = PatternStore.ARCHIVE_AGE_DAYS * 24 * 60 * 60 * 1000
742
-
743
- const staleKeys: string[] = []
744
- for (const [key, decision] of Object.entries(patterns.decisions)) {
745
- const lastSeenMs = new Date(decision.lastSeen).getTime()
746
- if (now - lastSeenMs > cutoff) {
747
- staleKeys.push(key)
748
- }
749
- }
750
-
751
- if (staleKeys.length === 0) return 0
752
-
753
- // Load or create archive
754
- const archivePath = this._getArchivePath(projectId)
755
- let archive: Record<string, unknown> = {}
756
- try {
757
- const content = await fs.readFile(archivePath, 'utf-8')
758
- archive = JSON.parse(content)
759
- } catch (error) {
760
- if (!isNotFoundError(error)) throw error
761
- }
762
-
763
- // Move stale decisions to archive
764
- for (const key of staleKeys) {
765
- archive[key] = patterns.decisions[key]
766
- delete patterns.decisions[key]
767
- }
768
-
769
- // Save archive and pruned patterns
770
- await fs.mkdir(path.dirname(archivePath), { recursive: true })
771
- await fs.writeFile(archivePath, JSON.stringify(archive, null, 2), 'utf-8')
772
- await this.save(projectId)
773
-
774
- return staleKeys.length
775
- }
776
- }
777
-
778
- // =============================================================================
779
- // Semantic Memories
780
- // =============================================================================
781
-
782
- /**
783
- * Semantic Memories
784
- * P3.3: Tagged, searchable, CRUD memory operations.
785
- */
786
- export class SemanticMemories extends CachedStore<MemoryDatabase> {
787
- protected getFilename(): string {
788
- return 'memories.json'
789
- }
790
-
791
- protected getDefault(): MemoryDatabase {
792
- return {
793
- version: 1,
794
- memories: [],
795
- index: this._createEmptyIndex(),
796
- }
797
- }
798
-
799
- protected afterLoad(db: MemoryDatabase): void {
800
- this._normalizeIndex(db)
801
- }
802
-
803
- private _createEmptyIndex(): Record<string, string[]> {
804
- const tags = Object.values(MEMORY_TAGS)
805
- const index: Record<string, string[]> = {}
806
- for (const tag of tags) index[tag] = []
807
- return index
808
- }
809
-
810
- private _normalizeIndex(db: MemoryDatabase): void {
811
- // Reason: older persisted files may not include newer tags; ensure all tags are present.
812
- const tags = Object.values(MEMORY_TAGS)
813
- for (const tag of tags) {
814
- if (!db.index[tag]) db.index[tag] = []
815
- }
816
- }
817
-
818
- private _coerceTags(tags: string[]): MemoryTag[] {
819
- const allowed = new Set<MemoryTag>(Object.values(MEMORY_TAGS) as MemoryTag[])
820
- return tags.filter((t): t is MemoryTag => allowed.has(t as MemoryTag))
821
- }
822
-
823
- // Convenience alias for backward compatibility
824
- async loadMemories(projectId: string): Promise<MemoryDatabase> {
825
- return this.load(projectId)
826
- }
827
-
828
- async saveMemories(projectId: string): Promise<void> {
829
- return this.save(projectId)
830
- }
831
-
832
- async createMemory(
833
- projectId: string,
834
- {
835
- title,
836
- content,
837
- tags = [],
838
- userTriggered = false,
839
- }: { title: string; content: string; tags?: string[]; userTriggered?: boolean }
840
- ): Promise<string> {
841
- const db = await this.load(projectId)
842
- const parsedTags = this._coerceTags(tags)
843
- const now = getTimestamp()
844
-
845
- const memory: Memory = {
846
- id: generateUUID(),
847
- title,
848
- content,
849
- tags: parsedTags,
850
- userTriggered,
851
- createdAt: now,
852
- updatedAt: now,
853
- }
854
-
855
- db.memories.push(memory)
856
-
857
- for (const tag of parsedTags) {
858
- db.index[tag].push(memory.id)
859
- }
860
-
861
- await this.save(projectId)
862
- return memory.id
863
- }
864
-
865
- async updateMemory(
866
- projectId: string,
867
- memoryId: string,
868
- updates: { title?: string; content?: string; tags?: string[] }
869
- ): Promise<boolean> {
870
- const db = await this.load(projectId)
871
-
872
- const index = db.memories.findIndex((m) => m.id === memoryId)
873
- if (index === -1) return false
874
-
875
- const memory = db.memories[index]
876
- const oldTags = memory.tags || []
877
-
878
- if (updates.title) memory.title = updates.title
879
- if (updates.content) memory.content = updates.content
880
- if (updates.tags) {
881
- const newTags = this._coerceTags(updates.tags)
882
- for (const tag of oldTags) {
883
- db.index[tag] = db.index[tag].filter((id: string) => id !== memoryId)
884
- }
885
- for (const tag of newTags) {
886
- db.index[tag].push(memoryId)
887
- }
888
- memory.tags = newTags
889
- }
890
-
891
- memory.updatedAt = getTimestamp()
892
- await this.save(projectId)
893
- return true
894
- }
895
-
896
- async deleteMemory(projectId: string, memoryId: string): Promise<boolean> {
897
- const db = await this.load(projectId)
898
-
899
- const index = db.memories.findIndex((m) => m.id === memoryId)
900
- if (index === -1) return false
901
-
902
- const memory = db.memories[index]
903
-
904
- for (const tag of memory.tags || []) {
905
- if (db.index[tag]) {
906
- db.index[tag] = db.index[tag].filter((id) => id !== memoryId)
907
- }
908
- }
909
-
910
- db.memories.splice(index, 1)
911
- await this.save(projectId)
912
- return true
913
- }
914
-
915
- async findByTags(
916
- projectId: string,
917
- tags: string[],
918
- matchAll: boolean = false
919
- ): Promise<Memory[]> {
920
- const db = await this.load(projectId)
921
- const parsedTags = this._coerceTags(tags)
922
-
923
- if (matchAll) {
924
- return db.memories.filter((m) => parsedTags.every((tag) => (m.tags || []).includes(tag)))
925
- } else {
926
- const matchingIds = new Set<string>()
927
- for (const tag of parsedTags) {
928
- const ids = db.index[tag]
929
- for (const id of ids) {
930
- matchingIds.add(id)
931
- }
932
- }
933
- return db.memories.filter((m) => matchingIds.has(m.id))
934
- }
935
- }
936
-
937
- async searchMemories(projectId: string, query: string): Promise<Memory[]> {
938
- const db = await this.load(projectId)
939
- const queryLower = query.toLowerCase()
940
-
941
- return db.memories.filter(
942
- (m) =>
943
- m.title.toLowerCase().includes(queryLower) || m.content.toLowerCase().includes(queryLower)
944
- )
945
- }
946
-
947
- async getRelevantMemories(
948
- projectId: string,
949
- context: MemoryContext,
950
- limit: number = 5
951
- ): Promise<Memory[]> {
952
- const db = await this.load(projectId)
953
-
954
- const scored = db.memories.map((memory) => {
955
- let score = 0
956
-
957
- const contextTags = this._extractContextTags(context)
958
- for (const tag of memory.tags || []) {
959
- if (contextTags.includes(tag)) score += 10
960
- }
961
-
962
- const age = Date.now() - new Date(memory.updatedAt).getTime()
963
- const daysSinceUpdate = age / (1000 * 60 * 60 * 24)
964
- score += Math.max(0, 5 - daysSinceUpdate)
965
-
966
- if (memory.userTriggered) score += 5
967
-
968
- const keywords = this._extractKeywords(context)
969
- for (const keyword of keywords) {
970
- if (memory.content.toLowerCase().includes(keyword)) score += 2
971
- if (memory.title.toLowerCase().includes(keyword)) score += 3
972
- }
973
-
974
- return { ...memory, _score: score }
975
- })
976
-
977
- return scored
978
- .filter((m) => m._score > 0)
979
- .sort((a, b) => b._score - a._score)
980
- .slice(0, limit)
981
- .map(({ _score, ...memory }) => memory as Memory)
982
- }
983
-
984
- /**
985
- * Enhanced memory retrieval with domain-based filtering and metrics.
986
- * Implements selective memory retrieval based on task relevance.
987
- * @see PRJ-107
988
- */
989
- async getRelevantMemoriesWithMetrics(
990
- projectId: string,
991
- query: RelevantMemoryQuery
992
- ): Promise<MemoryRetrievalResult> {
993
- const db = await this.load(projectId)
994
- const totalMemories = db.memories.length
995
-
996
- if (totalMemories === 0) {
997
- return {
998
- memories: [],
999
- metrics: {
1000
- totalMemories: 0,
1001
- memoriesConsidered: 0,
1002
- memoriesReturned: 0,
1003
- filteringRatio: 0,
1004
- avgRelevanceScore: 0,
1005
- },
1006
- }
1007
- }
1008
-
1009
- const maxResults = query.maxResults ?? 10
1010
- const minRelevance = query.minRelevance ?? 10
1011
-
1012
- // Score all memories
1013
- const scored: ScoredMemory[] = db.memories.map((memory) => {
1014
- const breakdown = {
1015
- domainMatch: 0,
1016
- tagMatch: 0,
1017
- recency: 0,
1018
- confidence: 0,
1019
- keywords: 0,
1020
- userTriggered: 0,
1021
- }
1022
-
1023
- // Domain match scoring (0-25 points) — semantic matching (PRJ-300)
1024
- if (query.taskDomain) {
1025
- breakdown.domainMatch = this._getSemanticDomainScore(query.taskDomain, memory.tags || [])
1026
- }
1027
-
1028
- // Tag match from command context (0-20 points)
1029
- if (query.commandName) {
1030
- const commandTags = this._getCommandTags(query.commandName)
1031
- const matchingTags = (memory.tags || []).filter((tag) => commandTags.includes(tag))
1032
- breakdown.tagMatch = Math.min(20, matchingTags.length * 8)
1033
- }
1034
-
1035
- // Recency scoring (0-15 points)
1036
- const age = Date.now() - new Date(memory.updatedAt).getTime()
1037
- const daysSinceUpdate = age / (1000 * 60 * 60 * 24)
1038
- breakdown.recency = Math.max(0, Math.round(15 - daysSinceUpdate * 0.5))
1039
-
1040
- // Confidence scoring (0-20 points) - PRJ-104 integration
1041
- if (memory.confidence) {
1042
- breakdown.confidence =
1043
- memory.confidence === 'high' ? 20 : memory.confidence === 'medium' ? 12 : 5
1044
- } else if (memory.observationCount) {
1045
- // Fallback to observation count
1046
- breakdown.confidence = Math.min(20, memory.observationCount * 3)
1047
- }
1048
-
1049
- // Keyword matching (0-15 points)
1050
- if (query.taskDescription) {
1051
- const keywords = this._extractKeywordsFromText(query.taskDescription)
1052
- let keywordScore = 0
1053
- for (const keyword of keywords) {
1054
- if (memory.content.toLowerCase().includes(keyword)) keywordScore += 2
1055
- if (memory.title.toLowerCase().includes(keyword)) keywordScore += 3
1056
- }
1057
- breakdown.keywords = Math.min(15, keywordScore)
1058
- }
1059
-
1060
- // User triggered bonus (0-5 points)
1061
- if (memory.userTriggered) {
1062
- breakdown.userTriggered = 5
1063
- }
1064
-
1065
- const relevanceScore =
1066
- breakdown.domainMatch +
1067
- breakdown.tagMatch +
1068
- breakdown.recency +
1069
- breakdown.confidence +
1070
- breakdown.keywords +
1071
- breakdown.userTriggered
1072
-
1073
- return {
1074
- ...memory,
1075
- relevanceScore,
1076
- scoreBreakdown: breakdown,
1077
- }
1078
- })
1079
-
1080
- // Filter by minimum relevance
1081
- const considered = scored.filter((m) => m.relevanceScore >= minRelevance)
1082
-
1083
- // Sort by relevance and take top N
1084
- const sorted = considered.sort((a, b) => b.relevanceScore - a.relevanceScore)
1085
- const returned = sorted.slice(0, maxResults)
1086
-
1087
- // Calculate average relevance
1088
- const avgRelevanceScore =
1089
- returned.length > 0
1090
- ? Math.round(returned.reduce((sum, m) => sum + m.relevanceScore, 0) / returned.length)
1091
- : 0
1092
-
1093
- return {
1094
- memories: returned,
1095
- metrics: {
1096
- totalMemories,
1097
- memoriesConsidered: considered.length,
1098
- memoriesReturned: returned.length,
1099
- filteringRatio: totalMemories > 0 ? returned.length / totalMemories : 0,
1100
- avgRelevanceScore,
1101
- },
1102
- }
1103
- }
1104
-
1105
- /**
1106
- * Compute semantic domain match score (0-25 points).
1107
- *
1108
- * Two-pass scoring:
1109
- * 1. Exact MEMORY_TAG match: memory tag in domain's tag list → 10 pts each
1110
- * 2. Semantic match: memory tag relates to domain via keywords → 5 pts each
1111
- *
1112
- * Unknown domains are resolved to canonical domain(s) via SEMANTIC_DOMAIN_KEYWORDS.
1113
- * @see PRJ-107, PRJ-300
1114
- */
1115
- private _getSemanticDomainScore(domain: TaskDomain, memoryTags: string[]): number {
1116
- // Resolve to canonical domain(s)
1117
- const canonicals = this._resolveCanonicalDomains(domain)
1118
- if (canonicals.length === 0) return 0
1119
-
1120
- // Collect all relevant MEMORY_TAGS for the canonical domains
1121
- const relevantTags = new Set<string>()
1122
- for (const canonical of canonicals) {
1123
- const tags = DOMAIN_TAG_MAP[canonical]
1124
- if (tags) {
1125
- for (const tag of tags) relevantTags.add(tag)
1126
- }
1127
- }
1128
-
1129
- // Collect semantic keywords for the canonical domains
1130
- const domainKeywords = new Set<string>()
1131
- for (const canonical of canonicals) {
1132
- const keywords = SEMANTIC_DOMAIN_KEYWORDS[canonical]
1133
- if (keywords) {
1134
- for (const kw of keywords) domainKeywords.add(kw)
1135
- }
1136
- }
1137
-
1138
- let score = 0
1139
-
1140
- for (const tag of memoryTags) {
1141
- // Pass 1: exact MEMORY_TAG match (10 pts)
1142
- if (relevantTags.has(tag)) {
1143
- score += 10
1144
- continue
1145
- }
1146
- // Pass 2: semantic keyword match (5 pts)
1147
- const normalized = tag.toLowerCase().replace(/[-_\s]/g, '')
1148
- for (const kw of domainKeywords) {
1149
- if (normalized.includes(kw) || kw.includes(normalized)) {
1150
- score += 5
1151
- break
1152
- }
1153
- }
1154
- }
1155
-
1156
- return Math.min(25, score)
1157
- }
1158
-
1159
- /**
1160
- * Resolve a domain string to canonical known domain(s).
1161
- * Delegates to module-level resolveCanonicalDomains().
1162
- * @see PRJ-300
1163
- */
1164
- private _resolveCanonicalDomains(domain: TaskDomain): KnownDomain[] {
1165
- return resolveCanonicalDomains(domain)
1166
- }
1167
-
1168
- /**
1169
- * Map command to relevant memory tags.
1170
- * @see PRJ-107
1171
- */
1172
- private _getCommandTags(commandName: string): MemoryTag[] {
1173
- const commandTags: Record<string, MemoryTag[]> = {
1174
- ship: [MEMORY_TAGS.COMMIT_STYLE, MEMORY_TAGS.SHIP_WORKFLOW, MEMORY_TAGS.TEST_BEHAVIOR],
1175
- feature: [MEMORY_TAGS.ARCHITECTURE, MEMORY_TAGS.CODE_STYLE],
1176
- done: [MEMORY_TAGS.SHIP_WORKFLOW],
1177
- analyze: [MEMORY_TAGS.TECH_STACK, MEMORY_TAGS.ARCHITECTURE],
1178
- spec: [MEMORY_TAGS.ARCHITECTURE, MEMORY_TAGS.CODE_STYLE],
1179
- task: [MEMORY_TAGS.BRANCH_NAMING, MEMORY_TAGS.CODE_STYLE],
1180
- sync: [MEMORY_TAGS.TECH_STACK, MEMORY_TAGS.ARCHITECTURE, MEMORY_TAGS.DEPENDENCIES],
1181
- test: [MEMORY_TAGS.TEST_BEHAVIOR],
1182
- bug: [MEMORY_TAGS.CODE_STYLE, MEMORY_TAGS.TEST_BEHAVIOR],
1183
- }
1184
- return commandTags[commandName] || []
1185
- }
1186
-
1187
- /**
1188
- * Extract keywords from text for matching.
1189
- */
1190
- private _extractKeywordsFromText(text: string): string[] {
1191
- const words = text.toLowerCase().split(/\s+/)
1192
- const stopWords = new Set([
1193
- 'the',
1194
- 'a',
1195
- 'an',
1196
- 'is',
1197
- 'are',
1198
- 'to',
1199
- 'for',
1200
- 'and',
1201
- 'or',
1202
- 'in',
1203
- 'on',
1204
- 'at',
1205
- 'by',
1206
- 'with',
1207
- 'from',
1208
- 'as',
1209
- 'it',
1210
- 'this',
1211
- 'that',
1212
- 'be',
1213
- 'have',
1214
- 'has',
1215
- ])
1216
- return words.filter((w) => w.length > 2 && !stopWords.has(w))
1217
- }
1218
-
1219
- private _extractContextTags(context: MemoryContext): string[] {
1220
- const tags: string[] = []
1221
-
1222
- const commandTags: Record<string, string[]> = {
1223
- ship: [MEMORY_TAGS.COMMIT_STYLE, MEMORY_TAGS.SHIP_WORKFLOW, MEMORY_TAGS.TEST_BEHAVIOR],
1224
- feature: [MEMORY_TAGS.ARCHITECTURE, MEMORY_TAGS.CODE_STYLE],
1225
- done: [MEMORY_TAGS.SHIP_WORKFLOW],
1226
- analyze: [MEMORY_TAGS.TECH_STACK, MEMORY_TAGS.ARCHITECTURE],
1227
- spec: [MEMORY_TAGS.ARCHITECTURE, MEMORY_TAGS.CODE_STYLE],
1228
- }
1229
-
1230
- if (context.commandName && commandTags[context.commandName]) {
1231
- tags.push(...commandTags[context.commandName])
1232
- }
1233
-
1234
- return tags
1235
- }
1236
-
1237
- private _extractKeywords(context: MemoryContext): string[] {
1238
- const keywords: string[] = []
1239
-
1240
- if (context.params?.description) {
1241
- keywords.push(...(context.params.description as string).toLowerCase().split(/\s+/))
1242
- }
1243
- if (context.params?.feature) {
1244
- keywords.push(...(context.params.feature as string).toLowerCase().split(/\s+/))
1245
- }
1246
-
1247
- const stopWords = ['the', 'a', 'an', 'is', 'are', 'to', 'for', 'and', 'or', 'in']
1248
- return keywords.filter((k) => k.length > 2 && !stopWords.includes(k))
1249
- }
1250
-
1251
- async autoRemember(
1252
- projectId: string,
1253
- decisionType: string,
1254
- value: string,
1255
- context: string = ''
1256
- ): Promise<void> {
1257
- const tagMap: Record<string, string[]> = {
1258
- commit_footer: [MEMORY_TAGS.COMMIT_STYLE],
1259
- branch_naming: [MEMORY_TAGS.BRANCH_NAMING],
1260
- test_before_ship: [MEMORY_TAGS.TEST_BEHAVIOR, MEMORY_TAGS.SHIP_WORKFLOW],
1261
- preferred_agent: [MEMORY_TAGS.AGENT_PREFERENCE],
1262
- code_style: [MEMORY_TAGS.CODE_STYLE],
1263
- verbosity: [MEMORY_TAGS.OUTPUT_VERBOSITY],
1264
- }
1265
-
1266
- const tags = tagMap[decisionType] || []
1267
-
1268
- const existing = await this.searchMemories(projectId, decisionType)
1269
- if (existing.length > 0) {
1270
- await this.updateMemory(projectId, existing[0].id, {
1271
- content: `${decisionType}: ${value}`,
1272
- tags,
1273
- })
1274
- } else {
1275
- await this.createMemory(projectId, {
1276
- title: `Preference: ${decisionType}`,
1277
- content: `${decisionType}: ${value}${context ? `\nContext: ${context}` : ''}`,
1278
- tags,
1279
- userTriggered: true,
1280
- })
1281
- }
1282
- }
1283
-
1284
- async getAllMemories(projectId: string): Promise<Memory[]> {
1285
- const db = await this.load(projectId)
1286
- return db.memories
1287
- }
1288
-
1289
- async getMemoryStats(projectId: string) {
1290
- const db = await this.load(projectId)
1291
-
1292
- const tagCounts: Record<string, number> = {}
1293
- for (const [tag, ids] of Object.entries(db.index)) {
1294
- tagCounts[tag] = ids.length
1295
- }
1296
-
1297
- return {
1298
- totalMemories: db.memories.length,
1299
- userTriggered: db.memories.filter((m) => m.userTriggered).length,
1300
- tagCounts,
1301
- oldestMemory: db.memories[0]?.createdAt,
1302
- newestMemory: db.memories[db.memories.length - 1]?.createdAt,
1303
- }
1304
- }
1305
- }
1306
-
1307
- // =============================================================================
1308
- // Memory System (Main Class)
1309
- // =============================================================================
1310
-
1311
- /**
1312
- * Three-tier memory system for learning user patterns.
1313
- * Tier 1: Session (ephemeral), Tier 2: Patterns (persistent), Tier 3: History (JSONL)
1314
- */
1315
- export class MemorySystem {
1316
- private _semanticMemories: SemanticMemories
1317
- private _patternStore: PatternStore
1318
- private _historyStore: HistoryStore
1319
- private _sessionStore: SessionStore
1320
-
1321
- constructor() {
1322
- this._semanticMemories = new SemanticMemories()
1323
- this._patternStore = new PatternStore()
1324
- this._historyStore = new HistoryStore()
1325
- this._sessionStore = new SessionStore()
1326
- }
1327
-
1328
- // ===========================================================================
1329
- // P3.3: SEMANTIC MEMORIES
1330
- // ===========================================================================
1331
-
1332
- loadMemories(projectId: string) {
1333
- return this._semanticMemories.loadMemories(projectId)
1334
- }
1335
-
1336
- saveMemories(projectId: string) {
1337
- return this._semanticMemories.saveMemories(projectId)
1338
- }
1339
-
1340
- createMemory(
1341
- projectId: string,
1342
- options: { title: string; content: string; tags?: string[]; userTriggered?: boolean }
1343
- ): Promise<string> {
1344
- return this._semanticMemories.createMemory(projectId, options)
1345
- }
1346
-
1347
- updateMemory(
1348
- projectId: string,
1349
- memoryId: string,
1350
- updates: { title?: string; content?: string; tags?: string[] }
1351
- ): Promise<boolean> {
1352
- return this._semanticMemories.updateMemory(projectId, memoryId, updates)
1353
- }
1354
-
1355
- deleteMemory(projectId: string, memoryId: string): Promise<boolean> {
1356
- return this._semanticMemories.deleteMemory(projectId, memoryId)
1357
- }
1358
-
1359
- findByTags(projectId: string, tags: string[], matchAll?: boolean): Promise<Memory[]> {
1360
- return this._semanticMemories.findByTags(projectId, tags, matchAll)
1361
- }
1362
-
1363
- searchMemories(projectId: string, query: string): Promise<Memory[]> {
1364
- return this._semanticMemories.searchMemories(projectId, query)
1365
- }
1366
-
1367
- getRelevantMemories(
1368
- projectId: string,
1369
- context: MemoryContext,
1370
- limit?: number
1371
- ): Promise<Memory[]> {
1372
- return this._semanticMemories.getRelevantMemories(projectId, context, limit)
1373
- }
1374
-
1375
- autoRemember(
1376
- projectId: string,
1377
- decisionType: string,
1378
- value: string,
1379
- context?: string
1380
- ): Promise<void> {
1381
- return this._semanticMemories.autoRemember(projectId, decisionType, value, context)
1382
- }
1383
-
1384
- getAllMemories(projectId: string): Promise<Memory[]> {
1385
- return this._semanticMemories.getAllMemories(projectId)
1386
- }
1387
-
1388
- getMemoryStats(projectId: string) {
1389
- return this._semanticMemories.getMemoryStats(projectId)
1390
- }
1391
-
1392
- /**
1393
- * Get relevant memories with domain-based filtering and metrics.
1394
- * Implements selective memory retrieval based on task relevance.
1395
- * @see PRJ-107
1396
- */
1397
- getRelevantMemoriesWithMetrics(
1398
- projectId: string,
1399
- query: RelevantMemoryQuery
1400
- ): Promise<MemoryRetrievalResult> {
1401
- return this._semanticMemories.getRelevantMemoriesWithMetrics(projectId, query)
1402
- }
1403
-
1404
- // ===========================================================================
1405
- // TIER 1: Session Memory
1406
- // ===========================================================================
1407
-
1408
- setSession(key: string, value: unknown): void {
1409
- this._sessionStore.setSession(key, value)
1410
- }
1411
-
1412
- getSession(key: string): unknown {
1413
- return this._sessionStore.getSession(key)
1414
- }
1415
-
1416
- clearSession(): void {
1417
- this._sessionStore.clearSession()
1418
- }
1419
-
1420
- // ===========================================================================
1421
- // TIER 2: Patterns
1422
- // ===========================================================================
1423
-
1424
- loadPatterns(projectId: string) {
1425
- return this._patternStore.loadPatterns(projectId)
1426
- }
1427
-
1428
- savePatterns(projectId: string) {
1429
- return this._patternStore.savePatterns(projectId)
1430
- }
1431
-
1432
- recordDecision(projectId: string, key: string, value: string, context?: string): Promise<void> {
1433
- return this._patternStore.recordDecision(projectId, key, value, context)
1434
- }
1435
-
1436
- getDecision(
1437
- projectId: string,
1438
- key: string
1439
- ): Promise<{ value: string; confidence: string } | null> {
1440
- return this._patternStore.getDecision(projectId, key)
1441
- }
1442
-
1443
- hasPattern(projectId: string, key: string): Promise<boolean> {
1444
- return this._patternStore.hasPattern(projectId, key)
1445
- }
1446
-
1447
- recordWorkflow(
1448
- projectId: string,
1449
- workflowName: string,
1450
- pattern: Record<string, unknown>
1451
- ): Promise<void> {
1452
- return this._patternStore.recordWorkflow(projectId, workflowName, pattern)
1453
- }
1454
-
1455
- getWorkflow(projectId: string, workflowName: string): Promise<Workflow | null> {
1456
- return this._patternStore.getWorkflow(projectId, workflowName)
1457
- }
1458
-
1459
- setPreference(
1460
- projectId: string,
1461
- key: string,
1462
- value: Preference['value'],
1463
- options?: { userConfirmed?: boolean }
1464
- ): Promise<void> {
1465
- return this._patternStore.setPreference(projectId, key, value, options)
1466
- }
1467
-
1468
- getPreference(projectId: string, key: string, defaultValue?: unknown): Promise<unknown> {
1469
- return this._patternStore.getPreference(projectId, key, defaultValue)
1470
- }
1471
-
1472
- confirmPreference(projectId: string, key: string): Promise<boolean> {
1473
- return this._patternStore.confirmPreference(projectId, key)
1474
- }
1475
-
1476
- confirmDecision(projectId: string, key: string): Promise<boolean> {
1477
- return this._patternStore.confirmDecision(projectId, key)
1478
- }
1479
-
1480
- confirmWorkflow(projectId: string, workflowName: string): Promise<boolean> {
1481
- return this._patternStore.confirmWorkflow(projectId, workflowName)
1482
- }
1483
-
1484
- getPatternsSummary(projectId: string) {
1485
- return this._patternStore.getPatternsSummary(projectId)
1486
- }
1487
-
1488
- archiveStaleDecisions(projectId: string): Promise<number> {
1489
- return this._patternStore.archiveStaleDecisions(projectId)
1490
- }
1491
-
1492
- // ===========================================================================
1493
- // TIER 3: History
1494
- // ===========================================================================
1495
-
1496
- appendHistory(
1497
- projectId: string,
1498
- entry: Record<string, unknown> & { type: HistoryEventType }
1499
- ): Promise<void> {
1500
- return this._historyStore.appendHistory(projectId, entry)
1501
- }
1502
-
1503
- getRecentHistory(projectId: string, limit?: number) {
1504
- return this._historyStore.getRecentHistory(projectId, limit)
1505
- }
1506
-
1507
- // ===========================================================================
1508
- // CONVENIENCE: Combined operations
1509
- // ===========================================================================
1510
-
1511
- async getSmartDecision(projectId: string, key: string): Promise<string | null> {
1512
- const sessionValue = this.getSession(`decision:${key}`)
1513
- if (sessionValue !== undefined) return sessionValue as string
1514
-
1515
- const pattern = await this.getDecision(projectId, key)
1516
- if (pattern) return pattern.value
1517
-
1518
- return null
1519
- }
1520
-
1521
- async learnDecision(
1522
- projectId: string,
1523
- key: string,
1524
- value: string,
1525
- context: string = ''
1526
- ): Promise<void> {
1527
- this.setSession(`decision:${key}`, value)
1528
- await this.recordDecision(projectId, key, value, context)
1529
- await this.appendHistory(projectId, { type: 'decision', key, value, context })
1530
- }
1531
-
1532
- /**
1533
- * Reset internal state (for testing)
1534
- */
1535
- resetState(): void {
1536
- this._sessionStore.clearSession()
1537
- this._semanticMemories.reset()
1538
- this._patternStore.reset()
1539
- }
1540
- }
1541
-
1542
- // =============================================================================
1543
- // Default Export
1544
- // =============================================================================
1545
-
1546
- const memorySystem = new MemorySystem()
1547
- export default memorySystem