@jamesaphoenix/tx-core 0.4.1

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 (289) hide show
  1. package/dist/db.d.ts +42 -0
  2. package/dist/db.d.ts.map +1 -0
  3. package/dist/db.js +46 -0
  4. package/dist/db.js.map +1 -0
  5. package/dist/errors.d.ts +231 -0
  6. package/dist/errors.d.ts.map +1 -0
  7. package/dist/errors.js +139 -0
  8. package/dist/errors.js.map +1 -0
  9. package/dist/id.d.ts +6 -0
  10. package/dist/id.d.ts.map +1 -0
  11. package/dist/id.js +21 -0
  12. package/dist/id.js.map +1 -0
  13. package/dist/index.d.ts +25 -0
  14. package/dist/index.d.ts.map +1 -0
  15. package/dist/index.js +56 -0
  16. package/dist/index.js.map +1 -0
  17. package/dist/layer.d.ts +50 -0
  18. package/dist/layer.d.ts.map +1 -0
  19. package/dist/layer.js +155 -0
  20. package/dist/layer.js.map +1 -0
  21. package/dist/mappers/anchor.d.ts +14 -0
  22. package/dist/mappers/anchor.d.ts.map +1 -0
  23. package/dist/mappers/anchor.js +38 -0
  24. package/dist/mappers/anchor.js.map +1 -0
  25. package/dist/mappers/attempt.d.ts +15 -0
  26. package/dist/mappers/attempt.d.ts.map +1 -0
  27. package/dist/mappers/attempt.js +23 -0
  28. package/dist/mappers/attempt.js.map +1 -0
  29. package/dist/mappers/candidate.d.ts +23 -0
  30. package/dist/mappers/candidate.d.ts.map +1 -0
  31. package/dist/mappers/candidate.js +53 -0
  32. package/dist/mappers/candidate.js.map +1 -0
  33. package/dist/mappers/claim.d.ts +30 -0
  34. package/dist/mappers/claim.d.ts.map +1 -0
  35. package/dist/mappers/claim.js +32 -0
  36. package/dist/mappers/claim.js.map +1 -0
  37. package/dist/mappers/deduplication.d.ts +39 -0
  38. package/dist/mappers/deduplication.d.ts.map +1 -0
  39. package/dist/mappers/deduplication.js +53 -0
  40. package/dist/mappers/deduplication.js.map +1 -0
  41. package/dist/mappers/edge.d.ts +10 -0
  42. package/dist/mappers/edge.d.ts.map +1 -0
  43. package/dist/mappers/edge.js +19 -0
  44. package/dist/mappers/edge.js.map +1 -0
  45. package/dist/mappers/file-learning.d.ts +14 -0
  46. package/dist/mappers/file-learning.d.ts.map +1 -0
  47. package/dist/mappers/file-learning.js +75 -0
  48. package/dist/mappers/file-learning.js.map +1 -0
  49. package/dist/mappers/index.d.ts +17 -0
  50. package/dist/mappers/index.d.ts.map +1 -0
  51. package/dist/mappers/index.js +30 -0
  52. package/dist/mappers/index.js.map +1 -0
  53. package/dist/mappers/learning.d.ts +19 -0
  54. package/dist/mappers/learning.d.ts.map +1 -0
  55. package/dist/mappers/learning.js +41 -0
  56. package/dist/mappers/learning.js.map +1 -0
  57. package/dist/mappers/orchestrator-state.d.ts +33 -0
  58. package/dist/mappers/orchestrator-state.d.ts.map +1 -0
  59. package/dist/mappers/orchestrator-state.js +34 -0
  60. package/dist/mappers/orchestrator-state.js.map +1 -0
  61. package/dist/mappers/run.d.ts +32 -0
  62. package/dist/mappers/run.d.ts.map +1 -0
  63. package/dist/mappers/run.js +64 -0
  64. package/dist/mappers/run.js.map +1 -0
  65. package/dist/mappers/task.d.ts +23 -0
  66. package/dist/mappers/task.d.ts.map +1 -0
  67. package/dist/mappers/task.js +54 -0
  68. package/dist/mappers/task.js.map +1 -0
  69. package/dist/mappers/tracked-project.d.ts +15 -0
  70. package/dist/mappers/tracked-project.d.ts.map +1 -0
  71. package/dist/mappers/tracked-project.js +23 -0
  72. package/dist/mappers/tracked-project.js.map +1 -0
  73. package/dist/mappers/worker.d.ts +33 -0
  74. package/dist/mappers/worker.d.ts.map +1 -0
  75. package/dist/mappers/worker.js +35 -0
  76. package/dist/mappers/worker.js.map +1 -0
  77. package/dist/repo/anchor-repo.d.ts +52 -0
  78. package/dist/repo/anchor-repo.d.ts.map +1 -0
  79. package/dist/repo/anchor-repo.js +204 -0
  80. package/dist/repo/anchor-repo.js.map +1 -0
  81. package/dist/repo/attempt-repo.d.ts +25 -0
  82. package/dist/repo/attempt-repo.d.ts.map +1 -0
  83. package/dist/repo/attempt-repo.js +78 -0
  84. package/dist/repo/attempt-repo.js.map +1 -0
  85. package/dist/repo/candidate-repo.d.ts +16 -0
  86. package/dist/repo/candidate-repo.d.ts.map +1 -0
  87. package/dist/repo/candidate-repo.js +143 -0
  88. package/dist/repo/candidate-repo.js.map +1 -0
  89. package/dist/repo/claim-repo.d.ts +17 -0
  90. package/dist/repo/claim-repo.d.ts.map +1 -0
  91. package/dist/repo/claim-repo.js +62 -0
  92. package/dist/repo/claim-repo.js.map +1 -0
  93. package/dist/repo/deduplication-repo.d.ts +37 -0
  94. package/dist/repo/deduplication-repo.d.ts.map +1 -0
  95. package/dist/repo/deduplication-repo.js +133 -0
  96. package/dist/repo/deduplication-repo.js.map +1 -0
  97. package/dist/repo/dep-repo.d.ts +19 -0
  98. package/dist/repo/dep-repo.d.ts.map +1 -0
  99. package/dist/repo/dep-repo.js +104 -0
  100. package/dist/repo/dep-repo.js.map +1 -0
  101. package/dist/repo/edge-repo.d.ts +26 -0
  102. package/dist/repo/edge-repo.d.ts.map +1 -0
  103. package/dist/repo/edge-repo.js +227 -0
  104. package/dist/repo/edge-repo.js.map +1 -0
  105. package/dist/repo/file-learning-repo.d.ts +17 -0
  106. package/dist/repo/file-learning-repo.d.ts.map +1 -0
  107. package/dist/repo/file-learning-repo.js +60 -0
  108. package/dist/repo/file-learning-repo.js.map +1 -0
  109. package/dist/repo/index.d.ts +18 -0
  110. package/dist/repo/index.d.ts.map +1 -0
  111. package/dist/repo/index.js +18 -0
  112. package/dist/repo/index.js.map +1 -0
  113. package/dist/repo/learning-repo.d.ts +31 -0
  114. package/dist/repo/learning-repo.d.ts.map +1 -0
  115. package/dist/repo/learning-repo.js +165 -0
  116. package/dist/repo/learning-repo.js.map +1 -0
  117. package/dist/repo/orchestrator-state-repo.d.ts +27 -0
  118. package/dist/repo/orchestrator-state-repo.d.ts.map +1 -0
  119. package/dist/repo/orchestrator-state-repo.js +96 -0
  120. package/dist/repo/orchestrator-state-repo.js.map +1 -0
  121. package/dist/repo/run-repo.d.ts +31 -0
  122. package/dist/repo/run-repo.d.ts.map +1 -0
  123. package/dist/repo/run-repo.js +132 -0
  124. package/dist/repo/run-repo.js.map +1 -0
  125. package/dist/repo/task-repo.d.ts +21 -0
  126. package/dist/repo/task-repo.d.ts.map +1 -0
  127. package/dist/repo/task-repo.js +169 -0
  128. package/dist/repo/task-repo.js.map +1 -0
  129. package/dist/repo/tracked-project-repo.d.ts +16 -0
  130. package/dist/repo/tracked-project-repo.d.ts.map +1 -0
  131. package/dist/repo/tracked-project-repo.js +54 -0
  132. package/dist/repo/tracked-project-repo.js.map +1 -0
  133. package/dist/repo/worker-repo.d.ts +19 -0
  134. package/dist/repo/worker-repo.d.ts.map +1 -0
  135. package/dist/repo/worker-repo.js +72 -0
  136. package/dist/repo/worker-repo.js.map +1 -0
  137. package/dist/schemas/index.d.ts +8 -0
  138. package/dist/schemas/index.d.ts.map +1 -0
  139. package/dist/schemas/index.js +7 -0
  140. package/dist/schemas/index.js.map +1 -0
  141. package/dist/schemas/sync.d.ts +296 -0
  142. package/dist/schemas/sync.d.ts.map +1 -0
  143. package/dist/schemas/sync.js +146 -0
  144. package/dist/schemas/sync.js.map +1 -0
  145. package/dist/schemas/worker.d.ts +77 -0
  146. package/dist/schemas/worker.d.ts.map +1 -0
  147. package/dist/schemas/worker.js +80 -0
  148. package/dist/schemas/worker.js.map +1 -0
  149. package/dist/services/anchor-service.d.ts +147 -0
  150. package/dist/services/anchor-service.d.ts.map +1 -0
  151. package/dist/services/anchor-service.js +540 -0
  152. package/dist/services/anchor-service.js.map +1 -0
  153. package/dist/services/anchor-verification.d.ts +94 -0
  154. package/dist/services/anchor-verification.d.ts.map +1 -0
  155. package/dist/services/anchor-verification.js +617 -0
  156. package/dist/services/anchor-verification.js.map +1 -0
  157. package/dist/services/ast-grep-service.d.ts +58 -0
  158. package/dist/services/ast-grep-service.d.ts.map +1 -0
  159. package/dist/services/ast-grep-service.js +356 -0
  160. package/dist/services/ast-grep-service.js.map +1 -0
  161. package/dist/services/attempt-service.d.ts +24 -0
  162. package/dist/services/attempt-service.d.ts.map +1 -0
  163. package/dist/services/attempt-service.js +55 -0
  164. package/dist/services/attempt-service.js.map +1 -0
  165. package/dist/services/auto-sync-service.d.ts +56 -0
  166. package/dist/services/auto-sync-service.d.ts.map +1 -0
  167. package/dist/services/auto-sync-service.js +66 -0
  168. package/dist/services/auto-sync-service.js.map +1 -0
  169. package/dist/services/candidate-extractor-service.d.ts +56 -0
  170. package/dist/services/candidate-extractor-service.d.ts.map +1 -0
  171. package/dist/services/candidate-extractor-service.js +365 -0
  172. package/dist/services/candidate-extractor-service.js.map +1 -0
  173. package/dist/services/claim-service.d.ts +52 -0
  174. package/dist/services/claim-service.d.ts.map +1 -0
  175. package/dist/services/claim-service.js +134 -0
  176. package/dist/services/claim-service.js.map +1 -0
  177. package/dist/services/daemon-service.d.ts +214 -0
  178. package/dist/services/daemon-service.d.ts.map +1 -0
  179. package/dist/services/daemon-service.js +522 -0
  180. package/dist/services/daemon-service.js.map +1 -0
  181. package/dist/services/deduplication-service.d.ts +67 -0
  182. package/dist/services/deduplication-service.d.ts.map +1 -0
  183. package/dist/services/deduplication-service.js +145 -0
  184. package/dist/services/deduplication-service.js.map +1 -0
  185. package/dist/services/dep-service.d.ts +14 -0
  186. package/dist/services/dep-service.d.ts.map +1 -0
  187. package/dist/services/dep-service.js +34 -0
  188. package/dist/services/dep-service.js.map +1 -0
  189. package/dist/services/diversifier-service.d.ts +46 -0
  190. package/dist/services/diversifier-service.d.ts.map +1 -0
  191. package/dist/services/diversifier-service.js +197 -0
  192. package/dist/services/diversifier-service.js.map +1 -0
  193. package/dist/services/edge-service.d.ts +78 -0
  194. package/dist/services/edge-service.d.ts.map +1 -0
  195. package/dist/services/edge-service.js +158 -0
  196. package/dist/services/edge-service.js.map +1 -0
  197. package/dist/services/embedding-service.d.ts +138 -0
  198. package/dist/services/embedding-service.d.ts.map +1 -0
  199. package/dist/services/embedding-service.js +318 -0
  200. package/dist/services/embedding-service.js.map +1 -0
  201. package/dist/services/feedback-tracker.d.ts +64 -0
  202. package/dist/services/feedback-tracker.d.ts.map +1 -0
  203. package/dist/services/feedback-tracker.js +110 -0
  204. package/dist/services/feedback-tracker.js.map +1 -0
  205. package/dist/services/file-learning-service.d.ts +17 -0
  206. package/dist/services/file-learning-service.d.ts.map +1 -0
  207. package/dist/services/file-learning-service.js +41 -0
  208. package/dist/services/file-learning-service.js.map +1 -0
  209. package/dist/services/file-watcher-service.d.ts +141 -0
  210. package/dist/services/file-watcher-service.d.ts.map +1 -0
  211. package/dist/services/file-watcher-service.js +278 -0
  212. package/dist/services/file-watcher-service.js.map +1 -0
  213. package/dist/services/graph-expansion.d.ts +155 -0
  214. package/dist/services/graph-expansion.d.ts.map +1 -0
  215. package/dist/services/graph-expansion.js +466 -0
  216. package/dist/services/graph-expansion.js.map +1 -0
  217. package/dist/services/hierarchy-service.d.ts +16 -0
  218. package/dist/services/hierarchy-service.d.ts.map +1 -0
  219. package/dist/services/hierarchy-service.js +66 -0
  220. package/dist/services/hierarchy-service.js.map +1 -0
  221. package/dist/services/index.d.ts +36 -0
  222. package/dist/services/index.d.ts.map +1 -0
  223. package/dist/services/index.js +36 -0
  224. package/dist/services/index.js.map +1 -0
  225. package/dist/services/learning-service.d.ts +39 -0
  226. package/dist/services/learning-service.d.ts.map +1 -0
  227. package/dist/services/learning-service.js +151 -0
  228. package/dist/services/learning-service.js.map +1 -0
  229. package/dist/services/migration-service.d.ts +67 -0
  230. package/dist/services/migration-service.d.ts.map +1 -0
  231. package/dist/services/migration-service.js +144 -0
  232. package/dist/services/migration-service.js.map +1 -0
  233. package/dist/services/orchestrator-service.d.ts +52 -0
  234. package/dist/services/orchestrator-service.d.ts.map +1 -0
  235. package/dist/services/orchestrator-service.js +203 -0
  236. package/dist/services/orchestrator-service.js.map +1 -0
  237. package/dist/services/promotion-service.d.ts +67 -0
  238. package/dist/services/promotion-service.d.ts.map +1 -0
  239. package/dist/services/promotion-service.js +151 -0
  240. package/dist/services/promotion-service.js.map +1 -0
  241. package/dist/services/query-expansion-service.d.ts +55 -0
  242. package/dist/services/query-expansion-service.d.ts.map +1 -0
  243. package/dist/services/query-expansion-service.js +174 -0
  244. package/dist/services/query-expansion-service.js.map +1 -0
  245. package/dist/services/ready-service.d.ts +16 -0
  246. package/dist/services/ready-service.d.ts.map +1 -0
  247. package/dist/services/ready-service.js +70 -0
  248. package/dist/services/ready-service.js.map +1 -0
  249. package/dist/services/reranker-service.d.ts +51 -0
  250. package/dist/services/reranker-service.d.ts.map +1 -0
  251. package/dist/services/reranker-service.js +128 -0
  252. package/dist/services/reranker-service.js.map +1 -0
  253. package/dist/services/retriever-service.d.ts +49 -0
  254. package/dist/services/retriever-service.d.ts.map +1 -0
  255. package/dist/services/retriever-service.js +419 -0
  256. package/dist/services/retriever-service.js.map +1 -0
  257. package/dist/services/score-service.d.ts +43 -0
  258. package/dist/services/score-service.d.ts.map +1 -0
  259. package/dist/services/score-service.js +82 -0
  260. package/dist/services/score-service.js.map +1 -0
  261. package/dist/services/swarm-verification.d.ts +104 -0
  262. package/dist/services/swarm-verification.d.ts.map +1 -0
  263. package/dist/services/swarm-verification.js +400 -0
  264. package/dist/services/swarm-verification.js.map +1 -0
  265. package/dist/services/sync-service.d.ts +115 -0
  266. package/dist/services/sync-service.d.ts.map +1 -0
  267. package/dist/services/sync-service.js +350 -0
  268. package/dist/services/sync-service.js.map +1 -0
  269. package/dist/services/task-service.d.ts +22 -0
  270. package/dist/services/task-service.d.ts.map +1 -0
  271. package/dist/services/task-service.js +221 -0
  272. package/dist/services/task-service.js.map +1 -0
  273. package/dist/services/worker-process.d.ts +41 -0
  274. package/dist/services/worker-process.d.ts.map +1 -0
  275. package/dist/services/worker-process.js +280 -0
  276. package/dist/services/worker-process.js.map +1 -0
  277. package/dist/services/worker-service.d.ts +74 -0
  278. package/dist/services/worker-service.d.ts.map +1 -0
  279. package/dist/services/worker-service.js +148 -0
  280. package/dist/services/worker-service.js.map +1 -0
  281. package/dist/utils/glob.d.ts +15 -0
  282. package/dist/utils/glob.d.ts.map +1 -0
  283. package/dist/utils/glob.js +27 -0
  284. package/dist/utils/glob.js.map +1 -0
  285. package/dist/utils/math.d.ts +6 -0
  286. package/dist/utils/math.d.ts.map +1 -0
  287. package/dist/utils/math.js +21 -0
  288. package/dist/utils/math.js.map +1 -0
  289. package/package.json +72 -0
@@ -0,0 +1,145 @@
1
+ import { Context, Effect, Layer } from "effect";
2
+ import { DeduplicationRepository } from "../repo/deduplication-repo.js";
3
+ import { hashContent } from "../mappers/deduplication.js";
4
+ /**
5
+ * Default batch size for hash checking operations.
6
+ * Balances between query efficiency and memory usage.
7
+ */
8
+ const DEFAULT_BATCH_SIZE = 100;
9
+ /**
10
+ * DeduplicationService handles JSONL line deduplication via SHA256 hashing.
11
+ * Tracks processed content hashes to skip already-seen lines.
12
+ * Supports incremental processing by tracking file progress.
13
+ */
14
+ export class DeduplicationService extends Context.Tag("DeduplicationService")() {
15
+ }
16
+ export const DeduplicationServiceLive = Layer.effect(DeduplicationService, Effect.gen(function* () {
17
+ const repo = yield* DeduplicationRepository;
18
+ return {
19
+ processLine: (content, filePath, lineNumber) => Effect.gen(function* () {
20
+ const hash = hashContent(content);
21
+ const exists = yield* repo.hashExists(hash);
22
+ if (exists) {
23
+ return {
24
+ hash,
25
+ isNew: false,
26
+ lineNumber,
27
+ content
28
+ };
29
+ }
30
+ // Record the new hash
31
+ yield* repo.insertHash({
32
+ contentHash: hash,
33
+ sourceFile: filePath,
34
+ sourceLine: lineNumber
35
+ });
36
+ return {
37
+ hash,
38
+ isNew: true,
39
+ lineNumber,
40
+ content
41
+ };
42
+ }),
43
+ processLines: (lines, filePath, options = {}) => Effect.gen(function* () {
44
+ const startTime = Date.now();
45
+ const batchSize = options.batchSize ?? DEFAULT_BATCH_SIZE;
46
+ const startLine = options.startLine ?? 1;
47
+ const maxLines = options.maxLines;
48
+ // Filter to lines we should process
49
+ let linesToProcess = lines.filter(l => l.lineNumber >= startLine);
50
+ if (maxLines !== undefined) {
51
+ linesToProcess = linesToProcess.slice(0, maxLines);
52
+ }
53
+ if (linesToProcess.length === 0) {
54
+ return {
55
+ filePath,
56
+ totalLines: lines.length,
57
+ newLines: 0,
58
+ skippedLines: 0,
59
+ startLine,
60
+ endLine: startLine - 1,
61
+ duration: Date.now() - startTime
62
+ };
63
+ }
64
+ // Compute hashes for all lines
65
+ const lineHashes = linesToProcess.map(l => ({
66
+ ...l,
67
+ hash: hashContent(l.content)
68
+ }));
69
+ // Check existing hashes in batches
70
+ let existingHashes = new Set();
71
+ for (let i = 0; i < lineHashes.length; i += batchSize) {
72
+ const batch = lineHashes.slice(i, i + batchSize);
73
+ const batchHashes = batch.map(l => l.hash);
74
+ const batchExisting = yield* repo.hashesExist(batchHashes);
75
+ existingHashes = new Set([...existingHashes, ...batchExisting]);
76
+ }
77
+ // Separate new and existing lines
78
+ const newLines = lineHashes.filter(l => !existingHashes.has(l.hash));
79
+ const skippedLines = lineHashes.filter(l => existingHashes.has(l.hash));
80
+ // Insert new hashes in batches
81
+ if (newLines.length > 0) {
82
+ const hashInputs = newLines.map(l => ({
83
+ contentHash: l.hash,
84
+ sourceFile: filePath,
85
+ sourceLine: l.lineNumber
86
+ }));
87
+ yield* repo.insertHashes(hashInputs);
88
+ }
89
+ // Calculate end line
90
+ const lastLine = linesToProcess[linesToProcess.length - 1];
91
+ const endLine = lastLine?.lineNumber ?? startLine - 1;
92
+ return {
93
+ filePath,
94
+ totalLines: lines.length,
95
+ newLines: newLines.length,
96
+ skippedLines: skippedLines.length,
97
+ startLine,
98
+ endLine,
99
+ duration: Date.now() - startTime
100
+ };
101
+ }),
102
+ isProcessed: (content) => Effect.gen(function* () {
103
+ const hash = hashContent(content);
104
+ return yield* repo.hashExists(hash);
105
+ }),
106
+ filterProcessed: (contents) => Effect.gen(function* () {
107
+ if (contents.length === 0)
108
+ return new Set();
109
+ // Compute hashes and check
110
+ const contentHashMap = new Map();
111
+ for (const content of contents) {
112
+ contentHashMap.set(hashContent(content), content);
113
+ }
114
+ const existingHashes = yield* repo.hashesExist([...contentHashMap.keys()]);
115
+ // Return the original content strings that have been processed
116
+ const processedContents = new Set();
117
+ for (const hash of existingHashes) {
118
+ const content = contentHashMap.get(hash);
119
+ if (content)
120
+ processedContents.add(content);
121
+ }
122
+ return processedContents;
123
+ }),
124
+ getProgress: (filePath) => repo.getFileProgress(filePath),
125
+ updateProgress: (filePath, lastLineProcessed, lastByteOffset, fileSize, fileChecksum) => repo.upsertFileProgress({
126
+ filePath,
127
+ lastLineProcessed,
128
+ lastByteOffset,
129
+ fileSize,
130
+ fileChecksum
131
+ }),
132
+ resetFile: (filePath) => Effect.gen(function* () {
133
+ const hashesDeleted = yield* repo.deleteHashesForFile(filePath);
134
+ yield* repo.deleteFileProgress(filePath);
135
+ return { hashesDeleted };
136
+ }),
137
+ getStats: () => Effect.gen(function* () {
138
+ const totalHashes = yield* repo.countHashes();
139
+ const trackedFiles = yield* repo.countFiles();
140
+ return { totalHashes, trackedFiles };
141
+ }),
142
+ computeHash: hashContent
143
+ };
144
+ }));
145
+ //# sourceMappingURL=deduplication-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deduplication-service.js","sourceRoot":"","sources":["../../src/services/deduplication-service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import { Context, Effect, Layer } from "effect";
2
+ import { DependencyRepository } from "../repo/dep-repo.js";
3
+ import { TaskRepository } from "../repo/task-repo.js";
4
+ import { ValidationError, CircularDependencyError, TaskNotFoundError, DatabaseError } from "../errors.js";
5
+ import type { TaskId } from "@jamesaphoenix/tx-types";
6
+ declare const DependencyService_base: Context.TagClass<DependencyService, "DependencyService", {
7
+ readonly addBlocker: (taskId: TaskId, blockerId: TaskId) => Effect.Effect<void, ValidationError | CircularDependencyError | TaskNotFoundError | DatabaseError>;
8
+ readonly removeBlocker: (taskId: TaskId, blockerId: TaskId) => Effect.Effect<void, DatabaseError>;
9
+ }>;
10
+ export declare class DependencyService extends DependencyService_base {
11
+ }
12
+ export declare const DependencyServiceLive: Layer.Layer<DependencyService, never, TaskRepository | DependencyRepository>;
13
+ export {};
14
+ //# sourceMappingURL=dep-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dep-service.d.ts","sourceRoot":"","sources":["../../src/services/dep-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAA;AAC/C,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AACrD,OAAO,EAAE,eAAe,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AACzG,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAA;;yBAK5B,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,eAAe,GAAG,uBAAuB,GAAG,iBAAiB,GAAG,aAAa,CAAC;4BACtI,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,aAAa,CAAC;;AAJrG,qBAAa,iBAAkB,SAAQ,sBAMpC;CAAG;AAEN,eAAO,MAAM,qBAAqB,8EAqCjC,CAAA"}
@@ -0,0 +1,34 @@
1
+ import { Context, Effect, Layer } from "effect";
2
+ import { DependencyRepository } from "../repo/dep-repo.js";
3
+ import { TaskRepository } from "../repo/task-repo.js";
4
+ import { ValidationError, CircularDependencyError, TaskNotFoundError } from "../errors.js";
5
+ export class DependencyService extends Context.Tag("DependencyService")() {
6
+ }
7
+ export const DependencyServiceLive = Layer.effect(DependencyService, Effect.gen(function* () {
8
+ const depRepo = yield* DependencyRepository;
9
+ const taskRepo = yield* TaskRepository;
10
+ return {
11
+ addBlocker: (taskId, blockerId) => Effect.gen(function* () {
12
+ if (taskId === blockerId) {
13
+ return yield* Effect.fail(new ValidationError({ reason: "A task cannot block itself" }));
14
+ }
15
+ const task = yield* taskRepo.findById(taskId);
16
+ if (!task) {
17
+ return yield* Effect.fail(new TaskNotFoundError({ id: taskId }));
18
+ }
19
+ const blocker = yield* taskRepo.findById(blockerId);
20
+ if (!blocker) {
21
+ return yield* Effect.fail(new TaskNotFoundError({ id: blockerId }));
22
+ }
23
+ // Cycle detection: check if there's already a path from taskId to blockerId
24
+ // (i.e., blockerId is transitively blocked by taskId)
25
+ const wouldCycle = yield* depRepo.hasPath(blockerId, taskId);
26
+ if (wouldCycle) {
27
+ return yield* Effect.fail(new CircularDependencyError({ taskId, blockerId }));
28
+ }
29
+ yield* depRepo.insert(blockerId, taskId);
30
+ }),
31
+ removeBlocker: (taskId, blockerId) => depRepo.remove(blockerId, taskId)
32
+ };
33
+ }));
34
+ //# sourceMappingURL=dep-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dep-service.js","sourceRoot":"","sources":["../../src/services/dep-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAA;AAC/C,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AACrD,OAAO,EAAE,eAAe,EAAE,uBAAuB,EAAE,iBAAiB,EAAiB,MAAM,cAAc,CAAA;AAGzG,MAAM,OAAO,iBAAkB,SAAQ,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,EAMpE;CAAG;AAEN,MAAM,CAAC,MAAM,qBAAqB,GAAG,KAAK,CAAC,MAAM,CAC/C,iBAAiB,EACjB,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,oBAAoB,CAAA;IAC3C,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,cAAc,CAAA;IAEtC,OAAO;QACL,UAAU,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,CAChC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;YAClB,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;gBACzB,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,eAAe,CAAC,EAAE,MAAM,EAAE,4BAA4B,EAAE,CAAC,CAAC,CAAA;YAC1F,CAAC;YAED,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAA;YAC7C,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,iBAAiB,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,CAAA;YAClE,CAAC;YAED,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAA;YACnD,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,iBAAiB,CAAC,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,CAAA;YACrE,CAAC;YAED,4EAA4E;YAC5E,sDAAsD;YACtD,MAAM,UAAU,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,EAAE,MAAM,CAAC,CAAA;YAC5D,IAAI,UAAU,EAAE,CAAC;gBACf,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,uBAAuB,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC,CAAA;YAC/E,CAAC;YAED,KAAK,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,CAAA;QAC1C,CAAC,CAAC;QAEJ,aAAa,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,CACnC,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC;KACpC,CAAA;AACH,CAAC,CAAC,CACH,CAAA"}
@@ -0,0 +1,46 @@
1
+ import { Context, Effect, Layer } from "effect";
2
+ import type { LearningWithScore } from "@jamesaphoenix/tx-types";
3
+ declare const DiversifierService_base: Context.TagClass<DiversifierService, "DiversifierService", {
4
+ /**
5
+ * Apply MMR diversification to scored candidates.
6
+ *
7
+ * @param candidates - Learnings with scores, sorted by relevance (highest first)
8
+ * @param limit - Maximum number of results to return
9
+ * @param lambda - Balance between relevance (1.0) and diversity (0.0), default 0.7
10
+ * @returns Diversified list of learnings, maintaining score order within diversity constraints
11
+ */
12
+ readonly mmrDiversify: (candidates: readonly LearningWithScore[], limit: number, lambda?: number) => Effect.Effect<readonly LearningWithScore[]>;
13
+ }>;
14
+ /**
15
+ * DiversifierService provides Maximal Marginal Relevance (MMR) diversification
16
+ * for search results to balance relevance and diversity.
17
+ *
18
+ * MMR iteratively selects items that are both relevant to the query AND
19
+ * dissimilar to already-selected items, preventing redundant results.
20
+ *
21
+ * Design: PRD-010 specifies diversity as a key quality metric for learning retrieval.
22
+ * The service also applies category-based limits to prevent over-representation.
23
+ */
24
+ export declare class DiversifierService extends DiversifierService_base {
25
+ }
26
+ /**
27
+ * Noop implementation - returns candidates unchanged (just truncated to limit).
28
+ * Used when diversification is not needed or for testing.
29
+ */
30
+ export declare const DiversifierServiceNoop: Layer.Layer<DiversifierService, never, never>;
31
+ /**
32
+ * Live implementation with full MMR algorithm and category limits.
33
+ *
34
+ * Algorithm:
35
+ * 1. If no embeddings available, fallback to relevance-only ordering with category limits
36
+ * 2. Start with the highest-relevance item
37
+ * 3. Iteratively select the item with highest MMR score that doesn't violate category limits
38
+ * 4. Repeat until limit reached or no candidates remain
39
+ */
40
+ export declare const DiversifierServiceLive: Layer.Layer<DiversifierService, never, never>;
41
+ /**
42
+ * Auto layer - uses Live implementation since MMR has no external dependencies.
43
+ */
44
+ export declare const DiversifierServiceAuto: Layer.Layer<DiversifierService, never, never>;
45
+ export {};
46
+ //# sourceMappingURL=diversifier-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diversifier-service.d.ts","sourceRoot":"","sources":["../../src/services/diversifier-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAA;AAC/C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;;IAgB5D;;;;;;;OAOG;2BACoB,CACrB,UAAU,EAAE,SAAS,iBAAiB,EAAE,EACxC,KAAK,EAAE,MAAM,EACb,MAAM,CAAC,EAAE,MAAM,KACZ,MAAM,CAAC,MAAM,CAAC,SAAS,iBAAiB,EAAE,CAAC;;AAzBpD;;;;;;;;;GASG;AACH,qBAAa,kBAAmB,SAAQ,uBAiBrC;CAAG;AAmGN;;;GAGG;AACH,eAAO,MAAM,sBAAsB,+CAMlC,CAAA;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,sBAAsB,+CAyElC,CAAA;AA4CD;;GAEG;AACH,eAAO,MAAM,sBAAsB,+CAAyB,CAAA"}
@@ -0,0 +1,197 @@
1
+ import { Context, Effect, Layer } from "effect";
2
+ import { cosineSimilarity } from "../utils/math.js";
3
+ /**
4
+ * DiversifierService provides Maximal Marginal Relevance (MMR) diversification
5
+ * for search results to balance relevance and diversity.
6
+ *
7
+ * MMR iteratively selects items that are both relevant to the query AND
8
+ * dissimilar to already-selected items, preventing redundant results.
9
+ *
10
+ * Design: PRD-010 specifies diversity as a key quality metric for learning retrieval.
11
+ * The service also applies category-based limits to prevent over-representation.
12
+ */
13
+ export class DiversifierService extends Context.Tag("DiversifierService")() {
14
+ }
15
+ /**
16
+ * Default lambda value for MMR.
17
+ * 0.7 weights relevance higher than diversity (70/30 split).
18
+ * Higher values = more relevant results, lower values = more diverse.
19
+ */
20
+ const DEFAULT_LAMBDA = 0.7;
21
+ /**
22
+ * Maximum items from the same category allowed in top N results.
23
+ * Per task spec: max 2 results from same category in top 5.
24
+ */
25
+ const CATEGORY_LIMIT_TOP_N = 5;
26
+ const CATEGORY_MAX_PER_TOP_N = 2;
27
+ /**
28
+ * Calculate maximum cosine similarity between a candidate and selected items.
29
+ * Returns 0 if candidate has no embedding or selected set is empty.
30
+ */
31
+ const maxSimilarityToSelected = (candidate, selected) => {
32
+ // No embedding means we can't compute similarity
33
+ if (!candidate.embedding) {
34
+ return 0;
35
+ }
36
+ // No selected items yet
37
+ if (selected.length === 0) {
38
+ return 0;
39
+ }
40
+ let maxSim = -Infinity;
41
+ for (const item of selected) {
42
+ // Skip items without embeddings
43
+ if (!item.embedding) {
44
+ continue;
45
+ }
46
+ const sim = cosineSimilarity(candidate.embedding, item.embedding);
47
+ if (sim > maxSim) {
48
+ maxSim = sim;
49
+ }
50
+ }
51
+ // If no valid comparisons were made, return 0
52
+ return maxSim === -Infinity ? 0 : maxSim;
53
+ };
54
+ /**
55
+ * Calculate MMR score for a candidate.
56
+ *
57
+ * Formula: λ * relevance(item) - (1-λ) * max_similarity(item, selected_items)
58
+ *
59
+ * Higher lambda means more weight on relevance.
60
+ * Lower lambda means more weight on diversity (dissimilarity).
61
+ */
62
+ const mmrScore = (candidate, selected, lambda) => {
63
+ const relevance = candidate.relevanceScore;
64
+ const maxSim = maxSimilarityToSelected(candidate, selected);
65
+ return lambda * relevance - (1 - lambda) * maxSim;
66
+ };
67
+ /**
68
+ * Check if adding a candidate would violate category limits in top N.
69
+ *
70
+ * Per spec: max 2 results from same category in top 5.
71
+ * This prevents over-representation of any single category.
72
+ */
73
+ const wouldViolateCategoryLimit = (candidate, selected, topN = CATEGORY_LIMIT_TOP_N, maxPerTopN = CATEGORY_MAX_PER_TOP_N) => {
74
+ // No category = no limit
75
+ if (!candidate.category) {
76
+ return false;
77
+ }
78
+ // Only check if we're still in the top N range
79
+ if (selected.length >= topN) {
80
+ return false;
81
+ }
82
+ // Count items with the same category in current selection
83
+ const categoryCount = selected.filter(item => item.category === candidate.category).length;
84
+ return categoryCount >= maxPerTopN;
85
+ };
86
+ /**
87
+ * Noop implementation - returns candidates unchanged (just truncated to limit).
88
+ * Used when diversification is not needed or for testing.
89
+ */
90
+ export const DiversifierServiceNoop = Layer.succeed(DiversifierService, {
91
+ mmrDiversify: (candidates, limit, _lambda) => Effect.succeed(candidates.slice(0, limit))
92
+ });
93
+ /**
94
+ * Live implementation with full MMR algorithm and category limits.
95
+ *
96
+ * Algorithm:
97
+ * 1. If no embeddings available, fallback to relevance-only ordering with category limits
98
+ * 2. Start with the highest-relevance item
99
+ * 3. Iteratively select the item with highest MMR score that doesn't violate category limits
100
+ * 4. Repeat until limit reached or no candidates remain
101
+ */
102
+ export const DiversifierServiceLive = Layer.succeed(DiversifierService, {
103
+ mmrDiversify: (candidates, limit, lambda = DEFAULT_LAMBDA) => Effect.sync(() => {
104
+ // Edge case: empty candidates
105
+ if (candidates.length === 0) {
106
+ return [];
107
+ }
108
+ // Edge case: limit <= 0
109
+ if (limit <= 0) {
110
+ return [];
111
+ }
112
+ // Edge case: only one candidate or limit is 1
113
+ if (candidates.length === 1 || limit === 1) {
114
+ return candidates.slice(0, 1);
115
+ }
116
+ // Check if any candidates have embeddings
117
+ const hasEmbeddings = candidates.some(c => c.embedding !== null);
118
+ // Fallback: if no embeddings, just apply category limits to relevance-sorted list
119
+ if (!hasEmbeddings) {
120
+ return applyFallbackWithCategoryLimits(candidates, limit);
121
+ }
122
+ // Full MMR algorithm
123
+ const selected = [];
124
+ const remaining = new Set(candidates);
125
+ while (selected.length < limit && remaining.size > 0) {
126
+ let bestCandidate = null;
127
+ let bestScore = -Infinity;
128
+ for (const candidate of remaining) {
129
+ // Skip if would violate category limit
130
+ if (wouldViolateCategoryLimit(candidate, selected)) {
131
+ continue;
132
+ }
133
+ const score = mmrScore(candidate, selected, lambda);
134
+ if (score > bestScore) {
135
+ bestScore = score;
136
+ bestCandidate = candidate;
137
+ }
138
+ }
139
+ // If no valid candidate found (all remaining violate category limits),
140
+ // try to find any candidate without category limit check
141
+ if (!bestCandidate) {
142
+ for (const candidate of remaining) {
143
+ const score = mmrScore(candidate, selected, lambda);
144
+ if (score > bestScore) {
145
+ bestScore = score;
146
+ bestCandidate = candidate;
147
+ }
148
+ }
149
+ }
150
+ // Still no candidate? We're done
151
+ if (!bestCandidate) {
152
+ break;
153
+ }
154
+ selected.push(bestCandidate);
155
+ remaining.delete(bestCandidate);
156
+ }
157
+ return selected;
158
+ })
159
+ });
160
+ /**
161
+ * Fallback diversification when no embeddings are available.
162
+ * Applies category limits to the relevance-sorted list.
163
+ *
164
+ * Returns candidates in original order, skipping items that would
165
+ * violate the category limit in top N.
166
+ */
167
+ const applyFallbackWithCategoryLimits = (candidates, limit) => {
168
+ const selected = [];
169
+ for (const candidate of candidates) {
170
+ if (selected.length >= limit) {
171
+ break;
172
+ }
173
+ // Skip if would violate category limit
174
+ if (wouldViolateCategoryLimit(candidate, selected)) {
175
+ continue;
176
+ }
177
+ selected.push(candidate);
178
+ }
179
+ // If we didn't get enough due to category limits, fill with remaining
180
+ if (selected.length < limit) {
181
+ const selectedSet = new Set(selected);
182
+ for (const candidate of candidates) {
183
+ if (selected.length >= limit) {
184
+ break;
185
+ }
186
+ if (!selectedSet.has(candidate)) {
187
+ selected.push(candidate);
188
+ }
189
+ }
190
+ }
191
+ return selected;
192
+ };
193
+ /**
194
+ * Auto layer - uses Live implementation since MMR has no external dependencies.
195
+ */
196
+ export const DiversifierServiceAuto = DiversifierServiceLive;
197
+ //# sourceMappingURL=diversifier-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diversifier-service.js","sourceRoot":"","sources":["../../src/services/diversifier-service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,78 @@
1
+ import { Context, Effect, Layer } from "effect";
2
+ import { EdgeRepository } from "../repo/edge-repo.js";
3
+ import { DatabaseError, EdgeNotFoundError, ValidationError } from "../errors.js";
4
+ import type { Edge, EdgeType, NodeType, CreateEdgeInput, UpdateEdgeInput, NeighborNode } from "@jamesaphoenix/tx-types";
5
+ /** Extended neighbor with depth information */
6
+ export interface NeighborWithDepth extends NeighborNode {
7
+ readonly depth: number;
8
+ }
9
+ /** Options for multi-hop neighbor finding */
10
+ export interface FindNeighborsOptions {
11
+ /** Maximum depth to traverse (default: 1) */
12
+ readonly depth?: number;
13
+ /** Direction of traversal */
14
+ readonly direction?: "outgoing" | "incoming" | "both";
15
+ /** Filter by edge types */
16
+ readonly edgeTypes?: readonly EdgeType[];
17
+ /** Include the path of edges that led to this neighbor */
18
+ readonly includePath?: boolean;
19
+ }
20
+ /** Neighbor with path information */
21
+ export interface NeighborWithPath extends NeighborWithDepth {
22
+ readonly path: readonly Edge[];
23
+ }
24
+ declare const EdgeService_base: Context.TagClass<EdgeService, "EdgeService", {
25
+ /**
26
+ * Create an edge between two nodes.
27
+ * Validates edge type, node types, and ensures weight is in [0, 1].
28
+ */
29
+ readonly createEdge: (input: CreateEdgeInput) => Effect.Effect<Edge, ValidationError | DatabaseError>;
30
+ /**
31
+ * Find neighbors of a node with optional multi-hop traversal.
32
+ * Supports depth, direction, and edge type filtering.
33
+ */
34
+ readonly findNeighbors: (nodeType: NodeType, nodeId: string, options?: FindNeighborsOptions) => Effect.Effect<readonly NeighborWithDepth[], DatabaseError>;
35
+ /**
36
+ * Find a path between two nodes.
37
+ * Returns the sequence of edges, or null if no path exists.
38
+ */
39
+ readonly findPath: (fromType: NodeType, fromId: string, toType: NodeType, toId: string, maxDepth?: number) => Effect.Effect<readonly Edge[] | null, DatabaseError>;
40
+ /**
41
+ * Invalidate (soft delete) an edge.
42
+ */
43
+ readonly invalidateEdge: (id: number) => Effect.Effect<boolean, EdgeNotFoundError | DatabaseError>;
44
+ /**
45
+ * Get an edge by ID.
46
+ */
47
+ readonly get: (id: number) => Effect.Effect<Edge, EdgeNotFoundError | DatabaseError>;
48
+ /**
49
+ * Update an edge's weight or metadata.
50
+ */
51
+ readonly update: (id: number, input: UpdateEdgeInput) => Effect.Effect<Edge, EdgeNotFoundError | ValidationError | DatabaseError>;
52
+ /**
53
+ * Find all edges of a specific type.
54
+ */
55
+ readonly findByType: (edgeType: EdgeType) => Effect.Effect<readonly Edge[], ValidationError | DatabaseError>;
56
+ /**
57
+ * Find all edges from a source node.
58
+ */
59
+ readonly findFromSource: (sourceType: NodeType, sourceId: string) => Effect.Effect<readonly Edge[], DatabaseError>;
60
+ /**
61
+ * Find all edges from multiple source nodes in a single batch query.
62
+ * Eliminates N+1 queries when fetching edges for multiple nodes.
63
+ */
64
+ readonly findFromMultipleSources: (sourceType: NodeType, sourceIds: readonly string[]) => Effect.Effect<ReadonlyMap<string, readonly Edge[]>, DatabaseError>;
65
+ /**
66
+ * Find all edges to a target node.
67
+ */
68
+ readonly findToTarget: (targetType: NodeType, targetId: string) => Effect.Effect<readonly Edge[], DatabaseError>;
69
+ /**
70
+ * Count edges by type.
71
+ */
72
+ readonly countByType: () => Effect.Effect<Map<EdgeType, number>, DatabaseError>;
73
+ }>;
74
+ export declare class EdgeService extends EdgeService_base {
75
+ }
76
+ export declare const EdgeServiceLive: Layer.Layer<EdgeService, never, EdgeRepository>;
77
+ export {};
78
+ //# sourceMappingURL=edge-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edge-service.d.ts","sourceRoot":"","sources":["../../src/services/edge-service.ts"],"names":[],"mappings":"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"}