memnant 0.1.0 → 0.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/README.md +131 -61
- package/dist/cli/archive.d.ts +9 -0
- package/dist/cli/archive.d.ts.map +1 -0
- package/dist/cli/archive.js +101 -0
- package/dist/cli/archive.js.map +1 -0
- package/dist/cli/export.d.ts.map +1 -1
- package/dist/cli/export.js +88 -7
- package/dist/cli/export.js.map +1 -1
- package/dist/cli/graph.d.ts +9 -0
- package/dist/cli/graph.d.ts.map +1 -0
- package/dist/cli/graph.js +108 -0
- package/dist/cli/graph.js.map +1 -0
- package/dist/cli/health.d.ts +9 -0
- package/dist/cli/health.d.ts.map +1 -0
- package/dist/cli/health.js +49 -0
- package/dist/cli/health.js.map +1 -0
- package/dist/cli/import.d.ts +10 -0
- package/dist/cli/import.d.ts.map +1 -0
- package/dist/cli/import.js +91 -0
- package/dist/cli/import.js.map +1 -0
- package/dist/cli/index.js +16 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/instructions.d.ts +11 -0
- package/dist/cli/instructions.d.ts.map +1 -1
- package/dist/cli/instructions.js +172 -32
- package/dist/cli/instructions.js.map +1 -1
- package/dist/cli/lint.d.ts +3 -0
- package/dist/cli/lint.d.ts.map +1 -1
- package/dist/cli/lint.js +81 -9
- package/dist/cli/lint.js.map +1 -1
- package/dist/cli/patterns.d.ts +8 -0
- package/dist/cli/patterns.d.ts.map +1 -0
- package/dist/cli/patterns.js +56 -0
- package/dist/cli/patterns.js.map +1 -0
- package/dist/cli/recall.d.ts.map +1 -1
- package/dist/cli/recall.js +24 -9
- package/dist/cli/recall.js.map +1 -1
- package/dist/cli/retract.d.ts +9 -0
- package/dist/cli/retract.d.ts.map +1 -0
- package/dist/cli/retract.js +64 -0
- package/dist/cli/retract.js.map +1 -0
- package/dist/cli/setup.d.ts +1 -0
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +33 -0
- package/dist/cli/setup.js.map +1 -1
- package/dist/cli/snapshot.d.ts.map +1 -1
- package/dist/cli/snapshot.js +21 -0
- package/dist/cli/snapshot.js.map +1 -1
- package/dist/cli/stats.d.ts +8 -0
- package/dist/cli/stats.d.ts.map +1 -0
- package/dist/cli/stats.js +96 -0
- package/dist/cli/stats.js.map +1 -0
- package/dist/cli/synthesise.d.ts +8 -0
- package/dist/cli/synthesise.d.ts.map +1 -0
- package/dist/cli/synthesise.js +55 -0
- package/dist/cli/synthesise.js.map +1 -0
- package/dist/context/branch.d.ts +27 -0
- package/dist/context/branch.d.ts.map +1 -0
- package/dist/context/branch.js +59 -0
- package/dist/context/branch.js.map +1 -0
- package/dist/context/brief.d.ts +27 -0
- package/dist/context/brief.d.ts.map +1 -0
- package/dist/context/brief.js +153 -0
- package/dist/context/brief.js.map +1 -0
- package/dist/context/compile.d.ts.map +1 -1
- package/dist/context/compile.js +19 -7
- package/dist/context/compile.js.map +1 -1
- package/dist/context/file-context.d.ts +27 -0
- package/dist/context/file-context.d.ts.map +1 -0
- package/dist/context/file-context.js +47 -0
- package/dist/context/file-context.js.map +1 -0
- package/dist/context/patterns.d.ts +23 -0
- package/dist/context/patterns.d.ts.map +1 -0
- package/dist/context/patterns.js +50 -0
- package/dist/context/patterns.js.map +1 -0
- package/dist/governor/drift.d.ts +26 -0
- package/dist/governor/drift.d.ts.map +1 -0
- package/dist/governor/drift.js +66 -0
- package/dist/governor/drift.js.map +1 -0
- package/dist/governor/overrides.d.ts +22 -0
- package/dist/governor/overrides.d.ts.map +1 -0
- package/dist/governor/overrides.js +39 -0
- package/dist/governor/overrides.js.map +1 -0
- package/dist/graph/queries.d.ts +33 -0
- package/dist/graph/queries.d.ts.map +1 -0
- package/dist/graph/queries.js +93 -0
- package/dist/graph/queries.js.map +1 -0
- package/dist/graph/relationships.d.ts +55 -0
- package/dist/graph/relationships.d.ts.map +1 -0
- package/dist/graph/relationships.js +176 -0
- package/dist/graph/relationships.js.map +1 -0
- package/dist/ledger/admin.d.ts +49 -0
- package/dist/ledger/admin.d.ts.map +1 -0
- package/dist/ledger/admin.js +121 -0
- package/dist/ledger/admin.js.map +1 -0
- package/dist/ledger/database.d.ts +4 -0
- package/dist/ledger/database.d.ts.map +1 -1
- package/dist/ledger/database.js +145 -3
- package/dist/ledger/database.js.map +1 -1
- package/dist/ledger/migrations.d.ts +15 -0
- package/dist/ledger/migrations.d.ts.map +1 -0
- package/dist/ledger/migrations.js +19 -0
- package/dist/ledger/migrations.js.map +1 -0
- package/dist/ledger/records.d.ts.map +1 -1
- package/dist/ledger/records.js +12 -1
- package/dist/ledger/records.js.map +1 -1
- package/dist/ledger/stats.d.ts +43 -0
- package/dist/ledger/stats.d.ts.map +1 -0
- package/dist/ledger/stats.js +81 -0
- package/dist/ledger/stats.js.map +1 -0
- package/dist/mcp/server.d.ts +3 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +178 -25
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/session-manager.d.ts +45 -0
- package/dist/mcp/session-manager.d.ts.map +1 -0
- package/dist/mcp/session-manager.js +136 -0
- package/dist/mcp/session-manager.js.map +1 -0
- package/dist/monitoring/health.d.ts +29 -0
- package/dist/monitoring/health.d.ts.map +1 -0
- package/dist/monitoring/health.js +112 -0
- package/dist/monitoring/health.js.map +1 -0
- package/dist/relevance/access.d.ts +27 -0
- package/dist/relevance/access.d.ts.map +1 -0
- package/dist/relevance/access.js +63 -0
- package/dist/relevance/access.js.map +1 -0
- package/dist/relevance/profiles.d.ts +15 -0
- package/dist/relevance/profiles.d.ts.map +1 -0
- package/dist/relevance/profiles.js +17 -0
- package/dist/relevance/profiles.js.map +1 -0
- package/dist/relevance/scoring.d.ts +58 -0
- package/dist/relevance/scoring.d.ts.map +1 -0
- package/dist/relevance/scoring.js +76 -0
- package/dist/relevance/scoring.js.map +1 -0
- package/dist/relevance/search.d.ts +26 -0
- package/dist/relevance/search.d.ts.map +1 -0
- package/dist/relevance/search.js +66 -0
- package/dist/relevance/search.js.map +1 -0
- package/dist/synthesis/cache.d.ts +30 -0
- package/dist/synthesis/cache.d.ts.map +1 -0
- package/dist/synthesis/cache.js +64 -0
- package/dist/synthesis/cache.js.map +1 -0
- package/dist/synthesis/patterns.d.ts +24 -0
- package/dist/synthesis/patterns.d.ts.map +1 -0
- package/dist/synthesis/patterns.js +117 -0
- package/dist/synthesis/patterns.js.map +1 -0
- package/dist/synthesis/synthesise.d.ts +31 -0
- package/dist/synthesis/synthesise.d.ts.map +1 -0
- package/dist/synthesis/synthesise.js +84 -0
- package/dist/synthesis/synthesise.js.map +1 -0
- package/dist/types.d.ts +24 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -1
- package/dist/vector/search.d.ts +2 -0
- package/dist/vector/search.d.ts.map +1 -1
- package/dist/vector/search.js +6 -0
- package/dist/vector/search.js.map +1 -1
- package/package.json +7 -2
package/README.md
CHANGED
|
@@ -1,100 +1,170 @@
|
|
|
1
1
|
# memnant
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Shared project memory for any MCP client.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## The problem
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Your AI agent forgets everything between sessions. The Next.js caching gotcha you solved last Tuesday? Gone. The architecture decision from three weeks ago? Not in the context window.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
But the real problem is bigger. Platform memory is locked to one client and one project. Claude Code's memory doesn't work in Cursor. Cursor's memory doesn't work in Windsurf. And none of them carry the framework fix you solved in project A into project B.
|
|
10
|
+
|
|
11
|
+
memnant is locked to nothing. It works across any MCP-compatible agent, any project, any session. Your engineering knowledge compounds everywhere you build.
|
|
12
|
+
|
|
13
|
+
## How it works
|
|
14
|
+
|
|
15
|
+
**It remembers.** The agent silently logs decisions, framework fixes, and rejections during conversation. Every record gets a vector embedding for semantic search. Ask "auth approach" and find the record where you chose JWTs over sessions.
|
|
16
|
+
|
|
17
|
+
**It compiles.** Sessions start and close automatically. At session start, memnant compiles context: last session's log, open TODOs, relevant decisions, framework fixes, staleness warnings. Three weeks away? One command. Full context. Under two minutes.
|
|
18
|
+
|
|
19
|
+
**It flags.** Codebase snapshots track file hashes. When a file changes after a decision was logged about it, that record is flagged `[stale]` everywhere. Every other memory tool serves old decisions as current. memnant tracks validity.
|
|
20
|
+
|
|
21
|
+
**It travels.** Export framework fixes from one project, import them into the next. The gotcha you solved once never bites you again — across any project, any codebase. No platform memory tool can do this because they're siloed by project. Your experience isn't.
|
|
22
|
+
|
|
23
|
+
## Quick start
|
|
10
24
|
|
|
11
25
|
```bash
|
|
12
|
-
cd your-project
|
|
13
26
|
npx memnant
|
|
14
27
|
```
|
|
15
28
|
|
|
16
|
-
|
|
29
|
+
First run creates your config and ledger. After that, it starts a session with compiled context.
|
|
17
30
|
|
|
18
|
-
|
|
31
|
+
Add memnant to your agent's MCP config:
|
|
32
|
+
|
|
33
|
+
```json
|
|
34
|
+
{
|
|
35
|
+
"mcpServers": {
|
|
36
|
+
"memnant": {
|
|
37
|
+
"command": "memnant",
|
|
38
|
+
"args": ["serve"]
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Start building. The agent logs decisions automatically. Start your next session with full context.
|
|
45
|
+
|
|
46
|
+
## What a session looks like
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
$ npx memnant
|
|
19
50
|
|
|
20
|
-
|
|
51
|
+
▪ memnant · session start
|
|
52
|
+
Compiled context: ~4,200 tokens
|
|
21
53
|
|
|
22
|
-
|
|
54
|
+
── Last Session (Feb 21) ──
|
|
55
|
+
Shipped: snapshot-first analytics pipeline
|
|
56
|
+
Decided: materialised views over live aggregation
|
|
57
|
+
TODO: wire dashboard filters to snapshot queries
|
|
23
58
|
|
|
24
|
-
|
|
59
|
+
── Relevant Decisions (3) ──
|
|
60
|
+
[a3f2] Chose snapshot-first analytics — live adds 200ms
|
|
61
|
+
[b7e1] Dashboard uses server components, no client state
|
|
62
|
+
[c4d9] [stale] Analytics schema — analytics.ts changed Feb 24
|
|
25
63
|
|
|
26
|
-
|
|
64
|
+
── Framework Fixes (1) ──
|
|
65
|
+
[d2a8] Next.js 15: useSearchParams needs Suspense boundary
|
|
27
66
|
|
|
28
|
-
|
|
29
|
-
|
|
67
|
+
Session e8f3 started. Good building.
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Fixes that travel
|
|
30
71
|
|
|
31
|
-
|
|
32
|
-
|
|
72
|
+
```bash
|
|
73
|
+
# In project A — you solved a Next.js gotcha
|
|
74
|
+
memnant export --type framework_fix --format portable
|
|
75
|
+
|
|
76
|
+
# In project B — it's already there before you hit it
|
|
77
|
+
memnant import .../framework-fixes.portable.json
|
|
78
|
+
# → Imported 3 framework fixes (1 skipped as duplicate)
|
|
79
|
+
```
|
|
33
80
|
|
|
34
|
-
|
|
35
|
-
Codebase snapshots track file hashes. When a file changes after a decision was logged about it, that record is flagged `[stale]` in recall and session context.
|
|
81
|
+
Framework fixes aren't project-specific. The caching bug you solved in your SaaS app applies to your next Next.js project. `memnant export` strips project-specific fields (embeddings, relationships, staleness). `memnant import` re-generates embeddings locally, deduplicates, and tags imports with their source.
|
|
36
82
|
|
|
37
|
-
|
|
38
|
-
Copy audits catch banned phrases. Design system checks catch banned components. The agent validates via MCP tools. Also runs in CI with `memnant lint`.
|
|
83
|
+
Platform memory is siloed by project. Your experience isn't.
|
|
39
84
|
|
|
40
|
-
|
|
41
|
-
Three tiers: triage (Haiku), analysis (Sonnet), build (Opus). Each gets tier-appropriate context.
|
|
85
|
+
## Under the hood
|
|
42
86
|
|
|
43
|
-
|
|
87
|
+
**Storage.** Single SQLite file at `.memnant/ledger.db`. Copy it to another machine and everything comes with you.
|
|
44
88
|
|
|
45
|
-
|
|
89
|
+
**Search.** Local vector embeddings via all-MiniLM-L6-v2. Semantic search on CPU. No API calls. Works on a plane.
|
|
46
90
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
91
|
+
**Integration.** MCP server over stdio. 10 tools. Plugs into Claude Code, Cursor, or any MCP-compatible agent.
|
|
92
|
+
|
|
93
|
+
**Config.** `memnant.yaml` at your project root. Version-controlled. No dashboard, no account, no login.
|
|
94
|
+
|
|
95
|
+
**Export.** Markdown or JSON. Every record, every decision, every session log. Your history is never locked in.
|
|
96
|
+
|
|
97
|
+
## As your ledger grows
|
|
98
|
+
|
|
99
|
+
The core loop is four things: remember, compile, flag, travel. As records accumulate, memnant has depth that earns its way in.
|
|
100
|
+
|
|
101
|
+
| Capability | What it does | Requires |
|
|
102
|
+
|---|---|---|
|
|
103
|
+
| **Connection Graph** | Records auto-link, supersede, and contradict at write time | Records in the ledger |
|
|
104
|
+
| **Relevance Scoring** | 4-signal composite: similarity, recency, freshness, frequency | Configurable in memnant.yaml |
|
|
105
|
+
| **Synthesis** | Cross-record questions with citations | `ANTHROPIC_API_KEY` |
|
|
106
|
+
| **Spec Governor** | Copy audits, design checks, persona tests, CI lint | Spec docs in `docs/` |
|
|
107
|
+
| **Predictive Context** | File-aware search, branch detection, co-occurrence patterns | Builds over sessions |
|
|
108
|
+
| **Model Routing** | Route tasks to Haiku/Sonnet/Opus with tier-appropriate context | API keys |
|
|
109
|
+
| **Health Monitoring** | Staleness rate, contradictions, spec drift, status levels | — |
|
|
110
|
+
| **Continuous Governance** | Pre-commit hooks, override tracking, governance feedback | Spec docs + git hooks |
|
|
111
|
+
| **Telegram** | Triage from your phone | `MEMRANT_TELEGRAM_TOKEN` |
|
|
112
|
+
|
|
113
|
+
Every capability is independent. Use what you need. Ignore the rest.
|
|
114
|
+
|
|
115
|
+
## Core commands
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
npx memnant # auto-detect: init, start session, or status
|
|
119
|
+
memnant log --type decision # write a record
|
|
120
|
+
memnant recall "auth approach" # semantic search
|
|
121
|
+
memnant session start # compile context
|
|
122
|
+
memnant session close # capture what happened
|
|
123
|
+
memnant snapshot # codebase snapshot for staleness
|
|
124
|
+
memnant export # full ledger to markdown/JSON
|
|
125
|
+
memnant lint # validate against spec docs
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
25 commands total. Full reference in the [docs](docs/).
|
|
129
|
+
|
|
130
|
+
## MCP tools
|
|
131
|
+
|
|
132
|
+
| Tool | Purpose |
|
|
133
|
+
|---|---|
|
|
134
|
+
| `memnant_recall` | Semantic search over the ledger |
|
|
135
|
+
| `memnant_log` | Write a record (auto-starts session) |
|
|
136
|
+
| `memnant_session_context` | Compiled context for session start |
|
|
137
|
+
| `memnant_session_close` | Close session with summary |
|
|
53
138
|
| `memnant_status` | Project status |
|
|
54
139
|
| `memnant_check_copy` | Copy audit against spec |
|
|
55
140
|
| `memnant_check_design` | Design system validation |
|
|
141
|
+
| `memnant_synthesise` | Cross-record questions with citations |
|
|
142
|
+
| `memnant_context_for_file` | Records relevant to a specific file |
|
|
143
|
+
| `memnant_project_brief` | Dynamic 500-token project summary |
|
|
56
144
|
|
|
57
|
-
|
|
145
|
+
## What it's not
|
|
58
146
|
|
|
59
|
-
|
|
147
|
+
**Not agent memory.** Agent memory stores preferences from conversations. memnant stores typed decisions with staleness tracking. It's a ledger, not a scratchpad.
|
|
60
148
|
|
|
61
|
-
|
|
149
|
+
**Not a context window.** Context windows are session-scoped. memnant is cross-session. It selects the right subset and injects it.
|
|
62
150
|
|
|
63
|
-
|
|
64
|
-
memnant init memnant session start memnant check-copy
|
|
65
|
-
memnant setup claude-code memnant session close memnant check-design
|
|
66
|
-
memnant setup codex memnant session status memnant test-persona
|
|
67
|
-
memnant log memnant snapshot memnant lint
|
|
68
|
-
memnant recall memnant export memnant serve
|
|
69
|
-
memnant ask memnant specs memnant instructions
|
|
70
|
-
```
|
|
151
|
+
**Not CLAUDE.md.** Static instructions tell agents how to behave. memnant is dynamic institutional knowledge — what was decided, when, why, and whether it's still valid.
|
|
71
152
|
|
|
72
|
-
|
|
153
|
+
**Not chat history.** Chat history is what was said. memnant is what was decided.
|
|
73
154
|
|
|
74
|
-
|
|
75
|
-
- SQLite via node-sqlite3-wasm
|
|
76
|
-
- Local vector embeddings via @xenova/transformers (all-MiniLM-L6-v2)
|
|
77
|
-
- CLI via Commander.js
|
|
78
|
-
- MCP server via @modelcontextprotocol/sdk
|
|
79
|
-
- 192 tests via vitest
|
|
155
|
+
## Who it's for
|
|
80
156
|
|
|
81
|
-
|
|
157
|
+
Solo builders shipping multiple products with AI agents. You work in sessions — days or weeks apart. You juggle 3-4 projects. You already have agents doing the work. You need your engineering knowledge to compound across everything you build, not reset every time you switch projects.
|
|
82
158
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
npm test
|
|
89
|
-
```
|
|
159
|
+
The test: three weeks away from a project, `npx memnant` gives full context in under two minutes. Switch to a new project, `memnant import` brings your framework fixes with you.
|
|
160
|
+
|
|
161
|
+
## Dependencies
|
|
162
|
+
|
|
163
|
+
**Required:** Node.js >= 20
|
|
90
164
|
|
|
91
|
-
|
|
165
|
+
**Bundled:** SQLite (WASM, no native deps), local embeddings, MCP SDK
|
|
92
166
|
|
|
93
|
-
|
|
94
|
-
- [`docs/SPEC.md`](docs/SPEC.md) — Data model and system behaviours
|
|
95
|
-
- [`docs/PLAN.md`](docs/PLAN.md) — Build plan with epics, stories, and acceptance criteria
|
|
96
|
-
- [`docs/PROJECT_INSTRUCTIONS.md`](docs/PROJECT_INSTRUCTIONS.md) — Decision framework
|
|
97
|
-
- [`docs/PERSONA_KAI.md`](docs/PERSONA_KAI.md) — Primary persona
|
|
167
|
+
**Optional:** `ANTHROPIC_API_KEY` for synthesis and routing. `MEMRANT_TELEGRAM_TOKEN` for Telegram. Core functionality — ledger, sessions, recall, staleness, export, lint — works fully offline with no API keys.
|
|
98
168
|
|
|
99
169
|
## License
|
|
100
170
|
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* memnant archive / unarchive — Archive old or superseded records.
|
|
3
|
+
*
|
|
4
|
+
* Archived records are excluded from recall, context compilation, and export.
|
|
5
|
+
* They are not deleted — they can be unarchived later.
|
|
6
|
+
*/
|
|
7
|
+
import { Command } from 'commander';
|
|
8
|
+
export declare function registerArchiveCommand(program: Command): void;
|
|
9
|
+
//# sourceMappingURL=archive.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"archive.d.ts","sourceRoot":"","sources":["../../src/cli/archive.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA2CpC,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAgE7D"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* memnant archive / unarchive — Archive old or superseded records.
|
|
3
|
+
*
|
|
4
|
+
* Archived records are excluded from recall, context compilation, and export.
|
|
5
|
+
* They are not deleted — they can be unarchived later.
|
|
6
|
+
*/
|
|
7
|
+
import { existsSync, readFileSync } from 'fs';
|
|
8
|
+
import { join } from 'path';
|
|
9
|
+
import yaml from 'js-yaml';
|
|
10
|
+
import { openDatabase } from '../ledger/database.js';
|
|
11
|
+
import { archiveRecord, unarchiveRecord, unarchiveAll, archiveSuperseded, archiveStaleOlderThan, } from '../ledger/admin.js';
|
|
12
|
+
function loadDb() {
|
|
13
|
+
const cwd = process.cwd();
|
|
14
|
+
const configPath = join(cwd, 'memnant.yaml');
|
|
15
|
+
if (!existsSync(configPath)) {
|
|
16
|
+
console.error('No memnant project found. Run `memnant init` first.');
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
const config = yaml.load(readFileSync(configPath, 'utf-8'));
|
|
20
|
+
const dbPath = join(cwd, config.memory.db_path);
|
|
21
|
+
if (!existsSync(dbPath)) {
|
|
22
|
+
console.error(`Ledger database not found at ${config.memory.db_path}. Run \`memnant init\` to recreate.`);
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
return openDatabase(dbPath);
|
|
26
|
+
}
|
|
27
|
+
function parseDuration(duration) {
|
|
28
|
+
const match = duration.match(/^(\d+)d$/);
|
|
29
|
+
if (!match) {
|
|
30
|
+
console.error(`Invalid duration '${duration}'. Expected format: <number>d (e.g. 90d for 90 days).`);
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
return parseInt(match[1], 10);
|
|
34
|
+
}
|
|
35
|
+
export function registerArchiveCommand(program) {
|
|
36
|
+
program
|
|
37
|
+
.command('archive')
|
|
38
|
+
.description('Archive old or superseded records')
|
|
39
|
+
.option('--id <id>', 'Archive a single record')
|
|
40
|
+
.option('--superseded', 'Archive all superseded records')
|
|
41
|
+
.option('--stale-older-than <duration>', 'Archive stale records older than duration (e.g. 90d)')
|
|
42
|
+
.action((opts) => {
|
|
43
|
+
if (!opts.id && !opts.superseded && !opts.staleOlderThan) {
|
|
44
|
+
console.error('Specify at least one: --id <id>, --superseded, or --stale-older-than <duration>');
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
const db = loadDb();
|
|
48
|
+
try {
|
|
49
|
+
if (opts.id) {
|
|
50
|
+
archiveRecord(db, opts.id);
|
|
51
|
+
console.log(`Archived record ${opts.id.slice(0, 8)}.`);
|
|
52
|
+
}
|
|
53
|
+
if (opts.superseded) {
|
|
54
|
+
const count = archiveSuperseded(db);
|
|
55
|
+
console.log(`Archived ${count} superseded record(s).`);
|
|
56
|
+
}
|
|
57
|
+
if (opts.staleOlderThan) {
|
|
58
|
+
const days = parseDuration(opts.staleOlderThan);
|
|
59
|
+
const count = archiveStaleOlderThan(db, days);
|
|
60
|
+
console.log(`Archived ${count} stale record(s) older than ${days} days.`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
catch (err) {
|
|
64
|
+
console.error(err.message);
|
|
65
|
+
process.exit(1);
|
|
66
|
+
}
|
|
67
|
+
finally {
|
|
68
|
+
db.close();
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
program
|
|
72
|
+
.command('unarchive')
|
|
73
|
+
.description('Restore archived records')
|
|
74
|
+
.option('--id <id>', 'Unarchive a single record')
|
|
75
|
+
.option('--all', 'Unarchive all archived records')
|
|
76
|
+
.action((opts) => {
|
|
77
|
+
if (!opts.id && !opts.all) {
|
|
78
|
+
console.error('Specify at least one: --id <id> or --all');
|
|
79
|
+
process.exit(1);
|
|
80
|
+
}
|
|
81
|
+
const db = loadDb();
|
|
82
|
+
try {
|
|
83
|
+
if (opts.id) {
|
|
84
|
+
unarchiveRecord(db, opts.id);
|
|
85
|
+
console.log(`Unarchived record ${opts.id.slice(0, 8)}. It will appear in queries again.`);
|
|
86
|
+
}
|
|
87
|
+
if (opts.all) {
|
|
88
|
+
const count = unarchiveAll(db);
|
|
89
|
+
console.log(`Unarchived ${count} record(s).`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
catch (err) {
|
|
93
|
+
console.error(err.message);
|
|
94
|
+
process.exit(1);
|
|
95
|
+
}
|
|
96
|
+
finally {
|
|
97
|
+
db.close();
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=archive.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"archive.js","sourceRoot":"","sources":["../../src/cli/archive.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/export.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"export.d.ts","sourceRoot":"","sources":["../../src/cli/export.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"export.d.ts","sourceRoot":"","sources":["../../src/cli/export.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA4BpC,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAsF5D"}
|
package/dist/cli/export.js
CHANGED
|
@@ -9,6 +9,7 @@ import { existsSync, readFileSync, mkdirSync, writeFileSync, rmSync } from 'fs';
|
|
|
9
9
|
import { join } from 'path';
|
|
10
10
|
import yaml from 'js-yaml';
|
|
11
11
|
import { openDatabase } from '../ledger/database.js';
|
|
12
|
+
import { RECORD_TYPES } from '../types.js';
|
|
12
13
|
const TYPE_SUBDIRS = {
|
|
13
14
|
decision: 'decisions',
|
|
14
15
|
session_log: 'session_logs',
|
|
@@ -16,17 +17,25 @@ const TYPE_SUBDIRS = {
|
|
|
16
17
|
spec_snapshot: 'spec_snapshots',
|
|
17
18
|
codebase_snapshot: 'codebase_snapshots',
|
|
18
19
|
orchestrator_task: 'orchestrator_tasks',
|
|
20
|
+
synthesis_cache: 'synthesis_cache',
|
|
21
|
+
governance_override: 'governance_overrides',
|
|
19
22
|
};
|
|
20
23
|
export function registerExportCommand(program) {
|
|
21
24
|
program
|
|
22
25
|
.command('export')
|
|
23
26
|
.description('Export the ledger to markdown or JSON')
|
|
24
|
-
.option('--format <format>', 'Export format: markdown or
|
|
27
|
+
.option('--format <format>', 'Export format: markdown, json, portable, or notebooklm', 'markdown')
|
|
25
28
|
.option('--since <date>', 'Export only records after YYYY-MM-DD')
|
|
29
|
+
.option('--type <type>', 'Export only records of this type')
|
|
26
30
|
.action((opts) => {
|
|
27
31
|
// Validate --format
|
|
28
|
-
if (
|
|
29
|
-
console.error(`Unknown export format '${opts.format}'. Valid formats: markdown, json`);
|
|
32
|
+
if (!['markdown', 'json', 'portable', 'notebooklm'].includes(opts.format)) {
|
|
33
|
+
console.error(`Unknown export format '${opts.format}'. Valid formats: markdown, json, portable, notebooklm`);
|
|
34
|
+
process.exit(1);
|
|
35
|
+
}
|
|
36
|
+
// Validate --type
|
|
37
|
+
if (opts.type && !RECORD_TYPES.includes(opts.type)) {
|
|
38
|
+
console.error(`Unknown record type '${opts.type}'. Valid types: ${RECORD_TYPES.join(', ')}`);
|
|
30
39
|
process.exit(1);
|
|
31
40
|
}
|
|
32
41
|
// Validate --since
|
|
@@ -48,18 +57,28 @@ export function registerExportCommand(program) {
|
|
|
48
57
|
process.exit(1);
|
|
49
58
|
}
|
|
50
59
|
const db = openDatabase(dbPath);
|
|
51
|
-
// Query records
|
|
52
|
-
let query = 'SELECT id, type, content_text, tags, related_records, created_at FROM record';
|
|
60
|
+
// Query records (exclude retracted and archived)
|
|
61
|
+
let query = 'SELECT id, type, content_text, tags, related_records, created_at FROM record WHERE retracted_at IS NULL AND archived_at IS NULL';
|
|
53
62
|
const params = [];
|
|
54
63
|
if (opts.since) {
|
|
55
|
-
query += '
|
|
64
|
+
query += ' AND created_at >= ?';
|
|
56
65
|
params.push(opts.since + 'T00:00:00.000Z');
|
|
57
66
|
}
|
|
67
|
+
if (opts.type) {
|
|
68
|
+
query += ' AND type = ?';
|
|
69
|
+
params.push(opts.type);
|
|
70
|
+
}
|
|
58
71
|
query += ' ORDER BY created_at ASC';
|
|
59
72
|
const records = db.all(query, params);
|
|
60
73
|
db.close();
|
|
61
74
|
const exportPath = join(cwd, config.memory.export_path);
|
|
62
|
-
if (opts.format === '
|
|
75
|
+
if (opts.format === 'notebooklm') {
|
|
76
|
+
exportNotebookLM(records, exportPath, config.project.name);
|
|
77
|
+
}
|
|
78
|
+
else if (opts.format === 'portable') {
|
|
79
|
+
exportPortable(records, exportPath, config.project.name);
|
|
80
|
+
}
|
|
81
|
+
else if (opts.format === 'json') {
|
|
63
82
|
exportJson(records, exportPath);
|
|
64
83
|
}
|
|
65
84
|
else {
|
|
@@ -93,6 +112,68 @@ function exportMarkdown(records, exportPath) {
|
|
|
93
112
|
writeFileSync(join(exportPath, subdir, filename), content);
|
|
94
113
|
}
|
|
95
114
|
}
|
|
115
|
+
function exportPortable(records, exportPath, projectName) {
|
|
116
|
+
mkdirSync(exportPath, { recursive: true });
|
|
117
|
+
const portablePath = join(exportPath, 'framework-fixes.portable.json');
|
|
118
|
+
const data = {
|
|
119
|
+
memnant_version: '0.1.0',
|
|
120
|
+
source_project: projectName,
|
|
121
|
+
exported_at: new Date().toISOString(),
|
|
122
|
+
record_count: records.length,
|
|
123
|
+
records: records.map((r) => ({
|
|
124
|
+
type: r.type,
|
|
125
|
+
content_text: r.content_text,
|
|
126
|
+
tags: JSON.parse(r.tags),
|
|
127
|
+
original_id: r.id,
|
|
128
|
+
created_at: r.created_at,
|
|
129
|
+
})),
|
|
130
|
+
};
|
|
131
|
+
writeFileSync(portablePath, JSON.stringify(data, null, 2) + '\n');
|
|
132
|
+
}
|
|
133
|
+
const TYPE_LABELS_PLURAL = {
|
|
134
|
+
decision: 'Decisions',
|
|
135
|
+
session_log: 'Session Logs',
|
|
136
|
+
framework_fix: 'Framework Fixes',
|
|
137
|
+
spec_snapshot: 'Spec Snapshots',
|
|
138
|
+
codebase_snapshot: 'Codebase Snapshots',
|
|
139
|
+
orchestrator_task: 'Orchestrator Tasks',
|
|
140
|
+
synthesis_cache: 'Synthesis Cache',
|
|
141
|
+
governance_override: 'Governance Overrides',
|
|
142
|
+
};
|
|
143
|
+
function exportNotebookLM(records, exportPath, projectName) {
|
|
144
|
+
mkdirSync(exportPath, { recursive: true });
|
|
145
|
+
const filePath = join(exportPath, 'notebooklm.md');
|
|
146
|
+
const lines = [];
|
|
147
|
+
lines.push(`# ${projectName} — Project Knowledge Ledger`);
|
|
148
|
+
lines.push('');
|
|
149
|
+
lines.push(`Exported from memnant on ${new Date().toISOString().slice(0, 10)}. ${records.length} records.`);
|
|
150
|
+
lines.push('');
|
|
151
|
+
lines.push('---');
|
|
152
|
+
lines.push('');
|
|
153
|
+
// Group by type
|
|
154
|
+
const byType = new Map();
|
|
155
|
+
for (const r of records) {
|
|
156
|
+
const group = byType.get(r.type) || [];
|
|
157
|
+
group.push(r);
|
|
158
|
+
byType.set(r.type, group);
|
|
159
|
+
}
|
|
160
|
+
for (const [type, group] of byType) {
|
|
161
|
+
lines.push(`## ${TYPE_LABELS_PLURAL[type]} (${group.length})`);
|
|
162
|
+
lines.push('');
|
|
163
|
+
for (const r of group) {
|
|
164
|
+
const date = r.created_at.slice(0, 10);
|
|
165
|
+
const tags = JSON.parse(r.tags);
|
|
166
|
+
const tagStr = tags.length > 0 ? ` [${tags.join(', ')}]` : '';
|
|
167
|
+
lines.push(`### ${date} — ${r.id.slice(0, 8)}${tagStr}`);
|
|
168
|
+
lines.push('');
|
|
169
|
+
lines.push(r.content_text);
|
|
170
|
+
lines.push('');
|
|
171
|
+
lines.push('---');
|
|
172
|
+
lines.push('');
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
writeFileSync(filePath, lines.join('\n'));
|
|
176
|
+
}
|
|
96
177
|
function exportJson(records, exportPath) {
|
|
97
178
|
mkdirSync(exportPath, { recursive: true });
|
|
98
179
|
const jsonPath = join(exportPath, 'export.json');
|
package/dist/cli/export.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"export.js","sourceRoot":"","sources":["../../src/cli/export.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,IAAI,CAAC;AAChF,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,IAAI,MAAM,SAAS,CAAC;AAC3B,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"export.js","sourceRoot":"","sources":["../../src/cli/export.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* memnant graph — Connection graph visualization and management.
|
|
3
|
+
*
|
|
4
|
+
* Story 9.4: Text-based graph, with --json, --type, --contradictions options.
|
|
5
|
+
* Also: unsupersede and dismiss-contradiction commands.
|
|
6
|
+
*/
|
|
7
|
+
import { Command } from 'commander';
|
|
8
|
+
export declare function registerGraphCommand(program: Command): void;
|
|
9
|
+
//# sourceMappingURL=graph.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph.d.ts","sourceRoot":"","sources":["../../src/cli/graph.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AASpC,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAsG3D"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* memnant graph — Connection graph visualization and management.
|
|
3
|
+
*
|
|
4
|
+
* Story 9.4: Text-based graph, with --json, --type, --contradictions options.
|
|
5
|
+
* Also: unsupersede and dismiss-contradiction commands.
|
|
6
|
+
*/
|
|
7
|
+
import { existsSync, readFileSync } from 'fs';
|
|
8
|
+
import { join } from 'path';
|
|
9
|
+
import yaml from 'js-yaml';
|
|
10
|
+
import { openDatabase } from '../ledger/database.js';
|
|
11
|
+
import { buildGraph, formatGraphAsText } from '../graph/queries.js';
|
|
12
|
+
import { unsupersede, dismissContradiction } from '../graph/relationships.js';
|
|
13
|
+
export function registerGraphCommand(program) {
|
|
14
|
+
program
|
|
15
|
+
.command('graph')
|
|
16
|
+
.description('Show the connection graph between records')
|
|
17
|
+
.argument('[record-id]', 'Show connections for a specific record')
|
|
18
|
+
.option('--json', 'Output as JSON')
|
|
19
|
+
.option('--type <type>', 'Filter by record type')
|
|
20
|
+
.option('--contradictions', 'Show only unresolved contradictions')
|
|
21
|
+
.action((recordId, opts) => {
|
|
22
|
+
const cwd = process.cwd();
|
|
23
|
+
const configPath = join(cwd, 'memnant.yaml');
|
|
24
|
+
if (!existsSync(configPath)) {
|
|
25
|
+
console.error('No memnant project found. Run `memnant init` first.');
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
|
+
const config = yaml.load(readFileSync(configPath, 'utf-8'));
|
|
29
|
+
const dbPath = join(cwd, config.memory.db_path);
|
|
30
|
+
if (!existsSync(dbPath)) {
|
|
31
|
+
console.error(`Ledger database not found at ${config.memory.db_path}. Run \`memnant init\` to recreate.`);
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
const db = openDatabase(dbPath);
|
|
35
|
+
try {
|
|
36
|
+
const nodes = buildGraph(db, {
|
|
37
|
+
recordId,
|
|
38
|
+
type: opts.type,
|
|
39
|
+
contradictionsOnly: opts.contradictions,
|
|
40
|
+
});
|
|
41
|
+
if (opts.json) {
|
|
42
|
+
console.log(JSON.stringify(nodes, null, 2));
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
console.log(formatGraphAsText(nodes));
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
finally {
|
|
49
|
+
db.close();
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
program
|
|
53
|
+
.command('unsupersede')
|
|
54
|
+
.description('Remove a supersession relationship for a record')
|
|
55
|
+
.argument('<record-id>', 'Record ID to unsupersede')
|
|
56
|
+
.action((recordId) => {
|
|
57
|
+
const cwd = process.cwd();
|
|
58
|
+
const configPath = join(cwd, 'memnant.yaml');
|
|
59
|
+
if (!existsSync(configPath)) {
|
|
60
|
+
console.error('No memnant project found. Run `memnant init` first.');
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
const config = yaml.load(readFileSync(configPath, 'utf-8'));
|
|
64
|
+
const dbPath = join(cwd, config.memory.db_path);
|
|
65
|
+
const db = openDatabase(dbPath);
|
|
66
|
+
try {
|
|
67
|
+
const removed = unsupersede(db, recordId);
|
|
68
|
+
if (removed) {
|
|
69
|
+
console.log(`Removed supersession relationship for record ${recordId.slice(0, 8)}.`);
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
console.log(`No supersession relationship found for record ${recordId.slice(0, 8)}.`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
finally {
|
|
76
|
+
db.close();
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
program
|
|
80
|
+
.command('dismiss-contradiction')
|
|
81
|
+
.description('Dismiss a contradiction between two records')
|
|
82
|
+
.argument('<id1>', 'First record ID')
|
|
83
|
+
.argument('<id2>', 'Second record ID')
|
|
84
|
+
.action((id1, id2) => {
|
|
85
|
+
const cwd = process.cwd();
|
|
86
|
+
const configPath = join(cwd, 'memnant.yaml');
|
|
87
|
+
if (!existsSync(configPath)) {
|
|
88
|
+
console.error('No memnant project found. Run `memnant init` first.');
|
|
89
|
+
process.exit(1);
|
|
90
|
+
}
|
|
91
|
+
const config = yaml.load(readFileSync(configPath, 'utf-8'));
|
|
92
|
+
const dbPath = join(cwd, config.memory.db_path);
|
|
93
|
+
const db = openDatabase(dbPath);
|
|
94
|
+
try {
|
|
95
|
+
const dismissed = dismissContradiction(db, id1, id2);
|
|
96
|
+
if (dismissed) {
|
|
97
|
+
console.log(`Dismissed contradiction between ${id1.slice(0, 8)} and ${id2.slice(0, 8)}.`);
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
console.log(`No active contradiction found between ${id1.slice(0, 8)} and ${id2.slice(0, 8)}.`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
finally {
|
|
104
|
+
db.close();
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=graph.js.map
|