oh-memos-mcp 2.0.0 → 2.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.
Files changed (88) hide show
  1. package/.env.example +44 -27
  2. package/CHANGELOG.md +145 -0
  3. package/README.md +260 -226
  4. package/dist/api-client.d.ts +0 -0
  5. package/dist/api-client.js +0 -0
  6. package/dist/canvas-format.d.ts +101 -0
  7. package/dist/canvas-format.js +259 -0
  8. package/dist/canvas-store.d.ts +62 -0
  9. package/dist/canvas-store.js +187 -0
  10. package/dist/config.d.ts +3 -0
  11. package/dist/config.js +44 -9
  12. package/dist/cube-manager.d.ts +0 -0
  13. package/dist/cube-manager.js +11 -0
  14. package/dist/formatters.d.ts +0 -0
  15. package/dist/formatters.js +0 -0
  16. package/dist/graph-provenance.d.ts +34 -0
  17. package/dist/graph-provenance.js +175 -0
  18. package/dist/graphify-import.d.ts +72 -0
  19. package/dist/graphify-import.js +194 -0
  20. package/dist/handlers/admin.d.ts +1 -0
  21. package/dist/handlers/admin.js +18 -0
  22. package/dist/handlers/arg-contract.d.ts +0 -0
  23. package/dist/handlers/arg-contract.js +0 -0
  24. package/dist/handlers/calendar.d.ts +0 -0
  25. package/dist/handlers/calendar.js +0 -0
  26. package/dist/handlers/canvas.d.ts +40 -0
  27. package/dist/handlers/canvas.js +334 -0
  28. package/dist/handlers/graph.d.ts +8 -0
  29. package/dist/handlers/graph.js +66 -14
  30. package/dist/handlers/index.d.ts +0 -0
  31. package/dist/handlers/index.js +28 -5
  32. package/dist/handlers/memory.d.ts +0 -0
  33. package/dist/handlers/memory.js +33 -2
  34. package/dist/handlers/search.d.ts +0 -0
  35. package/dist/handlers/search.js +56 -15
  36. package/dist/handlers/skill.d.ts +6 -0
  37. package/dist/handlers/skill.js +123 -0
  38. package/dist/handlers/think.d.ts +0 -0
  39. package/dist/handlers/think.js +0 -0
  40. package/dist/handlers/utils.d.ts +0 -0
  41. package/dist/handlers/utils.js +0 -0
  42. package/dist/handlers/wiki-export.d.ts +0 -0
  43. package/dist/handlers/wiki-export.js +7 -9
  44. package/dist/handlers/wiki-import-relations.d.ts +11 -0
  45. package/dist/handlers/wiki-import-relations.js +32 -0
  46. package/dist/handlers/wiki-import.d.ts +19 -0
  47. package/dist/handlers/wiki-import.js +382 -0
  48. package/dist/index.d.ts +0 -0
  49. package/dist/index.js +0 -0
  50. package/dist/keyword-enhancer.d.ts +0 -0
  51. package/dist/keyword-enhancer.js +0 -0
  52. package/dist/memory-analysis.d.ts +0 -0
  53. package/dist/memory-analysis.js +0 -0
  54. package/dist/memory-quality.d.ts +10 -0
  55. package/dist/memory-quality.js +57 -0
  56. package/dist/memory-write-response.d.ts +8 -0
  57. package/dist/memory-write-response.js +15 -0
  58. package/dist/models.d.ts +0 -0
  59. package/dist/models.js +0 -0
  60. package/dist/policy.d.ts +8 -0
  61. package/dist/policy.js +9 -0
  62. package/dist/providers/lite-embedding.d.ts +31 -0
  63. package/dist/providers/lite-embedding.js +60 -0
  64. package/dist/providers/local-jsonl-provider.d.ts +28 -0
  65. package/dist/providers/local-jsonl-provider.js +225 -0
  66. package/dist/providers/memory-provider.d.ts +21 -0
  67. package/dist/providers/memory-provider.js +2 -0
  68. package/dist/providers/provider-factory.d.ts +11 -0
  69. package/dist/providers/provider-factory.js +27 -0
  70. package/dist/query-processing.d.ts +0 -0
  71. package/dist/query-processing.js +0 -0
  72. package/dist/server.d.ts +0 -0
  73. package/dist/server.js +13 -3
  74. package/dist/skill-candidate.d.ts +11 -0
  75. package/dist/skill-candidate.js +56 -0
  76. package/dist/skill-lifecycle.d.ts +15 -0
  77. package/dist/skill-lifecycle.js +51 -0
  78. package/dist/tools-registry.d.ts +130 -7
  79. package/dist/tools-registry.js +93 -31
  80. package/dist/types.d.ts +0 -0
  81. package/dist/types.js +0 -0
  82. package/dist/wiki-import-format.d.ts +47 -0
  83. package/dist/wiki-import-format.js +113 -0
  84. package/dist/wiki-import-safety.d.ts +25 -0
  85. package/dist/wiki-import-safety.js +31 -0
  86. package/dist/wiki-relations.d.ts +44 -0
  87. package/dist/wiki-relations.js +88 -0
  88. package/package.json +5 -2
package/README.md CHANGED
@@ -1,226 +1,260 @@
1
- # oh-memos-mcp
2
-
3
- [![npm version](https://img.shields.io/npm/v/oh-memos-mcp.svg)](https://www.npmjs.com/package/oh-memos-mcp)
4
- [![Node.js >= 18](https://img.shields.io/badge/node-%3E%3D18-brightgreen)](https://nodejs.org)
5
- [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
6
-
7
- MCP Server for **oh-memos** — Intelligent Persistent Memory for AI Assistants.
8
-
9
- Pure Node.js. No Python required. Works with `npx` out of the box.
10
-
11
- ---
12
-
13
- ## Prerequisites
14
-
15
- oh-memos backend API must be running before connecting this MCP server:
16
-
17
- - **oh-memos API** on `http://localhost:18000`
18
- - **Neo4j** on `localhost:7687` (Knowledge Graph)
19
- - **Qdrant** on `localhost:6333` (Vector Search)
20
-
21
- > Start all services: run `scripts\local\start.bat` from the [oh-memos repo](https://github.com/xigou/oh-memos).
22
-
23
- ---
24
-
25
- ## Quick Start
26
-
27
- Add to your Claude Code `~/.claude/settings.json`:
28
-
29
- ```json
30
- {
31
- "mcpServers": {
32
- "oh-memos": {
33
- "command": "npx",
34
- "args": ["-y", "oh-memos-mcp"],
35
- "env": {
36
- "MEMOS_URL": "http://localhost:18000",
37
- "MEMOS_USER": "dev_user",
38
- "MEMOS_DEFAULT_CUBE": "dev_cube",
39
- "MEMOS_CUBES_DIR": "G:/test/oh-memos/data/oh-memos_cubes"
40
- }
41
- }
42
- }
43
- }
44
- ```
45
-
46
- Or use a `.env` file in your working directory (the server auto-discovers it):
47
-
48
- ```bash
49
- cp node_modules/oh-memos-mcp/.env.example .env
50
- # Edit .env with your paths
51
- npx oh-memos-mcp
52
- ```
53
-
54
- ---
55
-
56
- ## Configuration Examples
57
-
58
- ### Linux / macOS
59
-
60
- ```json
61
- {
62
- "mcpServers": {
63
- "oh-memos": {
64
- "command": "npx",
65
- "args": ["-y", "oh-memos-mcp"],
66
- "env": {
67
- "MEMOS_URL": "http://localhost:18000",
68
- "MEMOS_USER": "dev_user",
69
- "MEMOS_DEFAULT_CUBE": "dev_cube",
70
- "MEMOS_CUBES_DIR": "/home/user/oh-memos/data/oh-memos_cubes"
71
- }
72
- }
73
- }
74
- }
75
- ```
76
-
77
- ### Windows
78
-
79
- ```json
80
- {
81
- "mcpServers": {
82
- "oh-memos": {
83
- "command": "npx",
84
- "args": ["-y", "oh-memos-mcp"],
85
- "env": {
86
- "MEMOS_URL": "http://localhost:18000",
87
- "MEMOS_USER": "dev_user",
88
- "MEMOS_DEFAULT_CUBE": "dev_cube",
89
- "MEMOS_CUBES_DIR": "G:/test/oh-memos/data/oh-memos_cubes"
90
- }
91
- }
92
- }
93
- }
94
- ```
95
-
96
- ### WSL2
97
-
98
- ```json
99
- {
100
- "mcpServers": {
101
- "oh-memos": {
102
- "command": "npx",
103
- "args": ["-y", "oh-memos-mcp"],
104
- "env": {
105
- "MEMOS_URL": "http://localhost:18000",
106
- "MEMOS_USER": "dev_user",
107
- "MEMOS_DEFAULT_CUBE": "dev_cube",
108
- "MEMOS_CUBES_DIR": "/mnt/g/test/oh-memos/data/oh-memos_cubes"
109
- }
110
- }
111
- }
112
- }
113
- ```
114
-
115
- ### With `alwaysAllow` (skip per-tool confirmation)
116
-
117
- ```json
118
- {
119
- "mcpServers": {
120
- "oh-memos": {
121
- "type": "stdio",
122
- "command": "npx",
123
- "args": ["-y", "oh-memos-mcp"],
124
- "env": {
125
- "MEMOS_URL": "http://localhost:18000",
126
- "MEMOS_USER": "dev_user",
127
- "MEMOS_DEFAULT_CUBE": "dev_cube",
128
- "MEMOS_CUBES_DIR": "/path/to/oh-memos/data/oh-memos_cubes",
129
- "MEMOS_ENABLE_DELETE": "true"
130
- },
131
- "alwaysAllow": [
132
- "memos_context_resume",
133
- "memos_search",
134
- "memos_search",
135
- "memos_save",
136
- "memos_list_v2",
137
- "memos_get",
138
- "memos_suggest",
139
- "memos_admin(action=list_cubes)",
140
- "memos_admin(action=stats)",
141
- "memos_graph(mode=related)",
142
- "memos_graph(mode=path)",
143
- "memos_graph(mode=schema)",
144
- "memos_admin(action=register_cube)",
145
- "memos_admin(action=create_user)",
146
- "memos_admin(action=validate_cubes)",
147
- "memos_graph(mode=impact)",
148
- "memos_admin(action=calendar)",
149
- "memos_delete"
150
- ]
151
- }
152
- }
153
- }
154
- ```
155
-
156
- ---
157
-
158
- ## Environment Variables
159
-
160
- | Variable | Required | Default | Description |
161
- |----------|----------|---------|-------------|
162
- | `MEMOS_URL` | Yes | — | oh-memos API base URL |
163
- | `MEMOS_USER` | Yes | — | Default user ID |
164
- | `MEMOS_DEFAULT_CUBE` | Yes | — | Default memory cube ID |
165
- | `MEMOS_CUBES_DIR` | Yes | — | Absolute path to cubes storage directory |
166
- | `MEMOS_TIMEOUT_TOOL` | No | `300` | Tool call timeout (seconds) |
167
- | `MEMOS_TIMEOUT_STARTUP` | No | `30` | API startup wait timeout (seconds) |
168
- | `MEMOS_TIMEOUT_HEALTH` | No | `5` | Health check timeout (seconds) |
169
- | `MEMOS_API_WAIT_MAX` | No | `60` | Max time to wait for API on startup (seconds) |
170
- | `MEMOS_ENABLE_DELETE` | No | `false` | Enable `memos_delete` tool |
171
- | `NEO4J_HTTP_URL` | No | — | Neo4j HTTP endpoint (for direct graph queries) |
172
- | `NEO4J_USER` | No | — | Neo4j username |
173
- | `NEO4J_PASSWORD` | No | — | Neo4j password |
174
-
175
- > **Tip**: `.env` file in your working directory is loaded automatically with highest priority.
176
- > Copy `.env.example` to get started.
177
-
178
- ---
179
-
180
- ## Tools (10)
181
-
182
- | Tool | Description |
183
- |------|-------------|
184
- | `memos_context_resume` | Recover project context after compaction (recent 24h + project state) |
185
- | `memos_search` | Semantic search with keyword reranking. Pass `context` (recent turns) to enable LLM intent analysis and query expansion |
186
- | `memos_save` | Save memories with explicit type (BUGFIX, DECISION, MILESTONE, SYNTHESIS…) |
187
- | `memos_list_v2` | List memories with auto-compaction |
188
- | `memos_get` | Get full memory details by ID |
189
- | `memos_suggest` | Smart search query suggestions + `memory_type` decision tree |
190
- | `memos_think` | Evidence pack for a question: retrieval + contradiction/staleness flags + gap analysis. The caller synthesizes the answer and may persist it as `SYNTHESIS` |
191
- | `memos_graph` | Knowledge graph queries — `mode`: `related` / `path` / `impact` / `schema` |
192
- | `memos_admin` | Maintenance — `action`: `list_cubes` / `register_cube` / `create_user` / `validate_cubes` / `stats` / `calendar` |
193
- | `memos_export_wiki` | Export a cube as an interlinked markdown wiki (page per memory + index + mermaid graph) |
194
-
195
- Plus `memos_delete`, hidden from `tools/list` unless `MEMOS_ENABLE_DELETE=true`.
196
-
197
- ---
198
-
199
- ## How .env Loading Works
200
-
201
- Priority order (highest first):
202
-
203
- 1. **`process.cwd()/.env`** — your project working directory
204
- 2. **Package root `.env`** — where oh-memos-mcp is installed
205
- 3. **dotenv default search** — walks up from cwd
206
-
207
- This means you can place a `.env` in your project root and `npx oh-memos-mcp` will pick it up automatically — no need to repeat env vars in every MCP config.
208
-
209
- ---
210
-
211
- ## Development
212
-
213
- ```bash
214
- git clone https://github.com/xigou/oh-memos.git
215
- cd oh-memos/mcp-server-node
216
- npm install
217
- npm run dev # Run with tsx (no build needed)
218
- npm run build # Compile to dist/
219
- ```
220
-
221
- ---
222
-
223
- ## Requirements
224
-
225
- - Node.js >= 18.0.0
226
- - oh-memos backend API running (`scripts\local\start.bat`)
1
+ # oh-memos-mcp
2
+
3
+ [![npm version](https://img.shields.io/npm/v/oh-memos-mcp.svg)](https://www.npmjs.com/package/oh-memos-mcp)
4
+ [![Node.js >= 18](https://img.shields.io/badge/node-%3E%3D18-brightgreen)](https://nodejs.org)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
6
+
7
+ MCP Server for **oh-memos** — Intelligent Persistent Memory for AI Assistants.
8
+
9
+ Pure Node.js. No Python required. Works with `npx` out of the box.
10
+
11
+ ---
12
+
13
+ ## Prerequisites
14
+
15
+ oh-memos backend API must be running before connecting this MCP server:
16
+
17
+ - **oh-memos API** on `http://localhost:18000`
18
+ - **Neo4j** on `localhost:7687` (Knowledge Graph)
19
+ - **Qdrant** on `localhost:6333` (Vector Search)
20
+
21
+ > Start all services: run `scripts\local\start.bat` from the [oh-memos repo](https://github.com/xigou/oh-memos).
22
+
23
+ ---
24
+
25
+ ## Quick Start
26
+
27
+ Add to your Claude Code `~/.claude/settings.json`:
28
+
29
+ ```json
30
+ {
31
+ "mcpServers": {
32
+ "oh-memos": {
33
+ "command": "npx",
34
+ "args": ["-y", "oh-memos-mcp"],
35
+ "env": {
36
+ "MEMOS_URL": "http://localhost:18000",
37
+ "MEMOS_USER": "dev_user",
38
+ "MEMOS_DEFAULT_CUBE": "dev_cube",
39
+ "MEMOS_CUBES_DIR": "G:/test/oh-memos/data/oh-memos_cubes"
40
+ }
41
+ }
42
+ }
43
+ }
44
+ ```
45
+
46
+ Or use a `.env` file in your working directory (the server auto-discovers it):
47
+
48
+ ```bash
49
+ cp node_modules/oh-memos-mcp/.env.example .env
50
+ # Edit .env with your paths
51
+ npx oh-memos-mcp
52
+ ```
53
+
54
+ ---
55
+
56
+ ## Configuration Examples
57
+
58
+ ### Linux / macOS
59
+
60
+ ```json
61
+ {
62
+ "mcpServers": {
63
+ "oh-memos": {
64
+ "command": "npx",
65
+ "args": ["-y", "oh-memos-mcp"],
66
+ "env": {
67
+ "MEMOS_URL": "http://localhost:18000",
68
+ "MEMOS_USER": "dev_user",
69
+ "MEMOS_DEFAULT_CUBE": "dev_cube",
70
+ "MEMOS_CUBES_DIR": "/home/user/oh-memos/data/oh-memos_cubes"
71
+ }
72
+ }
73
+ }
74
+ }
75
+ ```
76
+
77
+ ### Windows
78
+
79
+ ```json
80
+ {
81
+ "mcpServers": {
82
+ "oh-memos": {
83
+ "command": "npx",
84
+ "args": ["-y", "oh-memos-mcp"],
85
+ "env": {
86
+ "MEMOS_URL": "http://localhost:18000",
87
+ "MEMOS_USER": "dev_user",
88
+ "MEMOS_DEFAULT_CUBE": "dev_cube",
89
+ "MEMOS_CUBES_DIR": "G:/test/oh-memos/data/oh-memos_cubes"
90
+ }
91
+ }
92
+ }
93
+ }
94
+ ```
95
+
96
+ ### WSL2
97
+
98
+ ```json
99
+ {
100
+ "mcpServers": {
101
+ "oh-memos": {
102
+ "command": "npx",
103
+ "args": ["-y", "oh-memos-mcp"],
104
+ "env": {
105
+ "MEMOS_URL": "http://localhost:18000",
106
+ "MEMOS_USER": "dev_user",
107
+ "MEMOS_DEFAULT_CUBE": "dev_cube",
108
+ "MEMOS_CUBES_DIR": "/mnt/g/test/oh-memos/data/oh-memos_cubes"
109
+ }
110
+ }
111
+ }
112
+ }
113
+ ```
114
+
115
+ ### With `alwaysAllow` (skip per-tool confirmation)
116
+
117
+ `alwaysAllow` matches **tool names**, so a call form like
118
+ `memos_admin(action=list_cubes)` matches nothing — list the bare name and every
119
+ action of that tool is auto-approved.
120
+
121
+ `memos_delete` is deliberately absent below. Auto-approving it means memories can
122
+ be deleted without a prompt; add it only if you have decided you want that.
123
+
124
+ ```json
125
+ {
126
+ "mcpServers": {
127
+ "oh-memos": {
128
+ "type": "stdio",
129
+ "command": "npx",
130
+ "args": ["-y", "oh-memos-mcp"],
131
+ "env": {
132
+ "MEMOS_URL": "http://localhost:18000",
133
+ "MEMOS_USER": "dev_user",
134
+ "MEMOS_DEFAULT_CUBE": "dev_cube",
135
+ "MEMOS_CUBES_DIR": "/path/to/oh-memos/data/oh-memos_cubes"
136
+ },
137
+ "alwaysAllow": [
138
+ "memos_context_resume",
139
+ "memos_search",
140
+ "memos_save",
141
+ "memos_list_v2",
142
+ "memos_get",
143
+ "memos_suggest",
144
+ "memos_think",
145
+ "memos_graph",
146
+ "memos_admin",
147
+ "memos_export_wiki",
148
+ "memos_canvas"
149
+ ]
150
+ }
151
+ }
152
+ }
153
+ ```
154
+
155
+ ---
156
+
157
+ ## Environment Variables
158
+
159
+ | Variable | Required | Default | Description |
160
+ |----------|----------|---------|-------------|
161
+ | `MEMOS_URL` | Yes | — | oh-memos API base URL |
162
+ | `MEMOS_USER` | Yes | — | Default user ID |
163
+ | `MEMOS_DEFAULT_CUBE` | Yes | — | Default memory cube ID |
164
+ | `MEMOS_CUBES_DIR` | Yes | — | Absolute path to cubes storage directory |
165
+ | `MEMOS_TIMEOUT_TOOL` | No | `300` | Tool call timeout (seconds) |
166
+ | `MEMOS_TIMEOUT_STARTUP` | No | `30` | API startup wait timeout (seconds) |
167
+ | `MEMOS_TIMEOUT_HEALTH` | No | `5` | Health check timeout (seconds) |
168
+ | `MEMOS_API_WAIT_MAX` | No | `60` | Max time to wait for API on startup (seconds) |
169
+ | `MEMOS_ENABLE_DELETE` | No | `false` | Enable `memos_delete` tool |
170
+ | `NEO4J_HTTP_URL` | No | — | Neo4j HTTP endpoint (for direct graph queries) |
171
+ | `NEO4J_USER` | No | — | Neo4j username |
172
+ | `NEO4J_PASSWORD` | No | — | Neo4j password |
173
+ | `MEMOS_ENV_FILE` | No | — | Explicit path to a `.env` file. Highest priority — see below |
174
+
175
+ > **On locating `.env`**: without `MEMOS_ENV_FILE`, the file is found by guessing
176
+ > from position (working directory, two levels above the package, then dotenv's
177
+ > upward search). That works from a checkout and **never works under `npx`**,
178
+ > where the package root sits in the npm cache and every candidate misses — so no
179
+ > variable loads at all. Set `MEMOS_ENV_FILE` (or pass `--memos-env-file`) when the
180
+ > client's working directory and the install location are both outside the project.
181
+ > A path that does not exist warns on stderr rather than failing silently.
182
+ >
183
+ > Copy `.env.example` to get started.
184
+
185
+ ---
186
+
187
+ ## Tools (17)
188
+
189
+ The package defines 17 tool schemas. `memos_delete` is exposed by `tools/list`
190
+ only when `MEMOS_ENABLE_DELETE=true`; the other 16 are available by default.
191
+
192
+ <!-- mcp-tool-inventory:start -->
193
+ | Tool | Description |
194
+ |------|-------------|
195
+ | `memos_context_resume` | Recover project context after compaction (recent 24h + project state) |
196
+ | `memos_search` | Semantic search with keyword reranking. Pass `context` (recent turns) to enable LLM intent analysis and query expansion |
197
+ | `memos_save` | Save memories with explicit type (BUGFIX, DECISION, MILESTONE, SYNTHESIS…) |
198
+ | `memos_list_v2` | List memories with auto-compaction |
199
+ | `memos_get` | Get full memory details by ID |
200
+ | `memos_suggest` | Smart search query suggestions + `memory_type` decision tree |
201
+ | `memos_think` | Evidence pack for a question: retrieval + contradiction/staleness flags + gap analysis. The caller synthesizes the answer and may persist it as `SYNTHESIS` |
202
+ | `memos_graph` | Explainable graph queries plus strict Graphify node-link validation — `mode`: `related` / `path` / `impact` / `schema` / `import` |
203
+ | `memos_admin` | Maintenance — `action`: `list_cubes` / `register_cube` / `create_user` / `validate_cubes` / `stats` / `calendar` |
204
+ | `memos_export_wiki` | Export a cube as an interlinked markdown wiki (page per memory + index + mermaid graph) |
205
+ | `memos_import_wiki` | Import an exported wiki back into a cube; supports dry-run and versioning edited pages, never deletes memories |
206
+ | `memos_canvas` | Symbolic task canvas — short-term task state that survives context compaction. `action`: `open` / `update` / `show` / `list`. Nodes carry greppable ids (`000-N1`) and a `ref` anchoring them to evidence: `mem:<memory_id>` / `file:<path>` / `note:<text>` |
207
+ | `memos_distill_skill` | Create an inert, reviewable Skill candidate under `<project_path>/skill-candidates`; it never installs the candidate automatically |
208
+ | `memos_list_skill_candidates` | List generated Skill candidates without modifying or installing them |
209
+ | `memos_review_skill_candidate` | Approve or reject a candidate with reviewer audit metadata; approval does not install |
210
+ | `memos_install_skill_candidate` | Install an approved candidate only into `.claude/skills/<slug>/SKILL.md`, without overwrite or script execution |
211
+ | `memos_delete` | Delete selected or all memories. Disabled by default and requires explicit user confirmation when enabled |
212
+ <!-- mcp-tool-inventory:end -->
213
+
214
+ ### `memos_graph` modes
215
+
216
+ | Mode | Main input | Result |
217
+ |------|------------|--------|
218
+ | `related` | `query` | Related memories and edges, with provenance explanations when available |
219
+ | `path` | `source_id`, `target_id` | A bounded path between two graph nodes, including relationship evidence |
220
+ | `impact` | `memory_id`, optional `max_depth` | Forward blast radius from one memory |
221
+ | `schema` | Optional `sample_size` | Graph structure and statistics |
222
+ | `import` | `graph_json`, optional `project_key` | Deterministic validation and dry-run plan for Graphify NetworkX node-link JSON |
223
+
224
+ `import` accepts at most 5 MB of JSON and rejects duplicate node ids, dangling
225
+ edges, unsafe source paths, invalid confidence values, and oversized graphs. It
226
+ does **not** write Code Graph nodes to Neo4j, Qdrant, or a memory cube.
227
+
228
+ ---
229
+
230
+ ## How .env Loading Works
231
+
232
+ Priority order for configuration values (highest first):
233
+
234
+ 1. **CLI configuration flags** such as `--memos-url`
235
+ 2. **Explicit env file** selected by `--memos-env-file` or inherited `MEMOS_ENV_FILE`
236
+ 3. **Inherited process environment** — this is where MCP client `env` values belong
237
+ 4. **Auto-discovered `process.cwd()/.env`** — provides only missing defaults
238
+ 5. **Auto-discovered package-root `.env`** — provides only missing defaults
239
+ 6. **dotenv upward fallback**, then built-in defaults
240
+
241
+ The automatic file search never overrides explicit MCP/launcher environment values. Use `MEMOS_ENV_FILE` only when the selected file should deliberately be authoritative; this is also the reliable option for `npx` installs.
242
+
243
+ ---
244
+
245
+ ## Development
246
+
247
+ ```bash
248
+ git clone https://github.com/xigou/oh-memos.git
249
+ cd oh-memos/mcp-server-node
250
+ npm install
251
+ npm run dev # Run with tsx (no build needed)
252
+ npm run build # Compile to dist/
253
+ ```
254
+
255
+ ---
256
+
257
+ ## Requirements
258
+
259
+ - Node.js >= 18.0.0
260
+ - oh-memos backend API running (`scripts\local\start.bat`)
File without changes
File without changes
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Symbolic task canvas — parse and render.
3
+ *
4
+ * A canvas is one Mermaid file. It is the whole truth: there is no parallel
5
+ * JSON sidecar, because two files describing one task drift apart the first
6
+ * time a write fails halfway. The cost of that choice is that the format has to
7
+ * survive a round trip exactly, which is what the tests pin down.
8
+ *
9
+ * The shape borrows the `NNN-Nn` node id from TencentDB Agent Memory, for the
10
+ * reason that made it work there: it is greppable. An id in a canvas, a commit
11
+ * message or a memory body all lead back to the same node.
12
+ *
13
+ * What is ours is the `ref`: an anchor with a scheme, so a node can point at a
14
+ * memory in the graph (`mem:`), a file the harness already offloaded (`file:`),
15
+ * or an inline remark (`note:`). Their design only ever pointed at local files.
16
+ */
17
+ export declare const NODE_STATUSES: readonly ["todo", "doing", "done", "blocked"];
18
+ export type NodeStatus = (typeof NODE_STATUSES)[number];
19
+ export interface CanvasNode {
20
+ /** `NNN-Nn`, allocated monotonically and never reused. */
21
+ id: string;
22
+ status: NodeStatus;
23
+ summary: string;
24
+ /** `mem:<uuid>` | `file:<path>` | `note:<text>`, or null. */
25
+ ref: string | null;
26
+ }
27
+ export interface Canvas {
28
+ /** Three-digit canvas prefix; every node id starts with it. */
29
+ prefix: string;
30
+ taskGoal: string;
31
+ createdTime: string | null;
32
+ updatedTime: string | null;
33
+ nodes: CanvasNode[];
34
+ }
35
+ /** Cap on a rendered node summary. Long enough to be useful, short enough that
36
+ * a 20-node canvas still costs a few hundred tokens rather than a few thousand. */
37
+ export declare const SUMMARY_MAX = 120;
38
+ /**
39
+ * Reduce a title to a filename-safe slug.
40
+ *
41
+ * The whitelist is `[a-z0-9-]` and nothing else — not a blacklist of dangerous
42
+ * characters, because that is the kind of list that is always missing one entry.
43
+ * `.` is outside the whitelist, so `..` cannot survive and traversal is
44
+ * structurally impossible rather than merely checked for.
45
+ *
46
+ * Returns "" when nothing usable remains (a purely CJK title, for instance);
47
+ * callers must have a fallback and must not write a file named "".
48
+ */
49
+ export declare function slugify(input: string): string;
50
+ /**
51
+ * Make text safe to sit inside a Mermaid `["..."]` label.
52
+ *
53
+ * Mermaid has no escape syntax inside a quoted label, so the only reliable move
54
+ * is to replace the characters that would terminate it with lookalikes. A
55
+ * summary is prose for a human to skim; swapping `"` for `'` costs nothing a
56
+ * reader will miss, and it makes `x"] --> EVIL["pwned` inert.
57
+ *
58
+ * Arrows are neutralised too: a literal `-->` inside a label does not break
59
+ * Mermaid, but it reads as an edge to anyone scanning the file, and to the
60
+ * regex in `parseCanvas` if it ever loosens.
61
+ */
62
+ export declare function escapeLabel(text: string): string;
63
+ /**
64
+ * Trim to `max` characters, counting by code point.
65
+ *
66
+ * `String.prototype.slice` counts UTF-16 units, so slicing a string of astral
67
+ * characters mid-pair yields a lone surrogate — which is not a character, and
68
+ * which some JSON consumers reject outright. Spreading into an array iterates
69
+ * code points, so a cut always lands on a boundary.
70
+ */
71
+ export declare function truncateSummary(text: string, max?: number): string;
72
+ /**
73
+ * Next unused node id for this canvas.
74
+ *
75
+ * Deliberately max+1 rather than filling gaps. A deleted `000-N2` may still be
76
+ * cited by a commit message, a memory body or another node's ref; handing that
77
+ * id to a new node would silently repoint every one of those citations. Ids are
78
+ * cheap, so they are spent rather than recycled.
79
+ */
80
+ export declare function allocateNodeId(canvas: Canvas): string;
81
+ export declare function renderCanvas(canvas: Canvas): string;
82
+ /**
83
+ * Parse a canvas file.
84
+ *
85
+ * Never throws. A canvas is recovered state — it is read at the moment the
86
+ * model has just lost its context, which is the worst possible moment to hand
87
+ * back an exception. A damaged header costs the goal; a damaged line costs that
88
+ * line; everything still parseable is returned.
89
+ */
90
+ export declare function parseCanvas(content: string): Canvas;
91
+ export interface CanvasCounts {
92
+ done: number;
93
+ doing: number;
94
+ todo: number;
95
+ blocked: number;
96
+ }
97
+ export declare function countByStatus(canvas: Canvas): CanvasCounts;
98
+ /** One-line digest for the progressive-disclosure index: enough to decide
99
+ * whether to open the canvas, not enough to be worth injecting wholesale. */
100
+ export declare function formatCanvasHeadline(canvas: Canvas): string;
101
+ //# sourceMappingURL=canvas-format.d.ts.map