@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.
- package/dist/db.d.ts +42 -0
- package/dist/db.d.ts.map +1 -0
- package/dist/db.js +46 -0
- package/dist/db.js.map +1 -0
- package/dist/errors.d.ts +231 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +139 -0
- package/dist/errors.js.map +1 -0
- package/dist/id.d.ts +6 -0
- package/dist/id.d.ts.map +1 -0
- package/dist/id.js +21 -0
- package/dist/id.js.map +1 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +56 -0
- package/dist/index.js.map +1 -0
- package/dist/layer.d.ts +50 -0
- package/dist/layer.d.ts.map +1 -0
- package/dist/layer.js +155 -0
- package/dist/layer.js.map +1 -0
- package/dist/mappers/anchor.d.ts +14 -0
- package/dist/mappers/anchor.d.ts.map +1 -0
- package/dist/mappers/anchor.js +38 -0
- package/dist/mappers/anchor.js.map +1 -0
- package/dist/mappers/attempt.d.ts +15 -0
- package/dist/mappers/attempt.d.ts.map +1 -0
- package/dist/mappers/attempt.js +23 -0
- package/dist/mappers/attempt.js.map +1 -0
- package/dist/mappers/candidate.d.ts +23 -0
- package/dist/mappers/candidate.d.ts.map +1 -0
- package/dist/mappers/candidate.js +53 -0
- package/dist/mappers/candidate.js.map +1 -0
- package/dist/mappers/claim.d.ts +30 -0
- package/dist/mappers/claim.d.ts.map +1 -0
- package/dist/mappers/claim.js +32 -0
- package/dist/mappers/claim.js.map +1 -0
- package/dist/mappers/deduplication.d.ts +39 -0
- package/dist/mappers/deduplication.d.ts.map +1 -0
- package/dist/mappers/deduplication.js +53 -0
- package/dist/mappers/deduplication.js.map +1 -0
- package/dist/mappers/edge.d.ts +10 -0
- package/dist/mappers/edge.d.ts.map +1 -0
- package/dist/mappers/edge.js +19 -0
- package/dist/mappers/edge.js.map +1 -0
- package/dist/mappers/file-learning.d.ts +14 -0
- package/dist/mappers/file-learning.d.ts.map +1 -0
- package/dist/mappers/file-learning.js +75 -0
- package/dist/mappers/file-learning.js.map +1 -0
- package/dist/mappers/index.d.ts +17 -0
- package/dist/mappers/index.d.ts.map +1 -0
- package/dist/mappers/index.js +30 -0
- package/dist/mappers/index.js.map +1 -0
- package/dist/mappers/learning.d.ts +19 -0
- package/dist/mappers/learning.d.ts.map +1 -0
- package/dist/mappers/learning.js +41 -0
- package/dist/mappers/learning.js.map +1 -0
- package/dist/mappers/orchestrator-state.d.ts +33 -0
- package/dist/mappers/orchestrator-state.d.ts.map +1 -0
- package/dist/mappers/orchestrator-state.js +34 -0
- package/dist/mappers/orchestrator-state.js.map +1 -0
- package/dist/mappers/run.d.ts +32 -0
- package/dist/mappers/run.d.ts.map +1 -0
- package/dist/mappers/run.js +64 -0
- package/dist/mappers/run.js.map +1 -0
- package/dist/mappers/task.d.ts +23 -0
- package/dist/mappers/task.d.ts.map +1 -0
- package/dist/mappers/task.js +54 -0
- package/dist/mappers/task.js.map +1 -0
- package/dist/mappers/tracked-project.d.ts +15 -0
- package/dist/mappers/tracked-project.d.ts.map +1 -0
- package/dist/mappers/tracked-project.js +23 -0
- package/dist/mappers/tracked-project.js.map +1 -0
- package/dist/mappers/worker.d.ts +33 -0
- package/dist/mappers/worker.d.ts.map +1 -0
- package/dist/mappers/worker.js +35 -0
- package/dist/mappers/worker.js.map +1 -0
- package/dist/repo/anchor-repo.d.ts +52 -0
- package/dist/repo/anchor-repo.d.ts.map +1 -0
- package/dist/repo/anchor-repo.js +204 -0
- package/dist/repo/anchor-repo.js.map +1 -0
- package/dist/repo/attempt-repo.d.ts +25 -0
- package/dist/repo/attempt-repo.d.ts.map +1 -0
- package/dist/repo/attempt-repo.js +78 -0
- package/dist/repo/attempt-repo.js.map +1 -0
- package/dist/repo/candidate-repo.d.ts +16 -0
- package/dist/repo/candidate-repo.d.ts.map +1 -0
- package/dist/repo/candidate-repo.js +143 -0
- package/dist/repo/candidate-repo.js.map +1 -0
- package/dist/repo/claim-repo.d.ts +17 -0
- package/dist/repo/claim-repo.d.ts.map +1 -0
- package/dist/repo/claim-repo.js +62 -0
- package/dist/repo/claim-repo.js.map +1 -0
- package/dist/repo/deduplication-repo.d.ts +37 -0
- package/dist/repo/deduplication-repo.d.ts.map +1 -0
- package/dist/repo/deduplication-repo.js +133 -0
- package/dist/repo/deduplication-repo.js.map +1 -0
- package/dist/repo/dep-repo.d.ts +19 -0
- package/dist/repo/dep-repo.d.ts.map +1 -0
- package/dist/repo/dep-repo.js +104 -0
- package/dist/repo/dep-repo.js.map +1 -0
- package/dist/repo/edge-repo.d.ts +26 -0
- package/dist/repo/edge-repo.d.ts.map +1 -0
- package/dist/repo/edge-repo.js +227 -0
- package/dist/repo/edge-repo.js.map +1 -0
- package/dist/repo/file-learning-repo.d.ts +17 -0
- package/dist/repo/file-learning-repo.d.ts.map +1 -0
- package/dist/repo/file-learning-repo.js +60 -0
- package/dist/repo/file-learning-repo.js.map +1 -0
- package/dist/repo/index.d.ts +18 -0
- package/dist/repo/index.d.ts.map +1 -0
- package/dist/repo/index.js +18 -0
- package/dist/repo/index.js.map +1 -0
- package/dist/repo/learning-repo.d.ts +31 -0
- package/dist/repo/learning-repo.d.ts.map +1 -0
- package/dist/repo/learning-repo.js +165 -0
- package/dist/repo/learning-repo.js.map +1 -0
- package/dist/repo/orchestrator-state-repo.d.ts +27 -0
- package/dist/repo/orchestrator-state-repo.d.ts.map +1 -0
- package/dist/repo/orchestrator-state-repo.js +96 -0
- package/dist/repo/orchestrator-state-repo.js.map +1 -0
- package/dist/repo/run-repo.d.ts +31 -0
- package/dist/repo/run-repo.d.ts.map +1 -0
- package/dist/repo/run-repo.js +132 -0
- package/dist/repo/run-repo.js.map +1 -0
- package/dist/repo/task-repo.d.ts +21 -0
- package/dist/repo/task-repo.d.ts.map +1 -0
- package/dist/repo/task-repo.js +169 -0
- package/dist/repo/task-repo.js.map +1 -0
- package/dist/repo/tracked-project-repo.d.ts +16 -0
- package/dist/repo/tracked-project-repo.d.ts.map +1 -0
- package/dist/repo/tracked-project-repo.js +54 -0
- package/dist/repo/tracked-project-repo.js.map +1 -0
- package/dist/repo/worker-repo.d.ts +19 -0
- package/dist/repo/worker-repo.d.ts.map +1 -0
- package/dist/repo/worker-repo.js +72 -0
- package/dist/repo/worker-repo.js.map +1 -0
- package/dist/schemas/index.d.ts +8 -0
- package/dist/schemas/index.d.ts.map +1 -0
- package/dist/schemas/index.js +7 -0
- package/dist/schemas/index.js.map +1 -0
- package/dist/schemas/sync.d.ts +296 -0
- package/dist/schemas/sync.d.ts.map +1 -0
- package/dist/schemas/sync.js +146 -0
- package/dist/schemas/sync.js.map +1 -0
- package/dist/schemas/worker.d.ts +77 -0
- package/dist/schemas/worker.d.ts.map +1 -0
- package/dist/schemas/worker.js +80 -0
- package/dist/schemas/worker.js.map +1 -0
- package/dist/services/anchor-service.d.ts +147 -0
- package/dist/services/anchor-service.d.ts.map +1 -0
- package/dist/services/anchor-service.js +540 -0
- package/dist/services/anchor-service.js.map +1 -0
- package/dist/services/anchor-verification.d.ts +94 -0
- package/dist/services/anchor-verification.d.ts.map +1 -0
- package/dist/services/anchor-verification.js +617 -0
- package/dist/services/anchor-verification.js.map +1 -0
- package/dist/services/ast-grep-service.d.ts +58 -0
- package/dist/services/ast-grep-service.d.ts.map +1 -0
- package/dist/services/ast-grep-service.js +356 -0
- package/dist/services/ast-grep-service.js.map +1 -0
- package/dist/services/attempt-service.d.ts +24 -0
- package/dist/services/attempt-service.d.ts.map +1 -0
- package/dist/services/attempt-service.js +55 -0
- package/dist/services/attempt-service.js.map +1 -0
- package/dist/services/auto-sync-service.d.ts +56 -0
- package/dist/services/auto-sync-service.d.ts.map +1 -0
- package/dist/services/auto-sync-service.js +66 -0
- package/dist/services/auto-sync-service.js.map +1 -0
- package/dist/services/candidate-extractor-service.d.ts +56 -0
- package/dist/services/candidate-extractor-service.d.ts.map +1 -0
- package/dist/services/candidate-extractor-service.js +365 -0
- package/dist/services/candidate-extractor-service.js.map +1 -0
- package/dist/services/claim-service.d.ts +52 -0
- package/dist/services/claim-service.d.ts.map +1 -0
- package/dist/services/claim-service.js +134 -0
- package/dist/services/claim-service.js.map +1 -0
- package/dist/services/daemon-service.d.ts +214 -0
- package/dist/services/daemon-service.d.ts.map +1 -0
- package/dist/services/daemon-service.js +522 -0
- package/dist/services/daemon-service.js.map +1 -0
- package/dist/services/deduplication-service.d.ts +67 -0
- package/dist/services/deduplication-service.d.ts.map +1 -0
- package/dist/services/deduplication-service.js +145 -0
- package/dist/services/deduplication-service.js.map +1 -0
- package/dist/services/dep-service.d.ts +14 -0
- package/dist/services/dep-service.d.ts.map +1 -0
- package/dist/services/dep-service.js +34 -0
- package/dist/services/dep-service.js.map +1 -0
- package/dist/services/diversifier-service.d.ts +46 -0
- package/dist/services/diversifier-service.d.ts.map +1 -0
- package/dist/services/diversifier-service.js +197 -0
- package/dist/services/diversifier-service.js.map +1 -0
- package/dist/services/edge-service.d.ts +78 -0
- package/dist/services/edge-service.d.ts.map +1 -0
- package/dist/services/edge-service.js +158 -0
- package/dist/services/edge-service.js.map +1 -0
- package/dist/services/embedding-service.d.ts +138 -0
- package/dist/services/embedding-service.d.ts.map +1 -0
- package/dist/services/embedding-service.js +318 -0
- package/dist/services/embedding-service.js.map +1 -0
- package/dist/services/feedback-tracker.d.ts +64 -0
- package/dist/services/feedback-tracker.d.ts.map +1 -0
- package/dist/services/feedback-tracker.js +110 -0
- package/dist/services/feedback-tracker.js.map +1 -0
- package/dist/services/file-learning-service.d.ts +17 -0
- package/dist/services/file-learning-service.d.ts.map +1 -0
- package/dist/services/file-learning-service.js +41 -0
- package/dist/services/file-learning-service.js.map +1 -0
- package/dist/services/file-watcher-service.d.ts +141 -0
- package/dist/services/file-watcher-service.d.ts.map +1 -0
- package/dist/services/file-watcher-service.js +278 -0
- package/dist/services/file-watcher-service.js.map +1 -0
- package/dist/services/graph-expansion.d.ts +155 -0
- package/dist/services/graph-expansion.d.ts.map +1 -0
- package/dist/services/graph-expansion.js +466 -0
- package/dist/services/graph-expansion.js.map +1 -0
- package/dist/services/hierarchy-service.d.ts +16 -0
- package/dist/services/hierarchy-service.d.ts.map +1 -0
- package/dist/services/hierarchy-service.js +66 -0
- package/dist/services/hierarchy-service.js.map +1 -0
- package/dist/services/index.d.ts +36 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +36 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/learning-service.d.ts +39 -0
- package/dist/services/learning-service.d.ts.map +1 -0
- package/dist/services/learning-service.js +151 -0
- package/dist/services/learning-service.js.map +1 -0
- package/dist/services/migration-service.d.ts +67 -0
- package/dist/services/migration-service.d.ts.map +1 -0
- package/dist/services/migration-service.js +144 -0
- package/dist/services/migration-service.js.map +1 -0
- package/dist/services/orchestrator-service.d.ts +52 -0
- package/dist/services/orchestrator-service.d.ts.map +1 -0
- package/dist/services/orchestrator-service.js +203 -0
- package/dist/services/orchestrator-service.js.map +1 -0
- package/dist/services/promotion-service.d.ts +67 -0
- package/dist/services/promotion-service.d.ts.map +1 -0
- package/dist/services/promotion-service.js +151 -0
- package/dist/services/promotion-service.js.map +1 -0
- package/dist/services/query-expansion-service.d.ts +55 -0
- package/dist/services/query-expansion-service.d.ts.map +1 -0
- package/dist/services/query-expansion-service.js +174 -0
- package/dist/services/query-expansion-service.js.map +1 -0
- package/dist/services/ready-service.d.ts +16 -0
- package/dist/services/ready-service.d.ts.map +1 -0
- package/dist/services/ready-service.js +70 -0
- package/dist/services/ready-service.js.map +1 -0
- package/dist/services/reranker-service.d.ts +51 -0
- package/dist/services/reranker-service.d.ts.map +1 -0
- package/dist/services/reranker-service.js +128 -0
- package/dist/services/reranker-service.js.map +1 -0
- package/dist/services/retriever-service.d.ts +49 -0
- package/dist/services/retriever-service.d.ts.map +1 -0
- package/dist/services/retriever-service.js +419 -0
- package/dist/services/retriever-service.js.map +1 -0
- package/dist/services/score-service.d.ts +43 -0
- package/dist/services/score-service.d.ts.map +1 -0
- package/dist/services/score-service.js +82 -0
- package/dist/services/score-service.js.map +1 -0
- package/dist/services/swarm-verification.d.ts +104 -0
- package/dist/services/swarm-verification.d.ts.map +1 -0
- package/dist/services/swarm-verification.js +400 -0
- package/dist/services/swarm-verification.js.map +1 -0
- package/dist/services/sync-service.d.ts +115 -0
- package/dist/services/sync-service.d.ts.map +1 -0
- package/dist/services/sync-service.js +350 -0
- package/dist/services/sync-service.js.map +1 -0
- package/dist/services/task-service.d.ts +22 -0
- package/dist/services/task-service.d.ts.map +1 -0
- package/dist/services/task-service.js +221 -0
- package/dist/services/task-service.js.map +1 -0
- package/dist/services/worker-process.d.ts +41 -0
- package/dist/services/worker-process.d.ts.map +1 -0
- package/dist/services/worker-process.js +280 -0
- package/dist/services/worker-process.js.map +1 -0
- package/dist/services/worker-service.d.ts +74 -0
- package/dist/services/worker-service.d.ts.map +1 -0
- package/dist/services/worker-service.js +148 -0
- package/dist/services/worker-service.js.map +1 -0
- package/dist/utils/glob.d.ts +15 -0
- package/dist/utils/glob.d.ts.map +1 -0
- package/dist/utils/glob.js +27 -0
- package/dist/utils/glob.js.map +1 -0
- package/dist/utils/math.d.ts +6 -0
- package/dist/utils/math.d.ts.map +1 -0
- package/dist/utils/math.js +21 -0
- package/dist/utils/math.js.map +1 -0
- package/package.json +72 -0
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
import { Context, Effect, Layer, Queue } from "effect";
|
|
2
|
+
import { FileWatcherError, WatcherAlreadyRunningError, WatcherNotRunningError } from "../errors.js";
|
|
3
|
+
/**
|
|
4
|
+
* FileWatcherService watches file system paths and emits events when files are
|
|
5
|
+
* added, changed, or deleted. Events are delivered via an Effect Queue for
|
|
6
|
+
* decoupled, backpressure-aware processing.
|
|
7
|
+
*
|
|
8
|
+
* Used by the telemetry daemon to watch Claude Code transcript files
|
|
9
|
+
* (~/.claude/projects/** /*.jsonl) and trigger the learning extraction pipeline.
|
|
10
|
+
*
|
|
11
|
+
* See DD-015 for the full architecture.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* const program = Effect.gen(function* () {
|
|
16
|
+
* const watcher = yield* FileWatcherService
|
|
17
|
+
* const eventQueue = yield* watcher.getEventQueue()
|
|
18
|
+
*
|
|
19
|
+
* // Start watching
|
|
20
|
+
* yield* watcher.start({
|
|
21
|
+
* patterns: ["~/.claude/projects/** /*.jsonl"],
|
|
22
|
+
* debounceMs: 2000
|
|
23
|
+
* })
|
|
24
|
+
*
|
|
25
|
+
* // Process events
|
|
26
|
+
* while (true) {
|
|
27
|
+
* const event = yield* Queue.take(eventQueue)
|
|
28
|
+
* yield* Effect.log(`File ${event.type}: ${event.path}`)
|
|
29
|
+
* }
|
|
30
|
+
* })
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export class FileWatcherService extends Context.Tag("FileWatcherService")() {
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* No-op implementation for testing or when file watching is disabled.
|
|
37
|
+
* All operations succeed but no actual watching occurs.
|
|
38
|
+
*/
|
|
39
|
+
export const FileWatcherServiceNoop = Layer.scoped(FileWatcherService, Effect.gen(function* () {
|
|
40
|
+
// Create a dummy queue that will never receive events
|
|
41
|
+
const eventQueue = yield* Queue.unbounded();
|
|
42
|
+
return {
|
|
43
|
+
start: () => Effect.void,
|
|
44
|
+
stop: () => Effect.void,
|
|
45
|
+
isRunning: () => Effect.succeed(false),
|
|
46
|
+
getWatchedPaths: () => Effect.succeed([]),
|
|
47
|
+
getEventQueue: () => Effect.succeed(eventQueue),
|
|
48
|
+
status: () => Effect.succeed({
|
|
49
|
+
running: false,
|
|
50
|
+
watchedPaths: [],
|
|
51
|
+
startedAt: null,
|
|
52
|
+
eventsProcessed: 0
|
|
53
|
+
})
|
|
54
|
+
};
|
|
55
|
+
}));
|
|
56
|
+
/**
|
|
57
|
+
* Expand tilde (~) to the user's home directory.
|
|
58
|
+
*/
|
|
59
|
+
const expandTilde = (path) => {
|
|
60
|
+
const { homedir } = require("node:os");
|
|
61
|
+
return path.startsWith("~") ? path.replace(/^~/, homedir()) : path;
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* Extract the base directory from a glob pattern.
|
|
65
|
+
* For "~/.claude/projects/** /*.jsonl", returns the expanded "~/.claude/projects".
|
|
66
|
+
* For paths without globs, returns the path as-is.
|
|
67
|
+
*/
|
|
68
|
+
const extractBaseDir = (pattern) => {
|
|
69
|
+
const expanded = expandTilde(pattern);
|
|
70
|
+
const firstGlobIndex = expanded.search(/[*?[\]{}]/);
|
|
71
|
+
if (firstGlobIndex === -1) {
|
|
72
|
+
return expanded;
|
|
73
|
+
}
|
|
74
|
+
// Find the last path separator before the first glob character
|
|
75
|
+
const beforeGlob = expanded.slice(0, firstGlobIndex);
|
|
76
|
+
const lastSep = Math.max(beforeGlob.lastIndexOf("/"), beforeGlob.lastIndexOf("\\"));
|
|
77
|
+
return lastSep > 0 ? expanded.slice(0, lastSep) : expanded;
|
|
78
|
+
};
|
|
79
|
+
/**
|
|
80
|
+
* Check if a file path matches a glob-like pattern.
|
|
81
|
+
* Simple implementation supporting:
|
|
82
|
+
* - ** for any directory depth
|
|
83
|
+
* - * for any characters in a filename
|
|
84
|
+
*/
|
|
85
|
+
const matchesPattern = (filePath, pattern) => {
|
|
86
|
+
const expanded = expandTilde(pattern);
|
|
87
|
+
// If no glob characters, just check if the path starts with the pattern
|
|
88
|
+
if (!/[*?[\]{}]/.test(expanded)) {
|
|
89
|
+
return filePath.startsWith(expanded);
|
|
90
|
+
}
|
|
91
|
+
// Convert glob pattern to regex
|
|
92
|
+
// Escape special regex chars except * and ?
|
|
93
|
+
let regexStr = expanded
|
|
94
|
+
.replace(/[.+^${}()|[\]\\]/g, "\\$&")
|
|
95
|
+
.replace(/\*\*/g, "<<<GLOBSTAR>>>")
|
|
96
|
+
.replace(/\*/g, "[^/\\\\]*")
|
|
97
|
+
.replace(/<<<GLOBSTAR>>>/g, ".*")
|
|
98
|
+
.replace(/\?/g, ".");
|
|
99
|
+
const regex = new RegExp(`^${regexStr}$`);
|
|
100
|
+
return regex.test(filePath);
|
|
101
|
+
};
|
|
102
|
+
/**
|
|
103
|
+
* Live implementation of FileWatcherService using chokidar.
|
|
104
|
+
*
|
|
105
|
+
* Features:
|
|
106
|
+
* - Uses chokidar for cross-platform file watching
|
|
107
|
+
* - awaitWriteFinish with 2000ms debounce for chunked writes
|
|
108
|
+
* - persistent mode to keep process running
|
|
109
|
+
* - ignoreInitial: false to emit events for existing files
|
|
110
|
+
* - Effect Queue for backpressure-aware event buffering
|
|
111
|
+
* - Supports glob patterns (expands ~ and extracts base directories)
|
|
112
|
+
*/
|
|
113
|
+
export const FileWatcherServiceLive = Layer.scoped(FileWatcherService, Effect.gen(function* () {
|
|
114
|
+
const chokidar = yield* Effect.tryPromise({
|
|
115
|
+
try: () => import("chokidar"),
|
|
116
|
+
catch: (error) => new FileWatcherError({
|
|
117
|
+
reason: "Failed to import chokidar",
|
|
118
|
+
cause: error
|
|
119
|
+
})
|
|
120
|
+
});
|
|
121
|
+
// Create the event queue for delivering file events
|
|
122
|
+
const eventQueue = yield* Queue.unbounded();
|
|
123
|
+
// Mutable state using Effect Ref
|
|
124
|
+
const stateRef = yield* Effect.sync(() => ({
|
|
125
|
+
current: {
|
|
126
|
+
running: false,
|
|
127
|
+
watcher: null,
|
|
128
|
+
watchedPaths: [],
|
|
129
|
+
startedAt: null,
|
|
130
|
+
eventsProcessed: 0
|
|
131
|
+
}
|
|
132
|
+
}));
|
|
133
|
+
const getState = () => stateRef.current;
|
|
134
|
+
const setState = (updater) => {
|
|
135
|
+
stateRef.current = updater(stateRef.current);
|
|
136
|
+
};
|
|
137
|
+
// Cleanup on scope finalization
|
|
138
|
+
yield* Effect.addFinalizer(() => Effect.gen(function* () {
|
|
139
|
+
const state = getState();
|
|
140
|
+
if (state.watcher) {
|
|
141
|
+
yield* Effect.tryPromise({
|
|
142
|
+
try: () => state.watcher.close(),
|
|
143
|
+
catch: () => new Error("cleanup") // Error will be ignored
|
|
144
|
+
}).pipe(Effect.ignore);
|
|
145
|
+
}
|
|
146
|
+
}));
|
|
147
|
+
const start = (config) => Effect.gen(function* () {
|
|
148
|
+
const state = getState();
|
|
149
|
+
if (state.running) {
|
|
150
|
+
return yield* Effect.fail(new WatcherAlreadyRunningError({
|
|
151
|
+
path: state.watchedPaths.join(", ")
|
|
152
|
+
}));
|
|
153
|
+
}
|
|
154
|
+
// Extract base directories from glob patterns
|
|
155
|
+
const expandedPaths = config.patterns.map((p) => expandTilde(p));
|
|
156
|
+
const baseDirs = [...new Set(config.patterns.map(extractBaseDir))];
|
|
157
|
+
// Store original patterns for filtering
|
|
158
|
+
const originalPatterns = config.patterns;
|
|
159
|
+
// Configure chokidar options
|
|
160
|
+
const debounceMs = config.debounceMs ?? 2000;
|
|
161
|
+
const watcherOptions = {
|
|
162
|
+
persistent: true,
|
|
163
|
+
ignoreInitial: config.ignoreInitial ?? false,
|
|
164
|
+
awaitWriteFinish: {
|
|
165
|
+
stabilityThreshold: debounceMs,
|
|
166
|
+
pollInterval: Math.min(100, debounceMs / 10)
|
|
167
|
+
},
|
|
168
|
+
// Use polling interval if specified
|
|
169
|
+
...(config.pollInterval && {
|
|
170
|
+
usePolling: true,
|
|
171
|
+
interval: config.pollInterval
|
|
172
|
+
})
|
|
173
|
+
};
|
|
174
|
+
// Create the watcher
|
|
175
|
+
const watcher = yield* Effect.try({
|
|
176
|
+
try: () => chokidar.watch(baseDirs, watcherOptions),
|
|
177
|
+
catch: (error) => new FileWatcherError({
|
|
178
|
+
reason: "Failed to create chokidar watcher",
|
|
179
|
+
cause: error
|
|
180
|
+
})
|
|
181
|
+
});
|
|
182
|
+
// Set up event handlers
|
|
183
|
+
const handleEvent = (type, path) => {
|
|
184
|
+
// Check if the path matches any of our patterns
|
|
185
|
+
const matches = originalPatterns.some((pattern) => matchesPattern(path, pattern));
|
|
186
|
+
if (!matches)
|
|
187
|
+
return;
|
|
188
|
+
const event = {
|
|
189
|
+
type,
|
|
190
|
+
path,
|
|
191
|
+
timestamp: new Date()
|
|
192
|
+
};
|
|
193
|
+
// Offer event to queue (non-blocking)
|
|
194
|
+
Effect.runFork(Queue.offer(eventQueue, event).pipe(Effect.tap(() => Effect.sync(() => {
|
|
195
|
+
setState((s) => ({ ...s, eventsProcessed: s.eventsProcessed + 1 }));
|
|
196
|
+
}))));
|
|
197
|
+
};
|
|
198
|
+
watcher.on("add", (path) => handleEvent("add", path));
|
|
199
|
+
watcher.on("change", (path) => handleEvent("change", path));
|
|
200
|
+
watcher.on("unlink", (path) => handleEvent("delete", path));
|
|
201
|
+
watcher.on("error", (error) => {
|
|
202
|
+
// Log errors but don't crash - fire and forget error reporting
|
|
203
|
+
Effect.runFork(Effect.logWarning(`File watcher error: ${error}`));
|
|
204
|
+
});
|
|
205
|
+
// Wait for the ready event
|
|
206
|
+
yield* Effect.async((resume) => {
|
|
207
|
+
const timeout = setTimeout(() => {
|
|
208
|
+
resume(Effect.fail(new FileWatcherError({
|
|
209
|
+
reason: "Watcher did not become ready within timeout"
|
|
210
|
+
})));
|
|
211
|
+
}, 30000); // 30 second timeout
|
|
212
|
+
watcher.once("ready", () => {
|
|
213
|
+
clearTimeout(timeout);
|
|
214
|
+
resume(Effect.void);
|
|
215
|
+
});
|
|
216
|
+
watcher.once("error", (error) => {
|
|
217
|
+
clearTimeout(timeout);
|
|
218
|
+
resume(Effect.fail(new FileWatcherError({
|
|
219
|
+
reason: "Watcher failed during initialization",
|
|
220
|
+
cause: error
|
|
221
|
+
})));
|
|
222
|
+
});
|
|
223
|
+
});
|
|
224
|
+
// Update state
|
|
225
|
+
setState(() => ({
|
|
226
|
+
running: true,
|
|
227
|
+
watcher,
|
|
228
|
+
watchedPaths: expandedPaths,
|
|
229
|
+
startedAt: new Date(),
|
|
230
|
+
eventsProcessed: 0
|
|
231
|
+
}));
|
|
232
|
+
});
|
|
233
|
+
const stop = () => Effect.gen(function* () {
|
|
234
|
+
const state = getState();
|
|
235
|
+
if (!state.running || !state.watcher) {
|
|
236
|
+
return yield* Effect.fail(new WatcherNotRunningError({
|
|
237
|
+
path: "no active watcher"
|
|
238
|
+
}));
|
|
239
|
+
}
|
|
240
|
+
// Close the watcher
|
|
241
|
+
yield* Effect.tryPromise({
|
|
242
|
+
try: () => state.watcher.close(),
|
|
243
|
+
catch: (error) => new FileWatcherError({
|
|
244
|
+
reason: "Failed to close chokidar watcher",
|
|
245
|
+
cause: error
|
|
246
|
+
})
|
|
247
|
+
});
|
|
248
|
+
// Update state
|
|
249
|
+
setState(() => ({
|
|
250
|
+
running: false,
|
|
251
|
+
watcher: null,
|
|
252
|
+
watchedPaths: [],
|
|
253
|
+
startedAt: null,
|
|
254
|
+
eventsProcessed: 0
|
|
255
|
+
}));
|
|
256
|
+
});
|
|
257
|
+
const isRunning = () => Effect.sync(() => getState().running);
|
|
258
|
+
const getWatchedPaths = () => Effect.sync(() => getState().watchedPaths);
|
|
259
|
+
const getEventQueue = () => Effect.succeed(eventQueue);
|
|
260
|
+
const status = () => Effect.sync(() => {
|
|
261
|
+
const state = getState();
|
|
262
|
+
return {
|
|
263
|
+
running: state.running,
|
|
264
|
+
watchedPaths: state.watchedPaths,
|
|
265
|
+
startedAt: state.startedAt,
|
|
266
|
+
eventsProcessed: state.eventsProcessed
|
|
267
|
+
};
|
|
268
|
+
});
|
|
269
|
+
return {
|
|
270
|
+
start,
|
|
271
|
+
stop,
|
|
272
|
+
isRunning,
|
|
273
|
+
getWatchedPaths,
|
|
274
|
+
getEventQueue,
|
|
275
|
+
status
|
|
276
|
+
};
|
|
277
|
+
}));
|
|
278
|
+
//# sourceMappingURL=file-watcher-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-watcher-service.js","sourceRoot":"","sources":["../../src/services/file-watcher-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { Context, Effect, Layer } from "effect";
|
|
2
|
+
import { EdgeService } from "./edge-service.js";
|
|
3
|
+
import { LearningRepository } from "../repo/learning-repo.js";
|
|
4
|
+
import { AnchorRepository } from "../repo/anchor-repo.js";
|
|
5
|
+
import { DatabaseError, ValidationError } from "../errors.js";
|
|
6
|
+
import type { Learning, EdgeType, LearningId } from "@jamesaphoenix/tx-types";
|
|
7
|
+
/**
|
|
8
|
+
* Seed learning with an initial score for graph expansion.
|
|
9
|
+
* Typically the RRF score from hybrid search.
|
|
10
|
+
*/
|
|
11
|
+
export interface SeedLearning {
|
|
12
|
+
readonly learning: Learning;
|
|
13
|
+
readonly score: number;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Expanded learning with graph traversal metadata.
|
|
17
|
+
*/
|
|
18
|
+
export interface ExpandedLearning {
|
|
19
|
+
readonly learning: Learning;
|
|
20
|
+
/** Number of hops from the nearest seed (0 = direct seed) */
|
|
21
|
+
readonly hops: number;
|
|
22
|
+
/** Score after applying weight decay per hop */
|
|
23
|
+
readonly decayedScore: number;
|
|
24
|
+
/** Path of learning IDs from seed to this learning */
|
|
25
|
+
readonly path: readonly LearningId[];
|
|
26
|
+
/** Edge type that connected this learning (null for seeds) */
|
|
27
|
+
readonly sourceEdge: EdgeType | null;
|
|
28
|
+
/** The edge weight that led to this learning (null for seeds) */
|
|
29
|
+
readonly edgeWeight: number | null;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Filter configuration for edge types during graph traversal.
|
|
33
|
+
* Supports include/exclude lists and per-hop overrides.
|
|
34
|
+
*/
|
|
35
|
+
export interface EdgeTypeFilter {
|
|
36
|
+
/** Only traverse these edge types (mutually exclusive with exclude for same types) */
|
|
37
|
+
readonly include?: readonly EdgeType[];
|
|
38
|
+
/** Traverse all edge types except these (mutually exclusive with include for same types) */
|
|
39
|
+
readonly exclude?: readonly EdgeType[];
|
|
40
|
+
/** Depth-specific filter overrides (1-indexed, matching hop number) */
|
|
41
|
+
readonly perHop?: Readonly<Record<number, EdgeTypeFilter>>;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Options for graph expansion algorithm.
|
|
45
|
+
*/
|
|
46
|
+
export interface GraphExpansionOptions {
|
|
47
|
+
/** Maximum traversal depth (default: 2) */
|
|
48
|
+
readonly depth?: number;
|
|
49
|
+
/** Score decay factor per hop (default: 0.7) */
|
|
50
|
+
readonly decayFactor?: number;
|
|
51
|
+
/** Maximum nodes to return (default: 100) */
|
|
52
|
+
readonly maxNodes?: number;
|
|
53
|
+
/** Filter by specific edge types (default: all types).
|
|
54
|
+
* Accepts either a simple array for backwards compatibility or EdgeTypeFilter for advanced filtering. */
|
|
55
|
+
readonly edgeTypes?: EdgeTypeFilter | readonly EdgeType[];
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Result of graph expansion operation.
|
|
59
|
+
*/
|
|
60
|
+
export interface GraphExpansionResult {
|
|
61
|
+
/** Seeds that were provided as input */
|
|
62
|
+
readonly seeds: readonly ExpandedLearning[];
|
|
63
|
+
/** Learnings discovered through graph expansion (excludes seeds) */
|
|
64
|
+
readonly expanded: readonly ExpandedLearning[];
|
|
65
|
+
/** Total learnings (seeds + expanded) */
|
|
66
|
+
readonly all: readonly ExpandedLearning[];
|
|
67
|
+
/** Statistics about the expansion */
|
|
68
|
+
readonly stats: {
|
|
69
|
+
readonly seedCount: number;
|
|
70
|
+
readonly expandedCount: number;
|
|
71
|
+
readonly maxDepthReached: number;
|
|
72
|
+
readonly nodesVisited: number;
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Options for file-based graph expansion.
|
|
77
|
+
* Expands from files via IMPORTS and CO_CHANGES_WITH edges to find related learnings.
|
|
78
|
+
* See PRD-016 for specification.
|
|
79
|
+
*/
|
|
80
|
+
export interface FileExpansionOptions {
|
|
81
|
+
/** Maximum traversal depth for file relationships (default: 2) */
|
|
82
|
+
readonly depth?: number;
|
|
83
|
+
/** Score decay factor per hop (default: 0.7) */
|
|
84
|
+
readonly decayFactor?: number;
|
|
85
|
+
/** Maximum learnings to return (default: 100) */
|
|
86
|
+
readonly maxNodes?: number;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* A learning discovered through file-based graph expansion.
|
|
90
|
+
* Contains metadata about how the learning was found via file relationships.
|
|
91
|
+
*/
|
|
92
|
+
export interface FileExpandedLearning {
|
|
93
|
+
readonly learning: Learning;
|
|
94
|
+
/** The source file path that led to this learning */
|
|
95
|
+
readonly sourceFile: string;
|
|
96
|
+
/** Number of hops from the source file (0 = directly anchored to input file) */
|
|
97
|
+
readonly hops: number;
|
|
98
|
+
/** Score after applying weight decay per hop */
|
|
99
|
+
readonly decayedScore: number;
|
|
100
|
+
/** Edge type that connected this learning (ANCHORED_TO for direct, IMPORTS or CO_CHANGES_WITH for expanded) */
|
|
101
|
+
readonly sourceEdge: EdgeType;
|
|
102
|
+
/** Edge weight (null for directly anchored learnings, weight value for IMPORTS/CO_CHANGES_WITH) */
|
|
103
|
+
readonly edgeWeight: number | null;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Result of file-based graph expansion operation.
|
|
107
|
+
*/
|
|
108
|
+
export interface FileExpansionResult {
|
|
109
|
+
/** Learnings directly anchored to the input files (hop 0) */
|
|
110
|
+
readonly anchored: readonly FileExpandedLearning[];
|
|
111
|
+
/** Learnings discovered through file expansion (hops > 0 via IMPORTS/CO_CHANGES_WITH) */
|
|
112
|
+
readonly expanded: readonly FileExpandedLearning[];
|
|
113
|
+
/** All learnings (anchored + expanded), sorted by decayedScore */
|
|
114
|
+
readonly all: readonly FileExpandedLearning[];
|
|
115
|
+
/** Statistics about the expansion */
|
|
116
|
+
readonly stats: {
|
|
117
|
+
readonly inputFileCount: number;
|
|
118
|
+
readonly anchoredCount: number;
|
|
119
|
+
readonly expandedCount: number;
|
|
120
|
+
readonly maxDepthReached: number;
|
|
121
|
+
readonly filesVisited: number;
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
declare const GraphExpansionService_base: Context.TagClass<GraphExpansionService, "GraphExpansionService", {
|
|
125
|
+
/**
|
|
126
|
+
* Expand from seed learnings through the knowledge graph.
|
|
127
|
+
* Uses BFS traversal with weight decay per hop.
|
|
128
|
+
* Bidirectional traversal (both incoming and outgoing edges).
|
|
129
|
+
*
|
|
130
|
+
* @param seeds - Learnings to start expansion from, with initial scores
|
|
131
|
+
* @param options - Expansion configuration (depth, decay, limits)
|
|
132
|
+
* @returns Seeds and expanded learnings with traversal metadata
|
|
133
|
+
*/
|
|
134
|
+
readonly expand: (seeds: readonly SeedLearning[], options?: GraphExpansionOptions) => Effect.Effect<GraphExpansionResult, ValidationError | DatabaseError>;
|
|
135
|
+
/**
|
|
136
|
+
* Expand from file paths to find related learnings.
|
|
137
|
+
* First finds learnings ANCHORED_TO the input files, then expands via
|
|
138
|
+
* IMPORTS and CO_CHANGES_WITH edges to find learnings anchored to related files.
|
|
139
|
+
*
|
|
140
|
+
* @param files - File paths to expand from (e.g., ["src/auth.ts", "src/jwt.ts"])
|
|
141
|
+
* @param options - Expansion configuration (depth, decay, limits)
|
|
142
|
+
* @returns Anchored and expanded learnings with file relationship metadata
|
|
143
|
+
*/
|
|
144
|
+
readonly expandFromFiles: (files: readonly string[], options?: FileExpansionOptions) => Effect.Effect<FileExpansionResult, ValidationError | DatabaseError>;
|
|
145
|
+
}>;
|
|
146
|
+
export declare class GraphExpansionService extends GraphExpansionService_base {
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Noop implementation that returns seeds without expansion.
|
|
150
|
+
* Used when graph expansion is disabled or for testing.
|
|
151
|
+
*/
|
|
152
|
+
export declare const GraphExpansionServiceNoop: Layer.Layer<GraphExpansionService, never, never>;
|
|
153
|
+
export declare const GraphExpansionServiceLive: Layer.Layer<GraphExpansionService, never, LearningRepository | AnchorRepository | EdgeService>;
|
|
154
|
+
export {};
|
|
155
|
+
//# sourceMappingURL=graph-expansion.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph-expansion.d.ts","sourceRoot":"","sources":["../../src/services/graph-expansion.ts"],"names":[],"mappings":"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"}
|