@londer/cortex 0.1.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/CHANGELOG.md +62 -0
- package/LICENSE +21 -0
- package/README.md +183 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +278 -0
- package/dist/cli.js.map +1 -0
- package/dist/config-store.d.ts +15 -0
- package/dist/config-store.d.ts.map +1 -0
- package/dist/config-store.js +86 -0
- package/dist/config-store.js.map +1 -0
- package/dist/config.d.ts +28 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +39 -0
- package/dist/config.js.map +1 -0
- package/dist/consolidation/cluster-finder.d.ts +5 -0
- package/dist/consolidation/cluster-finder.d.ts.map +1 -0
- package/dist/consolidation/cluster-finder.js +43 -0
- package/dist/consolidation/cluster-finder.js.map +1 -0
- package/dist/consolidation/consolidator.d.ts +29 -0
- package/dist/consolidation/consolidator.d.ts.map +1 -0
- package/dist/consolidation/consolidator.js +296 -0
- package/dist/consolidation/consolidator.js.map +1 -0
- package/dist/embedding/embedder.d.ts +9 -0
- package/dist/embedding/embedder.d.ts.map +1 -0
- package/dist/embedding/embedder.js +89 -0
- package/dist/embedding/embedder.js.map +1 -0
- package/dist/extraction/auto-extractor.d.ts +7 -0
- package/dist/extraction/auto-extractor.d.ts.map +1 -0
- package/dist/extraction/auto-extractor.js +174 -0
- package/dist/extraction/auto-extractor.js.map +1 -0
- package/dist/extraction/conversation-buffer.d.ts +15 -0
- package/dist/extraction/conversation-buffer.d.ts.map +1 -0
- package/dist/extraction/conversation-buffer.js +60 -0
- package/dist/extraction/conversation-buffer.js.map +1 -0
- package/dist/extraction/extractor.d.ts +23 -0
- package/dist/extraction/extractor.d.ts.map +1 -0
- package/dist/extraction/extractor.js +108 -0
- package/dist/extraction/extractor.js.map +1 -0
- package/dist/extraction/tier1-regex.d.ts +7 -0
- package/dist/extraction/tier1-regex.d.ts.map +1 -0
- package/dist/extraction/tier1-regex.js +119 -0
- package/dist/extraction/tier1-regex.js.map +1 -0
- package/dist/extraction/tier2-nlp.d.ts +13 -0
- package/dist/extraction/tier2-nlp.d.ts.map +1 -0
- package/dist/extraction/tier2-nlp.js +195 -0
- package/dist/extraction/tier2-nlp.js.map +1 -0
- package/dist/extraction/tier3-llm.d.ts +8 -0
- package/dist/extraction/tier3-llm.d.ts.map +1 -0
- package/dist/extraction/tier3-llm.js +57 -0
- package/dist/extraction/tier3-llm.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +398 -0
- package/dist/index.js.map +1 -0
- package/dist/llm/anthropic-client.d.ts +18 -0
- package/dist/llm/anthropic-client.d.ts.map +1 -0
- package/dist/llm/anthropic-client.js +116 -0
- package/dist/llm/anthropic-client.js.map +1 -0
- package/dist/orchestration/ranker.d.ts +18 -0
- package/dist/orchestration/ranker.d.ts.map +1 -0
- package/dist/orchestration/ranker.js +124 -0
- package/dist/orchestration/ranker.js.map +1 -0
- package/dist/orchestration/scope.d.ts +15 -0
- package/dist/orchestration/scope.d.ts.map +1 -0
- package/dist/orchestration/scope.js +28 -0
- package/dist/orchestration/scope.js.map +1 -0
- package/dist/storage/neo4j.d.ts +19 -0
- package/dist/storage/neo4j.d.ts.map +1 -0
- package/dist/storage/neo4j.js +246 -0
- package/dist/storage/neo4j.js.map +1 -0
- package/dist/storage/qdrant.d.ts +21 -0
- package/dist/storage/qdrant.d.ts.map +1 -0
- package/dist/storage/qdrant.js +125 -0
- package/dist/storage/qdrant.js.map +1 -0
- package/dist/storage/sqlite.d.ts +23 -0
- package/dist/storage/sqlite.d.ts.map +1 -0
- package/dist/storage/sqlite.js +162 -0
- package/dist/storage/sqlite.js.map +1 -0
- package/dist/templates/claude-instructions.d.ts +11 -0
- package/dist/templates/claude-instructions.d.ts.map +1 -0
- package/dist/templates/claude-instructions.js +110 -0
- package/dist/templates/claude-instructions.js.map +1 -0
- package/dist/tools/config.d.ts +21 -0
- package/dist/tools/config.d.ts.map +1 -0
- package/dist/tools/config.js +96 -0
- package/dist/tools/config.js.map +1 -0
- package/dist/tools/consolidate.d.ts +4 -0
- package/dist/tools/consolidate.d.ts.map +1 -0
- package/dist/tools/consolidate.js +16 -0
- package/dist/tools/consolidate.js.map +1 -0
- package/dist/tools/context.d.ts +8 -0
- package/dist/tools/context.d.ts.map +1 -0
- package/dist/tools/context.js +84 -0
- package/dist/tools/context.js.map +1 -0
- package/dist/tools/forget.d.ts +7 -0
- package/dist/tools/forget.d.ts.map +1 -0
- package/dist/tools/forget.js +49 -0
- package/dist/tools/forget.js.map +1 -0
- package/dist/tools/graph-query.d.ts +5 -0
- package/dist/tools/graph-query.d.ts.map +1 -0
- package/dist/tools/graph-query.js +35 -0
- package/dist/tools/graph-query.js.map +1 -0
- package/dist/tools/ingest.d.ts +8 -0
- package/dist/tools/ingest.d.ts.map +1 -0
- package/dist/tools/ingest.js +101 -0
- package/dist/tools/ingest.js.map +1 -0
- package/dist/tools/relate.d.ts +4 -0
- package/dist/tools/relate.d.ts.map +1 -0
- package/dist/tools/relate.js +10 -0
- package/dist/tools/relate.js.map +1 -0
- package/dist/tools/search.d.ts +6 -0
- package/dist/tools/search.d.ts.map +1 -0
- package/dist/tools/search.js +43 -0
- package/dist/tools/search.js.map +1 -0
- package/dist/tools/store.d.ts +8 -0
- package/dist/tools/store.d.ts.map +1 -0
- package/dist/tools/store.js +64 -0
- package/dist/tools/store.js.map +1 -0
- package/dist/types/index.d.ts +289 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +3 -0
- package/dist/types/index.js.map +1 -0
- package/docker-compose.yml +27 -0
- package/package.json +71 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
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-03-15
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **Tiered entity extraction** — Three-tier system (Regex → NLP → LLM) with automatic fallback
|
|
13
|
+
- Tier 1: Enhanced regex for snake_case, camelCase, PascalCase, quoted identifiers, and verb-pattern relationships
|
|
14
|
+
- Tier 2: NLP via compromise.js with POS tagging, named entity recognition, and embedding-based dedup
|
|
15
|
+
- Tier 3: Claude API extraction with structured JSON output (requires API key)
|
|
16
|
+
- In-memory LRU cache (SHA-256 key, 5 min TTL, 500 entries)
|
|
17
|
+
- **Automatic memory extraction** — Cortex observes tool calls and proactively extracts knowledge
|
|
18
|
+
- Conversation buffer with configurable size and debounce timer
|
|
19
|
+
- LLM-powered extraction when API key available, local heuristics as fallback
|
|
20
|
+
- Sentence scoring by technical term density, decision words, pattern words
|
|
21
|
+
- Embedding-based dedup against existing memories (threshold > 0.92)
|
|
22
|
+
- **Memory consolidation** — Background process to merge redundant memories
|
|
23
|
+
- Cluster detection via cosine similarity in Qdrant
|
|
24
|
+
- LLM mode: smart merge, contradiction resolution, archival with reasoning
|
|
25
|
+
- Local mode: near-identical dedup (> 0.95), flagging for review (> 0.90)
|
|
26
|
+
- Auto-consolidation timer with configurable interval
|
|
27
|
+
- Audit trail via consolidation_log table
|
|
28
|
+
- **Runtime configuration** — `memory_config` tool for live settings changes
|
|
29
|
+
- View full config with storage status and usage stats
|
|
30
|
+
- Set API key, extraction tier, auto-extract, and consolidation at runtime
|
|
31
|
+
- Persists to `~/.cortex/runtime-config.json`
|
|
32
|
+
- API key masked in responses
|
|
33
|
+
- **New MCP tools**: `memory_ingest`, `memory_consolidate`, `memory_config`
|
|
34
|
+
- **LLM client** — Anthropic API wrapper with retry logic, JSON extraction, token tracking
|
|
35
|
+
- **CLI** (`cortex` command) — serve, setup, init, config, consolidate, version, help
|
|
36
|
+
- **`cortex init`** — generates Claude Code instructions for project or global CLAUDE.md (idempotent, marker-based updates)
|
|
37
|
+
- **npm package** — Published as `@londer/cortex` with proper build step
|
|
38
|
+
- **Conventional commits** — commitlint + husky for commit message enforcement
|
|
39
|
+
- **Build infrastructure** — TypeScript compilation to `dist/`, declaration maps, source maps
|
|
40
|
+
|
|
41
|
+
### Changed
|
|
42
|
+
|
|
43
|
+
- `memory_store` now auto-extracts entities when not explicitly provided
|
|
44
|
+
- `memory_context` uses tiered extractor instead of basic regex
|
|
45
|
+
- SQLite schema extended with source_type, consolidated_from, extraction_confidence, extraction_tier columns
|
|
46
|
+
- MCP server version bumped to 0.2.0
|
|
47
|
+
- Package renamed to `@londer/cortex`
|
|
48
|
+
- Added `CONTRIBUTING.md` with branching strategy, commit rules, and merge policy
|
|
49
|
+
|
|
50
|
+
## [0.1.0] - 2026-03-15
|
|
51
|
+
|
|
52
|
+
### Added
|
|
53
|
+
|
|
54
|
+
- MCP server with stdio transport for Claude Code integration
|
|
55
|
+
- Six core tools: `memory_store`, `memory_search`, `memory_relate`, `memory_graph_query`, `memory_context`, `memory_forget`
|
|
56
|
+
- Triple storage backend: Qdrant (vectors), Neo4j (knowledge graph), SQLite (metadata)
|
|
57
|
+
- Local embedding pipeline using HuggingFace Transformers.js (`all-MiniLM-L6-v2`, 384 dimensions)
|
|
58
|
+
- Tiered memory scoping with automatic project inference and scope boosting
|
|
59
|
+
- Multi-source context retrieval combining semantic search, graph traversal, and recency
|
|
60
|
+
- Orchestration layer with merge, rank, and dedup logic
|
|
61
|
+
- Docker Compose setup for Qdrant and Neo4j
|
|
62
|
+
- Test suite covering all layers: embedding, storage, orchestration, and integration
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Arthur Lonfils / Londer
|
|
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,183 @@
|
|
|
1
|
+
# Cortex
|
|
2
|
+
|
|
3
|
+
A high-performance, locally-hosted AI memory system that stores, indexes, and retrieves contextual knowledge via MCP (Model Context Protocol). Designed for Claude Code, but works with any MCP client.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g @londer/cortex
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Or from source:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
git clone https://github.com/londer/cortex.git
|
|
15
|
+
cd cortex
|
|
16
|
+
npm install
|
|
17
|
+
npm run build
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Quick Start
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
# 1. Set up storage backends (Qdrant + Neo4j via Docker)
|
|
24
|
+
cortex setup
|
|
25
|
+
|
|
26
|
+
# 2. Start the MCP server
|
|
27
|
+
cortex serve
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Claude Code Integration
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
# Add Cortex to Claude Code
|
|
34
|
+
claude mcp add cortex -- cortex serve
|
|
35
|
+
|
|
36
|
+
# Generate Claude Code instructions for your project
|
|
37
|
+
cortex init
|
|
38
|
+
|
|
39
|
+
# Or set up global instructions (applies to all projects)
|
|
40
|
+
cortex init --global
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Or manually add to your MCP config:
|
|
44
|
+
|
|
45
|
+
```json
|
|
46
|
+
{
|
|
47
|
+
"servers": {
|
|
48
|
+
"cortex": {
|
|
49
|
+
"command": "cortex",
|
|
50
|
+
"args": ["serve"]
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## LLM Setup (Optional)
|
|
57
|
+
|
|
58
|
+
Cortex works fully without an API key. Adding one unlocks higher-quality extraction and smart consolidation.
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
# Via CLI
|
|
62
|
+
cortex config set anthropic_api_key sk-ant-your-key-here
|
|
63
|
+
|
|
64
|
+
# Or via environment variable
|
|
65
|
+
export ANTHROPIC_API_KEY=sk-ant-your-key-here
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Extraction Tiers
|
|
69
|
+
|
|
70
|
+
Cortex uses a tiered entity extraction system:
|
|
71
|
+
|
|
72
|
+
| Tier | Method | Quality | Latency | Cost | Requirements |
|
|
73
|
+
|------|--------|---------|---------|------|-------------|
|
|
74
|
+
| 1 | Regex + Heuristics | Basic | < 1ms | Free | Always available |
|
|
75
|
+
| 2 | NLP (compromise.js) | Good | < 50ms | Free | Always available |
|
|
76
|
+
| 3 | LLM (Claude API) | Best | 500ms-2s | ~$0.002/call | API key required |
|
|
77
|
+
|
|
78
|
+
The system automatically selects the best available tier and falls back gracefully.
|
|
79
|
+
|
|
80
|
+
## Capability Matrix
|
|
81
|
+
|
|
82
|
+
| Feature | No API Key | With API Key |
|
|
83
|
+
|---------|-----------|-------------|
|
|
84
|
+
| Entity extraction | Tier 1-2 (regex + NLP) | Tier 3 (LLM) |
|
|
85
|
+
| Relationship detection | Basic verb patterns | Full semantic understanding |
|
|
86
|
+
| Auto-extraction | Local heuristics | LLM-powered analysis |
|
|
87
|
+
| Consolidation: near-identical dedup | Yes (> 0.95 similarity) | Yes |
|
|
88
|
+
| Consolidation: smart merge | Flagged for review | Yes |
|
|
89
|
+
| Consolidation: contradiction resolution | No | Yes |
|
|
90
|
+
| memory_ingest | Tier 1-2 extraction | Tier 3 extraction |
|
|
91
|
+
| memory_config | Full access | Full access |
|
|
92
|
+
|
|
93
|
+
## Available Tools
|
|
94
|
+
|
|
95
|
+
| Tool | Description |
|
|
96
|
+
|------|-------------|
|
|
97
|
+
| `memory_store` | Store a memory. Auto-embeds content, stores metadata, links entities. |
|
|
98
|
+
| `memory_search` | Semantic search with scope boosting. |
|
|
99
|
+
| `memory_relate` | Create entity relationships in the knowledge graph. |
|
|
100
|
+
| `memory_graph_query` | Traverse the knowledge graph from an entity. |
|
|
101
|
+
| `memory_context` | Smart context retrieval combining semantic + graph + recency. |
|
|
102
|
+
| `memory_forget` | Delete a memory from all stores (requires confirmation). |
|
|
103
|
+
| `memory_ingest` | Ingest raw text and extract memories/entities/relationships. |
|
|
104
|
+
| `memory_consolidate` | Merge redundant memories. Supports dry_run preview. |
|
|
105
|
+
| `memory_config` | View/modify runtime configuration (including API key). |
|
|
106
|
+
|
|
107
|
+
## CLI Reference
|
|
108
|
+
|
|
109
|
+
```
|
|
110
|
+
cortex serve Start the MCP server (stdio transport)
|
|
111
|
+
cortex setup Pull Docker images, start Qdrant + Neo4j
|
|
112
|
+
cortex setup --stop Stop Docker containers
|
|
113
|
+
cortex init Generate Cortex instructions for project CLAUDE.md
|
|
114
|
+
cortex init --global Generate global instructions (~/.claude/CLAUDE.md)
|
|
115
|
+
cortex config get Show current configuration
|
|
116
|
+
cortex config set <key> <value> Set a runtime config value
|
|
117
|
+
cortex consolidate Run manual consolidation
|
|
118
|
+
cortex version Show version
|
|
119
|
+
cortex help Show help
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Configuration
|
|
123
|
+
|
|
124
|
+
Configuration is loaded from environment variables with sensible defaults. See `.env.example` for all options.
|
|
125
|
+
|
|
126
|
+
Key settings:
|
|
127
|
+
|
|
128
|
+
| Variable | Default | Description |
|
|
129
|
+
|----------|---------|-------------|
|
|
130
|
+
| `QDRANT_URL` | `http://localhost:16333` | Qdrant server URL |
|
|
131
|
+
| `NEO4J_URI` | `bolt://localhost:17687` | Neo4j bolt URI |
|
|
132
|
+
| `SQLITE_PATH` | `~/.cortex/cortex.db` | SQLite database path |
|
|
133
|
+
| `ANTHROPIC_API_KEY` | *(empty)* | Anthropic API key (optional) |
|
|
134
|
+
| `CORTEX_EXTRACTION_TIER` | `auto` | `auto`, `local-only`, or `llm-preferred` |
|
|
135
|
+
| `CORTEX_AUTO_EXTRACT` | `true` | Enable auto-extraction from conversations |
|
|
136
|
+
| `CORTEX_CONSOLIDATION_ENABLED` | `true` | Enable periodic memory consolidation |
|
|
137
|
+
|
|
138
|
+
Runtime overrides persist to `~/.cortex/runtime-config.json`.
|
|
139
|
+
|
|
140
|
+
## Development
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
# Run with hot reload
|
|
144
|
+
npm run dev
|
|
145
|
+
|
|
146
|
+
# Run tests (requires Docker backends running)
|
|
147
|
+
npm test
|
|
148
|
+
|
|
149
|
+
# Build
|
|
150
|
+
npm run build
|
|
151
|
+
|
|
152
|
+
# Release (bump version, update changelog, create tag)
|
|
153
|
+
npm run release
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Architecture
|
|
157
|
+
|
|
158
|
+
```
|
|
159
|
+
Claude Code
|
|
160
|
+
│ MCP (stdio)
|
|
161
|
+
▼
|
|
162
|
+
┌──────────────────────────────────────┐
|
|
163
|
+
│ Cortex MCP Server │
|
|
164
|
+
│ (TypeScript) │
|
|
165
|
+
├──────────────────────────────────────┤
|
|
166
|
+
│ Extraction │ Consolidation │
|
|
167
|
+
│ Tier 1-3 │ LLM / Local │
|
|
168
|
+
│ Auto-extract │ Cluster + Merge │
|
|
169
|
+
├──────────────────────────────────────┤
|
|
170
|
+
│ Orchestration Layer │
|
|
171
|
+
│ Scope inference, ranking, dedup │
|
|
172
|
+
├─────────┬──────────┬─────────────────┤
|
|
173
|
+
│ Qdrant │ Neo4j │ SQLite │
|
|
174
|
+
│ vectors │ graph │ metadata │
|
|
175
|
+
└─────────┴──────────┴─────────────────┘
|
|
176
|
+
▲ ▲
|
|
177
|
+
HuggingFace Anthropic API
|
|
178
|
+
Transformers.js (optional)
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## License
|
|
182
|
+
|
|
183
|
+
MIT - Arthur Lonfils / Londer
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { execSync } from 'node:child_process';
|
|
3
|
+
import { existsSync, mkdirSync, copyFileSync, readFileSync, writeFileSync } from 'node:fs';
|
|
4
|
+
import { join, dirname } from 'node:path';
|
|
5
|
+
import { homedir } from 'node:os';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
const CORTEX_DIR = join(homedir(), '.cortex');
|
|
8
|
+
const COMPOSE_DEST = join(CORTEX_DIR, 'docker-compose.yml');
|
|
9
|
+
function getVersion() {
|
|
10
|
+
try {
|
|
11
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
12
|
+
const pkgPaths = [
|
|
13
|
+
join(__dirname, '..', 'package.json'),
|
|
14
|
+
join(__dirname, '..', '..', 'package.json'),
|
|
15
|
+
];
|
|
16
|
+
for (const p of pkgPaths) {
|
|
17
|
+
if (existsSync(p)) {
|
|
18
|
+
const pkg = JSON.parse(readFileSync(p, 'utf-8'));
|
|
19
|
+
return pkg.version ?? 'unknown';
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
catch { /* fall through */ }
|
|
24
|
+
return 'unknown';
|
|
25
|
+
}
|
|
26
|
+
function printHelp() {
|
|
27
|
+
console.log(`
|
|
28
|
+
cortex — AI memory system with MCP integration
|
|
29
|
+
|
|
30
|
+
Usage:
|
|
31
|
+
cortex serve Start the MCP server (stdio transport)
|
|
32
|
+
cortex setup Pull Docker images and start Qdrant + Neo4j
|
|
33
|
+
cortex setup --stop Stop Docker containers
|
|
34
|
+
cortex init Generate Cortex instructions for project CLAUDE.md
|
|
35
|
+
cortex init --global Generate global Cortex instructions (~/.claude/CLAUDE.md)
|
|
36
|
+
cortex config get Show current configuration
|
|
37
|
+
cortex config set <key> <value> Set a runtime config value
|
|
38
|
+
cortex consolidate Run manual consolidation
|
|
39
|
+
cortex version Show version
|
|
40
|
+
cortex help Show this help message
|
|
41
|
+
|
|
42
|
+
Examples:
|
|
43
|
+
cortex setup Set up storage backends
|
|
44
|
+
cortex serve Start MCP server
|
|
45
|
+
cortex init Add Cortex instructions to current project
|
|
46
|
+
claude mcp add cortex -- cortex serve
|
|
47
|
+
`);
|
|
48
|
+
}
|
|
49
|
+
function checkDocker() {
|
|
50
|
+
try {
|
|
51
|
+
execSync('docker --version', { stdio: 'pipe' });
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function checkDockerCompose() {
|
|
59
|
+
try {
|
|
60
|
+
execSync('docker compose version', { stdio: 'pipe' });
|
|
61
|
+
return 'compose';
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
try {
|
|
65
|
+
execSync('docker-compose --version', { stdio: 'pipe' });
|
|
66
|
+
return 'docker-compose';
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
async function setup(stop) {
|
|
74
|
+
if (!checkDocker()) {
|
|
75
|
+
console.error('Error: Docker is not installed or not in PATH');
|
|
76
|
+
process.exit(1);
|
|
77
|
+
}
|
|
78
|
+
const composeCmd = checkDockerCompose();
|
|
79
|
+
if (!composeCmd) {
|
|
80
|
+
console.error('Error: Neither "docker compose" nor "docker-compose" is available');
|
|
81
|
+
process.exit(1);
|
|
82
|
+
}
|
|
83
|
+
mkdirSync(CORTEX_DIR, { recursive: true });
|
|
84
|
+
if (!existsSync(COMPOSE_DEST)) {
|
|
85
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
86
|
+
const sourcePaths = [
|
|
87
|
+
join(__dirname, '..', 'docker-compose.yml'),
|
|
88
|
+
join(__dirname, '..', '..', 'docker-compose.yml'),
|
|
89
|
+
];
|
|
90
|
+
let copied = false;
|
|
91
|
+
for (const src of sourcePaths) {
|
|
92
|
+
if (existsSync(src)) {
|
|
93
|
+
copyFileSync(src, COMPOSE_DEST);
|
|
94
|
+
console.log(`Copied docker-compose.yml to ${COMPOSE_DEST}`);
|
|
95
|
+
copied = true;
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (!copied) {
|
|
100
|
+
console.error('Warning: Could not find docker-compose.yml to copy');
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
const composeArgs = composeCmd === 'compose'
|
|
104
|
+
? ['docker', 'compose', '-f', COMPOSE_DEST]
|
|
105
|
+
: ['docker-compose', '-f', COMPOSE_DEST];
|
|
106
|
+
if (stop) {
|
|
107
|
+
console.log('Stopping Cortex containers...');
|
|
108
|
+
execSync([...composeArgs, 'down'].join(' '), { stdio: 'inherit' });
|
|
109
|
+
console.log('Containers stopped.');
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
console.log('Starting Cortex containers...');
|
|
113
|
+
execSync([...composeArgs, 'up', '-d'].join(' '), { stdio: 'inherit' });
|
|
114
|
+
console.log('Waiting for services to be ready...');
|
|
115
|
+
const qdrantUrl = process.env.QDRANT_URL ?? 'http://localhost:16333';
|
|
116
|
+
const neo4jUri = process.env.NEO4J_URI ?? 'bolt://localhost:17687';
|
|
117
|
+
let qdrantReady = false;
|
|
118
|
+
for (let i = 0; i < 30; i++) {
|
|
119
|
+
try {
|
|
120
|
+
const resp = await fetch(`${qdrantUrl}/collections`);
|
|
121
|
+
if (resp.ok) {
|
|
122
|
+
qdrantReady = true;
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
catch { /* not ready yet */ }
|
|
127
|
+
await new Promise(r => setTimeout(r, 1000));
|
|
128
|
+
}
|
|
129
|
+
console.log(`Qdrant: ${qdrantReady ? 'ready' : 'not responding (check manually)'}`);
|
|
130
|
+
let neo4jReady = false;
|
|
131
|
+
try {
|
|
132
|
+
const { default: neo4jDriver } = await import('neo4j-driver');
|
|
133
|
+
const driver = neo4jDriver.driver(neo4jUri, neo4jDriver.auth.basic(process.env.NEO4J_USER ?? 'neo4j', process.env.NEO4J_PASSWORD ?? 'cortex-dev'));
|
|
134
|
+
const session = driver.session();
|
|
135
|
+
await session.run('RETURN 1');
|
|
136
|
+
await session.close();
|
|
137
|
+
await driver.close();
|
|
138
|
+
neo4jReady = true;
|
|
139
|
+
}
|
|
140
|
+
catch { /* not ready */ }
|
|
141
|
+
console.log(`Neo4j: ${neo4jReady ? 'ready' : 'not responding (check manually)'}`);
|
|
142
|
+
console.log('\nSetup complete. Run "cortex serve" to start the MCP server.');
|
|
143
|
+
}
|
|
144
|
+
async function configAction(args) {
|
|
145
|
+
const subAction = args[0];
|
|
146
|
+
if (subAction === 'get') {
|
|
147
|
+
const { RuntimeConfigStore } = await import('./config-store.js');
|
|
148
|
+
const { loadConfig } = await import('./config.js');
|
|
149
|
+
const store = new RuntimeConfigStore();
|
|
150
|
+
const baseConfig = loadConfig();
|
|
151
|
+
const overrides = store.getAll();
|
|
152
|
+
console.log('Cortex Configuration:');
|
|
153
|
+
console.log('─'.repeat(40));
|
|
154
|
+
console.log(` Qdrant URL: ${baseConfig.qdrantUrl}`);
|
|
155
|
+
console.log(` Neo4j URI: ${baseConfig.neo4jUri}`);
|
|
156
|
+
console.log(` SQLite Path: ${baseConfig.sqlitePath}`);
|
|
157
|
+
console.log(` Embedding Model: ${baseConfig.embeddingModel}`);
|
|
158
|
+
console.log(` LLM Model: ${baseConfig.llmModel}`);
|
|
159
|
+
console.log(` API Key: ${baseConfig.anthropicApiKey ? 'set' : 'not set'}`);
|
|
160
|
+
console.log(` Extraction Tier: ${baseConfig.extractionTier}`);
|
|
161
|
+
console.log(` Auto-Extract: ${baseConfig.autoExtract}`);
|
|
162
|
+
console.log(` Consolidation: ${baseConfig.consolidationEnabled}`);
|
|
163
|
+
console.log(` Consolidation Int: ${baseConfig.consolidationIntervalMs}ms`);
|
|
164
|
+
if (Object.keys(overrides).length > 0) {
|
|
165
|
+
console.log('\nRuntime Overrides:');
|
|
166
|
+
for (const [key, value] of Object.entries(overrides)) {
|
|
167
|
+
console.log(` ${key}: ${value}`);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
if (subAction === 'set') {
|
|
173
|
+
const key = args[1];
|
|
174
|
+
const value = args[2];
|
|
175
|
+
if (!key || value === undefined) {
|
|
176
|
+
console.error('Usage: cortex config set <key> <value>');
|
|
177
|
+
process.exit(1);
|
|
178
|
+
}
|
|
179
|
+
const { RuntimeConfigStore } = await import('./config-store.js');
|
|
180
|
+
const store = new RuntimeConfigStore();
|
|
181
|
+
try {
|
|
182
|
+
const result = store.set(key, value);
|
|
183
|
+
console.log(`Set ${key}: ${result.previous ?? '(unset)'} → ${result.current}`);
|
|
184
|
+
}
|
|
185
|
+
catch (error) {
|
|
186
|
+
console.error(`Error: ${error instanceof Error ? error.message : error}`);
|
|
187
|
+
process.exit(1);
|
|
188
|
+
}
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
console.error('Usage: cortex config <get|set>');
|
|
192
|
+
process.exit(1);
|
|
193
|
+
}
|
|
194
|
+
async function initCommand(isGlobal) {
|
|
195
|
+
const { PROJECT_INSTRUCTIONS, GLOBAL_INSTRUCTIONS, START_MARKER, END_MARKER } = await import('./templates/claude-instructions.js');
|
|
196
|
+
if (isGlobal) {
|
|
197
|
+
const claudeDir = join(homedir(), '.claude');
|
|
198
|
+
const targetPath = join(claudeDir, 'CLAUDE.md');
|
|
199
|
+
mkdirSync(claudeDir, { recursive: true });
|
|
200
|
+
writeOrUpdateInstructions(targetPath, GLOBAL_INSTRUCTIONS, START_MARKER, END_MARKER);
|
|
201
|
+
console.log(`Global Cortex instructions written to ${targetPath}`);
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
const targetPath = join(process.cwd(), 'CLAUDE.md');
|
|
205
|
+
writeOrUpdateInstructions(targetPath, PROJECT_INSTRUCTIONS, START_MARKER, END_MARKER);
|
|
206
|
+
console.log(`Cortex instructions written to ${targetPath}`);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
function writeOrUpdateInstructions(filePath, instructions, startMarker, endMarker) {
|
|
210
|
+
if (!existsSync(filePath)) {
|
|
211
|
+
// File doesn't exist — create it with just the instructions
|
|
212
|
+
writeFileSync(filePath, instructions + '\n', 'utf-8');
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
const existing = readFileSync(filePath, 'utf-8');
|
|
216
|
+
const startIdx = existing.indexOf(startMarker);
|
|
217
|
+
const endIdx = existing.indexOf(endMarker);
|
|
218
|
+
if (startIdx !== -1 && endIdx !== -1) {
|
|
219
|
+
// Markers found — replace the section in-place
|
|
220
|
+
const before = existing.slice(0, startIdx);
|
|
221
|
+
const after = existing.slice(endIdx + endMarker.length);
|
|
222
|
+
writeFileSync(filePath, before + instructions + after, 'utf-8');
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
// No markers — append to the file
|
|
226
|
+
const separator = existing.endsWith('\n') ? '\n' : '\n\n';
|
|
227
|
+
writeFileSync(filePath, existing + separator + instructions + '\n', 'utf-8');
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
async function serve() {
|
|
231
|
+
await import('./index.js');
|
|
232
|
+
}
|
|
233
|
+
async function consolidate() {
|
|
234
|
+
console.log('Running manual consolidation...');
|
|
235
|
+
console.log('Use the memory_consolidate MCP tool for consolidation.');
|
|
236
|
+
console.log('Example: cortex serve, then call memory_consolidate through Claude Code.');
|
|
237
|
+
}
|
|
238
|
+
async function main() {
|
|
239
|
+
const args = process.argv.slice(2);
|
|
240
|
+
const command = args[0];
|
|
241
|
+
switch (command) {
|
|
242
|
+
case 'serve':
|
|
243
|
+
await serve();
|
|
244
|
+
break;
|
|
245
|
+
case 'setup':
|
|
246
|
+
await setup(args.includes('--stop'));
|
|
247
|
+
break;
|
|
248
|
+
case 'init':
|
|
249
|
+
await initCommand(args.includes('--global'));
|
|
250
|
+
break;
|
|
251
|
+
case 'config':
|
|
252
|
+
await configAction(args.slice(1));
|
|
253
|
+
break;
|
|
254
|
+
case 'consolidate':
|
|
255
|
+
await consolidate();
|
|
256
|
+
break;
|
|
257
|
+
case 'version':
|
|
258
|
+
case '--version':
|
|
259
|
+
case '-v':
|
|
260
|
+
console.log(`cortex v${getVersion()}`);
|
|
261
|
+
break;
|
|
262
|
+
case 'help':
|
|
263
|
+
case '--help':
|
|
264
|
+
case '-h':
|
|
265
|
+
case undefined:
|
|
266
|
+
printHelp();
|
|
267
|
+
break;
|
|
268
|
+
default:
|
|
269
|
+
console.error(`Unknown command: ${command}`);
|
|
270
|
+
printHelp();
|
|
271
|
+
process.exit(1);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
main().catch(error => {
|
|
275
|
+
console.error(`Error: ${error instanceof Error ? error.message : error}`);
|
|
276
|
+
process.exit(1);
|
|
277
|
+
});
|
|
278
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare class RuntimeConfigStore {
|
|
2
|
+
private overrides;
|
|
3
|
+
constructor();
|
|
4
|
+
get(key: string): string | null;
|
|
5
|
+
getAll(): Record<string, string>;
|
|
6
|
+
getRawApiKey(): string | null;
|
|
7
|
+
set(key: string, value: string): {
|
|
8
|
+
previous: string | null;
|
|
9
|
+
current: string;
|
|
10
|
+
};
|
|
11
|
+
isSettable(key: string): boolean;
|
|
12
|
+
private persist;
|
|
13
|
+
private loadPersisted;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=config-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-store.d.ts","sourceRoot":"","sources":["../src/config-store.ts"],"names":[],"mappings":"AAeA,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,SAAS,CAAkC;;IAMnD,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAI/B,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAYhC,YAAY,IAAI,MAAM,GAAG,IAAI;IAI7B,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG;QAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE;IAa7E,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAIhC,OAAO,CAAC,OAAO;IAaf,OAAO,CAAC,aAAa;CActB"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { homedir } from 'node:os';
|
|
4
|
+
import { dirname } from 'node:path';
|
|
5
|
+
const CONFIG_DIR = join(homedir(), '.cortex');
|
|
6
|
+
const CONFIG_FILE = join(CONFIG_DIR, 'runtime-config.json');
|
|
7
|
+
const SETTABLE_KEYS = new Set([
|
|
8
|
+
'anthropic_api_key',
|
|
9
|
+
'extraction_tier',
|
|
10
|
+
'auto_extract',
|
|
11
|
+
'consolidation_enabled',
|
|
12
|
+
]);
|
|
13
|
+
export class RuntimeConfigStore {
|
|
14
|
+
overrides = new Map();
|
|
15
|
+
constructor() {
|
|
16
|
+
this.loadPersisted();
|
|
17
|
+
}
|
|
18
|
+
get(key) {
|
|
19
|
+
return this.overrides.get(key) ?? null;
|
|
20
|
+
}
|
|
21
|
+
getAll() {
|
|
22
|
+
const result = {};
|
|
23
|
+
for (const [key, value] of this.overrides) {
|
|
24
|
+
if (key === 'anthropic_api_key') {
|
|
25
|
+
result[key] = maskApiKey(value);
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
result[key] = value;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return result;
|
|
32
|
+
}
|
|
33
|
+
getRawApiKey() {
|
|
34
|
+
return this.overrides.get('anthropic_api_key') ?? null;
|
|
35
|
+
}
|
|
36
|
+
set(key, value) {
|
|
37
|
+
if (!SETTABLE_KEYS.has(key)) {
|
|
38
|
+
throw new Error(`Key "${key}" is not settable at runtime. Settable keys: ${Array.from(SETTABLE_KEYS).join(', ')}`);
|
|
39
|
+
}
|
|
40
|
+
const previous = this.overrides.get(key) ?? null;
|
|
41
|
+
this.overrides.set(key, value);
|
|
42
|
+
this.persist();
|
|
43
|
+
return {
|
|
44
|
+
previous: key === 'anthropic_api_key' && previous ? maskApiKey(previous) : previous,
|
|
45
|
+
current: key === 'anthropic_api_key' ? maskApiKey(value) : value,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
isSettable(key) {
|
|
49
|
+
return SETTABLE_KEYS.has(key);
|
|
50
|
+
}
|
|
51
|
+
persist() {
|
|
52
|
+
try {
|
|
53
|
+
mkdirSync(dirname(CONFIG_FILE), { recursive: true });
|
|
54
|
+
const data = {};
|
|
55
|
+
for (const [key, value] of this.overrides) {
|
|
56
|
+
data[key] = value;
|
|
57
|
+
}
|
|
58
|
+
writeFileSync(CONFIG_FILE, JSON.stringify(data, null, 2), 'utf-8');
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
console.error(`[cortex] Failed to persist runtime config: ${error}`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
loadPersisted() {
|
|
65
|
+
try {
|
|
66
|
+
if (!existsSync(CONFIG_FILE))
|
|
67
|
+
return;
|
|
68
|
+
const raw = readFileSync(CONFIG_FILE, 'utf-8');
|
|
69
|
+
const data = JSON.parse(raw);
|
|
70
|
+
for (const [key, value] of Object.entries(data)) {
|
|
71
|
+
if (typeof value === 'string') {
|
|
72
|
+
this.overrides.set(key, value);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
// No persisted config or invalid file — start fresh
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
function maskApiKey(key) {
|
|
82
|
+
if (!key || key.length < 8)
|
|
83
|
+
return '***';
|
|
84
|
+
return key.slice(0, 7) + '...' + key.slice(-4);
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=config-store.js.map
|