claude-memory-layer 1.0.31 → 1.0.32

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 (313) hide show
  1. package/README.md +9 -2
  2. package/dist/cli/index.js +1 -1
  3. package/package.json +11 -2
  4. package/scripts/postinstall-embedding-backend.cjs +16 -12
  5. package/AGENTS.md +0 -71
  6. package/CLAUDE.md +0 -30
  7. package/HANDOFF.md +0 -92
  8. package/Memo.txt +0 -558
  9. package/benchmarks/replay/anonymized-real-sessions.json +0 -48
  10. package/config/kpi-thresholds.json +0 -7
  11. package/context.md +0 -636
  12. package/docs/ARCHITECTURE_COMPARISON_AND_RECOMMENDATIONS.md +0 -627
  13. package/docs/HERMES_MEMORY_INGESTION_ANALYSIS.md +0 -440
  14. package/docs/MCP_MEMORY_SERVICE_COMPARATIVE_REVIEW.md +0 -271
  15. package/docs/MEMORY_USEFULNESS_AUDIT.md +0 -371
  16. package/docs/MEMORY_USEFULNESS_AUDIT_RAW.json +0 -80
  17. package/docs/MEMSEARCH_PROJECT_STRUCTURE_ANALYSIS.md +0 -333
  18. package/docs/MEMU_ADOPTION.md +0 -40
  19. package/docs/OPERATIONS.md +0 -18
  20. package/docs/PRODUCT_VALIDATION_MATRIX.md +0 -82
  21. package/docs/PROJECT_STRUCTURE_ANALYSIS.md +0 -421
  22. package/docs/REFACTORING_MILESTONES_AND_ISSUES.md +0 -501
  23. package/docs/REFACTORING_PLAN_THIN_CORE.md +0 -414
  24. package/docs/REFERENCE_PROJECT_ANALYSES.md +0 -25
  25. package/docs/SUPERLOCALMEMORY_PROJECT_STRUCTURE_ANALYSIS.md +0 -452
  26. package/docs/TARGET_ARCHITECTURE_AND_FOLDER_STRUCTURE.md +0 -446
  27. package/docs/architecture/comparison-index.md +0 -47
  28. package/docs/reports/codex-real-data-validation-20260505T040447Z.md +0 -46
  29. package/plan.md +0 -1642
  30. package/scripts/build.ts +0 -159
  31. package/scripts/bump-patch-version.sh +0 -18
  32. package/scripts/delete-unknown-projects.js +0 -154
  33. package/scripts/fix-sync-gap.js +0 -32
  34. package/scripts/generate-session-qrels.ts +0 -126
  35. package/scripts/heartbeat-memory-orchestrator.sh +0 -28
  36. package/scripts/replay-retrieval-benchmark.ts +0 -69
  37. package/scripts/report-sync-gap.js +0 -26
  38. package/scripts/review-queue-auto-resolve.js +0 -21
  39. package/scripts/sync-gap-auto-heal.sh +0 -17
  40. package/spec.md +0 -624
  41. package/specs/20260207-dashboard-upgrade/context.md +0 -38
  42. package/specs/20260207-dashboard-upgrade/spec.md +0 -96
  43. package/specs/citations-system/context.md +0 -243
  44. package/specs/citations-system/plan.md +0 -495
  45. package/specs/citations-system/spec.md +0 -371
  46. package/specs/endless-mode/context.md +0 -305
  47. package/specs/endless-mode/plan.md +0 -620
  48. package/specs/endless-mode/spec.md +0 -455
  49. package/specs/entity-edge-model/context.md +0 -401
  50. package/specs/entity-edge-model/plan.md +0 -459
  51. package/specs/entity-edge-model/spec.md +0 -391
  52. package/specs/evidence-aligner-v2/context.md +0 -401
  53. package/specs/evidence-aligner-v2/plan.md +0 -303
  54. package/specs/evidence-aligner-v2/spec.md +0 -312
  55. package/specs/mcp-desktop-integration/context.md +0 -278
  56. package/specs/mcp-desktop-integration/plan.md +0 -550
  57. package/specs/mcp-desktop-integration/spec.md +0 -494
  58. package/specs/memory-utilization-improvements/context.md +0 -145
  59. package/specs/memory-utilization-improvements/plan.md +0 -361
  60. package/specs/memory-utilization-improvements/spec.md +0 -361
  61. package/specs/post-tool-use-hook/context.md +0 -319
  62. package/specs/post-tool-use-hook/plan.md +0 -469
  63. package/specs/post-tool-use-hook/spec.md +0 -364
  64. package/specs/private-tags/context.md +0 -288
  65. package/specs/private-tags/plan.md +0 -412
  66. package/specs/private-tags/spec.md +0 -345
  67. package/specs/progressive-disclosure/context.md +0 -346
  68. package/specs/progressive-disclosure/plan.md +0 -663
  69. package/specs/progressive-disclosure/spec.md +0 -415
  70. package/specs/selective-tool-observation/context.md +0 -100
  71. package/specs/selective-tool-observation/plan.md +0 -158
  72. package/specs/selective-tool-observation/spec.md +0 -127
  73. package/specs/task-entity-system/context.md +0 -297
  74. package/specs/task-entity-system/plan.md +0 -301
  75. package/specs/task-entity-system/spec.md +0 -314
  76. package/specs/thin-core-refactor/context.md +0 -275
  77. package/specs/thin-core-refactor/plan.md +0 -536
  78. package/specs/thin-core-refactor/spec.md +0 -465
  79. package/specs/vector-outbox-v2/context.md +0 -470
  80. package/specs/vector-outbox-v2/plan.md +0 -562
  81. package/specs/vector-outbox-v2/spec.md +0 -466
  82. package/specs/web-viewer-ui/context.md +0 -384
  83. package/specs/web-viewer-ui/plan.md +0 -797
  84. package/specs/web-viewer-ui/spec.md +0 -516
  85. package/src/adapters/claude/capture/index.ts +0 -3
  86. package/src/adapters/claude/context/index.ts +0 -3
  87. package/src/adapters/claude/hooks/index.ts +0 -21
  88. package/src/adapters/claude/hooks/post-tool-use.ts +0 -239
  89. package/src/adapters/claude/hooks/prompt-injection-policy.ts +0 -104
  90. package/src/adapters/claude/hooks/semantic-daemon-client.ts +0 -209
  91. package/src/adapters/claude/hooks/semantic-daemon.ts +0 -283
  92. package/src/adapters/claude/hooks/session-end.ts +0 -59
  93. package/src/adapters/claude/hooks/session-start.ts +0 -73
  94. package/src/adapters/claude/hooks/stop.ts +0 -128
  95. package/src/adapters/claude/hooks/user-prompt-submit.ts +0 -361
  96. package/src/adapters/claude/index.ts +0 -4
  97. package/src/adapters/claude/transcript/index.ts +0 -4
  98. package/src/adapters/claude/transcript/transcript-reader.ts +0 -57
  99. package/src/adapters/claude/transcript/turn-reconstructor.ts +0 -65
  100. package/src/apps/cli/claude-settings-hooks.ts +0 -138
  101. package/src/apps/cli/codex-import-runner.ts +0 -125
  102. package/src/apps/cli/codex-validation-output.ts +0 -95
  103. package/src/apps/cli/hermes-import-runner.ts +0 -130
  104. package/src/apps/cli/hermes-validation-output.ts +0 -91
  105. package/src/apps/cli/index.ts +0 -1735
  106. package/src/apps/cli/mcp-install.ts +0 -106
  107. package/src/apps/cli/retrieval-disclosure-output.ts +0 -196
  108. package/src/apps/dashboard/assets/js/bootstrap.js +0 -244
  109. package/src/apps/dashboard/assets/js/chat.js +0 -373
  110. package/src/apps/dashboard/assets/js/disclosure.js +0 -232
  111. package/src/apps/dashboard/assets/js/modals.js +0 -298
  112. package/src/apps/dashboard/assets/js/overview.js +0 -655
  113. package/src/apps/dashboard/assets/js/state.js +0 -72
  114. package/src/apps/dashboard/assets/js/views.js +0 -468
  115. package/src/apps/dashboard/index.html +0 -543
  116. package/src/apps/dashboard/index.ts +0 -3
  117. package/src/apps/dashboard/style.css +0 -1750
  118. package/src/apps/index.ts +0 -5
  119. package/src/apps/server/api/chat.ts +0 -244
  120. package/src/apps/server/api/citations.ts +0 -105
  121. package/src/apps/server/api/events.ts +0 -137
  122. package/src/apps/server/api/health.ts +0 -53
  123. package/src/apps/server/api/index.ts +0 -26
  124. package/src/apps/server/api/projects.ts +0 -74
  125. package/src/apps/server/api/search.ts +0 -184
  126. package/src/apps/server/api/sessions.ts +0 -115
  127. package/src/apps/server/api/stats.ts +0 -723
  128. package/src/apps/server/api/turns.ts +0 -143
  129. package/src/apps/server/api/utils.ts +0 -65
  130. package/src/apps/server/index.ts +0 -111
  131. package/src/cli/index.ts +0 -3
  132. package/src/cli/retrieval-disclosure-output.ts +0 -2
  133. package/src/compat/index.ts +0 -5
  134. package/src/core/canonical-key.ts +0 -186
  135. package/src/core/citation-generator.ts +0 -63
  136. package/src/core/consolidated-store.ts +0 -356
  137. package/src/core/consolidation-worker.ts +0 -493
  138. package/src/core/context-formatter.ts +0 -276
  139. package/src/core/continuity-manager.ts +0 -341
  140. package/src/core/db-wrapper.ts +0 -64
  141. package/src/core/derive/fact-deriver.ts +0 -170
  142. package/src/core/derive/index.ts +0 -2
  143. package/src/core/derive/summary-deriver.ts +0 -76
  144. package/src/core/edge-repo.ts +0 -333
  145. package/src/core/embedder.ts +0 -4
  146. package/src/core/engine/embedding-maintenance-service.ts +0 -187
  147. package/src/core/engine/endless-memory-services.ts +0 -4
  148. package/src/core/engine/index.ts +0 -19
  149. package/src/core/engine/memory-engine-services.ts +0 -170
  150. package/src/core/engine/memory-ingest-service.ts +0 -317
  151. package/src/core/engine/memory-query-service.ts +0 -173
  152. package/src/core/engine/memory-runtime-service.ts +0 -162
  153. package/src/core/engine/memory-service-composition.ts +0 -231
  154. package/src/core/engine/retrieval-analytics-service.ts +0 -181
  155. package/src/core/engine/retrieval-disclosure-service.ts +0 -420
  156. package/src/core/engine/retrieval-orchestrator.ts +0 -377
  157. package/src/core/engine/retrieval-services.ts +0 -176
  158. package/src/core/engine/shared-memory-services.ts +0 -4
  159. package/src/core/entity-repo.ts +0 -349
  160. package/src/core/event-store.ts +0 -779
  161. package/src/core/evidence-aligner.ts +0 -635
  162. package/src/core/external-market-context.ts +0 -582
  163. package/src/core/graduation-worker.ts +0 -171
  164. package/src/core/graduation.ts +0 -377
  165. package/src/core/index.ts +0 -64
  166. package/src/core/ingest-interceptor.ts +0 -80
  167. package/src/core/markdown-mirror.ts +0 -70
  168. package/src/core/matcher.ts +0 -208
  169. package/src/core/md-mirror.ts +0 -92
  170. package/src/core/metadata-extractor.ts +0 -203
  171. package/src/core/model/memory-fact.ts +0 -30
  172. package/src/core/model/memory-rule.ts +0 -14
  173. package/src/core/model/memory-summary.ts +0 -21
  174. package/src/core/model/raw-event.ts +0 -28
  175. package/src/core/model/retrieval-result.ts +0 -35
  176. package/src/core/mongo-sync-config.ts +0 -165
  177. package/src/core/mongo-sync-worker.ts +0 -381
  178. package/src/core/privacy/filter.ts +0 -190
  179. package/src/core/privacy/index.ts +0 -20
  180. package/src/core/privacy/tag-parser.ts +0 -145
  181. package/src/core/product-validation-matrix.ts +0 -314
  182. package/src/core/progressive-retriever.ts +0 -414
  183. package/src/core/registry/project-path.ts +0 -54
  184. package/src/core/registry/session-registry.ts +0 -69
  185. package/src/core/replay-evaluator.ts +0 -625
  186. package/src/core/retrieval-benchmark.ts +0 -117
  187. package/src/core/retrieval-quality.ts +0 -109
  188. package/src/core/retriever.ts +0 -800
  189. package/src/core/session-qrels.ts +0 -360
  190. package/src/core/shared-event-store.ts +0 -114
  191. package/src/core/shared-promoter.ts +0 -249
  192. package/src/core/shared-store.ts +0 -289
  193. package/src/core/shared-vector-store.ts +0 -203
  194. package/src/core/sqlite-event-store.ts +0 -1846
  195. package/src/core/sqlite-wrapper.ts +0 -116
  196. package/src/core/sync-worker.ts +0 -228
  197. package/src/core/tag-taxonomy.ts +0 -51
  198. package/src/core/task/blocker-resolver.ts +0 -333
  199. package/src/core/task/index.ts +0 -9
  200. package/src/core/task/task-matcher.ts +0 -240
  201. package/src/core/task/task-projector.ts +0 -358
  202. package/src/core/task/task-resolver.ts +0 -421
  203. package/src/core/turn-state.ts +0 -207
  204. package/src/core/types.ts +0 -952
  205. package/src/core/vector-outbox.ts +0 -299
  206. package/src/core/vector-store.ts +0 -231
  207. package/src/core/vector-worker.ts +0 -521
  208. package/src/core/working-set-store.ts +0 -257
  209. package/src/extensions/endless-memory/endless-memory-services.ts +0 -350
  210. package/src/extensions/endless-memory/index.ts +0 -1
  211. package/src/extensions/index.ts +0 -5
  212. package/src/extensions/mcp/handlers.ts +0 -960
  213. package/src/extensions/mcp/index.ts +0 -48
  214. package/src/extensions/mcp/tools.ts +0 -252
  215. package/src/extensions/shared-memory/index.ts +0 -1
  216. package/src/extensions/shared-memory/shared-memory-services.ts +0 -211
  217. package/src/extensions/vector/embedder.ts +0 -234
  218. package/src/extensions/vector/index.ts +0 -1
  219. package/src/hooks/post-tool-use.ts +0 -9
  220. package/src/hooks/semantic-daemon-client.ts +0 -1
  221. package/src/hooks/semantic-daemon.ts +0 -11
  222. package/src/hooks/session-end.ts +0 -9
  223. package/src/hooks/session-start.ts +0 -9
  224. package/src/hooks/stop.ts +0 -9
  225. package/src/hooks/user-prompt-submit.ts +0 -9
  226. package/src/index.ts +0 -13
  227. package/src/mcp/handlers.ts +0 -2
  228. package/src/mcp/index.ts +0 -4
  229. package/src/mcp/tools.ts +0 -2
  230. package/src/server/api/chat.ts +0 -2
  231. package/src/server/api/citations.ts +0 -2
  232. package/src/server/api/events.ts +0 -2
  233. package/src/server/api/health.ts +0 -2
  234. package/src/server/api/index.ts +0 -2
  235. package/src/server/api/projects.ts +0 -2
  236. package/src/server/api/search.ts +0 -2
  237. package/src/server/api/sessions.ts +0 -2
  238. package/src/server/api/stats.ts +0 -2
  239. package/src/server/api/turns.ts +0 -2
  240. package/src/server/api/utils.ts +0 -2
  241. package/src/server/index.ts +0 -2
  242. package/src/services/bootstrap-organizer.ts +0 -463
  243. package/src/services/codex-session-history-importer.ts +0 -966
  244. package/src/services/hermes-session-history-importer.ts +0 -733
  245. package/src/services/memory-service-config.ts +0 -36
  246. package/src/services/memory-service-registry.ts +0 -150
  247. package/src/services/memory-service.ts +0 -688
  248. package/src/services/session-history-importer.ts +0 -629
  249. package/tests/README.md +0 -23
  250. package/tests/adapters/claude/claude-semantic-daemon-adapter.test.ts +0 -54
  251. package/tests/adapters/claude/claude-transcript-reconstructor.test.ts +0 -98
  252. package/tests/adapters/claude-hook-prompt-injection-policy.test.ts +0 -99
  253. package/tests/apps/app-layer-boundary.test.ts +0 -48
  254. package/tests/apps/claude-settings-hooks.test.ts +0 -107
  255. package/tests/apps/cli-disclosure-output.test.ts +0 -212
  256. package/tests/apps/codex-import-runner.test.ts +0 -99
  257. package/tests/apps/codex-validation-output.test.ts +0 -100
  258. package/tests/apps/hermes-import-runner.test.ts +0 -99
  259. package/tests/apps/mcp-install-command.test.ts +0 -59
  260. package/tests/apps/package-build-entrypoints.test.ts +0 -30
  261. package/tests/apps/postinstall-embedding-backend.test.ts +0 -185
  262. package/tests/apps/search-api-disclosure.test.ts +0 -162
  263. package/tests/apps/stats-api-lightweight.test.ts +0 -67
  264. package/tests/apps/ui-disclosure-output.test.ts +0 -140
  265. package/tests/core/bootstrap-organizer.test.ts +0 -111
  266. package/tests/core/canonical-key.test.ts +0 -101
  267. package/tests/core/codex-session-history-importer-validation.test.ts +0 -185
  268. package/tests/core/consolidation-worker.test.ts +0 -75
  269. package/tests/core/embedding-maintenance-service.test.ts +0 -282
  270. package/tests/core/evidence-aligner.test.ts +0 -152
  271. package/tests/core/external-market-context.test.ts +0 -209
  272. package/tests/core/fact-deriver.test.ts +0 -79
  273. package/tests/core/hermes-session-history-importer-validation.test.ts +0 -609
  274. package/tests/core/ingest-interceptor.test.ts +0 -38
  275. package/tests/core/markdown-mirror.test.ts +0 -85
  276. package/tests/core/matcher.test.ts +0 -112
  277. package/tests/core/md-mirror.test.ts +0 -50
  278. package/tests/core/memory-engine-services.test.ts +0 -240
  279. package/tests/core/memory-ingest-service.test.ts +0 -296
  280. package/tests/core/memory-query-service.test.ts +0 -129
  281. package/tests/core/memory-runtime-service.test.ts +0 -201
  282. package/tests/core/memory-service-composition.test.ts +0 -192
  283. package/tests/core/memory-service-config.test.ts +0 -41
  284. package/tests/core/memory-service-facade.test.ts +0 -30
  285. package/tests/core/memory-service-registry.test.ts +0 -206
  286. package/tests/core/product-validation-matrix.test.ts +0 -61
  287. package/tests/core/project-registry.test.ts +0 -78
  288. package/tests/core/replay-evaluator.test.ts +0 -181
  289. package/tests/core/retrieval-analytics-service.test.ts +0 -210
  290. package/tests/core/retrieval-benchmark.test.ts +0 -93
  291. package/tests/core/retrieval-disclosure-service.test.ts +0 -264
  292. package/tests/core/retrieval-orchestrator.test.ts +0 -403
  293. package/tests/core/retrieval-quality.test.ts +0 -31
  294. package/tests/core/retrieval-services.test.ts +0 -185
  295. package/tests/core/retriever-fallback-chain.test.ts +0 -223
  296. package/tests/core/retriever-strategy-scope.test.ts +0 -164
  297. package/tests/core/retriever.memu-adoption.test.ts +0 -122
  298. package/tests/core/session-history-importer-filter.test.ts +0 -78
  299. package/tests/core/session-qrels.test.ts +0 -250
  300. package/tests/core/sqlite-event-store-replication.test.ts +0 -127
  301. package/tests/core/summary-deriver.test.ts +0 -66
  302. package/tests/extensions/embedder-warning-suppression.test.ts +0 -84
  303. package/tests/extensions/endless-memory-extension-boundary.test.ts +0 -17
  304. package/tests/extensions/endless-memory-services.test.ts +0 -325
  305. package/tests/extensions/mcp-context-tools.test.ts +0 -905
  306. package/tests/extensions/mcp-extension-boundary.test.ts +0 -21
  307. package/tests/extensions/mcp-package-build.test.ts +0 -22
  308. package/tests/extensions/mcp-project-aware-tools.test.ts +0 -102
  309. package/tests/extensions/shared-memory-extension-boundary.test.ts +0 -24
  310. package/tests/extensions/shared-memory-services.test.ts +0 -309
  311. package/tests/extensions/vector-extension-boundary.test.ts +0 -21
  312. package/tsconfig.json +0 -24
  313. package/vitest.config.ts +0 -15
@@ -1,421 +0,0 @@
1
- /**
2
- * Task Resolver - Process extracted task entries and emit task events
3
- * AXIOMMIND: Task state via event fold, no direct updates
4
- */
5
-
6
- import { dbRun, dbAll, type Database } from '../db-wrapper.js';
7
- import { randomUUID } from 'crypto';
8
- import type {
9
- Entity,
10
- TaskStatus,
11
- TaskPriority,
12
- BlockerMode
13
- } from '../types.js';
14
- import { makeEntityCanonicalKey, makeTaskEventDedupeKey } from '../canonical-key.js';
15
- import { TaskMatcher } from './task-matcher.js';
16
- import { BlockerResolver } from './blocker-resolver.js';
17
-
18
- export interface ExtractedTask {
19
- title: string;
20
- status?: TaskStatus;
21
- priority?: TaskPriority;
22
- blockedBy?: string[];
23
- description?: string;
24
- project?: string;
25
- }
26
-
27
- export interface TaskResolverConfig {
28
- sessionId: string;
29
- project?: string;
30
- evidenceAligned?: boolean;
31
- }
32
-
33
- // Valid status transitions
34
- const VALID_TRANSITIONS: Record<TaskStatus, TaskStatus[]> = {
35
- pending: ['in_progress', 'cancelled'],
36
- in_progress: ['blocked', 'done', 'cancelled'],
37
- blocked: ['in_progress', 'done', 'cancelled'],
38
- done: [], // Terminal state
39
- cancelled: [] // Terminal state
40
- };
41
-
42
- export class TaskResolver {
43
- private taskMatcher: TaskMatcher;
44
- private blockerResolver: BlockerResolver;
45
-
46
- constructor(
47
- private db: Database,
48
- private config: TaskResolverConfig
49
- ) {
50
- this.taskMatcher = new TaskMatcher(db);
51
- this.blockerResolver = new BlockerResolver(db, { project: config.project });
52
- }
53
-
54
- /**
55
- * Process extracted task entry
56
- * 1. Find or create task entity
57
- * 2. Emit status/priority change events if needed
58
- * 3. Process blockers
59
- */
60
- async processTask(extracted: ExtractedTask, sourceEntryId?: string): Promise<{
61
- taskId: string;
62
- isNew: boolean;
63
- events: string[];
64
- }> {
65
- const events: string[] = [];
66
-
67
- // Step 1: Find existing task or create new
68
- const { task, isNew, eventId: createEventId } = await this.findOrCreateTask(extracted);
69
-
70
- if (isNew && createEventId) {
71
- events.push(createEventId);
72
- }
73
-
74
- // Step 2: Handle status changes
75
- if (extracted.status) {
76
- const statusEvent = await this.handleStatusChange(task, extracted.status);
77
- if (statusEvent) {
78
- events.push(statusEvent);
79
- }
80
- }
81
-
82
- // Step 3: Handle priority changes
83
- if (extracted.priority) {
84
- const priorityEvent = await this.handlePriorityChange(task, extracted.priority);
85
- if (priorityEvent) {
86
- events.push(priorityEvent);
87
- }
88
- }
89
-
90
- // Step 4: Handle blockers
91
- if (extracted.blockedBy && extracted.blockedBy.length > 0) {
92
- const blockerEvent = await this.handleBlockers(
93
- task,
94
- extracted.blockedBy,
95
- sourceEntryId
96
- );
97
- if (blockerEvent) {
98
- events.push(blockerEvent);
99
- }
100
- } else if (extracted.status === 'blocked') {
101
- // Status is blocked but no blockers provided
102
- // Create unknown placeholder
103
- const blockerEvent = await this.handleUnknownBlocker(task);
104
- if (blockerEvent) {
105
- events.push(blockerEvent);
106
- }
107
- }
108
-
109
- return {
110
- taskId: task.entityId,
111
- isNew,
112
- events
113
- };
114
- }
115
-
116
- /**
117
- * Find existing task or create new one
118
- */
119
- private async findOrCreateTask(extracted: ExtractedTask): Promise<{
120
- task: Entity;
121
- isNew: boolean;
122
- eventId?: string;
123
- }> {
124
- // Try to find existing task
125
- const matchResult = await this.taskMatcher.match(extracted.title, extracted.project);
126
-
127
- if (matchResult.confidence === 'high' && matchResult.match) {
128
- return {
129
- task: matchResult.match,
130
- isNew: false
131
- };
132
- }
133
-
134
- // Create new task
135
- const taskId = randomUUID();
136
- const canonicalKey = makeEntityCanonicalKey('task', extracted.title, {
137
- project: extracted.project
138
- });
139
-
140
- // Correct initial status: never start as 'done'
141
- let initialStatus = extracted.status ?? 'pending';
142
- if (initialStatus === 'done') {
143
- initialStatus = 'in_progress'; // Correct: can't start as done
144
- }
145
-
146
- const now = new Date();
147
-
148
- const currentJson = {
149
- status: initialStatus,
150
- priority: extracted.priority ?? 'medium',
151
- description: extracted.description,
152
- project: extracted.project ?? this.config.project
153
- };
154
-
155
- // Insert entity
156
- await dbRun(
157
- this.db,
158
- `INSERT INTO entities (
159
- entity_id, entity_type, canonical_key, title, stage, status,
160
- current_json, title_norm, search_text, created_at, updated_at
161
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
162
- [
163
- taskId,
164
- 'task',
165
- canonicalKey,
166
- extracted.title,
167
- 'raw',
168
- 'active',
169
- JSON.stringify(currentJson),
170
- extracted.title.toLowerCase().trim(),
171
- `${extracted.title} ${extracted.description ?? ''}`,
172
- now.toISOString(),
173
- now.toISOString()
174
- ]
175
- );
176
-
177
- // Create alias
178
- await dbRun(
179
- this.db,
180
- `INSERT INTO entity_aliases (entity_type, canonical_key, entity_id, is_primary)
181
- VALUES (?, ?, ?, TRUE)
182
- ON CONFLICT (entity_type, canonical_key) DO NOTHING`,
183
- ['task', canonicalKey, taskId]
184
- );
185
-
186
- // Emit task_created event
187
- const eventId = await this.emitTaskEvent('task_created', {
188
- taskId,
189
- title: extracted.title,
190
- canonicalKey,
191
- initialStatus,
192
- priority: extracted.priority ?? 'medium',
193
- description: extracted.description,
194
- project: extracted.project ?? this.config.project
195
- });
196
-
197
- // Return created entity
198
- const task: Entity = {
199
- entityId: taskId,
200
- entityType: 'task',
201
- canonicalKey,
202
- title: extracted.title,
203
- stage: 'raw',
204
- status: 'active',
205
- currentJson,
206
- titleNorm: extracted.title.toLowerCase().trim(),
207
- searchText: `${extracted.title} ${extracted.description ?? ''}`,
208
- createdAt: now,
209
- updatedAt: now
210
- };
211
-
212
- return { task, isNew: true, eventId };
213
- }
214
-
215
- /**
216
- * Handle task status change
217
- */
218
- private async handleStatusChange(
219
- task: Entity,
220
- newStatus: TaskStatus
221
- ): Promise<string | null> {
222
- const currentJson = task.currentJson as { status: TaskStatus };
223
- const currentStatus = currentJson.status;
224
-
225
- if (currentStatus === newStatus) {
226
- return null; // No change
227
- }
228
-
229
- // Validate transition
230
- const validNextStates = VALID_TRANSITIONS[currentStatus] ?? [];
231
- if (!validNextStates.includes(newStatus)) {
232
- // Invalid transition - emit rejection event
233
- return this.emitTaskEvent('task_transition_rejected', {
234
- taskId: task.entityId,
235
- fromStatus: currentStatus,
236
- toStatus: newStatus,
237
- reason: `Invalid transition from ${currentStatus} to ${newStatus}`
238
- });
239
- }
240
-
241
- // Emit status change event
242
- const eventId = await this.emitTaskEvent('task_status_changed', {
243
- taskId: task.entityId,
244
- fromStatus: currentStatus,
245
- toStatus: newStatus
246
- });
247
-
248
- // Update entity (projector will do this, but we update for immediate consistency)
249
- await dbRun(
250
- this.db,
251
- `UPDATE entities
252
- SET current_json = json_set(current_json, '$.status', ?),
253
- updated_at = ?
254
- WHERE entity_id = ?`,
255
- [newStatus, new Date().toISOString(), task.entityId]
256
- );
257
-
258
- return eventId;
259
- }
260
-
261
- /**
262
- * Handle task priority change
263
- */
264
- private async handlePriorityChange(
265
- task: Entity,
266
- newPriority: TaskPriority
267
- ): Promise<string | null> {
268
- const currentJson = task.currentJson as { priority?: TaskPriority };
269
- const currentPriority = currentJson.priority ?? 'medium';
270
-
271
- if (currentPriority === newPriority) {
272
- return null; // No change
273
- }
274
-
275
- // Emit priority change event
276
- const eventId = await this.emitTaskEvent('task_priority_changed', {
277
- taskId: task.entityId,
278
- fromPriority: currentPriority,
279
- toPriority: newPriority
280
- });
281
-
282
- // Update entity
283
- await dbRun(
284
- this.db,
285
- `UPDATE entities
286
- SET current_json = json_set(current_json, '$.priority', ?),
287
- updated_at = ?
288
- WHERE entity_id = ?`,
289
- [newPriority, new Date().toISOString(), task.entityId]
290
- );
291
-
292
- return eventId;
293
- }
294
-
295
- /**
296
- * Handle blockers
297
- */
298
- private async handleBlockers(
299
- task: Entity,
300
- blockedByTexts: string[],
301
- sourceEntryId?: string
302
- ): Promise<string | null> {
303
- // Resolve blocker texts to entity refs
304
- const blockerRefs = await this.blockerResolver.resolveBlockers(blockedByTexts);
305
-
306
- // Determine mode based on evidence alignment
307
- const mode: BlockerMode = this.config.evidenceAligned ? 'replace' : 'suggest';
308
-
309
- // Emit task_blockers_set event
310
- const eventId = await this.emitTaskEvent('task_blockers_set', {
311
- taskId: task.entityId,
312
- mode,
313
- blockers: blockerRefs,
314
- sourceEntryId
315
- });
316
-
317
- return eventId;
318
- }
319
-
320
- /**
321
- * Handle unknown blocker (status=blocked but no blockedBy)
322
- */
323
- private async handleUnknownBlocker(task: Entity): Promise<string | null> {
324
- const placeholderRef = await this.blockerResolver.createUnknownPlaceholder(task.title);
325
-
326
- const eventId = await this.emitTaskEvent('task_blockers_set', {
327
- taskId: task.entityId,
328
- mode: 'suggest' as BlockerMode,
329
- blockers: [placeholderRef]
330
- });
331
-
332
- return eventId;
333
- }
334
-
335
- /**
336
- * Emit task event to events table
337
- */
338
- private async emitTaskEvent(
339
- eventType: string,
340
- payload: Record<string, unknown>
341
- ): Promise<string> {
342
- const eventId = randomUUID();
343
- const now = new Date();
344
-
345
- // Generate dedupe key
346
- const dedupeKey = makeTaskEventDedupeKey(
347
- eventType,
348
- payload.taskId as string,
349
- this.config.sessionId,
350
- JSON.stringify(payload)
351
- );
352
-
353
- // Check for duplicate
354
- const existing = await dbAll<{ event_id: string }>(
355
- this.db,
356
- `SELECT event_id FROM event_dedup WHERE dedupe_key = ?`,
357
- [dedupeKey]
358
- );
359
-
360
- if (existing.length > 0) {
361
- return existing[0].event_id; // Return existing event ID
362
- }
363
-
364
- // Insert event
365
- await dbRun(
366
- this.db,
367
- `INSERT INTO events (
368
- id, event_type, session_id, timestamp, content,
369
- canonical_key, dedupe_key, metadata
370
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
371
- [
372
- eventId,
373
- eventType,
374
- this.config.sessionId,
375
- now.toISOString(),
376
- JSON.stringify(payload),
377
- `task_event:${eventType}:${payload.taskId}`,
378
- dedupeKey,
379
- JSON.stringify({ source: 'task_resolver' })
380
- ]
381
- );
382
-
383
- // Insert dedup record
384
- await dbRun(
385
- this.db,
386
- `INSERT INTO event_dedup (dedupe_key, event_id)
387
- VALUES (?, ?)
388
- ON CONFLICT DO NOTHING`,
389
- [dedupeKey, eventId]
390
- );
391
-
392
- return eventId;
393
- }
394
-
395
- /**
396
- * Resolve condition to task (when condition is identified as existing task)
397
- */
398
- async resolveConditionToTask(
399
- conditionId: string,
400
- taskId: string
401
- ): Promise<string> {
402
- const eventId = await this.emitTaskEvent('condition_resolved_to', {
403
- conditionId,
404
- resolvedTo: {
405
- kind: 'task',
406
- entityId: taskId
407
- }
408
- });
409
-
410
- // Create resolves_to edge
411
- await dbRun(
412
- this.db,
413
- `INSERT INTO edges (edge_id, src_type, src_id, rel_type, dst_type, dst_id, meta_json)
414
- VALUES (?, 'entity', ?, 'resolves_to', 'entity', ?, ?)
415
- ON CONFLICT DO NOTHING`,
416
- [randomUUID(), conditionId, taskId, JSON.stringify({ resolved_at: new Date().toISOString() })]
417
- );
418
-
419
- return eventId;
420
- }
421
- }
@@ -1,207 +0,0 @@
1
- /**
2
- * Turn State Management
3
- *
4
- * Manages a per-session turn_id state file that links events within a conversation turn.
5
- *
6
- * Flow:
7
- * 1. UserPromptSubmit generates a new turn_id and writes it to a state file
8
- * 2. PostToolUse reads the current turn_id to associate tool observations with the turn
9
- * 3. Stop reads the turn_id to associate agent responses, then cleans up
10
- *
11
- * State file location: ~/.claude-code/memory/.turn-state-{session_id}.json
12
- *
13
- * The file is small (just a JSON with turnId + timestamp) and uses atomic writes
14
- * to prevent corruption from concurrent hook execution.
15
- */
16
-
17
- import * as fs from 'fs';
18
- import * as path from 'path';
19
- import * as os from 'os';
20
-
21
- const TURN_STATE_DIR = path.join(os.homedir(), '.claude-code', 'memory');
22
-
23
- interface TurnState {
24
- turnId: string;
25
- sessionId: string;
26
- createdAt: string;
27
- }
28
-
29
- /**
30
- * Get the state file path for a session
31
- */
32
- function getStatePath(sessionId: string): string {
33
- return path.join(TURN_STATE_DIR, `.turn-state-${sessionId}.json`);
34
- }
35
-
36
- /**
37
- * Write a new turn state for a session.
38
- * Called by UserPromptSubmit hook when a new user prompt arrives.
39
- */
40
- export function writeTurnState(sessionId: string, turnId: string): void {
41
- try {
42
- // Ensure directory exists
43
- if (!fs.existsSync(TURN_STATE_DIR)) {
44
- fs.mkdirSync(TURN_STATE_DIR, { recursive: true });
45
- }
46
-
47
- const state: TurnState = {
48
- turnId,
49
- sessionId,
50
- createdAt: new Date().toISOString()
51
- };
52
-
53
- const filePath = getStatePath(sessionId);
54
- const tempPath = filePath + '.tmp';
55
-
56
- // Atomic write: write to temp file then rename
57
- fs.writeFileSync(tempPath, JSON.stringify(state));
58
- fs.renameSync(tempPath, filePath);
59
- } catch (error) {
60
- // Non-critical: if we can't write turn state, events just won't be grouped
61
- if (process.env.CLAUDE_MEMORY_DEBUG) {
62
- console.error('Failed to write turn state:', error);
63
- }
64
- }
65
- }
66
-
67
- /**
68
- * Read the current turn_id for a session.
69
- * Called by PostToolUse and Stop hooks to associate events with the current turn.
70
- * Returns null if no turn state exists (events won't be grouped).
71
- */
72
- export function readTurnState(sessionId: string): string | null {
73
- try {
74
- const filePath = getStatePath(sessionId);
75
-
76
- if (!fs.existsSync(filePath)) {
77
- return null;
78
- }
79
-
80
- const data = fs.readFileSync(filePath, 'utf-8');
81
- const state: TurnState = JSON.parse(data);
82
-
83
- // Validate the state belongs to this session
84
- if (state.sessionId !== sessionId) {
85
- return null;
86
- }
87
-
88
- // Check staleness: if the turn state is older than 30 minutes, ignore it
89
- const createdAt = new Date(state.createdAt).getTime();
90
- const now = Date.now();
91
- if (now - createdAt > 30 * 60 * 1000) {
92
- // Stale turn state, clean up
93
- clearTurnState(sessionId);
94
- return null;
95
- }
96
-
97
- return state.turnId;
98
- } catch (error) {
99
- // Non-critical: return null if we can't read
100
- if (process.env.CLAUDE_MEMORY_DEBUG) {
101
- console.error('Failed to read turn state:', error);
102
- }
103
- return null;
104
- }
105
- }
106
-
107
- /**
108
- * Clear the turn state for a session.
109
- * Called by Stop hook after processing agent responses.
110
- */
111
- export function clearTurnState(sessionId: string): void {
112
- try {
113
- const filePath = getStatePath(sessionId);
114
- if (fs.existsSync(filePath)) {
115
- fs.unlinkSync(filePath);
116
- }
117
- } catch (error) {
118
- // Non-critical
119
- if (process.env.CLAUDE_MEMORY_DEBUG) {
120
- console.error('Failed to clear turn state:', error);
121
- }
122
- }
123
- }
124
-
125
- // ---------------------------------------------------------------------------
126
- // Last Assistant Snippet State
127
- // Persists the last ~500 chars of the assistant's response so the next
128
- // UserPromptSubmit can enrich the retrieval query with conversation context.
129
- // ---------------------------------------------------------------------------
130
-
131
- const LAST_RESPONSE_SNIPPET_CHARS = 500;
132
-
133
- interface LastResponseState {
134
- sessionId: string;
135
- snippet: string;
136
- createdAt: string;
137
- }
138
-
139
- function getLastResponsePath(sessionId: string): string {
140
- return path.join(TURN_STATE_DIR, `.last-response-${sessionId}.json`);
141
- }
142
-
143
- export function writeLastAssistantSnippet(sessionId: string, text: string): void {
144
- try {
145
- if (!fs.existsSync(TURN_STATE_DIR)) {
146
- fs.mkdirSync(TURN_STATE_DIR, { recursive: true });
147
- }
148
- const snippet = text.slice(0, LAST_RESPONSE_SNIPPET_CHARS);
149
- const state: LastResponseState = { sessionId, snippet, createdAt: new Date().toISOString() };
150
- const filePath = getLastResponsePath(sessionId);
151
- const tempPath = filePath + '.tmp';
152
- fs.writeFileSync(tempPath, JSON.stringify(state));
153
- fs.renameSync(tempPath, filePath);
154
- } catch {
155
- // non-critical
156
- }
157
- }
158
-
159
- export function readLastAssistantSnippet(sessionId: string): string | null {
160
- try {
161
- const filePath = getLastResponsePath(sessionId);
162
- if (!fs.existsSync(filePath)) return null;
163
- const state: LastResponseState = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
164
- if (state.sessionId !== sessionId) return null;
165
- // Ignore if older than 2 hours (stale session)
166
- if (Date.now() - new Date(state.createdAt).getTime() > 2 * 60 * 60 * 1000) return null;
167
- return state.snippet || null;
168
- } catch {
169
- return null;
170
- }
171
- }
172
-
173
- /**
174
- * Clean up stale turn state files (older than 1 hour).
175
- * Can be called periodically to prevent file accumulation.
176
- */
177
- export function cleanupStaleTurnStates(): number {
178
- let cleaned = 0;
179
-
180
- try {
181
- if (!fs.existsSync(TURN_STATE_DIR)) return 0;
182
-
183
- const files = fs.readdirSync(TURN_STATE_DIR);
184
- const now = Date.now();
185
-
186
- for (const file of files) {
187
- if (!file.startsWith('.turn-state-') || !file.endsWith('.json')) continue;
188
-
189
- const filePath = path.join(TURN_STATE_DIR, file);
190
-
191
- try {
192
- const stat = fs.statSync(filePath);
193
- // Remove files older than 1 hour
194
- if (now - stat.mtimeMs > 60 * 60 * 1000) {
195
- fs.unlinkSync(filePath);
196
- cleaned++;
197
- }
198
- } catch {
199
- // Skip files we can't stat
200
- }
201
- }
202
- } catch {
203
- // Non-critical
204
- }
205
-
206
- return cleaned;
207
- }