dsh-memento 0.3.1 → 0.4.1

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/ARCHITECTURE.md CHANGED
@@ -139,3 +139,39 @@ memory 工具(add)
139
139
 
140
140
  全部字段可 cordis.yml 覆盖,schema 见 `index.mjs` 的 `Config`;完整字段表(`enabled` / `dbPath` / `budgets` / `writePolicy` / `writePolicies` / `language` / `snapshotOrder` / `maxEntriesPerQuery` / `commandListLimit` / `commandAuditLimit` / `recall.*` / `panelEntriesLimit` / `panelAuditLimit` / `auditRetentionDays` / `proposals.*`)以 README 配置表为准,本文件不再逐项复制以免漂移。非法值加载期响亮失败。
141
141
  - **harness 主目录回退(0.3.1)**:`dbPath` 为空或相对路径时,基准目录取 `$DSH_HOME`;`dsh web` 启动不会把官方 `resolveDshHome()` 解析出的主目录写回 `process.env.DSH_HOME`,因此未导出时回退 `~/.dsh`(与官方回退同语义)——否则默认 Windows 配置会在真实 boot 时整体崩溃(issue #1)。`lib/` 零 DSH 依赖的红线不允许 import `@deepseek-ai/dsh-home-paths`,用 `os.homedir()` 复刻同一回退。
142
+
143
+ ## 协议 v1(0.4.0:dsh-memory-protocol 社区预演)
144
+
145
+ ### 13. 协议与实现分离:写语义抽进 lib/protocol.mjs(零 DSH 依赖)
146
+
147
+ 0.4.0 把 MemoryService 的写语义整体抽进 `lib/protocol.mjs` 的 `MemoryProtocolCore`:预算预检 →
148
+ gate → 预算复审 → 落盘 → 审计的完整流水线、唯一子串定位、`<action>-denied` 审计行、协议级
149
+ 校验(`validateMemoryEntry` / `validateExportEnvelope` / `validateAuditRow` / `normalizeTags`)。
150
+ `index.mjs` 的 `MemoryService` 变成薄子类,只注入两件 DSH 专属物:审批传输(ctx.approval)与
151
+ 会话事件派发(memory/* 已知类型自适应门,见决策 4)。一致性套件的黄金参考 = 同一 core +
152
+ 自动放行 gate——协议声称与实现同源,不存在"套件通过、实现另写一份"的漂移空间。协议常量
153
+ (`PROTOCOL_URI`、标签上限等)在 protocol.mjs;错误码语义进协议文档(docs/protocol-v1.md §7)。
154
+
155
+ ### 14. store schema v4:条目 tags + version(协议 v1 条目规范)
156
+
157
+ - `tags`:JSON 数组列;协议常量上限 16 个 × 每标签 32 字符,trim/去重/禁控制字符,
158
+ 协议层 `normalizeTags` 校验(预算只计 text,tags 不计)。
159
+ - `version`:整数列,新条目 1;每次 `replace` 在 Provider 事务内 `version = version + 1`;
160
+ consolidate/seed/导入产生全新 version 1 条目。审计链可经 entryId + 逐次审计行重建同一 id 的
161
+ 演进史。
162
+ - 迁移:SCHEMA_VERSION 3 → 4 走既有逐级迁移梯子(`V4_SCHEMA_SQL`),旧库无损升级;
163
+ 过新版本照旧响亮拒绝。
164
+
165
+ ### 15. 适配器注册表(ctx.memoryAdapters)与一致性套件
166
+
167
+ - `lib/registry.mjs` 的 `MemoryAdapterRegistry`:`register`(返回 disposer,id 冲突响亮)/
168
+ `list` / `adapt` / `export`;index.mjs 经 `ctx.effect` 注册三个参考适配器
169
+ (`lib/adapters.mjs`:mem0 / hermes-memory-md / claude-code-memory-md),随插件生命周期可逆。
170
+ 适配器是纯数据转换器——只转换、绝不调模型抽取(载荷无事实条目时 `ADAPTER_PAYLOAD` 响亮失败)。
171
+ - 命令面:`/memory adapters`、`export --adapter=<id>`(只读 stdout 转换)、
172
+ `import --adapter=<id> <路径|内联 JSON>`(转换 → `service.seed`:一次审批 + 全量预算预检 +
173
+ 单事务 + 逐条审计)。
174
+ - `test/protocol-conformance/`:可对外分发的用例集(suite/golden/run + Provider 契约 README),
175
+ 仓库 CI 以黄金参考全绿;第三方 Provider 拷贝目录即可跑同一套用例。协议文档:
176
+ `docs/protocol-v1.md`(双语)、`docs/schemas/dsh-memory-protocol-v1.schema.json`、
177
+ `docs/adapters-guide.md`(双语)、`docs/upstream-proposal.md`(双语,官方 seam 采纳论证与迁移路径)。
package/CHANGELOG.md CHANGED
@@ -5,6 +5,29 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.4.1] - 2026-08-19
9
+
10
+ ### Fixed
11
+
12
+ - The panel routes now unload with the plugin fiber: the three `/api/memento/*` route disposers ride one `ctx.effect`, so a config hot-reload or disable followed by a remount no longer throws `duplicate exact route` (the host route table previously kept handlers closed over the unloaded fiber). Regression covered by a dispose-and-remount lifecycle test against a duplicate-strict route table.
13
+
14
+ ## [0.4.0] - 2026-08-16
15
+
16
+ ### Added
17
+
18
+ - **dsh-memory-protocol v1** — the community rehearsal of the DSH memory protocol: normative spec in `docs/protocol-v1.md` (+ 中文), machine-readable JSON Schema in `docs/schemas/dsh-memory-protocol-v1.schema.json`, entry spec extended with `tags` (≤16 × ≤32 chars) and a per-entry `version` that increments on every `replace` (store schema v4, forward-migrated).
19
+ - **Protocol/implementation separation** — write semantics moved into `lib/protocol.mjs` (`MemoryProtocolCore`, zero DSH dependencies); `MemoryService` is now a thin subclass that only injects the approval transport and the session-event emission gate. Behavior is unchanged.
20
+ - **Adapter registry `ctx.memoryAdapters`** — reversible `register()`/`list()`/`adapt()`/`export()` plus three built-in reference adapters: `mem0`, `hermes-memory-md`, `claude-code-memory-md` (pure data converters — never model extraction). New command verbs: `/memory adapters`, `export --adapter=<id>` (read-only), `import --adapter=<id> <path|inline>` (rides the approval-gated `seed`, per-entry audit). Onboarding guide in `docs/adapters-guide.md` (+ 中文).
21
+ - **Protocol conformance suite** — `test/protocol-conformance/`: 22 distributable cases (entry model, write semantics, budget model, audit reconstruction, export envelope) with a `--provider` CLI for third parties; CI runs them against dsh-memento's own provider as the golden reference (`npm run test:conformance`).
22
+ - **Upstream proposal material** — `docs/upstream-proposal.md` (+ 中文): why the official `ctx.memory` seam should adopt the protocol, differences from the current seam, and the migration path.
23
+ - `memory` tool accepts optional `tags` on add/replace/consolidate; tool results and `/memory export` documents carry `tags`/`version`.
24
+
25
+ ### Changed
26
+
27
+ - Five-language READMEs: protocol section, adapter matrix, conformance suite, new command verbs, and the development gate list (now 133 tests).
28
+ - ARCHITECTURE: decisions 13–15 (protocol separation, schema v4, adapter registry + conformance suite).
29
+ - npm package now ships the protocol docs and the conformance suite (`files` whitelist).
30
+
8
31
  ## [0.3.1] - 2026-08-15
9
32
 
10
33
  ### Fixed
package/README.es.md CHANGED
@@ -1,167 +1,217 @@
1
- # dsh-memento
2
-
3
- **Memoria entre sesiones acotada, por capas, con puerta de aprobación y auditable para DeepSeek Harness.**
4
-
5
- [![license](https://img.shields.io/badge/license-Apache--2.0-3a7d44)](LICENSE)
6
- [![dsh](https://img.shields.io/badge/dsh-0.1.0--rc.6-4e51e8)](https://www.npmjs.com/package/@deepseek-ai/dsh)
7
- [![node](https://img.shields.io/badge/node-%5E22.19%20%7C%7C%20%3E%3D24-339933)](https://nodejs.org/)
8
- [![platform](https://img.shields.io/badge/platform-Windows%20%7C%20macOS%20%7C%20Linux-lightgrey)]()
9
- [![no build step](https://img.shields.io/badge/build-none%20%28pure%20ESM%29-8a6d3b)]()
10
-
11
- [English](README.md) · [中文](README.zh.md) · [Español](README.es.md) · [Português](README.pt.md) · [हिन्दी](README.hi.md)
12
-
13
- > Otros plugins de memoria venden un **almacén**. dsh-memento vende la **costura**: un servicio tipado `ctx.memory`, una puerta de aprobación de escritura que ninguna ruta del modelo puede eludir y pistas de auditoría que puedes reconstruir desde el registro de sesión. Memoria nativa de primera clase para DeepSeek Harness: protocolo + puerta de confianza + auditoría, con cero red y cero credenciales.
14
-
15
- ## ✨ ¿Por qué dsh-memento?
16
-
17
- - **Es una costura de capacidad, no otro almacén.** Definición de Servicio (`ctx.memory`), Proveedor SQLite local (`node:sqlite`, WAL, `0600`) y Consumidores (herramienta `memory` + inyección de instantánea congelada). Cualquier plugin futuro —una integración semilla `dsh-claude-move`, un puente, un panel— alimenta y lee el **mismo almacén a través de la misma puerta**.
18
- - **La puerta no se puede eludir.** Toda ruta de escritura (`add`/`replace`/`remove`/`seed`) se fuerza a través de la cascada de aprobación **dentro del servicio**, no en la capa de herramientas. `writePolicy: ask | auto | off` es configuración que el modelo no puede ver ni cambiar; una postura `never` a nivel de sesión sigue prevaleciendo sobre todo. `replace`/`remove`/`consolidate` llevan el texto completo de las entradas que cambiarán en el payload de aprobación — lo que apruebas es lo que ves, y una escritura denegada deja igualmente una fila de auditoría `*-denied`.
19
- - **Visible para el modelo ⟺ registrado.** La instantánea inyectada llega textualmente a `request/header.system`; cada escritura es reconstruible a partir de `approval/asked` (carga útil completa) + `approval/decided` (resultado) + la propia tabla de auditoría del plugin.
20
- - **Acotada y honesta.** Presupuestos estrictos de caracteres por pista y por capa (por defecto usuario 2000 / agente 4000). Un almacén lleno **falla con un error estructurado** (uso + límite): el modelo consolida y reintenta. Nunca se trunca, nunca se compacta automáticamente.
21
-
22
- ## ⚡ Inicio rápido
23
-
24
- ```sh
25
- # requires Node ^22.19 || >=24 and DSH 0.1.0-rc.6
26
- dsh plugin --profile web add dsh-memento # or ./dsh-memento / a tarball / a GitHub URL
27
- dsh --profile web --dump-config # expect a "# == dsh-memento" layer, no FAILED at startup
28
- ```
29
-
30
- Luego, en la interfaz web: pide al modelo que recuerde algo → aprueba la escritura → inicia una **sesión nueva** y pregúntale qué recuerda. Esa es toda la demostración.
31
-
32
- ```yaml
33
- # optional override in the profile's cordis.patch.yml
34
- - id: memento
35
- config:
36
- writePolicy: ask # ask (default) | auto | off — model-invisible
37
- budgets:
38
- user: { userGlobal: 4000, workspace: 2000 } # Chinese-heavy memory: raise + note why
39
- agent: { userGlobal: 4000, workspace: 4000 }
40
- ```
41
-
42
- ## 🧠 Qué hace
43
-
44
- | | Componente | Qué obtienes |
45
- | --- | --- | --- |
46
- | 🧩 Definición de Servicio | `ctx.memory` — `add` / `replace` / `remove` / `query` / `seed` / `budgets()` | Servicio tipado y declarado por fusión; los métodos de escritura aplican la puerta internamente |
47
- | 💾 Proveedor | `lib/store.mjs` — un solo archivo `node:sqlite` (`$DSH_HOME/dsh-memento/memory.db`, WAL) | Cero dependencias, cero red; tablas de entradas + auditoría; coincidencia por subcadena única |
48
- | 🛠 Consumidores | herramienta `memory` · inyección de instantánea congelada (sección del system prompt, orden `-50`) · herramienta `memory_recall` · comando `/memory` · panel web de solo lectura | Escrituras/lecturas orientadas al modelo, instantánea congelada encabezada por presupuesto, recuperación en dos partes, comando del lado del usuario, panel lateral en el navegador |
49
-
50
- **Dos pistas × dos capas × clave por agente.** La pista `user` = hechos sobre el usuario (preferencias, estilo de comunicación, temas delicados); la pista `agent` = hechos del entorno, convenciones del proyecto, lecciones aprendidas. Cada pista tiene capas `user-global` (entre espacios de trabajo) y `workspace` (cwd por sesión): capas fusionadas al estilo Codex, no solo global al estilo Hermes. Una tercera dimensión aísla entradas por el `agentPreset` de la sesión (ámbito por agente); las entradas sin preset quedan en la capa compartida visible para todos. Las lecturas y la localización de escritura con ámbito de sesión siguen la misma visibilidad: una sesión ve — y `replace`/`remove` solo puede tocar — entradas compartidas más las de su propio agente, y entradas `workspace` solo de su propio cwd. Las superficies de gestión (`/memory`, el panel) conservan la vista completa entre agentes.
51
-
52
- **Instantáneas congeladas.** La instantánea se renderiza una vez por sesión en el primer ensamblado del prompt (lectura síncrona de SQLite + caché por sesión) y nunca cambia a mitad de sesión: estable en caché de prefijo por construcción. Los cambios internos de la sesión persisten solo a disco + auditoría.
53
-
54
- ```
55
- Consumer: memory tool Consumer: frozen snapshot (systemPrompt section, order -50)
56
- add/replace/remove/query per-session freeze, budget-headed
57
- │ writes (agent+callId) │ reads (sync, session cwd)
58
- ▼ ▼
59
- Service Definition: ctx.memory — budgets/add/replace/remove/query/seed
60
- every write: budget precheck → ctx.approval.request (approval waterfall) → budget recheck → persist → audit
61
- │
62
- ▼
63
- Provider: lib/store.mjs — node:sqlite (WAL, 0600), entries + audit tables, unique-substring match
64
- ```
65
-
66
- ## 🧰 Instalación y desinstalación
67
-
68
- ```sh
69
- dsh plugin --profile <name> add ./dsh-memento # local checkout (no build step)
70
- dsh plugin --profile <name> add dsh-memento # paquete npm (publicado desde 0.2.0)
71
- dsh plugin --profile <name> add git+https://github.com/PerryLink/dsh-memento.git # instalación desde GitHub
72
- dsh plugin --profile <name> remove dsh-memento # uninstall: DB + session logs are kept
73
- ```
74
-
75
- Tras la desinstalación, la base de datos de memoria y los registros de sesión que guardaron la actividad de memoria permanecen; las sesiones antiguas siguen siendo cargables.
76
-
77
- ## ⚙️ Configuración
78
-
79
- Cada campo es un `Config` de Schemastery validado; los valores inválidos fallan de forma explícita al cargar. Sobrescríbelos en cordis.yml bajo la fila `memento`.
80
-
81
- | Campo | Valor por defecto | Significado |
82
- | --- | --- | --- |
83
- | `enabled` | `true` | `false` elimina por completo el servicio, las herramientas, la instantánea, el comando, el panel y el contestador (sin estados a medias) |
84
- | `dbPath` | `''` → `$DSH_HOME/dsh-memento/memory.db` | absoluto, o relativo a `$DSH_HOME`; si `$DSH_HOME` no está exportado (el valor por defecto en Windows — `dsh web` no devuelve el home resuelto al entorno), ambos caen a `~/.dsh` |
85
- | `budgets.user.userGlobal` / `budgets.user.workspace` | `2000` / `2000` | presupuesto estricto de caracteres por capa de la pista de usuario |
86
- | `budgets.agent.userGlobal` / `budgets.agent.workspace` | `4000` / `4000` | presupuesto estricto de caracteres por capa de la pista de agente |
87
- | `writePolicy` | `'ask'` | `'ask'` = aprobación del usuario; `'auto'` = dejar pasar (se registra el origen de la aprobación); `'off'` = rechazar. Invisible para el modelo |
88
- | `writePolicies` | `{}` | anulaciones por pista/capa o por fuente: claves `user/workspace`, `agent/user-global`, `source:claude`, … → `ask`/`auto`/`off`; sin coincidencia cae a `writePolicy` |
89
- | `language` | `'en'` | idioma del texto visible para el modelo y de la salida del comando: `'en'` (por defecto) o `'zh'` — descripciones de herramientas, instantánea congelada, comando `/memory` y panel web lo siguen |
90
- | `snapshotOrder` | `-50` | orden de la sección de la instantánea: después de la identidad del harness (`-100`), antes de la persona (`0`) |
91
- | `maxEntriesPerQuery` | `20` | tope de resultados por consulta por defecto (`limit` explícito permitido, tope duro 1000) |
92
- | `commandListLimit` | `50` | entradas mostradas por comando `/memory list` / `query` |
93
- | `commandAuditLimit` | `10` | filas de auditoría mostradas por comando `/memory audit` |
94
- | `recall.historyLimitDefault` / `recall.snippetCap` / `recall.snippetChars` / `recall.windowDays` | `8` / `5` / `300` / `30` | valores por defecto de historial de `memory_recall`: sesiones escaneadas, fragmentos por sesión, caracteres por fragmento, ventana de días |
95
- | `panelEntriesLimit` | `200` | tamaño de página de entradas del panel web (y tope) |
96
- | `panelAuditLimit` | `20` | filas de auditoría del panel web por defecto (tope 200) |
97
- | `auditRetentionDays` | `0` | retención de auditoría: 0 = para siempre, >0 = poda al abrir la tienda |
98
- | `proposals.enabled` / `proposals.maxChars` / `proposals.maxPending` | `true` / `2000` / `8` | auto-captura: propuesta de memoria pendiente tras cada compactación exitosa (truncada, una por sesión); desactivar o ajustar topes |
99
-
100
- ## 🛠 Herramientas y superficies
101
-
102
- - **`memory`** — add/replace/remove/consolidate/query con guía Guardar/Omitir incrustada en la descripción (guarda preferencias del usuario, correcciones, hechos del entorno, convenciones, lecciones; omite trivialidades, hechos re-derivables, volcados, rutas de un solo uso). Las escrituras pasan por la puerta de aprobación; las lecturas son libres; replace/remove apuntan a una **subcadena única** (las coincidencias ambiguas fallan con la lista de candidatos); consolidate fusiona 1..20 entradas en una con una sola aprobación y una escritura atómica.
103
- - **`memory_recall`** — recuperación en dos partes: coincidencias acotadas de memoria **más** coincidencias recientes del historial de sesión vía `ctx.sessionQuery` (se degrada con elegancia a solo memoria donde el servicio está ausente).
104
- - **`/memory`** — comando activado por el usuario (no es un turno del modelo): `list` · `query <word>` · `add [--track=user|agent] [--scope=user-global|workspace] <text>` · `remove [flags] <substring>` · `consolidate [flags] <substring...> => <text>` · `proposals [approve|dismiss <id>]` · `budgets` · `audit` · `export` · `import <path>`. Las escrituras del comando pasan por la misma cascada + política; la auditoría se registra en la tabla de auditoría del plugin + `command/done`. `export` es de solo lectura y vuelca todas las entradas + presupuestos como un documento JSON; `import` lo restaura (ruta de archivo o JSON en línea, una sola aprobación, presupuestos pre-comprobados) — un ciclo completo de copia de seguridad/migración. Las entradas importadas reciben ids y marcas de tiempo nuevos; las propuestas, las filas de auditoría y los contadores de recuperación no se migran.
105
- - **Propuestas auto-capturadas** — tras una compactación de sesión exitosa, el resumen se registra como propuesta de memoria pendiente (`agent/workspace`); aprobarla la escribe a través de la puerta de aprobación, descartarla la elimina. Las propuestas pendientes aparecen en la instantánea congelada y en el panel.
106
- - **Panel web** — panel lateral `dsh.client` sin compilación: navega por entradas por pista/capa, busca, barras de presupuesto, cola de auditoría. De solo lectura por diseño: las escrituras y la aprobación ocurren a través de la herramienta `memory` y la interfaz de aprobación integrada.
107
-
108
- ## 🎓 Lo que aprendimos de las memorias de terminal
109
-
110
- dsh-memento no es un port de Claude Code, Codex ni Hermes — pero su diseño absorbió deliberadamente las partes que cada uno hizo bien y rechazó las que hacen daño:
111
-
112
- | Memoria de terminal | Qué hizo bien | Qué adoptó dsh-memento |
113
- | --- | --- | --- |
114
- | **Claude Code** — `CLAUDE.md` | **archivos de memoria en texto plano** jerárquicos (nivel usuario → nivel proyecto), legibles y editables por humanos, y combinados automáticamente en cada sesión — memoria que puedes leer y corregir tú mismo | entradas en texto plano; capas `user-global` / `workspace` combinadas por sesión; un almacén que puedes navegar, `export` y auditar — la transparencia como característica |
115
- | **Codex** — `AGENTS.md` | **instrucciones con alcance por directorio** autodescubiertas e inyectadas sin fricción del modelo — la localidad importa más que el volumen; no hace falta llamada de herramienta para "cargar" memoria | capa `workspace` vinculada al cwd de la sesión (insensible a mayúsculas en Windows); la instantánea congelada se inyecta automáticamente al inicio de la sesión |
116
- | **Hermes** — `memory.md` | **guardados de memoria proactivos** (guardar/actualizar/borrar) y, en el [issue #48181](https://github.com/NousResearch/hermes-agent/issues/48181), la lección de seguridad de que una puerta impuesta solo en la capa de herramientas es eludible mediante inyección tardía de herramientas — hay que imponerla donde convergen todas las rutas de escritura | la herramienta `memory` con guía explícita Guardar/Omitir + propuestas de auto-captura con puerta de aprobación; la puerta de aprobación vive **dentro** de los métodos de escritura de `ctx.memory`, no en la capa de herramientas |
117
-
118
- Fuentes: [memoria de Claude Code](https://code.claude.com/docs/en/memory) · [AGENTS.md de Codex](https://developers.openai.com/codex/cli/agents-md) · [memoria de Hermes](https://github.com/NousResearch/hermes-agent/blob/main/website/docs/user-guide/features/memory.md) · [Hermes #48181](https://github.com/NousResearch/hermes-agent/issues/48181).
119
-
120
- Y las partes que rechazamos deliberadamente: la auto-resumición oculta en estado privado del modelo (aquí los resúmenes de compactación se convierten en **propuestas pendientes** que esperan un aprobar/descartar humano), las ambiciones de almacén/vectorial, y cualquier escritura sin aprobación o rastro de auditoría visible para el humano. También adoptamos la advertencia documentada de Hermes: dos procesos que comparten un directorio home escriben el mismo archivo de memoria — véase Límites de seguridad.
121
-
122
- ## 🆚 En qué se diferencia
123
-
124
- | Plugin | Qué es | La diferencia de dsh-memento |
125
- | --- | --- | --- |
126
- | dsh-memory-evolve | almacén de memoria / bucles de evolución | una costura de servicio tipado, puerta de aprobación y auditoría del registro de sesión; sin ambición de almacén |
127
- | dsh-mnemon | asistente de almacén de memoria | protocolo + puerta + auditoría, no otro almacén |
128
- | dsh-kb-sieve | cribado de base de conocimiento | sin ingeniería de recuperación: búsqueda por subcadena sobre un corpus pequeño, recuperación entre sesiones vía `session_search`/`sessionQuery` |
129
- | dsh-tdai-memory | herramientas de memoria dirigidas por tareas | los presupuestos son por pista×capa y se aplican en el servicio, no a mejor esfuerzo |
130
- | claude-bridge | puente con Claude Code | nativo de DSH; una futura ruta `seed(source:'claude')` permite que un puente alimente el mismo almacén |
131
- | dsh-external/Recall | memoria externa de agente | local primero, cero red, se apoya en la propia costura de aprobación de DSH |
132
- | Ejemplos oficiales de memoria MCP | la postura declarada de DSH de "memoria = MCP externo" | el complemento **nativo de primera parte**: mismo objetivo, sin servidor externo; ambos coexisten |
133
-
134
- El nombre es **`dsh-memento`** (publicado en npm y GitHub). No `dsh-recall` (confundible con dsh-external/Recall), ni el nombre heredado eliminado `dsh-memory`.
135
-
136
- ## 🔒 Límites de seguridad
137
-
138
- - **Solo servicios públicos** (`tools`, `systemPrompt`, la costura de aprobación). Sin cambios en el motor / agent-loop / apiproxy / UI oficial.
139
- - **Cero red, cero credenciales.** Base de datos local; modo de archivo POSIX `0600`.
140
- - **Falla de forma explícita.** Una base de datos corrupta o un esquema más nuevo falla al cargar; los presupuestos llenos y las coincidencias ambiguas de subcadena fallan con errores estructurados. Nada se traga ni se trunca en silencio.
141
- - **Un proceso, un almacén.** Varias sesiones en un proceso comparten el almacén SQLite (escrituras serializadas, auditoría por sesión). Dos **procesos** que comparten un `$DSH_HOME` escriben el mismo archivo: gana el último escritor bajo el bloqueo de SQLite — no ejecutes dos instancias del harness sobre un mismo `$DSH_HOME` si necesitas coherencia entre procesos (la misma advertencia que documenta el proyecto Hermes).
142
-
143
- ## ⚠️ Limitaciones conocidas
144
-
145
- - **El vocabulario de eventos de sesión está declarado, pero aún no se emite (rc.6).** `memory/added|updated|removed|recalled|snapshot` están declarados por fusión en `types.d.ts`, pero rc.6 no tiene superficie de registro para tipos de eventos fuera del repositorio (los appends no registrados harían que las sesiones persistidas no se pudieran cargar). La completitud de la auditoría proviene del par de aprobación + la tabla de auditoría; la emisión se activa automáticamente en cuanto una compilación del harness registre los tipos. Véase [ARCHITECTURE.md](ARCHITECTURE.md), decisión 4.
146
- - **La política `ask` necesita un contestador.** Sin un contestador de UI/ACP compuesto, las escrituras fallan en modo cerrado (`unavailable`): por diseño, la postura de fallo cerrado de la costura de aprobación.
147
- - **Sin índice FTS5.** La búsqueda por subcadena usa `instr` insensible a mayúsculas (correcto para CJK); el ranking de recuperación usa contadores de aciertos por entrada. El tokenizador trigram de FTS5 no puede indexar caracteres CJK de un solo carácter, así que no se usa — véase [ARCHITECTURE.md](ARCHITECTURE.md), decisión 10.
148
-
149
- ## 🧪 Desarrollo
150
-
151
- ```sh
152
- npm install
153
- npm test # node --test: 115 tests — budget, unique-substring, gate policy, store, snapshot, mock-ctx integration (S2/S3 invariants), V2 command/recall/panel/import
154
- npm run typecheck # puerta tsc --checkJs sobre index.mjs / lib / scripts
155
- npm run check:coverage # puerta de cobertura de líneas: lib ≥90 %, index.mjs ≥85 %, todos ≥90 %
156
- npm run check:readmes # puerta de coherencia de los cinco README
157
- ```
158
-
159
- `lib/` no tiene dependencias de DSH (solo builtins de node:); las importaciones de DSH solo existen en `index.mjs`. Disciplina completa en [AGENTS.md](AGENTS.md); decisiones de diseño en [ARCHITECTURE.md](ARCHITECTURE.md).
160
-
161
- ## 🏷 Temas
162
-
163
- Temas sugeridos para GitHub: `dsh` · `dsh-plugin` · `deepseek-harness` · `memory` · `agent-memory` · `approval` · `audit` · `sqlite` · `cordis` · `llm`
164
-
165
- ## 📄 Licencia
166
-
167
- Licencia Apache 2.0 — véase [LICENSE](LICENSE). No se redistribuye código de terceros; véase [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md).
1
+ <div align="center">
2
+
3
+ # dsh-memento
4
+
5
+ **Memoria entre sesiones acotada, por capas, con puerta de aprobación y auditable para DeepSeek Harness.**
6
+
7
+ *Una costura tipada `ctx.memory`, una puerta de aprobación de escritura que ninguna ruta del modelo puede eludir y pistas de auditoría reconstruibles desde el registro de sesión.*
8
+
9
+ [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE)
10
+ [![DSH plugin](https://img.shields.io/badge/dsh-plugin-✅-green)](https://github.com/topics/dsh-plugin)
11
+ [![Node](https://img.shields.io/badge/node-%5E22.19%20%7C%7C%20%3E%3D24-brightgreen.svg)](#)
12
+ [![CI](https://img.shields.io/github/actions/workflow/status/PerryLink/dsh-memento/ci.yml?branch=main&label=CI)](https://github.com/PerryLink/dsh-memento/actions)
13
+ [![Version](https://img.shields.io/github/v/tag/PerryLink/dsh-memento?label=version)](https://github.com/PerryLink/dsh-memento/releases)
14
+ [![npm version](https://img.shields.io/npm/v/dsh-memento)](https://www.npmjs.com/package/dsh-memento)
15
+ [![npm downloads](https://img.shields.io/npm/dm/dsh-memento)](https://www.npmjs.com/package/dsh-memento)
16
+
17
+ [English](README.md) · [简体中文](README.zh.md) · [Español](README.es.md) · [Português](README.pt.md) · [हिन्दी](README.hi.md)
18
+
19
+ </div>
20
+
21
+ ---
22
+
23
+ ## Compatibility
24
+
25
+ | Surface | Status |
26
+ |---|---|
27
+ | Harness | DeepSeek Harness `0.1.0-rc.6` |
28
+ | Node | `^22.19.0 || >=24.0.0` |
29
+ | Platforms | Windows / macOS / Linux (solo host; sin código nativo, sin red) |
30
+ | Model | Cualquiera |
31
+
32
+ ## What you get
33
+
34
+ `dsh-memento` es una costura de capacidad, no otro almacén: un servicio tipado `ctx.memory`, un proveedor SQLite local (`node:sqlite`, WAL, `0600`, en `$DSH_HOME/dsh-memento/memory.db`) y sus consumidores — la herramienta `memory` y una instantánea congelada inyectada en el prompt del sistema.
35
+
36
+ - **La puerta no se puede eludir.** Toda ruta de escritura (`add` / `replace` / `remove` / `seed`) se fuerza a través de la cascada de aprobación dentro del servicio, no en la capa de herramientas. `writePolicy: ask | auto | off` es configuración invisible para el modelo; `replace` / `remove` / `consolidate` llevan el texto completo de las entradas que cambian en el payload de aprobación, y una escritura denegada deja igualmente una fila de auditoría `*-denied`.
37
+ - **Visible para el modelo ⟺ registrado.** La instantánea inyectada llega textualmente a `request/header.system`; cada escritura es reconstruible a partir de `approval/asked` + `approval/decided` + la propia tabla de auditoría del plugin.
38
+ - **Acotada y honesta.** Presupuestos estrictos de caracteres por pista y por capa (por defecto usuario 2000 / agente 4000). Un almacén lleno falla con un error estructurado (uso + límite): nunca se trunca, nunca se compacta automáticamente.
39
+
40
+ Dos pistas × dos capas × clave por agente: una pista `user` (hechos sobre el usuario) y una pista `agent` (hechos de entorno y convenciones), cada una dividida en capas `user-global` y `workspace`, aisladas por `agentPreset`. La instantánea se congela una vez por sesión en el primer ensamblado del prompt y nunca cambia a mitad de sesión.
41
+
42
+ ## Quick start
43
+
44
+ ```sh
45
+ # 1. install the bundle into your profile
46
+ dsh plugin --profile web add "github:PerryLink/dsh-memento#main"
47
+
48
+ # or from npm (published releases)
49
+ dsh plugin --profile web add dsh-memento
50
+
51
+ # 2. restart and verify the row
52
+ dsh --profile web --dump-config | grep -A3 'id: memento'
53
+ ```
54
+
55
+ ## Install & uninstall
56
+
57
+ - **canal git** (último `main`): `dsh plugin --profile web add git+https://github.com/PerryLink/dsh-memento.git`.
58
+ - **canal npm** (versiones publicadas): `dsh plugin --profile web add dsh-memento`.
59
+ - **canal tarball**: `npm pack` en este repo, luego `dsh plugin --profile web add ./dsh-memento-<version>.tgz`.
60
+ - **desinstalar**: `dsh plugin --profile web remove dsh-memento` (la base de datos de memoria y los registros de sesión se conservan).
61
+
62
+ ## Configuration
63
+
64
+ Todos los parámetros son campos Schemastery `Config` (modificables desde cordis.yml). Los valores inválidos fallan de forma ruidosa al cargar. Se sobrescriben bajo la fila `memento`.
65
+
66
+ | Key | Default | Meaning |
67
+ |---|---|---|
68
+ | `enabled` | `true` | Interruptor maestro; `false` elimina servicio, herramientas, instantánea, comando, panel y answerer |
69
+ | `dbPath` | `''` → `$DSH_HOME/dsh-memento/memory.db` | Absoluto, o relativo a `$DSH_HOME` (en Windows cae a `~/.dsh`) |
70
+ | `budgets.user.userGlobal` | `2000` | Presupuesto estricto de caracteres de la capa user-global de la pista user |
71
+ | `budgets.user.workspace` | `2000` | Presupuesto estricto de caracteres de la capa workspace de la pista user |
72
+ | `budgets.agent.userGlobal` | `4000` | Presupuesto estricto de caracteres de la capa user-global de la pista agent |
73
+ | `budgets.agent.workspace` | `4000` | Presupuesto estricto de caracteres de la capa workspace de la pista agent |
74
+ | `writePolicy` | `'ask'` | Política de escritura por defecto: `ask` / `auto` / `off` (invisible para el modelo) |
75
+ | `writePolicies` | `{}` | Sobrescrituras por pista/ámbito o por origen (p. ej. `user/workspace`, `source:claude`) |
76
+ | `language` | `'en'` | Idioma del texto visible y la salida del comando: `en` / `zh` |
77
+ | `snapshotOrder` | `-50` | Orden de la sección de instantánea (tras la identidad del harness, antes de persona) |
78
+ | `maxEntriesPerQuery` | `20` | Tope de resultados por consulta por defecto (límite duro 1000) |
79
+ | `commandListLimit` | `50` | Entradas mostradas por `/memory list` / `query` |
80
+ | `commandAuditLimit` | `10` | Filas de auditoría mostradas por `/memory audit` |
81
+ | `recall.historyLimitDefault` | `8` | Sesiones escaneadas por `memory_recall` por defecto |
82
+ | `recall.snippetCap` | `5` | Fragmentos por sesión en `memory_recall` |
83
+ | `recall.snippetChars` | `300` | Caracteres de fragmento en `memory_recall` |
84
+ | `recall.windowDays` | `30` | Ventana de antigüedad en días de `memory_recall` |
85
+ | `panelEntriesLimit` | `200` | Tamaño de página de entradas del panel web |
86
+ | `panelAuditLimit` | `20` | Filas de auditoría del panel web por defecto |
87
+ | `auditRetentionDays` | `0` | Retención de auditoría (0 = conservar para siempre) |
88
+ | `proposals.enabled` | `true` | Capturar automáticamente una propuesta de memoria tras cada compactación exitosa |
89
+ | `proposals.maxChars` | `2000` | Tope de caracteres de la propuesta |
90
+ | `proposals.maxPending` | `8` | Tope de propuestas pendientes |
91
+
92
+ ## Tools & surfaces
93
+
94
+ | Surface | Kind | Notes |
95
+ |---|---|---|
96
+ | `memory` | tool | add/replace/remove/consolidate/query con guía Save/Skip; las escrituras pasan por la puerta de aprobación |
97
+ | `memory_recall` | tool | Coincidencias acotadas de memoria más coincidencias recientes del historial de sesión |
98
+ | `/memory` | command | `list` · `query` · `add` · `remove` · `consolidate` · `proposals` · `budgets` · `audit` · `export` · `import <path>` · `adapters` |
99
+ | web panel | client drawer | Solo lectura: explorar entradas, buscar, barras de presupuesto, cola de auditoría |
100
+
101
+ ## How it's different
102
+
103
+ | Plugin | Qué es | La diferencia de dsh-memento |
104
+ |---|---|---|
105
+ | dsh-memory-evolve | almacén de memoria / bucles de evolución | una costura de servicio tipada, puerta de aprobación y auditoría de registro de sesión; sin ambición de almacén |
106
+ | dsh-mnemon | ayudante de almacén de memoria | protocolo + puerta + auditoría, no otro almacén |
107
+ | dsh-kb-sieve | tamizado de base de conocimiento | sin ingeniería de recuperación: búsqueda por subcadena en corpus pequeño, recall entre sesiones vía `session_search`/`sessionQuery` |
108
+ | dsh-tdai-memory | herramientas de memoria dirigidas por tarea | los presupuestos son por track×capa y se aplican en el servicio, no a mejor esfuerzo |
109
+ | claude-bridge | puente de Claude Code | nativo de DSH; una futura ruta `seed(source:'claude')` deja que un puente alimente el mismo almacén |
110
+ | dsh-external/Recall | memoria de agente externa | local primero, cero red, usa la propia costura de aprobación de DSH |
111
+ | Official MCP memory examples | la posición declarada de DSH de "memoria = MCP externo" | el complemento **nativo de primera parte**: mismo objetivo, sin servidor externo; ambos coexisten |
112
+
113
+ El nombre es **`dsh-memento`** (publicado en npm y GitHub). No `dsh-recall` (confundible con dsh-external/Recall), no el nombre heredado eliminado `dsh-memory`.
114
+
115
+ ## dsh-memory-protocol v1
116
+
117
+ `dsh-memento` es el ensayo comunitario del protocolo de memoria DSH — una forma candidata para una costura oficial `ctx.memory`. El protocolo normaliza la costura de este plugin en un contrato entre plugins:
118
+
119
+ - **Entry spec** — dos pistas × dos capas × clave por agente, más `tags` cortos (≤16 × ≤32 caracteres) y un `version` por entrada que se incrementa en cada `replace`.
120
+ - **Write semantics** — escrituras condicionales idempotentes por subcadena única; payloads de aprobar-lo-que-se-ve (`replace` / `remove` / `consolidate` llevan el texto completo que cambian).
121
+ - **Audit contract** — cada escritura reconstruible desde `approval/asked` + `approval/decided` + el libro mayor del proveedor.
122
+ - **Budget model** — semántica `BUDGET_EXCEEDED` / `AMBIGUOUS_MATCH`.
123
+ - **Schema versioning** — reglas de migración con verificaciones de versión ruidosas.
124
+
125
+ - **Spec** — [docs/protocol-v1.md](docs/protocol-v1.md) (中文: [protocol-v1.zh.md](docs/protocol-v1.zh.md)); JSON Schema normativo en [docs/schemas/dsh-memory-protocol-v1.schema.json](docs/schemas/dsh-memory-protocol-v1.schema.json).
126
+
127
+ **Registro de adaptadores** — `ctx.memoryAdapters` (`register` / `list` / `adapt` / `export`) permite a plugins de memoria de terceros hablar el protocolo registrando un convertidor de datos puro (`register()` reversible; la importación usa el `seed` con puerta de aprobación, la exportación es de solo lectura). Incorporación: [docs/adapters-guide.md](docs/adapters-guide.md) (中文: [adapters-guide.zh.md](docs/adapters-guide.zh.md)).
128
+
129
+ | Built-in adapter | External format | Notes |
130
+ |---|---|---|
131
+ | `mem0` | colecciones de hechos mem0 (`{facts: [{memory, metadata?}]}`) | `metadata.category` / `metadata.tags` se convierten en tags; los arrays `messages` crudos se rechazan — los adaptadores convierten, nunca extraen |
132
+ | `hermes-memory-md` | `memory.md` de Hermes (`## section` + viñetas) | los nombres de sección se convierten en tags; la prosa sin viñetas falla ruidosamente |
133
+ | `claude-code-memory-md` | markdown estilo `CLAUDE.md` (encabezados, viñetas, párrafos) | las viñetas y párrafos se convierten en entradas; los nombres de sección se convierten en tags |
134
+
135
+ **Suite de conformidad** — [test/protocol-conformance/](test/protocol-conformance/README.md): un conjunto de casos distribuible que cualquier proveedor que reclame compatibilidad ejecuta (`node test/protocol-conformance/run.mjs --provider ./your-factory.mjs`); el CI de este repo lo ejecuta contra su propio proveedor como referencia dorada (`npm run test:conformance`).
136
+
137
+ - **Upstream proposal** — [docs/upstream-proposal.md](docs/upstream-proposal.md) (中文: [upstream-proposal.zh.md](docs/upstream-proposal.zh.md)): por qué la costura oficial `ctx.memory` debería adoptar el protocolo, las diferencias y la ruta de migración.
138
+
139
+ ## Permissions & data
140
+
141
+ - **Permissions**: el manifiesto de workshop declara `harness:tool`, `filesystem:read`, `filesystem:write` y `network:none` / `subprocess:none` / `shell:none` / `python:none` / `credentials:none`. La aprobación de escritura usa la costura oficial de aprobación.
142
+ - **Data**: base de datos SQLite local (`0600`), cero red, cero credenciales.
143
+ - **Session log**: la completitud de auditoría proviene del par de aprobación (`approval/asked` + `approval/decided`) más la tabla de auditoría del plugin.
144
+
145
+ ## Security boundaries
146
+
147
+ - **Solo servicios públicos.** Consume `tools`, `systemPrompt` y la costura de aprobación; sin cambios en engine / agent-loop / apiproxy / UI oficial.
148
+ - **Cero red, cero credenciales.** Base de datos local con modo de archivo POSIX `0600`.
149
+ - **Fallo ruidoso.** Base de datos corrupta, esquema más nuevo o configuración inválida falla al cargar; presupuestos llenos y coincidencias de subcadena ambiguas fallan con errores estructurados.
150
+ - **Un proceso, un almacén.** Varias sesiones comparten el almacén SQLite; dos procesos que comparten un `$DSH_HOME` escriben el mismo archivo (último escritor gana bajo el bloqueo de SQLite).
151
+
152
+ ## Known limitations
153
+
154
+ - **Los eventos de sesión están declarados, aún no emitidos (rc.6).** `memory/added|updated|removed|recalled|snapshot` están declarados por fusión, pero rc.6 no tiene superficie de registro para tipos de evento fuera del repo; la emisión se activa cuando una build del harness los registre.
155
+ - **La política `ask` necesita un answerer.** Sin un answerer UI/ACP compuesto, las escrituras fallan cerradas.
156
+ - **Sin indexado FTS5.** La búsqueda por subcadena usa `instr` insensible a mayúsculas (correcto para CJK).
157
+
158
+ ## What we learned from the terminal memories
159
+
160
+ `dsh-memento` no es un port de Claude Code, Codex o Hermes — pero su diseño absorbió deliberadamente las partes que cada uno hizo bien, y rechazó las que dañaban:
161
+
162
+ | Terminal memory | Lo que hizo bien | Lo que dsh-memento adoptó |
163
+ |---|---|---|
164
+ | **Claude Code** — `CLAUDE.md` | archivos de memoria en texto plano jerárquicos (nivel usuario → nivel proyecto), legibles y editables por humanos, fusionados automáticamente en cada sesión | entradas en texto plano; capas `user-global` / `workspace` fusionadas por sesión; un almacén que puedes explorar, `export` y auditar — transparencia como característica |
165
+ | **Codex** — `AGENTS.md` | instrucciones con ámbito por directorio auto-descubiertas e inyectadas con fricción cero para el modelo | la capa `workspace` indexada por el cwd de la sesión (insensible a mayúsculas en Windows); la instantánea congelada inyectada automáticamente al iniciar la sesión |
166
+ | **Hermes** — `memory.md` | guardados de memoria proactivos y la lección de seguridad de que una puerta aplicada solo en la capa de herramientas es eludible por inyección tardía de herramientas | la herramienta `memory` con guía Save/Skip + propuestas de auto-captura con puerta de aprobación; la puerta vive dentro de los métodos de escritura de `ctx.memory`, no en la capa de herramientas |
167
+
168
+ Fuentes: [Claude Code memory](https://code.claude.com/docs/en/memory) · [Codex AGENTS.md](https://developers.openai.com/codex/cli/agents-md) · [Hermes memory](https://github.com/NousResearch/hermes-agent/blob/main/website/docs/user-guide/features/memory.md) · [Hermes #48181](https://github.com/NousResearch/hermes-agent/issues/48181).
169
+
170
+ Y las partes deliberadamente rechazadas: la auto-resumación oculta hacia estado privado del modelo (los resúmenes de compactación aquí se convierten en **propuestas pendientes** que esperan un approve/dismiss humano), las ambiciones de almacén/vector-store, y cualquier escritura sin aprobación o rastro de auditoría visible para humanos. También adoptado: la advertencia documentada de Hermes de que dos procesos que comparten un directorio home escriben el mismo archivo de memoria — véase Security boundaries.
171
+
172
+ ## Development
173
+
174
+ ```sh
175
+ npm install # node ^22.19 || >=24
176
+ npm test # node --test: 133 tests
177
+ npm run test:conformance # dsh-memory-protocol v1 conformance suite
178
+ npm run typecheck # tsc --checkJs gate
179
+ npm run check:coverage # line-coverage gate
180
+ npm run check:readmes # five-language README consistency gate
181
+ ```
182
+
183
+ `lib/` tiene cero dependencias de DSH (solo builtins de node:); las importaciones de DSH solo existen en `index.mjs`.
184
+
185
+ ## Topics
186
+
187
+ `dsh`, `dsh-plugin`, `deepseek-harness`, `memory`, `agent-memory`, `approval`, `audit`, `sqlite`, `cordis`, `llm`
188
+
189
+ ## Contributors
190
+
191
+ - [@Niuniu-Sir](https://github.com/Niuniu-Sir) — el informe de fallo de arranque en [issue #1](https://github.com/PerryLink/dsh-memento/issues/1) que llevó al fallback `~/.dsh` incluido en 0.3.1.
192
+
193
+ ## PerryLink DSH Plugin Family
194
+
195
+ Este proyecto es uno de los [15 plugins de DeepSeek Harness](https://github.com/PerryLink) mantenidos por [PerryLink](https://github.com/PerryLink). Si este te ayuda, los demás probablemente también:
196
+
197
+ | Plugin | One-liner |
198
+ |---|---|
199
+ | [dsh-mcp-panel](https://github.com/PerryLink/dsh-mcp-panel) | Read-only MCP runtime panel: /mcp command + Settings tab with status, tools and errors |
200
+ | [dsh-doublecheck](https://github.com/PerryLink/dsh-doublecheck) | Engineering-discipline guard: requirements grill, test gates, adversary review |
201
+ | [dsh-background-agents](https://github.com/PerryLink/dsh-background-agents) | Durable background child agents with a Web UI sidebar, messaging and interrupt |
202
+ | [dsh-lsp-actions](https://github.com/PerryLink/dsh-lsp-actions) | LSP diagnostics, formatting, completion, code actions and rename over language servers |
203
+ | [dsh-output-styles](https://github.com/PerryLink/dsh-output-styles) | Claude Code outputStyles-equivalent runtime style switching |
204
+ | [dsh-checkpoint-rewind](https://github.com/PerryLink/dsh-checkpoint-rewind) | Claude Code /rewind-equivalent: snapshots, session forks, one-shot restore |
205
+ | [dsh-permission-rules](https://github.com/PerryLink/dsh-permission-rules) | Claude Code-style declarative allow/deny/ask permission rules with audit |
206
+ | [dsh-auto-review](https://github.com/PerryLink/dsh-auto-review) | Second-model auto-review on the approval chain, fail-closed by default |
207
+ | **[dsh-memento](https://github.com/PerryLink/dsh-memento)** | Approval-gated cross-session memory: ctx.memory seam + SQLite + memory tool |
208
+ | [dsh-skill-pack-security](https://github.com/PerryLink/dsh-skill-pack-security) | Security-audit skill pack: secret scan, dependency and supply-chain review |
209
+ | [dsh-session-pin](https://github.com/PerryLink/dsh-session-pin) | Pin sessions in the Web sidebar with durable ordering |
210
+ | [dsh-composer-history](https://github.com/PerryLink/dsh-composer-history) | Terminal-style input history for the web composer: arrows, Ctrl+R search |
211
+ | [dsh-github](https://github.com/PerryLink/dsh-github) | GitHub PR/issues integration for DSH, every write gated by approval |
212
+ | [dsh-plugin-guide](https://github.com/PerryLink/dsh-plugin-guide) | Plugin-development knowledge base as an on-demand agent skill |
213
+ | [dsh-claude-move](https://github.com/PerryLink/dsh-claude-move) | Migrate Claude Code sessions, memory, skills and CLAUDE.md into DSH |
214
+
215
+ ## License
216
+
217
+ [Apache License 2.0](LICENSE) © 2026 dsh-memento contributors