dsh-deja 0.18.3 → 0.20.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/README.md CHANGED
@@ -31,6 +31,9 @@ Three tools the model can call:
31
31
  | `deja_recall` | Sessions matching an error string, function name, file path or flag. |
32
32
  | `deja_session` | The full digest of one past session, when the reasoning behind it matters. |
33
33
  | `deja_blame` | The sessions that discussed a file, before you edit or delete it. |
34
+ | `deja_fix` | What this machine ran after that same error before. |
35
+ | `deja_how` | The real invocation for a build, test or deploy, from what ran here. |
36
+ | `deja_remember` | Stores one settled decision for later recall. |
34
37
 
35
38
  One command: `/deja <what to look for>`.
36
39
 
package/README.zh.md CHANGED
@@ -23,6 +23,9 @@ dsh plugin --profile web add dsh-deja
23
23
  | `deja_recall` | 匹配报错文本、函数名、文件路径或命令行参数的历史会话。 |
24
24
  | `deja_session` | 单个历史会话的完整摘要,用于需要当时的判断依据时。 |
25
25
  | `deja_blame` | 在修改或删除某个文件之前,讨论过这个文件的历史会话。 |
26
+ | `deja_fix` | 这台机器上同样的报错之后跑过什么。 |
27
+ | `deja_how` | 构建、测试或部署在这台机器上真实的执行命令。 |
28
+ | `deja_remember` | 把一条已确定的决定存下来,供以后召回。 |
26
29
 
27
30
  一个命令:`/deja <要查什么>`。
28
31
 
package/index.js CHANGED
@@ -10,10 +10,6 @@ import { execFileSync } from "node:child_process";
10
10
 
11
11
  const require = createRequire(import.meta.url);
12
12
 
13
- // The tool registry lives in the host, not here. A plugin that throws on a
14
- // missing peer takes the whole profile down with it, so both imports degrade:
15
- // without them the command and automatic recall still work, only the
16
- // model-facing tools are skipped.
17
13
  // The tool registry lives in the host. A plugin that throws on a missing peer
18
14
  // takes the whole profile down with it, so this degrades: without dsh-tools the
19
15
  // command and automatic recall still work, only the model-facing tools are
@@ -26,16 +22,32 @@ try {
26
22
  const PLATFORM = process.platform === "win32" ? "windows" : process.platform;
27
23
  const ARCH = process.arch === "x64" ? "amd64" : process.arch;
28
24
 
29
- // resolveDeja finds the binary: an explicit override first, then the platform
30
- // package npm installed next to this one, then whatever is on PATH.
25
+ // resolveDeja picks the binary in the order a user would expect: what they
26
+ // pointed at, then the deja they installed themselves and keep current with
27
+ // `deja update` or a package manager, and only then the copy npm brought along
28
+ // with this plugin. Each candidate is asked for its version rather than
29
+ // trusted, because a name on PATH that does not run is worse than no name.
31
30
  function resolveDeja() {
32
- if (process.env.DEJA_BIN) return process.env.DEJA_BIN;
33
31
  const exe = PLATFORM === "windows" ? "deja.exe" : "deja";
32
+ const candidates = [process.env.DEJA_BIN, exe];
34
33
  try {
35
- return require.resolve(`@vshulcz/deja-vu-${PLATFORM}-${ARCH}/bin/${exe}`);
36
- } catch {
37
- return exe;
34
+ candidates.push(require.resolve(`@vshulcz/deja-vu-${PLATFORM}-${ARCH}/bin/${exe}`));
35
+ } catch {}
36
+
37
+ for (const candidate of candidates) {
38
+ if (!candidate) continue;
39
+ try {
40
+ execFileSync(candidate, ["version"], {
41
+ encoding: "utf8",
42
+ timeout: 5000,
43
+ stdio: ["ignore", "pipe", "ignore"],
44
+ });
45
+ return candidate;
46
+ } catch {}
38
47
  }
48
+ // Nothing answered. Keep the plain name so the failure a user sees names the
49
+ // thing that is missing.
50
+ return exe;
39
51
  }
40
52
 
41
53
  const DEJA = resolveDeja();
@@ -57,12 +69,26 @@ function run(args, input) {
57
69
  }
58
70
 
59
71
  const NOTHING = "Nothing in this machine's history matches that.";
72
+ const MISSING =
73
+ "deja is not installed on this machine, so there is no history to search. " +
74
+ "Install it with: curl -fsSL https://raw.githubusercontent.com/vshulcz/deja-vu/main/install.sh | sh";
75
+
76
+ // installed answers whether the binary picked at load actually runs. Without
77
+ // this every tool would report an empty history to a user who simply never
78
+ // installed deja, which reads as "you have no past" rather than "nothing is
79
+ // here to read it".
80
+ const INSTALLED = run(["version"]) !== "";
81
+
82
+ function answer(text) {
83
+ if (INSTALLED) return text || NOTHING;
84
+ return MISSING;
85
+ }
60
86
 
61
87
  function tools(ctx) {
62
88
  if (!defineTool) return;
63
89
 
64
90
  // Every tool here answers with the text deja printed, so one output
65
- // declaration serves all three. The schema is plain JSON Schema — a
91
+ // declaration serves them all. The schema is plain JSON Schema — a
66
92
  // schemastery instance is rejected as "schema must be a value schema object",
67
93
  // because the host validates that this is an ordinary JSON record.
68
94
  const TEXT_OUTPUT = {
@@ -87,8 +113,11 @@ function tools(ctx) {
87
113
  },
88
114
  output: TEXT_OUTPUT,
89
115
  execute(args) {
90
- const limit = Number.isFinite(args.limit) ? String(Math.max(1, Math.trunc(args.limit))) : "5";
91
- return Promise.resolve(run(["search", "--json", "--limit", limit, String(args.query)]) || NOTHING);
116
+ // deja itself caps the window; asking for a hundred sessions would
117
+ // spend the model's context on a tail nobody reads.
118
+ const asked = Number.isFinite(args.limit) ? Math.trunc(args.limit) : 5;
119
+ const limit = String(Math.min(20, Math.max(1, asked)));
120
+ return Promise.resolve(answer(run(["search", "--json", "--limit", limit, String(args.query)])));
92
121
  },
93
122
  }));
94
123
 
@@ -105,7 +134,7 @@ function tools(ctx) {
105
134
  },
106
135
  output: TEXT_OUTPUT,
107
136
  execute(args) {
108
- return Promise.resolve(run(["ctx", String(args.query)]) || NOTHING);
137
+ return Promise.resolve(answer(run(["ctx", String(args.query)])));
109
138
  },
110
139
  }));
111
140
 
@@ -122,7 +151,60 @@ function tools(ctx) {
122
151
  },
123
152
  output: TEXT_OUTPUT,
124
153
  execute(args) {
125
- return Promise.resolve(run(["blame", String(args.path), "--json"]) || NOTHING);
154
+ return Promise.resolve(answer(run(["blame", String(args.path), "--json"])));
155
+ },
156
+ }));
157
+
158
+ ctx.tools.register(defineTool({
159
+ name: "deja_fix",
160
+ description:
161
+ "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.",
162
+ parameters: {
163
+ error: {
164
+ type: "string",
165
+ required: true,
166
+ description: "The failing output, copied as it was printed.",
167
+ },
168
+ },
169
+ output: TEXT_OUTPUT,
170
+ execute(args) {
171
+ return Promise.resolve(answer(run(["fix", String(args.error)])));
172
+ },
173
+ }));
174
+
175
+ ctx.tools.register(defineTool({
176
+ name: "deja_how",
177
+ description:
178
+ "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.",
179
+ parameters: {
180
+ what: {
181
+ type: "string",
182
+ required: true,
183
+ description: "The thing to run: a tool, a task, a script name.",
184
+ },
185
+ },
186
+ output: TEXT_OUTPUT,
187
+ execute(args) {
188
+ return Promise.resolve(answer(run(["how", String(args.what)])));
189
+ },
190
+ }));
191
+
192
+ ctx.tools.register(defineTool({
193
+ name: "deja_remember",
194
+ description:
195
+ "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.",
196
+ parameters: {
197
+ text: {
198
+ type: "string",
199
+ required: true,
200
+ description: "The decision, in one or two sentences, with the reason it was taken.",
201
+ },
202
+ },
203
+ output: TEXT_OUTPUT,
204
+ execute(args) {
205
+ const written = run(["remember", String(args.text)]);
206
+ if (!INSTALLED) return Promise.resolve(MISSING);
207
+ return Promise.resolve(written || "deja did not record that.");
126
208
  },
127
209
  }));
128
210
  }
@@ -138,7 +220,7 @@ function command(ctx) {
138
220
  return { kind: "error", text: "Say what to look for: /deja <error, file, or decision>" };
139
221
  }
140
222
  const out = run([query]);
141
- return { kind: "success", text: out || NOTHING };
223
+ return { kind: INSTALLED ? "success" : "error", text: answer(out) };
142
224
  },
143
225
  });
144
226
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-deja",
3
- "version": "0.18.3",
3
+ "version": "0.20.0",
4
4
  "description": "Brings the session history of nineteen 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",
@@ -18,10 +18,9 @@
18
18
  "license": "MIT",
19
19
  "repository": {
20
20
  "type": "git",
21
- "url": "git+https://github.com/vshulcz/deja-vu.git",
22
- "directory": "packages/dsh-deja"
21
+ "url": "git+https://github.com/vshulcz/dsh-deja.git"
23
22
  },
24
- "homepage": "https://github.com/vshulcz/deja-vu/tree/main/packages/dsh-deja",
23
+ "homepage": "https://github.com/vshulcz/dsh-deja",
25
24
  "bugs": {
26
25
  "url": "https://github.com/vshulcz/deja-vu/issues"
27
26
  },
@@ -43,6 +42,9 @@
43
42
  }
44
43
  },
45
44
  "dependencies": {
46
- "@vshulcz/deja-vu": "0.18.0"
45
+ "@vshulcz/deja-vu": "^0.18.0"
46
+ },
47
+ "scripts": {
48
+ "test": "node --test test/*.test.js"
47
49
  }
48
50
  }