@hir4ta/mneme 0.17.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/.claude-plugin/plugin.json +29 -0
- package/.mcp.json +18 -0
- package/README.ja.md +400 -0
- package/README.md +410 -0
- package/bin/mneme.js +203 -0
- package/dist/lib/db.js +340 -0
- package/dist/lib/fuzzy-search.js +214 -0
- package/dist/lib/github.js +121 -0
- package/dist/lib/similarity.js +193 -0
- package/dist/lib/utils.js +62 -0
- package/dist/public/apple-touch-icon.png +0 -0
- package/dist/public/assets/index-BgqCALAg.css +1 -0
- package/dist/public/assets/index-EMvn4VEa.js +330 -0
- package/dist/public/assets/react-force-graph-2d-DWoBaKmT.js +46 -0
- package/dist/public/favicon-128-max.png +0 -0
- package/dist/public/favicon-256-max.png +0 -0
- package/dist/public/favicon-32-max.png +0 -0
- package/dist/public/favicon-512-max.png +0 -0
- package/dist/public/favicon-64-max.png +0 -0
- package/dist/public/index.html +15 -0
- package/dist/server.js +4791 -0
- package/dist/servers/db-server.js +30558 -0
- package/dist/servers/search-server.js +30366 -0
- package/hooks/default-tags.json +1055 -0
- package/hooks/hooks.json +61 -0
- package/hooks/post-tool-use.sh +96 -0
- package/hooks/pre-compact.sh +187 -0
- package/hooks/session-end.sh +567 -0
- package/hooks/session-start.sh +380 -0
- package/hooks/user-prompt-submit.sh +253 -0
- package/package.json +77 -0
- package/servers/db-server.ts +993 -0
- package/servers/search-server.ts +675 -0
- package/skills/AGENTS.override.md +5 -0
- package/skills/harvest/skill.md +295 -0
- package/skills/init-mneme/skill.md +101 -0
- package/skills/plan/skill.md +422 -0
- package/skills/report/skill.md +74 -0
- package/skills/resume/skill.md +278 -0
- package/skills/review/skill.md +419 -0
- package/skills/save/skill.md +482 -0
- package/skills/search/skill.md +175 -0
- package/skills/using-mneme/skill.md +185 -0
package/README.md
ADDED
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
# mneme
|
|
2
|
+
|
|
3
|
+
> **⚠️ Breaking Change (v0.17.0)**: Renamed from `memoria` to `mneme`.
|
|
4
|
+
> If upgrading from `@hir4ta/memoria`, please reinstall:
|
|
5
|
+
> ```bash
|
|
6
|
+
> claude mcp remove mneme-search mneme-db
|
|
7
|
+
> claude plugin remove @hir4ta/memoria
|
|
8
|
+
> claude plugin add @hir4ta/mneme
|
|
9
|
+
> ```
|
|
10
|
+
> Data directory changed: `.memoria/` → `.mneme/`
|
|
11
|
+
> Rename manually: `mv .memoria .mneme`
|
|
12
|
+
|
|
13
|
+
Long-term memory plugin for Claude Code
|
|
14
|
+
|
|
15
|
+
Provides automatic session saving, intelligent memory search, and web dashboard management.
|
|
16
|
+
|
|
17
|
+
## Features
|
|
18
|
+
|
|
19
|
+
### Core Features
|
|
20
|
+
- **Auto-save interactions**: Conversations auto-saved at session end (jq-based, reliable)
|
|
21
|
+
- **Auto memory search**: Related past sessions/decisions automatically injected on each prompt
|
|
22
|
+
- **Backup on PreCompact**: Interactions backed up before Auto-Compact (context 95% full)
|
|
23
|
+
- **Full data extraction**: Save summary, decisions, patterns, and rules with `/mneme:save`
|
|
24
|
+
- **Memory-informed planning**: Design and plan with past knowledge via `/mneme:plan`
|
|
25
|
+
- **Session Resume**: Resume past sessions with `/mneme:resume` (with chain tracking)
|
|
26
|
+
- **Session Suggestion**: Recent 3 sessions shown at session start
|
|
27
|
+
- **Rule-based Review**: Code review based on `dev-rules.json` / `review-guidelines.json`
|
|
28
|
+
- **GitHub PR Review**: Review GitHub PRs with `/mneme:review <PR URL>`
|
|
29
|
+
- **Knowledge Harvesting**: Extract rules and patterns from PR comments with `/mneme:harvest`
|
|
30
|
+
- **Weekly Reports**: Auto-generate Markdown reports aggregating review results
|
|
31
|
+
- **Web Dashboard**: View sessions, decisions, patterns, and rules
|
|
32
|
+
|
|
33
|
+
## Problems Solved
|
|
34
|
+
|
|
35
|
+
### Common Issues in Claude Code Development
|
|
36
|
+
|
|
37
|
+
- **Context Loss**: Conversation context is lost on session end or Auto-Compact
|
|
38
|
+
- **Opaque Decisions**: "Why did we choose this design?" becomes untraceable
|
|
39
|
+
- **Repeated Mistakes**: Same errors solved multiple times without learning
|
|
40
|
+
- **Hard to Reuse Knowledge**: Past interactions and decisions are hard to search
|
|
41
|
+
|
|
42
|
+
### What mneme Enables
|
|
43
|
+
|
|
44
|
+
- **Auto-save + Resume** enables context continuity across sessions
|
|
45
|
+
- **Auto memory search** brings relevant past knowledge to every conversation
|
|
46
|
+
- **Decision & Pattern Recording** tracks reasoning and error solutions
|
|
47
|
+
- **Search and Dashboard** for quick access to past records
|
|
48
|
+
- **Review Feature** for repository-specific code review
|
|
49
|
+
|
|
50
|
+
### Team Benefits
|
|
51
|
+
|
|
52
|
+
- `.mneme/` JSON files are **Git-manageable**, enabling team sharing of decisions and session history
|
|
53
|
+
- Quickly understand background and context during onboarding or reviews
|
|
54
|
+
|
|
55
|
+
## Installation
|
|
56
|
+
|
|
57
|
+
### Prerequisites
|
|
58
|
+
|
|
59
|
+
- **jq**: Used for JSON processing in hooks
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
# macOS
|
|
63
|
+
brew install jq
|
|
64
|
+
|
|
65
|
+
# Ubuntu/Debian
|
|
66
|
+
sudo apt-get install jq
|
|
67
|
+
|
|
68
|
+
# Windows (Chocolatey)
|
|
69
|
+
choco install jq
|
|
70
|
+
|
|
71
|
+
# Windows (Scoop)
|
|
72
|
+
scoop install jq
|
|
73
|
+
|
|
74
|
+
# Windows (winget)
|
|
75
|
+
winget install jqlang.jq
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Plugin Installation
|
|
79
|
+
|
|
80
|
+
Run the following in Claude Code:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
/plugin marketplace add hir4ta/mneme-marketplace
|
|
84
|
+
/plugin install mneme@mneme-marketplace
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Then initialize mneme in your project:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
# In Claude Code
|
|
91
|
+
/init-mneme
|
|
92
|
+
|
|
93
|
+
# Or from terminal
|
|
94
|
+
npx @hir4ta/mneme --init
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Restart Claude Code to complete installation.
|
|
98
|
+
|
|
99
|
+
## Update
|
|
100
|
+
|
|
101
|
+
Run the following in Claude Code:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
/plugin marketplace update mneme-marketplace
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Restart Claude Code.
|
|
108
|
+
|
|
109
|
+
### Enable Auto-Update (Recommended)
|
|
110
|
+
|
|
111
|
+
1. Run `/plugin`
|
|
112
|
+
2. Select Marketplaces tab
|
|
113
|
+
3. Select `mneme-marketplace`
|
|
114
|
+
4. Enable "Enable auto-update"
|
|
115
|
+
|
|
116
|
+
This will auto-update on Claude Code startup.
|
|
117
|
+
|
|
118
|
+
## Usage
|
|
119
|
+
|
|
120
|
+
### Session Auto-Save
|
|
121
|
+
|
|
122
|
+
**Interactions are auto-saved** at session end using jq (no Claude dependency). No configuration needed.
|
|
123
|
+
|
|
124
|
+
**PreCompact** backs up interactions to `preCompactBackups` before Auto-Compact (context 95% full). Summary is NOT auto-created.
|
|
125
|
+
|
|
126
|
+
### Auto Memory Search
|
|
127
|
+
|
|
128
|
+
**On every prompt**, mneme automatically:
|
|
129
|
+
1. Extracts keywords from your message
|
|
130
|
+
2. Searches sessions/decisions/patterns
|
|
131
|
+
3. Injects relevant context to Claude
|
|
132
|
+
|
|
133
|
+
This means past knowledge is always available without manual lookup.
|
|
134
|
+
|
|
135
|
+
### Session Suggestion
|
|
136
|
+
|
|
137
|
+
At session start, recent 3 sessions are shown:
|
|
138
|
+
|
|
139
|
+
```
|
|
140
|
+
**Recent sessions:**
|
|
141
|
+
1. [abc123] JWT authentication implementation (2026-01-27, main)
|
|
142
|
+
2. [def456] Dashboard UI improvements (2026-01-26, main)
|
|
143
|
+
3. [ghi789] Bug fixes (2026-01-25, main)
|
|
144
|
+
|
|
145
|
+
Continue from a previous session? Use `/mneme:resume <id>`
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Commands
|
|
149
|
+
|
|
150
|
+
| Command | Description |
|
|
151
|
+
|---------|-------------|
|
|
152
|
+
| `/init-mneme` | Initialize mneme in current project |
|
|
153
|
+
| `/mneme:save` | Extract all data: summary, decisions, patterns, rules |
|
|
154
|
+
| `/mneme:plan [topic]` | Memory-informed design + Socratic questions + task breakdown |
|
|
155
|
+
| `/mneme:resume [id]` | Resume session (show list if ID omitted) |
|
|
156
|
+
| `/mneme:search "query"` | Search sessions, decisions, and patterns |
|
|
157
|
+
| `/mneme:review [--staged\|--all\|--diff=branch\|--full]` | Rule-based code review |
|
|
158
|
+
| `/mneme:review <PR URL>` | Review GitHub PR |
|
|
159
|
+
| `/mneme:harvest <PR URL>` | Extract knowledge from PR review comments |
|
|
160
|
+
| `/mneme:report [--from YYYY-MM-DD --to YYYY-MM-DD]` | Weekly review report |
|
|
161
|
+
|
|
162
|
+
### Recommended Workflow
|
|
163
|
+
|
|
164
|
+
```
|
|
165
|
+
plan → implement → save → review
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
1. **plan**: Design with memory lookup + Socratic questions + task breakdown
|
|
169
|
+
2. **implement**: Follow the plan
|
|
170
|
+
3. **save**: Extract decisions, patterns, rules
|
|
171
|
+
4. **review**: Verify against plan and code quality
|
|
172
|
+
|
|
173
|
+
### Dashboard
|
|
174
|
+
|
|
175
|
+
Run in your project directory:
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
npx @hir4ta/mneme --dashboard
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Open <http://localhost:7777> in your browser.
|
|
182
|
+
|
|
183
|
+
Change port:
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
npx @hir4ta/mneme --dashboard --port 8080
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
#### Screens
|
|
190
|
+
|
|
191
|
+
- **Sessions**: List and view sessions
|
|
192
|
+
- **Decisions**: List and view technical decisions
|
|
193
|
+
- **Rules**: View dev rules and review guidelines
|
|
194
|
+
- **Patterns**: View learned patterns (good patterns, anti-patterns, error solutions)
|
|
195
|
+
- **Statistics**: View activity charts and session statistics
|
|
196
|
+
- **Graph**: Visualize session connections by shared tags
|
|
197
|
+
|
|
198
|
+
#### Language Switching
|
|
199
|
+
|
|
200
|
+
The dashboard supports English and Japanese. Click the language toggle (EN/JA) in the header to switch. The preference is saved to localStorage.
|
|
201
|
+
|
|
202
|
+
### MCP Tools
|
|
203
|
+
|
|
204
|
+
mneme provides MCP servers with search and database tools callable directly from Claude Code:
|
|
205
|
+
|
|
206
|
+
| Server | Tool | Description |
|
|
207
|
+
|--------|------|-------------|
|
|
208
|
+
| mneme-search | `mneme_search` | Unified search (FTS5, tag alias resolution) |
|
|
209
|
+
| mneme-search | `mneme_get_session` | Get session details |
|
|
210
|
+
| mneme-search | `mneme_get_decision` | Get decision details |
|
|
211
|
+
| mneme-db | `mneme_list_projects` | List all projects |
|
|
212
|
+
| mneme-db | `mneme_cross_project_search` | Cross-project search |
|
|
213
|
+
|
|
214
|
+
### Subagents
|
|
215
|
+
|
|
216
|
+
| Agent | Description |
|
|
217
|
+
|-------|-------------|
|
|
218
|
+
| `mneme-reviewer` | Rule-based code review (isolated context) |
|
|
219
|
+
|
|
220
|
+
## How It Works
|
|
221
|
+
|
|
222
|
+
```mermaid
|
|
223
|
+
flowchart TB
|
|
224
|
+
subgraph autosave [Auto-Save Interactions]
|
|
225
|
+
A[Session End] --> B[SessionEnd Hook]
|
|
226
|
+
B --> C[jq extracts from transcript]
|
|
227
|
+
C --> D[interactions + files + metrics]
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
subgraph autosearch [Auto Memory Search]
|
|
231
|
+
E[User Prompt] --> F[UserPromptSubmit Hook]
|
|
232
|
+
F --> G[Search sessions/decisions/patterns]
|
|
233
|
+
G --> H[Inject relevant context]
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
subgraph backup [PreCompact Backup]
|
|
237
|
+
I[Context 95% Full] --> J[PreCompact Hook]
|
|
238
|
+
J --> K[Backup interactions to preCompactBackups]
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
subgraph manual [Manual Actions]
|
|
242
|
+
L["mneme:save"] --> M[Extract decisions + patterns + rules]
|
|
243
|
+
N["mneme:plan"] --> O[Memory-informed design + tasks]
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
subgraph resume [Session Resume]
|
|
247
|
+
P["mneme:resume"] --> Q[Select from list]
|
|
248
|
+
Q --> R[Restore past context + set resumedFrom]
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
subgraph review [Review]
|
|
252
|
+
S["mneme:review"] --> T[Rule-based findings]
|
|
253
|
+
T --> U[Save review results]
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
subgraph dashboard [Dashboard]
|
|
257
|
+
V["npx @hir4ta/mneme -d"] --> W[Open in browser]
|
|
258
|
+
W --> X[View all data]
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
D --> P
|
|
262
|
+
H --> L
|
|
263
|
+
M --> V
|
|
264
|
+
U --> V
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
## Data Storage
|
|
268
|
+
|
|
269
|
+
mneme uses a **hybrid storage** approach for privacy and collaboration:
|
|
270
|
+
|
|
271
|
+
| Storage | Location | Purpose | Sharing |
|
|
272
|
+
|---------|----------|---------|---------|
|
|
273
|
+
| **JSON** | `.mneme/` | Summaries, decisions, patterns, rules | Git-managed (team shared) |
|
|
274
|
+
| **SQLite** | `.mneme/local.db` | Interactions, backups | Local only (gitignored) |
|
|
275
|
+
|
|
276
|
+
**Why hybrid?**
|
|
277
|
+
- **Privacy**: Conversation history (interactions) stays local (gitignored)
|
|
278
|
+
- **Lightweight**: JSON files reduced from 100KB+ to ~5KB (interactions excluded)
|
|
279
|
+
- **Future-ready**: Embeddings table prepared for semantic search
|
|
280
|
+
|
|
281
|
+
### Directory Structure
|
|
282
|
+
|
|
283
|
+
**Project-local (`.mneme/`)**:
|
|
284
|
+
```text
|
|
285
|
+
.mneme/
|
|
286
|
+
├── local.db # SQLite with interactions (gitignored)
|
|
287
|
+
├── tags.json # Tag master file (93 tags, prevents notation variations)
|
|
288
|
+
├── sessions/ # Session metadata (YYYY/MM) - Git-managed
|
|
289
|
+
│ └── YYYY/MM/
|
|
290
|
+
│ └── {id}.json # Metadata only (interactions in local.db)
|
|
291
|
+
├── decisions/ # Technical decisions (from /save) - Git-managed
|
|
292
|
+
│ └── YYYY/MM/
|
|
293
|
+
│ └── {id}.json
|
|
294
|
+
├── patterns/ # Error patterns (from /save) - Git-managed
|
|
295
|
+
│ └── {user}.json
|
|
296
|
+
├── rules/ # Dev rules / review guidelines - Git-managed
|
|
297
|
+
├── reviews/ # Review results (YYYY/MM) - Git-managed
|
|
298
|
+
└── reports/ # Weekly reports (YYYY-MM) - Git-managed
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
The `local.db` file is automatically added to `.mneme/.gitignore` to keep conversations private.
|
|
302
|
+
|
|
303
|
+
### Session JSON Schema
|
|
304
|
+
|
|
305
|
+
Session metadata is stored in JSON (interactions are stored in SQLite for privacy):
|
|
306
|
+
|
|
307
|
+
```json
|
|
308
|
+
{
|
|
309
|
+
"id": "abc12345",
|
|
310
|
+
"sessionId": "full-uuid-from-claude-code",
|
|
311
|
+
"createdAt": "2026-01-27T10:00:00Z",
|
|
312
|
+
"endedAt": "2026-01-27T12:00:00Z",
|
|
313
|
+
"title": "JWT authentication implementation",
|
|
314
|
+
"tags": ["auth", "jwt"],
|
|
315
|
+
"context": {
|
|
316
|
+
"branch": "feature/auth",
|
|
317
|
+
"projectDir": "/path/to/project",
|
|
318
|
+
"user": { "name": "tanaka", "email": "tanaka@example.com" }
|
|
319
|
+
},
|
|
320
|
+
"metrics": {
|
|
321
|
+
"userMessages": 5,
|
|
322
|
+
"assistantResponses": 5,
|
|
323
|
+
"thinkingBlocks": 5,
|
|
324
|
+
"toolUsage": [{"name": "Edit", "count": 3}, {"name": "Write", "count": 2}]
|
|
325
|
+
},
|
|
326
|
+
"files": [
|
|
327
|
+
{ "path": "src/auth/jwt.ts", "action": "create" }
|
|
328
|
+
],
|
|
329
|
+
"resumedFrom": "def45678",
|
|
330
|
+
"status": "complete",
|
|
331
|
+
|
|
332
|
+
"summary": {
|
|
333
|
+
"title": "JWT authentication implementation",
|
|
334
|
+
"goal": "Implement JWT-based auth with refresh token support",
|
|
335
|
+
"outcome": "success",
|
|
336
|
+
"description": "Implemented JWT auth with RS256 signing",
|
|
337
|
+
"sessionType": "implementation"
|
|
338
|
+
},
|
|
339
|
+
|
|
340
|
+
"plan": {
|
|
341
|
+
"tasks": ["[x] JWT signing method selection", "[x] Middleware implementation", "[ ] Add tests"],
|
|
342
|
+
"remaining": ["Add tests"]
|
|
343
|
+
},
|
|
344
|
+
|
|
345
|
+
"discussions": [
|
|
346
|
+
{
|
|
347
|
+
"topic": "Signing algorithm",
|
|
348
|
+
"decision": "Adopt RS256",
|
|
349
|
+
"reasoning": "Security considerations for production",
|
|
350
|
+
"alternatives": ["HS256 (simpler but requires shared secret)"]
|
|
351
|
+
}
|
|
352
|
+
],
|
|
353
|
+
|
|
354
|
+
"errors": [
|
|
355
|
+
{
|
|
356
|
+
"error": "secretOrPrivateKey must be asymmetric",
|
|
357
|
+
"cause": "Using HS256 secret with RS256",
|
|
358
|
+
"solution": "Generate RS256 key pair"
|
|
359
|
+
}
|
|
360
|
+
],
|
|
361
|
+
|
|
362
|
+
"handoff": {
|
|
363
|
+
"stoppedReason": "Test creation postponed to next session",
|
|
364
|
+
"notes": ["vitest configured", "Mock key pair in test/fixtures/"],
|
|
365
|
+
"nextSteps": ["Create jwt.test.ts", "Add E2E tests"]
|
|
366
|
+
},
|
|
367
|
+
|
|
368
|
+
"references": [
|
|
369
|
+
{ "url": "https://jwt.io/introduction", "title": "JWT Introduction" }
|
|
370
|
+
]
|
|
371
|
+
}
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
### Session Types
|
|
375
|
+
|
|
376
|
+
The `sessionType` field classifies the session type.
|
|
377
|
+
|
|
378
|
+
| Type | Description |
|
|
379
|
+
|------|-------------|
|
|
380
|
+
| `decision` | Decision cycle present (design choices, tech selection) |
|
|
381
|
+
| `implementation` | Code changes made |
|
|
382
|
+
| `research` | Research, learning, catchup |
|
|
383
|
+
| `exploration` | Codebase exploration |
|
|
384
|
+
| `discussion` | Discussion, consultation only |
|
|
385
|
+
| `debug` | Debugging, investigation |
|
|
386
|
+
| `review` | Code review |
|
|
387
|
+
|
|
388
|
+
### Tags
|
|
389
|
+
|
|
390
|
+
Tags are selected from `.mneme/tags.json` to prevent notation variations (e.g., "フロント" → "frontend"). The master file contains 93 tags across 11 categories:
|
|
391
|
+
|
|
392
|
+
- **domain**: frontend, backend, api, db, infra, mobile, cli
|
|
393
|
+
- **phase**: feature, bugfix, refactor, test, docs
|
|
394
|
+
- **ai**: llm, ai-agent, mcp, rag, vector-db, embedding
|
|
395
|
+
- **cloud**: serverless, microservices, edge, wasm
|
|
396
|
+
- And more...
|
|
397
|
+
|
|
398
|
+
## Versioning
|
|
399
|
+
|
|
400
|
+
This project follows [Semantic Versioning](https://semver.org/).
|
|
401
|
+
|
|
402
|
+
**⚠️ While in 0.x (pre-1.0), breaking changes may occur between minor versions.**
|
|
403
|
+
|
|
404
|
+
If you encounter issues after an update:
|
|
405
|
+
1. Check the [releases](https://github.com/hir4ta/mneme/releases) for migration notes
|
|
406
|
+
2. Re-initialize with `npx @hir4ta/mneme --init` if needed
|
|
407
|
+
|
|
408
|
+
## License
|
|
409
|
+
|
|
410
|
+
MIT
|
package/bin/mneme.js
ADDED
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { fork } from "node:child_process";
|
|
4
|
+
import fs from "node:fs";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
|
|
8
|
+
// Suppress Node.js SQLite experimental warning (must be before dynamic import)
|
|
9
|
+
const originalEmit = process.emit;
|
|
10
|
+
process.emit = (name, data, ...args) => {
|
|
11
|
+
if (
|
|
12
|
+
name === "warning" &&
|
|
13
|
+
data?.name === "ExperimentalWarning" &&
|
|
14
|
+
data?.message?.includes("SQLite")
|
|
15
|
+
) {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
return originalEmit.call(process, name, data, ...args);
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
// Dynamic import to ensure warning suppression is active
|
|
22
|
+
const { DatabaseSync } = await import("node:sqlite");
|
|
23
|
+
|
|
24
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
25
|
+
const __dirname = path.dirname(__filename);
|
|
26
|
+
|
|
27
|
+
const args = process.argv.slice(2);
|
|
28
|
+
const packageDir = path.dirname(__dirname);
|
|
29
|
+
const projectRoot = process.cwd();
|
|
30
|
+
|
|
31
|
+
function showHelp() {
|
|
32
|
+
console.log(`
|
|
33
|
+
mneme - Claude Code Long-term Memory Plugin
|
|
34
|
+
|
|
35
|
+
Usage:
|
|
36
|
+
mneme --init Initialize .mneme directory in current project
|
|
37
|
+
mneme --dashboard Start the web dashboard
|
|
38
|
+
mneme -d Same as above (short form)
|
|
39
|
+
mneme --port <port> Specify port (default: 7777)
|
|
40
|
+
mneme --help Show this help
|
|
41
|
+
|
|
42
|
+
Examples:
|
|
43
|
+
cd /path/to/your/project
|
|
44
|
+
npx @hir4ta/mneme --init
|
|
45
|
+
npx @hir4ta/mneme --dashboard
|
|
46
|
+
npx @hir4ta/mneme -d --port 8080
|
|
47
|
+
`);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function checkMnemeDir() {
|
|
51
|
+
const mnemeDir = path.join(projectRoot, ".mneme");
|
|
52
|
+
if (!fs.existsSync(mnemeDir)) {
|
|
53
|
+
console.log(`\nWARNING: .mneme directory not found: ${projectRoot}`);
|
|
54
|
+
console.log(" Run: npx @hir4ta/mneme --init");
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function initMneme() {
|
|
59
|
+
const mnemeDir = path.join(projectRoot, ".mneme");
|
|
60
|
+
const sessionsDir = path.join(mnemeDir, "sessions");
|
|
61
|
+
const rulesDir = path.join(mnemeDir, "rules");
|
|
62
|
+
const patternsDir = path.join(mnemeDir, "patterns");
|
|
63
|
+
const tagsPath = path.join(mnemeDir, "tags.json");
|
|
64
|
+
const localDbPath = path.join(mnemeDir, "local.db");
|
|
65
|
+
const gitignorePath = path.join(mnemeDir, ".gitignore");
|
|
66
|
+
|
|
67
|
+
// Check if already initialized
|
|
68
|
+
if (fs.existsSync(mnemeDir)) {
|
|
69
|
+
console.log(`mneme is already initialized: ${mnemeDir}`);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Create directories
|
|
74
|
+
fs.mkdirSync(sessionsDir, { recursive: true });
|
|
75
|
+
fs.mkdirSync(rulesDir, { recursive: true });
|
|
76
|
+
fs.mkdirSync(patternsDir, { recursive: true });
|
|
77
|
+
|
|
78
|
+
// Copy default tags.json
|
|
79
|
+
const defaultTagsPath = path.join(packageDir, "hooks", "default-tags.json");
|
|
80
|
+
if (fs.existsSync(defaultTagsPath)) {
|
|
81
|
+
fs.copyFileSync(defaultTagsPath, tagsPath);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Initialize rules files
|
|
85
|
+
const now = new Date().toISOString();
|
|
86
|
+
const rulesTemplate = JSON.stringify(
|
|
87
|
+
{
|
|
88
|
+
schemaVersion: 1,
|
|
89
|
+
createdAt: now,
|
|
90
|
+
updatedAt: now,
|
|
91
|
+
items: [],
|
|
92
|
+
},
|
|
93
|
+
null,
|
|
94
|
+
2,
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
fs.writeFileSync(
|
|
98
|
+
path.join(rulesDir, "review-guidelines.json"),
|
|
99
|
+
rulesTemplate,
|
|
100
|
+
);
|
|
101
|
+
fs.writeFileSync(path.join(rulesDir, "dev-rules.json"), rulesTemplate);
|
|
102
|
+
|
|
103
|
+
// Create .gitignore for local.db
|
|
104
|
+
const gitignoreContent = `# Local SQLite database (private interactions)
|
|
105
|
+
local.db
|
|
106
|
+
local.db-wal
|
|
107
|
+
local.db-shm
|
|
108
|
+
`;
|
|
109
|
+
fs.writeFileSync(gitignorePath, gitignoreContent);
|
|
110
|
+
|
|
111
|
+
// Initialize local SQLite database
|
|
112
|
+
const schemaPath = path.join(packageDir, "lib", "schema.sql");
|
|
113
|
+
try {
|
|
114
|
+
const db = new DatabaseSync(localDbPath);
|
|
115
|
+
db.exec("PRAGMA journal_mode = WAL");
|
|
116
|
+
db.exec("PRAGMA busy_timeout = 5000");
|
|
117
|
+
db.exec("PRAGMA synchronous = NORMAL");
|
|
118
|
+
if (fs.existsSync(schemaPath)) {
|
|
119
|
+
const schema = fs.readFileSync(schemaPath, "utf-8");
|
|
120
|
+
db.exec(schema);
|
|
121
|
+
}
|
|
122
|
+
db.close();
|
|
123
|
+
} catch (error) {
|
|
124
|
+
console.error(
|
|
125
|
+
`Warning: Failed to initialize SQLite database: ${error.message}`,
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
console.log(`mneme initialized: ${mnemeDir}`);
|
|
130
|
+
console.log(`
|
|
131
|
+
Created:
|
|
132
|
+
${sessionsDir}/
|
|
133
|
+
${rulesDir}/
|
|
134
|
+
${patternsDir}/
|
|
135
|
+
${tagsPath}
|
|
136
|
+
${rulesDir}/review-guidelines.json
|
|
137
|
+
${rulesDir}/dev-rules.json
|
|
138
|
+
${gitignorePath}
|
|
139
|
+
${localDbPath}
|
|
140
|
+
|
|
141
|
+
You can now use mneme with Claude Code in this project.
|
|
142
|
+
`);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function getPort() {
|
|
146
|
+
const portIndex = args.indexOf("--port");
|
|
147
|
+
if (portIndex !== -1 && args[portIndex + 1]) {
|
|
148
|
+
return parseInt(args[portIndex + 1], 10) || 7777;
|
|
149
|
+
}
|
|
150
|
+
return 7777;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function startDashboard() {
|
|
154
|
+
checkMnemeDir();
|
|
155
|
+
|
|
156
|
+
const port = getPort();
|
|
157
|
+
const serverPath = path.join(packageDir, "dist", "server.js");
|
|
158
|
+
|
|
159
|
+
if (!fs.existsSync(serverPath)) {
|
|
160
|
+
console.error("ERROR: Server build not found.");
|
|
161
|
+
console.error(" The package may not be installed correctly.");
|
|
162
|
+
process.exit(1);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const child = fork(serverPath, [], {
|
|
166
|
+
cwd: packageDir,
|
|
167
|
+
env: {
|
|
168
|
+
...process.env,
|
|
169
|
+
MNEME_PROJECT_ROOT: projectRoot,
|
|
170
|
+
PORT: port.toString(),
|
|
171
|
+
},
|
|
172
|
+
stdio: "inherit",
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
child.on("error", (err) => {
|
|
176
|
+
console.error("ERROR: Failed to start dashboard:", err.message);
|
|
177
|
+
process.exit(1);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
child.on("close", (code) => {
|
|
181
|
+
process.exit(code || 0);
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
process.on("SIGINT", () => {
|
|
185
|
+
child.kill("SIGINT");
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Parse arguments
|
|
190
|
+
if (args.length === 0 || args.includes("--help") || args.includes("-h")) {
|
|
191
|
+
showHelp();
|
|
192
|
+
process.exit(0);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
if (args.includes("--init")) {
|
|
196
|
+
initMneme();
|
|
197
|
+
} else if (args.includes("--dashboard") || args.includes("-d")) {
|
|
198
|
+
startDashboard();
|
|
199
|
+
} else {
|
|
200
|
+
console.error(`ERROR: Unknown option: ${args.join(" ")}`);
|
|
201
|
+
showHelp();
|
|
202
|
+
process.exit(1);
|
|
203
|
+
}
|