claude-brain 0.14.2 → 0.14.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 +191 -191
- package/VERSION +1 -1
- package/assets/CLAUDE-unified.md +11 -11
- package/assets/CLAUDE.md +11 -11
- package/bunfig.toml +8 -8
- package/package.json +80 -80
- package/packs/backend/node.json +173 -173
- package/packs/core/javascript.json +176 -176
- package/packs/core/typescript.json +222 -222
- package/packs/frontend/react.json +254 -254
- package/packs/meta/testing.json +172 -172
- package/src/automation/auto-context.ts +240 -240
- package/src/automation/decision-detector.ts +452 -452
- package/src/automation/index.ts +11 -11
- package/src/automation/phase12-manager.ts +456 -456
- package/src/automation/proactive-recall.ts +373 -373
- package/src/automation/project-detector.ts +310 -310
- package/src/automation/repo-scanner.ts +205 -205
- package/src/cli/auto-setup.ts +82 -82
- package/src/cli/bin.ts +202 -202
- package/src/cli/commands/chroma.ts +573 -573
- package/src/cli/commands/git-hook.ts +189 -189
- package/src/cli/commands/hooks.ts +213 -213
- package/src/cli/commands/init.ts +122 -122
- package/src/cli/commands/install-mcp.ts +92 -92
- package/src/cli/commands/pack.ts +197 -197
- package/src/cli/commands/serve.ts +167 -167
- package/src/cli/commands/start.ts +42 -42
- package/src/cli/commands/uninstall-mcp.ts +41 -41
- package/src/cli/commands/update.ts +121 -121
- package/src/cli/diagnose.ts +4 -4
- package/src/cli/health-check.ts +4 -4
- package/src/cli/migrate-chroma.ts +106 -106
- package/src/cli/setup.ts +4 -4
- package/src/cli/ui/animations.ts +80 -80
- package/src/cli/ui/components.ts +82 -82
- package/src/cli/ui/index.ts +4 -4
- package/src/cli/ui/logo.ts +36 -36
- package/src/cli/ui/theme.ts +55 -55
- package/src/config/defaults.ts +50 -50
- package/src/config/home.ts +55 -55
- package/src/config/index.ts +7 -7
- package/src/config/loader.ts +166 -166
- package/src/config/migration.ts +76 -76
- package/src/config/schema.ts +360 -360
- package/src/config/validator.ts +184 -184
- package/src/config/watcher.ts +86 -86
- package/src/context/assembler.ts +398 -398
- package/src/context/cache-manager.ts +101 -101
- package/src/context/formatter.ts +84 -84
- package/src/context/hierarchy.ts +85 -85
- package/src/context/index.ts +83 -83
- package/src/context/progress-tracker.ts +174 -174
- package/src/context/standards-manager.ts +287 -287
- package/src/context/types.ts +252 -252
- package/src/context/validator.ts +58 -58
- package/src/diagnostics/index.ts +123 -123
- package/src/health/index.ts +229 -229
- package/src/hooks/brain-hook.ts +112 -112
- package/src/hooks/capture.ts +168 -168
- package/src/hooks/deduplicator.ts +72 -72
- package/src/hooks/git-capture.ts +109 -109
- package/src/hooks/git-hook-installer.ts +207 -207
- package/src/hooks/index.ts +20 -20
- package/src/hooks/installer.ts +191 -194
- package/src/hooks/passive-classifier.ts +366 -366
- package/src/hooks/queue.ts +129 -129
- package/src/hooks/session-tracker.ts +275 -275
- package/src/hooks/types.ts +47 -47
- package/src/index.ts +7 -7
- package/src/intelligence/cross-project/affinity.ts +162 -162
- package/src/intelligence/cross-project/generalizer.ts +283 -283
- package/src/intelligence/cross-project/index.ts +13 -13
- package/src/intelligence/cross-project/transfer.ts +201 -201
- package/src/intelligence/index.ts +24 -24
- package/src/intelligence/optimization/index.ts +10 -10
- package/src/intelligence/optimization/precompute.ts +202 -202
- package/src/intelligence/optimization/semantic-cache.ts +207 -207
- package/src/intelligence/prediction/context-anticipator.ts +198 -198
- package/src/intelligence/prediction/decision-predictor.ts +184 -184
- package/src/intelligence/prediction/index.ts +13 -13
- package/src/intelligence/prediction/recommender.ts +268 -268
- package/src/intelligence/reasoning/chain-retrieval.ts +247 -247
- package/src/intelligence/reasoning/counterfactual.ts +248 -248
- package/src/intelligence/reasoning/index.ts +13 -13
- package/src/intelligence/reasoning/synthesizer.ts +169 -169
- package/src/intelligence/temporal/evolution.ts +197 -197
- package/src/intelligence/temporal/index.ts +16 -16
- package/src/intelligence/temporal/query-processor.ts +190 -190
- package/src/intelligence/temporal/timeline.ts +259 -259
- package/src/intelligence/temporal/trends.ts +263 -263
- package/src/knowledge/entity-extractor.ts +416 -416
- package/src/knowledge/graph/builder.ts +185 -185
- package/src/knowledge/graph/linker.ts +201 -201
- package/src/knowledge/graph/memory-graph.ts +359 -359
- package/src/knowledge/graph/schema.ts +99 -99
- package/src/knowledge/graph/search.ts +168 -168
- package/src/knowledge/relationship-extractor.ts +108 -108
- package/src/memory/chroma/client.ts +174 -174
- package/src/memory/chroma/collection-manager.ts +94 -94
- package/src/memory/chroma/config.ts +57 -57
- package/src/memory/chroma/embeddings.ts +153 -153
- package/src/memory/chroma/index.ts +82 -82
- package/src/memory/chroma/migration.ts +270 -270
- package/src/memory/chroma/schemas.ts +69 -69
- package/src/memory/chroma/search.ts +315 -315
- package/src/memory/chroma/store.ts +741 -741
- package/src/memory/consolidation/archiver.ts +164 -164
- package/src/memory/consolidation/merger.ts +186 -186
- package/src/memory/consolidation/scorer.ts +138 -138
- package/src/memory/context-builder.ts +236 -236
- package/src/memory/database.ts +169 -169
- package/src/memory/embedding-utils.ts +156 -156
- package/src/memory/embeddings.ts +226 -226
- package/src/memory/episodic/detector.ts +108 -108
- package/src/memory/episodic/manager.ts +351 -351
- package/src/memory/episodic/summarizer.ts +179 -179
- package/src/memory/episodic/types.ts +52 -52
- package/src/memory/index.ts +582 -582
- package/src/memory/knowledge-extractor.ts +455 -455
- package/src/memory/learning.ts +378 -378
- package/src/memory/patterns.ts +396 -396
- package/src/memory/schema.ts +88 -88
- package/src/memory/search.ts +309 -309
- package/src/memory/store.ts +787 -787
- package/src/memory/types.ts +121 -121
- package/src/orchestrator/coordinator.ts +272 -272
- package/src/orchestrator/decision-logger.ts +228 -228
- package/src/orchestrator/event-emitter.ts +198 -198
- package/src/orchestrator/event-queue.ts +184 -184
- package/src/orchestrator/handlers/base-handler.ts +70 -70
- package/src/orchestrator/handlers/context-handler.ts +73 -73
- package/src/orchestrator/handlers/decision-handler.ts +204 -204
- package/src/orchestrator/handlers/index.ts +10 -10
- package/src/orchestrator/handlers/status-handler.ts +131 -131
- package/src/orchestrator/handlers/task-handler.ts +171 -171
- package/src/orchestrator/index.ts +275 -275
- package/src/orchestrator/task-parser.ts +284 -284
- package/src/orchestrator/types.ts +98 -98
- package/src/packs/index.ts +9 -9
- package/src/packs/loader.ts +134 -134
- package/src/packs/manager.ts +204 -204
- package/src/packs/ranker.ts +78 -78
- package/src/packs/types.ts +81 -81
- package/src/phase12/index.ts +5 -5
- package/src/retrieval/bm25/index.ts +300 -300
- package/src/retrieval/bm25/tokenizer.ts +184 -184
- package/src/retrieval/feedback/adaptive.ts +223 -223
- package/src/retrieval/feedback/index.ts +16 -16
- package/src/retrieval/feedback/metrics.ts +223 -223
- package/src/retrieval/feedback/store.ts +283 -283
- package/src/retrieval/fusion/index.ts +194 -194
- package/src/retrieval/fusion/rrf.ts +163 -163
- package/src/retrieval/index.ts +12 -12
- package/src/retrieval/pipeline.ts +375 -375
- package/src/retrieval/query/expander.ts +198 -198
- package/src/retrieval/query/index.ts +27 -27
- package/src/retrieval/query/intent-classifier.ts +236 -236
- package/src/retrieval/query/temporal-parser.ts +295 -295
- package/src/retrieval/reranker/index.ts +188 -188
- package/src/retrieval/reranker/model.ts +95 -95
- package/src/retrieval/service.ts +125 -125
- package/src/retrieval/types.ts +162 -162
- package/src/routing/entity-extractor.ts +428 -428
- package/src/routing/intent-classifier.ts +436 -436
- package/src/routing/response-filter.ts +258 -254
- package/src/routing/router.ts +1322 -1314
- package/src/routing/search-engine.ts +475 -475
- package/src/routing/types.ts +94 -84
- package/src/scripts/health-check.ts +118 -118
- package/src/scripts/setup.ts +122 -122
- package/src/server/handlers/call-tool.ts +156 -156
- package/src/server/handlers/index.ts +9 -9
- package/src/server/handlers/list-tools.ts +35 -35
- package/src/server/handlers/tools/analyze-decision-evolution.ts +151 -151
- package/src/server/handlers/tools/auto-remember.ts +200 -200
- package/src/server/handlers/tools/brain.ts +85 -85
- package/src/server/handlers/tools/create-project.ts +135 -135
- package/src/server/handlers/tools/detect-trends.ts +144 -144
- package/src/server/handlers/tools/find-cross-project-patterns.ts +168 -168
- package/src/server/handlers/tools/get-activity-log.ts +194 -194
- package/src/server/handlers/tools/get-code-standards.ts +124 -124
- package/src/server/handlers/tools/get-corrections.ts +154 -154
- package/src/server/handlers/tools/get-decision-timeline.ts +172 -172
- package/src/server/handlers/tools/get-episode.ts +103 -103
- package/src/server/handlers/tools/get-patterns.ts +158 -158
- package/src/server/handlers/tools/get-phase12-status.ts +63 -63
- package/src/server/handlers/tools/get-project-context.ts +75 -75
- package/src/server/handlers/tools/get-recommendations.ts +145 -145
- package/src/server/handlers/tools/index.ts +31 -31
- package/src/server/handlers/tools/init-project.ts +757 -757
- package/src/server/handlers/tools/list-episodes.ts +90 -90
- package/src/server/handlers/tools/list-projects.ts +125 -125
- package/src/server/handlers/tools/rate-memory.ts +101 -101
- package/src/server/handlers/tools/recall-similar.ts +87 -87
- package/src/server/handlers/tools/recognize-pattern.ts +126 -126
- package/src/server/handlers/tools/record-correction.ts +125 -125
- package/src/server/handlers/tools/remember-decision.ts +153 -153
- package/src/server/handlers/tools/schemas.ts +253 -253
- package/src/server/handlers/tools/search-knowledge-graph.ts +102 -102
- package/src/server/handlers/tools/smart-context.ts +146 -146
- package/src/server/handlers/tools/update-progress.ts +131 -131
- package/src/server/handlers/tools/what-if-analysis.ts +135 -135
- package/src/server/http-api.ts +693 -693
- package/src/server/index.ts +40 -40
- package/src/server/mcp-server.ts +283 -283
- package/src/server/providers/index.ts +7 -7
- package/src/server/providers/prompts.ts +327 -327
- package/src/server/providers/resources.ts +622 -622
- package/src/server/services.ts +468 -468
- package/src/server/types.ts +39 -39
- package/src/server/utils/error-handler.ts +155 -155
- package/src/server/utils/index.ts +13 -13
- package/src/server/utils/memory-indicator.ts +83 -83
- package/src/server/utils/request-context.ts +122 -122
- package/src/server/utils/response-formatter.ts +129 -124
- package/src/server/utils/validators.ts +210 -210
- package/src/setup/index.ts +48 -48
- package/src/setup/wizard.ts +461 -461
- package/src/tools/index.ts +24 -24
- package/src/tools/registry.ts +115 -115
- package/src/tools/schemas.test.ts +30 -30
- package/src/tools/schemas.ts +617 -617
- package/src/tools/types.ts +412 -412
- package/src/utils/circuit-breaker.ts +130 -130
- package/src/utils/cleanup.ts +34 -34
- package/src/utils/error-handler.ts +132 -132
- package/src/utils/error-messages.ts +60 -60
- package/src/utils/fallback.ts +45 -45
- package/src/utils/index.ts +54 -54
- package/src/utils/logger-utils.ts +80 -80
- package/src/utils/logger.ts +88 -88
- package/src/utils/phase12-helper.ts +56 -56
- package/src/utils/retry.ts +94 -94
- package/src/utils/timing.ts +47 -47
- package/src/utils/transaction.ts +63 -63
- package/src/vault/frontmatter.ts +264 -264
- package/src/vault/index.ts +318 -318
- package/src/vault/paths.ts +106 -106
- package/src/vault/query.ts +422 -422
- package/src/vault/reader.ts +264 -264
- package/src/vault/templates.ts +186 -186
- package/src/vault/types.ts +73 -73
- package/src/vault/watcher.ts +277 -277
- package/src/vault/writer.ts +413 -413
- package/tsconfig.json +30 -30
package/src/vault/index.ts
CHANGED
|
@@ -1,318 +1,318 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Vault Integration Module
|
|
3
|
-
* Barrel exports and VaultManager convenience class
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import fs from 'fs/promises'
|
|
7
|
-
import type { Logger } from 'pino'
|
|
8
|
-
import type { VaultPaths, VaultConfig, MarkdownFile, Frontmatter } from './types'
|
|
9
|
-
import { VaultPathUtils } from './paths'
|
|
10
|
-
import { VaultReader } from './reader'
|
|
11
|
-
import { VaultWriter } from './writer'
|
|
12
|
-
import { VaultWatcher, type FileChangeEvent } from './watcher'
|
|
13
|
-
import { VaultQuery, type QueryOptions, type QueryResult } from './query'
|
|
14
|
-
import { FrontmatterUtils } from './frontmatter'
|
|
15
|
-
|
|
16
|
-
// Re-export all types
|
|
17
|
-
export * from './types'
|
|
18
|
-
export * from './paths'
|
|
19
|
-
export * from './templates'
|
|
20
|
-
export * from './reader'
|
|
21
|
-
export * from './writer'
|
|
22
|
-
export * from './watcher'
|
|
23
|
-
export * from './query'
|
|
24
|
-
export * from './frontmatter'
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* VaultManager combines all vault functionality into a single interface
|
|
28
|
-
*/
|
|
29
|
-
export class VaultManager {
|
|
30
|
-
readonly reader: VaultReader
|
|
31
|
-
readonly writer: VaultWriter
|
|
32
|
-
readonly watcher: VaultWatcher
|
|
33
|
-
readonly query: VaultQuery
|
|
34
|
-
readonly paths: VaultPaths
|
|
35
|
-
private logger: Logger
|
|
36
|
-
private config: VaultConfig
|
|
37
|
-
|
|
38
|
-
constructor(
|
|
39
|
-
vaultRoot: string,
|
|
40
|
-
logger: Logger,
|
|
41
|
-
config: Partial<VaultConfig> = {}
|
|
42
|
-
) {
|
|
43
|
-
this.config = {
|
|
44
|
-
root: vaultRoot,
|
|
45
|
-
backupDir: config.backupDir ?? './data/backups',
|
|
46
|
-
cacheEnabled: config.cacheEnabled ?? true,
|
|
47
|
-
watchEnabled: config.watchEnabled ?? true,
|
|
48
|
-
debounceMs: config.debounceMs ?? 500
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
this.logger = logger.child({ component: 'vault-manager' })
|
|
52
|
-
this.paths = VaultPathUtils.getVaultPaths(vaultRoot)
|
|
53
|
-
this.reader = new VaultReader(logger, {
|
|
54
|
-
maxCacheSize: 100,
|
|
55
|
-
cacheMaxAge: 5 * 60 * 1000
|
|
56
|
-
})
|
|
57
|
-
this.writer = new VaultWriter(logger, this.config.backupDir)
|
|
58
|
-
this.watcher = new VaultWatcher(logger, this.config.debounceMs)
|
|
59
|
-
this.query = new VaultQuery(this.reader, logger)
|
|
60
|
-
|
|
61
|
-
// Wire up watcher to invalidate cache on file changes
|
|
62
|
-
this.watcher.on('change', (event: FileChangeEvent) => {
|
|
63
|
-
this.reader.invalidateCache(event.path)
|
|
64
|
-
this.logger.debug({ event }, 'Cache invalidated due to file change')
|
|
65
|
-
})
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Initialize vault (create directories if needed)
|
|
70
|
-
*/
|
|
71
|
-
async initialize(): Promise<void> {
|
|
72
|
-
const dirs = [
|
|
73
|
-
this.paths.projects,
|
|
74
|
-
this.paths.global,
|
|
75
|
-
this.paths.templates,
|
|
76
|
-
this.paths.memory
|
|
77
|
-
]
|
|
78
|
-
|
|
79
|
-
for (const dir of dirs) {
|
|
80
|
-
await fs.mkdir(dir, { recursive: true })
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
this.logger.info({ paths: this.paths }, 'Vault initialized')
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Start watching vault for changes
|
|
88
|
-
*/
|
|
89
|
-
startWatching(): void {
|
|
90
|
-
if (!this.config.watchEnabled) {
|
|
91
|
-
this.logger.warn('File watching is disabled')
|
|
92
|
-
return
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// Refresh file states before watching
|
|
96
|
-
this.watcher.refreshFileStates(this.paths.projects)
|
|
97
|
-
this.watcher.watch(this.paths.projects, true)
|
|
98
|
-
this.watcher.watch(this.paths.global, true)
|
|
99
|
-
|
|
100
|
-
this.logger.info('Started watching vault')
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Stop watching vault
|
|
105
|
-
*/
|
|
106
|
-
stopWatching(): void {
|
|
107
|
-
this.watcher.unwatchAll()
|
|
108
|
-
this.logger.info('Stopped watching vault')
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Get project paths for a specific project
|
|
113
|
-
*/
|
|
114
|
-
getProjectPaths(projectName: string) {
|
|
115
|
-
return VaultPathUtils.getProjectPaths(this.config.root, projectName)
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* Create a new project
|
|
120
|
-
*/
|
|
121
|
-
async createProject(projectName: string): Promise<void> {
|
|
122
|
-
const normalizedName = VaultPathUtils.normalizeProjectName(projectName)
|
|
123
|
-
|
|
124
|
-
if (!VaultPathUtils.isValidProjectName(normalizedName)) {
|
|
125
|
-
throw new Error(`Invalid project name: ${projectName}`)
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
const projectPaths = this.getProjectPaths(normalizedName)
|
|
129
|
-
|
|
130
|
-
// Check if project already exists
|
|
131
|
-
if (await this.reader.fileExists(projectPaths.context)) {
|
|
132
|
-
throw new Error(`Project already exists: ${normalizedName}`)
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
await this.writer.createProjectStructure(projectPaths.root, normalizedName)
|
|
136
|
-
this.logger.info({ projectName: normalizedName }, 'Project created')
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Get project context
|
|
141
|
-
*/
|
|
142
|
-
async getProjectContext(projectName: string): Promise<MarkdownFile | null> {
|
|
143
|
-
const projectPaths = this.getProjectPaths(projectName)
|
|
144
|
-
|
|
145
|
-
try {
|
|
146
|
-
return await this.reader.readMarkdownFile(projectPaths.context)
|
|
147
|
-
} catch {
|
|
148
|
-
return null
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* Update project progress
|
|
154
|
-
*/
|
|
155
|
-
async updateProgress(
|
|
156
|
-
projectName: string,
|
|
157
|
-
updates: {
|
|
158
|
-
status?: string
|
|
159
|
-
currentPhase?: string
|
|
160
|
-
completionPercentage?: number
|
|
161
|
-
content?: string
|
|
162
|
-
}
|
|
163
|
-
): Promise<void> {
|
|
164
|
-
const projectPaths = this.getProjectPaths(projectName)
|
|
165
|
-
|
|
166
|
-
const frontmatterUpdates: Partial<Frontmatter> = {}
|
|
167
|
-
if (updates.status) frontmatterUpdates.status = updates.status
|
|
168
|
-
if (updates.currentPhase) frontmatterUpdates.current_phase = updates.currentPhase
|
|
169
|
-
if (updates.completionPercentage !== undefined) {
|
|
170
|
-
frontmatterUpdates.completion_percentage = updates.completionPercentage
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
await this.writer.updateFrontmatter(projectPaths.progress, frontmatterUpdates)
|
|
174
|
-
|
|
175
|
-
if (updates.content) {
|
|
176
|
-
await this.writer.appendContent(projectPaths.progress, updates.content)
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
this.logger.info({ projectName, updates }, 'Progress updated')
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
/**
|
|
183
|
-
* Add a decision to the decision log
|
|
184
|
-
*/
|
|
185
|
-
async addDecision(
|
|
186
|
-
projectName: string,
|
|
187
|
-
decision: {
|
|
188
|
-
title: string
|
|
189
|
-
context: string
|
|
190
|
-
decision: string
|
|
191
|
-
consequences: string
|
|
192
|
-
status?: string
|
|
193
|
-
}
|
|
194
|
-
): Promise<void> {
|
|
195
|
-
const projectPaths = this.getProjectPaths(projectName)
|
|
196
|
-
|
|
197
|
-
// Read current decisions to get count
|
|
198
|
-
const decisionsFile = await this.reader.readMarkdownFile(projectPaths.decisions)
|
|
199
|
-
const currentCount = FrontmatterUtils.getDecisionCount(decisionsFile.frontmatter)
|
|
200
|
-
const newCount = currentCount + 1
|
|
201
|
-
|
|
202
|
-
// Format the decision entry
|
|
203
|
-
const today = new Date().toISOString().split('T')[0]
|
|
204
|
-
const decisionEntry = `
|
|
205
|
-
## Decision ${newCount}: ${decision.title}
|
|
206
|
-
|
|
207
|
-
**Date:** ${today}
|
|
208
|
-
**Status:** ${decision.status || 'accepted'}
|
|
209
|
-
**Context:** ${decision.context}
|
|
210
|
-
|
|
211
|
-
### Decision
|
|
212
|
-
${decision.decision}
|
|
213
|
-
|
|
214
|
-
### Consequences
|
|
215
|
-
${decision.consequences}
|
|
216
|
-
|
|
217
|
-
---`
|
|
218
|
-
|
|
219
|
-
// Update frontmatter with new count
|
|
220
|
-
await this.writer.updateFrontmatter(projectPaths.decisions, {
|
|
221
|
-
decision_count: newCount,
|
|
222
|
-
last_updated: today
|
|
223
|
-
})
|
|
224
|
-
|
|
225
|
-
// Append the decision
|
|
226
|
-
await this.writer.appendContent(projectPaths.decisions, decisionEntry)
|
|
227
|
-
|
|
228
|
-
this.logger.info(
|
|
229
|
-
{ projectName, decisionNumber: newCount, title: decision.title },
|
|
230
|
-
'Decision added'
|
|
231
|
-
)
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
/**
|
|
235
|
-
* Search across the vault
|
|
236
|
-
*/
|
|
237
|
-
async search(options: QueryOptions): Promise<QueryResult[]> {
|
|
238
|
-
const { results } = await this.query.query(this.config.root, options)
|
|
239
|
-
return results
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
/**
|
|
243
|
-
* Get all projects
|
|
244
|
-
*/
|
|
245
|
-
async listProjects(): Promise<string[]> {
|
|
246
|
-
return this.reader.getProjectDirectories(this.paths.projects)
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
/**
|
|
250
|
-
* Get project metadata
|
|
251
|
-
*/
|
|
252
|
-
async getProjectMetadata(projectName: string): Promise<{
|
|
253
|
-
name: string
|
|
254
|
-
status: string
|
|
255
|
-
techStack: string[]
|
|
256
|
-
tags: string[]
|
|
257
|
-
currentPhase: string
|
|
258
|
-
completionPercentage: number
|
|
259
|
-
} | null> {
|
|
260
|
-
const context = await this.getProjectContext(projectName)
|
|
261
|
-
if (!context) return null
|
|
262
|
-
|
|
263
|
-
const projectPaths = this.getProjectPaths(projectName)
|
|
264
|
-
let progress: MarkdownFile | null = null
|
|
265
|
-
|
|
266
|
-
try {
|
|
267
|
-
progress = await this.reader.readMarkdownFile(projectPaths.progress)
|
|
268
|
-
} catch {
|
|
269
|
-
// Progress file might not exist
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
return {
|
|
273
|
-
name: projectName,
|
|
274
|
-
status: FrontmatterUtils.getStatus(context.frontmatter) || 'unknown',
|
|
275
|
-
techStack: FrontmatterUtils.getTechStack(context.frontmatter),
|
|
276
|
-
tags: FrontmatterUtils.getTags(context.frontmatter),
|
|
277
|
-
currentPhase: progress
|
|
278
|
-
? FrontmatterUtils.getCurrentPhase(progress.frontmatter) || 'unknown'
|
|
279
|
-
: 'unknown',
|
|
280
|
-
completionPercentage: progress
|
|
281
|
-
? FrontmatterUtils.getCompletionPercentage(progress.frontmatter)
|
|
282
|
-
: 0
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
/**
|
|
287
|
-
* Cleanup resources
|
|
288
|
-
*/
|
|
289
|
-
async cleanup(): Promise<void> {
|
|
290
|
-
this.stopWatching()
|
|
291
|
-
this.reader.clearCache()
|
|
292
|
-
|
|
293
|
-
// Clean old backups
|
|
294
|
-
await this.writer.cleanOldBackups()
|
|
295
|
-
|
|
296
|
-
this.logger.info('Vault manager cleaned up')
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
/**
|
|
300
|
-
* Get vault statistics
|
|
301
|
-
*/
|
|
302
|
-
async getStats(): Promise<{
|
|
303
|
-
projectCount: number
|
|
304
|
-
totalFiles: number
|
|
305
|
-
cacheStats: { size: number; files: string[] }
|
|
306
|
-
watcherStatus: { watching: string[]; activeDebounces: number }
|
|
307
|
-
}> {
|
|
308
|
-
const projects = await this.listProjects()
|
|
309
|
-
const allFiles = await this.reader.readDirectory(this.paths.projects, true)
|
|
310
|
-
|
|
311
|
-
return {
|
|
312
|
-
projectCount: projects.length,
|
|
313
|
-
totalFiles: allFiles.length,
|
|
314
|
-
cacheStats: this.reader.getCacheStats(),
|
|
315
|
-
watcherStatus: this.watcher.getStatus()
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Vault Integration Module
|
|
3
|
+
* Barrel exports and VaultManager convenience class
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import fs from 'fs/promises'
|
|
7
|
+
import type { Logger } from 'pino'
|
|
8
|
+
import type { VaultPaths, VaultConfig, MarkdownFile, Frontmatter } from './types'
|
|
9
|
+
import { VaultPathUtils } from './paths'
|
|
10
|
+
import { VaultReader } from './reader'
|
|
11
|
+
import { VaultWriter } from './writer'
|
|
12
|
+
import { VaultWatcher, type FileChangeEvent } from './watcher'
|
|
13
|
+
import { VaultQuery, type QueryOptions, type QueryResult } from './query'
|
|
14
|
+
import { FrontmatterUtils } from './frontmatter'
|
|
15
|
+
|
|
16
|
+
// Re-export all types
|
|
17
|
+
export * from './types'
|
|
18
|
+
export * from './paths'
|
|
19
|
+
export * from './templates'
|
|
20
|
+
export * from './reader'
|
|
21
|
+
export * from './writer'
|
|
22
|
+
export * from './watcher'
|
|
23
|
+
export * from './query'
|
|
24
|
+
export * from './frontmatter'
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* VaultManager combines all vault functionality into a single interface
|
|
28
|
+
*/
|
|
29
|
+
export class VaultManager {
|
|
30
|
+
readonly reader: VaultReader
|
|
31
|
+
readonly writer: VaultWriter
|
|
32
|
+
readonly watcher: VaultWatcher
|
|
33
|
+
readonly query: VaultQuery
|
|
34
|
+
readonly paths: VaultPaths
|
|
35
|
+
private logger: Logger
|
|
36
|
+
private config: VaultConfig
|
|
37
|
+
|
|
38
|
+
constructor(
|
|
39
|
+
vaultRoot: string,
|
|
40
|
+
logger: Logger,
|
|
41
|
+
config: Partial<VaultConfig> = {}
|
|
42
|
+
) {
|
|
43
|
+
this.config = {
|
|
44
|
+
root: vaultRoot,
|
|
45
|
+
backupDir: config.backupDir ?? './data/backups',
|
|
46
|
+
cacheEnabled: config.cacheEnabled ?? true,
|
|
47
|
+
watchEnabled: config.watchEnabled ?? true,
|
|
48
|
+
debounceMs: config.debounceMs ?? 500
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
this.logger = logger.child({ component: 'vault-manager' })
|
|
52
|
+
this.paths = VaultPathUtils.getVaultPaths(vaultRoot)
|
|
53
|
+
this.reader = new VaultReader(logger, {
|
|
54
|
+
maxCacheSize: 100,
|
|
55
|
+
cacheMaxAge: 5 * 60 * 1000
|
|
56
|
+
})
|
|
57
|
+
this.writer = new VaultWriter(logger, this.config.backupDir)
|
|
58
|
+
this.watcher = new VaultWatcher(logger, this.config.debounceMs)
|
|
59
|
+
this.query = new VaultQuery(this.reader, logger)
|
|
60
|
+
|
|
61
|
+
// Wire up watcher to invalidate cache on file changes
|
|
62
|
+
this.watcher.on('change', (event: FileChangeEvent) => {
|
|
63
|
+
this.reader.invalidateCache(event.path)
|
|
64
|
+
this.logger.debug({ event }, 'Cache invalidated due to file change')
|
|
65
|
+
})
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Initialize vault (create directories if needed)
|
|
70
|
+
*/
|
|
71
|
+
async initialize(): Promise<void> {
|
|
72
|
+
const dirs = [
|
|
73
|
+
this.paths.projects,
|
|
74
|
+
this.paths.global,
|
|
75
|
+
this.paths.templates,
|
|
76
|
+
this.paths.memory
|
|
77
|
+
]
|
|
78
|
+
|
|
79
|
+
for (const dir of dirs) {
|
|
80
|
+
await fs.mkdir(dir, { recursive: true })
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
this.logger.info({ paths: this.paths }, 'Vault initialized')
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Start watching vault for changes
|
|
88
|
+
*/
|
|
89
|
+
startWatching(): void {
|
|
90
|
+
if (!this.config.watchEnabled) {
|
|
91
|
+
this.logger.warn('File watching is disabled')
|
|
92
|
+
return
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Refresh file states before watching
|
|
96
|
+
this.watcher.refreshFileStates(this.paths.projects)
|
|
97
|
+
this.watcher.watch(this.paths.projects, true)
|
|
98
|
+
this.watcher.watch(this.paths.global, true)
|
|
99
|
+
|
|
100
|
+
this.logger.info('Started watching vault')
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Stop watching vault
|
|
105
|
+
*/
|
|
106
|
+
stopWatching(): void {
|
|
107
|
+
this.watcher.unwatchAll()
|
|
108
|
+
this.logger.info('Stopped watching vault')
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Get project paths for a specific project
|
|
113
|
+
*/
|
|
114
|
+
getProjectPaths(projectName: string) {
|
|
115
|
+
return VaultPathUtils.getProjectPaths(this.config.root, projectName)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Create a new project
|
|
120
|
+
*/
|
|
121
|
+
async createProject(projectName: string): Promise<void> {
|
|
122
|
+
const normalizedName = VaultPathUtils.normalizeProjectName(projectName)
|
|
123
|
+
|
|
124
|
+
if (!VaultPathUtils.isValidProjectName(normalizedName)) {
|
|
125
|
+
throw new Error(`Invalid project name: ${projectName}`)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const projectPaths = this.getProjectPaths(normalizedName)
|
|
129
|
+
|
|
130
|
+
// Check if project already exists
|
|
131
|
+
if (await this.reader.fileExists(projectPaths.context)) {
|
|
132
|
+
throw new Error(`Project already exists: ${normalizedName}`)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
await this.writer.createProjectStructure(projectPaths.root, normalizedName)
|
|
136
|
+
this.logger.info({ projectName: normalizedName }, 'Project created')
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Get project context
|
|
141
|
+
*/
|
|
142
|
+
async getProjectContext(projectName: string): Promise<MarkdownFile | null> {
|
|
143
|
+
const projectPaths = this.getProjectPaths(projectName)
|
|
144
|
+
|
|
145
|
+
try {
|
|
146
|
+
return await this.reader.readMarkdownFile(projectPaths.context)
|
|
147
|
+
} catch {
|
|
148
|
+
return null
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Update project progress
|
|
154
|
+
*/
|
|
155
|
+
async updateProgress(
|
|
156
|
+
projectName: string,
|
|
157
|
+
updates: {
|
|
158
|
+
status?: string
|
|
159
|
+
currentPhase?: string
|
|
160
|
+
completionPercentage?: number
|
|
161
|
+
content?: string
|
|
162
|
+
}
|
|
163
|
+
): Promise<void> {
|
|
164
|
+
const projectPaths = this.getProjectPaths(projectName)
|
|
165
|
+
|
|
166
|
+
const frontmatterUpdates: Partial<Frontmatter> = {}
|
|
167
|
+
if (updates.status) frontmatterUpdates.status = updates.status
|
|
168
|
+
if (updates.currentPhase) frontmatterUpdates.current_phase = updates.currentPhase
|
|
169
|
+
if (updates.completionPercentage !== undefined) {
|
|
170
|
+
frontmatterUpdates.completion_percentage = updates.completionPercentage
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
await this.writer.updateFrontmatter(projectPaths.progress, frontmatterUpdates)
|
|
174
|
+
|
|
175
|
+
if (updates.content) {
|
|
176
|
+
await this.writer.appendContent(projectPaths.progress, updates.content)
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
this.logger.info({ projectName, updates }, 'Progress updated')
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Add a decision to the decision log
|
|
184
|
+
*/
|
|
185
|
+
async addDecision(
|
|
186
|
+
projectName: string,
|
|
187
|
+
decision: {
|
|
188
|
+
title: string
|
|
189
|
+
context: string
|
|
190
|
+
decision: string
|
|
191
|
+
consequences: string
|
|
192
|
+
status?: string
|
|
193
|
+
}
|
|
194
|
+
): Promise<void> {
|
|
195
|
+
const projectPaths = this.getProjectPaths(projectName)
|
|
196
|
+
|
|
197
|
+
// Read current decisions to get count
|
|
198
|
+
const decisionsFile = await this.reader.readMarkdownFile(projectPaths.decisions)
|
|
199
|
+
const currentCount = FrontmatterUtils.getDecisionCount(decisionsFile.frontmatter)
|
|
200
|
+
const newCount = currentCount + 1
|
|
201
|
+
|
|
202
|
+
// Format the decision entry
|
|
203
|
+
const today = new Date().toISOString().split('T')[0]
|
|
204
|
+
const decisionEntry = `
|
|
205
|
+
## Decision ${newCount}: ${decision.title}
|
|
206
|
+
|
|
207
|
+
**Date:** ${today}
|
|
208
|
+
**Status:** ${decision.status || 'accepted'}
|
|
209
|
+
**Context:** ${decision.context}
|
|
210
|
+
|
|
211
|
+
### Decision
|
|
212
|
+
${decision.decision}
|
|
213
|
+
|
|
214
|
+
### Consequences
|
|
215
|
+
${decision.consequences}
|
|
216
|
+
|
|
217
|
+
---`
|
|
218
|
+
|
|
219
|
+
// Update frontmatter with new count
|
|
220
|
+
await this.writer.updateFrontmatter(projectPaths.decisions, {
|
|
221
|
+
decision_count: newCount,
|
|
222
|
+
last_updated: today
|
|
223
|
+
})
|
|
224
|
+
|
|
225
|
+
// Append the decision
|
|
226
|
+
await this.writer.appendContent(projectPaths.decisions, decisionEntry)
|
|
227
|
+
|
|
228
|
+
this.logger.info(
|
|
229
|
+
{ projectName, decisionNumber: newCount, title: decision.title },
|
|
230
|
+
'Decision added'
|
|
231
|
+
)
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Search across the vault
|
|
236
|
+
*/
|
|
237
|
+
async search(options: QueryOptions): Promise<QueryResult[]> {
|
|
238
|
+
const { results } = await this.query.query(this.config.root, options)
|
|
239
|
+
return results
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Get all projects
|
|
244
|
+
*/
|
|
245
|
+
async listProjects(): Promise<string[]> {
|
|
246
|
+
return this.reader.getProjectDirectories(this.paths.projects)
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Get project metadata
|
|
251
|
+
*/
|
|
252
|
+
async getProjectMetadata(projectName: string): Promise<{
|
|
253
|
+
name: string
|
|
254
|
+
status: string
|
|
255
|
+
techStack: string[]
|
|
256
|
+
tags: string[]
|
|
257
|
+
currentPhase: string
|
|
258
|
+
completionPercentage: number
|
|
259
|
+
} | null> {
|
|
260
|
+
const context = await this.getProjectContext(projectName)
|
|
261
|
+
if (!context) return null
|
|
262
|
+
|
|
263
|
+
const projectPaths = this.getProjectPaths(projectName)
|
|
264
|
+
let progress: MarkdownFile | null = null
|
|
265
|
+
|
|
266
|
+
try {
|
|
267
|
+
progress = await this.reader.readMarkdownFile(projectPaths.progress)
|
|
268
|
+
} catch {
|
|
269
|
+
// Progress file might not exist
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return {
|
|
273
|
+
name: projectName,
|
|
274
|
+
status: FrontmatterUtils.getStatus(context.frontmatter) || 'unknown',
|
|
275
|
+
techStack: FrontmatterUtils.getTechStack(context.frontmatter),
|
|
276
|
+
tags: FrontmatterUtils.getTags(context.frontmatter),
|
|
277
|
+
currentPhase: progress
|
|
278
|
+
? FrontmatterUtils.getCurrentPhase(progress.frontmatter) || 'unknown'
|
|
279
|
+
: 'unknown',
|
|
280
|
+
completionPercentage: progress
|
|
281
|
+
? FrontmatterUtils.getCompletionPercentage(progress.frontmatter)
|
|
282
|
+
: 0
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Cleanup resources
|
|
288
|
+
*/
|
|
289
|
+
async cleanup(): Promise<void> {
|
|
290
|
+
this.stopWatching()
|
|
291
|
+
this.reader.clearCache()
|
|
292
|
+
|
|
293
|
+
// Clean old backups
|
|
294
|
+
await this.writer.cleanOldBackups()
|
|
295
|
+
|
|
296
|
+
this.logger.info('Vault manager cleaned up')
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Get vault statistics
|
|
301
|
+
*/
|
|
302
|
+
async getStats(): Promise<{
|
|
303
|
+
projectCount: number
|
|
304
|
+
totalFiles: number
|
|
305
|
+
cacheStats: { size: number; files: string[] }
|
|
306
|
+
watcherStatus: { watching: string[]; activeDebounces: number }
|
|
307
|
+
}> {
|
|
308
|
+
const projects = await this.listProjects()
|
|
309
|
+
const allFiles = await this.reader.readDirectory(this.paths.projects, true)
|
|
310
|
+
|
|
311
|
+
return {
|
|
312
|
+
projectCount: projects.length,
|
|
313
|
+
totalFiles: allFiles.length,
|
|
314
|
+
cacheStats: this.reader.getCacheStats(),
|
|
315
|
+
watcherStatus: this.watcher.getStatus()
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|