dsh-context 0.35.0 → 0.37.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 +8 -0
- package/lib/client.js +256 -64
- package/lib/index.d.ts +98 -317
- package/lib/index.js +261 -6
- package/package.json +8 -9
package/lib/index.js
CHANGED
|
@@ -1,7 +1,247 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join, normalize } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
1
4
|
import { z } from "zod";
|
|
2
5
|
import { settingsNamespace } from "@deepseek-ai/dsh-settings";
|
|
3
6
|
import z$1 from "@deepseek-ai/schemastery";
|
|
4
7
|
import { deriveEventMessage } from "@deepseek-ai/dsh-session";
|
|
8
|
+
/**
|
|
9
|
+
* Recover the MCP server display label from a proxied tool name, or undefined
|
|
10
|
+
* for non-MCP names. `dsh-mcp-client` names tools `mcp__<server>__<rawName>`
|
|
11
|
+
* (normalized, and hash-appended when overlong/invalid — the label then shows
|
|
12
|
+
* whatever of the server survived the truncation). The separating `__` is the
|
|
13
|
+
* LAST one in the name, and it must sit AFTER the `mcp__` prefix: the prefix's
|
|
14
|
+
* own separator (or an empty server right after it) is not a server.
|
|
15
|
+
*/
|
|
16
|
+
function mcpServerOf(name) {
|
|
17
|
+
if (!name.startsWith("mcp__")) return void 0;
|
|
18
|
+
const cut = name.lastIndexOf("__");
|
|
19
|
+
if (cut < 5) return void 0;
|
|
20
|
+
const server = name.slice(5, cut);
|
|
21
|
+
return server.length > 0 ? server : void 0;
|
|
22
|
+
}
|
|
23
|
+
/** The `mcp:<server>` display label of a proxied tool name, or undefined. */
|
|
24
|
+
function mcpSourceOf(name) {
|
|
25
|
+
const server = mcpServerOf(name);
|
|
26
|
+
return server !== void 0 ? `mcp:${server}` : void 0;
|
|
27
|
+
}
|
|
28
|
+
/** The pinned package of a first-party tool name, or undefined. */
|
|
29
|
+
function pinnedSourceOf(name) {
|
|
30
|
+
return FIRST_PARTY_SOURCES[name];
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Pinned first-party tool → plugin package map (see header comment). One entry
|
|
34
|
+
* per model-facing name of the shipped tool packages at dsh 0.1.1-rc.2, from
|
|
35
|
+
* the official tool-schema catalog; names are stable across the supported
|
|
36
|
+
* harness range. Packages that mount under distinct names per composition
|
|
37
|
+
* (bash/pwsh persistent variants, subagent fork) map to their primary package.
|
|
38
|
+
*/
|
|
39
|
+
const FIRST_PARTY_SOURCES = Object.freeze({
|
|
40
|
+
read: "@deepseek-ai/dsh-tool-fs",
|
|
41
|
+
write: "@deepseek-ai/dsh-tool-fs",
|
|
42
|
+
edit: "@deepseek-ai/dsh-tool-fs",
|
|
43
|
+
read_image: "@deepseek-ai/dsh-tool-fs",
|
|
44
|
+
glob: "@deepseek-ai/dsh-tool-fs-search",
|
|
45
|
+
grep: "@deepseek-ai/dsh-tool-fs-search",
|
|
46
|
+
str_replace_editor: "@deepseek-ai/dsh-tool-str-replace-editor",
|
|
47
|
+
bash: "@deepseek-ai/dsh-tool-bash",
|
|
48
|
+
pwsh: "@deepseek-ai/dsh-tool-pwsh",
|
|
49
|
+
web_search: "@deepseek-ai/dsh-tool-web",
|
|
50
|
+
web_fetch: "@deepseek-ai/dsh-tool-web",
|
|
51
|
+
job_output: "@deepseek-ai/dsh-tool-jobs",
|
|
52
|
+
job_list: "@deepseek-ai/dsh-tool-jobs",
|
|
53
|
+
job_kill: "@deepseek-ai/dsh-tool-jobs",
|
|
54
|
+
ask_user_question: "@deepseek-ai/dsh-tool-ask-user",
|
|
55
|
+
plan: "@deepseek-ai/dsh-plan-mode",
|
|
56
|
+
exit_plan_mode: "@deepseek-ai/dsh-plan-mode",
|
|
57
|
+
skill: "@deepseek-ai/dsh-tool-skill",
|
|
58
|
+
todo_write: "@deepseek-ai/dsh-tool-todo",
|
|
59
|
+
subagent: "@deepseek-ai/dsh-tool-subagent",
|
|
60
|
+
subagent_fork: "@deepseek-ai/dsh-tool-subagent",
|
|
61
|
+
send_message: "@deepseek-ai/dsh-tool-subagent-control",
|
|
62
|
+
interrupt_agent: "@deepseek-ai/dsh-tool-subagent-control",
|
|
63
|
+
list_agents: "@deepseek-ai/dsh-tool-subagent-control",
|
|
64
|
+
ralph: "@deepseek-ai/dsh-tool-ralph",
|
|
65
|
+
workflow: "@deepseek-ai/dsh-tool-workflow",
|
|
66
|
+
run_code: "@deepseek-ai/dsh-tools",
|
|
67
|
+
schedule_create: "@deepseek-ai/dsh-schedule",
|
|
68
|
+
schedule_list: "@deepseek-ai/dsh-schedule",
|
|
69
|
+
schedule_delete: "@deepseek-ai/dsh-schedule",
|
|
70
|
+
create_goal: "@deepseek-ai/dsh-tool-goal",
|
|
71
|
+
get_goal: "@deepseek-ai/dsh-tool-goal",
|
|
72
|
+
update_goal: "@deepseek-ai/dsh-tool-goal",
|
|
73
|
+
lsp: "@deepseek-ai/dsh-tool-lsp"
|
|
74
|
+
});
|
|
75
|
+
//#endregion
|
|
76
|
+
//#region src/host/attribution.ts
|
|
77
|
+
/**
|
|
78
|
+
* Live tool→plugin attribution layered on the static recovery in
|
|
79
|
+
* toolSources.ts.
|
|
80
|
+
*
|
|
81
|
+
* The session log records tools as plain `ToolSchema` entries (name /
|
|
82
|
+
* description / parameters) — the registering plugin is not in there.
|
|
83
|
+
* toolSources.ts derives the deterministic sources (harness-logged field,
|
|
84
|
+
* `mcp:<server>` naming, pinned first-party map). This module additionally
|
|
85
|
+
* watches RUNTIME registrations: cordis fires the `internal/get` waterfall on
|
|
86
|
+
* every context read of a service property, passing the READING context as the
|
|
87
|
+
* first argument, so `reader.fiber.name` identifies the plugin that is about
|
|
88
|
+
* to call `register()`.
|
|
89
|
+
*
|
|
90
|
+
* - The `internal/get` handler records who last read the `tools` service and
|
|
91
|
+
* wraps that instance's `register` (once — an earlier wrapper of a previous
|
|
92
|
+
* hook incarnation is peeled back to the original, so a plugin reload
|
|
93
|
+
* re-wraps without stacking) to capture the reader at registration time
|
|
94
|
+
* into a live map.
|
|
95
|
+
* - When the reader slot is missing, root-named, or this plugin's own (e.g.
|
|
96
|
+
* LOCAL-LINK plugins — dev installs via `dsh plugin add <path>` or
|
|
97
|
+
* npm/pnpm link — whose anonymous entrypoints make cordis fall back to the
|
|
98
|
+
* root name), the wrapped `register` falls back to the call stack: the first
|
|
99
|
+
* frame outside this package is resolved to its nearest `package.json`
|
|
100
|
+
* `name`. That covers both npm installs (`node_modules/<pkg>`) and local
|
|
101
|
+
* links (any directory carrying a package.json), which never pass through
|
|
102
|
+
* node_modules. Frames that resolve back to this package are skipped.
|
|
103
|
+
* - `ownerOf(name)` prefers the name-derived `mcp:<server>` label (it names
|
|
104
|
+
* the actual provider, where the live record would only ever name the MCP
|
|
105
|
+
* proxy client), then the LIVE record — for a post-boot registration it is
|
|
106
|
+
* the truth, even when the name collides with a pinned first-party tool —
|
|
107
|
+
* then the pinned map (the boot-time guess for tools registered before the
|
|
108
|
+
* hook), and finally tags tools that were ALREADY registered when the hook
|
|
109
|
+
* installed (the boot snapshot — third-party bundles, e.g. local links like
|
|
110
|
+
* dsh-file-claim, that applied before dsh-context) with the
|
|
111
|
+
* `UNKNOWN_TOOL_SOURCE` sentinel: their registering plugin is unknowable,
|
|
112
|
+
* and a bare gap would read as "no plugin" instead of "unknown plugin".
|
|
113
|
+
*
|
|
114
|
+
* Best-effort by design: a read separated from `register()` by an `await` can
|
|
115
|
+
* be overwritten by another plugin's read (misattribution) and the stack
|
|
116
|
+
* fallback needs a resolvable package.json — both degrade to the name/pinned
|
|
117
|
+
* chain; registrations that predate the hook degrade to the unknown tag. The
|
|
118
|
+
* hook costs roughly +1.4us per service-property read and is negligible on
|
|
119
|
+
* the rare register path (the stack walk only runs when the reader slot is
|
|
120
|
+
* unusable, and its package lookups are cached per directory).
|
|
121
|
+
*/
|
|
122
|
+
/** This module's own file URL — the stack walk skips its own frames. */
|
|
123
|
+
const selfUrl = normalize(fileURLToPath(import.meta.url));
|
|
124
|
+
/** Directory → package-name cache for the synchronous walk below. */
|
|
125
|
+
const packageCache = /* @__PURE__ */ new Map();
|
|
126
|
+
/**
|
|
127
|
+
* Best-effort package name for a module file: walk up to the nearest
|
|
128
|
+
* `package.json` carrying a `name`. Works for dependencies installed under
|
|
129
|
+
* `node_modules` as well as local links whose package root is any on-disk
|
|
130
|
+
* directory. The per-directory results are cached.
|
|
131
|
+
* @param file - absolute path of a module file.
|
|
132
|
+
*/
|
|
133
|
+
function packageNameFrom(file) {
|
|
134
|
+
let dir = dirname(file);
|
|
135
|
+
for (let depth = 0; depth < 12; depth++) {
|
|
136
|
+
const cached = packageCache.get(dir);
|
|
137
|
+
if (cached !== void 0) return cached;
|
|
138
|
+
const packageFile = join(dir, "package.json");
|
|
139
|
+
if (existsSync(packageFile)) try {
|
|
140
|
+
const name = JSON.parse(readFileSync(packageFile, "utf8")).name;
|
|
141
|
+
if (typeof name === "string" && name) {
|
|
142
|
+
packageCache.set(dir, name);
|
|
143
|
+
return name;
|
|
144
|
+
}
|
|
145
|
+
} catch {}
|
|
146
|
+
const parent = dirname(dir);
|
|
147
|
+
packageCache.set(dir, void 0);
|
|
148
|
+
if (parent === dir) return void 0;
|
|
149
|
+
dir = parent;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
const FRAME_POSITION = /:\d+:\d+$/;
|
|
153
|
+
/** Package name of this module's own package (self-fallbacks are filtered). */
|
|
154
|
+
const selfPackage = packageNameFrom(selfUrl);
|
|
155
|
+
/**
|
|
156
|
+
* Resolve the registering package from a stack trace: walk frames from the
|
|
157
|
+
* innermost out, skipping this module's own frames and frames that resolve to
|
|
158
|
+
* this package, and return the package name of the first frame that resolves
|
|
159
|
+
* elsewhere. Works with both `file://` URLs and bare absolute paths
|
|
160
|
+
* (transpiled modules render without a scheme), with optional `fn (...)` and
|
|
161
|
+
* `async` wrappers.
|
|
162
|
+
* @param stack - `Error().stack`, or undefined when no fallback is desired.
|
|
163
|
+
*/
|
|
164
|
+
function callerPackageFrom(stack) {
|
|
165
|
+
if (!stack) return void 0;
|
|
166
|
+
for (const raw of stack.split("\n").slice(1)) {
|
|
167
|
+
let line = raw.trim();
|
|
168
|
+
if (!line.startsWith("at ")) continue;
|
|
169
|
+
line = line.slice(3);
|
|
170
|
+
if (line.startsWith("async ")) line = line.slice(6);
|
|
171
|
+
line = line.replace(/\)\s*$/, "");
|
|
172
|
+
const position = FRAME_POSITION.exec(line);
|
|
173
|
+
if (!position) continue;
|
|
174
|
+
let target = line.slice(0, -position[0].length);
|
|
175
|
+
if (target.includes("(")) target = target.slice(target.lastIndexOf("(") + 1);
|
|
176
|
+
if (target.startsWith("file://")) try {
|
|
177
|
+
target = normalize(fileURLToPath(target));
|
|
178
|
+
} catch {
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
else if (!/^[A-Za-z]:[\\/]/.test(target) && !target.startsWith("/") && !target.startsWith("\\\\")) continue;
|
|
182
|
+
else target = normalize(target);
|
|
183
|
+
if (target === selfUrl) continue;
|
|
184
|
+
const name = packageNameFrom(target);
|
|
185
|
+
if (name !== void 0 && name !== selfPackage) return name;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Install the runtime-attribution hook on a cordis app context. The hook
|
|
190
|
+
* rides the calling fiber's lifetime (`ctx.on` / `ctx.get`), so it is
|
|
191
|
+
* disposed with the plugin.
|
|
192
|
+
* @param ctx - the context the dsh-context plugin runs in; its fiber name is
|
|
193
|
+
* excluded from attributions.
|
|
194
|
+
*/
|
|
195
|
+
function createToolAttribution(ctx) {
|
|
196
|
+
const live = /* @__PURE__ */ new Map();
|
|
197
|
+
const wrapped = /* @__PURE__ */ new WeakSet();
|
|
198
|
+
const self = ctx.fiber.name;
|
|
199
|
+
let lastReader;
|
|
200
|
+
const wrapInstance = (tools) => {
|
|
201
|
+
if (!tools || typeof tools !== "object" || wrapped.has(tools)) return;
|
|
202
|
+
const register = tools.register;
|
|
203
|
+
if (typeof register !== "function") return;
|
|
204
|
+
wrapped.add(tools);
|
|
205
|
+
const original = register.attributedOriginal ?? register;
|
|
206
|
+
if (typeof original !== "function") return;
|
|
207
|
+
const instance = tools;
|
|
208
|
+
const wrappedRegister = function(definition) {
|
|
209
|
+
const toolName = definition?.name;
|
|
210
|
+
let owner = lastReader?.fiber.name;
|
|
211
|
+
if (!owner || owner === "root" || owner === self) owner = callerPackageFrom((/* @__PURE__ */ new Error()).stack);
|
|
212
|
+
const dispose = original.call(this, definition);
|
|
213
|
+
if (typeof toolName === "string" && owner && owner !== "root" && owner !== self && owner !== selfPackage) {
|
|
214
|
+
live.set(toolName, owner);
|
|
215
|
+
if (typeof dispose === "function") return () => {
|
|
216
|
+
try {
|
|
217
|
+
return dispose();
|
|
218
|
+
} finally {
|
|
219
|
+
live.delete(toolName);
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
return dispose;
|
|
224
|
+
};
|
|
225
|
+
wrappedRegister.attributedOriginal = original;
|
|
226
|
+
instance.register = wrappedRegister;
|
|
227
|
+
};
|
|
228
|
+
ctx.on("internal/get", (reader, name, _error, next) => {
|
|
229
|
+
if (name !== "tools") return next();
|
|
230
|
+
const tools = next();
|
|
231
|
+
lastReader = reader;
|
|
232
|
+
wrapInstance(tools);
|
|
233
|
+
return tools;
|
|
234
|
+
});
|
|
235
|
+
const toolsService = ctx.get("tools", false);
|
|
236
|
+
wrapInstance(toolsService);
|
|
237
|
+
const boot = /* @__PURE__ */ new Set();
|
|
238
|
+
try {
|
|
239
|
+
const toolEntries = toolsService?.layers?.global?.tools;
|
|
240
|
+
if (toolEntries !== void 0 && typeof toolEntries.entries === "function") for (const [name] of toolEntries.entries()) boot.add(name);
|
|
241
|
+
} catch {}
|
|
242
|
+
return { ownerOf: (name) => mcpSourceOf(name) ?? live.get(name) ?? pinnedSourceOf(name) ?? (boot.has(name) ? "<unknown-plugin>" : void 0) };
|
|
243
|
+
}
|
|
244
|
+
//#endregion
|
|
5
245
|
//#region src/host/config.ts
|
|
6
246
|
/**
|
|
7
247
|
* dsh-context host configuration — the `config:` block of the `dsh-context`
|
|
@@ -322,6 +562,7 @@ const headerToolSchema = z.object({
|
|
|
322
562
|
name: z.string(),
|
|
323
563
|
tokens: z.number().int().nonnegative(),
|
|
324
564
|
description: z.string().optional(),
|
|
565
|
+
plugin: z.string().optional(),
|
|
325
566
|
schema: z.unknown().optional()
|
|
326
567
|
}).strict();
|
|
327
568
|
const contextHeadersSchema = z.object({ headers: z.array(z.object({
|
|
@@ -352,6 +593,7 @@ function recordOf(event) {
|
|
|
352
593
|
schema: t
|
|
353
594
|
};
|
|
354
595
|
if (typeof tool.description === "string" && tool.description !== "") entry.description = tool.description;
|
|
596
|
+
if (typeof tool.plugin === "string" && tool.plugin !== "") entry.plugin = tool.plugin;
|
|
355
597
|
return entry;
|
|
356
598
|
})
|
|
357
599
|
};
|
|
@@ -362,11 +604,20 @@ function recordOf(event) {
|
|
|
362
604
|
* The context-headers projection unit; registered alongside the timeline unit (host/index.ts); clients read it through
|
|
363
605
|
* `useProjection('contextHeaders')` and degrade to tokens-only header sections when the key is absent. Dual-contract definition (see
|
|
364
606
|
* compat.ts).
|
|
607
|
+
* @param resolve - best-effort tool-to-plugin attribution (see toolSources.ts); fills a missing `plugin` at view time so
|
|
608
|
+
* epochs folded without attribution still render a tag when the source is known.
|
|
365
609
|
*/
|
|
366
|
-
function createContextHeadersDefinition() {
|
|
610
|
+
function createContextHeadersDefinition(resolve) {
|
|
367
611
|
const view = (state) => ({ headers: state.headers.map((h) => ({
|
|
368
612
|
...h,
|
|
369
|
-
tools: h.tools.map((t) =>
|
|
613
|
+
tools: h.tools.map((t) => {
|
|
614
|
+
if (resolve === void 0 || t.plugin !== void 0) return { ...t };
|
|
615
|
+
const plugin = resolve(t.name);
|
|
616
|
+
return plugin === void 0 ? { ...t } : {
|
|
617
|
+
...t,
|
|
618
|
+
plugin
|
|
619
|
+
};
|
|
620
|
+
})
|
|
370
621
|
})) });
|
|
371
622
|
return {
|
|
372
623
|
key: "contextHeaders",
|
|
@@ -834,9 +1085,9 @@ function buildTimelineView(state, bounds) {
|
|
|
834
1085
|
const surfaceTotal = state.sums.user + state.sums.inject + state.sums.assistant + state.sums.tool;
|
|
835
1086
|
const result = {
|
|
836
1087
|
ok: true,
|
|
837
|
-
model: state.model,
|
|
838
|
-
provider: state.provider,
|
|
839
|
-
contextWindow: state.contextWindow,
|
|
1088
|
+
...state.model !== void 0 ? { model: state.model } : {},
|
|
1089
|
+
...state.provider !== void 0 ? { provider: state.provider } : {},
|
|
1090
|
+
...state.contextWindow !== void 0 ? { contextWindow: state.contextWindow } : {},
|
|
840
1091
|
current: {
|
|
841
1092
|
system: state.systemTokens,
|
|
842
1093
|
tools: state.toolsTokens,
|
|
@@ -1063,6 +1314,9 @@ const timelineStateSchema = z.object({
|
|
|
1063
1314
|
* The definition carries BOTH session-projection contracts (see compat.ts):
|
|
1064
1315
|
* `schema`/`view` for dsh <= 0.1.0-rc.8, `stateSchema`/`wire` for
|
|
1065
1316
|
* dsh >= 0.1.1-rc.1 — each registry reads its own fields off the same unit.
|
|
1317
|
+
* (The return type is the mirrored dual contract, not the installed dts
|
|
1318
|
+
* `ProjectionDefinition`: the 0.1.1+ registry's wired-register overload
|
|
1319
|
+
* demands `wire` PRESENT, which the dts's optional `wire?` fails.)
|
|
1066
1320
|
* Without the `wire` block the 0.1.1-rc.1+ registry treats the unit as
|
|
1067
1321
|
* host-only and never delivers `contextTimeline` to the browser (the Context
|
|
1068
1322
|
* tab would stay on its loading screen forever).
|
|
@@ -1089,8 +1343,9 @@ function createContextTimelineDefinition(config) {
|
|
|
1089
1343
|
const name = "dsh-context";
|
|
1090
1344
|
const inject = ["sessionProjections"];
|
|
1091
1345
|
function apply(ctx, config) {
|
|
1346
|
+
const attribution = createToolAttribution(ctx);
|
|
1092
1347
|
ctx.sessionProjections.register(createContextTimelineDefinition(config));
|
|
1093
|
-
ctx.sessionProjections.register(createContextHeadersDefinition());
|
|
1348
|
+
ctx.sessionProjections.register(createContextHeadersDefinition((name) => attribution.ownerOf(name)));
|
|
1094
1349
|
installSettings(ctx);
|
|
1095
1350
|
}
|
|
1096
1351
|
//#endregion
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-context",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.37.0",
|
|
4
4
|
"description": "A DeepSeek Harness plugin for context insight and management, with context dashboard and context command, for understanding how the context is made of, and how it evolves.",
|
|
5
5
|
"author": "bowenliang123",
|
|
6
6
|
"repository": {
|
|
@@ -52,7 +52,6 @@
|
|
|
52
52
|
"inject": [
|
|
53
53
|
"@deepseek-ai/dsh-client-connection",
|
|
54
54
|
"@deepseek-ai/dsh-client-locale",
|
|
55
|
-
"@deepseek-ai/dsh-client-runtime",
|
|
56
55
|
"@deepseek-ai/dsh-client-ui-conversation",
|
|
57
56
|
"@deepseek-ai/dsh-client-ui-settings"
|
|
58
57
|
],
|
|
@@ -71,9 +70,9 @@
|
|
|
71
70
|
"license": "Apache-2.0",
|
|
72
71
|
"peerDependencies": {
|
|
73
72
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
74
|
-
"@deepseek-ai/dsh-client-ui-primitives": "
|
|
75
|
-
"@deepseek-ai/dsh-session": "
|
|
76
|
-
"@deepseek-ai/dsh-settings": "
|
|
73
|
+
"@deepseek-ai/dsh-client-ui-primitives": ">=0.1.0-rc.7",
|
|
74
|
+
"@deepseek-ai/dsh-session": ">=0.1.0-rc.7",
|
|
75
|
+
"@deepseek-ai/dsh-settings": ">=0.1.0-rc.7",
|
|
77
76
|
"@deepseek-ai/schemastery": "^3.18.1",
|
|
78
77
|
"react": "^18.3.1",
|
|
79
78
|
"zod": "^4.4.3"
|
|
@@ -88,10 +87,10 @@
|
|
|
88
87
|
},
|
|
89
88
|
"devDependencies": {
|
|
90
89
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
91
|
-
"@deepseek-ai/dsh-client-ui-primitives": "^0.1.
|
|
92
|
-
"@deepseek-ai/dsh-session": "^0.1.
|
|
93
|
-
"@deepseek-ai/dsh-session-projection": "^0.1.
|
|
94
|
-
"@deepseek-ai/dsh-settings": "^0.1.
|
|
90
|
+
"@deepseek-ai/dsh-client-ui-primitives": "^0.1.1-rc.2",
|
|
91
|
+
"@deepseek-ai/dsh-session": "^0.1.1-rc.2",
|
|
92
|
+
"@deepseek-ai/dsh-session-projection": "^0.1.1-rc.2",
|
|
93
|
+
"@deepseek-ai/dsh-settings": "^0.1.1-rc.2",
|
|
95
94
|
"@deepseek-ai/schemastery": "^3.18.1",
|
|
96
95
|
"@stylistic/eslint-plugin": "^5.10.0",
|
|
97
96
|
"@types/node": "^26.2.0",
|