dsh-openwrite 0.2.18 → 0.2.20

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.
Files changed (45) hide show
  1. package/README.md +22 -5
  2. package/docs/ISSUE_76_REPAIRS.md +61 -0
  3. package/docs/RELEASE_ACCEPTANCE.md +10 -1
  4. package/package.json +1 -1
  5. package/packages/openwrite-bridge/lib/client.d.ts +1 -0
  6. package/packages/openwrite-bridge/lib/client.js +26 -4
  7. package/packages/openwrite-bridge/lib/contracts-generated.d.ts +1 -1
  8. package/packages/openwrite-bridge/lib/contracts-generated.js +1 -2
  9. package/packages/openwrite-bridge/lib/domain.js +2 -0
  10. package/packages/openwrite-bridge/lib/index.js +6 -6
  11. package/packages/openwrite-bridge/lib/managed-runtime.js +37 -37
  12. package/packages/openwrite-bridge/lib/tools.js +198 -32
  13. package/packages/studio-panel/lib/client.js +488 -488
  14. package/presets/openwrite/agent.cordis.yml +10 -2
  15. package/presets/openwrite/skills/canon/SKILL.md +2 -0
  16. package/presets/openwrite/skills/dialoguequality/SKILL.md +2 -0
  17. package/presets/openwrite/skills/dog-delivery-query/SKILL.md +2 -0
  18. package/presets/openwrite/skills/dog-import-query/SKILL.md +2 -0
  19. package/presets/openwrite/skills/dog-review-query/SKILL.md +2 -0
  20. package/presets/openwrite/skills/export-book/SKILL.md +2 -0
  21. package/presets/openwrite/skills/foreshadow/SKILL.md +2 -0
  22. package/presets/openwrite/skills/foreshadowing-system/SKILL.md +2 -0
  23. package/presets/openwrite/skills/learn/SKILL.md +2 -0
  24. package/presets/openwrite/skills/novel-creator/SKILL.md +2 -0
  25. package/presets/openwrite/skills/novel-reviewer/SKILL.md +2 -0
  26. package/presets/openwrite/skills/oh-story-deslop/SKILL.md +2 -0
  27. package/presets/openwrite/skills/oh-story-long-analyze/SKILL.md +2 -0
  28. package/presets/openwrite/skills/oh-story-long-scan/SKILL.md +2 -0
  29. package/presets/openwrite/skills/oh-story-long-write/SKILL.md +2 -0
  30. package/presets/openwrite/skills/oh-story-review/SKILL.md +2 -0
  31. package/presets/openwrite/skills/progress/SKILL.md +2 -0
  32. package/presets/openwrite/skills/review-chapter/SKILL.md +2 -0
  33. package/presets/openwrite/skills/revise-span/SKILL.md +2 -0
  34. package/presets/openwrite/skills/style-system/SKILL.md +2 -0
  35. package/presets/openwrite/skills/truth-validation/SKILL.md +2 -0
  36. package/presets/openwrite/skills/workflow-manager/SKILL.md +2 -0
  37. package/presets/openwrite/skills/world-query/SKILL.md +2 -0
  38. package/presets/openwrite/skills/write-next/SKILL.md +2 -0
  39. package/release/{openwrite-5.8.9-py3-none-any.whl → openwrite-5.8.10-py3-none-any.whl} +0 -0
  40. package/release/runtime-manifest.json +9 -6
  41. package/release/source.json +3 -3
  42. package/vendor/dsh-dog/lib/core.js +1 -1
  43. package/vendor/dsh-dog/lib/index.d.ts +1 -1
  44. package/vendor/dsh-dog/lib/index.js +202 -4
  45. package/vendor/dsh-dog/lib/{core-DdfMcrB4.js → core-BAlgZpLq.js} +2 -2
@@ -15,6 +15,14 @@
15
15
  name: '@deepseek-ai/dsh-persona'
16
16
  config:
17
17
  text: &openwrite_persona |-
18
+ Language contract: respond, ask questions, explain errors, and render slash-command help in
19
+ the author's current conversation language. Preserve the language of existing manuscripts,
20
+ outlines and assets unless the author asks to translate them. Chinese skill instructions
21
+ describe procedures; they do not require Chinese output. Translate their headings and help
22
+ when presenting them. In English conversations, use English throughout the creative loop.
23
+ Writing tasks return a task_id immediately; poll novel_task_get until terminal and present
24
+ cancellation as requested until the task reports cancelled. Resume saved drafts via run_id_v2.
25
+
18
26
  你是 OpenWrite 创作 Agent,运行在 DeepSeek Harness(dsh)的统一 OpenWrite 预设中。
19
27
  你通过 openwrite-bridge 插件提供的 novel_* 工具读写 OpenWrite 小说项目
20
28
  (底层走 OpenWrite Studio 的 HTTP 动作面),同时保留 dsh 的文件、Shell、检索等基础能力。
@@ -49,9 +57,9 @@
49
57
  定位正式实体并读取最新版本。正文、正典和其他普通文档的每个独立修改分别调用
50
58
  novel_document_change_plan(action="preview");大纲、资产、创作重点、伏笔和写作目标的每个独立
51
59
  修改分别调用 novel_structured_change_plan(action="preview")。向用户展示返回的 before/after 与来源版本;
52
- 只有用户明确确认后,才把原 preview_token 原样传给 action="apply",不得重新生成路径、
60
+ 只有用户明确确认后,才把原 preview_token 原样传给 action="apply", confirm=true,不得重新生成路径、
53
61
  锚点或内容。用户拒绝时用 action="reject";源文件冲突时用 action="retry" 生成新预览;
54
- 已应用项需要撤销时,只能把返回的 undo_preview_token 传给 action="undo"。
62
+ 已应用项需要撤销时,只能把返回的 undo_preview_token 传给 action="undo", confirm=true。
55
63
  novel_doc_write 是已获明确授权的完整文档写入兼容入口,不得用它绕过逐项预览。
56
64
  完成写入后可用 novel_trace_list 核对来源、预算、模型调用、工具调用和领域变更。Trace 只保留摘要、
57
65
  revision 与用量,作品正文、提示原文、模型原文、凭据和推理内容不得写入 trace。
@@ -3,6 +3,8 @@ name: canon
3
3
  description: 查设定。Use when the author asks 查设定, 人物卡, 世界观, or types /canon. Read registered assets and search; do not create a second lorebook.
4
4
  ---
5
5
 
6
+ Language: follow the author's current conversation language for responses and help; preserve the manuscript language. Translate these instructions when presenting them.
7
+
6
8
  # 查设定
7
9
 
8
10
  接到已有 `novel_*`。人物、地点、世界观以 OpenWrite 资产为准。
@@ -4,6 +4,8 @@ description: Use when user wants to analyze dialogue style, extract speech patte
4
4
  user-invocable: false
5
5
  ---
6
6
 
7
+ Language: follow the author's current conversation language for responses and help; preserve the manuscript language. Translate these instructions when presenting them.
8
+
7
9
  # 对话质量系统
8
10
 
9
11
  用于分析角色对白、提取说话习惯、检查角色声音是否区分明显,以及识别 AI 味对话问题。
@@ -4,6 +4,8 @@ description: Query a chapter delivery DoG graph across manuscript, review, revis
4
4
  user-invocable: false
5
5
  ---
6
6
 
7
+ Language: follow the author's current conversation language for responses and help; preserve the manuscript language. Translate these instructions when presenting them.
8
+
7
9
  # 章节交付 DoG 查询
8
10
 
9
11
  章节写作、评审和修订工具会生成:
@@ -4,6 +4,8 @@ description: Query a smart-import DoG graph after a novel has been split into ch
4
4
  user-invocable: false
5
5
  ---
6
6
 
7
+ Language: follow the author's current conversation language for responses and help; preserve the manuscript language. Translate these instructions when presenting them.
8
+
7
9
  # 拆书导入 DoG 验收
8
10
 
9
11
  `conductor/smart_import.py` 完成导入后会生成 `dog-graph.json`。这张图只验收导入
@@ -4,6 +4,8 @@ description: Query an existing hierarchical OpenWrite review-v2 artifact through
4
4
  user-invocable: false
5
5
  ---
6
6
 
7
+ Language: follow the author's current conversation language for responses and help; preserve the manuscript language. Translate these instructions when presenting them.
8
+
7
9
  # 分层评审 DoG 查询
8
10
 
9
11
  这个 Skill 只查询 OpenWrite 已物化的 review-v2 artifact。OpenWrite 的
@@ -3,6 +3,8 @@ name: export-book
3
3
  description: 导出。Use when the author asks 导出, 备份, 出书, EPUB, or types /export-book. Preflight first; never use the host /export session-log command for the manuscript.
4
4
  ---
5
5
 
6
+ Language: follow the author's current conversation language for responses and help; preserve the manuscript language. Translate these instructions when presenting them.
7
+
6
8
  # 导出
7
9
 
8
10
  接到已有 `novel_*`。成稿导出与会话日志下载不是同一条命令。
@@ -3,6 +3,8 @@ name: foreshadow
3
3
  description: 查伏笔。Use when the author asks 查伏笔, 待回收, 超期伏笔, or types /foreshadow. Read chapter obligations and continuity; do not keep a second foreshadow store.
4
4
  ---
5
5
 
6
+ Language: follow the author's current conversation language for responses and help; preserve the manuscript language. Translate these instructions when presenting them.
7
+
6
8
  # 查伏笔
7
9
 
8
10
  接到已有 `novel_*`。伏笔真源是 OpenWrite DAG 与章节工作简报。
@@ -4,6 +4,8 @@ description: Use when user wants to manage foreshadowing (伏笔), track story h
4
4
  user-invocable: false
5
5
  ---
6
6
 
7
+ Language: follow the author's current conversation language for responses and help; preserve the manuscript language. Translate these instructions when presenting them.
8
+
7
9
  # 伏笔管理系统
8
10
 
9
11
  管理小说中的伏笔和悬念,确保故事线索连贯。
@@ -3,6 +3,8 @@ name: learn
3
3
  description: 写法记忆。Use when the author asks 记住写法, 成功钩子, 作者偏好, or types /learn. Store style, hooks, and preferences as Workspace-scoped OpenWrite assets; do not create a second memory store.
4
4
  ---
5
5
 
6
+ Language: follow the author's current conversation language for responses and help; preserve the manuscript language. Translate these instructions when presenting them.
7
+
6
8
  # 写法记忆
7
9
 
8
10
  接到已有 `novel_*`。风格、成功钩子和作者偏好是当前 Workspace 作品资产,不是会话本地文件,也不是第二套 RAG / lorebook。
@@ -4,6 +4,8 @@ description: Use when user wants to write chapters, generate drafts, or continue
4
4
  user-invocable: false
5
5
  ---
6
6
 
7
+ Language: follow the author's current conversation language for responses and help; preserve the manuscript language. Translate these instructions when presenting them.
8
+
7
9
  # 小说创作编排
8
10
 
9
11
  通过 openwrite-bridge 的 `novel_*` 工具写章。不要调用 Python 模块、内置 Writer 类或已废弃的大纲命令。
@@ -4,6 +4,8 @@ description: Use when user wants to check logic consistency, polish style, find
4
4
  user-invocable: false
5
5
  ---
6
6
 
7
+ Language: follow the author's current conversation language for responses and help; preserve the manuscript language. Translate these instructions when presenting them.
8
+
7
9
  # 小说审查润色
8
10
 
9
11
  通过 openwrite-bridge 的 `novel_*` 工具评审与修订。不要调用 Python 审查类或本地 33 维脚本。
@@ -15,6 +15,8 @@ metadata:
15
15
  max_tool_calls: 20
16
16
  ---
17
17
 
18
+ Language: follow the author's current conversation language for responses and help; preserve the manuscript language. Translate these instructions when presenting them.
19
+
18
20
  # Oh Story 去 AI 味
19
21
 
20
22
  把 AI 味视为读感和叙事功能问题,不把词表命中当作错误。先确认用户要扫描、局部示范还是全文精修;默认先报告问题和样例,不擅自覆盖正文。
@@ -15,6 +15,8 @@ metadata:
15
15
  max_tool_calls: 20
16
16
  ---
17
17
 
18
+ Language: follow the author's current conversation language for responses and help; preserve the manuscript language. Translate these instructions when presenting them.
19
+
18
20
  # Oh Story 长篇拆解
19
21
 
20
22
  把拆解视为只读、转化性的文学分析。先确认材料来源、用户有权使用的范围、章节边界和期望深度;材料不完整时标注限制,不用常识补齐原作事实。
@@ -15,6 +15,8 @@ metadata:
15
15
  max_tool_calls: 20
16
16
  ---
17
17
 
18
+ Language: follow the author's current conversation language for responses and help; preserve the manuscript language. Translate these instructions when presenting them.
19
+
18
20
  # Oh Story 长篇市场研究
19
21
 
20
22
  把榜单当作有偏差的市场样本,不把排名本身当作选题答案。先确认平台、榜单口径、目标读者、题材范围、采样日期和作者自身优势。
@@ -15,6 +15,8 @@ metadata:
15
15
  max_tool_calls: 20
16
16
  ---
17
17
 
18
+ Language: follow the author's current conversation language for responses and help; preserve the manuscript language. Translate these instructions when presenting them.
19
+
18
20
  # Oh Story 长篇写作
19
21
 
20
22
  先读取当前作品状态和用户本轮目标,再选择开书、补纲、写指定章、续写或修订。裸调用时只诊断所处阶段并给出下一步,不自动生成正文。
@@ -15,6 +15,8 @@ metadata:
15
15
  max_tool_calls: 20
16
16
  ---
17
17
 
18
+ Language: follow the author's current conversation language for responses and help; preserve the manuscript language. Translate these instructions when presenting them.
19
+
18
20
  # Oh Story 商业审稿
19
21
 
20
22
  先确认审查对象、范围、目标读者和用户要“只诊断”还是“诊断后给修改稿”。默认只输出审查报告,不直接改动正文。
@@ -3,6 +3,8 @@ name: progress
3
3
  description: 看进度。Use when the author asks 看进度, 写到哪, 现在哪一章, or types /progress. Read OpenWrite status; do not invent a local workflow store.
4
4
  ---
5
5
 
6
+ Language: follow the author's current conversation language for responses and help; preserve the manuscript language. Translate these instructions when presenting them.
7
+
6
8
  # 看进度
7
9
 
8
10
  接到已有 `novel_*`。不要另建进度文件或阶段机。
@@ -3,6 +3,8 @@ name: review-chapter
3
3
  description: 审这一章。Use when the author asks 审这一章, 审查, 检查逻辑, or types /review-chapter. Run six-domain novel_review_chapter; do not rerun review from DoG.
4
4
  ---
5
5
 
6
+ Language: follow the author's current conversation language for responses and help; preserve the manuscript language. Translate these instructions when presenting them.
7
+
6
8
  # 审这一章
7
9
 
8
10
  接到已有 `novel_*`。正式评审是六域累加;37 项只作展开查询。
@@ -3,6 +3,8 @@ name: revise-span
3
3
  description: 改这段。Use when the author asks 改这段, 扩写, 缩写, 去 AI 味, 按审稿改, or types /revise-span. Stage revision hunks; never PUT the manuscript.
4
4
  ---
5
5
 
6
+ Language: follow the author's current conversation language for responses and help; preserve the manuscript language. Translate these instructions when presenting them.
7
+
6
8
  # 改这段
7
9
 
8
10
  接到已有 `novel_*`。改稿只走修订提案,不直接整章覆盖。
@@ -4,6 +4,8 @@ description: Use when user wants to initialize style, extract reusable writing s
4
4
  user-invocable: false
5
5
  ---
6
6
 
7
+ Language: follow the author's current conversation language for responses and help; preserve the manuscript language. Translate these instructions when presenting them.
8
+
7
9
  # 风格系统
8
10
 
9
11
  ## 核心原则
@@ -4,6 +4,8 @@ description: Use when user wants to validate story consistency, check for plot h
4
4
  user-invocable: false
5
5
  ---
6
6
 
7
+ Language: follow the author's current conversation language for responses and help; preserve the manuscript language. Translate these instructions when presenting them.
8
+
7
9
  # 真相文件验证系统
8
10
 
9
11
  验证真相文件与章节内容的一致性,确保故事逻辑连贯。
@@ -4,6 +4,8 @@ description: Use when user wants to check writing progress, manage workflow stag
4
4
  user-invocable: false
5
5
  ---
6
6
 
7
+ Language: follow the author's current conversation language for responses and help; preserve the manuscript language. Translate these instructions when presenting them.
8
+
7
9
  # 工作流管理
8
10
 
9
11
  跟踪写章 → 评审 → 修订 → 应用 → 复评 → 交付。全部状态来自 OpenWrite 任务与章节工作简报,不要虚构本地阶段机,也不要调用已废弃的工作流命令。
@@ -4,6 +4,8 @@ description: Use when querying or maintaining novel world entities, character re
4
4
  user-invocable: false
5
5
  ---
6
6
 
7
+ Language: follow the author's current conversation language for responses and help; preserve the manuscript language. Translate these instructions when presenting them.
8
+
7
9
  # 世界查询系统
8
10
 
9
11
  把 `data/novels/{novel_id}/src/` 下的人物与世界实体文件作为唯一关系真源。Studio 拓扑和 ReAct 的 `get_world_relations` 必须调用同一个拓扑查询,不维护 `graph.yaml` 或第二套关系数据库。
@@ -3,6 +3,8 @@ name: write-next
3
3
  description: 写下一章。Use when the author asks 写下一章, 续写, 生成章节, or types /write-next. Preview context then call novel_write_chapter; never overwrite existing prose.
4
4
  ---
5
5
 
6
+ Language: follow the author's current conversation language for responses and help; preserve the manuscript language. Translate these instructions when presenting them.
7
+
6
8
  # 写下一章
7
9
 
8
10
  接到已有 `novel_*`。已有正文不得覆盖。
@@ -3,7 +3,7 @@
3
3
  "dsh": "0.1.2-rc.1",
4
4
  "uv_version": "0.11.19",
5
5
  "python_version": "3.12.13",
6
- "core_version": "5.8.9",
6
+ "core_version": "5.8.10",
7
7
  "contract_version": 1,
8
8
  "platforms": {
9
9
  "darwin-arm64": {
@@ -56,8 +56,8 @@
56
56
  }
57
57
  },
58
58
  "wheel": {
59
- "file": "openwrite-5.8.9-py3-none-any.whl",
60
- "sha256": "9526a78dde66a81a0eb7dedc1454c8dd436e42d966b5b043d13c24e263104341"
59
+ "file": "openwrite-5.8.10-py3-none-any.whl",
60
+ "sha256": "f121410300c7e7c55d594d0b8d7f4da41f8a17f0dfb5dc3b195e447b618bfd4d"
61
61
  },
62
62
  "requirements": {
63
63
  "file": "requirements.lock",
@@ -66,13 +66,16 @@
66
66
  "sources": {
67
67
  "core": {
68
68
  "repository": "https://github.com/LiPu-jpg/Openwrite",
69
- "branch": "native-core",
70
- "commit": "d0a75e30047c28c99af909e1b85b07190abb1fb7"
69
+ "branch": "codex/fix-openwrite-core-65-76",
70
+ "commit": "18a500015f5d5da00f2f4d5ccd2325b084fed24b"
71
71
  },
72
72
  "dog": {
73
73
  "repository": "https://github.com/Fun10165/dsh-dog",
74
74
  "tag": "v1.2.0",
75
- "commit": "3a442ef4b1a82cc4258a01baf798913c94a99445"
75
+ "commit": "3a442ef4b1a82cc4258a01baf798913c94a99445",
76
+ "patches": [
77
+ "0.2.19: src/host-shims.ts 内置 dshHomePath/defineTool,移除 @deepseek-ai/dsh-home-paths 与 @deepseek-ai/dsh-tools 的运行时导入(#74)"
78
+ ]
76
79
  },
77
80
  "cryptography": {
78
81
  "package": "cryptography",
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "repository": "https://github.com/LiPu-jpg/Openwrite",
3
- "commit": "6e84c2a72e24196b3140597a9abbee241e5c285e",
4
- "tree": "476c3b5b0f81c15a5d45031c9d537d05cbb61aba",
3
+ "commit": "4d54f3c619f853a4243cd60e67ef6c8ba8d336af",
4
+ "tree": "1eba54e87821fac040dce513a2279bb869bc05c1",
5
5
  "dirty": false,
6
6
  "acquisition": "git-checkout",
7
- "sourceTreeSha256": "314373c9f9b259714e89b3f20f973dfbfa1792fe6944483ea370d715bc58123e",
7
+ "sourceTreeSha256": "b15b0a8f9fc8295220acbd570a9b736ff95269845016927aafb2ac39e8f4590e",
8
8
  "components": [
9
9
  {
10
10
  "name": "@deepseek-ai/schemastery",
@@ -1,2 +1,2 @@
1
- import { n as resolveScriptPath, t as DogEngine } from "./core-DdfMcrB4.js";
1
+ import { n as resolveScriptPath, t as DogEngine } from "./core-BAlgZpLq.js";
2
2
  export { DogEngine, resolveScriptPath };
@@ -1,7 +1,7 @@
1
1
  import { $ as VerifierShape, A as FailurePolicy, B as GoalRuntimeTrace, C as ConstraintKind, D as DogConfig, E as DependencyEdge, F as GoalNodeInput, G as JsonPrimitive, H as GoalState, I as GoalResult, J as NotExpr, K as JsonValue, L as GoalRuntimeError, M as GoalAgentSessionRef, N as GoalId, O as DogGraphInput, P as GoalKind, Q as VerificationRecord, R as GoalRuntimeEvent, S as CompiledGraph, T as DOG_SCHEMA_VERSION, U as GraphLimits, V as GoalRuntimeVerifier, W as GraphValidationReport, X as RootTerminalState, Y as RefExpr, Z as RunInvocationContext, _ as AtLeastExpr, b as CiGoalReport, c as AgenticRunner, d as runPlan, et as isJsonValue, f as DogRepository, g as AnyExpr, h as AllExpr, j as GoalAgentRole, k as DogRun, l as ProgrammaticRunner, m as AcceptancePlan, p as loadSchemaSet, q as JudgmentIdentity, r as DogEngine, s as WorkspaceManager, u as Verdict, v as BoolExpr, w as ContainsEdge, x as CiReport, y as CapturedInput, z as GoalRuntimePhase } from "./core-BiEBMLz3.js";
2
2
  import z from "@deepseek-ai/schemastery";
3
- import { ToolDefinition } from "@deepseek-ai/dsh-tools";
4
3
  import { Agent } from "@deepseek-ai/dsh-agent";
4
+ import { ToolDefinition } from "@deepseek-ai/dsh-tools";
5
5
  import { Context } from "@deepseek-ai/cordis";
6
6
  import { ConnectionRpcHandler } from "@deepseek-ai/dsh-client-connection";
7
7
  import { SessionId } from "@deepseek-ai/dsh-session";
@@ -1,11 +1,10 @@
1
- import { a as DogRepository, c as parseGraph, d as parseBoolExpr, i as runPlan, l as isJsonValue, n as resolveScriptPath, o as loadSchemaSet, r as WorkspaceManager, s as DogValidationError, t as DogEngine, u as evaluateBoolExpr } from "./core-DdfMcrB4.js";
1
+ import { a as DogRepository, c as parseGraph, d as parseBoolExpr, i as runPlan, l as isJsonValue, n as resolveScriptPath, o as loadSchemaSet, r as WorkspaceManager, s as DogValidationError, t as DogEngine, u as evaluateBoolExpr } from "./core-BAlgZpLq.js";
2
2
  import { spawn } from "node:child_process";
3
3
  import { fileURLToPath } from "node:url";
4
- import { dshHomePath } from "@deepseek-ai/dsh-home-paths";
4
+ import { homedir } from "node:os";
5
+ import { isAbsolute, join, resolve } from "node:path";
5
6
  import { mkdir, readFile, writeFile } from "node:fs/promises";
6
- import { isAbsolute, join } from "node:path";
7
7
  import z from "@deepseek-ai/schemastery";
8
- import { defineTool } from "@deepseek-ai/dsh-tools";
9
8
  //#region src/owned-script.ts
10
9
  /** Execute without blocking the host event loop; cancellation owns only this process tree. */
11
10
  async function runOwnedScript(script, input, signal) {
@@ -79,6 +78,205 @@ async function runOwnedScript(script, input, signal) {
79
78
  }
80
79
  }
81
80
  //#endregion
81
+ //#region src/host-shims.ts
82
+ /**
83
+ * Self-contained replacements for the two host packages this plugin used to
84
+ * import at runtime: `@deepseek-ai/dsh-home-paths` (`dshHomePath`) and
85
+ * `@deepseek-ai/dsh-tools` (`defineTool`). Both were declared as
86
+ * peerDependencies, and under the DSH profile install layout (pnpm isolated
87
+ * node_modules) peer instances are not resolvable from this vendored
88
+ * directory, so every entry import failed with ERR_MODULE_NOT_FOUND and the
89
+ * plugin never activated (GitHub issue #74). The implementations below match
90
+ * the host behavior for the schema subset this plugin declares; type-only
91
+ * imports from the host packages are still used and erased at build time.
92
+ */
93
+ /** Directory name for the default DeepSeek Harness home under the OS home. */
94
+ const DSH_HOME_DIR_NAME = ".dsh";
95
+ /** Environment variable that overrides the default DeepSeek Harness home. */
96
+ const DSH_HOME_ENV = "DSH_HOME";
97
+ /** Expand supported tilde prefixes against the operating-system home. */
98
+ function expandHomePath(path) {
99
+ if (path === "~") return homedir();
100
+ if (path.startsWith("~/") || path.startsWith("~\\")) return join(homedir(), path.slice(2));
101
+ return path;
102
+ }
103
+ /**
104
+ * Resolve the single-root DeepSeek Harness home: `$DSH_HOME` when set to a
105
+ * non-blank value, otherwise `~/.dsh`. Mirrors the host `resolveDshHome`.
106
+ */
107
+ function resolveDshHome() {
108
+ const fromEnv = process.env[DSH_HOME_ENV];
109
+ return resolve(expandHomePath(fromEnv !== void 0 && fromEnv.trim().length > 0 ? fromEnv : join(homedir(), DSH_HOME_DIR_NAME)));
110
+ }
111
+ /** Join path segments onto the resolved DeepSeek Harness home. */
112
+ function dshHomePath(...segments) {
113
+ return join(resolveDshHome(), ...segments);
114
+ }
115
+ /** Thrown when model-generated arguments violate the compiled schema. */
116
+ var ToolArgsError = class extends Error {
117
+ violations;
118
+ constructor(violations) {
119
+ super(`invalid arguments: ${violations.join("; ")}`);
120
+ this.name = "ToolArgsError";
121
+ this.violations = violations;
122
+ }
123
+ };
124
+ /** Compile one author-facing value schema node to raw JSON Schema. */
125
+ function compileValueSchema(spec, path) {
126
+ if (spec === null || typeof spec !== "object") throw new Error(`${path}: schema node must be an object`);
127
+ const node = {};
128
+ if (spec.description !== void 0) node.description = spec.description;
129
+ switch (spec.type) {
130
+ case "json": return node;
131
+ case "string":
132
+ case "number":
133
+ case "integer":
134
+ case "boolean":
135
+ case "null":
136
+ node.type = spec.type;
137
+ if ("enum" in spec && spec.enum !== void 0) node.enum = [...spec.enum];
138
+ if ("const" in spec && spec.const !== void 0) node.const = spec.const;
139
+ return node;
140
+ case "array":
141
+ node.type = "array";
142
+ if (spec.items !== void 0) node.items = compileValueSchema(spec.items, `${path}.items`);
143
+ return node;
144
+ case "object":
145
+ node.type = "object";
146
+ if (spec.additionalProperties !== void 0) node.additionalProperties = spec.additionalProperties;
147
+ if (spec.properties !== void 0) {
148
+ const { properties, required } = compilePropertyMap(spec.properties, `${path}.properties`);
149
+ node.properties = properties;
150
+ if (required.length > 0) node.required = required;
151
+ }
152
+ return node;
153
+ default: throw new Error(`${path}.type must be string/number/integer/boolean/null/array/object/json`);
154
+ }
155
+ }
156
+ /** Compile a property map, hoisting per-property `required` flags onto the parent. */
157
+ function compilePropertyMap(input, path) {
158
+ const properties = {};
159
+ const required = [];
160
+ for (const [key, property] of Object.entries(input)) {
161
+ const { required: isRequired, ...spec } = property;
162
+ properties[key] = compileValueSchema(spec, `${path}.${key}`);
163
+ if (isRequired === true) required.push(key);
164
+ }
165
+ return {
166
+ properties,
167
+ required
168
+ };
169
+ }
170
+ /** Compile the implicit open parameter object into raw JSON Schema. */
171
+ function compileParameters(spec) {
172
+ const { properties, required } = compilePropertyMap(spec, "parameters");
173
+ const schema = {
174
+ type: "object",
175
+ properties
176
+ };
177
+ if (required.length > 0) schema.required = required;
178
+ return schema;
179
+ }
180
+ /** Validate one JSON value against the compiled subset, collecting violations. */
181
+ function validateValue(schema, value, path, violations) {
182
+ const at = path === "" ? "arguments" : path;
183
+ if (schema.const !== void 0 && value !== schema.const) {
184
+ violations.push(`${at}: must equal ${JSON.stringify(schema.const)}`);
185
+ return;
186
+ }
187
+ if (Array.isArray(schema.enum) && !schema.enum.some((entry) => entry === value)) {
188
+ violations.push(`${at}: must be one of ${JSON.stringify(schema.enum)}`);
189
+ return;
190
+ }
191
+ switch (schema.type) {
192
+ case void 0: return;
193
+ case "null":
194
+ if (value !== null) violations.push(`${at}: expected null`);
195
+ return;
196
+ case "boolean":
197
+ if (typeof value !== "boolean") violations.push(`${at}: expected boolean, got ${describe(value)}`);
198
+ return;
199
+ case "string":
200
+ if (typeof value !== "string") violations.push(`${at}: expected string, got ${describe(value)}`);
201
+ return;
202
+ case "number":
203
+ if (typeof value !== "number" || !Number.isFinite(value)) violations.push(`${at}: expected number, got ${describe(value)}`);
204
+ return;
205
+ case "integer":
206
+ if (typeof value !== "number" || !Number.isInteger(value)) violations.push(`${at}: expected integer, got ${describe(value)}`);
207
+ return;
208
+ case "array": {
209
+ if (!Array.isArray(value)) {
210
+ violations.push(`${at}: expected array, got ${describe(value)}`);
211
+ return;
212
+ }
213
+ const items = schema.items;
214
+ if (items !== void 0) value.forEach((item, index) => validateValue(items, item, `${at}[${index}]`, violations));
215
+ return;
216
+ }
217
+ case "object": {
218
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
219
+ violations.push(`${at}: expected object, got ${describe(value)}`);
220
+ return;
221
+ }
222
+ const record = value;
223
+ for (const key of schema.required ?? []) if (!Object.hasOwn(record, key)) violations.push(`${at}: missing required property "${key}"`);
224
+ const properties = schema.properties;
225
+ if (properties !== void 0) {
226
+ for (const [key, propertySchema] of Object.entries(properties)) if (Object.hasOwn(record, key)) validateValue(propertySchema, record[key], `${at}.${key}`, violations);
227
+ }
228
+ return;
229
+ }
230
+ }
231
+ }
232
+ function describe(value) {
233
+ if (value === null) return "null";
234
+ if (Array.isArray(value)) return "array";
235
+ return typeof value;
236
+ }
237
+ /** Validate model-generated arguments against the compiled parameter schema. */
238
+ function validateArgs(parameters, args) {
239
+ const violations = [];
240
+ validateValue(parameters, args, "", violations);
241
+ return violations;
242
+ }
243
+ /**
244
+ * Define a first-party tool with strict execution validation, matching the
245
+ * host `defineTool` contract: arguments are validated before `execute`, and
246
+ * replay presenters validate softly and fall back to generic rendering.
247
+ */
248
+ function defineTool(options) {
249
+ const userExecute = options.execute;
250
+ const userRender = options.output.render;
251
+ const userPresentationMeta = options.output.presentationMeta;
252
+ const userIsConcurrencySafe = options.isConcurrencySafe;
253
+ if (options.timeoutMs !== void 0 && (!Number.isFinite(options.timeoutMs) || options.timeoutMs <= 0)) throw new Error(`defineTool(${options.name}): timeoutMs must be a positive finite number`);
254
+ const parameters = compileParameters(options.parameters);
255
+ const outputSchema = compileValueSchema(options.output.schema, "schema");
256
+ const validate = (args) => validateArgs(parameters, args);
257
+ const tool = {
258
+ name: options.name,
259
+ description: options.description,
260
+ parameters,
261
+ output: {
262
+ schema: outputSchema,
263
+ render: (args, value) => userRender(args, value),
264
+ ...userPresentationMeta !== void 0 ? { presentationMeta: (args, value) => userPresentationMeta(args, value) } : {}
265
+ },
266
+ ...options.timeoutMs !== void 0 ? { timeoutMs: options.timeoutMs } : {},
267
+ async execute(args, exec) {
268
+ const violations = validate(args);
269
+ if (violations.length > 0) throw new ToolArgsError(violations);
270
+ return userExecute(args, exec);
271
+ }
272
+ };
273
+ if (userIsConcurrencySafe) tool.isConcurrencySafe = (args) => {
274
+ if (validate(args).length > 0) return false;
275
+ return userIsConcurrencySafe(args);
276
+ };
277
+ return tool;
278
+ }
279
+ //#endregion
82
280
  //#region src/debug-contract.ts
83
281
  const DOG_DEBUG_RPC_CHANNEL = "/dog-rpc";
84
282
  const DOG_DEBUG_SNAPSHOT_ENDPOINT = "snapshot";
@@ -1,12 +1,12 @@
1
1
  import { fileURLToPath } from "node:url";
2
- import { appendFile, lstat, mkdir, mkdtemp, open, readFile, readdir, realpath, rename, rm, stat, writeFile } from "node:fs/promises";
2
+ import { tmpdir } from "node:os";
3
3
  import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
4
+ import { appendFile, lstat, mkdir, mkdtemp, open, readFile, readdir, realpath, rename, rm, stat, writeFile } from "node:fs/promises";
4
5
  import { createHash, randomUUID } from "node:crypto";
5
6
  import { existsSync, readFileSync, readdirSync } from "node:fs";
6
7
  import { c } from "tar";
7
8
  import Ajv2020 from "ajv/dist/2020.js";
8
9
  import addFormats from "ajv-formats";
9
- import { tmpdir } from "node:os";
10
10
  //#region src/logic.ts
11
11
  /**
12
12
  * Parse and type-check the only expression language accepted by DoG.