dsh-deja 0.20.3 → 0.20.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -4
- package/{README.zh.md → docs/zh.md} +2 -2
- package/index.js +53 -38
- package/lib.js +37 -0
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
# dsh-deja
|
|
2
2
|
|
|
3
|
-
English | [中文](
|
|
3
|
+
English | [中文](https://github.com/vshulcz/deja-vu/blob/main/extensions/dsh/docs/zh.md)
|
|
4
4
|
|
|
5
5
|
DeepSeek Harness can already search its own sessions — that is what the built-in
|
|
6
6
|
`session-query` subsystem does. This plugin answers the other question: what you
|
|
7
7
|
did in the *other* agents on this machine.
|
|
8
8
|
|
|
9
|
-
deja indexes the session files that
|
|
10
|
-
Antigravity, Grok Build, Kimi, Cline
|
|
11
|
-
disk. Nothing has to have been recorded ahead of time: the history is already
|
|
9
|
+
deja indexes the session files that twenty-one other coding agents — Claude Code,
|
|
10
|
+
Codex, Cursor, opencode, Antigravity, Grok Build, Kimi, Cline and Zed among
|
|
11
|
+
them — already write to disk. Nothing has to have been recorded ahead of time: the history is already
|
|
12
12
|
there, including the months before deja was installed. If you moved to dsh last
|
|
13
13
|
week, everything you did before last week is still reachable from inside it.
|
|
14
14
|
|
|
@@ -18,6 +18,13 @@ week, everything you did before last week is still reachable from inside it.
|
|
|
18
18
|
dsh plugin --profile web add dsh-deja
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
+
From the repository instead of npm — the root manifest re-exports this
|
|
22
|
+
directory, so either form works:
|
|
23
|
+
|
|
24
|
+
```sh
|
|
25
|
+
dsh plugin --profile web add github:vshulcz/deja-vu#path:extensions/dsh
|
|
26
|
+
```
|
|
27
|
+
|
|
21
28
|
The plugin runs the `deja` binary. It is pulled in as a dependency, so npm
|
|
22
29
|
installs it with the plugin; a `deja` already on `PATH` is used as-is, and
|
|
23
30
|
`DEJA_BIN` overrides both.
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# dsh-deja
|
|
2
2
|
|
|
3
|
-
[English](README.md) | 中文
|
|
3
|
+
[English](../README.md) | 中文
|
|
4
4
|
|
|
5
5
|
DeepSeek Harness 自带的 `session-query` 已经可以检索它自己的会话。这个插件回答的是另一个问题:你在这台机器上**其他**智能体里做过什么。
|
|
6
6
|
|
|
7
|
-
deja 索引 Claude Code、Codex、Cursor、opencode、Antigravity、Grok Build、Kimi、Cline、Zed
|
|
7
|
+
deja 索引 Claude Code、Codex、Cursor、opencode、Antigravity、Grok Build、Kimi、Cline、Zed 等二十一个智能体本来就写在磁盘上的会话文件。不需要提前录制:历史已经在那里,包括安装 deja 之前的那些月份。如果你上周才转到 dsh,上周之前做过的事仍然可以在 dsh 里查到。
|
|
8
8
|
|
|
9
9
|
## 安装
|
|
10
10
|
|
package/index.js
CHANGED
|
@@ -11,7 +11,7 @@ import { existsSync } from "node:fs";
|
|
|
11
11
|
import { homedir } from "node:os";
|
|
12
12
|
import { join } from "node:path";
|
|
13
13
|
|
|
14
|
-
import { contributions } from "./lib.js";
|
|
14
|
+
import { argv, contributions, guarded } from "./lib.js";
|
|
15
15
|
|
|
16
16
|
const require = createRequire(import.meta.url);
|
|
17
17
|
|
|
@@ -89,6 +89,7 @@ function answer(text) {
|
|
|
89
89
|
return MISSING;
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
+
|
|
92
93
|
function tools(ctx) {
|
|
93
94
|
if (!defineTool) return;
|
|
94
95
|
|
|
@@ -101,7 +102,7 @@ function tools(ctx) {
|
|
|
101
102
|
render: (_args, value) => [{ type: "text", text: String(value) }],
|
|
102
103
|
};
|
|
103
104
|
|
|
104
|
-
ctx.tools.register(defineTool({
|
|
105
|
+
guarded(() => ctx.tools.register(defineTool({
|
|
105
106
|
name: "deja_recall",
|
|
106
107
|
description:
|
|
107
108
|
"Search this machine's own past AI coding sessions — every agent used on it, including months before deja was installed. Use before debugging an error or re-implementing anything that may already exist. Match on the most specific token available: an exact error string, function name, file path or flag.",
|
|
@@ -122,11 +123,11 @@ function tools(ctx) {
|
|
|
122
123
|
// spend the model's context on a tail nobody reads.
|
|
123
124
|
const asked = Number.isFinite(args.limit) ? Math.trunc(args.limit) : 5;
|
|
124
125
|
const limit = String(Math.min(20, Math.max(1, asked)));
|
|
125
|
-
return Promise.resolve(answer(run(
|
|
126
|
+
return Promise.resolve(answer(run(argv("search", ["--json", "--limit", limit], args.query))));
|
|
126
127
|
},
|
|
127
|
-
}));
|
|
128
|
+
})));
|
|
128
129
|
|
|
129
|
-
ctx.tools.register(defineTool({
|
|
130
|
+
guarded(() => ctx.tools.register(defineTool({
|
|
130
131
|
name: "deja_session",
|
|
131
132
|
description:
|
|
132
133
|
"A full digest of the single best-matching past session — what was tried, what was decided, what it cost. Use after deja_recall when the reasoning behind an earlier decision matters, not just that it happened.",
|
|
@@ -139,11 +140,11 @@ function tools(ctx) {
|
|
|
139
140
|
},
|
|
140
141
|
output: TEXT_OUTPUT,
|
|
141
142
|
execute(args) {
|
|
142
|
-
return Promise.resolve(answer(run(
|
|
143
|
+
return Promise.resolve(answer(run(argv("ctx", [], args.query))));
|
|
143
144
|
},
|
|
144
|
-
}));
|
|
145
|
+
})));
|
|
145
146
|
|
|
146
|
-
ctx.tools.register(defineTool({
|
|
147
|
+
guarded(() => ctx.tools.register(defineTool({
|
|
147
148
|
name: "deja_blame",
|
|
148
149
|
description:
|
|
149
150
|
"The past sessions that discussed a file, so you know why it is shaped the way it is before editing, refactoring or deleting it. Session history, not git authorship.",
|
|
@@ -156,11 +157,11 @@ function tools(ctx) {
|
|
|
156
157
|
},
|
|
157
158
|
output: TEXT_OUTPUT,
|
|
158
159
|
execute(args) {
|
|
159
|
-
return Promise.resolve(answer(run(
|
|
160
|
+
return Promise.resolve(answer(run(argv("blame", ["--json"], args.path))));
|
|
160
161
|
},
|
|
161
|
-
}));
|
|
162
|
+
})));
|
|
162
163
|
|
|
163
|
-
ctx.tools.register(defineTool({
|
|
164
|
+
guarded(() => ctx.tools.register(defineTool({
|
|
164
165
|
name: "deja_fix",
|
|
165
166
|
description:
|
|
166
167
|
"What this machine ran after that same error before, in the sessions where the error did not come back. Paste the failing output verbatim rather than a paraphrase — the match is on the error's own words.",
|
|
@@ -173,11 +174,11 @@ function tools(ctx) {
|
|
|
173
174
|
},
|
|
174
175
|
output: TEXT_OUTPUT,
|
|
175
176
|
execute(args) {
|
|
176
|
-
return Promise.resolve(answer(run(
|
|
177
|
+
return Promise.resolve(answer(run(argv("fix", [], args.error))));
|
|
177
178
|
},
|
|
178
|
-
}));
|
|
179
|
+
})));
|
|
179
180
|
|
|
180
|
-
ctx.tools.register(defineTool({
|
|
181
|
+
guarded(() => ctx.tools.register(defineTool({
|
|
181
182
|
name: "deja_how",
|
|
182
183
|
description:
|
|
183
184
|
"The real invocation this machine uses for a build, test, deploy or script, with the flags it actually ran, ordered by how many sessions ran it. A guessed command is plausible and fails on this setup.",
|
|
@@ -190,11 +191,11 @@ function tools(ctx) {
|
|
|
190
191
|
},
|
|
191
192
|
output: TEXT_OUTPUT,
|
|
192
193
|
execute(args) {
|
|
193
|
-
return Promise.resolve(answer(run(
|
|
194
|
+
return Promise.resolve(answer(run(argv("how", [], args.what))));
|
|
194
195
|
},
|
|
195
|
-
}));
|
|
196
|
+
})));
|
|
196
197
|
|
|
197
|
-
ctx.tools.register(defineTool({
|
|
198
|
+
guarded(() => ctx.tools.register(defineTool({
|
|
198
199
|
name: "deja_remember",
|
|
199
200
|
description:
|
|
200
201
|
"Store one durable decision once it is settled, as a single self-contained fact that will make sense months later. Not transcripts, not a summary of the conversation, and not anything already obvious from the code.",
|
|
@@ -207,15 +208,15 @@ function tools(ctx) {
|
|
|
207
208
|
},
|
|
208
209
|
output: TEXT_OUTPUT,
|
|
209
210
|
execute(args) {
|
|
210
|
-
const written = run(
|
|
211
|
+
const written = run(argv("remember", [], args.text));
|
|
211
212
|
if (!INSTALLED) return Promise.resolve(MISSING);
|
|
212
213
|
return Promise.resolve(written || "deja did not record that.");
|
|
213
214
|
},
|
|
214
|
-
}));
|
|
215
|
+
})));
|
|
215
216
|
}
|
|
216
217
|
|
|
217
218
|
function command(ctx) {
|
|
218
|
-
ctx.commands.register({
|
|
219
|
+
guarded(() => ctx.commands.register({
|
|
219
220
|
name: "deja",
|
|
220
221
|
description: "Search this machine's past AI coding sessions",
|
|
221
222
|
input: { hint: "what to look for" },
|
|
@@ -224,10 +225,14 @@ function command(ctx) {
|
|
|
224
225
|
if (!query) {
|
|
225
226
|
return { kind: "error", text: "Say what to look for: /deja <error, file, or decision>" };
|
|
226
227
|
}
|
|
227
|
-
|
|
228
|
+
// Named, not handed over as deja's first word: the bare-query path
|
|
229
|
+
// dispatches a word that happens to be a command, so `/deja version`
|
|
230
|
+
// printed a version number and `/deja index` rebuilt the index, and one
|
|
231
|
+
// of the words people most want history about is `install`.
|
|
232
|
+
const out = run(argv("search", [], query));
|
|
228
233
|
return { kind: INSTALLED ? "success" : "error", text: answer(out) };
|
|
229
234
|
},
|
|
230
|
-
});
|
|
235
|
+
}));
|
|
231
236
|
}
|
|
232
237
|
|
|
233
238
|
function userText(message) {
|
|
@@ -245,26 +250,36 @@ function userText(message) {
|
|
|
245
250
|
// alternative — splicing a message into the "agent/pre-step" waterfall — looks
|
|
246
251
|
// like it works and does not: a later listener rebuilds its answer from the
|
|
247
252
|
// payload, and the added message is dropped with nothing reported.
|
|
253
|
+
//
|
|
254
|
+
// The registration is guarded because the host throws "prompt context
|
|
255
|
+
// deja:recall is already registered" on a second copy in the same profile, and
|
|
256
|
+
// that failure is not local: the whole profile fails to load, so a duplicate
|
|
257
|
+
// memory plugin costs the user their agent. One registration is all recall
|
|
258
|
+
// needs. installedByCLI() below is the first line of defence; this is the one
|
|
259
|
+
// that holds when the installer wrote to a different DSH_HOME than the profile
|
|
260
|
+
// boots from.
|
|
248
261
|
function autoRecall(ctx) {
|
|
249
262
|
let asked = "";
|
|
250
263
|
let recalled = "";
|
|
251
264
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
asked
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
265
|
+
guarded(() =>
|
|
266
|
+
ctx.systemPrompt.context({
|
|
267
|
+
name: "deja:recall",
|
|
268
|
+
order: 120,
|
|
269
|
+
text: (assembly) => {
|
|
270
|
+
const agent = assembly && assembly.agent;
|
|
271
|
+
if (!agent) return "";
|
|
272
|
+
const prompt = lastHumanText(agent);
|
|
273
|
+
if (!prompt) return "";
|
|
274
|
+
if (prompt !== asked) {
|
|
275
|
+
asked = prompt;
|
|
276
|
+
recalled = run(["hook-prompt", "--plain"], JSON.stringify({ prompt, cwd: process.cwd() }));
|
|
277
|
+
}
|
|
278
|
+
// Silence is the common case: this speaks only when the history answers.
|
|
279
|
+
return recalled;
|
|
280
|
+
},
|
|
281
|
+
}),
|
|
282
|
+
);
|
|
268
283
|
}
|
|
269
284
|
|
|
270
285
|
// lastHumanText is the newest thing the person actually typed. At assembly
|
package/lib.js
CHANGED
|
@@ -2,6 +2,43 @@
|
|
|
2
2
|
// anything a plugin module exports as part of the plugin — opencode does
|
|
3
3
|
// exactly that with its own — and this is a helper, not a second plugin.
|
|
4
4
|
|
|
5
|
+
// argv builds the call for a query somebody typed, rather than handing the text
|
|
6
|
+
// to deja as it stands.
|
|
7
|
+
//
|
|
8
|
+
// The command is always named. deja's bare-query path dispatches a first word
|
|
9
|
+
// that happens to be a command, so a one-word query went to the command of that
|
|
10
|
+
// name: `version` printed a version number, `index` rebuilt the index, and
|
|
11
|
+
// neither searched anything.
|
|
12
|
+
//
|
|
13
|
+
// A query that starts with a dash is read as a flag: `deja search --no-verify`
|
|
14
|
+
// exits on an unknown flag, the caller turns that into "", and the model is
|
|
15
|
+
// told the history holds nothing about --no-verify while eleven sessions
|
|
16
|
+
// discuss it — a confident wrong answer, which is worse than an error. `--`
|
|
17
|
+
// ends the flags. It is sent only when the query needs it, so a deja too old to
|
|
18
|
+
// know the terminator on this subcommand still answers every ordinary query.
|
|
19
|
+
export function argv(cmd, flags, text) {
|
|
20
|
+
const arg = String(text);
|
|
21
|
+
return arg.startsWith("-") ? [cmd, ...flags, "--", arg] : [cmd, ...flags, arg];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// guarded runs one registration, and swallows the host's refusal of a name it
|
|
25
|
+
// already holds.
|
|
26
|
+
//
|
|
27
|
+
// dsh answers a duplicate with "prompt context deja:recall is already
|
|
28
|
+
// registered" or "command deja is already registered", and that failure is not
|
|
29
|
+
// local: the whole plugin tree fails to load, so a second copy of this plugin —
|
|
30
|
+
// the npm package next to the installer's files, a --patch overlay naming it
|
|
31
|
+
// twice — costs the user their agent over an optional memory plugin. One
|
|
32
|
+
// registration is all any of these need, so the loser stands down.
|
|
33
|
+
export function guarded(register) {
|
|
34
|
+
try {
|
|
35
|
+
register();
|
|
36
|
+
return true;
|
|
37
|
+
} catch {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
5
42
|
// contributions says what this package adds, given what `deja install` already
|
|
6
43
|
// wrote into DSH_HOME and what the profile turned off. The rule is the same
|
|
7
44
|
// everywhere: fill the gaps, never repeat the installer.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-deja",
|
|
3
|
-
"version": "0.20.
|
|
4
|
-
"description": "Brings the session history of
|
|
3
|
+
"version": "0.20.5",
|
|
4
|
+
"description": "Brings the session history of twenty-one other coding agents into DeepSeek Harness: recall, session digest and per-file history tools over a local index, plus optional automatic recall before each step.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"exports": {
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"lib.js",
|
|
14
14
|
"cordis.patch.yml",
|
|
15
15
|
"README.md",
|
|
16
|
-
"
|
|
16
|
+
"docs/zh.md",
|
|
17
17
|
"LICENSE"
|
|
18
18
|
],
|
|
19
19
|
"license": "MIT",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
}
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@vshulcz/deja-vu": "^0.
|
|
47
|
+
"@vshulcz/deja-vu": "^0.19.2"
|
|
48
48
|
},
|
|
49
49
|
"scripts": {
|
|
50
50
|
"test": "node --test test/*.test.js"
|