dsh-session-eval 0.3.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/README.md +14 -0
- package/README.zh.md +13 -0
- package/lib/index.d.ts +8 -3
- package/lib/index.js +168 -3
- package/package.json +11 -10
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
## 0.4.1 — 2026-11-05
|
|
2
|
+
|
|
3
|
+
Peer-range compatibility release (no behavior change).
|
|
4
|
+
|
|
5
|
+
- `@deepseek-ai/dsh-*` peers widened to `^0.1.5-rc.3 || ^0.2.0 || 0.2.2-rc.1` and `@deepseek-ai/cordis` to `^4.0.2`, ahead of the DSH 0.2.2 release train.
|
|
6
|
+
- Verified against `@deepseek-ai/*@0.2.2-rc.1` in a scratch install: full suite 60/60 green. Notably `SESSION_FORMAT_VERSION` moved 3 → 4 upstream; a v3-header archive still round-trips through the 0.2.2 `buildArchiveFromLog` (historical formats are translated), so existing exported bundles keep grading identically.
|
|
7
|
+
|
|
8
|
+
## 0.4.0 — 2026-11-05
|
|
9
|
+
|
|
10
|
+
Evidence-handoff closure (#8): `/eval --report <bundle-or-archive.zip>`.
|
|
11
|
+
|
|
12
|
+
- Grades straight from an exported dsh-session-export artifact — bundle ZIPs (nested archive.zip) and raw /archive ZIPs — no session id to copy, and it works after the session is gone from the store.
|
|
13
|
+
- The artifact's JSONL is the canonical event log, so `--report` matches `/eval --id` exactly; a round-trip test builds bundles with the real dsh-session-export writer and asserts identical metrics and cards.
|
|
14
|
+
- Zero runtime dependencies kept: a minimal ZIP reader (central directory + raw DEFLATE via node:zlib, CRC32-verified) mirrors the export writer; dsh-session-export is a devDependency only, for the interop test.
|
|
15
|
+
- README.md / README.zh.md document the recall → report → eval closure with a worked example.
|
|
16
|
+
|
|
1
17
|
## 0.3.0 — 2026-10-23
|
|
2
18
|
|
|
3
19
|
Feature release: configurable grade bands (#1) and the history time window (#2).
|
package/README.md
CHANGED
|
@@ -61,6 +61,19 @@ Notes:
|
|
|
61
61
|
|
|
62
62
|
All three read through the same trusted `ctx.sessionQuery` seam, so any persistence backend (JSONL or SQLite) works without touching raw artifacts.
|
|
63
63
|
|
|
64
|
+
### Evidence-handoff closure (#8)
|
|
65
|
+
|
|
66
|
+
`/eval --report` grades straight from an artifact `dsh-session-export` already wrote — no session id to copy, and it works after the session is gone from the store:
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
recall "resume template font"
|
|
70
|
+
→ session session-ca62e005-… · report /proj/dsh-transcripts/bundle-ca62e005-20261104-120000.zip
|
|
71
|
+
|
|
72
|
+
/eval --report /proj/dsh-transcripts/bundle-ca62e005-20261104-120000.zip
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Bundle ZIPs (the nested `archive.zip` raw JSONL) and raw `/archive` ZIPs are both accepted. The JSONL inside is the canonical event log — the same bytes `readSession` returns — so `--report` grades **identically** to `/eval --id` (verified by a round-trip test against the real `dsh-session-export` writer). `--id` and `--report` are mutually exclusive.
|
|
76
|
+
|
|
64
77
|
## Contributing
|
|
65
78
|
|
|
66
79
|
- **Local dev**: `npm ci && npm run typecheck && npm test && npm run bundle` (Node 20 or 22).
|
|
@@ -85,6 +98,7 @@ Both are useful; they don't compete. Benchmarks test what you *predicted*; retro
|
|
|
85
98
|
|---|---|
|
|
86
99
|
| `/eval` | Grade card for the current session |
|
|
87
100
|
| `/eval --id <sessionId>` | Grade a specific session |
|
|
101
|
+
| `/eval --report <bundle-or-archive.zip>` | Grade from an exported artifact (works after the session is gone from the store) |
|
|
88
102
|
| `/eval --json` | Machine-readable metrics + card |
|
|
89
103
|
| `/eval-diff <beforeId> <afterId>` | Regression comparison, noise-tolerant |
|
|
90
104
|
| `/eval-diff … --json` | Machine-readable trend report |
|
package/README.zh.md
CHANGED
|
@@ -61,6 +61,19 @@ Notes:
|
|
|
61
61
|
|
|
62
62
|
三者都通过同一个可信的 `ctx.sessionQuery` 缝读取,JSONL / SQLite 等任何持久化后端均可使用。
|
|
63
63
|
|
|
64
|
+
### 证据联动闭环(#8)
|
|
65
|
+
|
|
66
|
+
`/eval --report` 直接从 `dsh-session-export` 已写出的产物评分——不用抄会话 id,会话从存储中删除后依然可评:
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
recall "resume template font"
|
|
70
|
+
→ session session-ca62e005-… · report /proj/dsh-transcripts/bundle-ca62e005-20261104-120000.zip
|
|
71
|
+
|
|
72
|
+
/eval --report /proj/dsh-transcripts/bundle-ca62e005-20261104-120000.zip
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
接受 bundle ZIP(内嵌 `archive.zip` 原始 JSONL)与裸 `/archive` ZIP。里面的 JSONL 就是权威事件日志——与 `readSession` 返回的是同一份字节——所以 `--report` 与 `/eval --id` **评分完全一致**(用真实 `dsh-session-export` 写入器做过往返测试)。`--id` 与 `--report` 互斥。
|
|
76
|
+
|
|
64
77
|
## 贡献
|
|
65
78
|
|
|
66
79
|
- **本地开发**:`npm ci && npm run typecheck && npm test && npm run bundle`(Node 20 或 22)。
|
package/lib/index.d.ts
CHANGED
|
@@ -114,13 +114,18 @@ declare function gradeSession(m: SessionMetrics, bands?: Partial<GradeBands>): G
|
|
|
114
114
|
/** Compare two sessions dimension by dimension. */
|
|
115
115
|
declare function compareSessions(before: SessionMetrics, after: SessionMetrics): TrendReport;
|
|
116
116
|
//#endregion
|
|
117
|
+
//#region src/artifact.d.ts
|
|
118
|
+
/** Filesystem seam (injectable for tests). */
|
|
119
|
+
type ReadFile = (path: string) => Buffer;
|
|
120
|
+
//#endregion
|
|
117
121
|
//#region src/evalCommand.d.ts
|
|
118
|
-
declare const EVAL_USAGE = "Usage: /eval [--id <sessionId>] [--json]";
|
|
122
|
+
declare const EVAL_USAGE = "Usage: /eval [--id <sessionId>] [--report <bundle-or-archive.zip>] [--json]";
|
|
119
123
|
declare const EVAL_DIFF_USAGE = "Usage: /eval-diff <beforeSessionId> <afterSessionId> [--json]";
|
|
120
124
|
declare function id8(sessionId: string): string;
|
|
121
125
|
/** Args for /eval. */
|
|
122
126
|
interface EvalArgs {
|
|
123
127
|
readonly sessionId?: string;
|
|
128
|
+
readonly report?: string;
|
|
124
129
|
readonly json?: boolean;
|
|
125
130
|
}
|
|
126
131
|
/** Args for /eval-diff. */
|
|
@@ -142,8 +147,8 @@ interface QuerySeam {
|
|
|
142
147
|
events: readonly unknown[];
|
|
143
148
|
}>;
|
|
144
149
|
}
|
|
145
|
-
/** Execute /eval against the session-query seam. */
|
|
146
|
-
declare function executeEval(ctx: Context, invocation: CommandInvocation, seam?: QuerySeam, bands?: Partial<GradeBands
|
|
150
|
+
/** Execute /eval against the session-query seam or an exported artifact. */
|
|
151
|
+
declare function executeEval(ctx: Context, invocation: CommandInvocation, seam?: QuerySeam, bands?: Partial<GradeBands>, readFile?: ReadFile): Promise<CommandResult>;
|
|
147
152
|
/** Execute /eval-diff against the session-query seam. */
|
|
148
153
|
declare function executeEvalDiff(ctx: Context, invocation: CommandInvocation, seam?: QuerySeam): Promise<CommandResult>;
|
|
149
154
|
//#endregion
|
package/lib/index.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { SessionId } from "@deepseek-ai/dsh-session";
|
|
2
|
+
import { crc32, inflateRawSync } from "node:zlib";
|
|
3
|
+
import { readFileSync } from "node:fs";
|
|
2
4
|
import { writeFile } from "node:fs/promises";
|
|
3
5
|
import { resolve } from "node:path";
|
|
4
6
|
//#region src/metrics.ts
|
|
@@ -85,6 +87,137 @@ function readBool(source, key) {
|
|
|
85
87
|
return typeof value === "boolean" ? value : void 0;
|
|
86
88
|
}
|
|
87
89
|
//#endregion
|
|
90
|
+
//#region src/zip.ts
|
|
91
|
+
/**
|
|
92
|
+
* Minimal single-file ZIP reader (methods 0 and 8, no external dependency).
|
|
93
|
+
*
|
|
94
|
+
* The mirror of dsh-session-export's `util/zip.ts` writer: parses the
|
|
95
|
+
* End-of-Central-Directory record, walks the central directory, and inflates
|
|
96
|
+
* each entry with raw DEFLATE (`node:zlib.inflateRawSync`, ZIP method 8) or
|
|
97
|
+
* copies stored entries (method 0). Data descriptors are not needed because
|
|
98
|
+
* the writer emits none; CRC32 is verified per entry. Only the features the
|
|
99
|
+
* toolchain's own archives use are supported — a ZIP using extensions beyond
|
|
100
|
+
* that is rejected with a clear error, not misread.
|
|
101
|
+
*
|
|
102
|
+
* @module dsh-session-eval/zip
|
|
103
|
+
*/
|
|
104
|
+
const EOCD_SIG = 101010256;
|
|
105
|
+
const CD_SIG = 33639248;
|
|
106
|
+
const LFH_SIG = 67324752;
|
|
107
|
+
/** Locate the EOCD record: normally the last 22 bytes; scan back over a comment if present. */
|
|
108
|
+
function findEocd(buf) {
|
|
109
|
+
const limit = Math.max(0, buf.length - 22 - 65536);
|
|
110
|
+
for (let i = buf.length - 22; i >= limit; i -= 1) if (buf.readUInt32LE(i) === EOCD_SIG) return i;
|
|
111
|
+
return -1;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Read every entry of a ZIP archive. Throws `Error` with a plain message on
|
|
115
|
+
* anything that is not a supported archive (truncated, unknown method, or a
|
|
116
|
+
* CRC mismatch) — callers surface the message to the user.
|
|
117
|
+
*/
|
|
118
|
+
function readZipEntries(buf) {
|
|
119
|
+
const eocd = findEocd(buf);
|
|
120
|
+
if (eocd < 0) throw new Error("not a ZIP archive (no end-of-central-directory record)");
|
|
121
|
+
const entryCount = buf.readUInt16LE(eocd + 10);
|
|
122
|
+
const cdOffset = buf.readUInt32LE(eocd + 16);
|
|
123
|
+
const entries = [];
|
|
124
|
+
let p = cdOffset;
|
|
125
|
+
for (let i = 0; i < entryCount; i += 1) {
|
|
126
|
+
if (p + 46 > buf.length || buf.readUInt32LE(p) !== CD_SIG) throw new Error(`corrupt ZIP: central directory entry ${i} is unreadable`);
|
|
127
|
+
const method = buf.readUInt16LE(p + 10);
|
|
128
|
+
const crcExpected = buf.readUInt32LE(p + 16);
|
|
129
|
+
const compressedSize = buf.readUInt32LE(p + 20);
|
|
130
|
+
const rawSize = buf.readUInt32LE(p + 24);
|
|
131
|
+
const nameLength = buf.readUInt16LE(p + 28);
|
|
132
|
+
const extraLength = buf.readUInt16LE(p + 30);
|
|
133
|
+
const commentLength = buf.readUInt16LE(p + 32);
|
|
134
|
+
const localOffset = buf.readUInt32LE(p + 42);
|
|
135
|
+
const name = buf.toString("utf8", p + 46, p + 46 + nameLength);
|
|
136
|
+
if (buf.readUInt32LE(localOffset) !== LFH_SIG) throw new Error(`corrupt ZIP: entry "${name}" has no local file header`);
|
|
137
|
+
const lfhNameLength = buf.readUInt16LE(localOffset + 26);
|
|
138
|
+
const lfhExtraLength = buf.readUInt16LE(localOffset + 28);
|
|
139
|
+
const dataStart = localOffset + 30 + lfhNameLength + lfhExtraLength;
|
|
140
|
+
const compressed = buf.subarray(dataStart, dataStart + compressedSize);
|
|
141
|
+
let raw;
|
|
142
|
+
if (method === 0) raw = Buffer.from(compressed);
|
|
143
|
+
else if (method === 8) raw = inflateRawSync(compressed);
|
|
144
|
+
else throw new Error(`unsupported ZIP compression method ${method} for entry "${name}"`);
|
|
145
|
+
if (raw.length !== rawSize) throw new Error(`corrupt ZIP: entry "${name}" decompressed to the wrong size`);
|
|
146
|
+
if (crc32(raw) >>> 0 !== crcExpected) throw new Error(`corrupt ZIP: CRC mismatch for entry "${name}"`);
|
|
147
|
+
entries.push({
|
|
148
|
+
name,
|
|
149
|
+
data: raw
|
|
150
|
+
});
|
|
151
|
+
p += 46 + nameLength + extraLength + commentLength;
|
|
152
|
+
}
|
|
153
|
+
return entries;
|
|
154
|
+
}
|
|
155
|
+
//#endregion
|
|
156
|
+
//#region src/artifact.ts
|
|
157
|
+
/**
|
|
158
|
+
* Evidence-handoff loader: grade a session straight from an artifact
|
|
159
|
+
* dsh-session-export already wrote (#8 closure).
|
|
160
|
+
*
|
|
161
|
+
* A bundle ZIP (`bundle-<id8>-<timestamp>.zip`) carries the raw JSONL
|
|
162
|
+
* archive as a nested `archive.zip`, and a `/archive` ZIP carries
|
|
163
|
+
* `session.jsonl` at its root. Both are the canonical event log — the same
|
|
164
|
+
* bytes `readSession` would return — so grading from an artifact matches
|
|
165
|
+
* grading through the seam exactly, and works after the session is gone
|
|
166
|
+
* from the store.
|
|
167
|
+
*
|
|
168
|
+
* @module dsh-session-eval/artifact
|
|
169
|
+
*/
|
|
170
|
+
function jsonlEvents(data) {
|
|
171
|
+
const out = [];
|
|
172
|
+
for (const line of data.toString("utf8").split("\n")) {
|
|
173
|
+
const trimmed = line.trim();
|
|
174
|
+
if (trimmed === "") continue;
|
|
175
|
+
out.push(JSON.parse(trimmed));
|
|
176
|
+
}
|
|
177
|
+
return out;
|
|
178
|
+
}
|
|
179
|
+
function byName(entries) {
|
|
180
|
+
return new Map(entries.map((entry) => [entry.name, entry.data]));
|
|
181
|
+
}
|
|
182
|
+
/** Parse one zip level; returns null when this level holds no session.jsonl. */
|
|
183
|
+
function loadFromZipLevel(buf, origin) {
|
|
184
|
+
const files = byName(readZipEntries(buf));
|
|
185
|
+
const jsonl = files.get("session.jsonl");
|
|
186
|
+
if (jsonl === void 0) return null;
|
|
187
|
+
const manifestRaw = files.get("manifest.json");
|
|
188
|
+
const manifest = manifestRaw === void 0 ? {} : JSON.parse(manifestRaw.toString("utf8"));
|
|
189
|
+
return {
|
|
190
|
+
sessionId: typeof manifest.sessionId === "string" ? manifest.sessionId : "unknown-session",
|
|
191
|
+
events: jsonlEvents(jsonl),
|
|
192
|
+
origin
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Load a gradeable session from an exported artifact path — a bundle ZIP
|
|
197
|
+
* (nested archive) or a raw `/archive` ZIP. Returns a plain error string on
|
|
198
|
+
* anything unreadable or unrecognized; never throws.
|
|
199
|
+
*/
|
|
200
|
+
function loadReportArtifact(path, readFile) {
|
|
201
|
+
let buf;
|
|
202
|
+
try {
|
|
203
|
+
buf = readFile(path);
|
|
204
|
+
} catch (error) {
|
|
205
|
+
return `Could not read ${path}: ${error instanceof Error ? error.message : String(error)}`;
|
|
206
|
+
}
|
|
207
|
+
try {
|
|
208
|
+
const nested = readZipEntries(buf).find((entry) => entry.name === "archive.zip");
|
|
209
|
+
if (nested !== void 0) {
|
|
210
|
+
const loaded = loadFromZipLevel(nested.data, `${path} (archive.zip)`);
|
|
211
|
+
if (loaded !== null) return loaded;
|
|
212
|
+
}
|
|
213
|
+
const direct = loadFromZipLevel(buf, path);
|
|
214
|
+
if (direct !== null) return direct;
|
|
215
|
+
return `${path} is a ZIP but carries no session.jsonl (neither at the root nor inside archive.zip) — is it a transcript report rather than a bundle or archive?`;
|
|
216
|
+
} catch (error) {
|
|
217
|
+
return `Could not load artifact ${path}: ${error instanceof Error ? error.message : String(error)}`;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
//#endregion
|
|
88
221
|
//#region src/grade.ts
|
|
89
222
|
/** The documented defaults; unchanged when no config is given. */
|
|
90
223
|
const DEFAULT_GRADE_BANDS = {
|
|
@@ -248,7 +381,7 @@ function compareSessions(before, after) {
|
|
|
248
381
|
const VERSION = "0.3.0";
|
|
249
382
|
//#endregion
|
|
250
383
|
//#region src/evalCommand.ts
|
|
251
|
-
const EVAL_USAGE = "Usage: /eval [--id <sessionId>] [--json]";
|
|
384
|
+
const EVAL_USAGE = "Usage: /eval [--id <sessionId>] [--report <bundle-or-archive.zip>] [--json]";
|
|
252
385
|
const EVAL_DIFF_USAGE = "Usage: /eval-diff <beforeSessionId> <afterSessionId> [--json]";
|
|
253
386
|
function id8(sessionId) {
|
|
254
387
|
return sessionId.length > 8 ? `${sessionId.slice(0, 8)}…` : sessionId;
|
|
@@ -271,6 +404,15 @@ function parseEvalArgs(rawInput) {
|
|
|
271
404
|
i += 2;
|
|
272
405
|
continue;
|
|
273
406
|
}
|
|
407
|
+
if (token === "--report") {
|
|
408
|
+
const value = tokens[i + 1];
|
|
409
|
+
if (value === void 0 || value.startsWith("--")) return `--report requires an artifact path value.\n${EVAL_USAGE}`;
|
|
410
|
+
if (args.report !== void 0) return `--report may be given only once.\n${EVAL_USAGE}`;
|
|
411
|
+
if (args.sessionId !== void 0) return `--id and --report are mutually exclusive.\n${EVAL_USAGE}`;
|
|
412
|
+
args.report = value;
|
|
413
|
+
i += 2;
|
|
414
|
+
continue;
|
|
415
|
+
}
|
|
274
416
|
if (token === "--json") {
|
|
275
417
|
if (args.json === true) return `--json may be given only once.\n${EVAL_USAGE}`;
|
|
276
418
|
args.json = true;
|
|
@@ -327,13 +469,36 @@ async function readEvents(ctx, seam, sessionIdRaw) {
|
|
|
327
469
|
return `Could not read session ${id8(sessionIdRaw)}: ${error instanceof Error ? error.message : String(error)}`;
|
|
328
470
|
}
|
|
329
471
|
}
|
|
330
|
-
/** Execute /eval against the session-query seam. */
|
|
331
|
-
async function executeEval(ctx, invocation, seam = ctx.sessionQuery, bands = {}) {
|
|
472
|
+
/** Execute /eval against the session-query seam or an exported artifact. */
|
|
473
|
+
async function executeEval(ctx, invocation, seam = ctx.sessionQuery, bands = {}, readFile = (path) => readFileSync(path)) {
|
|
332
474
|
const parsed = parseEvalArgs(invocation.rawInput);
|
|
333
475
|
if (typeof parsed === "string") return {
|
|
334
476
|
kind: "error",
|
|
335
477
|
text: parsed
|
|
336
478
|
};
|
|
479
|
+
if (parsed.report !== void 0) {
|
|
480
|
+
const artifact = loadReportArtifact(parsed.report, readFile);
|
|
481
|
+
if (typeof artifact === "string") return {
|
|
482
|
+
kind: "error",
|
|
483
|
+
text: artifact
|
|
484
|
+
};
|
|
485
|
+
const metrics = computeMetrics(artifact.sessionId, adaptEvents(artifact.events));
|
|
486
|
+
const card = gradeSession(metrics, bands);
|
|
487
|
+
const note = `from artifact ${artifact.origin}`;
|
|
488
|
+
if (parsed.json === true) return {
|
|
489
|
+
kind: "success",
|
|
490
|
+
text: JSON.stringify({
|
|
491
|
+
generator: "dsh-session-eval v0.3.0",
|
|
492
|
+
source: note,
|
|
493
|
+
metrics,
|
|
494
|
+
card
|
|
495
|
+
}, null, 2)
|
|
496
|
+
};
|
|
497
|
+
return {
|
|
498
|
+
kind: "success",
|
|
499
|
+
text: `${renderCard(card, "dsh-session-eval v0.3.0")}\n(${note})`
|
|
500
|
+
};
|
|
501
|
+
}
|
|
337
502
|
const sessionIdRaw = parsed.sessionId ?? String(invocation.agent.session.id);
|
|
338
503
|
const events = await readEvents(ctx, seam, sessionIdRaw);
|
|
339
504
|
if (typeof events === "string") return {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-session-eval",
|
|
3
3
|
"description": "Retrospective agent-session evaluation for DeepSeek Harness: deterministic grade cards from persisted session logs, cross-session regression diffs, era comparison — no benchmark runs, no LLM judges.",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.4.1",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -38,21 +38,22 @@
|
|
|
38
38
|
"regression"
|
|
39
39
|
],
|
|
40
40
|
"peerDependencies": {
|
|
41
|
+
"@deepseek-ai/cordis": "^4.0.2",
|
|
42
|
+
"@deepseek-ai/dsh-commands": "^0.1.5-rc.3 || ^0.2.0 || 0.2.2-rc.1",
|
|
43
|
+
"@deepseek-ai/dsh-llm": "^0.1.5-rc.3 || ^0.2.0 || 0.2.2-rc.1",
|
|
44
|
+
"@deepseek-ai/dsh-session": "^0.1.5-rc.3 || ^0.2.0 || 0.2.2-rc.1",
|
|
45
|
+
"@deepseek-ai/dsh-session-query": "^0.1.5-rc.3 || ^0.2.0 || 0.2.2-rc.1",
|
|
46
|
+
"@deepseek-ai/dsh-tools": "^0.1.5-rc.3 || ^0.2.0 || 0.2.2-rc.1"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
41
49
|
"@deepseek-ai/cordis": "4.0.2",
|
|
42
50
|
"@deepseek-ai/dsh-commands": "^0.1.5-rc.3",
|
|
43
|
-
"@deepseek-ai/dsh-llm": "^0.1.5-rc.3",
|
|
44
51
|
"@deepseek-ai/dsh-session": "^0.1.5-rc.3",
|
|
45
|
-
"@deepseek-ai/dsh-session-query": "^0.1.5-rc.3",
|
|
46
|
-
"@deepseek-ai/dsh-tools": "^0.1.5-rc.3"
|
|
47
|
-
},
|
|
48
|
-
"devDependencies": {
|
|
49
52
|
"@types/node": "^26.2.0",
|
|
53
|
+
"dsh-session-export": "^1.9.0",
|
|
50
54
|
"tsdown": "^0.22.14",
|
|
51
55
|
"typescript": "^7.0.2",
|
|
52
|
-
"vitest": "^4.1.11"
|
|
53
|
-
"@deepseek-ai/cordis": "4.0.2",
|
|
54
|
-
"@deepseek-ai/dsh-commands": "^0.1.5-rc.3",
|
|
55
|
-
"@deepseek-ai/dsh-session": "^0.1.5-rc.3"
|
|
56
|
+
"vitest": "^4.1.11"
|
|
56
57
|
},
|
|
57
58
|
"scripts": {
|
|
58
59
|
"bundle": "tsdown",
|