dsh-memory-recall 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +96 -0
- package/README.md +181 -0
- package/cordis.patch.yml +16 -0
- package/dsh.plugin.json +18 -0
- package/lib/client.js +1090 -0
- package/package.json +60 -0
- package/screenshots.json +6 -0
- package/src/chats.js +160 -0
- package/src/dsh-tools.js +75 -0
- package/src/index.js +156 -0
- package/src/memory-tool.js +136 -0
- package/src/recall-tool.js +203 -0
- package/src/recall.js +282 -0
- package/src/routes.js +153 -0
- package/src/snapshot.js +63 -0
- package/src/store.js +298 -0
- package/src/threats.js +113 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 adithyanraj03
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
|
23
|
+
-------------------------------------------------------------------------------
|
|
24
|
+
|
|
25
|
+
Portions of src/threats.js, src/memory-tool.js and src/store.js are adapted
|
|
26
|
+
from Hermes Agent (https://github.com/NousResearch/hermes-agent):
|
|
27
|
+
the threat-pattern list, the memory tool's design and wording, and the
|
|
28
|
+
§-delimited memory file format. Hermes Agent is distributed under this licence:
|
|
29
|
+
|
|
30
|
+
MIT License
|
|
31
|
+
|
|
32
|
+
Copyright (c) 2025 Nous Research
|
|
33
|
+
|
|
34
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
35
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
36
|
+
in the Software without restriction, including without limitation the rights
|
|
37
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
38
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
39
|
+
furnished to do so, subject to the following conditions:
|
|
40
|
+
|
|
41
|
+
The above copyright notice and this permission notice shall be included in all
|
|
42
|
+
copies or substantial portions of the Software.
|
|
43
|
+
|
|
44
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
45
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
46
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
47
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
48
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
49
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
50
|
+
SOFTWARE.
|
|
51
|
+
|
|
52
|
+
-------------------------------------------------------------------------------
|
|
53
|
+
|
|
54
|
+
The brain icon in lib/client.js is from Lucide (https://lucide.dev), under the
|
|
55
|
+
ISC License:
|
|
56
|
+
|
|
57
|
+
Copyright (c) for portions of Lucide are held by Cole Bemis 2013-2022 as part
|
|
58
|
+
of Feather (MIT). All other copyright (c) for Lucide are held by Lucide
|
|
59
|
+
Contributors 2022.
|
|
60
|
+
|
|
61
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
62
|
+
purpose with or without fee is hereby granted, provided that the above
|
|
63
|
+
copyright notice and this permission notice appear in all copies.
|
|
64
|
+
|
|
65
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
66
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
67
|
+
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
68
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
|
69
|
+
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
|
70
|
+
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
|
71
|
+
THIS SOFTWARE.
|
|
72
|
+
|
|
73
|
+
-------------------------------------------------------------------------------
|
|
74
|
+
|
|
75
|
+
The solid brain glyph in lib/client.js is from Phosphor Icons
|
|
76
|
+
(https://phosphoricons.com), under the MIT License:
|
|
77
|
+
|
|
78
|
+
Copyright (c) 2023 Phosphor Icons
|
|
79
|
+
|
|
80
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
81
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
82
|
+
in the Software without restriction, including without limitation the rights
|
|
83
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
84
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
85
|
+
furnished to do so, subject to the following conditions:
|
|
86
|
+
|
|
87
|
+
The above copyright notice and this permission notice shall be included in all
|
|
88
|
+
copies or substantial portions of the Software.
|
|
89
|
+
|
|
90
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
91
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
92
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
93
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
94
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
95
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
96
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
# dsh-memory-recall
|
|
2
|
+
|
|
3
|
+
      
|
|
4
|
+
|
|
5
|
+
A [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) plugin that gives the model a memory, in the style of [Hermes Agent](https://github.com/NousResearch/hermes-agent): what it learns about you and your projects carries into every new chat, and it can look back through your earlier chats — **only after you allow it**.
|
|
6
|
+
|
|
7
|
+
**Everything stays on your machine.** Two small text files, dsh's own session index, no embeddings, no service, no telemetry.
|
|
8
|
+
|
|
9
|
+

|
|
10
|
+
|
|
11
|
+
It does five things:
|
|
12
|
+
|
|
13
|
+
- **A `memory` tool** — the model keeps two short files: a **user profile** (who you are, how you like to work) and its **own notes** (environment facts, conventions, lessons). Every new chat starts with both in its prompt.
|
|
14
|
+
- **A `session_search` tool** — the model reads your earlier chats to answer *"what did we decide last time?"*. dsh's own approval prompt asks you first, saying what it wants to look for.
|
|
15
|
+
- **A 🧠 Saved to memory note in the chat** — every save shows what changed and how full memory is, so nothing is remembered behind your back.
|
|
16
|
+
- **A sidebar 🧠 Memory panel** — everything kept, in two tabs, with edit, delete, add and search.
|
|
17
|
+
- **Chats and workspaces in the `@` menu** — grouped by workspace, under their real titles, so you can hand the model a chat or point its search at one workspace.
|
|
18
|
+
|
|
19
|
+
## Install
|
|
20
|
+
|
|
21
|
+
Requires a working dsh (0.1.5 or later) with a `web` profile.
|
|
22
|
+
|
|
23
|
+
```sh
|
|
24
|
+
dsh plugin --profile web add dsh-memory-recall
|
|
25
|
+
dsh --profile web
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Or install from GitHub or a local folder instead:
|
|
29
|
+
|
|
30
|
+
```sh
|
|
31
|
+
dsh plugin --profile web add github:adithyanraj03/dsh-memory-recall
|
|
32
|
+
dsh plugin --profile web add /path/to/dsh-memory-recall
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Then **restart dsh** (`dsh --profile web`) if it was already running, and **hard-refresh the browser** (Ctrl+Shift+R / Cmd+Shift+R) — a plain refresh can serve a cached client bundle. **🧠 Memory** appears at the bottom of the sidebar.
|
|
36
|
+
|
|
37
|
+
### Turn on dsh's full-text search (recommended)
|
|
38
|
+
|
|
39
|
+
`session_search` uses dsh's own session index, which dsh ships **switched off**. Add this to your profile's `cordis.patch.yml` (`~/.dsh/profiles/web/cordis.patch.yml`):
|
|
40
|
+
|
|
41
|
+
```yaml
|
|
42
|
+
- id: session-query-sqlite
|
|
43
|
+
config:
|
|
44
|
+
path: '/absolute/path/to/.dsh/session-search.db'
|
|
45
|
+
openAt: first-search
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
`first-search` opens the index only when something first searches; a file path keeps it across restarts. The index is derived from your session logs, so deleting the file only costs a rebuild. An override replaces the row's whole config — keep both keys.
|
|
49
|
+
|
|
50
|
+
Without it, `session_search` still works: it falls back to a literal scan of your 150 most recent chats — slower and unranked — and says so in its card.
|
|
51
|
+
|
|
52
|
+
## What you get
|
|
53
|
+
|
|
54
|
+
### Memory that carries over
|
|
55
|
+
|
|
56
|
+
Just talk. The model saves what will matter later — that you use PowerShell, that a server lives on another machine, that the docs build breaks on a trailing colon — and each save appears in the chat. Click it to see exactly what changed and how full that store is:
|
|
57
|
+
|
|
58
|
+

|
|
59
|
+
|
|
60
|
+

|
|
61
|
+
|
|
62
|
+
You can also ask directly: *"remember that I prefer short answers"*, *"forget that I use npm"*.
|
|
63
|
+
|
|
64
|
+
Memory is pasted into each new chat's prompt once, when the chat starts, and is **fixed for the life of that chat** — rewriting the prompt mid-chat would throw away dsh's cached prompt prefix. A save made mid-chat is on disk at once and reaches the prompt from the **next** new chat. The model is told this, so it does not save twice.
|
|
65
|
+
|
|
66
|
+
### Looking back through earlier chats
|
|
67
|
+
|
|
68
|
+
Refer to an earlier conversation — *"what did we decide about the rollback?"*, *"do it like last time"* — and the model calls `session_search`. dsh's approval prompt takes over the message box with what it wants to read, e.g. *Search your earlier chats for "deploy rollback".*, with **Allow** and **Deny**. The chats it found appear in a card, each with its date, the matching lines and a link to open it:
|
|
69
|
+
|
|
70
|
+

|
|
71
|
+
|
|
72
|
+
It returns the chats' actual messages — nothing summarised, nothing invented — cut to about 9,000 characters so one search cannot flood the context. The asking chat and sub-agent sessions are never results.
|
|
73
|
+
|
|
74
|
+
### The Memory panel
|
|
75
|
+
|
|
76
|
+
**🧠 Memory**, at the bottom of the sidebar above ⏱️ Scheduled when both are installed, opens everything that is kept:
|
|
77
|
+
|
|
78
|
+
- **Notes** and **Profile** tabs, each with a ring and a bar showing how full it is.
|
|
79
|
+
- **Edit** or **delete** any entry in place (hover it), with an inline confirm for delete.
|
|
80
|
+
- **Add** an entry yourself, and **search** once a tab holds a few.
|
|
81
|
+
- With the sidebar collapsed, it becomes a single icon, like Settings.
|
|
82
|
+
|
|
83
|
+

|
|
84
|
+
|
|
85
|
+
Edits you make here are your own words, so they are not scanned (see [Safety](#safety)), but they still respect the budget. Hand edits to the files show in the panel at once and in the prompt from the next new chat.
|
|
86
|
+
|
|
87
|
+
### Chats and workspaces in the @ menu
|
|
88
|
+
|
|
89
|
+
Type `@` in the message box. Below dsh's own files and folders, your chats are listed **grouped by workspace**, under the titles your sidebar shows:
|
|
90
|
+
|
|
91
|
+
- **Just `@`** — *This workspace* with its most recent chats, then *Workspaces* with every other one and how many chats it holds, then chats in no workspace.
|
|
92
|
+
- **`@` + text** — matching workspaces, then matching chats under their workspace's heading.
|
|
93
|
+
- **Tab, or the chevron, on a workspace** — all of its chats, with an *All workspaces* crumb back.
|
|
94
|
+
|
|
95
|
+
**Pick a chat** and dsh attaches a read-only snapshot of it to your message, exactly as its own `@` chat rows do — no search and no permission prompt, because you chose it. **Pick a workspace** and it reaches the model as `[workspace "Web Search" — /path/to/Web Search]`; `session_search` then searches only that workspace's chats (after asking, as always).
|
|
96
|
+
|
|
97
|
+
Every chat gets a readable name — its title, or the start of its first message if it never got one. Sub-agent sessions are left out, and nothing is capped at 50. These rows replace dsh's own flat `@` chat list while its file rows stay as they are; dsh offers no switch for that, so the plugin wraps its `@` source and restores it when unloaded.
|
|
98
|
+
|
|
99
|
+
## How asking works
|
|
100
|
+
|
|
101
|
+
- **Reading earlier chats asks first**, through dsh's own approval prompt.
|
|
102
|
+
- **One Allow covers that reply.** A search is usually followed by a closer read of the best hit; asking twice for one question is noise. The permission ends when the reply finishes, so the next question asks again.
|
|
103
|
+
- **Deny means nothing is read**, and the model is told not to ask again in that reply. If the prompt is withdrawn (you stopped the reply) or nobody can be asked, nothing is read either.
|
|
104
|
+
- **Saving to memory does not ask** — it is always shown in the chat and can be undone in the Memory panel. This matches Hermes Agent's default.
|
|
105
|
+
|
|
106
|
+
If dsh runs in `danger-full-access` mode its approval policy is `never`, which **rejects** every approval request without prompting — so recall is refused there. Set `askBeforeRecall: false` if you want recall without asking in that mode.
|
|
107
|
+
|
|
108
|
+
## What goes into the prompt
|
|
109
|
+
|
|
110
|
+
Each new chat gets one prompt section: a short note on how memory works, then the two stores, rendered as Hermes renders them:
|
|
111
|
+
|
|
112
|
+
```
|
|
113
|
+
══════════════════════════════════════════════
|
|
114
|
+
USER PROFILE (who the user is) [14% — 189/1,375 chars]
|
|
115
|
+
══════════════════════════════════════════════
|
|
116
|
+
Works on Windows 11 in PowerShell; projects live under D:/code.
|
|
117
|
+
§
|
|
118
|
+
Prefers short answers with the command first, explanation after.
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
The budgets are small on purpose — **2,200 characters of notes and 1,375 of profile**, Hermes's defaults, together roughly 900 tokens — because they are paid in every chat. When a store is full, a save that would overflow it is refused whole, never cut; the model is shown the entries and consolidates in one batch that merges or drops stale entries and adds the new one, checked against the final size. Raise the budgets with `limits` (below) if you would rather pay more per chat.
|
|
122
|
+
|
|
123
|
+
Sub-agent sessions do not get the section; they are the model's own workers.
|
|
124
|
+
|
|
125
|
+
## Configuration
|
|
126
|
+
|
|
127
|
+
All optional, on this plugin's row in the profile's `cordis.patch.yml`:
|
|
128
|
+
|
|
129
|
+
```yaml
|
|
130
|
+
- id: dsh-memory-recall
|
|
131
|
+
config:
|
|
132
|
+
limits:
|
|
133
|
+
memory: 4000
|
|
134
|
+
user: 1375
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
| Key | Default | Meaning |
|
|
138
|
+
|---|---|---|
|
|
139
|
+
| `dir` | `~/.dsh/dsh-memory-recall` | Where `USER.md` and `MEMORY.md` live |
|
|
140
|
+
| `limits` | `{memory: 2200, user: 1375}` | Character budgets for the notes and the profile |
|
|
141
|
+
| `recall` | `true` | `false` drops `session_search` and keeps memory |
|
|
142
|
+
| `askBeforeRecall` | `true` | `false` reads earlier chats without asking |
|
|
143
|
+
|
|
144
|
+
An override replaces the row's whole config, so restate every key you set. Restart dsh after changing it.
|
|
145
|
+
|
|
146
|
+
## Safety
|
|
147
|
+
|
|
148
|
+
Memory is re-read into every future chat, so a poisoned entry would keep instructing the model until someone deleted it. Every write **the model** makes is scanned for prompt-injection and exfiltration phrasing — *ignore previous instructions*, *don't tell the user*, piping secrets to a URL, SSH keys, edits to dsh's own config, hidden Unicode — and refused with the reason. The patterns are Hermes Agent's.
|
|
149
|
+
|
|
150
|
+
Other guards:
|
|
151
|
+
|
|
152
|
+
- A change re-reads the file first, so a hand edit is never overwritten by a stale copy; writes are atomic and one at a time.
|
|
153
|
+
- Replace and remove need a piece of text unique to one entry; an ambiguous one is refused, not guessed.
|
|
154
|
+
- A batch is all-or-nothing.
|
|
155
|
+
|
|
156
|
+
## How it works
|
|
157
|
+
|
|
158
|
+
- **Host side** (`src/index.js`): registers the `memory` and `session_search` tools, adds the memory section to each new top-level chat's system prompt on `agent/session-start`, and serves the panel's routes under `/plugin-data/dsh-memory-recall/`. Recall goes through dsh's `sessionQuery` service and its `approval` service; nothing talks to the network.
|
|
159
|
+
- **Client side** (`lib/client.js`, plain JavaScript, no build step): the in-chat chip and recall card replace dsh's own rows for those two tools through the `tool.call.toolview` slot; the panel mounts into `sidebar.footer.action`; the `@` rows are an `inputTriggers` source.
|
|
160
|
+
- **Files**:
|
|
161
|
+
|
|
162
|
+
```
|
|
163
|
+
~/.dsh/dsh-memory-recall/USER.md the user profile
|
|
164
|
+
~/.dsh/dsh-memory-recall/MEMORY.md the model's notes
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Plain text, entries separated by a line holding only `§` — the same format as Hermes, readable and editable by hand.
|
|
168
|
+
|
|
169
|
+
## Requirements
|
|
170
|
+
|
|
171
|
+
- dsh 0.1.5 or later, with a `web` profile
|
|
172
|
+
- Node 22+
|
|
173
|
+
- No runtime dependencies — the client bundle requires only `react`
|
|
174
|
+
|
|
175
|
+
## Credits
|
|
176
|
+
|
|
177
|
+
The design — two bounded stores, a frozen per-chat snapshot, the batch-against-final-budget rule, `session_search`'s shapes, the §-delimited files and the threat patterns — comes from [Hermes Agent](https://github.com/NousResearch/hermes-agent) by Nous Research (MIT). The brain icons are Lucide's (ISC) and Phosphor's (MIT).
|
|
178
|
+
|
|
179
|
+
## Licence
|
|
180
|
+
|
|
181
|
+
MIT — see the [LICENSE](LICENSE) file, which also carries the notices for Hermes Agent, Lucide and Phosphor.
|
package/cordis.patch.yml
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# dsh-memory-recall: mount the host half — the memory store, the `memory` and
|
|
2
|
+
# `session_search` tools, the per-chat memory snapshot, and the routes the
|
|
3
|
+
# browser half reads. The Memory panel and the in-chat cards are mounted by the
|
|
4
|
+
# `dsh.client` entry in package.json, not from here.
|
|
5
|
+
#
|
|
6
|
+
# `name` MUST be the package name: the loader imports this exact specifier.
|
|
7
|
+
#
|
|
8
|
+
# Config (all optional, set on this row):
|
|
9
|
+
# dir where USER.md and MEMORY.md live
|
|
10
|
+
# (default ~/.dsh/dsh-memory-recall)
|
|
11
|
+
# limits: {memory, user} character budgets (default 2200 / 1375, as Hermes)
|
|
12
|
+
# recall: false drop session_search, keep memory
|
|
13
|
+
# askBeforeRecall: false read earlier chats without asking first
|
|
14
|
+
- insert:
|
|
15
|
+
- id: dsh-memory-recall
|
|
16
|
+
name: 'dsh-memory-recall'
|
package/dsh.plugin.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "dsh-memory-recall",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"main": "./src/index.js",
|
|
5
|
+
"description": "Persistent memory for dsh in the style of Hermes Agent: a memory tool that keeps a user profile and the model's own notes in every new chat's prompt, and a session_search tool that reads earlier chats only after the user approves, with a Memory panel to see and edit what is kept.",
|
|
6
|
+
"engines": {
|
|
7
|
+
"dsh": ">=0.1.5-rc.2"
|
|
8
|
+
},
|
|
9
|
+
"contributes": {
|
|
10
|
+
"tools": [
|
|
11
|
+
"memory",
|
|
12
|
+
"session_search"
|
|
13
|
+
]
|
|
14
|
+
},
|
|
15
|
+
"client": {
|
|
16
|
+
"main": "./lib/client.js"
|
|
17
|
+
}
|
|
18
|
+
}
|