@jamesaphoenix/tx-core 0.4.2 → 0.4.4
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.
- package/README.md +480 -0
- package/dist/db.d.ts +28 -14
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +108 -14
- package/dist/db.js.map +1 -1
- package/dist/errors.d.ts +178 -34
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +119 -26
- package/dist/errors.js.map +1 -1
- package/dist/id.d.ts +10 -0
- package/dist/id.d.ts.map +1 -1
- package/dist/id.js +17 -1
- package/dist/id.js.map +1 -1
- package/dist/index.d.ts +15 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +62 -8
- package/dist/index.js.map +1 -1
- package/dist/layer.d.ts +23 -14
- package/dist/layer.d.ts.map +1 -1
- package/dist/layer.js +75 -76
- package/dist/layer.js.map +1 -1
- package/dist/mappers/attempt.d.ts +3 -1
- package/dist/mappers/attempt.d.ts.map +1 -1
- package/dist/mappers/attempt.js +23 -9
- package/dist/mappers/attempt.js.map +1 -1
- package/dist/mappers/claim.d.ts +1 -1
- package/dist/mappers/claim.d.ts.map +1 -1
- package/dist/mappers/claim.js +11 -4
- package/dist/mappers/claim.js.map +1 -1
- package/dist/mappers/deduplication.d.ts +13 -1
- package/dist/mappers/deduplication.d.ts.map +1 -1
- package/dist/mappers/deduplication.js +22 -3
- package/dist/mappers/deduplication.js.map +1 -1
- package/dist/mappers/doc.d.ts +24 -0
- package/dist/mappers/doc.d.ts.map +1 -0
- package/dist/mappers/doc.js +161 -0
- package/dist/mappers/doc.js.map +1 -0
- package/dist/mappers/file-learning.d.ts.map +1 -1
- package/dist/mappers/file-learning.js +2 -1
- package/dist/mappers/file-learning.js.map +1 -1
- package/dist/mappers/index.d.ts +6 -7
- package/dist/mappers/index.d.ts.map +1 -1
- package/dist/mappers/index.js +10 -12
- package/dist/mappers/index.js.map +1 -1
- package/dist/mappers/learning.d.ts +9 -1
- package/dist/mappers/learning.d.ts.map +1 -1
- package/dist/mappers/learning.js +94 -14
- package/dist/mappers/learning.js.map +1 -1
- package/dist/mappers/orchestrator-state.d.ts +1 -1
- package/dist/mappers/orchestrator-state.d.ts.map +1 -1
- package/dist/mappers/orchestrator-state.js +31 -5
- package/dist/mappers/orchestrator-state.js.map +1 -1
- package/dist/mappers/parse-date.d.ts +11 -0
- package/dist/mappers/parse-date.d.ts.map +1 -0
- package/dist/mappers/parse-date.js +18 -0
- package/dist/mappers/parse-date.js.map +1 -0
- package/dist/mappers/run.d.ts +14 -4
- package/dist/mappers/run.d.ts.map +1 -1
- package/dist/mappers/run.js +49 -18
- package/dist/mappers/run.js.map +1 -1
- package/dist/mappers/task.d.ts +5 -1
- package/dist/mappers/task.d.ts.map +1 -1
- package/dist/mappers/task.js +66 -16
- package/dist/mappers/task.js.map +1 -1
- package/dist/mappers/tracked-project.d.ts +3 -1
- package/dist/mappers/tracked-project.d.ts.map +1 -1
- package/dist/mappers/tracked-project.js +23 -9
- package/dist/mappers/tracked-project.js.map +1 -1
- package/dist/mappers/worker.d.ts +1 -1
- package/dist/mappers/worker.d.ts.map +1 -1
- package/dist/mappers/worker.js +44 -6
- package/dist/mappers/worker.js.map +1 -1
- package/dist/repo/attempt-repo.d.ts +2 -2
- package/dist/repo/attempt-repo.d.ts.map +1 -1
- package/dist/repo/attempt-repo.js +16 -6
- package/dist/repo/attempt-repo.js.map +1 -1
- package/dist/repo/claim-repo.d.ts +46 -2
- package/dist/repo/claim-repo.d.ts.map +1 -1
- package/dist/repo/claim-repo.js +113 -6
- package/dist/repo/claim-repo.js.map +1 -1
- package/dist/repo/deduplication-repo.d.ts +9 -1
- package/dist/repo/deduplication-repo.d.ts.map +1 -1
- package/dist/repo/deduplication-repo.js +46 -9
- package/dist/repo/deduplication-repo.js.map +1 -1
- package/dist/repo/dep-repo.d.ts +27 -3
- package/dist/repo/dep-repo.d.ts.map +1 -1
- package/dist/repo/dep-repo.js +166 -39
- package/dist/repo/dep-repo.js.map +1 -1
- package/dist/repo/doc-repo.d.ts +59 -0
- package/dist/repo/doc-repo.d.ts.map +1 -0
- package/dist/repo/doc-repo.js +276 -0
- package/dist/repo/doc-repo.js.map +1 -0
- package/dist/repo/file-learning-repo.d.ts +3 -3
- package/dist/repo/file-learning-repo.d.ts.map +1 -1
- package/dist/repo/file-learning-repo.js +19 -8
- package/dist/repo/file-learning-repo.js.map +1 -1
- package/dist/repo/index.d.ts +4 -6
- package/dist/repo/index.d.ts.map +1 -1
- package/dist/repo/index.js +3 -5
- package/dist/repo/index.js.map +1 -1
- package/dist/repo/learning-repo.d.ts +10 -3
- package/dist/repo/learning-repo.d.ts.map +1 -1
- package/dist/repo/learning-repo.js +68 -11
- package/dist/repo/learning-repo.js.map +1 -1
- package/dist/repo/orchestrator-state-repo.d.ts.map +1 -1
- package/dist/repo/orchestrator-state-repo.js +8 -1
- package/dist/repo/orchestrator-state-repo.js.map +1 -1
- package/dist/repo/run-repo.d.ts +3 -3
- package/dist/repo/run-repo.d.ts.map +1 -1
- package/dist/repo/run-repo.js +40 -19
- package/dist/repo/run-repo.js.map +1 -1
- package/dist/repo/task-repo.d.ts +14 -3
- package/dist/repo/task-repo.d.ts.map +1 -1
- package/dist/repo/task-repo.js +194 -20
- package/dist/repo/task-repo.js.map +1 -1
- package/dist/repo/tracked-project-repo.d.ts.map +1 -1
- package/dist/repo/tracked-project-repo.js +15 -1
- package/dist/repo/tracked-project-repo.js.map +1 -1
- package/dist/repo/worker-repo.d.ts +3 -2
- package/dist/repo/worker-repo.d.ts.map +1 -1
- package/dist/repo/worker-repo.js +54 -8
- package/dist/repo/worker-repo.js.map +1 -1
- package/dist/schemas/sync.js +2 -2
- package/dist/schemas/sync.js.map +1 -1
- package/dist/schemas/worker.d.ts +1 -0
- package/dist/schemas/worker.d.ts.map +1 -1
- package/dist/schemas/worker.js +1 -0
- package/dist/schemas/worker.js.map +1 -1
- package/dist/services/agent-service.d.ts +57 -0
- package/dist/services/agent-service.d.ts.map +1 -0
- package/dist/services/agent-service.js +81 -0
- package/dist/services/agent-service.js.map +1 -0
- package/dist/services/attempt-service.d.ts.map +1 -1
- package/dist/services/attempt-service.js +1 -4
- package/dist/services/attempt-service.js.map +1 -1
- package/dist/services/auto-sync-service.d.ts.map +1 -1
- package/dist/services/auto-sync-service.js +18 -10
- package/dist/services/auto-sync-service.js.map +1 -1
- package/dist/services/claim-service.d.ts +8 -2
- package/dist/services/claim-service.d.ts.map +1 -1
- package/dist/services/claim-service.js +37 -23
- package/dist/services/claim-service.js.map +1 -1
- package/dist/services/cycle-scan-service.d.ts +32 -0
- package/dist/services/cycle-scan-service.d.ts.map +1 -0
- package/dist/services/cycle-scan-service.js +546 -0
- package/dist/services/cycle-scan-service.js.map +1 -0
- package/dist/services/daemon-service.d.ts +40 -2
- package/dist/services/daemon-service.d.ts.map +1 -1
- package/dist/services/daemon-service.js +199 -52
- package/dist/services/daemon-service.js.map +1 -1
- package/dist/services/deduplication-service.d.ts +8 -4
- package/dist/services/deduplication-service.d.ts.map +1 -1
- package/dist/services/deduplication-service.js +79 -25
- package/dist/services/deduplication-service.js.map +1 -1
- package/dist/services/dep-service.d.ts +2 -2
- package/dist/services/dep-service.d.ts.map +1 -1
- package/dist/services/dep-service.js +9 -5
- package/dist/services/dep-service.js.map +1 -1
- package/dist/services/diversifier-service.d.ts +2 -1
- package/dist/services/diversifier-service.d.ts.map +1 -1
- package/dist/services/diversifier-service.js +37 -43
- package/dist/services/diversifier-service.js.map +1 -1
- package/dist/services/doc-service.d.ts +49 -0
- package/dist/services/doc-service.d.ts.map +1 -0
- package/dist/services/doc-service.js +605 -0
- package/dist/services/doc-service.js.map +1 -0
- package/dist/services/embedding-service.d.ts +66 -2
- package/dist/services/embedding-service.d.ts.map +1 -1
- package/dist/services/embedding-service.js +138 -24
- package/dist/services/embedding-service.js.map +1 -1
- package/dist/services/file-learning-service.d.ts.map +1 -1
- package/dist/services/file-learning-service.js +8 -7
- package/dist/services/file-learning-service.js.map +1 -1
- package/dist/services/file-watcher-service.d.ts.map +1 -1
- package/dist/services/file-watcher-service.js +58 -11
- package/dist/services/file-watcher-service.js.map +1 -1
- package/dist/services/hierarchy-service.d.ts +1 -1
- package/dist/services/hierarchy-service.d.ts.map +1 -1
- package/dist/services/hierarchy-service.js +50 -32
- package/dist/services/hierarchy-service.js.map +1 -1
- package/dist/services/index.d.ts +13 -15
- package/dist/services/index.d.ts.map +1 -1
- package/dist/services/index.js +13 -15
- package/dist/services/index.js.map +1 -1
- package/dist/services/learning-service.d.ts +3 -3
- package/dist/services/learning-service.d.ts.map +1 -1
- package/dist/services/learning-service.js +75 -42
- package/dist/services/learning-service.js.map +1 -1
- package/dist/services/llm-service.d.ts +62 -0
- package/dist/services/llm-service.d.ts.map +1 -0
- package/dist/services/llm-service.js +172 -0
- package/dist/services/llm-service.js.map +1 -0
- package/dist/services/migration-service.d.ts +1 -1
- package/dist/services/migration-service.d.ts.map +1 -1
- package/dist/services/migration-service.js +18 -7
- package/dist/services/migration-service.js.map +1 -1
- package/dist/services/orchestrator-service.d.ts +4 -3
- package/dist/services/orchestrator-service.d.ts.map +1 -1
- package/dist/services/orchestrator-service.js +66 -27
- package/dist/services/orchestrator-service.js.map +1 -1
- package/dist/services/query-expansion-service.d.ts +30 -9
- package/dist/services/query-expansion-service.d.ts.map +1 -1
- package/dist/services/query-expansion-service.js +54 -63
- package/dist/services/query-expansion-service.js.map +1 -1
- package/dist/services/ready-service.d.ts +21 -1
- package/dist/services/ready-service.d.ts.map +1 -1
- package/dist/services/ready-service.js +44 -21
- package/dist/services/ready-service.js.map +1 -1
- package/dist/services/retriever-service.d.ts +10 -10
- package/dist/services/retriever-service.d.ts.map +1 -1
- package/dist/services/retriever-service.js +53 -161
- package/dist/services/retriever-service.js.map +1 -1
- package/dist/services/sync-service.d.ts +17 -4
- package/dist/services/sync-service.d.ts.map +1 -1
- package/dist/services/sync-service.js +381 -116
- package/dist/services/sync-service.js.map +1 -1
- package/dist/services/task-service.d.ts +6 -4
- package/dist/services/task-service.d.ts.map +1 -1
- package/dist/services/task-service.js +165 -35
- package/dist/services/task-service.js.map +1 -1
- package/dist/services/tracing-service.d.ts +55 -0
- package/dist/services/tracing-service.d.ts.map +1 -0
- package/dist/services/tracing-service.js +99 -0
- package/dist/services/tracing-service.js.map +1 -0
- package/dist/services/transcript-adapter.d.ts +99 -0
- package/dist/services/transcript-adapter.d.ts.map +1 -0
- package/dist/services/transcript-adapter.js +283 -0
- package/dist/services/transcript-adapter.js.map +1 -0
- package/dist/services/validation-service.d.ts +85 -0
- package/dist/services/validation-service.d.ts.map +1 -0
- package/dist/services/validation-service.js +289 -0
- package/dist/services/validation-service.js.map +1 -0
- package/dist/services/worker-process.d.ts +23 -4
- package/dist/services/worker-process.d.ts.map +1 -1
- package/dist/services/worker-process.js +168 -72
- package/dist/services/worker-process.js.map +1 -1
- package/dist/services/worker-service.d.ts.map +1 -1
- package/dist/services/worker-service.js +7 -12
- package/dist/services/worker-service.js.map +1 -1
- package/dist/sync/claude-task-writer.d.ts +49 -0
- package/dist/sync/claude-task-writer.d.ts.map +1 -0
- package/dist/sync/claude-task-writer.js +135 -0
- package/dist/sync/claude-task-writer.js.map +1 -0
- package/dist/utils/doc-hash.d.ts +10 -0
- package/dist/utils/doc-hash.d.ts.map +1 -0
- package/dist/utils/doc-hash.js +14 -0
- package/dist/utils/doc-hash.js.map +1 -0
- package/dist/utils/doc-renderer.d.ts +44 -0
- package/dist/utils/doc-renderer.d.ts.map +1 -0
- package/dist/utils/doc-renderer.js +202 -0
- package/dist/utils/doc-renderer.js.map +1 -0
- package/dist/utils/math.d.ts +5 -1
- package/dist/utils/math.d.ts.map +1 -1
- package/dist/utils/math.js +12 -4
- package/dist/utils/math.js.map +1 -1
- package/dist/utils/sql.d.ts +9 -0
- package/dist/utils/sql.d.ts.map +1 -0
- package/dist/utils/sql.js +9 -0
- package/dist/utils/sql.js.map +1 -0
- package/dist/utils/toml-config.d.ts +22 -0
- package/dist/utils/toml-config.d.ts.map +1 -0
- package/dist/utils/toml-config.js +75 -0
- package/dist/utils/toml-config.js.map +1 -0
- package/dist/worker/hooks.d.ts +102 -0
- package/dist/worker/hooks.d.ts.map +1 -0
- package/dist/worker/hooks.js +11 -0
- package/dist/worker/hooks.js.map +1 -0
- package/dist/worker/index.d.ts +9 -0
- package/dist/worker/index.d.ts.map +1 -0
- package/dist/worker/index.js +8 -0
- package/dist/worker/index.js.map +1 -0
- package/dist/worker/run-worker.d.ts +33 -0
- package/dist/worker/run-worker.d.ts.map +1 -0
- package/dist/worker/run-worker.js +265 -0
- package/dist/worker/run-worker.js.map +1 -0
- package/package.json +14 -12
- package/dist/mappers/anchor.d.ts +0 -14
- package/dist/mappers/anchor.d.ts.map +0 -1
- package/dist/mappers/anchor.js +0 -38
- package/dist/mappers/anchor.js.map +0 -1
- package/dist/mappers/candidate.d.ts +0 -23
- package/dist/mappers/candidate.d.ts.map +0 -1
- package/dist/mappers/candidate.js +0 -53
- package/dist/mappers/candidate.js.map +0 -1
- package/dist/mappers/edge.d.ts +0 -10
- package/dist/mappers/edge.d.ts.map +0 -1
- package/dist/mappers/edge.js +0 -19
- package/dist/mappers/edge.js.map +0 -1
- package/dist/repo/anchor-repo.d.ts +0 -52
- package/dist/repo/anchor-repo.d.ts.map +0 -1
- package/dist/repo/anchor-repo.js +0 -204
- package/dist/repo/anchor-repo.js.map +0 -1
- package/dist/repo/candidate-repo.d.ts +0 -16
- package/dist/repo/candidate-repo.d.ts.map +0 -1
- package/dist/repo/candidate-repo.js +0 -143
- package/dist/repo/candidate-repo.js.map +0 -1
- package/dist/repo/edge-repo.d.ts +0 -26
- package/dist/repo/edge-repo.d.ts.map +0 -1
- package/dist/repo/edge-repo.js +0 -227
- package/dist/repo/edge-repo.js.map +0 -1
- package/dist/services/anchor-service.d.ts +0 -147
- package/dist/services/anchor-service.d.ts.map +0 -1
- package/dist/services/anchor-service.js +0 -540
- package/dist/services/anchor-service.js.map +0 -1
- package/dist/services/anchor-verification.d.ts +0 -94
- package/dist/services/anchor-verification.d.ts.map +0 -1
- package/dist/services/anchor-verification.js +0 -617
- package/dist/services/anchor-verification.js.map +0 -1
- package/dist/services/ast-grep-service.d.ts +0 -58
- package/dist/services/ast-grep-service.d.ts.map +0 -1
- package/dist/services/ast-grep-service.js +0 -356
- package/dist/services/ast-grep-service.js.map +0 -1
- package/dist/services/candidate-extractor-service.d.ts +0 -56
- package/dist/services/candidate-extractor-service.d.ts.map +0 -1
- package/dist/services/candidate-extractor-service.js +0 -365
- package/dist/services/candidate-extractor-service.js.map +0 -1
- package/dist/services/edge-service.d.ts +0 -78
- package/dist/services/edge-service.d.ts.map +0 -1
- package/dist/services/edge-service.js +0 -158
- package/dist/services/edge-service.js.map +0 -1
- package/dist/services/feedback-tracker.d.ts +0 -64
- package/dist/services/feedback-tracker.d.ts.map +0 -1
- package/dist/services/feedback-tracker.js +0 -110
- package/dist/services/feedback-tracker.js.map +0 -1
- package/dist/services/graph-expansion.d.ts +0 -155
- package/dist/services/graph-expansion.d.ts.map +0 -1
- package/dist/services/graph-expansion.js +0 -466
- package/dist/services/graph-expansion.js.map +0 -1
- package/dist/services/promotion-service.d.ts +0 -67
- package/dist/services/promotion-service.d.ts.map +0 -1
- package/dist/services/promotion-service.js +0 -151
- package/dist/services/promotion-service.js.map +0 -1
- package/dist/services/swarm-verification.d.ts +0 -104
- package/dist/services/swarm-verification.d.ts.map +0 -1
- package/dist/services/swarm-verification.js +0 -400
- package/dist/services/swarm-verification.js.map +0 -1
|
@@ -1,365 +0,0 @@
|
|
|
1
|
-
import { Context, Effect, Layer, Config, Option } from "effect";
|
|
2
|
-
import { ExtractionUnavailableError } from "../errors.js";
|
|
3
|
-
/**
|
|
4
|
-
* The prompt template for learning candidate extraction.
|
|
5
|
-
* Designed to extract actionable, generalizable learnings from Claude Code transcripts.
|
|
6
|
-
* @see PRD-015 for specification
|
|
7
|
-
*/
|
|
8
|
-
const EXTRACTION_PROMPT = `Analyze this Claude Code session transcript and extract actionable learnings.
|
|
9
|
-
|
|
10
|
-
<transcript>
|
|
11
|
-
{transcript_excerpt}
|
|
12
|
-
</transcript>
|
|
13
|
-
|
|
14
|
-
Extract learnings that meet these criteria:
|
|
15
|
-
1. **Technical decisions**: Describes a choice and its rationale
|
|
16
|
-
2. **Gotchas/pitfalls**: Something to avoid next time
|
|
17
|
-
3. **Patterns that worked**: Reusable approaches
|
|
18
|
-
4. **Future improvements**: Things to do differently
|
|
19
|
-
|
|
20
|
-
For each learning, provide:
|
|
21
|
-
- content: The learning text (1-3 sentences, actionable)
|
|
22
|
-
- confidence: "high" (certain, tested), "medium" (likely useful), "low" (speculative)
|
|
23
|
-
- category: One of [architecture, testing, performance, security, debugging, tooling, patterns, other]
|
|
24
|
-
|
|
25
|
-
Return JSON array:
|
|
26
|
-
[
|
|
27
|
-
{
|
|
28
|
-
"content": "Always wrap database operations in transactions to ensure atomicity",
|
|
29
|
-
"confidence": "high",
|
|
30
|
-
"category": "patterns"
|
|
31
|
-
}
|
|
32
|
-
]
|
|
33
|
-
|
|
34
|
-
Rules:
|
|
35
|
-
- Skip generic advice (things any developer knows)
|
|
36
|
-
- Skip context-specific details that won't generalize
|
|
37
|
-
- Prefer actionable "do X when Y" format
|
|
38
|
-
- Maximum 5 learnings per transcript
|
|
39
|
-
- If no meaningful learnings found, return empty array: []`;
|
|
40
|
-
/**
|
|
41
|
-
* Valid confidence levels for validation.
|
|
42
|
-
*/
|
|
43
|
-
const VALID_CONFIDENCES = ["high", "medium", "low"];
|
|
44
|
-
/**
|
|
45
|
-
* Valid categories for validation.
|
|
46
|
-
*/
|
|
47
|
-
const VALID_CATEGORIES = [
|
|
48
|
-
"architecture",
|
|
49
|
-
"testing",
|
|
50
|
-
"performance",
|
|
51
|
-
"security",
|
|
52
|
-
"debugging",
|
|
53
|
-
"tooling",
|
|
54
|
-
"patterns",
|
|
55
|
-
"other"
|
|
56
|
-
];
|
|
57
|
-
/**
|
|
58
|
-
* Parse LLM JSON response, handling common formatting issues.
|
|
59
|
-
* Robust parser following DD-006 patterns.
|
|
60
|
-
*/
|
|
61
|
-
const parseLlmJson = (raw) => {
|
|
62
|
-
// Step 1: Try direct parse
|
|
63
|
-
try {
|
|
64
|
-
return JSON.parse(raw);
|
|
65
|
-
}
|
|
66
|
-
catch { /* continue */ }
|
|
67
|
-
// Step 2: Strip markdown code fences
|
|
68
|
-
const fenceMatch = raw.match(/```(?:json)?\s*\n?([\s\S]*?)```/);
|
|
69
|
-
if (fenceMatch && fenceMatch[1]) {
|
|
70
|
-
try {
|
|
71
|
-
return JSON.parse(fenceMatch[1].trim());
|
|
72
|
-
}
|
|
73
|
-
catch { /* continue */ }
|
|
74
|
-
}
|
|
75
|
-
// Step 3: Find first [ or { and parse from there
|
|
76
|
-
const jsonStart = raw.search(/[[{]/);
|
|
77
|
-
if (jsonStart >= 0) {
|
|
78
|
-
const candidate = raw.slice(jsonStart);
|
|
79
|
-
try {
|
|
80
|
-
return JSON.parse(candidate);
|
|
81
|
-
}
|
|
82
|
-
catch { /* continue */ }
|
|
83
|
-
// Step 4: Find matching bracket and extract
|
|
84
|
-
const openChar = candidate[0];
|
|
85
|
-
const closeChar = openChar === "[" ? "]" : "}";
|
|
86
|
-
const lastClose = candidate.lastIndexOf(closeChar);
|
|
87
|
-
if (lastClose > 0) {
|
|
88
|
-
try {
|
|
89
|
-
return JSON.parse(candidate.slice(0, lastClose + 1));
|
|
90
|
-
}
|
|
91
|
-
catch { /* continue */ }
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
return null;
|
|
95
|
-
};
|
|
96
|
-
/**
|
|
97
|
-
* Validate and normalize an extracted candidate from LLM response.
|
|
98
|
-
* Returns null if the candidate is invalid.
|
|
99
|
-
*/
|
|
100
|
-
const validateCandidate = (raw) => {
|
|
101
|
-
if (!raw || typeof raw !== "object")
|
|
102
|
-
return null;
|
|
103
|
-
const obj = raw;
|
|
104
|
-
// Validate content
|
|
105
|
-
if (typeof obj.content !== "string" || obj.content.trim().length === 0)
|
|
106
|
-
return null;
|
|
107
|
-
const content = obj.content.trim();
|
|
108
|
-
// Skip if content is too short (likely not actionable)
|
|
109
|
-
if (content.length < 10)
|
|
110
|
-
return null;
|
|
111
|
-
// Validate confidence
|
|
112
|
-
const rawConfidence = String(obj.confidence || "").toLowerCase();
|
|
113
|
-
const confidence = VALID_CONFIDENCES.includes(rawConfidence)
|
|
114
|
-
? rawConfidence
|
|
115
|
-
: "medium"; // Default to medium if invalid
|
|
116
|
-
// Validate category
|
|
117
|
-
const rawCategory = String(obj.category || "").toLowerCase();
|
|
118
|
-
const category = VALID_CATEGORIES.includes(rawCategory)
|
|
119
|
-
? rawCategory
|
|
120
|
-
: "other"; // Default to other if invalid
|
|
121
|
-
return { content, confidence, category };
|
|
122
|
-
};
|
|
123
|
-
/**
|
|
124
|
-
* CandidateExtractorService extracts learning candidates from Claude Code transcripts.
|
|
125
|
-
*
|
|
126
|
-
* This service uses LLM to analyze transcript content and identify:
|
|
127
|
-
* - Technical decisions with rationale
|
|
128
|
-
* - Gotchas and pitfalls to avoid
|
|
129
|
-
* - Patterns that worked well
|
|
130
|
-
* - Future improvements
|
|
131
|
-
*
|
|
132
|
-
* Design: Following DD-006 patterns for LLM integration with pluggable backends.
|
|
133
|
-
* Supports Anthropic, OpenAI, and noop backends with graceful degradation.
|
|
134
|
-
*
|
|
135
|
-
* @see PRD-015 for the JSONL daemon and knowledge promotion pipeline
|
|
136
|
-
*/
|
|
137
|
-
export class CandidateExtractorService extends Context.Tag("CandidateExtractorService")() {
|
|
138
|
-
}
|
|
139
|
-
/**
|
|
140
|
-
* Noop implementation - returns empty results without LLM processing.
|
|
141
|
-
* Used when no LLM API key is configured or for testing.
|
|
142
|
-
*/
|
|
143
|
-
export const CandidateExtractorServiceNoop = Layer.succeed(CandidateExtractorService, {
|
|
144
|
-
extract: (chunk) => Effect.succeed({
|
|
145
|
-
candidates: [],
|
|
146
|
-
sourceChunk: chunk,
|
|
147
|
-
wasExtracted: false
|
|
148
|
-
}),
|
|
149
|
-
isAvailable: () => Effect.succeed(false)
|
|
150
|
-
});
|
|
151
|
-
/**
|
|
152
|
-
* Anthropic (Claude) implementation.
|
|
153
|
-
* Uses Claude to extract learning candidates from transcripts.
|
|
154
|
-
*/
|
|
155
|
-
export const CandidateExtractorServiceAnthropic = Layer.effect(CandidateExtractorService, Effect.gen(function* () {
|
|
156
|
-
// Read API key from environment
|
|
157
|
-
const apiKey = yield* Config.string("ANTHROPIC_API_KEY").pipe(Effect.mapError(() => new ExtractionUnavailableError({
|
|
158
|
-
reason: "ANTHROPIC_API_KEY environment variable is not set"
|
|
159
|
-
})));
|
|
160
|
-
// Lazy-load client
|
|
161
|
-
let client = null;
|
|
162
|
-
const ensureClient = Effect.gen(function* () {
|
|
163
|
-
if (client)
|
|
164
|
-
return client;
|
|
165
|
-
// Dynamic import of Anthropic SDK (optional peer dependency)
|
|
166
|
-
const Anthropic = yield* Effect.tryPromise({
|
|
167
|
-
try: async () => {
|
|
168
|
-
// @ts-expect-error - @anthropic-ai/sdk is an optional peer dependency
|
|
169
|
-
const mod = await import("@anthropic-ai/sdk");
|
|
170
|
-
return mod.default;
|
|
171
|
-
},
|
|
172
|
-
catch: () => new ExtractionUnavailableError({
|
|
173
|
-
reason: "@anthropic-ai/sdk is not installed"
|
|
174
|
-
})
|
|
175
|
-
});
|
|
176
|
-
client = new Anthropic({ apiKey });
|
|
177
|
-
return client;
|
|
178
|
-
});
|
|
179
|
-
return {
|
|
180
|
-
extract: (chunk) => Effect.gen(function* () {
|
|
181
|
-
const startTime = Date.now();
|
|
182
|
-
const anthropic = yield* ensureClient;
|
|
183
|
-
// Build prompt with transcript content
|
|
184
|
-
const prompt = EXTRACTION_PROMPT.replace("{transcript_excerpt}", chunk.content);
|
|
185
|
-
const response = yield* Effect.tryPromise({
|
|
186
|
-
try: () => anthropic.messages.create({
|
|
187
|
-
model: "claude-haiku-4-20250514",
|
|
188
|
-
max_tokens: 1024,
|
|
189
|
-
messages: [{
|
|
190
|
-
role: "user",
|
|
191
|
-
content: prompt
|
|
192
|
-
}]
|
|
193
|
-
}),
|
|
194
|
-
catch: (e) => new ExtractionUnavailableError({
|
|
195
|
-
reason: `Anthropic API call failed: ${String(e)}`
|
|
196
|
-
})
|
|
197
|
-
});
|
|
198
|
-
// Extract text from response
|
|
199
|
-
const textContent = response.content.find(c => c.type === "text");
|
|
200
|
-
if (!textContent || !textContent.text) {
|
|
201
|
-
return {
|
|
202
|
-
candidates: [],
|
|
203
|
-
sourceChunk: chunk,
|
|
204
|
-
wasExtracted: true,
|
|
205
|
-
metadata: {
|
|
206
|
-
model: "claude-haiku-4-20250514",
|
|
207
|
-
tokensUsed: (response.usage?.input_tokens ?? 0) + (response.usage?.output_tokens ?? 0),
|
|
208
|
-
durationMs: Date.now() - startTime
|
|
209
|
-
}
|
|
210
|
-
};
|
|
211
|
-
}
|
|
212
|
-
// Parse the JSON array of candidates
|
|
213
|
-
const rawCandidates = parseLlmJson(textContent.text);
|
|
214
|
-
if (!rawCandidates || !Array.isArray(rawCandidates)) {
|
|
215
|
-
return {
|
|
216
|
-
candidates: [],
|
|
217
|
-
sourceChunk: chunk,
|
|
218
|
-
wasExtracted: true,
|
|
219
|
-
metadata: {
|
|
220
|
-
model: "claude-haiku-4-20250514",
|
|
221
|
-
tokensUsed: (response.usage?.input_tokens ?? 0) + (response.usage?.output_tokens ?? 0),
|
|
222
|
-
durationMs: Date.now() - startTime
|
|
223
|
-
}
|
|
224
|
-
};
|
|
225
|
-
}
|
|
226
|
-
// Validate and normalize each candidate
|
|
227
|
-
const candidates = rawCandidates
|
|
228
|
-
.map(validateCandidate)
|
|
229
|
-
.filter((c) => c !== null)
|
|
230
|
-
.slice(0, 5); // Max 5 candidates per chunk
|
|
231
|
-
return {
|
|
232
|
-
candidates,
|
|
233
|
-
sourceChunk: chunk,
|
|
234
|
-
wasExtracted: true,
|
|
235
|
-
metadata: {
|
|
236
|
-
model: "claude-haiku-4-20250514",
|
|
237
|
-
tokensUsed: (response.usage?.input_tokens ?? 0) + (response.usage?.output_tokens ?? 0),
|
|
238
|
-
durationMs: Date.now() - startTime
|
|
239
|
-
}
|
|
240
|
-
};
|
|
241
|
-
}),
|
|
242
|
-
isAvailable: () => Effect.succeed(true)
|
|
243
|
-
};
|
|
244
|
-
}));
|
|
245
|
-
/**
|
|
246
|
-
* OpenAI (GPT) implementation.
|
|
247
|
-
* Uses GPT to extract learning candidates from transcripts.
|
|
248
|
-
*/
|
|
249
|
-
export const CandidateExtractorServiceOpenAI = Layer.effect(CandidateExtractorService, Effect.gen(function* () {
|
|
250
|
-
// Read API key from environment
|
|
251
|
-
const apiKey = yield* Config.string("OPENAI_API_KEY").pipe(Effect.mapError(() => new ExtractionUnavailableError({
|
|
252
|
-
reason: "OPENAI_API_KEY environment variable is not set"
|
|
253
|
-
})));
|
|
254
|
-
// Lazy-load client
|
|
255
|
-
let client = null;
|
|
256
|
-
const ensureClient = Effect.gen(function* () {
|
|
257
|
-
if (client)
|
|
258
|
-
return client;
|
|
259
|
-
// Dynamic import of OpenAI SDK (optional peer dependency)
|
|
260
|
-
const OpenAI = yield* Effect.tryPromise({
|
|
261
|
-
try: async () => {
|
|
262
|
-
// @ts-expect-error - openai is an optional peer dependency
|
|
263
|
-
const mod = await import("openai");
|
|
264
|
-
return mod.default;
|
|
265
|
-
},
|
|
266
|
-
catch: () => new ExtractionUnavailableError({
|
|
267
|
-
reason: "openai package is not installed"
|
|
268
|
-
})
|
|
269
|
-
});
|
|
270
|
-
client = new OpenAI({ apiKey });
|
|
271
|
-
return client;
|
|
272
|
-
});
|
|
273
|
-
return {
|
|
274
|
-
extract: (chunk) => Effect.gen(function* () {
|
|
275
|
-
const startTime = Date.now();
|
|
276
|
-
const openai = yield* ensureClient;
|
|
277
|
-
// Build prompt with transcript content
|
|
278
|
-
const prompt = EXTRACTION_PROMPT.replace("{transcript_excerpt}", chunk.content);
|
|
279
|
-
const response = yield* Effect.tryPromise({
|
|
280
|
-
try: () => openai.chat.completions.create({
|
|
281
|
-
model: "gpt-4o-mini",
|
|
282
|
-
max_tokens: 1024,
|
|
283
|
-
messages: [{
|
|
284
|
-
role: "user",
|
|
285
|
-
content: prompt
|
|
286
|
-
}],
|
|
287
|
-
response_format: { type: "json_object" }
|
|
288
|
-
}),
|
|
289
|
-
catch: (e) => new ExtractionUnavailableError({
|
|
290
|
-
reason: `OpenAI API call failed: ${String(e)}`
|
|
291
|
-
})
|
|
292
|
-
});
|
|
293
|
-
// Extract text from response
|
|
294
|
-
const textContent = response.choices[0]?.message?.content;
|
|
295
|
-
if (!textContent) {
|
|
296
|
-
return {
|
|
297
|
-
candidates: [],
|
|
298
|
-
sourceChunk: chunk,
|
|
299
|
-
wasExtracted: true,
|
|
300
|
-
metadata: {
|
|
301
|
-
model: "gpt-4o-mini",
|
|
302
|
-
tokensUsed: (response.usage?.prompt_tokens ?? 0) + (response.usage?.completion_tokens ?? 0),
|
|
303
|
-
durationMs: Date.now() - startTime
|
|
304
|
-
}
|
|
305
|
-
};
|
|
306
|
-
}
|
|
307
|
-
// Parse the JSON array of candidates
|
|
308
|
-
// OpenAI with json_object mode might wrap in an object
|
|
309
|
-
const parsed = parseLlmJson(textContent);
|
|
310
|
-
let rawCandidates = [];
|
|
311
|
-
if (Array.isArray(parsed)) {
|
|
312
|
-
rawCandidates = parsed;
|
|
313
|
-
}
|
|
314
|
-
else if (parsed && typeof parsed === "object") {
|
|
315
|
-
// Handle wrapped response like { candidates: [...] } or { learnings: [...] }
|
|
316
|
-
const obj = parsed;
|
|
317
|
-
const arrayField = Object.values(obj).find(Array.isArray);
|
|
318
|
-
if (arrayField) {
|
|
319
|
-
rawCandidates = arrayField;
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
// Validate and normalize each candidate
|
|
323
|
-
const candidates = rawCandidates
|
|
324
|
-
.map(validateCandidate)
|
|
325
|
-
.filter((c) => c !== null)
|
|
326
|
-
.slice(0, 5); // Max 5 candidates per chunk
|
|
327
|
-
return {
|
|
328
|
-
candidates,
|
|
329
|
-
sourceChunk: chunk,
|
|
330
|
-
wasExtracted: true,
|
|
331
|
-
metadata: {
|
|
332
|
-
model: "gpt-4o-mini",
|
|
333
|
-
tokensUsed: (response.usage?.prompt_tokens ?? 0) + (response.usage?.completion_tokens ?? 0),
|
|
334
|
-
durationMs: Date.now() - startTime
|
|
335
|
-
}
|
|
336
|
-
};
|
|
337
|
-
}),
|
|
338
|
-
isAvailable: () => Effect.succeed(true)
|
|
339
|
-
};
|
|
340
|
-
}));
|
|
341
|
-
/**
|
|
342
|
-
* Auto-detecting layer that selects the appropriate backend based on environment.
|
|
343
|
-
*
|
|
344
|
-
* Priority:
|
|
345
|
-
* 1. ANTHROPIC_API_KEY set → Use Anthropic (Claude)
|
|
346
|
-
* 2. OPENAI_API_KEY set → Use OpenAI (GPT)
|
|
347
|
-
* 3. Neither set → Use Noop (graceful degradation)
|
|
348
|
-
*
|
|
349
|
-
* This allows graceful degradation when no LLM API keys are configured.
|
|
350
|
-
*/
|
|
351
|
-
export const CandidateExtractorServiceAuto = Layer.unwrapEffect(Effect.gen(function* () {
|
|
352
|
-
// Check for Anthropic API key first (preferred)
|
|
353
|
-
const anthropicKey = yield* Config.string("ANTHROPIC_API_KEY").pipe(Effect.option);
|
|
354
|
-
if (Option.isSome(anthropicKey) && anthropicKey.value.trim().length > 0) {
|
|
355
|
-
return CandidateExtractorServiceAnthropic;
|
|
356
|
-
}
|
|
357
|
-
// Fall back to OpenAI if available
|
|
358
|
-
const openaiKey = yield* Config.string("OPENAI_API_KEY").pipe(Effect.option);
|
|
359
|
-
if (Option.isSome(openaiKey) && openaiKey.value.trim().length > 0) {
|
|
360
|
-
return CandidateExtractorServiceOpenAI;
|
|
361
|
-
}
|
|
362
|
-
// No API keys configured - use noop
|
|
363
|
-
return CandidateExtractorServiceNoop;
|
|
364
|
-
}));
|
|
365
|
-
//# sourceMappingURL=candidate-extractor-service.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"candidate-extractor-service.js","sourceRoot":"","sources":["../../src/services/candidate-extractor-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,78 +0,0 @@
|
|
|
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
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"edge-service.d.ts","sourceRoot":"","sources":["../../src/services/edge-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
import { Context, Effect, Layer } from "effect";
|
|
2
|
-
import { EdgeRepository } from "../repo/edge-repo.js";
|
|
3
|
-
import { EdgeNotFoundError, ValidationError } from "../errors.js";
|
|
4
|
-
/** Valid edge types - imported at runtime for validation */
|
|
5
|
-
const VALID_EDGE_TYPES = [
|
|
6
|
-
"ANCHORED_TO",
|
|
7
|
-
"DERIVED_FROM",
|
|
8
|
-
"IMPORTS",
|
|
9
|
-
"CO_CHANGES_WITH",
|
|
10
|
-
"SIMILAR_TO",
|
|
11
|
-
"LINKS_TO",
|
|
12
|
-
"USED_IN_RUN",
|
|
13
|
-
"INVALIDATED_BY"
|
|
14
|
-
];
|
|
15
|
-
/** Valid node types - imported at runtime for validation */
|
|
16
|
-
const VALID_NODE_TYPES = ["learning", "file", "task", "run"];
|
|
17
|
-
export class EdgeService extends Context.Tag("EdgeService")() {
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Validate edge type.
|
|
21
|
-
*/
|
|
22
|
-
const validateEdgeType = (edgeType) => Effect.gen(function* () {
|
|
23
|
-
if (!VALID_EDGE_TYPES.includes(edgeType)) {
|
|
24
|
-
return yield* Effect.fail(new ValidationError({
|
|
25
|
-
reason: `Invalid edge type: ${edgeType}. Valid types: ${VALID_EDGE_TYPES.join(", ")}`
|
|
26
|
-
}));
|
|
27
|
-
}
|
|
28
|
-
return edgeType;
|
|
29
|
-
});
|
|
30
|
-
/**
|
|
31
|
-
* Validate node type.
|
|
32
|
-
*/
|
|
33
|
-
const validateNodeType = (nodeType, field) => Effect.gen(function* () {
|
|
34
|
-
if (!VALID_NODE_TYPES.includes(nodeType)) {
|
|
35
|
-
return yield* Effect.fail(new ValidationError({
|
|
36
|
-
reason: `Invalid ${field}: ${nodeType}. Valid types: ${VALID_NODE_TYPES.join(", ")}`
|
|
37
|
-
}));
|
|
38
|
-
}
|
|
39
|
-
return nodeType;
|
|
40
|
-
});
|
|
41
|
-
/**
|
|
42
|
-
* Validate weight is in [0, 1] range.
|
|
43
|
-
*/
|
|
44
|
-
const validateWeight = (weight) => Effect.gen(function* () {
|
|
45
|
-
const w = weight ?? 1.0;
|
|
46
|
-
if (w < 0 || w > 1) {
|
|
47
|
-
return yield* Effect.fail(new ValidationError({
|
|
48
|
-
reason: `Weight must be between 0 and 1, got: ${w}`
|
|
49
|
-
}));
|
|
50
|
-
}
|
|
51
|
-
return w;
|
|
52
|
-
});
|
|
53
|
-
/**
|
|
54
|
-
* Validate node ID is non-empty.
|
|
55
|
-
*/
|
|
56
|
-
const validateNodeId = (nodeId, field) => Effect.gen(function* () {
|
|
57
|
-
if (!nodeId || nodeId.trim().length === 0) {
|
|
58
|
-
return yield* Effect.fail(new ValidationError({
|
|
59
|
-
reason: `${field} is required and cannot be empty`
|
|
60
|
-
}));
|
|
61
|
-
}
|
|
62
|
-
return nodeId;
|
|
63
|
-
});
|
|
64
|
-
export const EdgeServiceLive = Layer.effect(EdgeService, Effect.gen(function* () {
|
|
65
|
-
const edgeRepo = yield* EdgeRepository;
|
|
66
|
-
return {
|
|
67
|
-
createEdge: (input) => Effect.gen(function* () {
|
|
68
|
-
// Validate all inputs
|
|
69
|
-
yield* validateEdgeType(input.edgeType);
|
|
70
|
-
yield* validateNodeType(input.sourceType, "sourceType");
|
|
71
|
-
yield* validateNodeType(input.targetType, "targetType");
|
|
72
|
-
yield* validateNodeId(input.sourceId, "sourceId");
|
|
73
|
-
yield* validateNodeId(input.targetId, "targetId");
|
|
74
|
-
yield* validateWeight(input.weight);
|
|
75
|
-
// Create the edge
|
|
76
|
-
return yield* edgeRepo.create(input);
|
|
77
|
-
}),
|
|
78
|
-
findNeighbors: (nodeType, nodeId, options = {}) => Effect.gen(function* () {
|
|
79
|
-
const depth = options.depth ?? 1;
|
|
80
|
-
const direction = options.direction ?? "both";
|
|
81
|
-
const edgeTypes = options.edgeTypes;
|
|
82
|
-
// For depth 1, use the repository directly
|
|
83
|
-
if (depth === 1) {
|
|
84
|
-
const neighbors = yield* edgeRepo.findNeighbors(nodeType, nodeId, { direction, edgeTypes });
|
|
85
|
-
return neighbors.map(n => ({ ...n, depth: 1 }));
|
|
86
|
-
}
|
|
87
|
-
// Multi-hop BFS traversal
|
|
88
|
-
const visited = new Set([`${nodeType}:${nodeId}`]);
|
|
89
|
-
const result = [];
|
|
90
|
-
let frontier = [{ nodeType, nodeId }];
|
|
91
|
-
for (let currentDepth = 1; currentDepth <= depth; currentDepth++) {
|
|
92
|
-
const nextFrontier = [];
|
|
93
|
-
for (const node of frontier) {
|
|
94
|
-
const neighbors = yield* edgeRepo.findNeighbors(node.nodeType, node.nodeId, { direction, edgeTypes });
|
|
95
|
-
for (const neighbor of neighbors) {
|
|
96
|
-
const key = `${neighbor.nodeType}:${neighbor.nodeId}`;
|
|
97
|
-
if (!visited.has(key)) {
|
|
98
|
-
visited.add(key);
|
|
99
|
-
result.push({ ...neighbor, depth: currentDepth });
|
|
100
|
-
nextFrontier.push({ nodeType: neighbor.nodeType, nodeId: neighbor.nodeId });
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
frontier = nextFrontier;
|
|
105
|
-
if (frontier.length === 0)
|
|
106
|
-
break;
|
|
107
|
-
}
|
|
108
|
-
return result;
|
|
109
|
-
}),
|
|
110
|
-
findPath: (fromType, fromId, toType, toId, maxDepth = 5) => edgeRepo.findPath(fromType, fromId, toType, toId, maxDepth),
|
|
111
|
-
invalidateEdge: (id) => edgeRepo.invalidate(id),
|
|
112
|
-
get: (id) => Effect.gen(function* () {
|
|
113
|
-
const edge = yield* edgeRepo.findById(id);
|
|
114
|
-
if (!edge) {
|
|
115
|
-
return yield* Effect.fail(new EdgeNotFoundError({ id }));
|
|
116
|
-
}
|
|
117
|
-
return edge;
|
|
118
|
-
}),
|
|
119
|
-
update: (id, input) => Effect.gen(function* () {
|
|
120
|
-
// Validate weight if provided
|
|
121
|
-
if (input.weight !== undefined) {
|
|
122
|
-
yield* validateWeight(input.weight);
|
|
123
|
-
}
|
|
124
|
-
// Get existing edge to verify it exists
|
|
125
|
-
const existing = yield* edgeRepo.findById(id);
|
|
126
|
-
if (!existing) {
|
|
127
|
-
return yield* Effect.fail(new EdgeNotFoundError({ id }));
|
|
128
|
-
}
|
|
129
|
-
// Update the edge
|
|
130
|
-
const updated = yield* edgeRepo.update(id, input);
|
|
131
|
-
if (!updated) {
|
|
132
|
-
return yield* Effect.fail(new EdgeNotFoundError({ id }));
|
|
133
|
-
}
|
|
134
|
-
return updated;
|
|
135
|
-
}),
|
|
136
|
-
findByType: (edgeType) => Effect.gen(function* () {
|
|
137
|
-
yield* validateEdgeType(edgeType);
|
|
138
|
-
return yield* edgeRepo.findByEdgeType(edgeType);
|
|
139
|
-
}),
|
|
140
|
-
findFromSource: (sourceType, sourceId) => edgeRepo.findBySource(sourceType, sourceId),
|
|
141
|
-
findFromMultipleSources: (sourceType, sourceIds) => edgeRepo.findByMultipleSources(sourceType, sourceIds),
|
|
142
|
-
findToTarget: (targetType, targetId) => edgeRepo.findByTarget(targetType, targetId),
|
|
143
|
-
countByType: () => Effect.gen(function* () {
|
|
144
|
-
const dbCounts = yield* edgeRepo.countByType();
|
|
145
|
-
const counts = new Map();
|
|
146
|
-
// Initialize all types with 0
|
|
147
|
-
for (const type of VALID_EDGE_TYPES) {
|
|
148
|
-
counts.set(type, 0);
|
|
149
|
-
}
|
|
150
|
-
// Merge in the actual counts from database
|
|
151
|
-
for (const [edgeType, count] of dbCounts) {
|
|
152
|
-
counts.set(edgeType, count);
|
|
153
|
-
}
|
|
154
|
-
return counts;
|
|
155
|
-
})
|
|
156
|
-
};
|
|
157
|
-
}));
|
|
158
|
-
//# sourceMappingURL=edge-service.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"edge-service.js","sourceRoot":"","sources":["../../src/services/edge-service.ts"],"names":[],"mappings":"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"}
|