@chude/memory 4.0.0
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 +294 -0
- package/dist/application/index.d.ts +6 -0
- package/dist/application/services/ambient-context-service.d.ts +90 -0
- package/dist/application/services/backfill-service.d.ts +71 -0
- package/dist/application/services/budget-allocator.d.ts +57 -0
- package/dist/application/services/embedding-service.d.ts +131 -0
- package/dist/application/services/export-service.d.ts +225 -0
- package/dist/application/services/extraction-pipeline.d.ts +50 -0
- package/dist/application/services/friction-service.d.ts +148 -0
- package/dist/application/services/fts-sanitizer.d.ts +25 -0
- package/dist/application/services/index.d.ts +34 -0
- package/dist/application/services/llm-extractor.d.ts +96 -0
- package/dist/application/services/memory-file-sync-service.d.ts +58 -0
- package/dist/application/services/pattern-extractor.d.ts +95 -0
- package/dist/application/services/recovery-service.d.ts +81 -0
- package/dist/application/services/rrf-fusion.d.ts +53 -0
- package/dist/application/services/smart-context-service.d.ts +126 -0
- package/dist/application/services/sync-service.d.ts +157 -0
- package/dist/application/services/temporal-decay.d.ts +62 -0
- package/dist/domain/entities/backfill-state.d.ts +56 -0
- package/dist/domain/entities/entity.d.ts +131 -0
- package/dist/domain/entities/extraction-state.d.ts +128 -0
- package/dist/domain/entities/fact.d.ts +59 -0
- package/dist/domain/entities/friction-entry.d.ts +84 -0
- package/dist/domain/entities/index.d.ts +15 -0
- package/dist/domain/entities/link.d.ts +74 -0
- package/dist/domain/entities/memory-file.d.ts +78 -0
- package/dist/domain/entities/message.d.ts +70 -0
- package/dist/domain/entities/session.d.ts +93 -0
- package/dist/domain/entities/tool-use.d.ts +85 -0
- package/dist/domain/errors/error-codes.d.ts +37 -0
- package/dist/domain/errors/index.d.ts +8 -0
- package/dist/domain/errors/memory-error.d.ts +52 -0
- package/dist/domain/errors/unknown-error.d.ts +9 -0
- package/dist/domain/index.d.ts +11 -0
- package/dist/domain/ports/embedding.d.ts +96 -0
- package/dist/domain/ports/extraction.d.ts +13 -0
- package/dist/domain/ports/index.d.ts +14 -0
- package/dist/domain/ports/redactor.d.ts +17 -0
- package/dist/domain/ports/repositories.d.ts +658 -0
- package/dist/domain/ports/services.d.ts +180 -0
- package/dist/domain/ports/signals.d.ts +82 -0
- package/dist/domain/ports/sources.d.ts +122 -0
- package/dist/domain/ports/types.d.ts +150 -0
- package/dist/domain/services/content-extractor.d.ts +61 -0
- package/dist/domain/services/index.d.ts +8 -0
- package/dist/domain/services/path-decoder.d.ts +56 -0
- package/dist/domain/services/query-parser.d.ts +47 -0
- package/dist/domain/value-objects/embedding-config.d.ts +56 -0
- package/dist/domain/value-objects/embedding-result.d.ts +46 -0
- package/dist/domain/value-objects/index.d.ts +10 -0
- package/dist/domain/value-objects/project-path.d.ts +92 -0
- package/dist/domain/value-objects/search-query.d.ts +30 -0
- package/dist/domain/value-objects/search-result.d.ts +92 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +1548 -0
- package/dist/infrastructure/database/connection.d.ts +161 -0
- package/dist/infrastructure/database/event-log.d.ts +22 -0
- package/dist/infrastructure/database/health-checker.d.ts +248 -0
- package/dist/infrastructure/database/index.d.ts +11 -0
- package/dist/infrastructure/database/repositories/backfill-state-repository.d.ts +19 -0
- package/dist/infrastructure/database/repositories/embedding-repository.d.ts +121 -0
- package/dist/infrastructure/database/repositories/entity-repository.d.ts +73 -0
- package/dist/infrastructure/database/repositories/extraction-log-repository.d.ts +17 -0
- package/dist/infrastructure/database/repositories/extraction-state-repository.d.ts +52 -0
- package/dist/infrastructure/database/repositories/fact-repository.d.ts +25 -0
- package/dist/infrastructure/database/repositories/friction-repository.d.ts +41 -0
- package/dist/infrastructure/database/repositories/index.d.ts +17 -0
- package/dist/infrastructure/database/repositories/link-repository.d.ts +64 -0
- package/dist/infrastructure/database/repositories/memory-file-repository.d.ts +28 -0
- package/dist/infrastructure/database/repositories/message-repository.d.ts +87 -0
- package/dist/infrastructure/database/repositories/session-repository.d.ts +125 -0
- package/dist/infrastructure/database/repositories/tool-use-repository.d.ts +72 -0
- package/dist/infrastructure/database/schema.d.ts +203 -0
- package/dist/infrastructure/database/services/context-service.d.ts +93 -0
- package/dist/infrastructure/database/services/hybrid-search-service.d.ts +156 -0
- package/dist/infrastructure/database/services/index.d.ts +10 -0
- package/dist/infrastructure/database/services/search-service.d.ts +57 -0
- package/dist/infrastructure/database/services/stats-service.d.ts +36 -0
- package/dist/infrastructure/embedding/background-embedder.d.ts +125 -0
- package/dist/infrastructure/embedding/embedding-provider-factory.d.ts +44 -0
- package/dist/infrastructure/embedding/index.d.ts +5 -0
- package/dist/infrastructure/embedding/ollama-provider.d.ts +41 -0
- package/dist/infrastructure/embedding/openai-provider.d.ts +38 -0
- package/dist/infrastructure/embedding/transformers-js-provider.d.ts +34 -0
- package/dist/infrastructure/external/index.d.ts +7 -0
- package/dist/infrastructure/external/qmd-runner.d.ts +36 -0
- package/dist/infrastructure/hooks/auto-memory-writer.d.ts +52 -0
- package/dist/infrastructure/hooks/config-manager.d.ts +237 -0
- package/dist/infrastructure/hooks/git-syncer.d.ts +44 -0
- package/dist/infrastructure/hooks/hook-runner.d.ts +126 -0
- package/dist/infrastructure/hooks/index.d.ts +12 -0
- package/dist/infrastructure/hooks/log-writer.d.ts +106 -0
- package/dist/infrastructure/hooks/settings-manager.d.ts +163 -0
- package/dist/infrastructure/hooks/sync-hook-script.d.ts +83 -0
- package/dist/infrastructure/hooks/sync-logger-adapter.d.ts +17 -0
- package/dist/infrastructure/index.d.ts +11 -0
- package/dist/infrastructure/llm/anthropic-extractor.d.ts +20 -0
- package/dist/infrastructure/llm/claude-cli-extractor.d.ts +14 -0
- package/dist/infrastructure/llm/claude-summary-generator.d.ts +14 -0
- package/dist/infrastructure/llm/extraction-helper.d.ts +16 -0
- package/dist/infrastructure/llm/ollama-extractor.d.ts +20 -0
- package/dist/infrastructure/llm/openai-extractor.d.ts +23 -0
- package/dist/infrastructure/migration.d.ts +103 -0
- package/dist/infrastructure/parsers/event-classifier.d.ts +111 -0
- package/dist/infrastructure/parsers/index.d.ts +8 -0
- package/dist/infrastructure/parsers/jsonl-parser.d.ts +25 -0
- package/dist/infrastructure/parsers/timestamp.d.ts +18 -0
- package/dist/infrastructure/paths.d.ts +129 -0
- package/dist/infrastructure/providers/provider-defaults.d.ts +11 -0
- package/dist/infrastructure/providers/provider-registry.d.ts +28 -0
- package/dist/infrastructure/security/pattern-redactor.d.ts +6 -0
- package/dist/infrastructure/signals/adapters.d.ts +27 -0
- package/dist/infrastructure/signals/checkpoint-manager.d.ts +83 -0
- package/dist/infrastructure/signals/index.d.ts +8 -0
- package/dist/infrastructure/signals/signal-handler.d.ts +113 -0
- package/dist/infrastructure/sources/index.d.ts +8 -0
- package/dist/infrastructure/sources/memory-file-scanner.d.ts +23 -0
- package/dist/infrastructure/sources/project-name-resolver.d.ts +67 -0
- package/dist/infrastructure/sources/session-source.d.ts +70 -0
- package/dist/presentation/cli/command-result.d.ts +10 -0
- package/dist/presentation/cli/commands/_helpers/capture-json.d.ts +36 -0
- package/dist/presentation/cli/commands/_helpers/deprecation-warning.d.ts +41 -0
- package/dist/presentation/cli/commands/backfill.d.ts +56 -0
- package/dist/presentation/cli/commands/browse.d.ts +55 -0
- package/dist/presentation/cli/commands/completion.d.ts +61 -0
- package/dist/presentation/cli/commands/context.d.ts +53 -0
- package/dist/presentation/cli/commands/doctor.d.ts +55 -0
- package/dist/presentation/cli/commands/export.d.ts +36 -0
- package/dist/presentation/cli/commands/extract.d.ts +40 -0
- package/dist/presentation/cli/commands/facts.d.ts +17 -0
- package/dist/presentation/cli/commands/friction/dashboard.d.ts +18 -0
- package/dist/presentation/cli/commands/friction/index.d.ts +12 -0
- package/dist/presentation/cli/commands/friction/list.d.ts +12 -0
- package/dist/presentation/cli/commands/friction/log.d.ts +12 -0
- package/dist/presentation/cli/commands/friction/purge.d.ts +12 -0
- package/dist/presentation/cli/commands/friction/resolve.d.ts +12 -0
- package/dist/presentation/cli/commands/friction/types.d.ts +86 -0
- package/dist/presentation/cli/commands/friction/wontfix.d.ts +12 -0
- package/dist/presentation/cli/commands/import.d.ts +38 -0
- package/dist/presentation/cli/commands/index.d.ts +51 -0
- package/dist/presentation/cli/commands/install.d.ts +67 -0
- package/dist/presentation/cli/commands/list.d.ts +61 -0
- package/dist/presentation/cli/commands/migrate.d.ts +36 -0
- package/dist/presentation/cli/commands/purge.d.ts +100 -0
- package/dist/presentation/cli/commands/query.d.ts +51 -0
- package/dist/presentation/cli/commands/related.d.ts +47 -0
- package/dist/presentation/cli/commands/remote.d.ts +36 -0
- package/dist/presentation/cli/commands/search.d.ts +100 -0
- package/dist/presentation/cli/commands/show.d.ts +51 -0
- package/dist/presentation/cli/commands/stats.d.ts +38 -0
- package/dist/presentation/cli/commands/status.d.ts +152 -0
- package/dist/presentation/cli/commands/sync/ambient.d.ts +22 -0
- package/dist/presentation/cli/commands/sync/background.d.ts +23 -0
- package/dist/presentation/cli/commands/sync/embedding-pass.d.ts +32 -0
- package/dist/presentation/cli/commands/sync/helpers.d.ts +25 -0
- package/dist/presentation/cli/commands/sync/index.d.ts +17 -0
- package/dist/presentation/cli/commands/sync/memory-files.d.ts +26 -0
- package/dist/presentation/cli/commands/sync/types.d.ts +163 -0
- package/dist/presentation/cli/commands/uninstall.d.ts +44 -0
- package/dist/presentation/cli/db-startup.d.ts +61 -0
- package/dist/presentation/cli/formatters/ai-formatter.d.ts +38 -0
- package/dist/presentation/cli/formatters/color.d.ts +82 -0
- package/dist/presentation/cli/formatters/context-formatter.d.ts +55 -0
- package/dist/presentation/cli/formatters/dto-helpers.d.ts +176 -0
- package/dist/presentation/cli/formatters/envelope.d.ts +136 -0
- package/dist/presentation/cli/formatters/error-formatter.d.ts +41 -0
- package/dist/presentation/cli/formatters/friction-dashboard.d.ts +46 -0
- package/dist/presentation/cli/formatters/index.d.ts +17 -0
- package/dist/presentation/cli/formatters/list-formatter.d.ts +48 -0
- package/dist/presentation/cli/formatters/output-formatter.d.ts +98 -0
- package/dist/presentation/cli/formatters/related-formatter.d.ts +57 -0
- package/dist/presentation/cli/formatters/show-formatter.d.ts +63 -0
- package/dist/presentation/cli/formatters/stats-formatter.d.ts +54 -0
- package/dist/presentation/cli/formatters/text-width.d.ts +37 -0
- package/dist/presentation/cli/formatters/timestamp-formatter.d.ts +38 -0
- package/dist/presentation/cli/index.d.ts +10 -0
- package/dist/presentation/cli/index.js +1664 -0
- package/dist/presentation/cli/parsers/date-parser.d.ts +28 -0
- package/dist/presentation/cli/parsers/index.d.ts +6 -0
- package/dist/presentation/cli/pickers/index.d.ts +6 -0
- package/dist/presentation/cli/pickers/session-picker.d.ts +59 -0
- package/dist/presentation/cli/progress-reporter.d.ts +199 -0
- package/package.json +94 -0
package/README.md
ADDED
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
# @chude/memory
|
|
2
|
+
|
|
3
|
+
Cross-project context persistence for Claude Code sessions.
|
|
4
|
+
|
|
5
|
+
## Problem
|
|
6
|
+
|
|
7
|
+
Claude Code sessions are per-directory and deleted after 30 days. Context does not transfer between projects. Knowledge gained in one project is invisible to work in another.
|
|
8
|
+
|
|
9
|
+
## Solution
|
|
10
|
+
|
|
11
|
+
Extract session JSONL files into a searchable SQLite database accessible from any project via the `memory` CLI.
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
bun add -g @chude/memory
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Setup
|
|
20
|
+
|
|
21
|
+
Install Claude Code hooks for automatic session sync:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
memory install
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Verify installation:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
memory doctor
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Usage
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
# Sync sessions to database
|
|
37
|
+
memory sync
|
|
38
|
+
|
|
39
|
+
# Search across all sessions
|
|
40
|
+
memory search "authentication patterns"
|
|
41
|
+
|
|
42
|
+
# Get context for a specific project
|
|
43
|
+
memory context wow-system
|
|
44
|
+
|
|
45
|
+
# List recent sessions
|
|
46
|
+
memory list
|
|
47
|
+
|
|
48
|
+
# Show session details
|
|
49
|
+
memory show <session-id>
|
|
50
|
+
|
|
51
|
+
# Find related sessions
|
|
52
|
+
memory related <session-id>
|
|
53
|
+
|
|
54
|
+
# Browse sessions interactively
|
|
55
|
+
memory browse
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## How It Works
|
|
59
|
+
|
|
60
|
+
1. Claude Code stores sessions as JSONL files in `~/.claude/projects/`
|
|
61
|
+
2. `memory sync` extracts messages, topics, and entities into a SQLite database with FTS5
|
|
62
|
+
3. Claude Code hooks trigger background sync automatically on session end
|
|
63
|
+
4. `memory search` and `memory context` query the database from any project directory
|
|
64
|
+
|
|
65
|
+
## Data Paths
|
|
66
|
+
|
|
67
|
+
| Purpose | Path | Override |
|
|
68
|
+
|---------|------|----------|
|
|
69
|
+
| Config | `~/.config/memory/config.json` | `XDG_CONFIG_HOME` |
|
|
70
|
+
| Database | `~/.local/share/memory/memory.db` | `XDG_DATA_HOME` |
|
|
71
|
+
| Logs | `~/.local/share/memory/logs/` | `XDG_DATA_HOME` |
|
|
72
|
+
| Legacy memory files | `~/.memory/` | `MEMORY_HOME` |
|
|
73
|
+
|
|
74
|
+
Tool-managed paths follow the XDG Base Directory Specification. Override with `XDG_CONFIG_HOME` and `XDG_DATA_HOME`.
|
|
75
|
+
|
|
76
|
+
Legacy memory files are retained for compatibility with pre-v4 markdown sidecars. They are not read or written by default. To index them during sync, use `memory sync --include-memory-files`, set `MEMORY_LEGACY_MEMORY_FILES=1`, or set `legacyMemoryFiles.enabled=true` in config. To generate legacy daily logs with `memory backfill`, pass `--write-memory-files` or use the same env/config opt-in. `MEMORY_HOME` follows the `GNUPGHOME` / `JAVA_HOME` tradition: the value is the exact directory path, not a base directory under which a subdirectory is appended. Empty string is ignored; no `~` expansion.
|
|
77
|
+
|
|
78
|
+
## Secret Handling
|
|
79
|
+
|
|
80
|
+
Remote provider credentials should come from environment injection, not plaintext config files. `embedding.apiKey` is retained only as deprecated compatibility input.
|
|
81
|
+
|
|
82
|
+
Use `apiKeyEnv` when a provider needs a runtime key:
|
|
83
|
+
|
|
84
|
+
```json
|
|
85
|
+
{
|
|
86
|
+
"embedding": {
|
|
87
|
+
"provider": "openai",
|
|
88
|
+
"apiKeyEnv": "OPENAI_API_KEY"
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Use `apiKeyRef` only as opaque metadata for an external secret manager:
|
|
94
|
+
|
|
95
|
+
```json
|
|
96
|
+
{
|
|
97
|
+
"embedding": {
|
|
98
|
+
"provider": "openai",
|
|
99
|
+
"apiKeyRef": "authkey://memory/openai-api-key"
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
`memory` never resolves `apiKeyRef` to a raw secret and never calls `authkey get`. If you use authkey, inject secrets into the child process:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
authkey run --env memory -- memory sync --embed
|
|
108
|
+
authkey run --env memory -- memory extract memory-nexus
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Known secret patterns in newly synced transcript content, tool inputs/results, extraction payloads, embeddings, and CLI JSON exports are redacted before storage or provider egress. Raw JSON backups require explicit opt-in:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
memory export backup.json --include-sensitive
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Provider Support
|
|
118
|
+
|
|
119
|
+
Provider support is explicit and registry-backed. Built-in embedding providers are `local`, `openai`, `ollama`, and `openai-compatible`. Built-in extraction providers are `claude-cli`, `anthropic`, `openai`, `ollama`, and `openai-compatible`.
|
|
120
|
+
|
|
121
|
+
Use `openai-compatible` for gateways or providers that expose OpenAI-compatible APIs:
|
|
122
|
+
|
|
123
|
+
```json
|
|
124
|
+
{
|
|
125
|
+
"embedding": {
|
|
126
|
+
"provider": "openai-compatible",
|
|
127
|
+
"baseUrl": "https://gateway.example.com/v1",
|
|
128
|
+
"apiKeyEnv": "MEMORY_GATEWAY_API_KEY"
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
`LLM_PROVIDER` selects the extraction provider. `LLM_MODEL` overrides the extraction model without changing embedding configuration.
|
|
134
|
+
|
|
135
|
+
## AI-First Design
|
|
136
|
+
|
|
137
|
+
This tool is designed for Claude to use via the Bash tool:
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
# Claude runs these commands to access cross-project knowledge
|
|
141
|
+
memory context <project-name>
|
|
142
|
+
memory search "query" --limit 5
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Standard CLI output works for both humans and AI agents.
|
|
146
|
+
|
|
147
|
+
## Programmatic API
|
|
148
|
+
|
|
149
|
+
Install as a dependency:
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
bun add @chude/memory
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Import and call execute functions:
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
import {
|
|
159
|
+
executeSyncCommand,
|
|
160
|
+
executeSearchCommand,
|
|
161
|
+
executeContextCommand,
|
|
162
|
+
type CommandResult,
|
|
163
|
+
type SyncCommandOptions,
|
|
164
|
+
type SearchCommandOptions,
|
|
165
|
+
type SearchMode,
|
|
166
|
+
} from "@chude/memory";
|
|
167
|
+
|
|
168
|
+
// Sync sessions to database
|
|
169
|
+
const syncResult = await executeSyncCommand({ quiet: true });
|
|
170
|
+
// syncResult: { exitCode: 0 }
|
|
171
|
+
|
|
172
|
+
// Search sessions
|
|
173
|
+
const searchResult = await executeSearchCommand("authentication patterns", {
|
|
174
|
+
limit: "5",
|
|
175
|
+
json: true,
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
// Get project context
|
|
179
|
+
const contextResult = await executeContextCommand("my-project", {
|
|
180
|
+
json: true,
|
|
181
|
+
days: 7,
|
|
182
|
+
});
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Exported Functions
|
|
186
|
+
|
|
187
|
+
| Function | Parameters | Returns |
|
|
188
|
+
|----------|------------|---------|
|
|
189
|
+
| `executeSyncCommand` | `options: SyncCommandOptions` | `Promise<CommandResult>` |
|
|
190
|
+
| `executeSearchCommand` | `query: string, options: SearchCommandOptions` | `Promise<CommandResult>` |
|
|
191
|
+
| `executeListCommand` | `options: ListCommandOptions` | `Promise<CommandResult>` |
|
|
192
|
+
| `executeStatsCommand` | `options: StatsCommandOptions` | `Promise<CommandResult>` |
|
|
193
|
+
| `executeContextCommand` | `project: string, options: ContextCommandOptions` | `Promise<CommandResult>` |
|
|
194
|
+
| `executeRelatedCommand` | `sessionId: string, options: RelatedCommandOptions` | `Promise<CommandResult>` |
|
|
195
|
+
| `executeShowCommand` | `sessionId: string, options: ShowCommandOptions` | `Promise<CommandResult>` |
|
|
196
|
+
| `executeBrowseCommand` | `options: BrowseCommandOptions` | `Promise<CommandResult>` |
|
|
197
|
+
| `executeInstallCommand` | `options: InstallOptions` | `Promise<CommandResult>` |
|
|
198
|
+
| `executeUninstallCommand` | `options: UninstallOptions` | `Promise<CommandResult>` |
|
|
199
|
+
| `executeStatusCommand` | `options: StatusOptions` | `Promise<CommandResult>` |
|
|
200
|
+
| `executeDoctorCommand` | `options: DoctorOptions` | `Promise<CommandResult>` |
|
|
201
|
+
| `executePurgeCommand` | `options: PurgeCommandOptions` | `Promise<CommandResult>` |
|
|
202
|
+
| `executeExportCommand` | `outputPath: string, options: ExportOptions` | `Promise<CommandResult>` |
|
|
203
|
+
| `executeImportCommand` | `inputPath: string, options: ImportOptions` | `Promise<CommandResult>` |
|
|
204
|
+
| `executeCompletionCommand` | `shell: string` | `CommandResult` |
|
|
205
|
+
|
|
206
|
+
### CommandResult
|
|
207
|
+
|
|
208
|
+
```typescript
|
|
209
|
+
interface CommandResult {
|
|
210
|
+
exitCode: number; // 0 = success, 1 = error/not found
|
|
211
|
+
}
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
All functions handle their own database initialization and teardown. They never call `process.exit()`.
|
|
215
|
+
|
|
216
|
+
### Domain Types
|
|
217
|
+
|
|
218
|
+
The following domain types are exported for TypeScript consumers who need typed search and stats operations:
|
|
219
|
+
|
|
220
|
+
| Type | Description |
|
|
221
|
+
|------|-------------|
|
|
222
|
+
| `SearchMode` | Union type: `"auto" \| "fts" \| "vector" \| "hybrid"`. Controls search strategy. |
|
|
223
|
+
| `HybridSearchOptions` | Extends `SearchOptions` with `mode` and `noDecay` fields for hybrid search. |
|
|
224
|
+
| `IStatsService` | Port interface for database statistics queries. |
|
|
225
|
+
| `StatsResult` | Return type from `IStatsService.getStats()`: session/message/tool-use totals, database size, and per-project breakdown. |
|
|
226
|
+
| `ProjectStats` | Per-project statistics: `projectName`, `sessionCount`, `messageCount`. |
|
|
227
|
+
|
|
228
|
+
```typescript
|
|
229
|
+
import type {
|
|
230
|
+
SearchMode,
|
|
231
|
+
HybridSearchOptions,
|
|
232
|
+
IStatsService,
|
|
233
|
+
StatsResult,
|
|
234
|
+
ProjectStats,
|
|
235
|
+
} from "@chude/memory";
|
|
236
|
+
|
|
237
|
+
// Typed search options
|
|
238
|
+
const opts: HybridSearchOptions = {
|
|
239
|
+
mode: "hybrid" satisfies SearchMode,
|
|
240
|
+
limit: 10,
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
// Typed stats result
|
|
244
|
+
function processStats(stats: StatsResult): void {
|
|
245
|
+
console.log(`${stats.totalSessions} sessions, ${stats.totalMessages} messages`);
|
|
246
|
+
stats.projectBreakdown.forEach((p: ProjectStats) => {
|
|
247
|
+
console.log(` ${p.projectName}: ${p.messageCount} messages`);
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
## Previously Published As
|
|
253
|
+
|
|
254
|
+
This package was previously published as `memory-nexus`. The old package name now installs a deprecation stub. See [MIGRATION.md](MIGRATION.md) for upgrade instructions.
|
|
255
|
+
|
|
256
|
+
## Development
|
|
257
|
+
|
|
258
|
+
### Quality gates
|
|
259
|
+
|
|
260
|
+
```bash
|
|
261
|
+
bun run typecheck
|
|
262
|
+
bun run build
|
|
263
|
+
bun test --timeout 15000
|
|
264
|
+
bun run test:isolation
|
|
265
|
+
bun run test:coverage
|
|
266
|
+
bun audit
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
`bun run quality` runs the release gate sequence. `bun run test:coverage` uses an Istanbul-backed Bun harness and is intentionally strict: statements, branches, functions, and lines must each be available and at least 95%. Missing metrics fail the gate.
|
|
270
|
+
|
|
271
|
+
### Running tests on Windows
|
|
272
|
+
|
|
273
|
+
Current 2026-05-28 verification has `bun test --timeout 15000` passing on Windows 11 with Bun 1.3.5. A previous full-suite run crashed with Bun's `panic(main thread): integer overflow` signature at ~6.8GB peak memory pressure; keep the subdirectory workaround available if that upstream runtime crash returns.
|
|
274
|
+
|
|
275
|
+
Fallback workaround: run the suite by subdirectory.
|
|
276
|
+
|
|
277
|
+
```bash
|
|
278
|
+
bun test src/infrastructure/
|
|
279
|
+
bun test src/presentation/
|
|
280
|
+
bun test src/application src/domain
|
|
281
|
+
bun test tests/helpers tests/generators tests/infrastructure tests/integration tests/smoke
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
Or run a single file directly:
|
|
285
|
+
|
|
286
|
+
```bash
|
|
287
|
+
bun test src/path/to/file.test.ts
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
Linux and macOS contributors should run the full suite normally.
|
|
291
|
+
|
|
292
|
+
## License
|
|
293
|
+
|
|
294
|
+
MIT
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ambient Context Service
|
|
3
|
+
*
|
|
4
|
+
* Application-layer service that composes SmartContextService and
|
|
5
|
+
* IAmbientContextWriter to generate ambient context files for
|
|
6
|
+
* Claude Code's auto memory directory.
|
|
7
|
+
*
|
|
8
|
+
* After a sync, this service:
|
|
9
|
+
* 1. Queries SmartContextService for structured project context
|
|
10
|
+
* 2. Formats context.md via an injected formatter
|
|
11
|
+
* 3. Builds a concise MEMORY.md summary block with counts
|
|
12
|
+
* 4. Writes both artifacts via IAmbientContextWriter
|
|
13
|
+
*
|
|
14
|
+
* Dependencies are injected via constructor (hexagonal architecture).
|
|
15
|
+
* Zero imports from infrastructure or presentation layers.
|
|
16
|
+
*/
|
|
17
|
+
import type { IAmbientContextWriter } from "../../domain/ports/services.js";
|
|
18
|
+
import type { SmartContextService, SmartContextResult } from "./smart-context-service.js";
|
|
19
|
+
/**
|
|
20
|
+
* Options for ambient context generation.
|
|
21
|
+
*/
|
|
22
|
+
export interface AmbientContextOptions {
|
|
23
|
+
/** Human-readable project name for SmartContextService lookup */
|
|
24
|
+
projectName: string;
|
|
25
|
+
/** Path to the auto memory directory (e.g., ~/.claude/projects/<encoded>/memory/) */
|
|
26
|
+
autoMemoryDir: string;
|
|
27
|
+
/** Token budget for context.md (from config) */
|
|
28
|
+
budget: number;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Result of ambient context generation.
|
|
32
|
+
*/
|
|
33
|
+
export interface AmbientContextResult {
|
|
34
|
+
/** Whether context was successfully generated */
|
|
35
|
+
success: boolean;
|
|
36
|
+
/** Reason for failure (only when success=false) */
|
|
37
|
+
reason?: "project-not-found" | "no-context" | "error";
|
|
38
|
+
/** Estimated token count of context.md content */
|
|
39
|
+
contextTokens?: number;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Structural type for the formatter dependency.
|
|
43
|
+
* Accepts any object with a formatSmartContext method.
|
|
44
|
+
* This avoids importing from the presentation layer.
|
|
45
|
+
*/
|
|
46
|
+
interface SmartContextFormatter {
|
|
47
|
+
formatSmartContext(result: SmartContextResult): string;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Ambient Context Service.
|
|
51
|
+
*
|
|
52
|
+
* Orchestrates SmartContextService, a formatter, and IAmbientContextWriter
|
|
53
|
+
* to produce context.md and update MEMORY.md in the auto memory directory.
|
|
54
|
+
*/
|
|
55
|
+
export declare class AmbientContextService {
|
|
56
|
+
private readonly smartContext;
|
|
57
|
+
private readonly contextWriter;
|
|
58
|
+
private readonly formatter;
|
|
59
|
+
constructor(smartContext: SmartContextService, contextWriter: IAmbientContextWriter, formatter: SmartContextFormatter);
|
|
60
|
+
/**
|
|
61
|
+
* Generate ambient context for the given project.
|
|
62
|
+
*
|
|
63
|
+
* Queries SmartContextService for structured context, formats it
|
|
64
|
+
* for context.md, builds a summary block for MEMORY.md, and
|
|
65
|
+
* writes both artifacts.
|
|
66
|
+
*
|
|
67
|
+
* @param options Generation options
|
|
68
|
+
* @returns Result indicating success or failure with reason
|
|
69
|
+
*/
|
|
70
|
+
generateAmbientContext(options: AmbientContextOptions): Promise<AmbientContextResult>;
|
|
71
|
+
/**
|
|
72
|
+
* Build a concise summary block for MEMORY.md.
|
|
73
|
+
*
|
|
74
|
+
* Extracts counts from SmartContextResult sections and produces
|
|
75
|
+
* a block under 10 lines matching the CONTEXT.md spec.
|
|
76
|
+
*
|
|
77
|
+
* @param result SmartContextResult with sections
|
|
78
|
+
* @returns Formatted summary block content
|
|
79
|
+
*/
|
|
80
|
+
private buildSummaryBlock;
|
|
81
|
+
/**
|
|
82
|
+
* Count non-empty lines in a section by key.
|
|
83
|
+
*
|
|
84
|
+
* @param sections Context sections from SmartContextResult
|
|
85
|
+
* @param key Section key to look for
|
|
86
|
+
* @returns Number of non-empty lines, or 0 if section not found
|
|
87
|
+
*/
|
|
88
|
+
private countSectionLines;
|
|
89
|
+
}
|
|
90
|
+
export {};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BackfillService
|
|
3
|
+
*
|
|
4
|
+
* Application service that orchestrates session backfilling:
|
|
5
|
+
* 1. Query sessions without backfill state (unprocessed)
|
|
6
|
+
* 2. Extract content from messages
|
|
7
|
+
* 3. Generate structured summary via ISummaryGenerator
|
|
8
|
+
* 4. Write daily log file via IDailyLogWriter
|
|
9
|
+
* 5. Save BackfillState record for idempotency
|
|
10
|
+
*
|
|
11
|
+
* Depends on domain ports only. Infrastructure is injected via constructor.
|
|
12
|
+
*/
|
|
13
|
+
import type { ISessionRepository } from "../../domain/ports/repositories.js";
|
|
14
|
+
import type { IBackfillStateRepository } from "../../domain/ports/repositories.js";
|
|
15
|
+
import type { IMessageRepository } from "../../domain/ports/repositories.js";
|
|
16
|
+
import type { ISummaryGenerator } from "../../domain/ports/index.js";
|
|
17
|
+
export interface BackfillProgress {
|
|
18
|
+
current: number;
|
|
19
|
+
total: number;
|
|
20
|
+
sessionId: string;
|
|
21
|
+
action: "processing" | "skipped" | "error";
|
|
22
|
+
}
|
|
23
|
+
export interface BackfillResult {
|
|
24
|
+
sessionsProcessed: number;
|
|
25
|
+
sessionsFailed: number;
|
|
26
|
+
sessionsSkipped: number;
|
|
27
|
+
dailyLogsCreated: number;
|
|
28
|
+
dailyLogsUpdated: number;
|
|
29
|
+
errors: Array<{
|
|
30
|
+
sessionId: string;
|
|
31
|
+
error: string;
|
|
32
|
+
}>;
|
|
33
|
+
}
|
|
34
|
+
export interface DryRunResult {
|
|
35
|
+
unprocessedCount: number;
|
|
36
|
+
estimatedCost: number;
|
|
37
|
+
}
|
|
38
|
+
export interface BackfillOptions {
|
|
39
|
+
batch?: number | undefined;
|
|
40
|
+
project?: string | undefined;
|
|
41
|
+
onProgress?: ((progress: BackfillProgress) => void) | undefined;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* File writer abstraction for daily log files.
|
|
45
|
+
*
|
|
46
|
+
* Allows the service to write daily log files without importing
|
|
47
|
+
* filesystem modules directly. Infrastructure provides the implementation.
|
|
48
|
+
*/
|
|
49
|
+
export interface IDailyLogWriter {
|
|
50
|
+
/**
|
|
51
|
+
* Write or append content to a daily log file.
|
|
52
|
+
* Creates parent directories if needed.
|
|
53
|
+
*
|
|
54
|
+
* @param datePath Date-based path relative to memory dir (e.g., "daily/2026-03-08.md")
|
|
55
|
+
* @param content Markdown content to write or append
|
|
56
|
+
* @returns Whether the file was created (true) or appended to (false)
|
|
57
|
+
*/
|
|
58
|
+
writeOrAppend(datePath: string, content: string): Promise<boolean>;
|
|
59
|
+
}
|
|
60
|
+
export declare class BackfillService {
|
|
61
|
+
private readonly sessionRepo;
|
|
62
|
+
private readonly messageRepo;
|
|
63
|
+
private readonly backfillStateRepo;
|
|
64
|
+
private readonly summaryGenerator;
|
|
65
|
+
private readonly dailyLogWriter;
|
|
66
|
+
constructor(sessionRepo: ISessionRepository, messageRepo: IMessageRepository, backfillStateRepo: IBackfillStateRepository, summaryGenerator: ISummaryGenerator, dailyLogWriter: IDailyLogWriter);
|
|
67
|
+
dryRun(options?: Pick<BackfillOptions, "project">): Promise<DryRunResult>;
|
|
68
|
+
backfill(options?: BackfillOptions): Promise<BackfillResult>;
|
|
69
|
+
private getUnprocessedSessions;
|
|
70
|
+
private extractContent;
|
|
71
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Budget Allocator
|
|
3
|
+
*
|
|
4
|
+
* Pure function that distributes a token budget across prioritized sections.
|
|
5
|
+
* Sections are filled in priority order (1 = highest). Lower-priority sections
|
|
6
|
+
* are truncated first when budget is exceeded.
|
|
7
|
+
*
|
|
8
|
+
* Token estimation: ~4 characters per token for English text.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* A section of content with a priority for budget allocation.
|
|
12
|
+
*/
|
|
13
|
+
export interface BudgetSection {
|
|
14
|
+
/** Section identifier (e.g., "decisions", "learnings") */
|
|
15
|
+
key: string;
|
|
16
|
+
/** Priority (1 = highest, filled first) */
|
|
17
|
+
priority: number;
|
|
18
|
+
/** Section content text */
|
|
19
|
+
content: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* A section after budget allocation, with truncation info.
|
|
23
|
+
*/
|
|
24
|
+
export interface AllocatedSection extends BudgetSection {
|
|
25
|
+
/** Content after budget truncation (prefix of original) */
|
|
26
|
+
truncatedContent: string;
|
|
27
|
+
/** Estimated tokens allocated to this section */
|
|
28
|
+
allocated: number;
|
|
29
|
+
/** Whether this section was truncated */
|
|
30
|
+
truncated: boolean;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Result of budget allocation across sections.
|
|
34
|
+
*/
|
|
35
|
+
export interface BudgetAllocationResult {
|
|
36
|
+
/** Sections with allocation details */
|
|
37
|
+
sections: AllocatedSection[];
|
|
38
|
+
/** Total estimated tokens used across all sections */
|
|
39
|
+
totalTokensUsed: number;
|
|
40
|
+
/** Whether the total content exceeded the budget */
|
|
41
|
+
budgetExceeded: boolean;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Distribute a token budget across prioritized sections.
|
|
45
|
+
*
|
|
46
|
+
* Sections are sorted by priority (1 = highest) and allocated budget
|
|
47
|
+
* in order. Lower-priority sections are truncated or dropped first.
|
|
48
|
+
*
|
|
49
|
+
* When totalBudget is 0 or negative, no constraint is applied and all
|
|
50
|
+
* sections are returned untruncated.
|
|
51
|
+
*
|
|
52
|
+
* @param sections Array of content sections to allocate budget to
|
|
53
|
+
* @param totalBudget Maximum tokens allowed (0 or negative = no limit)
|
|
54
|
+
* @param charsPerToken Characters per token heuristic (default: 4)
|
|
55
|
+
* @returns Allocation result with sections, token usage, and overflow flag
|
|
56
|
+
*/
|
|
57
|
+
export declare function allocateBudget(sections: BudgetSection[], totalBudget: number, charsPerToken?: number): BudgetAllocationResult;
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Embedding Service
|
|
3
|
+
*
|
|
4
|
+
* Application layer service that orchestrates the embedding pipeline:
|
|
5
|
+
* check model hash -> query unembedded -> batch embed -> store results.
|
|
6
|
+
*
|
|
7
|
+
* Does NOT own the IEmbeddingProvider lifecycle -- the caller creates
|
|
8
|
+
* and initializes the provider, then passes it in via constructor.
|
|
9
|
+
*
|
|
10
|
+
* Sits between the presentation layer (sync command) and infrastructure
|
|
11
|
+
* (repository + provider). Respects hexagonal architecture boundaries.
|
|
12
|
+
*/
|
|
13
|
+
import type { IEmbeddingProvider } from "../../domain/ports/embedding.js";
|
|
14
|
+
import type { IRedactor } from "../../domain/ports/redactor.js";
|
|
15
|
+
import type { IEmbeddingRepository, EmbeddingServiceConfig } from "../../domain/ports/repositories.js";
|
|
16
|
+
/**
|
|
17
|
+
* Options for embedding operations.
|
|
18
|
+
*/
|
|
19
|
+
export interface EmbedOptions {
|
|
20
|
+
/** Callback invoked after each batch completes */
|
|
21
|
+
onProgress?: (progress: EmbedProgress) => void;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Progress report after each embedding batch.
|
|
25
|
+
*/
|
|
26
|
+
export interface EmbedProgress {
|
|
27
|
+
/** Number of messages embedded so far */
|
|
28
|
+
current: number;
|
|
29
|
+
/** Total number of messages to embed */
|
|
30
|
+
total: number;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Result of an embedding operation.
|
|
34
|
+
*/
|
|
35
|
+
export interface EmbedResult {
|
|
36
|
+
/** Number of messages successfully embedded */
|
|
37
|
+
embedded: number;
|
|
38
|
+
/** Number of messages skipped */
|
|
39
|
+
skipped: number;
|
|
40
|
+
/** Total duration in milliseconds */
|
|
41
|
+
durationMs: number;
|
|
42
|
+
/** Embedding rate in messages per second */
|
|
43
|
+
rate: number;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Model state comparison result.
|
|
47
|
+
*
|
|
48
|
+
* Used to detect model changes and determine whether re-embedding
|
|
49
|
+
* is needed. Carries human-readable model names for user prompts.
|
|
50
|
+
*/
|
|
51
|
+
export interface ModelState {
|
|
52
|
+
/** Whether the configured model differs from the stored model */
|
|
53
|
+
modelChanged: boolean;
|
|
54
|
+
/** Whether all embeddings need to be regenerated */
|
|
55
|
+
needsReEmbed: boolean;
|
|
56
|
+
/** Hash of the previously-used model (from embedding_state) */
|
|
57
|
+
storedHash?: string;
|
|
58
|
+
/** Hash of the currently-configured model */
|
|
59
|
+
currentHash: string;
|
|
60
|
+
/**
|
|
61
|
+
* Human-readable name of the previously-used model.
|
|
62
|
+
* Falls back to storedHash if the stored name is unavailable (legacy data).
|
|
63
|
+
*/
|
|
64
|
+
storedModelName?: string;
|
|
65
|
+
/** Human-readable name of the currently-configured model (from config) */
|
|
66
|
+
currentModelName: string;
|
|
67
|
+
/** Number of existing embeddings (for re-embedding cost estimation) */
|
|
68
|
+
embeddedCount?: number;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Compute a model hash from embedding configuration.
|
|
72
|
+
*
|
|
73
|
+
* Generates a SHA-256 hash of the "provider:model:dimensions" string,
|
|
74
|
+
* truncated to 16 hex characters. Used for model change detection.
|
|
75
|
+
*
|
|
76
|
+
* @param config Embedding config with provider, model, and dimensions
|
|
77
|
+
* @returns 16-character hex hash string
|
|
78
|
+
*/
|
|
79
|
+
export declare function computeModelHash(config: Pick<EmbeddingServiceConfig, "provider" | "model" | "dimensions">): string;
|
|
80
|
+
/**
|
|
81
|
+
* Application service for embedding orchestration.
|
|
82
|
+
*
|
|
83
|
+
* Manages the embedding lifecycle: model state detection, batch embedding,
|
|
84
|
+
* progress reporting, and re-embedding on model change. Dependencies are
|
|
85
|
+
* injected via constructor for testability.
|
|
86
|
+
*/
|
|
87
|
+
export declare class EmbeddingService {
|
|
88
|
+
private readonly repository;
|
|
89
|
+
private readonly provider;
|
|
90
|
+
private readonly batchSize;
|
|
91
|
+
private readonly modelHash;
|
|
92
|
+
private readonly modelName;
|
|
93
|
+
private readonly redactor;
|
|
94
|
+
constructor(deps: {
|
|
95
|
+
repository: IEmbeddingRepository;
|
|
96
|
+
provider: IEmbeddingProvider;
|
|
97
|
+
config: EmbeddingServiceConfig;
|
|
98
|
+
redactor?: IRedactor;
|
|
99
|
+
});
|
|
100
|
+
/**
|
|
101
|
+
* Check whether the configured model matches the stored model.
|
|
102
|
+
*
|
|
103
|
+
* Compares the current model hash against what is stored in
|
|
104
|
+
* embedding_state. Returns model state with human-readable names
|
|
105
|
+
* for user-facing prompts.
|
|
106
|
+
*
|
|
107
|
+
* @returns Model state comparison result
|
|
108
|
+
*/
|
|
109
|
+
checkModelState(): ModelState;
|
|
110
|
+
/**
|
|
111
|
+
* Embed all unembedded messages in batches.
|
|
112
|
+
*
|
|
113
|
+
* Queries for unembedded messages, sends them to the provider in
|
|
114
|
+
* batch-sized chunks, and stores the results. Calls onProgress
|
|
115
|
+
* after each batch completes.
|
|
116
|
+
*
|
|
117
|
+
* @param options Embedding options (progress callback)
|
|
118
|
+
* @returns Summary of the embedding operation
|
|
119
|
+
*/
|
|
120
|
+
embedUnembedded(options?: EmbedOptions): Promise<EmbedResult>;
|
|
121
|
+
/**
|
|
122
|
+
* Clear all existing embeddings and re-embed everything.
|
|
123
|
+
*
|
|
124
|
+
* Used when the model has changed and all embeddings need
|
|
125
|
+
* to be regenerated. Clears first, then embeds.
|
|
126
|
+
*
|
|
127
|
+
* @param options Embedding options (progress callback)
|
|
128
|
+
* @returns Summary of the re-embedding operation
|
|
129
|
+
*/
|
|
130
|
+
clearAndReembed(options?: EmbedOptions): Promise<EmbedResult>;
|
|
131
|
+
}
|