@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,203 @@
1
+ /**
2
+ * OrchestratorService - PRD-018
3
+ *
4
+ * Manages orchestrator lifecycle and reconciliation loop.
5
+ * Uses Effect-TS patterns per DD-002.
6
+ */
7
+ import { Context, Effect, Layer } from "effect";
8
+ import { OrchestratorStateRepository } from "../repo/orchestrator-state-repo.js";
9
+ import { TaskRepository } from "../repo/task-repo.js";
10
+ import { ClaimRepository } from "../repo/claim-repo.js";
11
+ import { WorkerService } from "./worker-service.js";
12
+ import { ClaimService } from "./claim-service.js";
13
+ import { OrchestratorError } from "../errors.js";
14
+ /**
15
+ * Default orchestrator configuration values.
16
+ */
17
+ const DEFAULT_CONFIG = {
18
+ workerPoolSize: 1,
19
+ heartbeatIntervalSeconds: 30,
20
+ leaseDurationMinutes: 30,
21
+ reconcileIntervalSeconds: 60,
22
+ shutdownTimeoutSeconds: 300,
23
+ maxClaimRenewals: 10
24
+ };
25
+ export class OrchestratorService extends Context.Tag("OrchestratorService")() {
26
+ }
27
+ export const OrchestratorServiceLive = Layer.effect(OrchestratorService, Effect.gen(function* () {
28
+ const stateRepo = yield* OrchestratorStateRepository;
29
+ const workerService = yield* WorkerService;
30
+ const claimService = yield* ClaimService;
31
+ const taskRepo = yield* TaskRepository;
32
+ const claimRepo = yield* ClaimRepository;
33
+ return {
34
+ start: (config) => Effect.gen(function* () {
35
+ const currentState = yield* stateRepo.get();
36
+ // Check if already running
37
+ if (currentState.status === "running") {
38
+ return yield* Effect.fail(new OrchestratorError({
39
+ code: "ALREADY_RUNNING",
40
+ reason: "Orchestrator is already running"
41
+ }));
42
+ }
43
+ // Check if in an incompatible state
44
+ if (currentState.status === "stopping") {
45
+ return yield* Effect.fail(new OrchestratorError({
46
+ code: "INVALID_STATE",
47
+ reason: "Orchestrator is currently stopping"
48
+ }));
49
+ }
50
+ const mergedConfig = { ...DEFAULT_CONFIG, ...config };
51
+ // Transition to starting
52
+ yield* stateRepo.update({
53
+ status: "starting",
54
+ pid: process.pid,
55
+ startedAt: new Date(),
56
+ workerPoolSize: mergedConfig.workerPoolSize,
57
+ reconcileIntervalSeconds: mergedConfig.reconcileIntervalSeconds,
58
+ heartbeatIntervalSeconds: mergedConfig.heartbeatIntervalSeconds,
59
+ leaseDurationMinutes: mergedConfig.leaseDurationMinutes,
60
+ metadata: {
61
+ maxClaimRenewals: mergedConfig.maxClaimRenewals,
62
+ shutdownTimeoutSeconds: mergedConfig.shutdownTimeoutSeconds
63
+ }
64
+ });
65
+ // Transition to running
66
+ yield* stateRepo.update({ status: "running" });
67
+ yield* Effect.log(`Orchestrator started with pool size ${mergedConfig.workerPoolSize}`);
68
+ }),
69
+ stop: (graceful) => Effect.gen(function* () {
70
+ const currentState = yield* stateRepo.get();
71
+ // Check if not running
72
+ if (currentState.status !== "running") {
73
+ return yield* Effect.fail(new OrchestratorError({
74
+ code: "NOT_RUNNING",
75
+ reason: "Orchestrator is not running"
76
+ }));
77
+ }
78
+ // Transition to stopping
79
+ yield* stateRepo.update({ status: "stopping" });
80
+ yield* Effect.log("Orchestrator stopping...");
81
+ if (graceful) {
82
+ // Get all active workers
83
+ const workers = yield* workerService.list({
84
+ status: ["idle", "busy", "starting"]
85
+ });
86
+ // Signal workers to stop
87
+ for (const worker of workers) {
88
+ yield* workerService.updateStatus(worker.id, "stopping").pipe(Effect.catchAll(() => Effect.void));
89
+ }
90
+ // Note: In a full implementation, we would wait for workers
91
+ // to finish their current tasks with a timeout.
92
+ // For Phase 1, we just mark them as stopping.
93
+ yield* Effect.log(`Signaled ${workers.length} worker(s) to stop`);
94
+ }
95
+ // Mark any remaining active workers as dead
96
+ const remainingWorkers = yield* workerService.list({
97
+ status: ["idle", "busy", "starting", "stopping"]
98
+ });
99
+ for (const worker of remainingWorkers) {
100
+ yield* workerService.markDead(worker.id).pipe(Effect.catchAll(() => Effect.void));
101
+ }
102
+ // Transition to stopped
103
+ yield* stateRepo.update({
104
+ status: "stopped",
105
+ pid: null
106
+ });
107
+ yield* Effect.log("Orchestrator stopped");
108
+ }),
109
+ status: () => stateRepo.get(),
110
+ reconcile: () => Effect.gen(function* () {
111
+ const startTime = Date.now();
112
+ let deadWorkersFound = 0;
113
+ let expiredClaimsReleased = 0;
114
+ let orphanedTasksRecovered = 0;
115
+ let staleStatesFixed = 0;
116
+ // 1. Detect dead workers (missed 2+ heartbeats)
117
+ const deadWorkers = yield* workerService.findDead({
118
+ missedHeartbeats: 2
119
+ });
120
+ for (const worker of deadWorkers) {
121
+ yield* workerService.markDead(worker.id).pipe(Effect.catchAll(() => Effect.void));
122
+ // Release any claims held by this dead worker
123
+ yield* claimService.releaseByWorker(worker.id).pipe(Effect.catchAll(() => Effect.succeed(0)));
124
+ deadWorkersFound++;
125
+ }
126
+ // 2. Expire stale claims (past lease expiration)
127
+ const expiredClaims = yield* claimService.getExpired();
128
+ for (const claim of expiredClaims) {
129
+ yield* claimService.expire(claim.id).pipe(Effect.catchAll(() => Effect.void));
130
+ // Return task to ready state if it was active
131
+ const task = yield* taskRepo.findById(claim.taskId);
132
+ if (task && task.status === "active") {
133
+ const now = new Date();
134
+ yield* taskRepo.update({
135
+ ...task,
136
+ status: "ready",
137
+ updatedAt: now
138
+ });
139
+ }
140
+ expiredClaimsReleased++;
141
+ }
142
+ // 3. Find orphaned tasks (status='active' but no active claim)
143
+ const activeTasks = yield* taskRepo.findAll({ status: "active" });
144
+ for (const task of activeTasks) {
145
+ const activeClaim = yield* claimRepo.findActiveByTaskId(task.id);
146
+ if (!activeClaim) {
147
+ // Task is orphaned - return to ready state
148
+ const now = new Date();
149
+ yield* taskRepo.update({
150
+ ...task,
151
+ status: "ready",
152
+ updatedAt: now
153
+ });
154
+ orphanedTasksRecovered++;
155
+ }
156
+ }
157
+ // 4. Fix workers marked busy but with no current_task_id
158
+ const busyWorkers = yield* workerService.list({ status: ["busy"] });
159
+ for (const worker of busyWorkers) {
160
+ if (worker.currentTaskId === null) {
161
+ yield* workerService.updateStatus(worker.id, "idle").pipe(Effect.catchAll(() => Effect.void));
162
+ staleStatesFixed++;
163
+ }
164
+ }
165
+ // 5. Fix workers with current_task_id but task is not active
166
+ for (const worker of busyWorkers) {
167
+ if (worker.currentTaskId) {
168
+ const task = yield* taskRepo.findById(worker.currentTaskId);
169
+ if (!task || task.status !== "active") {
170
+ yield* workerService.updateStatus(worker.id, "idle").pipe(Effect.catchAll(() => Effect.void));
171
+ staleStatesFixed++;
172
+ }
173
+ }
174
+ }
175
+ const reconcileTime = Date.now() - startTime;
176
+ // Update last reconcile timestamp
177
+ yield* stateRepo.update({
178
+ lastReconcileAt: new Date()
179
+ });
180
+ // Log if any issues were found
181
+ if (deadWorkersFound > 0 ||
182
+ expiredClaimsReleased > 0 ||
183
+ orphanedTasksRecovered > 0 ||
184
+ staleStatesFixed > 0) {
185
+ yield* Effect.log(`Reconciliation: ${deadWorkersFound} dead workers, ` +
186
+ `${expiredClaimsReleased} expired claims, ` +
187
+ `${orphanedTasksRecovered} orphaned tasks, ` +
188
+ `${staleStatesFixed} stale states fixed ` +
189
+ `(${reconcileTime}ms)`);
190
+ }
191
+ // Build and return the result
192
+ const result = {
193
+ deadWorkersFound,
194
+ expiredClaimsReleased,
195
+ orphanedTasksRecovered,
196
+ staleStatesFixed,
197
+ reconcileTime
198
+ };
199
+ return result;
200
+ })
201
+ };
202
+ }));
203
+ //# sourceMappingURL=orchestrator-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orchestrator-service.js","sourceRoot":"","sources":["../../src/services/orchestrator-service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,67 @@
1
+ import { Context, Effect, Layer } from "effect";
2
+ import { CandidateNotFoundError, DatabaseError, ValidationError } from "../errors.js";
3
+ import { CandidateRepository } from "../repo/candidate-repo.js";
4
+ import { LearningService } from "./learning-service.js";
5
+ import { EdgeService } from "./edge-service.js";
6
+ import type { LearningCandidate, CandidateFilter, CandidateId, Learning } from "@jamesaphoenix/tx-types";
7
+ /**
8
+ * Result of promoting a candidate to the learnings table.
9
+ */
10
+ export interface PromotionResult {
11
+ /** The updated candidate with promoted status */
12
+ readonly candidate: LearningCandidate;
13
+ /** The newly created learning */
14
+ readonly learning: Learning;
15
+ }
16
+ /**
17
+ * Result of auto-promotion batch operation.
18
+ */
19
+ export interface AutoPromoteResult {
20
+ /** Number of candidates auto-promoted */
21
+ readonly promoted: number;
22
+ /** Number of candidates skipped (already processed or low confidence) */
23
+ readonly skipped: number;
24
+ /** Number of candidates that failed to promote */
25
+ readonly failed: number;
26
+ /** IDs of promoted learnings */
27
+ readonly learningIds: readonly number[];
28
+ }
29
+ declare const PromotionService_base: Context.TagClass<PromotionService, "PromotionService", {
30
+ /**
31
+ * List candidates matching the given filter.
32
+ * Supports filtering by status, confidence, category, and pagination.
33
+ */
34
+ readonly list: (filter: CandidateFilter) => Effect.Effect<readonly LearningCandidate[], DatabaseError>;
35
+ /**
36
+ * Promote a candidate to the learnings table.
37
+ * Creates a new learning and updates the candidate status to 'promoted'.
38
+ */
39
+ readonly promote: (id: CandidateId) => Effect.Effect<PromotionResult, CandidateNotFoundError | DatabaseError>;
40
+ /**
41
+ * Reject a candidate with a reason.
42
+ * Updates the candidate status to 'rejected' and stores the rejection reason.
43
+ */
44
+ readonly reject: (id: CandidateId, reason: string) => Effect.Effect<LearningCandidate, CandidateNotFoundError | ValidationError | DatabaseError>;
45
+ /**
46
+ * Auto-promote high-confidence candidates.
47
+ * Promotes all pending candidates with 'high' confidence level.
48
+ * Uses 'auto' as the reviewer identifier.
49
+ */
50
+ readonly autoPromote: () => Effect.Effect<AutoPromoteResult, DatabaseError>;
51
+ /**
52
+ * Get all pending candidates awaiting review.
53
+ * Convenience method equivalent to list({ status: 'pending' }).
54
+ */
55
+ readonly getPending: () => Effect.Effect<readonly LearningCandidate[], DatabaseError>;
56
+ }>;
57
+ /**
58
+ * PromotionService manages the lifecycle of learning candidates,
59
+ * including listing, promoting to learnings, rejecting, and auto-promotion.
60
+ *
61
+ * @see PRD-015 for the knowledge promotion pipeline
62
+ */
63
+ export declare class PromotionService extends PromotionService_base {
64
+ }
65
+ export declare const PromotionServiceLive: Layer.Layer<PromotionService, never, CandidateRepository | EdgeService | LearningService>;
66
+ export {};
67
+ //# sourceMappingURL=promotion-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"promotion-service.d.ts","sourceRoot":"","sources":["../../src/services/promotion-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAA;AAC/C,OAAO,EAAE,sBAAsB,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AACrF,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAA;AAC/D,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC/C,OAAO,KAAK,EACV,iBAAiB,EACjB,eAAe,EACf,WAAW,EACX,QAAQ,EACT,MAAM,yBAAyB,CAAA;AAEhC;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,iDAAiD;IACjD,QAAQ,CAAC,SAAS,EAAE,iBAAiB,CAAA;IACrC,iCAAiC;IACjC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAA;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,yCAAyC;IACzC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,yEAAyE;IACzE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,kDAAkD;IAClD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,gCAAgC;IAChC,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAA;CACxC;;IAWG;;;OAGG;mBACY,CAAC,MAAM,EAAE,eAAe,KAAK,MAAM,CAAC,MAAM,CAAC,SAAS,iBAAiB,EAAE,EAAE,aAAa,CAAC;IAEtG;;;OAGG;sBACe,CAAC,EAAE,EAAE,WAAW,KAAK,MAAM,CAAC,MAAM,CAAC,eAAe,EAAE,sBAAsB,GAAG,aAAa,CAAC;IAE7G;;;OAGG;qBACc,CAAC,EAAE,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,iBAAiB,EAAE,sBAAsB,GAAG,eAAe,GAAG,aAAa,CAAC;IAEhJ;;;;OAIG;0BACmB,MAAM,MAAM,CAAC,MAAM,CAAC,iBAAiB,EAAE,aAAa,CAAC;IAE3E;;;OAGG;yBACkB,MAAM,MAAM,CAAC,MAAM,CAAC,SAAS,iBAAiB,EAAE,EAAE,aAAa,CAAC;;AAtCzF;;;;;GAKG;AACH,qBAAa,gBAAiB,SAAQ,qBAkCnC;CAAG;AAKN,eAAO,MAAM,oBAAoB,2FAiLhC,CAAA"}
@@ -0,0 +1,151 @@
1
+ import { Context, Effect, Layer } from "effect";
2
+ import { CandidateNotFoundError, DatabaseError, ValidationError } from "../errors.js";
3
+ import { CandidateRepository } from "../repo/candidate-repo.js";
4
+ import { LearningService } from "./learning-service.js";
5
+ import { EdgeService } from "./edge-service.js";
6
+ /**
7
+ * PromotionService manages the lifecycle of learning candidates,
8
+ * including listing, promoting to learnings, rejecting, and auto-promotion.
9
+ *
10
+ * @see PRD-015 for the knowledge promotion pipeline
11
+ */
12
+ export class PromotionService extends Context.Tag("PromotionService")() {
13
+ }
14
+ /** Duplicate detection threshold for auto-promotion (0.85 = high similarity) */
15
+ const DUPLICATE_MIN_SCORE = 0.85;
16
+ export const PromotionServiceLive = Layer.effect(PromotionService, Effect.gen(function* () {
17
+ const candidateRepo = yield* CandidateRepository;
18
+ const learningService = yield* LearningService;
19
+ const edgeService = yield* EdgeService;
20
+ /**
21
+ * Promote a single candidate with optional reviewer identifier.
22
+ * Internal helper shared by promote() and autoPromote().
23
+ */
24
+ const promoteCandidate = (candidate, reviewedBy) => Effect.gen(function* () {
25
+ // Create learning from candidate content
26
+ // Map ValidationError to DatabaseError (validation should not fail for existing candidates)
27
+ const learning = yield* Effect.mapError(learningService.create({
28
+ content: candidate.content,
29
+ sourceType: "run",
30
+ sourceRef: candidate.sourceRunId ?? candidate.sourceFile,
31
+ category: candidate.category
32
+ }), (error) => error._tag === "ValidationError"
33
+ ? new DatabaseError({ cause: error.reason })
34
+ : error);
35
+ // Create DERIVED_FROM edge for provenance tracking
36
+ // Link the learning back to its source (run or task)
37
+ if (candidate.sourceRunId) {
38
+ yield* Effect.catchAll(edgeService.createEdge({
39
+ edgeType: "DERIVED_FROM",
40
+ sourceType: "learning",
41
+ sourceId: String(learning.id),
42
+ targetType: "run",
43
+ targetId: candidate.sourceRunId,
44
+ weight: 1.0
45
+ }), () => Effect.void // Ignore edge creation failures
46
+ );
47
+ }
48
+ else if (candidate.sourceTaskId) {
49
+ yield* Effect.catchAll(edgeService.createEdge({
50
+ edgeType: "DERIVED_FROM",
51
+ sourceType: "learning",
52
+ sourceId: String(learning.id),
53
+ targetType: "task",
54
+ targetId: candidate.sourceTaskId,
55
+ weight: 1.0
56
+ }), () => Effect.void // Ignore edge creation failures
57
+ );
58
+ }
59
+ // Update candidate status to promoted
60
+ const now = new Date();
61
+ const updatedCandidate = yield* candidateRepo.update(candidate.id, {
62
+ status: "promoted",
63
+ reviewedAt: now,
64
+ reviewedBy,
65
+ promotedLearningId: learning.id
66
+ });
67
+ if (!updatedCandidate) {
68
+ return yield* Effect.fail(new CandidateNotFoundError({ id: candidate.id }));
69
+ }
70
+ return { candidate: updatedCandidate, learning };
71
+ });
72
+ return {
73
+ list: (filter) => candidateRepo.findByFilter(filter),
74
+ promote: (id) => Effect.gen(function* () {
75
+ const candidate = yield* candidateRepo.findById(id);
76
+ if (!candidate) {
77
+ return yield* Effect.fail(new CandidateNotFoundError({ id }));
78
+ }
79
+ return yield* promoteCandidate(candidate, "manual");
80
+ }),
81
+ reject: (id, reason) => Effect.gen(function* () {
82
+ // Validate reason is provided
83
+ if (!reason || reason.trim().length === 0) {
84
+ return yield* Effect.fail(new ValidationError({ reason: "Rejection reason is required" }));
85
+ }
86
+ const candidate = yield* candidateRepo.findById(id);
87
+ if (!candidate) {
88
+ return yield* Effect.fail(new CandidateNotFoundError({ id }));
89
+ }
90
+ const now = new Date();
91
+ const updatedCandidate = yield* candidateRepo.update(id, {
92
+ status: "rejected",
93
+ reviewedAt: now,
94
+ reviewedBy: "manual",
95
+ rejectionReason: reason.trim()
96
+ });
97
+ if (!updatedCandidate) {
98
+ return yield* Effect.fail(new CandidateNotFoundError({ id }));
99
+ }
100
+ return updatedCandidate;
101
+ }),
102
+ autoPromote: () => Effect.gen(function* () {
103
+ // Get all pending high-confidence candidates
104
+ const candidates = yield* candidateRepo.findByFilter({
105
+ status: "pending",
106
+ confidence: "high"
107
+ });
108
+ let promoted = 0;
109
+ let skipped = 0;
110
+ let failed = 0;
111
+ const learningIds = [];
112
+ for (const candidate of candidates) {
113
+ // Check for duplicates using semantic search
114
+ const searchResult = yield* Effect.catchAll(learningService.search({
115
+ query: candidate.content,
116
+ limit: 1,
117
+ minScore: DUPLICATE_MIN_SCORE
118
+ }), () => Effect.succeed([]));
119
+ // If a highly similar learning exists, skip this candidate
120
+ if (searchResult.length > 0) {
121
+ skipped++;
122
+ // Mark as merged with the existing learning
123
+ yield* Effect.catchAll(candidateRepo.update(candidate.id, {
124
+ status: "merged",
125
+ reviewedAt: new Date(),
126
+ reviewedBy: "auto",
127
+ promotedLearningId: searchResult[0].id
128
+ }), () => Effect.void);
129
+ continue;
130
+ }
131
+ // Promote the candidate
132
+ const result = yield* Effect.either(promoteCandidate(candidate, "auto"));
133
+ if (result._tag === "Right") {
134
+ promoted++;
135
+ learningIds.push(result.right.learning.id);
136
+ }
137
+ else {
138
+ failed++;
139
+ }
140
+ }
141
+ return {
142
+ promoted,
143
+ skipped,
144
+ failed,
145
+ learningIds
146
+ };
147
+ }),
148
+ getPending: () => candidateRepo.findByFilter({ status: "pending" })
149
+ };
150
+ }));
151
+ //# sourceMappingURL=promotion-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"promotion-service.js","sourceRoot":"","sources":["../../src/services/promotion-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAA;AAC/C,OAAO,EAAE,sBAAsB,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AACrF,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAA;AAC/D,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAgC/C;;;;;GAKG;AACH,MAAM,OAAO,gBAAiB,SAAQ,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,EAkClE;CAAG;AAEN,gFAAgF;AAChF,MAAM,mBAAmB,GAAG,IAAI,CAAA;AAEhC,MAAM,CAAC,MAAM,oBAAoB,GAAG,KAAK,CAAC,MAAM,CAC9C,gBAAgB,EAChB,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,MAAM,aAAa,GAAG,KAAK,CAAC,CAAC,mBAAmB,CAAA;IAChD,MAAM,eAAe,GAAG,KAAK,CAAC,CAAC,eAAe,CAAA;IAC9C,MAAM,WAAW,GAAG,KAAK,CAAC,CAAC,WAAW,CAAA;IAEtC;;;OAGG;IACH,MAAM,gBAAgB,GAAG,CACvB,SAA4B,EAC5B,UAAkB,EACsD,EAAE,CAC1E,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAClB,yCAAyC;QACzC,4FAA4F;QAC5F,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,CACrC,eAAe,CAAC,MAAM,CAAC;YACrB,OAAO,EAAE,SAAS,CAAC,OAAO;YAC1B,UAAU,EAAE,KAAK;YACjB,SAAS,EAAE,SAAS,CAAC,WAAW,IAAI,SAAS,CAAC,UAAU;YACxD,QAAQ,EAAE,SAAS,CAAC,QAAQ;SAC7B,CAAC,EACF,CAAC,KAAK,EAAE,EAAE,CACR,KAAK,CAAC,IAAI,KAAK,iBAAiB;YAC9B,CAAC,CAAC,IAAI,aAAa,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC;YAC5C,CAAC,CAAC,KAAK,CACZ,CAAA;QAED,mDAAmD;QACnD,qDAAqD;QACrD,IAAI,SAAS,CAAC,WAAW,EAAE,CAAC;YAC1B,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,CACpB,WAAW,CAAC,UAAU,CAAC;gBACrB,QAAQ,EAAE,cAAc;gBACxB,UAAU,EAAE,UAAU;gBACtB,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC7B,UAAU,EAAE,KAAK;gBACjB,QAAQ,EAAE,SAAS,CAAC,WAAW;gBAC/B,MAAM,EAAE,GAAG;aACZ,CAAC,EACF,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,gCAAgC;aACnD,CAAA;QACH,CAAC;aAAM,IAAI,SAAS,CAAC,YAAY,EAAE,CAAC;YAClC,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,CACpB,WAAW,CAAC,UAAU,CAAC;gBACrB,QAAQ,EAAE,cAAc;gBACxB,UAAU,EAAE,UAAU;gBACtB,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC7B,UAAU,EAAE,MAAM;gBAClB,QAAQ,EAAE,SAAS,CAAC,YAAY;gBAChC,MAAM,EAAE,GAAG;aACZ,CAAC,EACF,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,gCAAgC;aACnD,CAAA;QACH,CAAC;QAED,sCAAsC;QACtC,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAA;QACtB,MAAM,gBAAgB,GAAG,KAAK,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,EAAE;YACjE,MAAM,EAAE,UAAU;YAClB,UAAU,EAAE,GAAG;YACf,UAAU;YACV,kBAAkB,EAAE,QAAQ,CAAC,EAAE;SAChC,CAAC,CAAA;QAEF,IAAI,CAAC,gBAAgB,EAAE,CAAC;YACtB,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,sBAAsB,CAAC,EAAE,EAAE,EAAE,SAAS,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA;QAC7E,CAAC;QAED,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,QAAQ,EAAE,CAAA;IAClD,CAAC,CAAC,CAAA;IAEJ,OAAO;QACL,IAAI,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,aAAa,CAAC,YAAY,CAAC,MAAM,CAAC;QAEpD,OAAO,EAAE,CAAC,EAAE,EAAE,EAAE,CACd,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;YAClB,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,aAAa,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAA;YACnD,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,sBAAsB,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAA;YAC/D,CAAC;YAED,OAAO,KAAK,CAAC,CAAC,gBAAgB,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAA;QACrD,CAAC,CAAC;QAEJ,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,CACrB,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;YAClB,8BAA8B;YAC9B,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC1C,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,eAAe,CAAC,EAAE,MAAM,EAAE,8BAA8B,EAAE,CAAC,CAAC,CAAA;YAC5F,CAAC;YAED,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,aAAa,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAA;YACnD,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,sBAAsB,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAA;YAC/D,CAAC;YAED,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAA;YACtB,MAAM,gBAAgB,GAAG,KAAK,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,EAAE,EAAE;gBACvD,MAAM,EAAE,UAAU;gBAClB,UAAU,EAAE,GAAG;gBACf,UAAU,EAAE,QAAQ;gBACpB,eAAe,EAAE,MAAM,CAAC,IAAI,EAAE;aAC/B,CAAC,CAAA;YAEF,IAAI,CAAC,gBAAgB,EAAE,CAAC;gBACtB,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,sBAAsB,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAA;YAC/D,CAAC;YAED,OAAO,gBAAgB,CAAA;QACzB,CAAC,CAAC;QAEJ,WAAW,EAAE,GAAG,EAAE,CAChB,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;YAClB,6CAA6C;YAC7C,MAAM,UAAU,GAAG,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC;gBACnD,MAAM,EAAE,SAAS;gBACjB,UAAU,EAAE,MAAM;aACnB,CAAC,CAAA;YAEF,IAAI,QAAQ,GAAG,CAAC,CAAA;YAChB,IAAI,OAAO,GAAG,CAAC,CAAA;YACf,IAAI,MAAM,GAAG,CAAC,CAAA;YACd,MAAM,WAAW,GAAa,EAAE,CAAA;YAEhC,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;gBACnC,6CAA6C;gBAC7C,MAAM,YAAY,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,CACzC,eAAe,CAAC,MAAM,CAAC;oBACrB,KAAK,EAAE,SAAS,CAAC,OAAO;oBACxB,KAAK,EAAE,CAAC;oBACR,QAAQ,EAAE,mBAAmB;iBAC9B,CAAC,EACF,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,EAAW,CAAC,CAClC,CAAA;gBAED,2DAA2D;gBAC3D,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBAC5B,OAAO,EAAE,CAAA;oBACT,4CAA4C;oBAC5C,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,CACpB,aAAa,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,EAAE;wBACjC,MAAM,EAAE,QAAQ;wBAChB,UAAU,EAAE,IAAI,IAAI,EAAE;wBACtB,UAAU,EAAE,MAAM;wBAClB,kBAAkB,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE;qBACvC,CAAC,EACF,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,CAClB,CAAA;oBACD,SAAQ;gBACV,CAAC;gBAED,wBAAwB;gBACxB,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,CAAA;gBAExE,IAAI,MAAM,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;oBAC5B,QAAQ,EAAE,CAAA;oBACV,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAA;gBAC5C,CAAC;qBAAM,CAAC;oBACN,MAAM,EAAE,CAAA;gBACV,CAAC;YACH,CAAC;YAED,OAAO;gBACL,QAAQ;gBACR,OAAO;gBACP,MAAM;gBACN,WAAW;aACZ,CAAA;QACH,CAAC,CAAC;QAEJ,UAAU,EAAE,GAAG,EAAE,CAAC,aAAa,CAAC,YAAY,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;KACpE,CAAA;AACH,CAAC,CAAC,CACH,CAAA"}
@@ -0,0 +1,55 @@
1
+ import { Context, Effect, Layer } from "effect";
2
+ declare const QueryExpansionUnavailableError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => import("effect/Cause").YieldableError & {
3
+ readonly _tag: "QueryExpansionUnavailableError";
4
+ } & Readonly<A>;
5
+ /**
6
+ * Error indicating query expansion is unavailable.
7
+ */
8
+ export declare class QueryExpansionUnavailableError extends QueryExpansionUnavailableError_base<{
9
+ readonly reason: string;
10
+ }> {
11
+ get message(): string;
12
+ }
13
+ /**
14
+ * Result of query expansion.
15
+ */
16
+ export interface QueryExpansionResult {
17
+ /** Original query */
18
+ readonly original: string;
19
+ /** Expanded queries (includes original plus alternatives) */
20
+ readonly expanded: readonly string[];
21
+ /** Whether expansion was performed (false if using noop) */
22
+ readonly wasExpanded: boolean;
23
+ }
24
+ declare const QueryExpansionService_base: Context.TagClass<QueryExpansionService, "QueryExpansionService", {
25
+ /** Expand a search query into multiple alternative phrasings */
26
+ readonly expand: (query: string) => Effect.Effect<QueryExpansionResult, QueryExpansionUnavailableError>;
27
+ /** Check if query expansion is available */
28
+ readonly isAvailable: () => Effect.Effect<boolean>;
29
+ }>;
30
+ /**
31
+ * QueryExpansionService uses an LLM to generate alternative phrasings of search queries.
32
+ * This improves recall by searching for semantically equivalent but differently worded queries.
33
+ *
34
+ * Design: Following DD-006 patterns for LLM integration.
35
+ * The service gracefully degrades when ANTHROPIC_API_KEY is not set.
36
+ */
37
+ export declare class QueryExpansionService extends QueryExpansionService_base {
38
+ }
39
+ /**
40
+ * Noop implementation - returns original query only.
41
+ * Used when ANTHROPIC_API_KEY is not set or LLM features are disabled.
42
+ */
43
+ export declare const QueryExpansionServiceNoop: Layer.Layer<QueryExpansionService, never, never>;
44
+ /**
45
+ * Live implementation using Anthropic Claude API.
46
+ * Lazy-loads the SDK and caches the client.
47
+ */
48
+ export declare const QueryExpansionServiceLive: Layer.Layer<QueryExpansionService, QueryExpansionUnavailableError, never>;
49
+ /**
50
+ * Auto-detecting layer that uses Live if ANTHROPIC_API_KEY is set, Noop otherwise.
51
+ * This allows graceful degradation when the API key is not configured.
52
+ */
53
+ export declare const QueryExpansionServiceAuto: Layer.Layer<QueryExpansionService, QueryExpansionUnavailableError, never>;
54
+ export {};
55
+ //# sourceMappingURL=query-expansion-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query-expansion-service.d.ts","sourceRoot":"","sources":["../../src/services/query-expansion-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAkB,MAAM,QAAQ,CAAA;;;;AAG/D;;GAEG;AACH,qBAAa,8BAA+B,SAAQ,oCAAmD;IACrG,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CACxB,CAAC;IACA,IAAI,OAAO,WAEV;CACF;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,qBAAqB;IACrB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,6DAA6D;IAC7D,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAA;IACpC,4DAA4D;IAC5D,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAA;CAC9B;;IA2BG,gEAAgE;qBAC/C,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,oBAAoB,EAAE,8BAA8B,CAAC;IACvG,4CAA4C;0BACtB,MAAM,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC;;AAbtD;;;;;;GAMG;AACH,qBAAa,qBAAsB,SAAQ,0BAQxC;CAAG;AAyDN;;;GAGG;AACH,eAAO,MAAM,yBAAyB,kDAUrC,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,yBAAyB,2EAmFrC,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,yBAAyB,2EAUrC,CAAA"}