codex-dev-mcp-suite 1.7.0 → 1.8.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 +23 -0
- package/docs/clients/antigravity.md +52 -0
- package/docs/clients/hermes.md +48 -0
- package/package.json +1 -1
- package/project-memory/embedding.js +23 -8
- package/project-memory/local-embed.js +92 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,26 @@
|
|
|
1
|
+
## 1.8.0 - 2026-07-22
|
|
2
|
+
|
|
3
|
+
### Added
|
|
4
|
+
- **Zero-Dependency Local Offline Vector Embedding Engine**:
|
|
5
|
+
- Pure JS 384-dimensional term-frequency hashing vector engine with sublinear $1 + \log(tf)$ scaling and L2 normalization (`project-memory/local-embed.js`).
|
|
6
|
+
- Activated via `MCP_LOCAL_EMBED=true` / `LOCAL_EMBED=true` env flag when no remote embedding API key is available.
|
|
7
|
+
- Sub-millisecond execution, zero network calls, zero external npm dependencies.
|
|
8
|
+
- Full compatibility with existing `cosine(a, b)` and graph ranking in `project-memory`.
|
|
9
|
+
- **Universal Multi-Client Guides**:
|
|
10
|
+
- Hermes Agent setup guide (`docs/clients/hermes.md`).
|
|
11
|
+
- Google Antigravity CLI (AGY CLI) setup guide (`docs/clients/antigravity.md`).
|
|
12
|
+
- Claude Code & Generic MCP setup guides (`docs/clients/claude-code.md`, `docs/clients/generic-mcp.md`).
|
|
13
|
+
- **Test Suite**: 100/100 unit tests passing (100% green across 8 test suites).
|
|
14
|
+
|
|
15
|
+
## 1.7.0 - 2026-07-22
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
- **Obsidian Vault Parity & MOC Tools**:
|
|
19
|
+
- `memory_moc` Map of Content generator & `.obsidian` vault structure integration.
|
|
20
|
+
- `memory_graph` knowledge graph visualization & backlinks.
|
|
21
|
+
- **Codebase Security Audit Tool (`pack_audit`)**:
|
|
22
|
+
- Detect missing `.gitignore`, exposed secrets/keys (`.env`, `.pem`, `id_rsa`), and overly large files.
|
|
23
|
+
|
|
1
24
|
## 1.5.0
|
|
2
25
|
|
|
3
26
|
- add `memory_link` with wiki-link resolution for `[[id]]`, `[[title]]`, `[[project:id]]`, and `[[project:title]]`, plus backlink inspection
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Google Antigravity CLI (AGY CLI) Setup
|
|
2
|
+
|
|
3
|
+
`codex-dev-mcp-suite` connects seamlessly to **Google Antigravity CLI (AGY CLI)** and the AGY SDK agent framework.
|
|
4
|
+
|
|
5
|
+
## Quick Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g codex-dev-mcp-suite
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## AGY Configuration (`mcp.json` / `settings.json`)
|
|
12
|
+
|
|
13
|
+
Add the suite to your AGY CLI settings or project `mcp.json`:
|
|
14
|
+
|
|
15
|
+
```json
|
|
16
|
+
{
|
|
17
|
+
"mcpServers": {
|
|
18
|
+
"project-memory": {
|
|
19
|
+
"command": "project-memory-mcp",
|
|
20
|
+
"args": [],
|
|
21
|
+
"env": {
|
|
22
|
+
"MEMORY_VAULT_DIR": "~/.local/share/dev-mcp-suite/memories/vault",
|
|
23
|
+
"MCP_LOCAL_EMBED": "true"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"devjournal": {
|
|
27
|
+
"command": "devjournal-mcp",
|
|
28
|
+
"args": [],
|
|
29
|
+
"env": {
|
|
30
|
+
"JOURNAL_DIR": "~/.local/share/dev-mcp-suite/memories/journal"
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"checkpoint": {
|
|
34
|
+
"command": "checkpoint-mcp",
|
|
35
|
+
"args": [],
|
|
36
|
+
"env": {
|
|
37
|
+
"CHECKPOINT_DIR": "~/.local/share/dev-mcp-suite/memories/checkpoints"
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"context-pack": {
|
|
41
|
+
"command": "context-pack-mcp",
|
|
42
|
+
"args": []
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Client Compatibility Highlights
|
|
49
|
+
|
|
50
|
+
- **Stdio Isolation**: Zero stdout noise — all logs and diagnostic messages are routed exclusively to `stderr` or MCP log frames.
|
|
51
|
+
- **Offline Vector Engine**: Automatically uses the built-in 384-d term-frequency hashing vector when no remote embedding API key is set (`MCP_LOCAL_EMBED=true`).
|
|
52
|
+
- **Obsidian Graph Compatibility**: Compatible with `.obsidian` vault structure and `[[WikiLinks]]`.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Hermes Agent Setup
|
|
2
|
+
|
|
3
|
+
`codex-dev-mcp-suite` is fully compatible with **Hermes Agent** via the standard Model Context Protocol (MCP) stdio interface.
|
|
4
|
+
|
|
5
|
+
## Quick Installation
|
|
6
|
+
|
|
7
|
+
Ensure the package is installed globally or accessible via `npx`:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install -g codex-dev-mcp-suite
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Hermes Configuration (`~/.hermes/config.yaml`)
|
|
14
|
+
|
|
15
|
+
Add the suite servers to your Hermes `mcp_servers` configuration block in `~/.hermes/config.yaml`:
|
|
16
|
+
|
|
17
|
+
```yaml
|
|
18
|
+
mcp_servers:
|
|
19
|
+
project-memory:
|
|
20
|
+
command: project-memory-mcp
|
|
21
|
+
args: []
|
|
22
|
+
env:
|
|
23
|
+
MEMORY_VAULT_DIR: "~/.local/share/dev-mcp-suite/memories/vault"
|
|
24
|
+
MCP_LOCAL_EMBED: "true" # Enables zero-dependency local offline vector search
|
|
25
|
+
|
|
26
|
+
devjournal:
|
|
27
|
+
command: devjournal-mcp
|
|
28
|
+
args: []
|
|
29
|
+
env:
|
|
30
|
+
JOURNAL_DIR: "~/.local/share/dev-mcp-suite/memories/journal"
|
|
31
|
+
|
|
32
|
+
checkpoint:
|
|
33
|
+
command: checkpoint-mcp
|
|
34
|
+
args: []
|
|
35
|
+
env:
|
|
36
|
+
CHECKPOINT_DIR: "~/.local/share/dev-mcp-suite/memories/checkpoints"
|
|
37
|
+
|
|
38
|
+
context-pack:
|
|
39
|
+
command: context-pack-mcp
|
|
40
|
+
args: []
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Features Available to Hermes
|
|
44
|
+
|
|
45
|
+
- **`memory_save` / `memory_recall`**: Persistent cross-session memory with optional local offline 384-d term-frequency hashing vector search (`MCP_LOCAL_EMBED=true`).
|
|
46
|
+
- **`journal_log` / `journal_resume` / `journal_handoff`**: Session log & handoff recovery.
|
|
47
|
+
- **`checkpoint_create` / `checkpoint_diff`**: File checkpoints independent of git.
|
|
48
|
+
- **`pack_overview` / `pack_tree` / `pack_audit`**: Codebase orientation & security risk auditing.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codex-dev-mcp-suite",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.0",
|
|
4
4
|
"description": "Four local, file-based MCP servers for solo devs/vibecoders: persistent project memory, session handoff/resume, git-independent file checkpoints, and token-efficient project briefings. Works with any MCP client.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -19,6 +19,7 @@ import http from "http";
|
|
|
19
19
|
import https from "https";
|
|
20
20
|
import { URL } from "url";
|
|
21
21
|
import { deterministicEnabled } from "./env.js";
|
|
22
|
+
import { generateLocalVectors } from "./local-embed.js";
|
|
22
23
|
|
|
23
24
|
/** Read env at runtime (not module-load time) so tests can override and config is dynamic). */
|
|
24
25
|
function readEnv() {
|
|
@@ -30,6 +31,10 @@ function readEnv() {
|
|
|
30
31
|
};
|
|
31
32
|
}
|
|
32
33
|
|
|
34
|
+
export function localEmbedEnabled() {
|
|
35
|
+
return process.env.MCP_LOCAL_EMBED === "true" || process.env.LOCAL_EMBED === "true";
|
|
36
|
+
}
|
|
37
|
+
|
|
33
38
|
/**
|
|
34
39
|
* Resolve what retrieval mode memory_recall will use, given current env.
|
|
35
40
|
* Returns one of: "deterministic" | "semantic" | "keyword".
|
|
@@ -38,17 +43,20 @@ function readEnv() {
|
|
|
38
43
|
export function recallMode() {
|
|
39
44
|
if (deterministicEnabled()) return "deterministic";
|
|
40
45
|
const { key } = readEnv();
|
|
41
|
-
|
|
46
|
+
if (key) return "semantic";
|
|
47
|
+
if (localEmbedEnabled()) return "semantic (local)";
|
|
48
|
+
return "keyword";
|
|
42
49
|
}
|
|
43
50
|
|
|
44
51
|
export function embeddingConfig() {
|
|
45
52
|
const { base, key, model } = readEnv();
|
|
53
|
+
const isLocal = !key && localEmbedEnabled();
|
|
46
54
|
return {
|
|
47
|
-
base,
|
|
48
|
-
model,
|
|
49
|
-
enabled: Boolean(key) && !deterministicEnabled(),
|
|
55
|
+
base: key ? base : (isLocal ? "local-offline" : base),
|
|
56
|
+
model: key ? model : (isLocal ? "local-384d-tf-ngram" : model),
|
|
57
|
+
enabled: Boolean(key || isLocal) && !deterministicEnabled(),
|
|
50
58
|
deterministic: deterministicEnabled(),
|
|
51
|
-
endpoint: isCloudflareURL(base) ? "cloudflare" : "openai-compatible",
|
|
59
|
+
endpoint: key ? (isCloudflareURL(base) ? "cloudflare" : "openai-compatible") : (isLocal ? "local-offline" : "none"),
|
|
52
60
|
mode: recallMode(),
|
|
53
61
|
};
|
|
54
62
|
}
|
|
@@ -136,10 +144,17 @@ async function embedCloudflare(inputs) {
|
|
|
136
144
|
export async function embed(inputs) {
|
|
137
145
|
if (deterministicEnabled()) return [];
|
|
138
146
|
const { base, key } = readEnv();
|
|
139
|
-
if (!key) return [];
|
|
140
147
|
const arr = Array.isArray(inputs) ? inputs : [inputs];
|
|
141
|
-
if (
|
|
142
|
-
|
|
148
|
+
if (!key) {
|
|
149
|
+
if (localEmbedEnabled()) return generateLocalVectors(arr);
|
|
150
|
+
return [];
|
|
151
|
+
}
|
|
152
|
+
try {
|
|
153
|
+
const res = isCloudflareURL(base) ? await embedCloudflare(arr) : await embedOpenAI(arr);
|
|
154
|
+
if (res && res.length) return res;
|
|
155
|
+
} catch { /* fallback to local if enabled */ }
|
|
156
|
+
if (localEmbedEnabled()) return generateLocalVectors(arr);
|
|
157
|
+
return [];
|
|
143
158
|
}
|
|
144
159
|
|
|
145
160
|
export async function embedOne(text) {
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local offline vector embedding engine (384-dimensional term-frequency hashing vector).
|
|
3
|
+
* Zero external dependencies, zero network calls, sub-millisecond execution.
|
|
4
|
+
*
|
|
5
|
+
* Provides a reliable fallback for semantic search when no remote API keys
|
|
6
|
+
* (OpenAI/Cloudflare/Gemini/Ollama) are available.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const VECTOR_DIM = 384;
|
|
10
|
+
|
|
11
|
+
/** Simple hash function for N-gram string to integer bucket [0, VECTOR_DIM-1] */
|
|
12
|
+
function hashNgram(ngram) {
|
|
13
|
+
let hash = 5381;
|
|
14
|
+
for (let i = 0; i < ngram.length; i++) {
|
|
15
|
+
hash = ((hash << 5) + hash) + ngram.charCodeAt(i);
|
|
16
|
+
hash = hash & hash; // Convert to 32bit integer
|
|
17
|
+
}
|
|
18
|
+
return Math.abs(hash) % VECTOR_DIM;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Generate a 384-dimensional L2-normalized vector for a text string.
|
|
23
|
+
* @param {string} text
|
|
24
|
+
* @returns {number[]} Array of 384 float numbers
|
|
25
|
+
*/
|
|
26
|
+
export function generateLocalVector(text) {
|
|
27
|
+
if (!text || typeof text !== "string") {
|
|
28
|
+
return new Array(VECTOR_DIM).fill(0);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const normalized = text.toLowerCase().trim();
|
|
32
|
+
if (!normalized) {
|
|
33
|
+
return new Array(VECTOR_DIM).fill(0);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const vec = new Array(VECTOR_DIM).fill(0);
|
|
37
|
+
|
|
38
|
+
// Extract word tokens and character 3-grams
|
|
39
|
+
const words = normalized.split(/\s+/).filter(Boolean);
|
|
40
|
+
|
|
41
|
+
// 1. Process words (higher weight)
|
|
42
|
+
for (const word of words) {
|
|
43
|
+
const cleanWord = word.replace(/[^a-z0-9]/g, "");
|
|
44
|
+
if (!cleanWord) continue;
|
|
45
|
+
|
|
46
|
+
const idx = hashNgram(cleanWord);
|
|
47
|
+
vec[idx] += 2.0;
|
|
48
|
+
|
|
49
|
+
// 2. Process character 3-grams for fuzzy matching
|
|
50
|
+
if (cleanWord.length >= 3) {
|
|
51
|
+
for (let i = 0; i <= cleanWord.length - 3; i++) {
|
|
52
|
+
const sub = cleanWord.substring(i, i + 3);
|
|
53
|
+
const subIdx = hashNgram(sub);
|
|
54
|
+
vec[subIdx] += 1.0;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// 3. Sublinear term-frequency scaling (1 + log(tf))
|
|
60
|
+
for (let i = 0; i < VECTOR_DIM; i++) {
|
|
61
|
+
if (vec[i] > 0) {
|
|
62
|
+
vec[i] = 1 + Math.log(vec[i]);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// 4. L2 Normalization (unit length vector)
|
|
67
|
+
let normSq = 0;
|
|
68
|
+
for (let i = 0; i < VECTOR_DIM; i++) {
|
|
69
|
+
normSq += vec[i] * vec[i];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (normSq === 0) {
|
|
73
|
+
return vec;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const norm = Math.sqrt(normSq);
|
|
77
|
+
for (let i = 0; i < VECTOR_DIM; i++) {
|
|
78
|
+
vec[i] = vec[i] / norm;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return vec;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Generate vectors for an array of strings.
|
|
86
|
+
* @param {string[]} inputs
|
|
87
|
+
* @returns {number[][]}
|
|
88
|
+
*/
|
|
89
|
+
export function generateLocalVectors(inputs) {
|
|
90
|
+
const arr = Array.isArray(inputs) ? inputs : [inputs];
|
|
91
|
+
return arr.map((t) => generateLocalVector(t));
|
|
92
|
+
}
|