@xiaoso/dsh-tool-plus 0.1.4 → 0.1.6

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
@@ -106,7 +106,7 @@ npx @xiaoso/dsh-tool-plus-presets
106
106
  - **dsh CLI**:需全局安装,`npm i -g @deepseek-ai/dsh`
107
107
  - **Node.js** ≥ 22.19 或 ≥ 24
108
108
  - **Git Bash**(推荐):Windows 上作为 bash 执行环境
109
- - 适用于 DeepSeek Harness `dsh` v0.1.2-rc.1(pre-release,接口可能变动)
109
+ - 适用于 DeepSeek Harness `dsh` v0.1.5-rc.1(pre-release,接口可能变动)
110
110
 
111
111
  ## 注意事项
112
112
 
package/lib/index.mjs CHANGED
@@ -3,7 +3,7 @@ __installBunShim();
3
3
  import { n as fs_promises_shim_exports, t as exists } from "./fs-promises-shim-Bx0fpxuk.mjs";
4
4
  import { i as setRuntimeLogger, n as systemChromiumCandidatesForTest, r as runtimeLogger } from "./launch-BmgEUycu.mjs";
5
5
  import { $ as peekFile, A as formatAge, C as error, F as $envpos, I as $flag, M as formatCount, P as $env, Q as isProbablyBinary, S as debug, T as warn, U as getAutoQaDbPath, V as VERSION, X as getRemoteDir, Y as getPuppeteerDir, b as isEnotdir, c as combineSignals, d as $which, j as formatBytes$1, k as installBunShim, l as exec, p as readImageMetadata, q as getInstallId, tt as untilAborted, u as render, v as hasFsCode, y as isEnoent } from "./src-BcD0_rQR.mjs";
6
- import { C as truncateToWidth$1, S as replaceTabs, _ as formatCodeFrameLine, a as fetchBinary, b as LRUCache, c as getParallelExtractContent, d as convertFileWithMarkit, f as Settings, g as capParseErrors, h as OMP_DEFAULTS, i as convertWithMarkit, l as ensureTool, m as settings, o as extractWithParallel, p as isSettingsInitialized, s as findParallelApiKey, u as CONVERTIBLE_EXTENSIONS, v as formatParseErrors, x as padding, y as shortenPath } from "./utils-DeT1yYiQ.mjs";
6
+ import { C as truncateToWidth$1, S as replaceTabs, _ as formatCodeFrameLine, a as fetchBinary, b as LRUCache, c as getParallelExtractContent, d as convertFileWithMarkit, f as Settings, g as capParseErrors, h as OMP_DEFAULTS, i as convertWithMarkit, l as ensureTool, m as settings, o as extractWithParallel, p as isSettingsInitialized, s as findParallelApiKey, u as CONVERTIBLE_EXTENSIONS, v as formatParseErrors, x as padding, y as shortenPath } from "./utils-C-dSORPa.mjs";
7
7
  import { t as sanitizeText } from "./sanitize-text-CfcXzw5X.mjs";
8
8
  import { n as isRecord$2 } from "./type-guards-B9VVjRDK.mjs";
9
9
  import { n as ToolError, r as throwIfAborted, t as ToolAbortError } from "./tool-errors-DoyxivAR.mjs";
@@ -14858,7 +14858,7 @@ let specialHandlersPromise;
14858
14858
  * requires a special handler, so we keep them out of the cold-startup graph.
14859
14859
  */
14860
14860
  function loadSpecialHandlers() {
14861
- specialHandlersPromise ??= import("./scrapers-D145Jmdq.mjs").then((m) => m.specialHandlers);
14861
+ specialHandlersPromise ??= import("./scrapers-Cg5w77td.mjs").then((m) => m.specialHandlers);
14862
14862
  return specialHandlersPromise;
14863
14863
  }
14864
14864
  /**
@@ -3,7 +3,7 @@ __installBunShim();
3
3
  import { n as fs_promises_shim_exports } from "./fs-promises-shim-Bx0fpxuk.mjs";
4
4
  import { B as USER_AGENT, G as getDocsRsCacheDir, N as formatNumber, P as $env, T as warn, c as combineSignals, j as formatBytes, l as exec, s as Snowflake, x as parseFrontmatter, y as isEnoent } from "./src-BcD0_rQR.mjs";
5
5
  import { V as tryParseJson } from "./utils-Cp2Mxf_U.mjs";
6
- import { a as fetchBinary, c as getParallelExtractContent, i as convertWithMarkit, l as ensureTool, m as settings, n as asRecord, o as extractWithParallel, r as asString, s as findParallelApiKey, t as asNumber } from "./utils-DeT1yYiQ.mjs";
6
+ import { a as fetchBinary, c as getParallelExtractContent, i as convertWithMarkit, l as ensureTool, m as settings, n as asRecord, o as extractWithParallel, r as asString, s as findParallelApiKey, t as asNumber } from "./utils-C-dSORPa.mjs";
7
7
  import { n as isRecord } from "./type-guards-B9VVjRDK.mjs";
8
8
  import { r as throwIfAborted, t as ToolAbortError } from "./tool-errors-DoyxivAR.mjs";
9
9
  import { c as getLocalizedText, d as looksLikeHtml, i as decodeHtmlEntities, l as htmlToBasicMarkdown, o as formatIsoDate, r as buildResult, s as formatMediaDuration, u as loadPage } from "./types-DX_bvuus.mjs";
package/lib/trash-cli.mjs CHANGED
@@ -1,5 +1,20 @@
1
1
  import * as fs from "node:fs";
2
2
  //#region src/tools/bash/trash-cli.ts
3
+ /**
4
+ * rmSafe: rm 命令的回收站重定义核心。
5
+ *
6
+ * 参数解析与行为语义对齐 GNU coreutils rm(tests/rm/ 用例移植),差异:
7
+ * - 删除目标 = 系统回收站(trash 包),非永久删除;
8
+ * - `-i`/`-I`/`--interactive[=WHEN]` 接受但忽略交互(直接进回收站);
9
+ * - verbose 只输出顶层项(trash 是原子移动,不递归输出子项)。
10
+ *
11
+ * 保护语义(r-root / r-4 移植):默认 --preserve-root 拒绝 `/` 及其同义词
12
+ * (`//`、`///`、realpath 后是根目录的路径);拒绝 `.` / `..` 结尾的路径。
13
+ *
14
+ * 本模块零外部依赖(trash 包在 trash-cli-main.ts 入口动态加载),
15
+ * 便于单测注入 fake trash。
16
+ * @module @xiaoso/dsh-tool-plus/bash/trash-cli
17
+ */
3
18
  const SHORT_OPTIONS = {
4
19
  r: "recursive",
5
20
  R: "recursive",
@@ -195,6 +210,42 @@ async function isRootPath(p, deps) {
195
210
  const root = await deps.stat("/");
196
211
  return root !== null && st.dev === root.dev && st.ino === root.ino;
197
212
  }
213
+ /** 探测目标名后缀(rename 探测临时名)。 */
214
+ const PROBE_SUFFIX = ".dsh-trash-probe";
215
+ /** 从 unknown 错误里取 errno 码(边界解析)。 */
216
+ function errnoCode(err) {
217
+ if (typeof err !== "object" || err === null) return void 0;
218
+ const code = err.code;
219
+ return typeof code === "string" ? code : void 0;
220
+ }
221
+ /** rename 探测:移到同目录临时名再改回;不改内容,返回 errno 码或 null(可移动)。 */
222
+ async function defaultProbeRename(from, to) {
223
+ try {
224
+ await fs.promises.rename(from, to);
225
+ } catch (err) {
226
+ return errnoCode(err) ?? "UNKNOWN";
227
+ }
228
+ try {
229
+ await fs.promises.rename(to, from);
230
+ return null;
231
+ } catch {
232
+ return "PROBE_STUCK";
233
+ }
234
+ }
235
+ /**
236
+ * rename 探测结果 → 可读原因(null = 无结论)。
237
+ *
238
+ * trash 的 windows-trash.exe 失败时把原因吞成 0x8000FFFF、stderr 为空,
239
+ * 所以这里靠 rename 探测拿文件系统的真实回答;不同 errno 必须分开报,
240
+ * 权限不足不是“被占用”。
241
+ */
242
+ function describeProbeCode(code) {
243
+ if (code === null) return null;
244
+ if (code === "ENOENT" || code === "ENOTDIR") return "no longer exists (removed by another process?)";
245
+ if (code === "EBUSY" || code === "ENOTEMPTY" || code === "PROBE_STUCK") return "file is locked or cannot be moved by this process (close programs using it and retry)";
246
+ if (code === "EPERM" || code === "EACCES") return "permission denied (read-only file or restricted directory)";
247
+ return null;
248
+ }
198
249
  /**
199
250
  * 执行一次 rm 语义的回收站删除。
200
251
  *
@@ -256,8 +307,18 @@ async function runTrashCli(argv, deps) {
256
307
  if (items.length > 0) try {
257
308
  await deps.trash(items.map((item) => item.path));
258
309
  } catch (err) {
259
- deps.stderr(`rm: cannot remove '${items[0].authored}': ${errorMessage(err)}`);
260
- failed = true;
310
+ if (process.platform !== "win32") {
311
+ deps.stderr(`rm: cannot remove '${items[0].authored}': ${errorMessage(err)}`);
312
+ failed = true;
313
+ } else {
314
+ const probe = deps.probeRename ?? defaultProbeRename;
315
+ for (const item of items) {
316
+ const code = await probe(item.path, `${item.path}${PROBE_SUFFIX}`);
317
+ if (code === "ENOENT" || code === "ENOTDIR") continue;
318
+ deps.stderr(`rm: cannot remove '${item.authored}': ${describeProbeCode(code) ?? errorMessage(err)}`);
319
+ failed = true;
320
+ }
321
+ }
261
322
  }
262
323
  if (verbose && !failed) for (const { authored, isDir } of items) deps.stdout(isDir ? `removed directory '${normalizeTrailingSlash(authored)}'` : `removed '${authored}'`);
263
324
  deps.exit(failed ? 1 : 0);
@@ -7202,7 +7202,7 @@ const settings = {
7202
7202
  };
7203
7203
  //#endregion
7204
7204
  //#region package.json
7205
- var version = "0.1.4";
7205
+ var version = "0.1.6";
7206
7206
  /** `.tmp` files older than this are treated as orphaned writes and swept. */
7207
7207
  const TMP_ORPHAN_MAX_AGE_MS = 3e5;
7208
7208
  function markitConversionCacheKey(bytes, extension) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@xiaoso/dsh-tool-plus",
3
3
  "description": "Oh My Pi bash runtime ported as a deepseek-harness tool plugin: persistent shell session, output minimizer, managed background jobs, command interception",
4
- "version": "0.1.4",
4
+ "version": "0.1.6",
5
5
  "license": "MIT",
6
6
  "keywords": [
7
7
  "deepseek-harness",
@@ -80,19 +80,19 @@
80
80
  },
81
81
  "peerDependencies": {
82
82
  "@deepseek-ai/cordis": "4.0.2",
83
- "@deepseek-ai/dsh-agent": "0.1.2-rc.1",
84
- "@deepseek-ai/dsh-attachment": "0.1.2-rc.1",
85
- "@deepseek-ai/dsh-client-connection": "0.1.2-rc.1",
86
- "@deepseek-ai/dsh-fs": "0.1.2-rc.1",
87
- "@deepseek-ai/dsh-jobs": "0.1.2-rc.1",
88
- "@deepseek-ai/dsh-llm": "0.1.2-rc.1",
89
- "@deepseek-ai/dsh-sandbox": "0.1.2-rc.1",
90
- "@deepseek-ai/dsh-session": "0.1.2-rc.1",
91
- "@deepseek-ai/dsh-settings": "0.1.2-rc.1",
92
- "@deepseek-ai/dsh-shell": "0.1.2-rc.1",
93
- "@deepseek-ai/dsh-shell-env": "0.1.2-rc.1",
94
- "@deepseek-ai/dsh-system-prompt": "0.1.2-rc.1",
95
- "@deepseek-ai/dsh-tools": "0.1.2-rc.1"
83
+ "@deepseek-ai/dsh-agent": "0.1.5-rc.1",
84
+ "@deepseek-ai/dsh-attachment": "0.1.5-rc.1",
85
+ "@deepseek-ai/dsh-client-connection": "0.1.5-rc.1",
86
+ "@deepseek-ai/dsh-fs": "0.1.5-rc.1",
87
+ "@deepseek-ai/dsh-jobs": "0.1.5-rc.1",
88
+ "@deepseek-ai/dsh-llm": "0.1.5-rc.1",
89
+ "@deepseek-ai/dsh-sandbox": "0.1.5-rc.1",
90
+ "@deepseek-ai/dsh-session": "0.1.5-rc.1",
91
+ "@deepseek-ai/dsh-settings": "0.1.5-rc.1",
92
+ "@deepseek-ai/dsh-shell": "0.1.5-rc.1",
93
+ "@deepseek-ai/dsh-shell-env": "0.1.5-rc.1",
94
+ "@deepseek-ai/dsh-system-prompt": "0.1.5-rc.1",
95
+ "@deepseek-ai/dsh-tools": "0.1.5-rc.1"
96
96
  },
97
97
  "optionalPeerDependencies": {
98
98
  "sharp": ">=0.33"
@@ -109,30 +109,32 @@
109
109
  "json5": "^2.2.3",
110
110
  "puppeteer-core": "^25.3.0",
111
111
  "trash": "^10.1.1",
112
- "yaml": "^2.9.0"
112
+ "yaml": "^2.9.0",
113
+ "@deepseek-ai/dsh-brand": "0.1.5-rc.1",
114
+ "@deepseek-ai/dsh-invariants": "0.1.5-rc.1"
113
115
  },
114
116
  "devDependencies": {
115
117
  "@deepseek-ai/cordis": "4.0.2",
116
- "@deepseek-ai/dsh-agent": "0.1.2-rc.1",
117
- "@deepseek-ai/dsh-client-connection": "0.1.2-rc.1",
118
- "@deepseek-ai/dsh-client-locale": "0.1.2-rc.1",
119
- "@deepseek-ai/dsh-client-ui-primitives": "0.1.2-rc.1",
120
- "@deepseek-ai/dsh-client-ui-renderer": "0.1.2-rc.1",
121
- "@deepseek-ai/dsh-client-ui-settings": "0.1.2-rc.1",
122
- "@deepseek-ai/dsh-client-ui-settings-plugins": "0.1.2-rc.1",
123
- "@deepseek-ai/dsh-client-ui-slots": "0.1.2-rc.1",
124
- "@deepseek-ai/dsh-fs-local": "0.1.2-rc.1",
125
- "@deepseek-ai/dsh-jobs": "0.1.2-rc.1",
126
- "@deepseek-ai/dsh-jobs-local": "0.1.2-rc.1",
127
- "@deepseek-ai/dsh-llm": "0.1.2-rc.1",
128
- "@deepseek-ai/dsh-session": "0.1.2-rc.1",
129
- "@deepseek-ai/dsh-settings": "0.1.2-rc.1",
130
- "@deepseek-ai/dsh-shell": "0.1.2-rc.1",
131
- "@deepseek-ai/dsh-shell-env": "0.1.2-rc.1",
132
- "@deepseek-ai/dsh-system-prompt": "0.1.2-rc.1",
133
- "@deepseek-ai/dsh-tool-jobs": "0.1.2-rc.1",
134
- "@deepseek-ai/dsh-tool-str-replace-editor": "0.1.2-rc.1",
135
- "@deepseek-ai/dsh-tools": "0.1.2-rc.1",
118
+ "@deepseek-ai/dsh-agent": "0.1.5-rc.1",
119
+ "@deepseek-ai/dsh-client-connection": "0.1.5-rc.1",
120
+ "@deepseek-ai/dsh-client-locale": "0.1.5-rc.1",
121
+ "@deepseek-ai/dsh-client-ui-primitives": "0.1.5-rc.1",
122
+ "@deepseek-ai/dsh-client-ui-renderer": "0.1.5-rc.1",
123
+ "@deepseek-ai/dsh-client-ui-settings": "0.1.5-rc.1",
124
+ "@deepseek-ai/dsh-client-ui-settings-plugins": "0.1.5-rc.1",
125
+ "@deepseek-ai/dsh-client-ui-slots": "0.1.5-rc.1",
126
+ "@deepseek-ai/dsh-fs-local": "0.1.5-rc.1",
127
+ "@deepseek-ai/dsh-jobs": "0.1.5-rc.1",
128
+ "@deepseek-ai/dsh-jobs-local": "0.1.5-rc.1",
129
+ "@deepseek-ai/dsh-llm": "0.1.5-rc.1",
130
+ "@deepseek-ai/dsh-session": "0.1.5-rc.1",
131
+ "@deepseek-ai/dsh-settings": "0.1.5-rc.1",
132
+ "@deepseek-ai/dsh-shell": "0.1.5-rc.1",
133
+ "@deepseek-ai/dsh-shell-env": "0.1.5-rc.1",
134
+ "@deepseek-ai/dsh-system-prompt": "0.1.5-rc.1",
135
+ "@deepseek-ai/dsh-tool-jobs": "0.1.5-rc.1",
136
+ "@deepseek-ai/dsh-tool-str-replace-editor": "0.1.5-rc.1",
137
+ "@deepseek-ai/dsh-tools": "0.1.5-rc.1",
136
138
  "@types/node": "^22.19.0",
137
139
  "@types/react": "^19.0.0",
138
140
  "@types/react-dom": "^19.0.0",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xiaoso/dsh-tool-plus-presets",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "Agent-preset installer for dsh-tool-plus: installs the standard / PTC enhanced preset templates into a DeepSeek Harness home.",
5
5
  "license": "MIT",
6
6
  "keywords": [
@@ -50,8 +50,9 @@
50
50
  - id: persona
51
51
  name: '@deepseek-ai/dsh-persona'
52
52
  config:
53
- text: >-
54
- You are a coding agent powered by the {{model}} model. Your working directory is {{cwd}}.
53
+ suffix: Your working directory is {{cwd}}.
54
+ prefix: >-
55
+ You are a coding agent powered by the {{model}} model.
55
56
 
56
57
  - id: agent-instructions
57
58
  name: '@deepseek-ai/dsh-agent-instructions'
@@ -108,6 +109,9 @@
108
109
  # resolves `goals` on the host and an entry-local realm here would hide it. The
109
110
  # registry is keyed by session anyway, so one host instance serves every
110
111
  # session. What a preset chooses is whether its agent can call the goal tool.
112
+ - id: command-goal
113
+ name: '@deepseek-ai/dsh-command-goal'
114
+
111
115
  - id: tool-goal
112
116
  name: '@deepseek-ai/dsh-tool-goal'
113
117
 
@@ -202,6 +206,7 @@
202
206
  config:
203
207
  provider: spawn
204
208
  toolName: subagent
209
+ modelSelectionSettings: true
205
210
  backgroundMode: continuable
206
211
 
207
212
  - id: tool-subagent-fork
@@ -239,6 +244,7 @@
239
244
 
240
245
  - id: tool-workflow
241
246
  name: '@deepseek-ai/dsh-tool-workflow'
247
+ disabled: true
242
248
 
243
249
  - id: tool-ralph
244
250
  name: '@deepseek-ai/dsh-tool-ralph'
@@ -264,6 +270,9 @@
264
270
  fetch: false
265
271
  searchTimeoutMs: 60000
266
272
 
273
+ - id: present
274
+ name: '@deepseek-ai/dsh-tool-present'
275
+
267
276
  # ── presentation ────────────────────────────────────────────────────────────
268
277
 
269
278
  # Code Mode for this agent alone. The row waits for the host's `codeRuntime`
@@ -272,4 +281,4 @@
272
281
  - id: tool-presentation
273
282
  name: '@deepseek-ai/dsh-agent-tool-presentation'
274
283
  config:
275
- mode: code
284
+ mode: ptc
@@ -46,8 +46,9 @@
46
46
  - id: persona
47
47
  name: '@deepseek-ai/dsh-persona'
48
48
  config:
49
- text: >-
50
- You are a coding agent powered by the {{model}} model. Your working directory is {{cwd}}.
49
+ suffix: Your working directory is {{cwd}}.
50
+ prefix: >-
51
+ You are a coding agent powered by the {{model}} model.
51
52
 
52
53
  - id: agent-instructions
53
54
  name: '@deepseek-ai/dsh-agent-instructions'
@@ -104,6 +105,9 @@
104
105
  # resolves `goals` on the host and an entry-local realm here would hide it. The
105
106
  # registry is keyed by session anyway, so one host instance serves every
106
107
  # session. What a preset chooses is whether its agent can call the goal tool.
108
+ - id: command-goal
109
+ name: '@deepseek-ai/dsh-command-goal'
110
+
107
111
  - id: tool-goal
108
112
  name: '@deepseek-ai/dsh-tool-goal'
109
113
 
@@ -198,6 +202,7 @@
198
202
  config:
199
203
  provider: spawn
200
204
  toolName: subagent
205
+ modelSelectionSettings: true
201
206
  backgroundMode: continuable
202
207
 
203
208
  - id: tool-subagent-fork
@@ -259,3 +264,6 @@
259
264
  config:
260
265
  fetch: false
261
266
  searchTimeoutMs: 60000
267
+
268
+ - id: present
269
+ name: '@deepseek-ai/dsh-tool-present'