@abarcenas/ai-workflow-template 1.25.0 β 1.26.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/.agents/instructions/agent-skill.instructions.md +18 -20
- package/.agents/instructions/agent.instructions.md +111 -570
- package/.agents/instructions/ai-prompt-engineering-safety.instructions.md +3 -3
- package/.agents/instructions/instructions.instructions.md +6 -7
- package/.agents/instructions/memory-bank.instructions.md +72 -18
- package/.agents/instructions/memory-schema.instructions.md +75 -0
- package/.agents/instructions/prompt.instructions.md +25 -30
- package/.agents/skills/conventional-commit/SKILL.md +2 -2
- package/.agents/skills/github-issues/SKILL.md +2 -2
- package/.agents/skills/memory-search/SKILL.md +69 -0
- package/.agents/skills/microsoft-docs/SKILL.md +1 -1
- package/.agents/skills/polygot-test-agent/SKILL.md +0 -1
- package/.agents/skills/prompt-builder/SKILL.md +15 -14
- package/.husky/post-merge +10 -0
- package/.husky/pre-commit +2 -0
- package/README.md +75 -4
- package/memory-bank/.vocabulary.json +52 -0
- package/opencode.mcp.example.json +7 -1
- package/package.json +19 -4
- package/scripts/mcp-memory-server.js +243 -0
- package/scripts/memory-cli.js +110 -0
- package/scripts/memory-index.js +512 -0
- package/scripts/normalize-memory.js +349 -0
- package/scripts/validate-memory-schema.js +190 -0
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# π€ AI Workflow Template
|
|
2
2
|
|
|
3
|
-
**Publishable AI workflow starter pack for
|
|
3
|
+
**Publishable AI workflow starter pack for OpenCode** β Auto-syncing, version-managed, npm-distributed agent configuration suite with vector search memory.
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -16,7 +16,8 @@ This isn't a one-off template to cloneβit's a **live npm package** that distri
|
|
|
16
16
|
- π§ͺ **TDD Orchestrator** β Strict REDβGREENβREFACTOR/VERIFY test-driven pipeline (90% coverage gate)
|
|
17
17
|
- π **Framework Instructions** - Technology-specific guidance (`.agents/instructions/`)
|
|
18
18
|
- π¬ **Prompt Templates** - Ready-to-use prompt blueprints (`.agents/prompts/`)
|
|
19
|
-
- π§ **Memory Bank** β Persistent project context across AI sessions
|
|
19
|
+
- π§ **Memory Bank** β Persistent project context across AI sessions with semantic search
|
|
20
|
+
- π **Vector Memory Search** β sqlite-vec powered semantic search (token-efficient, zero deps)
|
|
20
21
|
- πββοΈ **Caveman Mode** - Ultra-compressed communication for token efficiency
|
|
21
22
|
- π **Playwright Testing** - Automated E2E testing with MCP integration
|
|
22
23
|
- β‘ **Vitest Unit Testing** β Fast unit tests with v8 coverage (β₯90% threshold)
|
|
@@ -241,9 +242,38 @@ implementer (PLAN) β unit-testerβ₯ (RED) β coderβ₯ (GREEN) β unit-tester
|
|
|
241
242
|
|
|
242
243
|
The TDD orchestrator uses `subagent_type "tdd-orchestrator"` and auto-selects the strict TDD pipeline when testable code changes are requested.
|
|
243
244
|
|
|
244
|
-
### π§ Memory Bank β Persistent Project Context
|
|
245
|
+
### π§ Memory Bank β Persistent Project Context with Vector Search
|
|
245
246
|
|
|
246
|
-
The memory bank preserves project knowledge across AI sessions, preventing context loss after resets:
|
|
247
|
+
The memory bank preserves project knowledge across AI sessions, preventing context loss after resets. **New: semantic vector search** lets agents query project memory without loading all files into context β saving thousands of tokens per session.
|
|
248
|
+
|
|
249
|
+
#### Architecture
|
|
250
|
+
|
|
251
|
+
```
|
|
252
|
+
Markdown files (git-committed) Vector Index (.gitignore'd)
|
|
253
|
+
ββββββββββββββββββββββββββββββ ββββββββββββββββββββββββββββ
|
|
254
|
+
memory-bank/ memory-bank/.index/
|
|
255
|
+
βββ activeContext.md βββ memory.db β sqlite-vec + better-sqlite3
|
|
256
|
+
βββ progress.md β
|
|
257
|
+
βββ systemPatterns.md β rebuilt from .md files
|
|
258
|
+
βββ ... βΌ on demand
|
|
259
|
+
memory_search("tdd orchestrator")
|
|
260
|
+
β top 5 relevant chunks (~500 tokens)
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
**Source of truth:** Markdown files (git-versioned, human-readable).
|
|
264
|
+
**Search index:** `sqlite-vec` vector database (disposable, rebuildable, never committed).
|
|
265
|
+
|
|
266
|
+
#### MCP Tools (OpenCode)
|
|
267
|
+
|
|
268
|
+
| Tool | Purpose |
|
|
269
|
+
|---|---|
|
|
270
|
+
| `memory_search` | Semantic search across memory-bank + docs (query + topK) |
|
|
271
|
+
| `memory_update` | Incremental sync β only changed files (~2 seconds) |
|
|
272
|
+
| `memory_rebuild` | Full rebuild from markdown files (rare β clone/corruption) |
|
|
273
|
+
| `memory_get` | Read a specific memory file by name |
|
|
274
|
+
| `memory_stats` | Index statistics (vector count, DB size) |
|
|
275
|
+
|
|
276
|
+
#### File Structure
|
|
247
277
|
|
|
248
278
|
```
|
|
249
279
|
projectbrief.md β productContext.md / systemPatterns.md / techContext.md β activeContext.md β progress.md / tasks/
|
|
@@ -259,8 +289,35 @@ projectbrief.md β productContext.md / systemPatterns.md / techContext.md β a
|
|
|
259
289
|
| `memory-bank/progress.md` | What works, what's left, known issues |
|
|
260
290
|
| `memory-bank/tasks/` | Per-task tracking with `_index.md` |
|
|
261
291
|
|
|
292
|
+
#### Document Schema
|
|
293
|
+
|
|
294
|
+
All memory-bank files use YAML frontmatter for search indexing:
|
|
295
|
+
|
|
296
|
+
```yaml
|
|
297
|
+
---
|
|
298
|
+
id: activeContext
|
|
299
|
+
title: "Active Context"
|
|
300
|
+
updated: 2026-07-23
|
|
301
|
+
tags: [orchestrator, bootstrap, tdd]
|
|
302
|
+
entities: [vitest, graphify, memory-bank]
|
|
303
|
+
category: context
|
|
304
|
+
---
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
See `memory-bank/.vocabulary.json` for the controlled vocabulary (user-extensible).
|
|
308
|
+
|
|
309
|
+
**Auto-normalization:** `npm install` runs `normalize-memory.js` to add frontmatter to existing files.
|
|
310
|
+
**Pre-commit validation:** Husky hook rejects commits with invalid frontmatter.
|
|
311
|
+
|
|
262
312
|
**Task commands:** `add task`, `update task [ID]`, `show tasks [filter]`
|
|
263
313
|
|
|
314
|
+
#### Token Efficiency
|
|
315
|
+
|
|
316
|
+
| Approach | Tokens per session |
|
|
317
|
+
|---|---|
|
|
318
|
+
| Read all memory files | ~5,000β15,000+ |
|
|
319
|
+
| Semantic search | ~500β2,000 (top 3β5 chunks) |
|
|
320
|
+
|
|
264
321
|
---
|
|
265
322
|
|
|
266
323
|
## π¦ Versioning
|
|
@@ -314,6 +371,20 @@ npm run test:unit:coverage
|
|
|
314
371
|
|
|
315
372
|
# Watch mode for unit tests
|
|
316
373
|
npm run test:unit:watch
|
|
374
|
+
|
|
375
|
+
# βββ Memory Bank (Vector Search) βββ
|
|
376
|
+
|
|
377
|
+
# Build the vector search index (one-time, ~8 min for 5K files)
|
|
378
|
+
npm run memory:rebuild
|
|
379
|
+
|
|
380
|
+
# Incremental update (seconds β only changed files)
|
|
381
|
+
npm run memory:update
|
|
382
|
+
|
|
383
|
+
# Search project memory
|
|
384
|
+
npm run memory:search "tdd orchestrator status"
|
|
385
|
+
|
|
386
|
+
# Normalize document frontmatter (runs automatically on install)
|
|
387
|
+
npm run memory:normalize
|
|
317
388
|
```
|
|
318
389
|
|
|
319
390
|
### Testing
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"categories": {
|
|
3
|
+
"brief": "Project scope, goals (projectbrief.md)",
|
|
4
|
+
"product": "Product context, UX goals (productContext.md)",
|
|
5
|
+
"architecture": "System patterns, design decisions, component relationships",
|
|
6
|
+
"tech": "Technology stack, dev setup, constraints",
|
|
7
|
+
"context": "Current focus, recent changes, next steps (activeContext.md)",
|
|
8
|
+
"progress": "What works, what's left, known issues (progress.md)",
|
|
9
|
+
"task": "Individual task tracking (tasks/TASK*.md)",
|
|
10
|
+
"decision": "ADR-style architecture/technical decisions"
|
|
11
|
+
},
|
|
12
|
+
|
|
13
|
+
"tags": {
|
|
14
|
+
"agent_roles": [
|
|
15
|
+
"designer", "architect", "researcher", "coder", "implementer",
|
|
16
|
+
"tester", "reviewer", "tracker", "deployer", "orchestrator"
|
|
17
|
+
],
|
|
18
|
+
"workflow": [
|
|
19
|
+
"bootstrap", "setup", "configuration", "migration", "refactor",
|
|
20
|
+
"tdd", "feature-pipeline", "onboarding", "normalization",
|
|
21
|
+
"research", "spike", "implementation"
|
|
22
|
+
],
|
|
23
|
+
"memory_ops": [
|
|
24
|
+
"decision", "discovery", "status-update", "task-plan", "retrospective"
|
|
25
|
+
]
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
"entity_patterns": {
|
|
29
|
+
"vitest": ["vitest", "vitest\\.config", "@vitest\\/coverage"],
|
|
30
|
+
"playwright": ["playwright", "@playwright", "browser.*test"],
|
|
31
|
+
"graphify": ["graphify", "knowledge graph", "graph\\.json"],
|
|
32
|
+
"memory-bank": ["memory-bank", "memory bank", "activeContext", "systemPatterns"],
|
|
33
|
+
"husky": ["husky", "pre-commit", "git hook"],
|
|
34
|
+
"tdd-orchestrator": ["tdd orchestrator", "RED.*GREEN.*REFACTOR"],
|
|
35
|
+
"mcp-server": ["mcp", "modelcontextprotocol", "stdio", "mcp server"],
|
|
36
|
+
"sqlite-vec": ["sqlite-vec", "sqlite.vec", "better-sqlite3"],
|
|
37
|
+
"transformers.js": ["@xenova\\/transformers", "transformers\\.js", "all-MiniLM"],
|
|
38
|
+
"opencode": ["opencode", "OpenCode", "open code"],
|
|
39
|
+
"npm": ["npm", "npm package", "npm install"]
|
|
40
|
+
},
|
|
41
|
+
|
|
42
|
+
"file_category_map": {
|
|
43
|
+
"projectbrief": "brief",
|
|
44
|
+
"productContext": "product",
|
|
45
|
+
"systemPatterns": "architecture",
|
|
46
|
+
"techContext": "tech",
|
|
47
|
+
"activeContext": "context",
|
|
48
|
+
"progress": "progress"
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
"doc_types": ["spike", "architecture", "configuration", "orchestrator-log", "tracker-log", "decision"]
|
|
52
|
+
}
|
|
@@ -53,6 +53,11 @@
|
|
|
53
53
|
"type": "remote",
|
|
54
54
|
"url": "https://your-mcp-server.com/mcp",
|
|
55
55
|
"enabled": false
|
|
56
|
+
},
|
|
57
|
+
"memory-bank": {
|
|
58
|
+
"type": "local",
|
|
59
|
+
"command": ["node", "scripts/mcp-memory-server.js"],
|
|
60
|
+
"enabled": true
|
|
56
61
|
}
|
|
57
62
|
},
|
|
58
63
|
"permission": {
|
|
@@ -60,6 +65,7 @@
|
|
|
60
65
|
"github_*": "allow",
|
|
61
66
|
"mcp-everything_*": "allow",
|
|
62
67
|
"angular-cli_*": "allow",
|
|
63
|
-
"playwright_*": "allow"
|
|
68
|
+
"playwright_*": "allow",
|
|
69
|
+
"memory-bank_*": "allow"
|
|
64
70
|
}
|
|
65
71
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abarcenas/ai-workflow-template",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "A comprehensive template repository for AI-assisted development workflows using
|
|
3
|
+
"version": "1.26.0",
|
|
4
|
+
"description": "A comprehensive template repository for AI-assisted development workflows using OpenCode. Provides structured agent pipelines, TDD orchestrator, memory bank with vector search, skills, prompts, and coding standards distributed as an npm package.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"test": "playwright test",
|
|
@@ -14,7 +14,11 @@
|
|
|
14
14
|
"test:unit:watch": "vitest",
|
|
15
15
|
"prepare": "husky",
|
|
16
16
|
"sync": "node ./scripts/sync.js",
|
|
17
|
-
"postinstall": "node ./scripts/sync.js"
|
|
17
|
+
"postinstall": "node ./scripts/sync.js && node ./scripts/normalize-memory.js",
|
|
18
|
+
"memory:search": "node ./scripts/memory-cli.js search",
|
|
19
|
+
"memory:rebuild": "node ./scripts/memory-cli.js rebuild",
|
|
20
|
+
"memory:update": "node ./scripts/memory-cli.js update",
|
|
21
|
+
"memory:normalize": "node ./scripts/normalize-memory.js"
|
|
18
22
|
},
|
|
19
23
|
"repository": {
|
|
20
24
|
"type": "git",
|
|
@@ -34,9 +38,12 @@
|
|
|
34
38
|
"scripts/",
|
|
35
39
|
".opencode/agents/",
|
|
36
40
|
".opencode/commands/",
|
|
41
|
+
".husky/",
|
|
42
|
+
"memory-bank/.vocabulary.json",
|
|
37
43
|
"AGENTS.md",
|
|
38
44
|
"opencode.mcp.example.json",
|
|
39
|
-
"skills-lock.json"
|
|
45
|
+
"skills-lock.json",
|
|
46
|
+
".husky/post-merge"
|
|
40
47
|
],
|
|
41
48
|
"devDependencies": {
|
|
42
49
|
"@playwright/test": "^1.59.1",
|
|
@@ -44,5 +51,13 @@
|
|
|
44
51
|
"dotenv": "^17.4.2",
|
|
45
52
|
"husky": "^9.0.0",
|
|
46
53
|
"vitest": "^4.1.8"
|
|
54
|
+
},
|
|
55
|
+
"dependencies": {
|
|
56
|
+
"better-sqlite3": "^12.11.0",
|
|
57
|
+
"sqlite-vec": "^0.1.9",
|
|
58
|
+
"@modelcontextprotocol/sdk": "^1.0.0"
|
|
59
|
+
},
|
|
60
|
+
"optionalDependencies": {
|
|
61
|
+
"@xenova/transformers": "^2.17.0"
|
|
47
62
|
}
|
|
48
63
|
}
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* mcp-memory-server.js β MCP server exposing memory-bank tools to OpenCode.
|
|
5
|
+
*
|
|
6
|
+
* Provides: memory_search, memory_rebuild, memory_get
|
|
7
|
+
* Uses stdio transport β OpenCode spawns this as a child process.
|
|
8
|
+
*
|
|
9
|
+
* Configuration (opencode.json):
|
|
10
|
+
* "memory-bank": {
|
|
11
|
+
* "type": "local",
|
|
12
|
+
* "command": ["node", "scripts/mcp-memory-server.js"],
|
|
13
|
+
* "enabled": true
|
|
14
|
+
* }
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
18
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
19
|
+
import {
|
|
20
|
+
CallToolRequestSchema,
|
|
21
|
+
ListToolsRequestSchema,
|
|
22
|
+
} from '@modelcontextprotocol/sdk/types.js';
|
|
23
|
+
import { search, rebuildIndex, incrementalUpdate, getFile, getStats } from './memory-index.js';
|
|
24
|
+
|
|
25
|
+
const VALID_FILES = [
|
|
26
|
+
'activeContext', 'systemPatterns', 'techContext',
|
|
27
|
+
'productContext', 'progress', 'projectbrief',
|
|
28
|
+
'tracker-log', 'architecture-context', 'orchestrator-log',
|
|
29
|
+
'spike-vector-db-memory', 'playwright-mcp-configuration',
|
|
30
|
+
];
|
|
31
|
+
|
|
32
|
+
const server = new Server(
|
|
33
|
+
{
|
|
34
|
+
name: 'memory-bank',
|
|
35
|
+
version: '1.0.0',
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
capabilities: {
|
|
39
|
+
tools: {},
|
|
40
|
+
},
|
|
41
|
+
}
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
// ββ List tools βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
45
|
+
|
|
46
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
47
|
+
tools: [
|
|
48
|
+
{
|
|
49
|
+
name: 'memory_search',
|
|
50
|
+
description:
|
|
51
|
+
'Semantic search across the project memory bank (activeContext, systemPatterns, progress, decisions, tasks). ' +
|
|
52
|
+
'Returns ranked chunks with source file and similarity score. ' +
|
|
53
|
+
'Use this instead of reading all memory files to save tokens.',
|
|
54
|
+
inputSchema: {
|
|
55
|
+
type: 'object',
|
|
56
|
+
properties: {
|
|
57
|
+
query: {
|
|
58
|
+
type: 'string',
|
|
59
|
+
description: 'Natural language query about project context, decisions, or status',
|
|
60
|
+
},
|
|
61
|
+
topK: {
|
|
62
|
+
type: 'number',
|
|
63
|
+
default: 5,
|
|
64
|
+
description: 'Number of results to return (1-20)',
|
|
65
|
+
},
|
|
66
|
+
sourceFile: {
|
|
67
|
+
type: 'string',
|
|
68
|
+
description: 'Optional: filter to a specific memory file (e.g., "activeContext", "systemPatterns")',
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
required: ['query'],
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
name: 'memory_rebuild',
|
|
76
|
+
description:
|
|
77
|
+
'Full rebuild of the memory vector index from memory-bank/*.md and docs/*.md files. ' +
|
|
78
|
+
'Re-indexes every file regardless of change. ' +
|
|
79
|
+
'Use memory_update instead for faster incremental sync (only changed files). ' +
|
|
80
|
+
'The index is disposable β rebuilding is safe.',
|
|
81
|
+
inputSchema: {
|
|
82
|
+
type: 'object',
|
|
83
|
+
properties: {},
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
name: 'memory_update',
|
|
88
|
+
description:
|
|
89
|
+
'Incremental update β only re-indexes files whose content changed (SHA-256 content hash). ' +
|
|
90
|
+
'Much faster than memory_rebuild for daily use (~2 seconds vs minutes). ' +
|
|
91
|
+
'Run this after completing tasks, writing to memory-bank, or after git pull.',
|
|
92
|
+
inputSchema: {
|
|
93
|
+
type: 'object',
|
|
94
|
+
properties: {},
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
name: 'memory_get',
|
|
99
|
+
description:
|
|
100
|
+
'Read the full content of a specific memory file by name. ' +
|
|
101
|
+
'Use when you need the complete file, not just search snippets.',
|
|
102
|
+
inputSchema: {
|
|
103
|
+
type: 'object',
|
|
104
|
+
properties: {
|
|
105
|
+
file: {
|
|
106
|
+
type: 'string',
|
|
107
|
+
description: 'File ID without extension. One of: ' + VALID_FILES.join(', '),
|
|
108
|
+
enum: VALID_FILES,
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
required: ['file'],
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
name: 'memory_stats',
|
|
116
|
+
description: 'Get statistics about the memory index (vector count, file count, database size).',
|
|
117
|
+
inputSchema: {
|
|
118
|
+
type: 'object',
|
|
119
|
+
properties: {},
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
],
|
|
123
|
+
}));
|
|
124
|
+
|
|
125
|
+
// ββ Handle tool calls ββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
126
|
+
|
|
127
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
128
|
+
const { name, arguments: args } = request.params;
|
|
129
|
+
|
|
130
|
+
try {
|
|
131
|
+
switch (name) {
|
|
132
|
+
case 'memory_search': {
|
|
133
|
+
const results = await search(args.query, {
|
|
134
|
+
topK: args.topK || 5,
|
|
135
|
+
sourceFile: args.sourceFile || undefined,
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
if (results.length === 0) {
|
|
139
|
+
return {
|
|
140
|
+
content: [{
|
|
141
|
+
type: 'text',
|
|
142
|
+
text: 'No results found. The index may be empty. Try running memory_rebuild first.',
|
|
143
|
+
}],
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const formatted = results
|
|
148
|
+
.map((r, i) =>
|
|
149
|
+
`### Result ${i + 1} (score: ${r.score})\n` +
|
|
150
|
+
`**File:** \`${r.source_file}\`\n\n${r.content}`
|
|
151
|
+
)
|
|
152
|
+
.join('\n\n---\n\n');
|
|
153
|
+
|
|
154
|
+
return {
|
|
155
|
+
content: [{ type: 'text', text: formatted }],
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
case 'memory_rebuild': {
|
|
160
|
+
const result = await rebuildIndex();
|
|
161
|
+
return {
|
|
162
|
+
content: [{
|
|
163
|
+
type: 'text',
|
|
164
|
+
text: `Index rebuilt successfully.\n` +
|
|
165
|
+
`- Chunks indexed: ${result.indexed}\n` +
|
|
166
|
+
`- Chunks skipped (unchanged): ${result.skipped}\n` +
|
|
167
|
+
`- Total vectors: ${result.stats.totalVectors}\n` +
|
|
168
|
+
`- Total files: ${result.stats.totalFiles}\n` +
|
|
169
|
+
`- DB size: ${result.stats.dbSize}`,
|
|
170
|
+
}],
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
case 'memory_update': {
|
|
175
|
+
const result = await incrementalUpdate();
|
|
176
|
+
return {
|
|
177
|
+
content: [{
|
|
178
|
+
type: 'text',
|
|
179
|
+
text: `Index updated incrementally.\n` +
|
|
180
|
+
`- Chunks re-indexed: ${result.indexed}\n` +
|
|
181
|
+
`- Chunks cached (unchanged): ${result.skipped}\n` +
|
|
182
|
+
(result.changed.length > 0
|
|
183
|
+
? `- Changed files: ${result.changed.join(', ')}\n`
|
|
184
|
+
: '- No files changed.\n') +
|
|
185
|
+
`- Total vectors: ${(await getStats()).totalVectors}`,
|
|
186
|
+
}],
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
case 'memory_get': {
|
|
191
|
+
const content = getFile(args.file);
|
|
192
|
+
if (!content) {
|
|
193
|
+
return {
|
|
194
|
+
content: [{
|
|
195
|
+
type: 'text',
|
|
196
|
+
text: `File not found: ${args.file}.md. Available files: ${VALID_FILES.join(', ')}`,
|
|
197
|
+
}],
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
return {
|
|
201
|
+
content: [{ type: 'text', text: content }],
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
case 'memory_stats': {
|
|
206
|
+
const stats = getStats();
|
|
207
|
+
return {
|
|
208
|
+
content: [{
|
|
209
|
+
type: 'text',
|
|
210
|
+
text: `**Memory Index Stats**\n` +
|
|
211
|
+
`- Total vectors: ${stats.totalVectors}\n` +
|
|
212
|
+
`- Total files indexed: ${stats.totalFiles}\n` +
|
|
213
|
+
`- Database size: ${stats.dbSize}`,
|
|
214
|
+
}],
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
default:
|
|
219
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
220
|
+
}
|
|
221
|
+
} catch (err) {
|
|
222
|
+
return {
|
|
223
|
+
content: [{
|
|
224
|
+
type: 'text',
|
|
225
|
+
text: `Error: ${err.message}`,
|
|
226
|
+
}],
|
|
227
|
+
isError: true,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
// ββ Start server βββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
233
|
+
|
|
234
|
+
async function main() {
|
|
235
|
+
const transport = new StdioServerTransport();
|
|
236
|
+
await server.connect(transport);
|
|
237
|
+
console.error('[memory-bank-mcp] Server started via stdio transport');
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
main().catch((err) => {
|
|
241
|
+
console.error('[memory-bank-mcp] Fatal error:', err);
|
|
242
|
+
process.exit(1);
|
|
243
|
+
});
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* memory-cli.js β CLI for manual memory index operations.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* node scripts/memory-cli.js search "<query>" [--topK 5] [--file activeContext]
|
|
8
|
+
* node scripts/memory-cli.js rebuild
|
|
9
|
+
* node scripts/memory-cli.js update (incremental)
|
|
10
|
+
* node scripts/memory-cli.js get <fileId>
|
|
11
|
+
* node scripts/memory-cli.js stats
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { search, rebuildIndex, incrementalUpdate, getFile, getStats, closeDB } from './memory-index.js';
|
|
15
|
+
|
|
16
|
+
const args = process.argv.slice(2);
|
|
17
|
+
const command = args[0];
|
|
18
|
+
|
|
19
|
+
function parseFlags(argv) {
|
|
20
|
+
const flags = {};
|
|
21
|
+
const positional = [];
|
|
22
|
+
for (let i = 0; i < argv.length; i++) {
|
|
23
|
+
if (argv[i] === '--topK' && i + 1 < argv.length) {
|
|
24
|
+
flags.topK = parseInt(argv[++i], 10);
|
|
25
|
+
} else if (argv[i] === '--file' && i + 1 < argv.length) {
|
|
26
|
+
flags.sourceFile = argv[++i];
|
|
27
|
+
} else {
|
|
28
|
+
positional.push(argv[i]);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return { flags, positional };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function main() {
|
|
35
|
+
try {
|
|
36
|
+
switch (command) {
|
|
37
|
+
case 'search': {
|
|
38
|
+
const { flags, positional } = parseFlags(args.slice(1));
|
|
39
|
+
const query = positional.join(' ');
|
|
40
|
+
if (!query) {
|
|
41
|
+
console.error('Usage: node scripts/memory-cli.js search "<query>" [--topK 5] [--file name]');
|
|
42
|
+
process.exit(1);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const results = await search(query, {
|
|
46
|
+
topK: flags.topK || 5,
|
|
47
|
+
sourceFile: flags.sourceFile,
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
if (results.length === 0) {
|
|
51
|
+
console.log(JSON.stringify({ results: [], hint: 'No results. Try running "rebuild" first.' }));
|
|
52
|
+
} else {
|
|
53
|
+
console.log(JSON.stringify({ results }, null, 2));
|
|
54
|
+
}
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
case 'rebuild': {
|
|
59
|
+
const result = await rebuildIndex();
|
|
60
|
+
console.log(JSON.stringify({ status: 'ok', ...result }, null, 2));
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
case 'update': {
|
|
65
|
+
const result = await incrementalUpdate();
|
|
66
|
+
console.log(JSON.stringify({ status: 'ok', ...result }, null, 2));
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
case 'get': {
|
|
71
|
+
const fileId = args[1];
|
|
72
|
+
if (!fileId) {
|
|
73
|
+
console.error('Usage: node scripts/memory-cli.js get <fileId>');
|
|
74
|
+
process.exit(1);
|
|
75
|
+
}
|
|
76
|
+
const content = getFile(fileId);
|
|
77
|
+
if (content) {
|
|
78
|
+
console.log(content);
|
|
79
|
+
} else {
|
|
80
|
+
console.error(`File not found: ${fileId}`);
|
|
81
|
+
process.exit(1);
|
|
82
|
+
}
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
case 'stats': {
|
|
87
|
+
console.log(JSON.stringify(getStats(), null, 2));
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
default:
|
|
92
|
+
console.error(`Usage: node scripts/memory-cli.js <search|rebuild|update|get|stats> [args...]`);
|
|
93
|
+
console.error('');
|
|
94
|
+
console.error('Commands:');
|
|
95
|
+
console.error(' search "<query>" [--topK N] [--file name] Semantic search');
|
|
96
|
+
console.error(' rebuild Full index rebuild');
|
|
97
|
+
console.error(' update Incremental update');
|
|
98
|
+
console.error(' get <fileId> Read a memory file');
|
|
99
|
+
console.error(' stats Index statistics');
|
|
100
|
+
process.exit(1);
|
|
101
|
+
}
|
|
102
|
+
} catch (err) {
|
|
103
|
+
console.error(`Error: ${err.message}`);
|
|
104
|
+
process.exit(1);
|
|
105
|
+
} finally {
|
|
106
|
+
closeDB();
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
main();
|