codex-dev-mcp-suite 3.1.1 → 3.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.
package/CHANGELOG.md CHANGED
@@ -1,37 +1,13 @@
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).
1
+ # Changelog
14
2
 
15
- ## 1.7.0 - 2026-07-22
3
+ ## 3.2.0 - 2026-07-27 — Session Conversation Watchdog & Transcript Digesting 🧠
16
4
 
17
5
  ### 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
-
24
- ## 1.5.0
25
-
26
- - add `memory_link` with wiki-link resolution for `[[id]]`, `[[title]]`, `[[project:id]]`, and `[[project:title]]`, plus backlink inspection
27
- - add `memory_global_recall` with same-project bias and graceful keyword/semantic fallback across project vaults
28
- - add `memory_dedup` with non-destructive duplicate suggestions for project or global scope
29
- - add hybrid lazy graph backfill so link metadata is derived on first graph-aware use and remains rebuildable from canonical notes
30
- - add graph-aware soft boost in recall paths without making embeddings mandatory
31
- - 36 project-memory tests pass after graph/global/dedup coverage expansion
32
-
33
- # Changelog
34
-
6
+ - **Session Conversation Watchdog & Transcript Digesting (`project-memory`)**:
7
+ - Added `scanSessionLogs()` helper in `auto-indexer.js` to autonomously scan recent `.jsonl`, `.json`, or `.log` session transcript files across `.codex/`, `.gemini/`, `.agents/logs/`, and custom session directories.
8
+ - Heuristic keyword analysis automatically detects architectural decisions, migration plans, and strategy discussions (e.g., V1 vs V2 trading bots).
9
+ - Upgraded `memory_auto_index` tool schema (`server.js`) with `scanSessions` and `sessionDir` parameters.
10
+ - Auto-derived decisions are now persisted directly into the Obsidian knowledge vault as individual notes (`notesCreated`), ensuring key chat discussions are permanently indexed and searchable via `memory_recall`.
35
11
  ## 3.1.1 - 2026-07-22 — CI/CD Hardening & Complete Wizard Tracking 🛡️
36
12
 
37
13
  ### Fixed
@@ -80,6 +56,39 @@
80
56
  - Notifies users via `stderr` when a new version of `codex-dev-mcp-suite` is published to upstream npm.
81
57
  - Safe for stdio MCP JSON-RPC protocol transport; sub-millisecond execution, zero startup latency.
82
58
 
59
+ ## 1.8.0 - 2026-07-22
60
+
61
+ ### Added
62
+ - **Zero-Dependency Local Offline Vector Embedding Engine**:
63
+ - Pure JS 384-dimensional term-frequency hashing vector engine with sublinear $1 + \log(tf)$ scaling and L2 normalization (`project-memory/local-embed.js`).
64
+ - Activated via `MCP_LOCAL_EMBED=true` / `LOCAL_EMBED=true` env flag when no remote embedding API key is available.
65
+ - Sub-millisecond execution, zero network calls, zero external npm dependencies.
66
+ - Full compatibility with existing `cosine(a, b)` and graph ranking in `project-memory`.
67
+ - **Universal Multi-Client Guides**:
68
+ - Hermes Agent setup guide (`docs/clients/hermes.md`).
69
+ - Google Antigravity CLI (AGY CLI) setup guide (`docs/clients/antigravity.md`).
70
+ - Claude Code & Generic MCP setup guides (`docs/clients/claude-code.md`, `docs/clients/generic-mcp.md`).
71
+ - **Test Suite**: 100/100 unit tests passing (100% green across 8 test suites).
72
+
73
+ ## 1.7.0 - 2026-07-22
74
+
75
+ ### Added
76
+ - **Obsidian Vault Parity & MOC Tools**:
77
+ - `memory_moc` Map of Content generator & `.obsidian` vault structure integration.
78
+ - `memory_graph` knowledge graph visualization & backlinks.
79
+ - **Codebase Security Audit Tool (`pack_audit`)**:
80
+ - Detect missing `.gitignore`, exposed secrets/keys (`.env`, `.pem`, `id_rsa`), and overly large files.
81
+
82
+ ## 1.5.0
83
+
84
+ - add `memory_link` with wiki-link resolution for `[[id]]`, `[[title]]`, `[[project:id]]`, and `[[project:title]]`, plus backlink inspection
85
+ - add `memory_global_recall` with same-project bias and graceful keyword/semantic fallback across project vaults
86
+ - add `memory_dedup` with non-destructive duplicate suggestions for project or global scope
87
+ - add hybrid lazy graph backfill so link metadata is derived on first graph-aware use and remains rebuildable from canonical notes
88
+ - add graph-aware soft boost in recall paths without making embeddings mandatory
89
+ - 36 project-memory tests pass after graph/global/dedup coverage expansion
90
+
91
+
83
92
  ## 1.4.0 - 2026-06-17
84
93
 
85
94
  ### Added
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codex-dev-mcp-suite",
3
- "version": "3.1.1",
3
+ "version": "3.2.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",
@@ -1,14 +1,97 @@
1
1
  /**
2
- * Autonomous Background Git & Mtime Observer for project-memory.
3
- * Inspects recent git commits and modified file mtimes to auto-derive
4
- * project notes and update the Obsidian knowledge vault without manual prompts.
2
+ * Autonomous Background Git, Mtime & Session Watchdog Observer for project-memory.
3
+ * Inspects recent git commits, modified file mtimes, and chat session transcripts
4
+ * to auto-derive project notes, extract architectural decisions, and update the
5
+ * Obsidian knowledge vault without manual prompts.
5
6
  */
6
7
 
7
8
  import fs from "fs/promises";
8
9
  import path from "path";
9
10
  import { execSync } from "child_process";
10
11
 
11
- export async function runAutoIndexer(projectDir, { dryRun = false } = {}) {
12
+ async function scanSessionLogs(root, customSessionDir) {
13
+ const decisions = [];
14
+ const candidateDirs = customSessionDir
15
+ ? [path.resolve(root, customSessionDir)]
16
+ : [
17
+ path.join(root, ".codex", "sessions"),
18
+ path.join(root, ".codex"),
19
+ path.join(root, ".gemini", "logs"),
20
+ path.join(root, ".gemini"),
21
+ path.join(root, ".agents", "logs"),
22
+ path.join(root, "logs"),
23
+ ];
24
+
25
+ const filesToScan = [];
26
+ for (const d of candidateDirs) {
27
+ try {
28
+ const stat = await fs.stat(d);
29
+ if (stat.isFile() && (d.endsWith(".jsonl") || d.endsWith(".log") || d.endsWith(".json"))) {
30
+ filesToScan.push(d);
31
+ continue;
32
+ }
33
+ if (stat.isDirectory()) {
34
+ const entries = await fs.readdir(d, { withFileTypes: true });
35
+ for (const e of entries) {
36
+ if (e.isFile() && (e.name.endsWith(".jsonl") || e.name.endsWith(".log") || e.name.endsWith(".json") || e.name.includes("history"))) {
37
+ filesToScan.push(path.join(d, e.name));
38
+ }
39
+ }
40
+ }
41
+ } catch {}
42
+ }
43
+
44
+ const fileStats = [];
45
+ for (const f of filesToScan) {
46
+ try {
47
+ const s = await fs.stat(f);
48
+ fileStats.push({ file: f, mtime: s.mtimeMs });
49
+ } catch {}
50
+ }
51
+ fileStats.sort((a, b) => b.mtime - a.mtime);
52
+ const topFiles = fileStats.slice(0, 5).map((x) => x.file);
53
+
54
+ const keywordRegex = /\b(v1|v2|v3|vs|versus|architecture|arsitektur|migration|migrasi|decision|keputusan|strategy|strategi|refactor|database|schema|tradeoff|perbedaan|kesimpulan|monolith|microservice)\b/i;
55
+
56
+ for (const file of topFiles) {
57
+ try {
58
+ const raw = await fs.readFile(file, "utf8");
59
+ const lines = raw.split("\n").filter((l) => l.trim());
60
+ for (const line of lines) {
61
+ let text = "";
62
+ let role = "unknown";
63
+ try {
64
+ const parsed = JSON.parse(line);
65
+ text = typeof parsed === "string" ? parsed : parsed.content || parsed.text || parsed.message || JSON.stringify(parsed);
66
+ role = parsed.type || parsed.role || parsed.source || "log";
67
+ } catch {
68
+ text = line;
69
+ }
70
+
71
+ if (typeof text !== "string" || text.length < 20) continue;
72
+
73
+ const match = text.match(keywordRegex);
74
+ if (match) {
75
+ const keyword = match[0].toLowerCase();
76
+ const cleanText = text.replace(/\s+/g, " ").trim();
77
+ const snippet = cleanText.length > 300 ? cleanText.substring(0, 300) + "..." : cleanText;
78
+ decisions.push({
79
+ keyword,
80
+ role: String(role),
81
+ snippet,
82
+ file: path.relative(root, file) || path.basename(file),
83
+ });
84
+ if (decisions.length >= 10) break;
85
+ }
86
+ }
87
+ } catch {}
88
+ if (decisions.length >= 10) break;
89
+ }
90
+
91
+ return decisions;
92
+ }
93
+
94
+ export async function runAutoIndexer(projectDir, { dryRun = false, scanSessions = true, sessionDir = null } = {}) {
12
95
  const root = path.resolve(projectDir || process.cwd());
13
96
  const notesCreated = [];
14
97
 
@@ -25,19 +108,44 @@ export async function runAutoIndexer(projectDir, { dryRun = false } = {}) {
25
108
  branch = execSync("git branch --show-current", { cwd: root, encoding: "utf8" }).trim();
26
109
  } catch {}
27
110
 
28
- const summary = [
111
+ // 3. Inspect recent session transcripts / chat logs if enabled
112
+ let sessionDecisions = [];
113
+ if (scanSessions) {
114
+ sessionDecisions = await scanSessionLogs(root, sessionDir);
115
+ }
116
+
117
+ const summaryLines = [
29
118
  `# Auto-Derived Knowledge Snapshot: ${path.basename(root)}`,
30
119
  `Active Branch: \`${branch}\``,
31
120
  `Inspected At: ${new Date().toISOString()}`,
32
121
  ``,
33
122
  `## 📜 Recent Git Activity`,
34
123
  ...(gitLogs.length ? gitLogs.map((l) => `- \`${l}\``) : ["- No git history found"]),
35
- ].join("\n");
124
+ ];
125
+
126
+ if (sessionDecisions.length > 0) {
127
+ summaryLines.push(``, `## 💬 Session Conversation Digest (Watchdog)`);
128
+ const seenKeywords = new Set();
129
+ for (const d of sessionDecisions) {
130
+ summaryLines.push(`- **[${d.keyword.toUpperCase()}]** (${d.file}): ${d.snippet}`);
131
+ if (!seenKeywords.has(d.keyword)) {
132
+ seenKeywords.add(d.keyword);
133
+ notesCreated.push({
134
+ title: `Session Digest: ${d.keyword.toUpperCase()} Discussion (${new Date().toISOString().substring(0, 10)})`,
135
+ content: `# Session Digest: ${d.keyword.toUpperCase()} Discussion\n\nExtracted from conversation watchdog on branch \`${branch}\` (Source: \`${d.file}\`).\n\n## Discussion Context\n\n- **Role (${d.role})**: ${d.snippet}\n`,
136
+ tags: ["session-digest", "watchdog", d.keyword.toLowerCase()],
137
+ });
138
+ }
139
+ }
140
+ }
141
+
142
+ const summary = summaryLines.join("\n");
36
143
 
37
144
  return {
38
145
  projectDir: root,
39
146
  branch,
40
147
  recentCommits: gitLogs,
148
+ sessionDecisions,
41
149
  summaryText: summary,
42
150
  notesCreated,
43
151
  };
@@ -437,12 +437,14 @@ class ProjectMemoryServer {
437
437
  },
438
438
  {
439
439
  name: "memory_auto_index",
440
- description: "Run autonomous background observer to inspect git commits, branch switches, and file modifications to auto-derive project notes.",
440
+ description: "Run autonomous background observer to inspect git commits, branch switches, file modifications, and chat session transcripts to auto-derive project notes and architectural decisions.",
441
441
  inputSchema: {
442
442
  type: "object",
443
443
  properties: {
444
444
  dir: { type: "string", description: "Project directory (defaults to CWD)" },
445
445
  dryRun: { type: "boolean", description: "Preview derived knowledge without saving", default: false },
446
+ scanSessions: { type: "boolean", description: "Scan recent chat session logs/transcripts to auto-extract architectural decisions and key discussions", default: true },
447
+ sessionDir: { type: "string", description: "Optional custom directory containing session JSONL logs" },
446
448
  },
447
449
  },
448
450
  },
@@ -876,17 +878,26 @@ class ProjectMemoryServer {
876
878
  return { content: [{ type: "text", text: lines.join("\n") }] };
877
879
  }
878
880
 
879
- async autoIndex({ dir, dryRun = false } = {}) {
881
+ async autoIndex({ dir, dryRun = false, scanSessions = true, sessionDir = null } = {}) {
880
882
  const p = this.paths(dir);
881
- const res = await runAutoIndexer(dir, { dryRun });
883
+ const res = await runAutoIndexer(dir, { dryRun, scanSessions, sessionDir });
882
884
  if (!dryRun && res.summaryText) {
883
885
  await this.save({
884
886
  title: `Auto-Index ${new Date().toISOString().substring(0, 10)} (${res.branch})`,
885
887
  content: res.summaryText,
886
888
  dir,
887
- tags: ["auto-index", "git"],
889
+ tags: ["auto-index", "git", "session-digest"],
888
890
  kind: "auto-derived"
889
891
  });
892
+ for (const note of (res.notesCreated || [])) {
893
+ await this.save({
894
+ title: note.title,
895
+ content: note.content,
896
+ dir,
897
+ tags: note.tags || ["session-digest", "auto-derived"],
898
+ kind: "session-digest"
899
+ });
900
+ }
890
901
  }
891
902
  return { content: [{ type: "text", text: res.summaryText + (dryRun ? "\n\n(Dry Run — note not saved)" : "\n\n(Saved to project memory vault)") }] };
892
903
  }