@ddtcorex/dsh-maestro-memory 1.0.1 → 1.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.
- package/CHANGELOG.md +17 -0
- package/README.md +39 -397
- package/lib/auto-memory.d.ts +21 -0
- package/lib/auto-memory.d.ts.map +1 -0
- package/lib/auto-memory.js +105 -0
- package/lib/auto-memory.js.map +1 -0
- package/lib/client.js +57 -2
- package/lib/health-score.d.ts +23 -0
- package/lib/health-score.d.ts.map +1 -0
- package/lib/health-score.js +28 -0
- package/lib/health-score.js.map +1 -0
- package/lib/index.d.ts +4 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +123 -0
- package/lib/index.js.map +1 -1
- package/lib/memory/sanitize.d.ts +25 -0
- package/lib/memory/sanitize.d.ts.map +1 -0
- package/lib/memory/sanitize.js +44 -0
- package/lib/memory/sanitize.js.map +1 -0
- package/lib/memory/store.d.ts +4 -1
- package/lib/memory/store.d.ts.map +1 -1
- package/lib/memory/store.js +73 -11
- package/lib/memory/store.js.map +1 -1
- package/lib/prompt/snapshot.d.ts +6 -3
- package/lib/prompt/snapshot.d.ts.map +1 -1
- package/lib/prompt/snapshot.js +42 -5
- package/lib/prompt/snapshot.js.map +1 -1
- package/lib/skills-browser.d.ts.map +1 -1
- package/lib/skills-browser.js +4 -2
- package/lib/skills-browser.js.map +1 -1
- package/lib/storage/layout.d.ts +3 -0
- package/lib/storage/layout.d.ts.map +1 -1
- package/lib/storage/layout.js +11 -0
- package/lib/storage/layout.js.map +1 -1
- package/lib/types/client/index.d.ts.map +1 -1
- package/package.json +2 -1
- package/src/client/index.tsx +87 -3
- package/src/host/auto-memory.ts +97 -0
- package/src/host/health-score.ts +47 -0
- package/src/host/index.ts +111 -1
- package/src/host/memory/sanitize.ts +43 -0
- package/src/host/memory/store.ts +64 -10
- package/src/host/prompt/snapshot.ts +38 -5
- package/src/host/skills-browser.ts +5 -3
- package/src/host/storage/layout.ts +10 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,23 @@ All notable changes to this project are documented in this file. Format follows
|
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/); this project uses
|
|
5
5
|
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [1.1.0] - 2026-08-29
|
|
8
|
+
|
|
9
|
+
Adopts proven mechanisms from `FuRongJun-1999/dsh-memory` in file-native form (no Python). Live-validated in chat, 268 tests.
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- **Desensitize sanitizer** (`src/host/memory/sanitize.ts`, 7 patterns: `sk-`, `api_key`, `password`, `Bearer`, `ID`, `phone` with English `[Filtered:...]`; pure-credential → `content filtered`).
|
|
14
|
+
- **Opt-in auto-memory hook** (`src/host/auto-memory.ts`, `config.autoMemory`, `session/event` → project/daily, desensitize + dedupe, default `enabled:false`).
|
|
15
|
+
- **Snapshot auto-recall top-4** (`src/host/prompt/snapshot.ts`, new `Project Context` section, newest 4 project entries 600 chars each, cap `autoRecall:1024`, keeps `recentDaily:512`).
|
|
16
|
+
- **Concurrency + abort gating** (`READ_ACTIONS`, `isMemoryConcurrencySafe`, `isConcurrencySafe` for `memory`/`dtodo`/`memory_suggest` + `signal.aborted` checks).
|
|
17
|
+
- **Health 5-dim scoring** (`src/host/health-score.ts`, `S/R/J/C/Safety` 0-10, `composite = min*0.4+mean*0.6`, client `HealthView` 5 cards).
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- `store.add` desensitizes by default (`{desensitize:false}` to opt-out for tests).
|
|
22
|
+
- Snapshot caps now `2K/4K/6K+0.5K+1K` (autoRecall) with bounded `Project Context`.
|
|
23
|
+
|
|
7
24
|
## [1.0.1] - 2026-08-25
|
|
8
25
|
|
|
9
26
|
Fix a live gap in the `memory` tool: the `daily` track only honored an explicit
|
package/README.md
CHANGED
|
@@ -1,448 +1,90 @@
|
|
|
1
1
|
# dsh-maestro-memory
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Durable memory and todos for DeepSeek Harness (DSH) — preserves `~/.dsh/memories` in place.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
> **One sentence:** Give the AI in DSH cross-session durable memory and todos — the more you use it, the more it understands you, and switching sessions never loses context.
|
|
5
|
+
> Give the AI cross-session durable memory and todos — the more you use it, the more it understands you.
|
|
8
6
|
|
|
9
7
|
- **Package:** `@ddtcorex/dsh-maestro-memory` (`cordis.patch.yml` id `maestro-memory`)
|
|
10
|
-
- **Changelog:** `CHANGELOG.md`
|
|
11
|
-
- **Version:** `1.0.1`
|
|
12
|
-
|
|
13
|
-
---
|
|
8
|
+
- **Version:** `1.1.0` · **Changelog:** `CHANGELOG.md`
|
|
14
9
|
|
|
15
10
|
## Requirements
|
|
16
11
|
|
|
17
12
|
- Node.js 22+, pnpm 11+
|
|
18
|
-
- DSH `deepseek-harness` master
|
|
19
|
-
- Existing `~/.dsh/memories` directory (created lazily if absent)
|
|
20
|
-
|
|
21
|
-
---
|
|
13
|
+
- DSH `deepseek-harness` master
|
|
22
14
|
|
|
23
15
|
## Install
|
|
24
16
|
|
|
25
|
-
From the checked-out repo:
|
|
26
|
-
|
|
27
|
-
```sh
|
|
28
|
-
pnpm install # install deps (frozen lockfile in CI)
|
|
29
|
-
pnpm run build # tsc host + tsc client + build-client.mjs -> lib/
|
|
30
|
-
pnpm run verify # tsc --noEmit host + client (typecheck)
|
|
31
|
-
pnpm test # full Vitest suite (13 files, 199 tests)
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
Manual verification of the client bundle:
|
|
35
|
-
|
|
36
17
|
```sh
|
|
37
|
-
|
|
38
|
-
|
|
18
|
+
pnpm install
|
|
19
|
+
pnpm run build # -> lib/
|
|
20
|
+
pnpm test # 268 tests
|
|
39
21
|
```
|
|
40
22
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
The package is consumed as a DSH plugin via `cordis.patch.yml`. Two install paths:
|
|
44
|
-
|
|
45
|
-
**Local link (development / recommended for cutover rehearsal):**
|
|
23
|
+
**DSH profile (operator):**
|
|
46
24
|
|
|
47
25
|
```sh
|
|
48
|
-
# inside the profile that will own the plugin:
|
|
49
26
|
dsh plugin --profile web add link:<workspace-root>/packages/dsh-maestro-memory
|
|
50
|
-
#
|
|
51
|
-
# "@ddtcorex/dsh-maestro-memory": "link:<workspace-root>/packages/dsh-maestro-memory"
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
**Git / registry (production after release):**
|
|
55
|
-
|
|
56
|
-
```sh
|
|
57
|
-
dsh plugin --profile web add github:ddtcorex/dsh-maestro-memory#<tag-or-sha>
|
|
58
|
-
# pin to an exact commit SHA; branch names reuse stale tarballs (pnpm cache pitfall)
|
|
27
|
+
# production: dsh plugin --profile web add github:ddtcorex/dsh-maestro-memory#<tag-or-sha>
|
|
59
28
|
```
|
|
60
29
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
---
|
|
64
|
-
|
|
65
|
-
## Profile Patch
|
|
66
|
-
|
|
67
|
-
`cordis.patch.yml` is **owned by the package** and applied automatically by `dsh plugin add`. Do not duplicate it in the profile.
|
|
30
|
+
`cordis.patch.yml` is shipped with the package — do not duplicate it in the profile.
|
|
68
31
|
|
|
69
32
|
```yaml
|
|
70
|
-
# dsh-maestro-memory/cordis.patch.yml (shipped with the package)
|
|
71
33
|
- insert:
|
|
72
34
|
- id: maestro-memory
|
|
73
35
|
name: '@ddtcorex/dsh-maestro-memory'
|
|
74
36
|
config:
|
|
75
|
-
memoryDir: null
|
|
76
|
-
snapshotOrder: 500
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
Profile `~/.dsh/profiles/web/package.json` after a correct install:
|
|
80
|
-
|
|
81
|
-
```json
|
|
82
|
-
{
|
|
83
|
-
"dsh": { "profile": { "bundles": ["@ddtcorex/dsh-maestro-memory"] } },
|
|
84
|
-
"dependencies": {
|
|
85
|
-
"@ddtcorex/dsh-maestro-memory": "link:<workspace-root>/packages/dsh-maestro-memory"
|
|
86
|
-
}
|
|
87
|
-
}
|
|
37
|
+
memoryDir: null # -> ~/.dsh/memories
|
|
38
|
+
snapshotOrder: 500
|
|
39
|
+
autoMemory: { enabled: false, userMessage: true, desensitize: true } # opt-in
|
|
88
40
|
```
|
|
89
41
|
|
|
90
|
-
|
|
42
|
+
## Tools
|
|
91
43
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
44
|
+
| Tool | Purpose |
|
|
45
|
+
|------|---------|
|
|
46
|
+
| `memory` | Five tracks `memory`/`user`/`project`/`key`/`daily` + archive/expand. `key` is gated via `memory_suggest`. |
|
|
47
|
+
| `dtodo` | Four tracks `life`/`work`/`project`/`daily` with ids, smart view (max 8). |
|
|
48
|
+
| `memory_suggest` | Gated proposals to `SUGGESTIONS.jsonl` — requires human approve. |
|
|
95
49
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
```ts
|
|
99
|
-
import { createFixtureProfile, assertSingleOwner } from '@ddtcorex/dsh-maestro-memory/migration/fixture'
|
|
100
|
-
await createFixtureProfile({ profileDir: '/tmp/profile', packageDir: '/path/to/dsh-maestro-memory' })
|
|
101
|
-
const res = await assertSingleOwner('/tmp/profile')
|
|
102
|
-
console.assert(res.ok && res.owners['memory'] === '@ddtcorex/dsh-maestro-memory')
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
---
|
|
106
|
-
|
|
107
|
-
## Supported Tools
|
|
108
|
-
|
|
109
|
-
All tools are registered via `ctx.tools.register` inside `ctx.effect(..., 'label')` so they dispose cleanly on unload. No HTTP.
|
|
110
|
-
|
|
111
|
-
| Tool | Purpose | When visible |
|
|
112
|
-
|------|---------|--------------|
|
|
113
|
-
| `memory` | CRUD + query for five tracks (`memory`/`user`/`project`/`key`/`daily`) + archive/expand. See `src/host/memory/store.ts`. | Always |
|
|
114
|
-
| `dtodo` | Four-track todos (`life`/`work`/`project`/`daily`) with stable 8-hex ids, status/due/quadrant, smart view (max 8), historical daily lookup. | Always |
|
|
115
|
-
| `memory_suggest` | **Gated** — model proposes `memory`/`user`/`key`/`todo-*` into `SUGGESTIONS.jsonl`; never writes directly. Requires human approve/edit/reject via Review UI or `queue.decide` RPC. | Always |
|
|
116
|
-
| `memory_review_status` | Read-only queue depth / write-block status (used by prompt hint / UI badge). | Always |
|
|
117
|
-
| `skill_manage` | Browse / mutate `~/.agents/skills` (optional module). Disabled by default; enable only if the optional skills module is explicitly configured. | Opt-in |
|
|
118
|
-
|
|
119
|
-
### `memory` — actions and targets
|
|
120
|
-
|
|
121
|
-
```ts
|
|
122
|
-
memory({
|
|
123
|
-
action: 'add'|'list'|'replace'|'remove'|'archive'|'expand',
|
|
124
|
-
target: 'memory'|'user'|'project'|'key'|'daily', // memory=global, key=per-cwd long-term
|
|
125
|
-
content?: string, // add: entry body; replace: new body
|
|
126
|
-
match?: string, // replace/remove/archive: unique substring of existing entry
|
|
127
|
-
filter?: string, // list: content substring filter
|
|
128
|
-
since?: string, until?: string, // list: YYYY-MM-DD
|
|
129
|
-
limit?: number, recent?: boolean, branch?: string, archived?: boolean,
|
|
130
|
-
branches?: string, // add key: csv "main,dev" (empty=all), branch scope
|
|
131
|
-
summary?: string, // add key: one-line summary for progressive disclosure
|
|
132
|
-
id?: string, // expand: [mem-xxxx] id
|
|
133
|
-
cwd?: string, // project/key track working directory (defaults to session cwd)
|
|
134
|
-
date?: string, // daily track YYYY-MM-DD
|
|
135
|
-
})
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
- **Progressive disclosure:** `key` entries are stored with an optional `[summary]` line; `list` without `expand` returns summaries; `expand` with `id` returns full text.
|
|
139
|
-
- **Branch scope:** `key` entries may carry `[branch:main]` tags; `list` with `branch` filters to that branch + entries with no branch tag.
|
|
140
|
-
|
|
141
|
-
### `dtodo` — actions
|
|
142
|
-
|
|
143
|
-
```ts
|
|
144
|
-
dtodo({
|
|
145
|
-
action: 'add'|'list'|'done'|'update'|'remove',
|
|
146
|
-
target?: 'life'|'work'|'project'|'daily', // add/list filter; add defaults to cwd?project:work
|
|
147
|
-
content?: string,
|
|
148
|
-
id?: string, // done/update/remove
|
|
149
|
-
due?: string, // YYYY-MM-DD
|
|
150
|
-
quadrant?: 'q1'|'q2'|'q3'|'q4', // or important/urgent booleans -> quadrant
|
|
151
|
-
cat?: string, status?: 'pending'|'doing'|'done'|'blocked'|'cancelled',
|
|
152
|
-
all?: boolean, past?: boolean, expired?: boolean, // list: smart-view controls
|
|
153
|
-
cwd?: string, date?: string,
|
|
154
|
-
})
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
- **Smart view (default):** when `all !== true` and no filter, `list` returns at most 8 items ordered `overdue -> due today -> current project -> q1/q2 -> rest`. Uses local date, not UTC.
|
|
158
|
-
- **History:** `past=true` alone shows only completed history; `past=true AND expired=true` includes expired unfinished daily todos (daily todos expire same day).
|
|
159
|
-
|
|
160
|
-
### `memory_suggest` (gated)
|
|
161
|
-
|
|
162
|
-
```ts
|
|
163
|
-
memory_suggest({ target: 'memory'|'user'|'key'|'todo-life'|'todo-work'|'todo-project'|'todo-daily', content: string, reason: string })
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
Dedupes by `(target, content)` within the queue (bumps `hits`), appends to `SUGGESTIONS.jsonl`. The model must never write `key`/`user` directly — queue + human click is the only activation path.
|
|
167
|
-
|
|
168
|
-
---
|
|
50
|
+
`memory` sanitizes sensitive fragments (`[Filtered:API key/password/token/ID/phone]`, pure credential → `content filtered`).
|
|
169
51
|
|
|
170
52
|
## System Prompt Snapshot
|
|
171
53
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
Injected text is **bounded** and deterministic: `USER + global MEMORY + current-project KEY` (branch-filtered if `session.header.branch` is present), plus a header with `sessionId`/`sessionName` and an end-of-turn discipline note (rendered verbatim as `---` + newline + sentence):
|
|
175
|
-
|
|
176
|
-
> End of every turn you must: 1. Write daily+project via memory entries (daily+project in one call) 2. Check dtodo list (bounded, max 8)
|
|
54
|
+
`memory:snapshot` (order 500) injects bounded deterministic context:
|
|
177
55
|
|
|
178
|
-
`
|
|
56
|
+
`USER + MEMORY + KEY (branch-filtered) + Project Context (auto-recall top-4, 600 chars each, cap 1024) + Recent Daily (last 2 days, 512) + header + discipline note`
|
|
179
57
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
---
|
|
58
|
+
Caps: `memory 2048 / user 4096 / key 6144 / recentDaily 512 / autoRecall 1024`.
|
|
183
59
|
|
|
184
60
|
## UI & RPC
|
|
185
61
|
|
|
186
|
-
|
|
187
|
-
- **RPC channel:** `/dsh-maestro-memory` (`ctx.connection.rpc.handle` host, `ctx.connection.rpc.call` client). Endpoints: `queue.list`, `queue.decide` (`approve`/`reject`/`archive` with optional `edits`/`targets` + `cwd`), `memory.list`, `todo.list`, `todo.mutate`, `migration.inspect`/`dryRun`/`run`/`verify`, `status` (`{ queue, blocked }`). `migration.run` via RPC requires `payload.apply === true`.
|
|
188
|
-
|
|
189
|
-
---
|
|
62
|
+
One `conversation.view` slot (`maestro-memory`, order 40) with tabs **Memory / Review / Todos / Skills / Health**. Health shows `coverage`, `daily last 7d`, `longest` + 5-dim score `S/R/J/C/Safety` (composite `min*0.4+mean*0.6`).
|
|
190
63
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
**Principle:** staged single-owner replacement — never run `dsh-memory-evolve` and `dsh-maestro-memory` in the same profile. The new internals, services, RPC methods, and slot ids use a Maestro namespace; compatibility is limited to agent-facing tool names and legacy file grammar.
|
|
194
|
-
|
|
195
|
-
**Operator steps (production):**
|
|
196
|
-
|
|
197
|
-
1. **Preflight** on a copy, not live home (see Migration). Keep the live profile untouched until verification passes.
|
|
198
|
-
2. **Backup** the live `~/.dsh/memories` via `node scripts/migrate.mjs --root ~/.dsh/memories --apply` — this is the only write; it creates `manifest.json` + byte-identical `files/` under `.maestro-memory/backups/<utc-run-id>/` + `schema.json` + `journal`.
|
|
199
|
-
3. **Verify** (`--verify`) — must be `ok=true`, `mismatches=[]`. If not, writes are blocked (`write-block.json`) — resolve before continuing.
|
|
200
|
-
4. **Profile swap:** remove `dsh-memory-evolve` from `bundles`/`dependencies`, add `@ddtcorex/dsh-maestro-memory` as `link:` (or pinned git SHA). Ensure exactly one owner per compat tool (`memory`, `dtodo`).
|
|
201
|
-
5. **Reload profile:** restart `dsh web` at a user-approved window (ask first — do not kill the live `dsh web` process mid-session; it holds both :3000 and :3080). After restart, live-read every track (`memory` list for each target, `dtodo` list) before first mutation.
|
|
202
|
-
6. **One write** against live data, then `verify` again.
|
|
203
|
-
|
|
204
|
-
**Before any writes, rollback is just a profile change** (remove Maestro, restore old bundle). After writes, restore files from the manifest.
|
|
205
|
-
|
|
206
|
-
For a disposable rehearsal, use `src/host/migration/fixture.ts` (`createFixtureProfile`, `createCopiedMemoryRoot`, `assertSingleOwner`) — see `tests/m4-rehearsal.spec.ts` and the `Migration rehearsal` CI job. Never touch `~/.dsh/memories` in tests.
|
|
207
|
-
|
|
208
|
-
---
|
|
209
|
-
|
|
210
|
-
## Migration
|
|
211
|
-
|
|
212
|
-
CLI: `node scripts/migrate.mjs --root <path> [--inspect|--dry-run|--verify|--apply] [--run-id <id>]`
|
|
213
|
-
|
|
214
|
-
Default is **read-only**. The only write is `--apply`.
|
|
215
|
-
|
|
216
|
-
| Command | Effect | Side effects |
|
|
217
|
-
|---------|--------|--------------|
|
|
218
|
-
| `--inspect` (default) | Inventory, parse, byte count, SHA-256, warnings for malformed JSONL / locks / non-canonical files | None |
|
|
219
|
-
| `--dry-run` | Same as inspect, explicitly read-only | None |
|
|
220
|
-
| `--apply` | **Backup + adopt:** byte-preserving copy of every file (excluding `.maestro-memory`) into `backups/<utc-run-id>/files/` + `manifest.json` (`path, bytes, sha256, inventory`) + `schema.json` + `migration-journal.jsonl` entry. Only after all required data parses; source content is never reformatted. | Writes `manifest`, `files/`, `schema.json`, `journal` |
|
|
221
|
-
| `--verify` | Reopen with new stores, compare digest (`bytes`, `sha256`) + inventory (`memoryEntries`, `todoIds`, `queueValid`) against manifest. On mismatch, writes `.maestro-memory/write-block.json` and blocks mutations; on success clears the block. | Writes `write-block.json` on failure; clears on success |
|
|
222
|
-
|
|
223
|
-
**Disk layout:**
|
|
224
|
-
|
|
225
|
-
```
|
|
226
|
-
~/.dsh/memories/
|
|
227
|
-
MEMORY.md USER.md # may be absent until first global write
|
|
228
|
-
MEMORY-archive.md USER-archive.md
|
|
229
|
-
SUGGESTIONS.jsonl
|
|
230
|
-
TODOS-life.md TODOS-work.md
|
|
231
|
-
daily/YYYY-MM-DD.md daily/YYYY-MM-DD.todo.md
|
|
232
|
-
projects/<sha1(cwd)[:12]>/
|
|
233
|
-
MEMORY.md KEY.md
|
|
234
|
-
KEY-archive.md TODOS.md
|
|
235
|
-
.maestro-memory/
|
|
236
|
-
schema.json
|
|
237
|
-
migration-journal.jsonl
|
|
238
|
-
write-block.json # present only when verify failed
|
|
239
|
-
backups/<utc-run-id>/
|
|
240
|
-
manifest.json # { files:[{path,relative,bytes,sha256,kind,...}], inventory, runId, at }
|
|
241
|
-
files/... # byte-identical copies
|
|
242
|
-
```
|
|
64
|
+
RPC: `/dsh-maestro-memory` + loopback `/dsh-maestro-memory-health` + `/dsh-maestro-memory-propose`.
|
|
243
65
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
- `non-canonical` — file does not round-trip through `§` parse/serialize (drift); mutation is refused until canonicalized.
|
|
247
|
-
- `malformed todo` — entry missing timestamp/id in a todo file.
|
|
248
|
-
- `malformed queue` — JSONL line in `SUGGESTIONS.jsonl` that does not parse as `{target, content}`.
|
|
249
|
-
|
|
250
|
-
**Write-block:** `migration/service.ts:isWriteBlocked(root)` checks `.maestro-memory/write-block.json`. When blocked, `memory`/`dtodo` mutations return an error until `verify` passes or `rollback` clears it.
|
|
251
|
-
|
|
252
|
-
**Examples:**
|
|
253
|
-
|
|
254
|
-
```sh
|
|
255
|
-
node scripts/migrate.mjs --root ~/.dsh/memories # inspect (read-only)
|
|
256
|
-
node scripts/migrate.mjs --root /tmp/mem --dry-run # dry-run
|
|
257
|
-
node scripts/migrate.mjs --root /tmp/mem --apply # backup + adopt
|
|
258
|
-
node scripts/migrate.mjs --root /tmp/mem --verify # verify (latest manifest)
|
|
259
|
-
node scripts/migrate.mjs --root /tmp/mem --verify --run-id 20260824T151230.425Z
|
|
260
|
-
```
|
|
261
|
-
|
|
262
|
-
---
|
|
263
|
-
|
|
264
|
-
## Verification
|
|
265
|
-
|
|
266
|
-
1. After `inspect`/`dryRun`, confirm `ok=true`, expected `memoryEntries`/`todoIdsCount`/`queueValid`, and review `warnings`.
|
|
267
|
-
2. After `--apply`, confirm `manifest.json` exists, each `files/<relative>` copy is byte-identical (`sha256` matches), and `~/.dsh/memories` files are unchanged (no reformatting).
|
|
268
|
-
3. After `--verify`, confirm `ok=true`, `mismatches=[]`. If `ok=false`, check `mismatches` (`digest mismatch`, `byte count mismatch`, `todo ID set mismatch`, `inventory mismatch`) and `.maestro-memory/write-block.json`. No mutation should proceed while blocked.
|
|
269
|
-
4. After profile reload, live-read via tools/RPC (`memory` list for `memory`/`user`/`key`/`daily`/`project`, `dtodo` list for `life`/`work`/`project`/`daily`) and compare to pre-cutover inventory.
|
|
270
|
-
|
|
271
|
-
The rehearsal suite (`tests/m4-rehearsal.spec.ts`) exercises the full sequence against a copied schema: fixture profile (`link:`) → one-owner proof → dry-run (no `.maestro-memory`) → backup (byte-preserving) → verify → profile reload (`apply`/`ctx.effect`) → live reads → one write → second verify (fails) → rollback (byte-identical) → verify (passes) → live home untouched.
|
|
272
|
-
|
|
273
|
-
---
|
|
274
|
-
|
|
275
|
-
## Rollback
|
|
276
|
-
|
|
277
|
-
Rollback restores files **byte-identical** from a backup manifest. It is exercised and tested in `tests/m4-rehearsal.spec.ts`.
|
|
278
|
-
|
|
279
|
-
**When to rollback:**
|
|
280
|
-
|
|
281
|
-
- Before any writes: no rollback needed — just revert the profile change (remove Maestro bundle, restore old plugin).
|
|
282
|
-
- After a failed `verify` or a bad write: restore from the backup that `verify` reports.
|
|
283
|
-
|
|
284
|
-
**How (CLI / service API):**
|
|
285
|
-
|
|
286
|
-
```ts
|
|
287
|
-
import { rollback } from './src/host/migration/service.ts'
|
|
288
|
-
// restore latest (schema.json runId or newest backup)
|
|
289
|
-
await rollback('/tmp/memories')
|
|
290
|
-
// or specific run
|
|
291
|
-
await rollback('/tmp/memories', '20260824T151230.425Z')
|
|
292
|
-
```
|
|
293
|
-
|
|
294
|
-
Or via the `migration` RPC (host) if exposed. The service:
|
|
295
|
-
|
|
296
|
-
- Copies each `manifest.files[].relative` from `backups/<runId>/files/` to its original `path`, verifying `sha256` after copy.
|
|
297
|
-
- If a file was absent at backup time (`exists:false` in manifest) but appeared later, it is removed.
|
|
298
|
-
- Clears `write-block.json` on completion and appends a `rollback` entry to `migration-journal.jsonl`.
|
|
299
|
-
- Returns `{ ok, runId, manifestPath, restored, errors }` (`restored` = count of files restored/removed).
|
|
300
|
-
|
|
301
|
-
**After rollback:**
|
|
302
|
-
|
|
303
|
-
- `verify` must pass (`ok=true`, no mismatches).
|
|
304
|
-
- A new write must succeed (the write-block is cleared).
|
|
305
|
-
|
|
306
|
-
**Retention:** keep `~/.dsh/memories/.maestro-memory/backups/` for at least 90 days after cutover (per plan). Do not delete the manifest for the adopted run.
|
|
307
|
-
|
|
308
|
-
---
|
|
309
|
-
|
|
310
|
-
## Removed Features (intentionally not in v1)
|
|
311
|
-
|
|
312
|
-
Source-grounded inventory. Propose any as a separate plugin later.
|
|
313
|
-
|
|
314
|
-
| Source subsystem | Verdict | Rationale |
|
|
315
|
-
|------------------|---------|-----------|
|
|
316
|
-
| **Cross-device Git memory sync** (`lib/sync/*`) | **KEEP as optional module (M5)** | Large conflict-resolution product; must not delay local-data reliability. Disabled = zero network/Git activity. |
|
|
317
|
-
| **Skills management/browser** (`lib/skills.js`, `lib/skills-manager.js`) | **KEEP as optional module (M6)** | Mutates `~/.agents/skills`; Maestro already owns skills in `maestro-skills`. Core stays read-only. |
|
|
318
|
-
| **COI / external CLI dispatch, scheduler, broadcast, ws coordinator, stats, attachments, session orchestration** (`lib/coi/*`, `lib/session-orch.js`) | **DROP** | Independent orchestration platform; profile already has DSH Codex/Claude subagent bundles. |
|
|
319
|
-
| **Advisor** (`lib/advisor/*`) | **REDESIGN** (separate opt-in plugin) | Full reviewer runtime with model calls and panel — not memory. |
|
|
320
|
-
| **Notify / channel send / session images** (`lib/notify.js`) | **DROP** | IM/web delivery via global integration registry (`de_channel_send`, `de_notify`); unrelated to durable memory. |
|
|
321
|
-
| **Local / docs / Codex search** (`lib/search-docs.js`, `lib/search/*`) | **DROP** | Host file scans / shell-out expands authority without being needed for memory. |
|
|
322
|
-
| **Prompt injection library** (`lib/prompts.js`) | **DROP** | Reusable guidance belongs in `maestro-skills`. |
|
|
323
|
-
| **Model registry / settings** (`lib/models.js`) | **DROP** | Overlays DSH model config; `lib/index.js` already injects DSH settings/llm. |
|
|
324
|
-
| **Bookmarks, Mermaid, canvas, UI settings, aliases, update checker, i18n** (`lib/{bookmarks,mermaid,canvas,ui-settings,aliases,update,i18n}.js`) | **REDESIGN** | Independent features; propose individually if needed. |
|
|
325
|
-
| **Client/WebUI broad tabs** (`src/client/index.ts` family) | **REDESIGN** | Legacy mounts many tabs/actions + HTTP API; v1 has one slot + package-private RPC. |
|
|
326
|
-
| **HTTP API** (`lib/api.js` `/memory-evolve` prefix, `ctx.webServer`) | **DROP** | No `webServer` registration; only `ctx.connection.rpc.handle('/dsh-maestro-memory', …)`. |
|
|
327
|
-
|
|
328
|
-
**Preserved in backup but not imported:** `advisor/`, `pending-skills/`, `plugin-state.json`, `search-docs-index.json`, `coi/` (copied byte-identical into `files/` and listed in `manifest.json`, never parsed as memory state).
|
|
329
|
-
|
|
330
|
-
---
|
|
331
|
-
|
|
332
|
-
## Workflow: Superpowers skills are mandatory
|
|
333
|
-
|
|
334
|
-
Every change to this repository MUST follow the Superpowers skill workflow, in order:
|
|
335
|
-
|
|
336
|
-
1. **brainstorming** — explore intent, requirements, and design before any code; record the outcome in `docs/superpowers/specs/` (`YYYY-MM-DD-<topic>-design.md`).
|
|
337
|
-
2. **writing-plans** — turn an approved spec into a task-by-task plan with exact test and implementation sketches in `docs/superpowers/plans/` (`YYYY-MM-DD-<topic>.md`).
|
|
338
|
-
3. **executing-plans** — implement task by task with strict TDD: write the failing test first, verify RED, implement, verify GREEN, then commit that task as its own commit before starting the next.
|
|
339
|
-
|
|
340
|
-
Do not skip ahead to implementation, batch multiple tasks into one commit, or commit while a task's tests are red. Trivial mechanical fixes may go straight to a commit but still need tests when behavior changes.
|
|
341
|
-
|
|
342
|
-
---
|
|
343
|
-
|
|
344
|
-
## Git Workflow
|
|
345
|
-
|
|
346
|
-
- Never commit to `master` directly; batch related work on a feature branch (`feat/...`, `fix/...`). One TDD task = one commit while executing a plan.
|
|
347
|
-
- Conventional commit subjects, imperative mood.
|
|
348
|
-
- Push the branch and open an MR when the batch is green; rebase instead of merging master into the branch when the base moves.
|
|
349
|
-
- `origin` is `git@github.com:ddtcorex/dsh-maestro-memory.git` (private, default branch `master`).
|
|
350
|
-
|
|
351
|
-
---
|
|
352
|
-
|
|
353
|
-
## Layout
|
|
354
|
-
|
|
355
|
-
- `src/host/` — Cordis host plugin (`storage/legacy-format.ts`, `storage/layout.ts`, `storage/atomic-store.ts`, `memory/store.ts`, `todo/store.ts`, `review/queue.ts`, `migration/service.ts`, `prompt/snapshot.ts`, `index.ts`).
|
|
356
|
-
- `src/client/` — DSH client bundle (`src/client/index.tsx` → `lib/client.js` via `scripts/build-client.mjs`, `conversation.view` id `maestro-memory` order 40, internal Memory/Review/Todos tabs, RPC `/dsh-maestro-memory`).
|
|
357
|
-
- `tests/` — Vitest specs (`legacy-format.spec.ts`, `storage.spec.ts`, `atomic-store.spec.ts`, `memory-m2.spec.ts`, `todo-m3.spec.ts`, `migration.spec.ts`, `m4-rehearsal.spec.ts`, etc.).
|
|
358
|
-
- `scripts/migrate.mjs` — migration CLI (`--root`, `--apply`/`--dry-run`/`--verify`).
|
|
359
|
-
|
|
360
|
-
Build outputs in `lib/` (`lib/client.js` via `scripts/build-client.mjs`) are generated — never edit by hand.
|
|
361
|
-
|
|
362
|
-
---
|
|
363
|
-
|
|
364
|
-
## Development
|
|
66
|
+
## Maintenance
|
|
365
67
|
|
|
366
68
|
```sh
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
pnpm run verify # tsc --noEmit host + client (typecheck)
|
|
370
|
-
pnpm run build # tsc host + tsc client + bundle client.js
|
|
371
|
-
pnpm exec vitest run tests/legacy-format.spec.ts tests/storage.spec.ts tests/atomic-store.spec.ts # unit
|
|
372
|
-
pnpm exec vitest run tests/memory-m2.spec.ts tests/todo-m3.spec.ts tests/suggestion-queue.spec.ts tests/rpc-queue.spec.ts # integration
|
|
373
|
-
pnpm exec vitest run tests/migration.spec.ts # migration
|
|
374
|
-
pnpm exec vitest run tests/m4-rehearsal.spec.ts # rehearsal (fixture profile + rollback)
|
|
375
|
-
node scripts/migrate.mjs --root ~/.dsh/memories # inspect (read-only)
|
|
376
|
-
node scripts/migrate.mjs --root /tmp/mem --apply # backup + adopt
|
|
377
|
-
node scripts/migrate.mjs --root /tmp/mem --verify # verify
|
|
69
|
+
node scripts/maestro-memory-remediate.mjs --apply --threshold-days 14
|
|
70
|
+
node scripts/enforce-rules.mjs --check-memory --threshold 90
|
|
378
71
|
```
|
|
379
72
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
### CI
|
|
383
|
-
|
|
384
|
-
`.github/workflows/ci.yml` runs on `push` to `master`/`main` and on every PR:
|
|
385
|
-
|
|
386
|
-
| Job step | Command | What it proves |
|
|
387
|
-
|----------|---------|----------------|
|
|
388
|
-
| Install | `pnpm install --frozen-lockfile` | Reproducible deps |
|
|
389
|
-
| Build | `pnpm run build` | Host + client compile |
|
|
390
|
-
| Typecheck | `pnpm run verify` | `tsc --noEmit` host + client |
|
|
391
|
-
| Unit | `vitest run tests/legacy-format.spec.ts tests/storage.spec.ts tests/atomic-store.spec.ts` | Pure delimiter / path / atomic-store |
|
|
392
|
-
| Integration | `vitest run tests/memory-m2.spec.ts tests/todo-m3.spec.ts tests/suggestion-queue.spec.ts tests/rpc-queue.spec.ts tests/smoke.spec.ts` | Stores + queue + RPC |
|
|
393
|
-
| Migration | `vitest run tests/migration.spec.ts` | inspect/dryRun/run/verify, backup manifest, write-block |
|
|
394
|
-
| Rehearsal | `vitest run tests/m4-rehearsal.spec.ts` | Fixture `link:` profile, one-owner proof, copied-schema cutover + rollback, live home untouched |
|
|
395
|
-
| Client | `test -f lib/client.js && grep ModuleLoader lib/client.js` | Bundle exists + header |
|
|
396
|
-
| Full | `pnpm test` | Entire suite (13 files, 199 tests) |
|
|
397
|
-
|
|
398
|
-
---
|
|
399
|
-
|
|
400
|
-
## Security
|
|
401
|
-
|
|
402
|
-
- Never print, commit, or add fixture values for secrets. Use obviously synthetic values in tests and docs.
|
|
403
|
-
- No cloud service, database rewrite, telemetry, or sync in v1; M5 sync (Git-backed) is opt-in and disabled means zero network activity.
|
|
404
|
-
- Secrets must never be echoed to the client; new secret-bearing fields need masking + constant-time comparison.
|
|
405
|
-
- File permissions: memory files inherit host umask; `SUGGESTIONS.jsonl` is append-only; `write-block.json` is local-only.
|
|
406
|
-
|
|
407
|
-
---
|
|
408
|
-
|
|
409
|
-
## Troubleshooting
|
|
410
|
-
|
|
411
|
-
| Symptom | Cause | Fix |
|
|
412
|
-
|---------|-------|-----|
|
|
413
|
-
| `tool "memory" has multiple owners` in `assertSingleOwner` | Both `dsh-memory-evolve` and `dsh-maestro-memory` in `bundles` | Remove the old plugin from the profile; keep exactly one owner per compat tool |
|
|
414
|
-
| `profile cordis.patch.yml must not duplicate id maestro-memory` | Profile patch duplicates the package's `cordis.patch.yml` row | Delete the row from the profile patch; the package provides it |
|
|
415
|
-
| `verify failed: digest mismatch` / `write-block.json` exists | File changed after backup (hand-edit, concurrent writer) | Inspect `write-block.json` mismatches, then `rollback(root, runId)` or resolve drift and `verify` again |
|
|
416
|
-
| `non-canonical` warning | File contains non-`§`-canonical content (hand-edit) | Back up manually, then normalize via a single `replace` edit through the tool (creates canonical serialization) |
|
|
417
|
-
| `mismatched todo IDs` after verify | Todo file edited outside the store | Roll back or re-run `inspect` and compare inventories |
|
|
418
|
-
| DSH Web UI shows no Memory tab | `lib/client.js` not built or bundle header missing | `pnpm run build` at the checkout, then restart `dsh web` (user-approved window) and hard-refresh the browser |
|
|
419
|
-
|
|
420
|
-
---
|
|
421
|
-
|
|
422
|
-
## Ghi chú vận hành (Tiếng Việt — ngắn gọn)
|
|
423
|
-
|
|
424
|
-
> English là ngôn ngữ chính của tài liệu và mã nguồn. Phần này chỉ tóm tắt thao tác cho người vận hành tiếng Việt.
|
|
73
|
+
## Cutover
|
|
425
74
|
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
- **Rollback:** `await rollback(root, runId)` khôi phục byte-identical từ `backups/<runId>/files/`; xóa `write-block.json` khi xong. Trước khi có ghi mới, rollback chỉ là đổi profile.
|
|
431
|
-
- **Tính năng đã loại bỏ:** COI/broadcast, advisor, notify/`de_channel_send`, search, prompt library, model registry, bookmarks/mermaid/canvas. Chi tiết xem bảng "Removed Features".
|
|
432
|
-
- **CI:** `build` + `typecheck` + `unit` + `integration` + `migration` + `rehearsal` + `client` + `full` — tất cả phải xanh trước khi merge.
|
|
75
|
+
1. Backup: `node scripts/migrate.mjs --root ~/.dsh/memories --apply`
|
|
76
|
+
2. Verify: `node scripts/migrate.mjs --root ~/.dsh/memories --verify` (must be `ok=true`)
|
|
77
|
+
3. Swap profile: remove `dsh-memory-evolve`, add `dsh-maestro-memory` as `link:` or pinned SHA.
|
|
78
|
+
4. Restart `dsh web` at user-approved window, then live-read each track.
|
|
433
79
|
|
|
434
|
-
|
|
80
|
+
Rollback: `rollback(root, runId)` restores byte-identical files from `backups/<runId>/`.
|
|
435
81
|
|
|
436
|
-
##
|
|
82
|
+
## Migration CLI
|
|
437
83
|
|
|
438
|
-
|
|
84
|
+
`node scripts/migrate.mjs --root <path> [--inspect|--dry-run|--verify|--apply]`
|
|
439
85
|
|
|
440
|
-
|
|
86
|
+
Default read-only; only `--apply` writes `manifest.json` + `backups/<runId>/files/` + `schema.json`.
|
|
441
87
|
|
|
442
|
-
##
|
|
88
|
+
## Verification
|
|
443
89
|
|
|
444
|
-
- `
|
|
445
|
-
- `src/host/migration/fixture.ts` — fixture profile + copied-schema helpers for rehearsal
|
|
446
|
-
- `tests/m4-rehearsal.spec.ts` — end-to-end rehearsal (profile → backup → verify → reload → write → rollback)
|
|
447
|
-
- `scripts/migrate.mjs` — operations CLI (read-only by default, `--apply` to write)
|
|
448
|
-
- `.github/workflows/ci.yml` — build / typecheck / unit / integration / migration / client / full
|
|
90
|
+
After `--apply`/`--verify`: `ok=true`, `mismatches=[]`, `manifest.json` byte-identical. Rehearsal suite `tests/m4-rehearsal.spec.ts` covers fixture `link:` profile → backup → verify → rollback.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* auto-memory.ts — opt-in automatic session/event → memory persistence.
|
|
3
|
+
* Ported from FuRongJun-1999/dsh-memory hooks.ts (memory hooks) but
|
|
4
|
+
* file-native (MaestroMemoryStore) and English-only.
|
|
5
|
+
*/
|
|
6
|
+
import type { MaestroMemoryStore } from './memory/store.ts';
|
|
7
|
+
export interface AutoMemoryOptions {
|
|
8
|
+
enabled: boolean;
|
|
9
|
+
userMessage: boolean;
|
|
10
|
+
assistantMessage: boolean;
|
|
11
|
+
toolResult: boolean;
|
|
12
|
+
importance: number;
|
|
13
|
+
desensitize: boolean;
|
|
14
|
+
}
|
|
15
|
+
export declare const DEFAULT_AUTO_MEMORY: AutoMemoryOptions;
|
|
16
|
+
/**
|
|
17
|
+
* Install session/event hooks for auto-memory.
|
|
18
|
+
* Returns a disposer (ctx.on returns disposer in Cordis 4).
|
|
19
|
+
*/
|
|
20
|
+
export declare function installAutoMemoryHooks(ctx: any, store: MaestroMemoryStore, opts: AutoMemoryOptions): () => void;
|
|
21
|
+
//# sourceMappingURL=auto-memory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auto-memory.d.ts","sourceRoot":"","sources":["../src/host/auto-memory.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AAG3D,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,OAAO,CAAA;IAChB,WAAW,EAAE,OAAO,CAAA;IACpB,gBAAgB,EAAE,OAAO,CAAA;IACzB,UAAU,EAAE,OAAO,CAAA;IACnB,UAAU,EAAE,MAAM,CAAA;IAClB,WAAW,EAAE,OAAO,CAAA;CACrB;AAED,eAAO,MAAM,mBAAmB,EAAE,iBAOjC,CAAA;AAgBD;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,kBAAkB,EAAE,IAAI,EAAE,iBAAiB,GAAG,MAAM,IAAI,CAmD/G"}
|