dsh-mindmap 0.7.0 → 0.8.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 +5 -0
- package/client.js +41 -9
- package/index.js +19 -7
- package/package.json +5 -1
package/CHANGELOG.md
CHANGED
|
@@ -23,6 +23,11 @@ All notable changes to this project are documented here. Release-specific notes
|
|
|
23
23
|
|
|
24
24
|
### Fixed
|
|
25
25
|
|
|
26
|
+
- Compatibility with dsh 0.1.2-rc.1 (statically verified, docs/023), while keeping 0.1.1-rc.2 working — all fixes are dual-path with the old path first:
|
|
27
|
+
- **Host tools**: `Agent` no longer carries a live `session` (it is reduced to `{ id }`), so `sessionCwd` now falls back from `exec.agent.session.header.cwd` (dsh ≤0.1.1) to looking the session up via `ctx.sessions.get(exec.agent.id).header.cwd` (0.1.2-rc.1). Without this, every tool failed with "the session has no working directory" on 0.1.2-rc.1.
|
|
28
|
+
- **Live panel data**: the session snapshot no longer carries a flat `nodes` array (conversation content moved to the Chat view), so the panel now reads nodes via `useChat → ChatSnapshot.legacy.nodes` (0.1.2-rc.1+) first and falls back to `useSession → SessionSnapshot.nodes` (dsh ≤0.1.1). `ToolResultNode` field names are unchanged across both, so document replay, auto-open, and error surfacing work as before.
|
|
29
|
+
- **Settings panel**: `settings.describe` over the client connection now returns the descriptor array directly (0.1.2-rc.1+) instead of an aggregate `result.value.namespaces` (dsh ≤0.1.1); both envelope shapes are parsed.
|
|
30
|
+
- **Hygiene**: `dsh.client.inject` additionally lists `@deepseek-ai/dsh-cordis-client-runner` (the 0.1.2-rc.1 browser runtime module id; `@deepseek-ai/dsh-client-runtime` is kept for 0.1.1-rc.2 — a missing id is silently skipped by the loader, so both coexist safely).
|
|
26
31
|
- The panel now reliably auto-opens when the AI completes `mindmap_open` / `mindmap_create`. A structural fingerprint of the session nodes (`nodesFingerprint`) feeds a second `useSession` selector; its value comparison bypasses the reference-equality short-circuit that starved the auto-open effect whenever the host store mutated the nodes array in place.
|
|
27
32
|
- The "AI 正在打开脑图…" loading state is no longer a dead end. Snapshot documents whose path differs from the tree-click key only by letter case (macOS case-insensitive filesystem) now merge automatically; errored mindmap tool results (`isError` or `ok !== true`) surface as an inline error; a ~30s watchdog switches to a timeout state. Both failure states offer a one-click retry that re-sends the open request.
|
|
28
33
|
- A code-review sweep (`_issues/002`) landed 11 fixes, each with a failing regression test first:
|
package/client.js
CHANGED
|
@@ -7,9 +7,10 @@
|
|
|
7
7
|
// - 脑图面板:014 起注册在 shell.overlay(list 槽、root scope、点击穿透层),
|
|
8
8
|
// 右缘贴边全高悬浮、左缘拖拽调宽(280~80% 视口,localStorage 持久化);
|
|
9
9
|
// details 槽已归还官方(原生「工具详情」栏恢复,003 的顶替方案退役)。
|
|
10
|
-
// -
|
|
11
|
-
//
|
|
12
|
-
//
|
|
10
|
+
// - 实时数据通路:消费会话快照里 mindmap_* 工具的 ToolResultNode,重放出各文档
|
|
11
|
+
// 的最新内容并渲染(002/003:无自定义事件通道,工具调用本身就是事件流)。
|
|
12
|
+
// 023 双代:useChat → ChatSnapshot.legacy.nodes(dsh 0.1.2-rc.1+)优先,
|
|
13
|
+
// useSession → SessionSnapshot.nodes(dsh ≤0.1.1)兜底。
|
|
13
14
|
// - markdown→脑图树:本文件内置零依赖解析器(MarkGrove mdastConverter 的映射
|
|
14
15
|
// 语法移植:标题栈→树、列表→子节点、空列表项=占位节点、代码块→首行摘要叶
|
|
15
16
|
// 节点、段落→挂标题的正文说明、结构路径稳定 ID)。
|
|
@@ -1498,20 +1499,35 @@ window.__ModuleLoader__.load({
|
|
|
1498
1499
|
] });
|
|
1499
1500
|
}
|
|
1500
1501
|
|
|
1502
|
+
/**
|
|
1503
|
+
* 会话内容节点的双代快照选择(023):dsh ≤0.1.1 的 useSession 快照带
|
|
1504
|
+
* 平铺 nodes;0.1.2-rc.1 起 SessionSnapshot 拆成纯控制状态,会话内容
|
|
1505
|
+
* 迁入 useChat 的 ChatSnapshot.legacy.nodes(官方兼容面,ToolResultNode
|
|
1506
|
+
* 字段同名)。legacy 优先、旧 nodes 兜底,两代通吃。
|
|
1507
|
+
*/
|
|
1508
|
+
function conversationNodesOf(s) {
|
|
1509
|
+
if (!s) return EMPTY_NODES;
|
|
1510
|
+
const legacy = s.legacy;
|
|
1511
|
+
if (legacy && Array.isArray(legacy.nodes)) return legacy.nodes;
|
|
1512
|
+
return Array.isArray(s.nodes) ? s.nodes : EMPTY_NODES;
|
|
1513
|
+
}
|
|
1514
|
+
|
|
1501
1515
|
/**
|
|
1502
1516
|
* 「思维脑图」槽位组件(014):同一槽位渲染 M 按钮 + 悬浮面板宿主层。
|
|
1503
1517
|
* session scope 的 useSession/sessionId/inputActions 直给,经 props 传给
|
|
1504
1518
|
* MindmapDetailsPanel(无桥、无 useSyncExternalStore——shell.overlay 跨槽
|
|
1505
|
-
* 方案实测未渲染,弃用后顺手把桥也删了)。
|
|
1519
|
+
* 方案实测未渲染,弃用后顺手把桥也删了)。023:内容钩子改为
|
|
1520
|
+
* useChat(0.1.2-rc.1+)优先、useSession(≤0.1.1)兜底。
|
|
1506
1521
|
*/
|
|
1507
1522
|
function MindmapSlot(props) {
|
|
1508
|
-
const { useSession, sessionId, inputActions, mindmapFace } = props;
|
|
1509
|
-
const
|
|
1523
|
+
const { useSession, useChat, sessionId, inputActions, mindmapFace } = props;
|
|
1524
|
+
const nodesHook = useChat ?? useSession;
|
|
1525
|
+
const nodes = nodesHook ? nodesHook(conversationNodesOf) : EMPTY_NODES;
|
|
1510
1526
|
// 016 可靠性加固:结构指纹作第二 selector。store 原地改数组(引用
|
|
1511
1527
|
// 不变)时,nodes prop 不换、memo 命中缓存、auto-open effect 永不
|
|
1512
1528
|
// 重跑——「AI 打开了脑图但面板不展开」的根因。指纹是原始值字符串,
|
|
1513
|
-
//
|
|
1514
|
-
const nodesVersion =
|
|
1529
|
+
// 值比较天然绕过引用相等短路;内容钩子不可用时回退空串。
|
|
1530
|
+
const nodesVersion = nodesHook ? nodesHook((s) => nodesFingerprint(conversationNodesOf(s))) : "";
|
|
1515
1531
|
const [open, setOpen] = react.useState(false);
|
|
1516
1532
|
return (0, react_jsx_runtime.jsxs)(react.Fragment, { children: [
|
|
1517
1533
|
(0, react_jsx_runtime.jsxs)("button", {
|
|
@@ -3270,6 +3286,19 @@ window.__ModuleLoader__.load({
|
|
|
3270
3286
|
}
|
|
3271
3287
|
//#endregion
|
|
3272
3288
|
|
|
3289
|
+
/**
|
|
3290
|
+
* settings describe 应答的双代信封解析(023):dsh ≤0.1.1 的远端把
|
|
3291
|
+
* 描述符聚合在 result.value.namespaces[];0.1.2-rc.1 起直接返回描述符
|
|
3292
|
+
* 数组(每项 {ns, schema, value, …},字段两代同名)。数组优先、
|
|
3293
|
+
* namespaces 兜底,两代通吃。
|
|
3294
|
+
*/
|
|
3295
|
+
function settingsNamespacesOf(res) {
|
|
3296
|
+
const value = res?.result?.value;
|
|
3297
|
+
if (Array.isArray(value)) return value;
|
|
3298
|
+
const list = value?.namespaces;
|
|
3299
|
+
return Array.isArray(list) ? list : [];
|
|
3300
|
+
}
|
|
3301
|
+
|
|
3273
3302
|
function apply(ctx) {
|
|
3274
3303
|
const face = {};
|
|
3275
3304
|
|
|
@@ -3331,7 +3360,7 @@ window.__ModuleLoader__.load({
|
|
|
3331
3360
|
face.readSettings = async () => {
|
|
3332
3361
|
if (!settingsApi || typeof settingsApi.settings?.describe !== "function") return null;
|
|
3333
3362
|
const res = await settingsApi.settings.describe({});
|
|
3334
|
-
const namespaces = res
|
|
3363
|
+
const namespaces = settingsNamespacesOf(res);
|
|
3335
3364
|
const ns = namespaces.find((n) => n?.ns === "mindmap");
|
|
3336
3365
|
return ns?.value ?? null;
|
|
3337
3366
|
};
|
|
@@ -3413,6 +3442,9 @@ window.__ModuleLoader__.load({
|
|
|
3413
3442
|
isActivatable,
|
|
3414
3443
|
TOOL_NAMES,
|
|
3415
3444
|
OPENING_OPS,
|
|
3445
|
+
// 023 双代兼容纯函数(供测试):会话内容节点 / settings 信封。
|
|
3446
|
+
conversationNodesOf,
|
|
3447
|
+
settingsNamespacesOf,
|
|
3416
3448
|
// 021 画布组件:仅供测试驱动平移手势(不参与运行时契约)。
|
|
3417
3449
|
MindmapCanvas,
|
|
3418
3450
|
});
|
package/index.js
CHANGED
|
@@ -65,9 +65,21 @@ function textOut(value) {
|
|
|
65
65
|
return [{ type: 'text', text: String(value) }]
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
/**
|
|
69
|
-
|
|
70
|
-
|
|
68
|
+
/**
|
|
69
|
+
* 会话工作目录:工具执行的 agent → session → header.cwd(dsh-session 契约)。
|
|
70
|
+
* 023 双路径:dsh ≤0.1.1 的 Agent 直挂 live session(agent.session.header.cwd);
|
|
71
|
+
* 0.1.2-rc.1 起 Agent 只剩 { id },改经 sessions 服务按 id 查 header.cwd
|
|
72
|
+
* (SessionStore.get / SessionHeader.cwd 两代同名)。旧链优先,新链兜底。
|
|
73
|
+
*/
|
|
74
|
+
function sessionCwd(exec, sessions) {
|
|
75
|
+
const direct = exec?.agent?.session?.header?.cwd
|
|
76
|
+
if (direct) return direct
|
|
77
|
+
const id = exec?.agent?.id
|
|
78
|
+
if (id && sessions?.get) {
|
|
79
|
+
const cwd = sessions.get(id)?.header?.cwd
|
|
80
|
+
if (cwd) return cwd
|
|
81
|
+
}
|
|
82
|
+
return undefined
|
|
71
83
|
}
|
|
72
84
|
|
|
73
85
|
//#region 013 目录树 API(host 自建只读 HTTP 路由;dsh-better-sidebar 同款机制)
|
|
@@ -355,7 +367,7 @@ export function apply(ctx, config = {}) {
|
|
|
355
367
|
output: { schema: { type: 'string' }, render: (_args, value) => textOut(value) },
|
|
356
368
|
timeoutMs: TOOL_TIMEOUT_MS,
|
|
357
369
|
async execute(args, exec) {
|
|
358
|
-
const cwd = sessionCwd(exec)
|
|
370
|
+
const cwd = sessionCwd(exec, ctx.sessions)
|
|
359
371
|
if (!cwd) throw new Error('The session has no working directory; cannot create a mindmap.')
|
|
360
372
|
const stem = sanitizeStem(args?.name)
|
|
361
373
|
const path = await resolveMindmapPath(cwd, `${stem}.md`)
|
|
@@ -385,7 +397,7 @@ export function apply(ctx, config = {}) {
|
|
|
385
397
|
output: { schema: { type: 'string' }, render: (_args, value) => textOut(value) },
|
|
386
398
|
timeoutMs: TOOL_TIMEOUT_MS,
|
|
387
399
|
async execute(args, exec) {
|
|
388
|
-
const path = await resolveMindmapPath(sessionCwd(exec), args?.path)
|
|
400
|
+
const path = await resolveMindmapPath(sessionCwd(exec, ctx.sessions), args?.path)
|
|
389
401
|
const content = await readFile(path, 'utf8')
|
|
390
402
|
return buildResult('open', path, { content })
|
|
391
403
|
},
|
|
@@ -404,7 +416,7 @@ export function apply(ctx, config = {}) {
|
|
|
404
416
|
output: { schema: { type: 'string' }, render: (_args, value) => textOut(value) },
|
|
405
417
|
timeoutMs: TOOL_TIMEOUT_MS,
|
|
406
418
|
async execute(args, exec) {
|
|
407
|
-
const path = await resolveMindmapPath(sessionCwd(exec), args?.path)
|
|
419
|
+
const path = await resolveMindmapPath(sessionCwd(exec, ctx.sessions), args?.path)
|
|
408
420
|
const content = await readFile(path, 'utf8')
|
|
409
421
|
return buildResult('get', path, { content })
|
|
410
422
|
},
|
|
@@ -425,7 +437,7 @@ export function apply(ctx, config = {}) {
|
|
|
425
437
|
output: { schema: { type: 'string' }, render: (_args, value) => textOut(value) },
|
|
426
438
|
timeoutMs: TOOL_TIMEOUT_MS,
|
|
427
439
|
async execute(args, exec) {
|
|
428
|
-
const cwd = sessionCwd(exec)
|
|
440
|
+
const cwd = sessionCwd(exec, ctx.sessions)
|
|
429
441
|
const path = await resolveMindmapPath(cwd, args?.path)
|
|
430
442
|
const hasContent = typeof args?.content === 'string'
|
|
431
443
|
if (!hasContent && typeof args?.renameRoot !== 'string') {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-mindmap",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.1",
|
|
4
4
|
"description": "Mindmap plugin for DeepSeek Harness: a plain markdown file in the working directory IS the mindmap; the chat edits it step by step and the right-side panel follows live.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -35,6 +35,9 @@
|
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"@deepseek-ai/schemastery": "^3.18.0"
|
|
37
37
|
},
|
|
38
|
+
"peerDependencies": {
|
|
39
|
+
"@deepseek-ai/dsh-tools": "^0.1.0-rc.6 || ^0.1.1-rc.0 || ^0.1.2-alpha.0 || ^0.1.3-alpha.0"
|
|
40
|
+
},
|
|
38
41
|
"dsh": {
|
|
39
42
|
"bundle": {
|
|
40
43
|
"patch": "./cordis.patch.yml"
|
|
@@ -42,6 +45,7 @@
|
|
|
42
45
|
"client": {
|
|
43
46
|
"inject": [
|
|
44
47
|
"@deepseek-ai/dsh-client-runtime",
|
|
48
|
+
"@deepseek-ai/dsh-cordis-client-runner",
|
|
45
49
|
"@deepseek-ai/dsh-client-ui-layout"
|
|
46
50
|
],
|
|
47
51
|
"platform": "web",
|