open-mem 0.2.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.
Files changed (53) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/LICENSE +21 -0
  3. package/README.md +309 -0
  4. package/dist/ai/compressor.d.ts +43 -0
  5. package/dist/ai/compressor.d.ts.map +1 -0
  6. package/dist/ai/parser.d.ts +35 -0
  7. package/dist/ai/parser.d.ts.map +1 -0
  8. package/dist/ai/prompts.d.ts +15 -0
  9. package/dist/ai/prompts.d.ts.map +1 -0
  10. package/dist/ai/summarizer.d.ts +30 -0
  11. package/dist/ai/summarizer.d.ts.map +1 -0
  12. package/dist/config.d.ts +16 -0
  13. package/dist/config.d.ts.map +1 -0
  14. package/dist/context/builder.d.ts +11 -0
  15. package/dist/context/builder.d.ts.map +1 -0
  16. package/dist/context/progressive.d.ts +13 -0
  17. package/dist/context/progressive.d.ts.map +1 -0
  18. package/dist/db/database.d.ts +45 -0
  19. package/dist/db/database.d.ts.map +1 -0
  20. package/dist/db/observations.d.ts +17 -0
  21. package/dist/db/observations.d.ts.map +1 -0
  22. package/dist/db/pending.d.ts +20 -0
  23. package/dist/db/pending.d.ts.map +1 -0
  24. package/dist/db/schema.d.ts +13 -0
  25. package/dist/db/schema.d.ts.map +1 -0
  26. package/dist/db/sessions.d.ts +17 -0
  27. package/dist/db/sessions.d.ts.map +1 -0
  28. package/dist/db/summaries.d.ts +12 -0
  29. package/dist/db/summaries.d.ts.map +1 -0
  30. package/dist/hooks/compaction.d.ts +19 -0
  31. package/dist/hooks/compaction.d.ts.map +1 -0
  32. package/dist/hooks/context-inject.d.ts +19 -0
  33. package/dist/hooks/context-inject.d.ts.map +1 -0
  34. package/dist/hooks/session-events.d.ts +18 -0
  35. package/dist/hooks/session-events.d.ts.map +1 -0
  36. package/dist/hooks/tool-capture.d.ts +25 -0
  37. package/dist/hooks/tool-capture.d.ts.map +1 -0
  38. package/dist/index.d.ts +5 -0
  39. package/dist/index.d.ts.map +1 -0
  40. package/dist/index.js +361 -0
  41. package/dist/queue/processor.d.ts +52 -0
  42. package/dist/queue/processor.d.ts.map +1 -0
  43. package/dist/tools/recall.d.ts +4 -0
  44. package/dist/tools/recall.d.ts.map +1 -0
  45. package/dist/tools/save.d.ts +5 -0
  46. package/dist/tools/save.d.ts.map +1 -0
  47. package/dist/tools/search.d.ts +5 -0
  48. package/dist/tools/search.d.ts.map +1 -0
  49. package/dist/tools/timeline.d.ts +6 -0
  50. package/dist/tools/timeline.d.ts.map +1 -0
  51. package/dist/types.d.ts +177 -0
  52. package/dist/types.d.ts.map +1 -0
  53. package/package.json +60 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,38 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.2.0] - 2026-02-06
9
+
10
+ ### Added
11
+ - `mem-recall` tool for fetching full observation details by ID
12
+ - Progressive disclosure context injection with type icons, token costs, and file grouping
13
+ - `<private>` tag support for user-controlled content exclusion from memory
14
+ - Structured session summaries with request, investigated, learned, completed, and next steps fields
15
+ - Concept vocabulary guidance in AI compression prompts (how-it-works, gotcha, pattern, trade-off, etc.)
16
+ - Context injection configuration options (token cost display, observation type filters, full observation count)
17
+
18
+ ### Fixed
19
+ - README `OPEN_MEM_CONTEXT_INJECTION` default incorrectly documented as `false` (actual default: `true`)
20
+ - Missing `.open-mem/` in project .gitignore
21
+
22
+ ### Changed
23
+ - License changed from AGPL-3.0 to MIT
24
+
25
+ ## [0.1.0] - 2026-01-15
26
+
27
+ ### Added
28
+ - Initial release
29
+ - Automatic observation capture from tool executions
30
+ - AI-powered compression using Claude (optional — works without API key)
31
+ - SQLite + FTS5 full-text search for fast retrieval
32
+ - Context injection into new sessions via system prompt
33
+ - Three custom tools: `mem-search`, `mem-save`, `mem-timeline`
34
+ - Session summaries with AI-generated narratives
35
+ - Progressive disclosure with token budget management
36
+ - Configurable sensitive content redaction
37
+ - Data retention policies (default: 90 days)
38
+ - 162 tests with 395 assertions
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Cristobal Callejon
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,309 @@
1
+ # open-mem
2
+
3
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
4
+ [![npm version](https://img.shields.io/npm/v/open-mem.svg)](https://www.npmjs.com/package/open-mem)
5
+ [![Bun](https://img.shields.io/badge/Bun-%3E%3D1.0-pink.svg)](https://bun.sh)
6
+
7
+ Persistent memory for [OpenCode](https://opencode.ai) — captures, compresses, and recalls context across coding sessions.
8
+
9
+ ## Requirements
10
+
11
+ - [OpenCode](https://opencode.ai) (the AI coding assistant)
12
+ - [Bun](https://bun.sh) >= 1.0
13
+
14
+ ## Quick Start
15
+
16
+ ### Install
17
+
18
+ ```bash
19
+ bun add open-mem
20
+ ```
21
+
22
+ ### Configure OpenCode
23
+
24
+ Add `open-mem` to the `plugin` array in your OpenCode config (`~/.config/opencode/opencode.json`):
25
+
26
+ ```json
27
+ {
28
+ "plugin": ["open-mem"]
29
+ }
30
+ ```
31
+
32
+ > **Note**: If you already have plugins, just append `"open-mem"` to the existing array.
33
+
34
+ That's it. open-mem starts capturing from your next OpenCode session.
35
+
36
+ ### Enable AI Compression (Optional)
37
+
38
+ For intelligent compression of observations using Claude:
39
+
40
+ ```bash
41
+ export ANTHROPIC_API_KEY=sk-ant-...
42
+ ```
43
+
44
+ Without an API key, open-mem still works — it falls back to a basic metadata extractor that captures tool names, file paths, and output snippets.
45
+
46
+ ## Key Features
47
+
48
+ - 🧠 **Automatic observation capture** from tool executions
49
+ - 🤖 **AI-powered compression** using Claude (optional — works without API key)
50
+ - 🔍 **SQLite + FTS5** full-text search for fast retrieval
51
+ - 💡 **Progressive disclosure** with token-cost-aware context injection
52
+ - 🔒 **Privacy controls** with `<private>` tag support
53
+ - 🛠️ **Four custom tools**: mem-search, mem-save, mem-timeline, mem-recall
54
+ - ⚡ **Zero-config setup** — works out of the box
55
+ - 📁 **All data stored locally** in your project directory
56
+
57
+ ## How It Works
58
+
59
+ open-mem runs in the background as an OpenCode plugin. When you use tools (reading files, running commands, editing code), it captures what happened. During idle time, it compresses those captures into structured observations using AI. At the start of your next session, it injects a compact memory index into the system prompt — so your agent knows what you've been working on.
60
+
61
+ ```
62
+ ┌─────────────────────────────────────────────────────┐
63
+ │ OpenCode │
64
+ │ │
65
+ │ tool.execute.after ───> [Tool Capture Hook] │
66
+ │ │ │
67
+ │ v │
68
+ │ [Pending Queue] │
69
+ │ │ │
70
+ │ session.idle ─────────> [Queue Processor] │
71
+ │ │ │
72
+ │ v │
73
+ │ [AI Compressor] ───> Anthropic │
74
+ │ │ │
75
+ │ v │
76
+ │ [SQLite + FTS5] │
77
+ │ │ │
78
+ │ system.transform <─── [Context Injector] │
79
+ │ │
80
+ │ mem-search ─────────> [FTS5 Search] │
81
+ │ mem-save ───────────> [Direct Save] │
82
+ │ mem-timeline ───────> [Session Query] │
83
+ │ mem-recall ─────────> [Full Observation Fetch] │
84
+ └─────────────────────────────────────────────────────┘
85
+ ```
86
+
87
+ ### Observation Capture
88
+
89
+ When you use tools in OpenCode (reading files, running commands, editing code), open-mem's `tool.execute.after` hook captures each execution as a pending observation. Sensitive content (API keys, tokens, passwords) is automatically redacted, and `<private>` blocks are stripped.
90
+
91
+ ### AI Compression
92
+
93
+ On `session.idle`, the queue processor batches pending observations and sends them to Claude for semantic compression. Each raw tool output is distilled into a structured observation with:
94
+
95
+ - Type classification (decision, bugfix, feature, refactor, discovery, change)
96
+ - Title and narrative summary
97
+ - Key facts extracted
98
+ - Concepts/tags for search
99
+ - Files involved
100
+
101
+ If no Anthropic API key is set, a fallback compressor extracts basic metadata without AI.
102
+
103
+ ### Progressive Disclosure
104
+
105
+ open-mem injects a compact index into the system prompt at session start. Each entry shows a type icon, title, token cost, and related files — giving the agent a map of what's in memory without consuming the full context window.
106
+
107
+ The agent sees *what* exists and decides *what to fetch* using `mem-search` and `mem-recall`. This minimizes context window usage while providing full access to all stored observations.
108
+
109
+ Example of an injected index entry:
110
+
111
+ ```
112
+ 🔧 [refactor] Extract pricing logic (~120 tokens) — src/pricing.ts
113
+ 💡 [discovery] FTS5 requires specific tokenizer config (~85 tokens)
114
+ ```
115
+
116
+ ### Session Compaction
117
+
118
+ During session compaction (`experimental.session.compacting`), open-mem injects memory context to preserve important information across compaction boundaries.
119
+
120
+ ## Custom Tools
121
+
122
+ ### mem-search
123
+
124
+ Search through past observations and session summaries using FTS5 full-text search.
125
+
126
+ | Argument | Type | Required | Description |
127
+ |----------|------|----------|-------------|
128
+ | `query` | string | yes | Search query (keywords, phrases, file paths) |
129
+ | `type` | enum | no | Filter by type: `decision`, `bugfix`, `feature`, `refactor`, `discovery`, `change` |
130
+ | `limit` | number | no | Max results (1–50, default: 10) |
131
+
132
+ ### mem-save
133
+
134
+ Manually save an important observation to memory.
135
+
136
+ | Argument | Type | Required | Description |
137
+ |----------|------|----------|-------------|
138
+ | `title` | string | yes | Brief title (max 80 chars) |
139
+ | `type` | enum | yes | Observation type: `decision`, `bugfix`, `feature`, `refactor`, `discovery`, `change` |
140
+ | `narrative` | string | yes | Detailed description of what to remember |
141
+ | `concepts` | string[] | no | Related concepts/tags |
142
+ | `files` | string[] | no | Related file paths |
143
+
144
+ ### mem-timeline
145
+
146
+ View a timeline of past coding sessions for the current project.
147
+
148
+ | Argument | Type | Required | Description |
149
+ |----------|------|----------|-------------|
150
+ | `limit` | number | no | Number of recent sessions (1–20, default: 5) |
151
+ | `sessionId` | string | no | Show details for a specific session |
152
+
153
+ ### mem-recall
154
+
155
+ Fetch full observation details by ID. Use after `mem-search` to get complete narratives, facts, concepts, and file lists for specific observations.
156
+
157
+ | Argument | Type | Required | Description |
158
+ |----------|------|----------|-------------|
159
+ | `ids` | string[] | yes | Observation IDs to fetch |
160
+ | `limit` | number | no | Maximum number of results (1–50, default: 10) |
161
+
162
+ ## Configuration
163
+
164
+ open-mem works out of the box with zero configuration. All settings can be customized via environment variables:
165
+
166
+ | Variable | Default | Description |
167
+ |----------|---------|-------------|
168
+ | `ANTHROPIC_API_KEY` | — | API key for AI compression (optional) |
169
+ | `OPEN_MEM_DB_PATH` | `.open-mem/memory.db` | Path to SQLite database |
170
+ | `OPEN_MEM_MODEL` | `claude-sonnet-4-20250514` | Model for AI compression |
171
+ | `OPEN_MEM_MAX_CONTEXT_TOKENS` | `4000` | Token budget for injected context |
172
+ | `OPEN_MEM_COMPRESSION` | `true` | Set to `false` to disable AI compression |
173
+ | `OPEN_MEM_CONTEXT_INJECTION` | `true` | Set to `false` to disable context injection |
174
+ | `OPEN_MEM_IGNORED_TOOLS` | — | Comma-separated tool names to ignore (e.g. `Bash,Glob`) |
175
+ | `OPEN_MEM_BATCH_SIZE` | `5` | Observations per processing batch |
176
+ | `OPEN_MEM_RETENTION_DAYS` | `90` | Delete observations older than N days (0 = forever) |
177
+ | `OPEN_MEM_LOG_LEVEL` | `warn` | Log verbosity: `debug`, `info`, `warn`, `error` |
178
+ | `OPEN_MEM_CONTEXT_SHOW_TOKEN_COSTS` | `true` | Show token costs in context index entries |
179
+ | `OPEN_MEM_CONTEXT_TYPES` | all | Observation types to include in context injection |
180
+ | `OPEN_MEM_CONTEXT_FULL_COUNT` | `3` | Number of recent observations shown in full |
181
+ | `OPEN_MEM_MAX_OBSERVATIONS` | `50` | Maximum observations to consider for context |
182
+
183
+ <details>
184
+ <summary><strong>Programmatic Configuration Reference</strong></summary>
185
+
186
+ If you need to configure open-mem programmatically (e.g. for testing or custom integrations), these are the full config options:
187
+
188
+ | Option | Type | Default | Description |
189
+ |--------|------|---------|-------------|
190
+ | `dbPath` | string | `.open-mem/memory.db` | SQLite database file path |
191
+ | `apiKey` | string | `undefined` | Anthropic API key |
192
+ | `model` | string | `claude-sonnet-4-20250514` | Claude model for compression |
193
+ | `maxTokensPerCompression` | number | `1024` | Max tokens per compression response |
194
+ | `compressionEnabled` | boolean | `true` | Enable AI compression |
195
+ | `contextInjectionEnabled` | boolean | `true` | Enable context injection |
196
+ | `maxContextTokens` | number | `4000` | Token budget for system prompt injection |
197
+ | `batchSize` | number | `5` | Observations per batch |
198
+ | `batchIntervalMs` | number | `30000` | Batch processing interval (ms) |
199
+ | `ignoredTools` | string[] | `[]` | Tool names to skip |
200
+ | `minOutputLength` | number | `50` | Minimum output length to capture |
201
+ | `maxIndexEntries` | number | `20` | Max observation index entries in context |
202
+ | `sensitivePatterns` | string[] | `[]` | Additional regex patterns to redact |
203
+ | `retentionDays` | number | `90` | Data retention period (0 = forever) |
204
+ | `maxDatabaseSizeMb` | number | `500` | Maximum database size |
205
+ | `logLevel` | string | `warn` | Log level: `debug`, `info`, `warn`, `error` |
206
+
207
+ </details>
208
+
209
+ ## Privacy & Security
210
+
211
+ ### Local Data Storage
212
+
213
+ All data is stored locally in your project's `.open-mem/` directory. No data leaves your machine except when AI compression is enabled.
214
+
215
+ ### Anthropic API
216
+
217
+ When AI compression is enabled, tool outputs are sent to Claude for compression. Disable with `OPEN_MEM_COMPRESSION=false` to keep everything fully local.
218
+
219
+ ### Automatic Redaction
220
+
221
+ open-mem automatically redacts common sensitive patterns before storage:
222
+
223
+ - API keys and tokens (e.g. `sk-ant-...`, `ghp_...`, `Bearer ...`)
224
+ - Passwords and secrets
225
+ - Environment variable values matching sensitive patterns
226
+ - Custom patterns via the `sensitivePatterns` config option
227
+
228
+ ### `<private>` Tags
229
+
230
+ Wrap any content in `<private>...</private>` tags to exclude it from memory entirely. Private blocks are stripped before observation capture — they never reach the database or the Anthropic API.
231
+
232
+ ```
233
+ <private>
234
+ This content will not be stored in memory.
235
+ </private>
236
+ ```
237
+
238
+ ### Gitignore
239
+
240
+ Add `.open-mem/` to your `.gitignore` to prevent committing memory data:
241
+
242
+ ```bash
243
+ echo '.open-mem/' >> .gitignore
244
+ ```
245
+
246
+ ## Troubleshooting
247
+
248
+ ### "AI compression enabled but no ANTHROPIC_API_KEY found"
249
+
250
+ This is a warning, not an error. open-mem works without an API key — it falls back to a basic metadata extractor. To enable AI compression:
251
+
252
+ ```bash
253
+ export ANTHROPIC_API_KEY=sk-ant-...
254
+ ```
255
+
256
+ ### Database errors
257
+
258
+ If you encounter SQLite errors, try removing the database and letting it recreate:
259
+
260
+ ```bash
261
+ rm -rf .open-mem/
262
+ ```
263
+
264
+ ### Context not appearing in sessions
265
+
266
+ 1. Verify the plugin is loaded: check OpenCode logs for `[open-mem]` messages
267
+ 2. Ensure `OPEN_MEM_CONTEXT_INJECTION` is not set to `false`
268
+ 3. Check that observations exist: use the `mem-timeline` tool
269
+ 4. The first session won't have context — observations must be captured first
270
+
271
+ ### High memory usage
272
+
273
+ If the database grows too large, adjust retention:
274
+
275
+ ```bash
276
+ export OPEN_MEM_RETENTION_DAYS=30
277
+ export OPEN_MEM_MAX_CONTEXT_TOKENS=2000
278
+ ```
279
+
280
+ ## Uninstalling
281
+
282
+ 1. Remove `"open-mem"` from the `plugin` array in your OpenCode config (`~/.config/opencode/opencode.json`).
283
+
284
+ 2. Remove the package:
285
+ ```bash
286
+ bun remove open-mem
287
+ ```
288
+
289
+ 3. Optionally, delete stored memory data:
290
+ ```bash
291
+ rm -rf .open-mem/
292
+ ```
293
+
294
+ ## Documentation
295
+
296
+ - [Getting Started](docs/getting-started.md) — installation, configuration, and first steps
297
+ - [Architecture](docs/architecture.md) — internal design, data flow, and source layout
298
+
299
+ ## Contributing
300
+
301
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, code style, and submission guidelines.
302
+
303
+ ## Changelog
304
+
305
+ See [CHANGELOG.md](CHANGELOG.md) for a detailed history of changes.
306
+
307
+ ## License
308
+
309
+ [MIT](LICENSE)
@@ -0,0 +1,43 @@
1
+ import { type ParsedObservation } from "./parser";
2
+ export interface CompressorConfig {
3
+ apiKey: string | undefined;
4
+ model: string;
5
+ maxTokensPerCompression: number;
6
+ compressionEnabled: boolean;
7
+ minOutputLength: number;
8
+ }
9
+ /**
10
+ * Compresses raw tool output into structured observations using the
11
+ * Anthropic Messages API. Falls back to a heuristic-based observation
12
+ * when the API is unavailable or disabled.
13
+ */
14
+ export declare class ObservationCompressor {
15
+ private client;
16
+ private config;
17
+ constructor(config: CompressorConfig);
18
+ /** Maximum input characters sent to the API (~12.5K tokens) */
19
+ static readonly MAX_INPUT_LENGTH = 50000;
20
+ /**
21
+ * Compress a single tool output into a structured observation.
22
+ * Returns `null` when compression is disabled, the output is too short,
23
+ * or the API call fails after retries.
24
+ */
25
+ compress(toolName: string, toolOutput: string, sessionContext?: string): Promise<ParsedObservation | null>;
26
+ /**
27
+ * Compress multiple items sequentially (avoids rate-limit bursts).
28
+ * Returns a map of `callId -> ParsedObservation | null`.
29
+ */
30
+ compressBatch(items: ReadonlyArray<{
31
+ toolName: string;
32
+ toolOutput: string;
33
+ callId: string;
34
+ sessionContext?: string;
35
+ }>): Promise<Map<string, ParsedObservation | null>>;
36
+ /**
37
+ * Produce a basic observation from tool metadata when AI compression
38
+ * is unavailable.
39
+ */
40
+ createFallbackObservation(toolName: string, toolOutput: string): ParsedObservation;
41
+ isAvailable(): Promise<boolean>;
42
+ }
43
+ //# sourceMappingURL=compressor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compressor.d.ts","sourceRoot":"","sources":["../../src/ai/compressor.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,iBAAiB,EAA4B,MAAM,UAAU,CAAC;AAO5E,MAAM,WAAW,gBAAgB;IAChC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,uBAAuB,EAAE,MAAM,CAAC;IAChC,kBAAkB,EAAE,OAAO,CAAC;IAC5B,eAAe,EAAE,MAAM,CAAC;CACxB;AAMD;;;;GAIG;AACH,qBAAa,qBAAqB;IACjC,OAAO,CAAC,MAAM,CAAmB;IACjC,OAAO,CAAC,MAAM,CAAmB;gBAErB,MAAM,EAAE,gBAAgB;IAUpC,+DAA+D;IAC/D,MAAM,CAAC,QAAQ,CAAC,gBAAgB,SAAU;IAE1C;;;;OAIG;IACG,QAAQ,CACb,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,cAAc,CAAC,EAAE,MAAM,GACrB,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC;IAiDpC;;;OAGG;IACG,aAAa,CAClB,KAAK,EAAE,aAAa,CAAC;QACpB,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,EAAE,MAAM,CAAC;QACnB,MAAM,EAAE,MAAM,CAAC;QACf,cAAc,CAAC,EAAE,MAAM,CAAC;KACxB,CAAC,GACA,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,iBAAiB,GAAG,IAAI,CAAC,CAAC;IAqBjD;;;OAGG;IACH,yBAAyB,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,iBAAiB;IAqB5E,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;CAarC"}
@@ -0,0 +1,35 @@
1
+ import type { ObservationType } from "../types";
2
+ export interface ParsedObservation {
3
+ type: ObservationType;
4
+ title: string;
5
+ subtitle: string;
6
+ facts: string[];
7
+ narrative: string;
8
+ concepts: string[];
9
+ filesRead: string[];
10
+ filesModified: string[];
11
+ }
12
+ export interface ParsedSummary {
13
+ summary: string;
14
+ keyDecisions: string[];
15
+ filesModified: string[];
16
+ concepts: string[];
17
+ request?: string;
18
+ investigated?: string;
19
+ learned?: string;
20
+ completed?: string;
21
+ nextSteps?: string;
22
+ }
23
+ /**
24
+ * Parse an AI response containing `<observation>...</observation>` XML into
25
+ * a structured object. Returns `null` if the response cannot be parsed at all.
26
+ */
27
+ export declare function parseObservationResponse(response: string): ParsedObservation | null;
28
+ /**
29
+ * Parse an AI response containing `<session_summary>...</session_summary>`
30
+ * into a structured object. Returns `null` if unparseable.
31
+ */
32
+ export declare function parseSummaryResponse(response: string): ParsedSummary | null;
33
+ /** Rough token count (4 chars ~ 1 token for English text) */
34
+ export declare function estimateTokens(text: string): number;
35
+ //# sourceMappingURL=parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/ai/parser.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAMhD,MAAM,WAAW,iBAAiB;IACjC,IAAI,EAAE,eAAe,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,aAAa,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,aAAa;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,QAAQ,EAAE,MAAM,EAAE,CAAC;IAEnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAyCD;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI,CA4BnF;AAMD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CA0B3E;AAMD,6DAA6D;AAC7D,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEnD"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Build a prompt that instructs the AI to compress raw tool output into a
3
+ * structured observation (type, title, facts, narrative, concepts, files).
4
+ */
5
+ export declare function buildCompressionPrompt(toolName: string, toolOutput: string, sessionContext?: string): string;
6
+ /**
7
+ * Build a prompt that instructs the AI to produce a session summary from
8
+ * a list of observations.
9
+ */
10
+ export declare function buildSummarizationPrompt(observations: ReadonlyArray<{
11
+ type: string;
12
+ title: string;
13
+ narrative: string;
14
+ }>, sessionId: string): string;
15
+ //# sourceMappingURL=prompts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../src/ai/prompts.ts"],"names":[],"mappings":"AAIA;;;GAGG;AACH,wBAAgB,sBAAsB,CACrC,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,cAAc,CAAC,EAAE,MAAM,GACrB,MAAM,CAkDR;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CACvC,YAAY,EAAE,aAAa,CAAC;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CAClB,CAAC,EACF,SAAS,EAAE,MAAM,GACf,MAAM,CAwCR"}
@@ -0,0 +1,30 @@
1
+ import type { Observation } from "../types";
2
+ import { type ParsedSummary } from "./parser";
3
+ export interface SummarizerConfig {
4
+ apiKey: string | undefined;
5
+ model: string;
6
+ maxTokensPerCompression: number;
7
+ compressionEnabled: boolean;
8
+ }
9
+ /**
10
+ * Generates a concise summary of a coding session from its observations.
11
+ * Falls back to a heuristic aggregation when the API is unavailable.
12
+ */
13
+ export declare class SessionSummarizer {
14
+ private client;
15
+ private config;
16
+ constructor(config: SummarizerConfig);
17
+ /**
18
+ * Summarize a session's observations via the Anthropic API.
19
+ * Returns `null` for empty observation lists, falls back to heuristic
20
+ * summary when the API is disabled or errors out.
21
+ */
22
+ summarize(sessionId: string, observations: ReadonlyArray<Observation>): Promise<ParsedSummary | null>;
23
+ /**
24
+ * Build a summary by aggregating observation metadata — no AI required.
25
+ */
26
+ createFallbackSummary(observations: ReadonlyArray<Observation>): ParsedSummary;
27
+ /** Whether a session has enough observations to warrant summarization */
28
+ shouldSummarize(observationCount: number): boolean;
29
+ }
30
+ //# sourceMappingURL=summarizer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"summarizer.d.ts","sourceRoot":"","sources":["../../src/ai/summarizer.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,EAAE,KAAK,aAAa,EAAwB,MAAM,UAAU,CAAC;AAOpE,MAAM,WAAW,gBAAgB;IAChC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,uBAAuB,EAAE,MAAM,CAAC;IAChC,kBAAkB,EAAE,OAAO,CAAC;CAC5B;AAMD;;;GAGG;AACH,qBAAa,iBAAiB;IAC7B,OAAO,CAAC,MAAM,CAAmB;IACjC,OAAO,CAAC,MAAM,CAAmB;gBAErB,MAAM,EAAE,gBAAgB;IAUpC;;;;OAIG;IACG,SAAS,CACd,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,aAAa,CAAC,WAAW,CAAC,GACtC,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IA2ChC;;OAEG;IACH,qBAAqB,CAAC,YAAY,EAAE,aAAa,CAAC,WAAW,CAAC,GAAG,aAAa;IAqC9E,yEAAyE;IACzE,eAAe,CAAC,gBAAgB,EAAE,MAAM,GAAG,OAAO;CAGlD"}
@@ -0,0 +1,16 @@
1
+ import type { OpenMemConfig } from "./types";
2
+ /**
3
+ * Resolve configuration by merging defaults, environment variables, and overrides.
4
+ * Priority: defaults < env vars < overrides
5
+ */
6
+ export declare function resolveConfig(projectDir: string, overrides?: Partial<OpenMemConfig>): OpenMemConfig;
7
+ /**
8
+ * Validate a resolved configuration. Returns an array of error messages.
9
+ * An empty array means the configuration is valid.
10
+ */
11
+ export declare function validateConfig(config: OpenMemConfig): string[];
12
+ /** Get a copy of the default configuration */
13
+ export declare function getDefaultConfig(): OpenMemConfig;
14
+ /** Ensure the database directory exists */
15
+ export declare function ensureDbDirectory(config: OpenMemConfig): Promise<void>;
16
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAmB,aAAa,EAAE,MAAM,SAAS,CAAC;AAyF9D;;;GAGG;AACH,wBAAgB,aAAa,CAC5B,UAAU,EAAE,MAAM,EAClB,SAAS,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,GAChC,aAAa,CAoBf;AAMD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,EAAE,CAsB9D;AAMD,8CAA8C;AAC9C,wBAAgB,gBAAgB,IAAI,aAAa,CAEhD;AAED,2CAA2C;AAC3C,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAI5E"}
@@ -0,0 +1,11 @@
1
+ import type { ObservationType } from "../types";
2
+ import type { ProgressiveContext } from "./progressive";
3
+ export interface ContextBuilderConfig {
4
+ showTokenCosts: boolean;
5
+ observationTypes: ObservationType[] | "all";
6
+ fullObservationCount: number;
7
+ showLastSummary: boolean;
8
+ }
9
+ export declare function buildContextString(context: ProgressiveContext, config?: ContextBuilderConfig): string;
10
+ export declare function buildCompactContext(context: ProgressiveContext): string;
11
+ //# sourceMappingURL=builder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"builder.d.ts","sourceRoot":"","sources":["../../src/context/builder.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAiC,eAAe,EAAE,MAAM,UAAU,CAAC;AAC/E,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAMxD,MAAM,WAAW,oBAAoB;IACpC,cAAc,EAAE,OAAO,CAAC;IACxB,gBAAgB,EAAE,eAAe,EAAE,GAAG,KAAK,CAAC;IAC5C,oBAAoB,EAAE,MAAM,CAAC;IAC7B,eAAe,EAAE,OAAO,CAAC;CACzB;AA0BD,wBAAgB,kBAAkB,CACjC,OAAO,EAAE,kBAAkB,EAC3B,MAAM,GAAE,oBAA6C,GACnD,MAAM,CAgFR;AA8BD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,kBAAkB,GAAG,MAAM,CAoBvE"}
@@ -0,0 +1,13 @@
1
+ import type { Observation, ObservationIndex, Session, SessionSummary } from "../types";
2
+ export interface ProgressiveContext {
3
+ recentSummaries: SessionSummary[];
4
+ observationIndex: ObservationIndex[];
5
+ fullObservations: Observation[];
6
+ totalTokens: number;
7
+ }
8
+ /**
9
+ * Select summaries and observation-index entries that fit within the
10
+ * token budget. Summaries are higher priority (richer context).
11
+ */
12
+ export declare function buildProgressiveContext(_recentSessions: ReadonlyArray<Session>, summaries: ReadonlyArray<SessionSummary>, observationIndex: ReadonlyArray<ObservationIndex>, maxTokens: number, fullObservations?: ReadonlyArray<Observation>): ProgressiveContext;
13
+ //# sourceMappingURL=progressive.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"progressive.d.ts","sourceRoot":"","sources":["../../src/context/progressive.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAMvF,MAAM,WAAW,kBAAkB;IAClC,eAAe,EAAE,cAAc,EAAE,CAAC;IAClC,gBAAgB,EAAE,gBAAgB,EAAE,CAAC;IACrC,gBAAgB,EAAE,WAAW,EAAE,CAAC;IAChC,WAAW,EAAE,MAAM,CAAC;CACpB;AAMD;;;GAGG;AACH,wBAAgB,uBAAuB,CACtC,eAAe,EAAE,aAAa,CAAC,OAAO,CAAC,EACvC,SAAS,EAAE,aAAa,CAAC,cAAc,CAAC,EACxC,gBAAgB,EAAE,aAAa,CAAC,gBAAgB,CAAC,EACjD,SAAS,EAAE,MAAM,EACjB,gBAAgB,GAAE,aAAa,CAAC,WAAW,CAAM,GAC/C,kBAAkB,CA2BpB"}
@@ -0,0 +1,45 @@
1
+ import { Database as BunDatabase, type SQLQueryBindings } from "bun:sqlite";
2
+ /** Param array accepted by query helpers */
3
+ type Params = SQLQueryBindings[];
4
+ export interface Migration {
5
+ version: number;
6
+ name: string;
7
+ up: string;
8
+ }
9
+ /**
10
+ * Manages the SQLite connection lifecycle: opening, configuring (WAL mode,
11
+ * foreign keys, busy timeout), running migrations, and exposing typed
12
+ * query helpers. Wraps bun:sqlite.
13
+ */
14
+ export declare class Database {
15
+ private db;
16
+ constructor(dbPath: string);
17
+ private open;
18
+ private configure;
19
+ private ensureMigrationTable;
20
+ /**
21
+ * Run pending migrations in version order. Already-applied migrations
22
+ * are skipped. Each migration runs inside a transaction.
23
+ */
24
+ migrate(migrations: Migration[]): void;
25
+ /** Execute a write statement (INSERT / UPDATE / DELETE) with optional params */
26
+ run(sql: string, params?: Params): void;
27
+ /** Fetch a single row, or null if not found */
28
+ get<T>(sql: string, params?: Params): T | null;
29
+ /** Fetch all matching rows */
30
+ all<T>(sql: string, params?: Params): T[];
31
+ /** Execute raw SQL (multiple statements, no params) */
32
+ exec(sql: string): void;
33
+ /** Wrap a function in a SQLite transaction — auto-commits or rolls back */
34
+ transaction<T>(fn: () => T): T;
35
+ /** Close the database connection */
36
+ close(): void;
37
+ /** Check whether the connection is still usable */
38
+ get isOpen(): boolean;
39
+ /** Access the underlying bun:sqlite instance for advanced use */
40
+ get raw(): BunDatabase;
41
+ }
42
+ /** Create and configure a Database instance at the given path */
43
+ export declare function createDatabase(dbPath: string): Database;
44
+ export {};
45
+ //# sourceMappingURL=database.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/db/database.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,QAAQ,IAAI,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAG5E,4CAA4C;AAC5C,KAAK,MAAM,GAAG,gBAAgB,EAAE,CAAC;AAMjC,MAAM,WAAW,SAAS;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;CACX;AAMD;;;;GAIG;AACH,qBAAa,QAAQ;IACpB,OAAO,CAAC,EAAE,CAAc;gBAEZ,MAAM,EAAE,MAAM;IAS1B,OAAO,CAAC,IAAI;IAWZ,OAAO,CAAC,SAAS;IAejB,OAAO,CAAC,oBAAoB;IAU5B;;;OAGG;IACI,OAAO,CAAC,UAAU,EAAE,SAAS,EAAE,GAAG,IAAI;IA0B7C,gFAAgF;IACzE,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI;IAS9C,+CAA+C;IACxC,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI;IAKrD,8BAA8B;IACvB,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,CAAC,EAAE;IAKhD,uDAAuD;IAChD,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAI9B,2EAA2E;IACpE,WAAW,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC;IAQrC,oCAAoC;IAC7B,KAAK,IAAI,IAAI;IAIpB,mDAAmD;IACnD,IAAW,MAAM,IAAI,OAAO,CAO3B;IAED,iEAAiE;IACjE,IAAW,GAAG,IAAI,WAAW,CAE5B;CACD;AAMD,iEAAiE;AACjE,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,CAEvD"}
@@ -0,0 +1,17 @@
1
+ import type { Observation, ObservationIndex, SearchQuery, SearchResult } from "../types";
2
+ import type { Database } from "./database";
3
+ export declare class ObservationRepository {
4
+ private db;
5
+ constructor(db: Database);
6
+ create(data: Omit<Observation, "id" | "createdAt">): Observation;
7
+ getById(id: string): Observation | null;
8
+ getBySession(sessionId: string): Observation[];
9
+ getCount(sessionId?: string): number;
10
+ /** Lightweight index for progressive disclosure */
11
+ getIndex(projectPath: string, limit?: number): ObservationIndex[];
12
+ search(query: SearchQuery): SearchResult[];
13
+ searchByConcept(concept: string, limit?: number): Observation[];
14
+ searchByFile(filePath: string, limit?: number): Observation[];
15
+ private mapRow;
16
+ }
17
+ //# sourceMappingURL=observations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"observations.d.ts","sourceRoot":"","sources":["../../src/db/observations.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACX,WAAW,EACX,gBAAgB,EAEhB,WAAW,EACX,YAAY,EACZ,MAAM,UAAU,CAAC;AAClB,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,qBAAa,qBAAqB;IACrB,OAAO,CAAC,EAAE;gBAAF,EAAE,EAAE,QAAQ;IAMhC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,GAAG,WAAW,CAAC,GAAG,WAAW;IAiChE,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI;IAOvC,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,WAAW,EAAE;IAS9C,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM;IAYpC,mDAAmD;IACnD,QAAQ,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG,gBAAgB,EAAE;IAyB7D,MAAM,CAAC,KAAK,EAAE,WAAW,GAAG,YAAY,EAAE;IA6B1C,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG,WAAW,EAAE;IAc3D,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG,WAAW,EAAE;IAkBzD,OAAO,CAAC,MAAM;CAkBd"}