dsh-prime-memory 0.26.11 → 0.26.13

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 CHANGED
@@ -1,5 +1,21 @@
1
1
  # 更新日志(Changelog)
2
2
 
3
+ ## [0.26.13] — 2026-10-28
4
+
5
+ > 修复 issue #19:单条 L1 priority 越界(如 LLM 回 `-1`)经无夹取写点落库后,`memoryRecall` 投影的 `viewSchema` 严格校验(判非负整数)抛错 → 宿主把整会话包成 `SESSION_QUERY_CORRUPT_SESSION` → **一条脏数据打死整个会话历史**。
6
+
7
+ ### 修复
8
+
9
+ - **双防线**:
10
+ - **写侧夹取(防新增)**:新建 `src/util/priority.ts` 单源 `clampPriority`(非有限→回落缺省、小数 `Math.round`、夹到整数 `[0,100]`),L1 抽取/合并构造(`pipeline/l1.ts` 两处)、upsert 绑定层(`store/sqlite.ts`,保留历史缺省 50)、MD 导入解析(`store/memory-md-parse.ts`)统一走同一夹取。
11
+ - **读侧兜底(自愈存量)**:投影 `makeView` 遇脏 priority 就地夹取并 `warn`(带 record id + 原值),绝不让单条脏字段打死整会话。因升级必重启宿主、`viewMemo`(进程内 WeakMap)随之清空,脏行读时被夹取 → **存量脏数据无需手动改库、无需迁移**。
12
+ - 保留 `viewSchema` 严格校验(纵深防御仍在,只是喂进去的已是干净值);合法 0–100 整数读写逐字不变;`slots.ts` 的同名私有 `clampPriority`(floor/50,memorySlots 另一条链)不受影响。
13
+ - 本版叠加在 0.26.12(DSH 0.2.1-rc.4 适配)之上,`latest` 与 `dsh-0.2.1-rc.4` dist-tag 同指本版。
14
+
15
+ ## [0.26.12] — 2026-10-28
16
+
17
+ > 0.26.12: host enumeration addendum for DSH 0.2.1-rc.4 (declaration-only bump; contract plane zero diff). `engines.dsh`/`dsh.plugin.json`/README 同串补 `0.2.1-rc.4` 枚举行(19 档)。
18
+
3
19
  ## [0.26.11] — 2026-10-27
4
20
 
5
21
  > 本版闭环三条外部 issue:#12(两级 Room slug 写不进)、#13(默认路由表硬编码作者本机路径)、#14(重建以已写停的 L0 为事实源)、#16(图谱投影只有配置文件开关)。
package/INSTALL.de.md ADDED
@@ -0,0 +1,92 @@
1
+ # Installationsanleitung (dsh-prime-memory)
2
+
3
+ Dieses Plugin wird als **offizielles DSH-Bundle** ausgeliefert: Nach der Installation mountet die `dsh.bundle`-Schicht in `cordis.patch.yml` den Plugin-Eintrag automatisch — manuelle Profilbearbeitung ist nicht erforderlich.
4
+
5
+ ## Voraussetzungen
6
+
7
+ - Node.js ≥ 22.16 (DSH 0.2.0-rc.1 oder neuer)
8
+ - DeepSeek Harness (im Folgenden DSH) installiert, mit verfügbarem `--profile web`
9
+
10
+ ## Installation
11
+
12
+ Wählen Sie eine der folgenden Aufrufarten (das Präfix `npx` kann in jedem der folgenden Befehle `dsh` ersetzen):
13
+
14
+ ```bash
15
+ # Variante 1: offizielle CLI direkt per npx ausführen (kein vorinstalliertes dsh nötig; Version kann gepinnt werden, z. B. dsh-prime-memory@0.8.4)
16
+ npx -y @deepseek-ai/dsh plugin --profile web add dsh-prime-memory
17
+
18
+ # Variante 2: mit installierter dsh-CLI (dsh ist ein pnpm-Forwarder; falls pnpm fehlt, zuerst npm i -g pnpm)
19
+ dsh plugin --profile web add dsh-prime-memory
20
+
21
+ # Alternative Paketquellen: GitHub-Repository / lokaler Pfad (Entwicklung/Debug; link: verweist auf das Repository, npm run build + dsh-Neustart genügt)
22
+ dsh plugin --profile web add https://github.com/drscrewdriver/dsh-prime-memory
23
+ dsh plugin --profile web add /path/to/dsh-prime-memory
24
+ ```
25
+
26
+ ### Installation durch den Agenten (empfohlen)
27
+
28
+ Senden Sie die folgende Nachricht unverändert an den aktuellen Agenten (sofern er Terminalbefehle ausführen kann):
29
+
30
+ ```text
31
+ Bitte installiere das Plugin dsh-prime-memory für das Web-Profil von DeepSeek Harness.
32
+
33
+ Führe ausschließlich die beiden folgenden Befehle aus und ändere keine anderen Profile:
34
+ dsh plugin --profile web add dsh-prime-memory
35
+ dsh --profile web --dump-config
36
+
37
+ Sobald dsh-prime-memory in der Ausgabe erscheint, melde mir das Installationsergebnis.
38
+ Beende oder starte den laufenden DSH nicht selbst neu; erinnere mich nach der Installation daran, den DSH Web Host manuell neu zu starten.
39
+ ```
40
+
41
+ ## Update
42
+
43
+ ```bash
44
+ # Auf die neueste Version aktualisieren
45
+ dsh plugin --profile web update dsh-prime-memory
46
+
47
+ # Auf eine bestimmte Version aktualisieren
48
+ dsh plugin --profile web update dsh-prime-memory@0.8.11
49
+ ```
50
+
51
+ Ein Update ersetzt nur den Plugin-Code und die `dist/`-Artefakte; das Datenverzeichnis `~/.dsh/memory/` bleibt unberührt.
52
+
53
+ ## Verifikation
54
+
55
+ Prüfen Sie nach der Installation und dem Neustart des DSH Web Host:
56
+
57
+ 1. **Das Datenverzeichnis entsteht** — das Plugin wurde erfolgreich angewendet: unter `~/.dsh/memory/` erscheinen die Verzeichnisse `conversations/`, `records/`, `scenes/` sowie `memory.db`;
58
+ 2. **Die Seite „Memory" erscheint in den Einstellungen** und das Modus-Pill erscheint in der Eingabeleiste — die Client-Hälfte ist bereit;
59
+ 3. Schicken Sie eine Nachricht mit persönlichen Informationen, warten Sie die Destillation ab und fragen Sie in einem späteren Zug danach: Im Kontext sollte die Zeile „Kontextinjektion · memory" erscheinen.
60
+
61
+ Optionaler Rauchtest (Entwicklung/Fehlerdiagnose):
62
+
63
+ ```bash
64
+ npm run build
65
+ npx tsc src/smoke.ts --outDir dist-smoke --module nodenext --moduleResolution nodenext --target es2022 --strict --skipLibCheck --esModuleInterop
66
+ node dist-smoke/smoke.js
67
+ ```
68
+
69
+ ## Migration / Downgrade
70
+
71
+ - **Migration von der alten Version (vor 0.5.0 hieß das Paket `dsh-memory-plugin`)**: Das alte Datenverzeichnis ist mit dem neuen Paket inkompatibel; sichern Sie es und löschen Sie `~/.dsh/memory/` — es wird beim ersten Start des neuen Plugins neu aufgebaut. Bestehende Erinnerungen können nicht direkt übernommen werden, sie müssen neu destilliert werden.
72
+ - **Zurück zur alten Version**: Nach `dsh plugin --profile web remove dsh-prime-memory` gemäß der Dokumentation der alten Version neu installieren; das Datenverzeichnis bleibt erhalten, aber die alte Version erkennt die neue Struktur nicht — eine Bereinigung wird empfohlen.
73
+
74
+ ## Deinstallation
75
+
76
+ ```bash
77
+ dsh plugin --profile web remove dsh-prime-memory
78
+ ```
79
+
80
+ Die Daten bleiben in `~/.dsh/memory/`; löschen Sie bei Bedarf das gesamte Verzeichnis von Hand.
81
+
82
+ ## Fehlerbehebung
83
+
84
+ | Symptom | Wahrscheinliche Ursache | Lösung |
85
+ | --- | --- | --- |
86
+ | Nach der Installation fehlt die Seite „Memory" in den Einstellungen | DSH nicht neu gestartet / Bundle nicht gemountet | DSH Web Host neu starten; mit `dsh --profile web --dump-config` prüfen, dass `dsh-prime-memory` enthalten ist |
87
+ | `duplicate loader entry id` beim Neustart | ein manuell hinzugefügtes `insert:` kollidiert mit dem Bundle-Eintrag gleicher id | Das manuell hinzugefügte `insert:`-Element entfernen; das Paket bringt seine Bundle-Schicht bereits mit |
88
+ | Keine Zeile „Kontextinjektion · memory" | Destillation nicht gelaufen / Recall deaktiviert | Prüfen, dass der Modus nicht off und `recall.enabled=true` ist; in `memory.log` nach `L1 阶段完成` suchen |
89
+ | Download des lokalen Embedding-Modells hängt | Mirror direkt nicht erreichbar | `embedding.proxy` setzen, um über einen Proxy zu gehen; oder `embedding.mirror` auf das offizielle `huggingface.co` umstellen |
90
+ | Remote-Embedding meldet 401 | apiKey falsch / schlüsselloser Dienst darf keinen Key erhalten | `embedding.apiKey` prüfen; bei einem selbst gehosteten Dienst ohne Key apiKey leer lassen |
91
+
92
+ Mehr dazu in [README.md](./README.md) und [CHANGELOG.md](./CHANGELOG.md).
package/INSTALL.es.md ADDED
@@ -0,0 +1,92 @@
1
+ # Guía de instalación (dsh-prime-memory)
2
+
3
+ Este plugin se distribuye como **bundle oficial de DSH**: tras la instalación, la capa `dsh.bundle` de `cordis.patch.yml` monta automáticamente la entrada del plugin; no hace falta editar a mano ningún perfil.
4
+
5
+ ## Requisitos
6
+
7
+ - Node.js ≥ 22.16 (DSH 0.2.0-rc.1 o superior)
8
+ - DeepSeek Harness (en adelante DSH) instalado, con `--profile web` disponible
9
+
10
+ ## Instalación
11
+
12
+ Elige el modo de invocación que prefieras (el prefijo `npx` puede sustituir a `dsh` en cualquiera de los comandos siguientes):
13
+
14
+ ```bash
15
+ # Modo 1: ejecutar la CLI oficial directamente con npx (no requiere dsh preinstalado; se puede fijar la versión, p. ej. dsh-prime-memory@0.8.4)
16
+ npx -y @deepseek-ai/dsh plugin --profile web add dsh-prime-memory
17
+
18
+ # Modo 2: con la CLI dsh ya instalada (dsh es un reenviador de pnpm; si no tienes pnpm, antes npm i -g pnpm)
19
+ dsh plugin --profile web add dsh-prime-memory
20
+
21
+ # Fuentes alternativas del paquete: repositorio de GitHub / ruta local (desarrollo y depuración; link: apunta al repositorio, basta npm run build + reiniciar dsh)
22
+ dsh plugin --profile web add https://github.com/drscrewdriver/dsh-prime-memory
23
+ dsh plugin --profile web add /path/to/dsh-prime-memory
24
+ ```
25
+
26
+ ### Dejar que el agente instale (recomendado)
27
+
28
+ Envía tal cual el siguiente mensaje al agente actual (siempre que pueda ejecutar comandos de terminal):
29
+
30
+ ```text
31
+ Instala el plugin dsh-prime-memory para el perfil web de DeepSeek Harness.
32
+
33
+ Ejecuta solo los dos comandos siguientes y no modifiques otros perfiles:
34
+ dsh plugin --profile web add dsh-prime-memory
35
+ dsh --profile web --dump-config
36
+
37
+ Cuando aparezca dsh-prime-memory en la salida, infórmame del resultado de la instalación.
38
+ No cierres ni reinicies por tu cuenta el DSH en ejecución; cuando termine la instalación, recuérdame que reinicie manualmente el DSH Web Host.
39
+ ```
40
+
41
+ ## Actualización
42
+
43
+ ```bash
44
+ # Actualizar a la última versión
45
+ dsh plugin --profile web update dsh-prime-memory
46
+
47
+ # Actualizar a una versión concreta
48
+ dsh plugin --profile web update dsh-prime-memory@0.8.11
49
+ ```
50
+
51
+ La actualización solo reemplaza el código del plugin y los artefactos de `dist/`; el directorio de datos `~/.dsh/memory/` no se ve afectado.
52
+
53
+ ## Verificación
54
+
55
+ Tras instalar y reiniciar el DSH Web Host, comprueba:
56
+
57
+ 1. **Aparece el directorio de datos** — el plugin se aplicó correctamente: bajo `~/.dsh/memory/` aparecen los directorios `conversations/`, `records/`, `scenes/` y el archivo `memory.db`;
58
+ 2. **Aparece la página «Memoria» en los ajustes** y en la barra de entrada aparece la píldora de modo — la mitad cliente está lista;
59
+ 3. Envía un mensaje con información personal, espera a que termine la destilación y pregunta por ello en otro turno de conversación: en el contexto debería verse la línea «Inyección de contexto · memory».
60
+
61
+ Smoke test opcional (desarrollo/diagnóstico):
62
+
63
+ ```bash
64
+ npm run build
65
+ npx tsc src/smoke.ts --outDir dist-smoke --module nodenext --moduleResolution nodenext --target es2022 --strict --skipLibCheck --esModuleInterop
66
+ node dist-smoke/smoke.js
67
+ ```
68
+
69
+ ## Migración / retroceso
70
+
71
+ - **Migrar desde la versión antigua (antes de 0.5.0 se llamaba `dsh-memory-plugin`)**: el directorio de datos antiguo es incompatible con el paquete nuevo; haz una copia de seguridad y borra `~/.dsh/memory/`, el nuevo plugin la reconstruirá en su primer arranque. Las memorias existentes no se pueden actualizar directamente: hay que volver a destilarlas.
72
+ - **Volver a la versión antigua**: tras `dsh plugin --profile web remove dsh-prime-memory`, reinstala siguiendo la documentación de la versión antigua; el directorio de datos se conserva, pero la versión antigua no reconoce la nueva estructura; conviene limpiarlo.
73
+
74
+ ## Desinstalación
75
+
76
+ ```bash
77
+ dsh plugin --profile web remove dsh-prime-memory
78
+ ```
79
+
80
+ Los datos permanecen en `~/.dsh/memory/`; si ya no los necesitas, borra todo el directorio a mano.
81
+
82
+ ## Resolución de problemas
83
+
84
+ | Síntoma | Causa probable | Solución |
85
+ | --- | --- | --- |
86
+ | Tras la instalación no aparece la página «Memoria» en los ajustes | DSH sin reiniciar / bundle sin montar | Reinicia el DSH Web Host; con `dsh --profile web --dump-config` comprueba que aparece `dsh-prime-memory` |
87
+ | `duplicate loader entry id` al reiniciar | un `insert:` añadido a mano convive con la entrada bundle del mismo id | Elimina la entrada `insert:` añadida manualmente; el paquete ya incluye su propia capa bundle |
88
+ | No aparece la línea «Inyección de contexto · memory» | destilación sin ejecutar / recuerdo desactivado | Comprueba que el modo no es off y que `recall.enabled=true`; busca `L1 阶段完成` en `memory.log` |
89
+ | La descarga del modelo de embeddings local se queda colgada | el espejo no es accesible en conexión directa | Configura `embedding.proxy` para salir por un proxy; o cambia `embedding.mirror` al oficial `huggingface.co` |
90
+ | El embedding remoto da error 401 | apiKey errónea / servicio sin clave al que no hay que enviarla | Revisa `embedding.apiKey`; en un servicio autoalojado sin clave deja apiKey vacía |
91
+
92
+ Para más información, consulta [README.md](./README.md) y [CHANGELOG.md](./CHANGELOG.md).
package/INSTALL.fr.md ADDED
@@ -0,0 +1,92 @@
1
+ # Guide d'installation (dsh-prime-memory)
2
+
3
+ Ce plugin est distribué sous forme de **bundle officiel DSH** : après l'installation, la couche `dsh.bundle` de `cordis.patch.yml` monte automatiquement l'entrée du plugin — aucune modification manuelle du profil n'est nécessaire.
4
+
5
+ ## Prérequis
6
+
7
+ - Node.js ≥ 22.16 (DSH 0.2.0-rc.1 ou supérieur)
8
+ - DeepSeek Harness (ci-après DSH) installé, avec `--profile web` disponible
9
+
10
+ ## Installation
11
+
12
+ Choisissez librement l'un des modes d'invocation suivants (le préfixe `npx` peut remplacer `dsh` dans n'importe laquelle des commandes ci-dessous) :
13
+
14
+ ```bash
15
+ # Méthode 1 : lancer le CLI officiel directement via npx (pas besoin d'installer dsh au préalable ; la version peut être épinglée, ex. dsh-prime-memory@0.8.4)
16
+ npx -y @deepseek-ai/dsh plugin --profile web add dsh-prime-memory
17
+
18
+ # Méthode 2 : avec le CLI dsh installé (dsh est un relais pnpm ; si pnpm manque, commencez par npm i -g pnpm)
19
+ dsh plugin --profile web add dsh-prime-memory
20
+
21
+ # Sources de paquets alternatives : dépôt GitHub / chemin local (développement/débogage ; link: pointe vers le dépôt, npm run build + redémarrage de dsh suffisent)
22
+ dsh plugin --profile web add https://github.com/drscrewdriver/dsh-prime-memory
23
+ dsh plugin --profile web add /path/to/dsh-prime-memory
24
+ ```
25
+
26
+ ### Laisser l'agent installer (recommandé)
27
+
28
+ Envoyez tel quel le message ci-dessous à l'agent actuel (du moment qu'il peut exécuter des commandes de terminal) :
29
+
30
+ ```text
31
+ Veuillez installer le plugin dsh-prime-memory pour le profil web de DeepSeek Harness.
32
+
33
+ Exécutez uniquement les deux commandes suivantes, sans modifier d'autres profils :
34
+ dsh plugin --profile web add dsh-prime-memory
35
+ dsh --profile web --dump-config
36
+
37
+ Une fois que dsh-prime-memory apparaît dans la sortie, confirmez-moi le résultat de l'installation.
38
+ Ne fermez pas et ne redémarrez pas vous-même le DSH en cours d'exécution ; après l'installation, rappelez-moi de redémarrer manuellement le DSH Web Host.
39
+ ```
40
+
41
+ ## Mise à jour
42
+
43
+ ```bash
44
+ # Mettre à jour vers la dernière version
45
+ dsh plugin --profile web update dsh-prime-memory
46
+
47
+ # Mettre à jour vers une version donnée
48
+ dsh plugin --profile web update dsh-prime-memory@0.8.11
49
+ ```
50
+
51
+ La mise à jour ne remplace que le code du plugin et les artefacts de `dist/` ; le répertoire de données `~/.dsh/memory/` n'est pas affecté.
52
+
53
+ ## Vérification
54
+
55
+ Après l'installation et le redémarrage du DSH Web Host, vérifiez :
56
+
57
+ 1. **Le répertoire de données apparaît** — le plugin s'est appliqué avec succès : sous `~/.dsh/memory/` apparaissent les répertoires `conversations/`, `records/`, `scenes/` ainsi que `memory.db` ;
58
+ 2. **La page « Mémoire » apparaît dans les paramètres** et le pill de mode s'affiche dans la barre de saisie — la moitié client est prête ;
59
+ 3. Envoyez un message contenant des informations personnelles, attendez la fin de la distillation, puis demandez ces informations dans un autre tour de conversation : la ligne « Injection de contexte · memory » doit apparaître dans le contexte.
60
+
61
+ Test de fumée optionnel (développement/diagnostic) :
62
+
63
+ ```bash
64
+ npm run build
65
+ npx tsc src/smoke.ts --outDir dist-smoke --module nodenext --moduleResolution nodenext --target es2022 --strict --skipLibCheck --esModuleInterop
66
+ node dist-smoke/smoke.js
67
+ ```
68
+
69
+ ## Migration / retour à une version antérieure
70
+
71
+ - **Migration depuis l'ancienne version (nommée `dsh-memory-plugin` avant le 0.5.0)** : l'ancien répertoire de données est incompatible avec le nouveau paquet ; sauvegardez puis supprimez `~/.dsh/memory/`, il sera reconstruit au premier démarrage du nouveau plugin. Les mémoires existantes ne peuvent pas être mises à niveau directement, une re-distillation est nécessaire.
72
+ - **Revenir à l'ancienne version** : après `dsh plugin --profile web remove dsh-prime-memory`, réinstallez en suivant la documentation de l'ancienne version ; le répertoire de données est conservé, mais l'ancienne version ne reconnaît pas la nouvelle structure — un nettoyage est recommandé.
73
+
74
+ ## Désinstallation
75
+
76
+ ```bash
77
+ dsh plugin --profile web remove dsh-prime-memory
78
+ ```
79
+
80
+ Les données restent dans `~/.dsh/memory/` ; supprimez manuellement tout le répertoire si vous n'en avez plus besoin.
81
+
82
+ ## Dépannage
83
+
84
+ | Symptôme | Cause probable | Solution |
85
+ | --- | --- | --- |
86
+ | Aucune page « Mémoire » dans les paramètres après l'installation | DSH non redémarré / bundle non monté | Redémarrez le DSH Web Host ; vérifiez avec `dsh --profile web --dump-config` que `dsh-prime-memory` figure bien dans la configuration |
87
+ | `duplicate loader entry id` au redémarrage | un `insert:` ajouté manuellement coexiste avec l'entrée bundle de même id | Supprimez l'entrée `insert:` ajoutée à la main ; ce paquet embarque déjà sa couche bundle |
88
+ | Aucune ligne « Injection de contexte · memory » | distillation non exécutée / rappel désactivé | Vérifiez que le mode n'est pas off et que `recall.enabled=true` ; cherchez `L1 阶段完成` dans `memory.log` |
89
+ | Téléchargement du modèle d'embedding local bloqué | miroir inaccessible en connexion directe | Configurez `embedding.proxy` pour passer par un proxy ; ou remplacez `embedding.mirror` par l'officiel `huggingface.co` |
90
+ | Erreur 401 de l'embedding distant | apiKey erronée / service sans clé auquel il ne faut pas en envoyer | Vérifiez `embedding.apiKey` ; laissez apiKey vide pour un service auto-hébergé sans clé |
91
+
92
+ Pour aller plus loin, voir [README.md](./README.md) et [CHANGELOG.md](./CHANGELOG.md).
package/INSTALL.it.md ADDED
@@ -0,0 +1,92 @@
1
+ # Guida all'installazione (dsh-prime-memory)
2
+
3
+ Questo plugin è distribuito come **bundle ufficiale DSH**: dopo l'installazione, il livello `dsh.bundle` di `cordis.patch.yml` monta automaticamente la voce del plugin — non serve modificare a mano alcun profilo.
4
+
5
+ ## Requisiti
6
+
7
+ - Node.js ≥ 22.16 (DSH 0.2.0-rc.1 o superiore)
8
+ - DeepSeek Harness (di seguito DSH) installato, con `--profile web` disponibile
9
+
10
+ ## Installazione
11
+
12
+ Scegli liberamente uno dei modi di invocazione seguenti (il prefisso `npx` può sostituire `dsh` in qualsiasi comando qui sotto):
13
+
14
+ ```bash
15
+ # Modo 1: eseguire la CLI ufficiale direttamente con npx (niente dsh preinstallato; la versione può essere fissata, es. dsh-prime-memory@0.8.4)
16
+ npx -y @deepseek-ai/dsh plugin --profile web add dsh-prime-memory
17
+
18
+ # Modo 2: con la CLI dsh già installata (dsh è un inoltratore pnpm; se pnpm manca, prima npm i -g pnpm)
19
+ dsh plugin --profile web add dsh-prime-memory
20
+
21
+ # Sorgenti alternative del pacchetto: repository GitHub / percorso locale (sviluppo/debug; link: punta al repository, bastano npm run build + riavvio di dsh)
22
+ dsh plugin --profile web add https://github.com/drscrewdriver/dsh-prime-memory
23
+ dsh plugin --profile web add /path/to/dsh-prime-memory
24
+ ```
25
+
26
+ ### Far installare dall'agente (consigliato)
27
+
28
+ Invia tale e quale il messaggio seguente all'agente attuale (purché possa eseguire comandi da terminale):
29
+
30
+ ```text
31
+ Installa il plugin dsh-prime-memory per il profilo web di DeepSeek Harness.
32
+
33
+ Esegui solo i due comandi seguenti e non modificare altri profili:
34
+ dsh plugin --profile web add dsh-prime-memory
35
+ dsh --profile web --dump-config
36
+
37
+ Quando dsh-prime-memory compare nell'output, comunicami l'esito dell'installazione.
38
+ Non chiudere o riavviare di tua iniziativa il DSH in esecuzione; a installazione completata, ricordami di riavviare manualmente il DSH Web Host.
39
+ ```
40
+
41
+ ## Aggiornamento
42
+
43
+ ```bash
44
+ # Aggiornare all'ultima versione
45
+ dsh plugin --profile web update dsh-prime-memory
46
+
47
+ # Aggiornare a una versione specifica
48
+ dsh plugin --profile web update dsh-prime-memory@0.8.11
49
+ ```
50
+
51
+ L'aggiornamento sostituisce solo il codice del plugin e gli artefatti in `dist/`; la directory dei dati `~/.dsh/memory/` non viene toccata.
52
+
53
+ ## Verifica
54
+
55
+ Dopo l'installazione e il riavvio del DSH Web Host, controlla:
56
+
57
+ 1. **Compare la directory dei dati** — il plugin è stato applicato con successo: sotto `~/.dsh/memory/` compaiono le directory `conversations/`, `records/`, `scenes/` e il file `memory.db`;
58
+ 2. **La pagina «Memoria» compare nelle impostazioni** e il pill di modalità compare nella barra di input — la metà client è pronta;
59
+ 3. Invia un messaggio con informazioni personali, attendi la fine della distillazione e poi chiedine conto in un altro turno di conversazione: nel contesto dovrebbe comparire la riga «Iniezione di contesto · memory».
60
+
61
+ Smoke test opzionale (sviluppo/diagnostica):
62
+
63
+ ```bash
64
+ npm run build
65
+ npx tsc src/smoke.ts --outDir dist-smoke --module nodenext --moduleResolution nodenext --target es2022 --strict --skipLibCheck --esModuleInterop
66
+ node dist-smoke/smoke.js
67
+ ```
68
+
69
+ ## Migrazione / downgrade
70
+
71
+ - **Migrazione dalla vecchia versione (chiamata `dsh-memory-plugin` prima del 0.5.0)**: la vecchia directory dei dati è incompatibile col nuovo pacchetto; fai un backup e poi elimina `~/.dsh/memory/`, verrà ricostruita al primo avvio del nuovo plugin. Le memorie esistenti non possono essere aggiornate direttamente: serve una nuova distillazione.
72
+ - **Tornare alla vecchia versione**: dopo `dsh plugin --profile web remove dsh-prime-memory` reinstalla seguendo la documentazione della vecchia versione; la directory dei dati resta, ma la vecchia versione non riconosce la nuova struttura — si consiglia di ripulirla.
73
+
74
+ ## Disinstallazione
75
+
76
+ ```bash
77
+ dsh plugin --profile web remove dsh-prime-memory
78
+ ```
79
+
80
+ I dati restano in `~/.dsh/memory/`; se non servono più, elimina a mano l'intera directory.
81
+
82
+ ## Risoluzione dei problemi
83
+
84
+ | Sintomo | Causa probabile | Rimedio |
85
+ | --- | --- | --- |
86
+ | Dopo l'installazione manca la pagina «Memoria» nelle impostazioni | DSH non riavviato / bundle non montato | Riavvia il DSH Web Host; verifica con `dsh --profile web --dump-config` che ci sia `dsh-prime-memory` |
87
+ | `duplicate loader entry id` al riavvio | un `insert:` aggiunto a mano convive con la voce bundle di pari id | Elimina la voce `insert:` aggiunta manualmente; il pacchetto include già il suo livello bundle |
88
+ | Nessuna riga «Iniezione di contesto · memory» | distillazione non eseguita / richiamo disattivato | Verifica che la modalità non sia off e che `recall.enabled=true`; cerca `L1 阶段完成` in `memory.log` |
89
+ | Download del modello di embedding locale bloccato | mirror non raggiungibile in connessione diretta | Imposta `embedding.proxy` per passare da un proxy; oppure sostituisci `embedding.mirror` con l'ufficiale `huggingface.co` |
90
+ | Errore 401 dall'embedding remoto | apiKey errata / servizio senza chiave a cui non va inviata | Controlla `embedding.apiKey`; per un servizio self-hosted senza chiave lascia apiKey vuota |
91
+
92
+ Per approfondire, vedi [README.md](./README.md) e [CHANGELOG.md](./CHANGELOG.md).
package/INSTALL.ru.md ADDED
@@ -0,0 +1,92 @@
1
+ # Руководство по установке (dsh-prime-memory)
2
+
3
+ Плагин распространяется в виде **официального bundle-пакета DSH**: после установки слой `dsh.bundle` в `cordis.patch.yml` автоматически подключает запись плагина — вручную править конфигурацию профиля не нужно.
4
+
5
+ ## Требования к окружению
6
+
7
+ - Node.js ≥ 22.16 (DSH 0.2.0-rc.1 и новее)
8
+ - Установленный DeepSeek Harness (далее — DSH), доступен `--profile web`
9
+
10
+ ## Установка
11
+
12
+ Выберите любой способ вызова (префикс `npx` может заменить `dsh` в любой из команд ниже):
13
+
14
+ ```bash
15
+ # Способ 1: запустить официальный CLI напрямую через npx (предустановка dsh не нужна; можно зафиксировать версию, например dsh-prime-memory@0.8.4)
16
+ npx -y @deepseek-ai/dsh plugin --profile web add dsh-prime-memory
17
+
18
+ # Способ 2: при установленном CLI dsh (dsh — это forwarding-обёртка pnpm; если pnpm нет, сначала npm i -g pnpm)
19
+ dsh plugin --profile web add dsh-prime-memory
20
+
21
+ # Альтернативные источники пакета: репозиторий GitHub / локальный путь (разработка и отладка; link: указывает на репозиторий, достаточно npm run build + перезапуска dsh)
22
+ dsh plugin --profile web add https://github.com/drscrewdriver/dsh-prime-memory
23
+ dsh plugin --profile web add /path/to/dsh-prime-memory
24
+ ```
25
+
26
+ ### Поручить установку агенту (рекомендуется)
27
+
28
+ Отправьте текущему агенту приведённое ниже сообщение целиком и без изменений (если он умеет выполнять команды терминала):
29
+
30
+ ```text
31
+ Установи плагин dsh-prime-memory для web-профиля DeepSeek Harness.
32
+
33
+ Выполни только следующие две команды и не изменяй другие профили:
34
+ dsh plugin --profile web add dsh-prime-memory
35
+ dsh --profile web --dump-config
36
+
37
+ Когда dsh-prime-memory появится в выводе, сообщи мне результат установки.
38
+ Не закрывай и не перезапускай работающий DSH по своей инициативе; после установки напомни мне вручную перезапустить DSH Web Host.
39
+ ```
40
+
41
+ ## Обновление
42
+
43
+ ```bash
44
+ # Обновить до последней версии
45
+ dsh plugin --profile web update dsh-prime-memory
46
+
47
+ # Обновить до конкретной версии
48
+ dsh plugin --profile web update dsh-prime-memory@0.8.11
49
+ ```
50
+
51
+ Обновление заменяет только код плагина и артефакты в `dist/`; каталог данных `~/.dsh/memory/` не затрагивается.
52
+
53
+ ## Проверка
54
+
55
+ После установки и перезапуска DSH Web Host проверьте:
56
+
57
+ 1. **Появился каталог данных** — плагин успешно применён: в `~/.dsh/memory/` появляются каталоги `conversations/`, `records/`, `scenes/` и файл `memory.db`;
58
+ 2. **В настройках появилась страница «Память»** и в строке ввода появился пилюльный переключатель режимов — клиентская половина готова;
59
+ 3. Отправьте сообщение с личной информацией, дождитесь завершения дистилляции, затем спросите об этом в другом ходе беседы: в контексте должна появиться строка «Внедрение контекста · memory».
60
+
61
+ Необязательный smoke-тест (для разработки/диагностики):
62
+
63
+ ```bash
64
+ npm run build
65
+ npx tsc src/smoke.ts --outDir dist-smoke --module nodenext --moduleResolution nodenext --target es2022 --strict --skipLibCheck --esModuleInterop
66
+ node dist-smoke/smoke.js
67
+ ```
68
+
69
+ ## Миграция / откат
70
+
71
+ - **Миграция со старой версии (до 0.5.0 пакет назывался `dsh-memory-plugin`)**: старый каталог данных несовместим с новым пакетом; сделайте резервную копию и удалите `~/.dsh/memory/` — при первом запуске новый плагин пересоздаст его. Существующие воспоминания нельзя перенести напрямую, потребуется повторная дистилляция.
72
+ - **Откат на старую версию**: после `dsh plugin --profile web remove dsh-prime-memory` переустановите по документации старой версии; каталог данных сохранится, но старая версия не распознаёт новую структуру — рекомендуется его очистить.
73
+
74
+ ## Удаление
75
+
76
+ ```bash
77
+ dsh plugin --profile web remove dsh-prime-memory
78
+ ```
79
+
80
+ Данные остаются в `~/.dsh/memory/`; если они больше не нужны, удалите весь каталог вручную.
81
+
82
+ ## Поиск и устранение неисправностей
83
+
84
+ | Симптом | Вероятная причина | Решение |
85
+ | --- | --- | --- |
86
+ | После установки в настройках нет страницы «Память» | DSH не перезапущен / bundle не подключён | Перезапустите DSH Web Host; командой `dsh --profile web --dump-config` убедитесь, что `dsh-prime-memory` присутствует |
87
+ | При перезапуске ошибка `duplicate loader entry id` | в patch одновременно присутствует ручной `insert:` и добавление bundle с тем же id | Удалите добавленный вручную элемент `insert:`; пакет уже содержит собственный слой bundle |
88
+ | Нет строки «Внедрение контекста · memory» | дистилляция не запускалась / припоминание отключено | Проверьте, что режим не off и `recall.enabled=true`; найдите `L1 阶段完成` в `memory.log` |
89
+ | Загрузка локальной модели эмбеддингов зависает | зеркало недоступно по прямому соединению | Задайте `embedding.proxy` для работы через прокси; либо замените `embedding.mirror` на официальный `huggingface.co` |
90
+ | Удалённый эмбеддинг отдаёт ошибку 401 | неверная apiKey / сервис без ключа, которому ключ передавать не нужно | Проверьте `embedding.apiKey`; для собственного сервиса без ключа оставьте apiKey пустой |
91
+
92
+ Подробнее см. [README.md](./README.md) и [CHANGELOG.md](./CHANGELOG.md).
package/README.de.md CHANGED
@@ -61,7 +61,7 @@ alt="DeepSeek Harness Hero-Banner: Unterhaltungen werden automatisch zu mehrschi
61
61
  > Kompatibilitätsmechanismus: Die Settings-Registrierung durchläuft zur Laufzeit drei Zweige
62
62
  > (`register` → `installSection`-Brücke → Dauerein-Notbetrieb), siehe Eintrag 0.11.0 im
63
63
  > [CHANGELOG.md](./CHANGELOG.md). `dsh.plugin.json` deklariert
64
- > `engines.dsh` 为逐 rc 精确枚举串(0.1.0-rc.2 → 0.2.1-rc.3,18 rc).
64
+ > `engines.dsh` 为逐 rc 精确枚举串(0.1.0-rc.2 → 0.2.1-rc.4,19 rc).
65
65
 
66
66
  ## Schnellstart
67
67
 
package/README.en.md CHANGED
@@ -61,7 +61,7 @@
61
61
  > Compatibility mechanism: settings registration uses a three-way runtime branch
62
62
  > (`register` → `installSection` bridge → always-on degradation); see the 0.11.0 entry
63
63
  > in [CHANGELOG.md](./CHANGELOG.md). `dsh.plugin.json` declares
64
- > `engines.dsh` 为逐 rc 精确枚举串(0.1.0-rc.2 → 0.2.1-rc.3,18 rc).
64
+ > `engines.dsh` 为逐 rc 精确枚举串(0.1.0-rc.2 → 0.2.1-rc.4,19 rc).
65
65
 
66
66
  ## Getting Started
67
67
 
package/README.es.md CHANGED
@@ -61,7 +61,7 @@ alt="Banner hero de DeepSeek Harness: las conversaciones se destilan automática
61
61
  > Mecanismo de compatibilidad: el registro de ajustes pasa en tiempo de ejecución por tres ramas
62
62
  > (`register` → puente `installSection` → degradación a siempre activado),
63
63
  > ver la entrada 0.11.0 del [CHANGELOG.md](./CHANGELOG.md). `dsh.plugin.json` declara
64
- > `engines.dsh` 为逐 rc 精确枚举串(0.1.0-rc.2 → 0.2.1-rc.3,18 rc).
64
+ > `engines.dsh` 为逐 rc 精确枚举串(0.1.0-rc.2 → 0.2.1-rc.4,19 rc).
65
65
 
66
66
  ## Inicio rápido
67
67
 
package/README.fr.md CHANGED
@@ -61,7 +61,7 @@ alt="Bannière hero de DeepSeek Harness : les conversations sont automatiquement
61
61
  > Mécanisme de compatibilité : l'enregistrement settings passe par trois branches à l'exécution
62
62
  > (`register` → pont `installSection` → dégradation en mode toujours actif),
63
63
  > voir l'entrée 0.11.0 du [CHANGELOG.md](./CHANGELOG.md). `dsh.plugin.json` déclare
64
- > `engines.dsh` 为逐 rc 精确枚举串(0.1.0-rc.2 → 0.2.1-rc.3,18 rc).
64
+ > `engines.dsh` 为逐 rc 精确枚举串(0.1.0-rc.2 → 0.2.1-rc.4,19 rc).
65
65
 
66
66
  ## Démarrage rapide
67
67
 
package/README.it.md CHANGED
@@ -61,7 +61,7 @@ alt="Banner hero di DeepSeek Harness: le conversazioni vengono distillate automa
61
61
  > Meccanismo di compatibilità: la registrazione delle impostazioni passa per tre rami a runtime
62
62
  > (`register` → ponte `installSection` → degrado a sempre-attivo),
63
63
  > vedi la voce 0.11.0 del [CHANGELOG.md](./CHANGELOG.md). `dsh.plugin.json` dichiara
64
- > `engines.dsh` 为逐 rc 精确枚举串(0.1.0-rc.2 → 0.2.1-rc.3,18 rc).
64
+ > `engines.dsh` 为逐 rc 精确枚举串(0.1.0-rc.2 → 0.2.1-rc.4,19 rc).
65
65
 
66
66
  ## Avvio rapido
67
67
 
package/README.ja.md CHANGED
@@ -62,7 +62,7 @@ alt="DeepSeek Harness ヒーロー画像:会話がバックグラウンドで
62
62
 
63
63
  > 互換メカニズム:settings 登録は 3 分岐のランタイム判定(`register` → `installSection` ブリッジ → 常時オン縮退)。
64
64
  > 詳細は [CHANGELOG.md](./CHANGELOG.md) の 0.11.0 エントリ参照。`dsh.plugin.json` は
65
- > `engines.dsh` 为逐 rc 精确枚举串(0.1.0-rc.2 → 0.2.1-rc.3,18 rc) を宣言。
65
+ > `engines.dsh` 为逐 rc 精确枚举串(0.1.0-rc.2 → 0.2.1-rc.4,19 rc) を宣言。
66
66
 
67
67
  ## クイックスタート
68
68
 
package/README.ko.md CHANGED
@@ -62,7 +62,7 @@ alt="DeepSeek Harness 히어로 이미지: 대화가 백그라운드에서 계
62
62
 
63
63
  > 호환 메커니즘: settings 등록은 3분기 런타임 분기(`register` → `installSection` 브리지 → 상시 온 강등).
64
64
  > 자세한 내용은 [CHANGELOG.md](./CHANGELOG.md)의 0.11.0 항목 참조. `dsh.plugin.json`은
65
- > `engines.dsh` 为逐 rc 精确枚举串(0.1.0-rc.2 → 0.2.1-rc.3,18 rc) 선언.
65
+ > `engines.dsh` 为逐 rc 精确枚举串(0.1.0-rc.2 → 0.2.1-rc.4,19 rc) 선언.
66
66
 
67
67
  ## 빠른 시작
68
68
 
package/README.md CHANGED
@@ -60,7 +60,7 @@ alt="DeepSeek Harness hero 横幅:对话自动分层蒸馏成记忆,模型
60
60
 
61
61
  > 兼容机制:settings 注册走运行时三分支(`register` → `installSection` 桥接 → 恒开降级),
62
62
  > 详见 [CHANGELOG.md](./CHANGELOG.md) 的 0.11.0 条目。`dsh.plugin.json` 声明
63
- > `engines.dsh` 为逐 rc 精确枚举串(0.1.0-rc.2 → 0.2.1-rc.3,18 rc)。
63
+ > `engines.dsh` 为逐 rc 精确枚举串(0.1.0-rc.2 → 0.2.1-rc.4,19 rc)。
64
64
 
65
65
  ## 快速开始
66
66
 
package/README.ru.md CHANGED
@@ -61,7 +61,7 @@ alt="Баннер hero DeepSeek Harness: диалоги автоматическ
61
61
  > Механизм совместимости: регистрация настроек на этапе исполнения идёт по трём ветвям
62
62
  > (`register` → мост `installSection` → деградация в режим «всегда включено»),
63
63
  > подробнее — запись 0.11.0 в [CHANGELOG.md](./CHANGELOG.md). `dsh.plugin.json` объявляет
64
- > `engines.dsh` 为逐 rc 精确枚举串(0.1.0-rc.2 → 0.2.1-rc.3,18 rc).
64
+ > `engines.dsh` 为逐 rc 精确枚举串(0.1.0-rc.2 → 0.2.1-rc.4,19 rc).
65
65
 
66
66
  ## Быстрый старт
67
67
 
package/dist/index.js CHANGED
@@ -497,7 +497,7 @@ export async function apply(ctx, config) {
497
497
  // memoryRecall 投影:本会话“已注入且未被压缩覆盖”的召回集(会话感知,init 取 header.id),
498
498
  // 与常驻槽位是两条轴:那个是手动 pin 的硬注入约定,这个是非常驻的相关性浮现结果。
499
499
  // 带上反馈面:条目要显示人已经打过的那一笔(rating)。
500
- registerRecallProjection(ctx, stores.recalled, stores.l1, recallFeedback);
500
+ registerRecallProjection(ctx, stores.recalled, stores.l1, recallFeedback, logger);
501
501
  // 人打 -1 声明过时后,下一轮向模型一次性播报“这条已退场、别再依据它作答”。
502
502
  registerObsoleteNotice(ctx, config, obsoleteNotices, logger);
503
503
  void slotRecall;
@@ -14,6 +14,7 @@ import { buildConflictPair, conflictRejectId, DEFER_MAX, normalizeClaimKey, norm
14
14
  import { formatExtractionPrompt, getExtractMemoriesSystemPrompt } from '../prompts/l1-extraction.js';
15
15
  import { normTags, normUsageScenario, readCognitiveHall, readWing } from '../metadata-validators.js';
16
16
  import { acceptTitle } from '../util/md-name.js';
17
+ import { clampPriority } from '../util/priority.js';
17
18
  import { formatBatchConflictPrompt, getConflictDetectionSystemPrompt } from '../prompts/l1-dedup.js';
18
19
  import { resolveSourceAnchors, withSourceAnchors } from './anchors.js';
19
20
  import { stampValidity, validToSourceOf } from '../store/validity.js';
@@ -196,7 +197,7 @@ export function toStoreRecord(m, now, ts, anchorMap) {
196
197
  id: m.record_id,
197
198
  content: m.content,
198
199
  type: m.type,
199
- priority: Number(m.priority) || 60,
200
+ priority: clampPriority(m.priority),
200
201
  scene_name: m.scene_name,
201
202
  timestamps: [Number.isNaN(ts) ? now : ts],
202
203
  createdAt: now,
@@ -714,7 +715,7 @@ routeHealth) {
714
715
  id: m.record_id,
715
716
  content: mergedContent,
716
717
  type: decision.merged_type || m.type,
717
- priority: Number(decision.merged_priority) || Number(m.priority) || 60,
718
+ priority: clampPriority(decision.merged_priority ?? m.priority),
718
719
  scene_name: m.scene_name,
719
720
  timestamps: Array.from(new Set(mergedTs)).sort((a, b) => a - b),
720
721
  createdAt: now,
@@ -116,5 +116,7 @@ export interface RecallFeedbackFace {
116
116
  * apply 是 O(1) 判脏(store.revision() 与反馈序号比对),任意已提交事件都会带进来看一眼。
117
117
  * @param feedback - 相关度反馈只读面;缺席时 view 不带 rating(旧行为)。
118
118
  */
119
- export declare function registerRecallProjection(ctx: Context, store: SessionRecalledStore, l1?: RecallL1Face, feedback?: RecallFeedbackFace): void;
119
+ export declare function registerRecallProjection(ctx: Context, store: SessionRecalledStore, l1?: RecallL1Face, feedback?: RecallFeedbackFace, log?: {
120
+ warn(message: string): void;
121
+ }): void;
120
122
  export {};
@@ -1,5 +1,6 @@
1
1
  import { isRetired } from '../store/supersede.js';
2
2
  import { stateOfRecord } from '../store/validity.js';
3
+ import { clampPriority, isDirtyPriority } from '../util/priority.js';
3
4
  export const MEMORY_RECALL_KEY = 'memoryRecall';
4
5
  /** view 最多透出条数(最近在上;超出部分只计入 count,防 wire 体量失控)。 */
5
6
  export const RECALL_VIEW_CAP = 20;
@@ -141,7 +142,7 @@ function sameIds(a, b) {
141
142
  }
142
143
  /** view 引用稳定:同一 state 恒返回同一对象(registry 按 Object.is 判发布)。 */
143
144
  const viewMemo = new WeakMap();
144
- function makeView(state, l1, feedback) {
145
+ function makeView(state, l1, feedback, log) {
145
146
  const memoized = viewMemo.get(state);
146
147
  if (memoized !== undefined)
147
148
  return memoized;
@@ -163,11 +164,16 @@ function makeView(state, l1, feedback) {
163
164
  // 未退场行才会真判过时两档(退场行由 retired 键表达,validity 不再叠加)。
164
165
  const vState = isRetired(r) ? undefined : stateOfRecord(r, Date.now());
165
166
  const showValidity = vState === 'expired' || vState === 'expired_suspect';
167
+ // #19 读侧兜底:脏 priority(负/超界/非整数/非有限)就地夹取,绝不让 viewSchema
168
+ // 因单条脏字段抛错打死整会话;命中时 warn 留痕(静默夹取会掩盖上游 LLM 异常)。
169
+ const rawPriority = r.priority;
170
+ if (isDirtyPriority(rawPriority))
171
+ log?.warn(`[memory][recall] 脏 priority 回落 record=${r.id} raw=${String(rawPriority)}`);
166
172
  items.push({
167
173
  id: r.id,
168
174
  type: r.type,
169
175
  title: r.name || firstLine(r.content),
170
- priority: r.priority,
176
+ priority: clampPriority(rawPriority),
171
177
  body: clampBody(r.content),
172
178
  ...(scenario !== undefined && scenario.length > 0 ? { scenario } : {}),
173
179
  ...(typeof rating === 'number' ? { rating } : {}),
@@ -196,7 +202,7 @@ function sessionIdOf(header) {
196
202
  * apply 是 O(1) 判脏(store.revision() 与反馈序号比对),任意已提交事件都会带进来看一眼。
197
203
  * @param feedback - 相关度反馈只读面;缺席时 view 不带 rating(旧行为)。
198
204
  */
199
- export function registerRecallProjection(ctx, store, l1, feedback) {
205
+ export function registerRecallProjection(ctx, store, l1, feedback, log) {
200
206
  ctx.inject(['sessionProjections'], (injected) => {
201
207
  const registry = injected.sessionProjections;
202
208
  if (registry === undefined || typeof registry.register !== 'function')
@@ -208,9 +214,9 @@ export function registerRecallProjection(ctx, store, l1, feedback) {
208
214
  stateSchema,
209
215
  init: (header) => buildState(sessionIdOf(header), store, fbRev()),
210
216
  apply: (state) => buildState(state.sessionId, store, fbRev(), state),
211
- wire: { viewSchema, view: (state) => makeView(state, l1, feedback) },
217
+ wire: { viewSchema, view: (state) => makeView(state, l1, feedback, log) },
212
218
  schema: viewSchema,
213
- view: (state) => makeView(state, l1, feedback),
219
+ view: (state) => makeView(state, l1, feedback, log),
214
220
  stateVersion: 0,
215
221
  };
216
222
  registry.register(definition);
@@ -13,6 +13,7 @@
13
13
  * 与正文本体是否一致(`hashValid`),不替调用方决定怎么处置——那属于同步侧的裁决。
14
14
  */
15
15
  import { contentHash } from './memory-md.js';
16
+ import { clampPriority } from '../util/priority.js';
16
17
  /** 取 frontmatter 块:首行必须是 `---`,到下一个 `---` 为止。 */
17
18
  function splitFrontmatter(text) {
18
19
  // BOM 与 CRLF 都要先吃掉:人在记事本里改一行就会引入 \r,而 `\r` 会让 key 匹配不上。
@@ -71,7 +72,7 @@ export function parseMdFile(text) {
71
72
  return {
72
73
  name: str(fields.get('name')),
73
74
  type: str(fields.get('type')),
74
- priority: Number.isFinite(prio) ? prio : 60,
75
+ priority: clampPriority(prio),
75
76
  createdAt: str(fields.get('createdAt')),
76
77
  updatedAt: str(fields.get('updatedAt')),
77
78
  usageScenario: scenario,
@@ -26,6 +26,7 @@ import { normApplicability } from '../repo-scope.js';
26
26
  import { normalizeWorkspacePath } from '../workspace.js';
27
27
  import { bm25RankToScore, buildFtsQuery, tokenizeForFts } from './search-utils.js';
28
28
  import { describeTokenizer, ensureTokenizer, tokenizerStamp } from '../util/tokenizer.js';
29
+ import { clampPriority } from '../util/priority.js';
29
30
  const require = createRequire(import.meta.url);
30
31
  const TAG = '[memory][sqlite]';
31
32
  /**
@@ -992,7 +993,7 @@ export class MemoryDb {
992
993
  // 无法绑定(node:sqlite 拒绝绑定),曾致旧版导入逐条全挂、每次启动无限重试。
993
994
  // 主表与 FTS 两条语句共用同源归一化值;type 归一化后 familyForType 也不再收到 undefined。
994
995
  const type = record.type ?? '';
995
- const priority = record.priority ?? 50;
996
+ const priority = clampPriority(record.priority, 50);
996
997
  const sceneName = record.scene_name ?? '';
997
998
  const family = record.family ?? familyForType(type);
998
999
  // §E 写入侧兜底归一,并维持一条**不变量**:`scope='global'` 的记录 `workspace_id` 恒为空串。
@@ -0,0 +1,22 @@
1
+ /**
2
+ * L1 记忆 priority 的归一单源(issue #19)。
3
+ *
4
+ * 存在理由:priority 是磁盘契约列,且被 memoryRecall 投影的 `viewSchema` 严格校验
5
+ * (`requireCounter` 判非负整数)。任一写入口把 LLM 回传的负数/超界/小数原样落库,
6
+ * 投影出网即抛 → 宿主把整会话包成 `SESSION_QUERY_CORRUPT_SESSION` → **一条脏数据
7
+ * 打死整个会话历史**。故所有喂进 `l1_records.priority` 的路径必须过同一夹取。
8
+ *
9
+ * 语义(用户选定):非有限值→`fallback`;小数 `Math.round`;结果夹到整数 `[0,100]`。
10
+ * `fallback` 形参是为保留各写点既有的缺省差异(upsert 绑定层历史上用 50,抽取用 60),
11
+ * 避免为修范围而把某处的默认值静默漂移。
12
+ *
13
+ * 注意:**不动** `store/slots.ts` 里的同名私有 `clampPriority`(floor/50,服务 memorySlots
14
+ * 另一条链);本文件只服务 L1 记忆 priority。
15
+ */
16
+ export declare const PRIORITY_DEFAULT = 60;
17
+ export declare const PRIORITY_MIN = 0;
18
+ export declare const PRIORITY_MAX = 100;
19
+ /** 夹取到 `[PRIORITY_MIN, PRIORITY_MAX]` 的整数;非有限值回落 `fallback`。 */
20
+ export declare function clampPriority(value: unknown, fallback?: number): number;
21
+ /** 是否会被夹取改变(负 / 超界 / 非整数 / 非有限 / 缺失)——供读侧判定要不要 warn。 */
22
+ export declare function isDirtyPriority(value: unknown): boolean;
@@ -0,0 +1,36 @@
1
+ /**
2
+ * L1 记忆 priority 的归一单源(issue #19)。
3
+ *
4
+ * 存在理由:priority 是磁盘契约列,且被 memoryRecall 投影的 `viewSchema` 严格校验
5
+ * (`requireCounter` 判非负整数)。任一写入口把 LLM 回传的负数/超界/小数原样落库,
6
+ * 投影出网即抛 → 宿主把整会话包成 `SESSION_QUERY_CORRUPT_SESSION` → **一条脏数据
7
+ * 打死整个会话历史**。故所有喂进 `l1_records.priority` 的路径必须过同一夹取。
8
+ *
9
+ * 语义(用户选定):非有限值→`fallback`;小数 `Math.round`;结果夹到整数 `[0,100]`。
10
+ * `fallback` 形参是为保留各写点既有的缺省差异(upsert 绑定层历史上用 50,抽取用 60),
11
+ * 避免为修范围而把某处的默认值静默漂移。
12
+ *
13
+ * 注意:**不动** `store/slots.ts` 里的同名私有 `clampPriority`(floor/50,服务 memorySlots
14
+ * 另一条链);本文件只服务 L1 记忆 priority。
15
+ */
16
+ export const PRIORITY_DEFAULT = 60;
17
+ export const PRIORITY_MIN = 0;
18
+ export const PRIORITY_MAX = 100;
19
+ /** 夹取到 `[PRIORITY_MIN, PRIORITY_MAX]` 的整数;非有限值回落 `fallback`。 */
20
+ export function clampPriority(value, fallback = PRIORITY_DEFAULT) {
21
+ const sanitize = (x) => Math.max(PRIORITY_MIN, Math.min(PRIORITY_MAX, Math.round(x)));
22
+ // null/undefined 显式回落(Number(null) 得 0,若不当缺省处理会把旧 `?? 50` 漂移成 0)。
23
+ if (value === null || value === undefined)
24
+ return sanitize(fallback);
25
+ const n = typeof value === 'number' ? value : Number(value);
26
+ if (!Number.isFinite(n))
27
+ return sanitize(fallback);
28
+ return sanitize(n);
29
+ }
30
+ /** 是否会被夹取改变(负 / 超界 / 非整数 / 非有限 / 缺失)——供读侧判定要不要 warn。 */
31
+ export function isDirtyPriority(value) {
32
+ if (value === null || value === undefined)
33
+ return true;
34
+ const n = typeof value === 'number' ? value : Number(value);
35
+ return !Number.isInteger(n) || n < PRIORITY_MIN || n > PRIORITY_MAX;
36
+ }
package/dsh.plugin.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "id": "dsh-prime-memory",
3
3
  "name": "dsh-prime-memory",
4
- "version": "0.26.11",
4
+ "version": "0.26.13",
5
5
  "description": {
6
6
  "en": "Layered distilled memory plugin (L0 capture → L1 atomic memory → L2 scenes → L3 persona) with automatic recall injection before each model step.",
7
7
  "zh": "L0~L3 分层蒸馏记忆插件:自动捕获对话、抽取原子记忆、整合场景块、蒸馏核心画像,并在模型步骤前自动召回注入。"
@@ -13,7 +13,7 @@
13
13
  },
14
14
  "license": "MIT",
15
15
  "engines": {
16
- "dsh": "0.1.0-rc.2 || 0.1.0-rc.3 || 0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-rc.1 || 0.2.1-rc.2 || 0.2.1-rc.3"
16
+ "dsh": "0.1.0-rc.2 || 0.1.0-rc.3 || 0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-rc.1 || 0.2.1-rc.2 || 0.2.1-rc.3 || 0.2.1-rc.4"
17
17
  },
18
18
  "components": {
19
19
  "host": "dist/index.js",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-prime-memory",
3
- "version": "0.26.11",
3
+ "version": "0.26.13",
4
4
  "publishConfig": {
5
5
  "registry": "https://registry.npmjs.org",
6
6
  "access": "public",
@@ -41,10 +41,20 @@
41
41
  "README.en.md",
42
42
  "README.ja.md",
43
43
  "README.ko.md",
44
+ "README.de.md",
45
+ "README.es.md",
46
+ "README.fr.md",
47
+ "README.it.md",
48
+ "README.ru.md",
44
49
  "INSTALL.md",
45
50
  "INSTALL.en.md",
46
51
  "INSTALL.ja.md",
47
52
  "INSTALL.ko.md",
53
+ "INSTALL.de.md",
54
+ "INSTALL.es.md",
55
+ "INSTALL.fr.md",
56
+ "INSTALL.it.md",
57
+ "INSTALL.ru.md",
48
58
  "CHANGELOG.md",
49
59
  "CHANGELOG.en.md",
50
60
  "CHANGELOG.ja.md",
@@ -54,6 +64,7 @@
54
64
  "CHANGELOG.fr.md",
55
65
  "CHANGELOG.it.md",
56
66
  "CHANGELOG.ru.md",
67
+ "LICENSE",
57
68
  "ENGINEERING-NOTES.md"
58
69
  ],
59
70
  "scripts": {
@@ -69,7 +80,7 @@
69
80
  },
70
81
  "engines": {
71
82
  "node": ">=22.16.0",
72
- "dsh": "0.1.0-rc.2 || 0.1.0-rc.3 || 0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-rc.1 || 0.2.1-rc.2 || 0.2.1-rc.3"
83
+ "dsh": "0.1.0-rc.2 || 0.1.0-rc.3 || 0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-rc.1 || 0.2.1-rc.2 || 0.2.1-rc.3 || 0.2.1-rc.4"
73
84
  },
74
85
  "keywords": [
75
86
  "dsh",
@@ -93,15 +104,15 @@
93
104
  },
94
105
  "peerDependencies": {
95
106
  "@deepseek-ai/cordis": "^4.0.1",
96
- "@deepseek-ai/dsh-agent": "0.1.0-rc.2 || 0.1.0-rc.3 || 0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-rc.1 || 0.2.1-rc.2 || 0.2.1-rc.3",
97
- "@deepseek-ai/dsh-client-connection": "0.1.0-rc.2 || 0.1.0-rc.3 || 0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-rc.1 || 0.2.1-rc.2 || 0.2.1-rc.3",
98
- "@deepseek-ai/dsh-client-ui-primitives": "0.1.0-rc.2 || 0.1.0-rc.3 || 0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-rc.1 || 0.2.1-rc.2 || 0.2.1-rc.3",
99
- "@deepseek-ai/dsh-home-paths": "0.1.0-rc.2 || 0.1.0-rc.3 || 0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-rc.1 || 0.2.1-rc.2 || 0.2.1-rc.3",
100
- "@deepseek-ai/dsh-llm": "0.1.0-rc.2 || 0.1.0-rc.3 || 0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-rc.1 || 0.2.1-rc.2 || 0.2.1-rc.3",
101
- "@deepseek-ai/dsh-session": "0.1.0-rc.2 || 0.1.0-rc.3 || 0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-rc.1 || 0.2.1-rc.2 || 0.2.1-rc.3",
102
- "@deepseek-ai/dsh-settings": "0.1.0-rc.2 || 0.1.0-rc.3 || 0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-rc.1 || 0.2.1-rc.2 || 0.2.1-rc.3",
103
- "@deepseek-ai/dsh-system-prompt": "0.1.0-rc.2 || 0.1.0-rc.3 || 0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-rc.1 || 0.2.1-rc.2 || 0.2.1-rc.3",
104
- "@deepseek-ai/dsh-tools": "0.1.0-rc.2 || 0.1.0-rc.3 || 0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-rc.1 || 0.2.1-rc.2 || 0.2.1-rc.3"
107
+ "@deepseek-ai/dsh-agent": "0.1.0-rc.2 || 0.1.0-rc.3 || 0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-rc.1 || 0.2.1-rc.2 || 0.2.1-rc.3 || 0.2.1-rc.4",
108
+ "@deepseek-ai/dsh-client-connection": "0.1.0-rc.2 || 0.1.0-rc.3 || 0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-rc.1 || 0.2.1-rc.2 || 0.2.1-rc.3 || 0.2.1-rc.4",
109
+ "@deepseek-ai/dsh-client-ui-primitives": "0.1.0-rc.2 || 0.1.0-rc.3 || 0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-rc.1 || 0.2.1-rc.2 || 0.2.1-rc.3 || 0.2.1-rc.4",
110
+ "@deepseek-ai/dsh-home-paths": "0.1.0-rc.2 || 0.1.0-rc.3 || 0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-rc.1 || 0.2.1-rc.2 || 0.2.1-rc.3 || 0.2.1-rc.4",
111
+ "@deepseek-ai/dsh-llm": "0.1.0-rc.2 || 0.1.0-rc.3 || 0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-rc.1 || 0.2.1-rc.2 || 0.2.1-rc.3 || 0.2.1-rc.4",
112
+ "@deepseek-ai/dsh-session": "0.1.0-rc.2 || 0.1.0-rc.3 || 0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-rc.1 || 0.2.1-rc.2 || 0.2.1-rc.3 || 0.2.1-rc.4",
113
+ "@deepseek-ai/dsh-settings": "0.1.0-rc.2 || 0.1.0-rc.3 || 0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-rc.1 || 0.2.1-rc.2 || 0.2.1-rc.3 || 0.2.1-rc.4",
114
+ "@deepseek-ai/dsh-system-prompt": "0.1.0-rc.2 || 0.1.0-rc.3 || 0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-rc.1 || 0.2.1-rc.2 || 0.2.1-rc.3 || 0.2.1-rc.4",
115
+ "@deepseek-ai/dsh-tools": "0.1.0-rc.2 || 0.1.0-rc.3 || 0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-rc.1 || 0.2.1-rc.2 || 0.2.1-rc.3 || 0.2.1-rc.4"
105
116
  },
106
117
  "peerDependenciesMeta": {
107
118
  "@deepseek-ai/dsh-agent": {