dsh-unplug 0.2.0 → 0.2.2

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 CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.2.2 (2026-08-20)
4
+
5
+ - 中文本地化:CLI 帮助与输出、agent 工具描述双语;新增 README.zh.md。
6
+ - 中文用户开箱即用。
7
+
8
+ ## 0.2.1 (2026-08-20)
9
+
10
+ - Fix: 0.2.0 was published with a stale build (typecheck gate had failed).
11
+ This release ships the actual `reconcile` implementation.
12
+
3
13
  ## 0.2.0 (2026-08-20)
4
14
 
5
15
  - New `reconcile` command: auto-fix dangling bundles and orphaned patch rows
package/README.zh.md ADDED
@@ -0,0 +1,56 @@
1
+ # dsh-unplug
2
+
3
+ 让 DeepSeek Harness(dsh)的插件**装得容易、拔得干净**。
4
+
5
+ **为什么需要它?** 官方 `dsh plugin remove` 只处理 profile 里 `dsh.profile.bundles` 列表中的 bundle:
6
+
7
+ - 不会清理 profile/home 的 `cordis.patch.yml` 里残留的插件行
8
+ - 没有"禁用但保留配置"的能力(插拔自如)
9
+ - 没有审计接口,拔完也不知道有没有残留
10
+
11
+ `dsh-unplug` 补上这三个缺口。
12
+
13
+ ## 快速开始
14
+
15
+ ```sh
16
+ dsh plugin add dsh-unplug
17
+ ```
18
+
19
+ ## 命令行
20
+
21
+ ```sh
22
+ dsh-unplug list # 列出所有已挂载插件(bundles + 补丁行)
23
+ dsh-unplug remove <插件> --yes # 完整卸载(bundle + 补丁行 + 依赖)
24
+ dsh-unplug disable <插件> # 禁用但不删除(保留依赖,可随时启用)
25
+ dsh-unplug enable <插件> # 重新启用
26
+ dsh-unplug audit # 检测孤立行 / 悬空 bundle
27
+ dsh-unplug reconcile --yes # 一键自动修复悬空与孤立状态
28
+ ```
29
+
30
+ 选项:`--profile <名>`(默认 `default`)、`--home <路径>`、`--json`、`--yes`。
31
+
32
+ ## Agent 可调用工具
33
+
34
+ 安装后 agent 获得 `unplug` 工具:
35
+
36
+ - `list` / `audit` — 只读,任何时候可用
37
+ - `remove` / `reconcile` — 需要 `force: true` 显式确认
38
+ - `disable` / `enable` — 可逆操作,无需确认
39
+
40
+ 返回 `dsh-unplug/v1` 报告。
41
+
42
+ ## 工作原理
43
+
44
+ - bundle 列表(`dsh.profile.bundles`)— 移出列表 + pnpm remove
45
+ - 禁用列表(`dsh.profile.disabledBundles`)— 在 bundles/disabled 之间移动
46
+ - profile 的 `cordis.patch.yml` — 删除插件行或切换 `disabled: true`
47
+ - home 的 `cordis.patch.yml` — 同上
48
+ - 孤立/悬空状态 — audit 发现,reconcile 修复
49
+
50
+ ## 安全
51
+
52
+ 默认只读;`remove` / `reconcile` 需要显式 `--yes`(CLI)或 `force: true`(工具)。
53
+
54
+ ## License
55
+
56
+ MIT
package/lib/cli.js CHANGED
@@ -10,27 +10,27 @@ import { removePlugin, setPluginEnabled } from './lib/remove.js';
10
10
  import { reconcile } from './lib/reconcile.js';
11
11
  function usage() {
12
12
  return [
13
- 'dsh-unplug — plug/unplug any DeepSeek Harness plugin cleanly',
13
+ 'dsh-unplug — 让 DSH 插件插拔自如 / plug/unplug any DeepSeek Harness plugin cleanly',
14
14
  '',
15
- 'Usage:',
15
+ '用法 / Usage:',
16
16
  ' dsh-unplug <command> [options]',
17
17
  '',
18
- 'Commands:',
19
- ' list List all mounted plugin rows across bundles and patches',
20
- ' remove <plugin> Fully unplug a plugin (bundles + patch rows + dependencies)',
21
- ' disable <plugin> Disable without deleting (removes from bundles, keeps deps)',
22
- ' enable <plugin> Re-enable a disabled plugin (re-adds to bundles, clears disabled flag)',
23
- ' audit Detect orphaned rows, dangling bundles, missing patch files',
24
- ' reconcile Auto-fix dangling bundles and orphaned rows',
18
+ '命令 / Commands:',
19
+ ' list 列出所有已挂载插件(bundles + 补丁行) / list every mounted plugin row',
20
+ ' remove <plugin> 完整卸载(bundle + 补丁行 + 依赖) / fully unplug a plugin',
21
+ ' disable <plugin> 禁用但不删除(移出 bundles,保留依赖) / disable without deleting',
22
+ ' enable <plugin> 重新启用(加回 bundles,清除 disabled / re-enable a disabled plugin',
23
+ ' audit 检测孤立行/悬空 bundle / detect orphaned rows, dangling bundles',
24
+ ' reconcile 自动修复悬空与孤立状态 / auto-fix dangling bundles and orphan rows',
25
25
  '',
26
- 'Options:',
27
- ' --profile <name> Profile name (default: default)',
28
- ' --home <path> DSH_HOME path (default: env DSH_HOME or ~/.dsh)',
29
- ' --yes Confirm destructive operations (remove)',
30
- ' --json Output machine-readable JSON report',
31
- ' --help Show this help',
26
+ '选项 / Options:',
27
+ ' --profile <name> Profile 名(默认 default / profile name',
28
+ ' --home <path> DSH_HOME 路径(默认 env DSH_HOME ~/.dsh) / DSH_HOME path',
29
+ ' --yes 确认破坏性操作(remove/reconcile 需要) / confirm destructive ops',
30
+ ' --json 输出机器可读 JSON / machine-readable JSON report',
31
+ ' --help 显示帮助 / show this help',
32
32
  '',
33
- 'Examples:',
33
+ '示例 / Examples:',
34
34
  ' dsh-unplug list',
35
35
  ' dsh-unplug remove dsh-disk-audit --yes',
36
36
  ' dsh-unplug disable dsh-readme-forge --profile my-profile',
@@ -88,27 +88,30 @@ function printResult(value, json) {
88
88
  case 'list':
89
89
  case 'audit':
90
90
  console.log(`Profile: ${report.profile ?? 'default'}`);
91
- console.log(`Bundles (${(report.bundles ?? []).length}): ${(report.bundles ?? []).join(', ') || '(none)'}`);
92
- console.log(`Disabled (${(report.disabledBundles ?? []).length}): ${(report.disabledBundles ?? []).join(', ') || '(none)'}`);
93
- console.log(`Rows (${(report.rows ?? []).length})`);
91
+ console.log(`Bundles/已装 (${(report.bundles ?? []).length}): ${(report.bundles ?? []).join(', ') || '(无/none)'}`);
92
+ console.log(`Disabled/已禁用 (${(report.disabledBundles ?? []).length}): ${(report.disabledBundles ?? []).join(', ') || '(无/none)'}`);
93
+ console.log(`Rows/插件行 (${(report.rows ?? []).length})`);
94
94
  for (const row of (report.rows ?? [])) {
95
95
  console.log(` ${row.disabled ? '🔴' : '🟢'} ${row.id} (${row.name ?? ''}) [${row.layer}]`);
96
96
  }
97
97
  if ((report.issues ?? []).length > 0) {
98
- console.log(`Issues (${report.issues.length}):`);
98
+ console.log(`Issues/问题 (${report.issues.length}):`);
99
99
  for (const issue of report.issues) {
100
100
  console.log(` ⚠ ${issue.detail}`);
101
101
  }
102
102
  }
103
103
  break;
104
104
  case 'remove':
105
- console.log(`Removed: bundle=${report.removedBundle} patchRows=${report.patchRowsRemoved} pnpm=${report.pnpmRemoved}`);
105
+ console.log(`已卸载/Removed: bundle=${report.removedBundle} patchRows=${report.patchRowsRemoved} pnpm=${report.pnpmRemoved}`);
106
106
  if (report.note)
107
- console.log(`Note: ${report.note}`);
107
+ console.log(`备注/Note: ${report.note}`);
108
108
  break;
109
109
  case 'disable':
110
110
  case 'enable':
111
- console.log(`${report.enabled ? 'Enabled' : 'Disabled'}: bundleMoved=${report.bundleMoved} patchChanged=${report.patchChanged}`);
111
+ console.log(`${report.enabled ? '已启用/Enabled' : '已禁用/Disabled'}: bundleMoved=${report.bundleMoved} patchChanged=${report.patchChanged}`);
112
+ break;
113
+ case 'reconcile':
114
+ console.log(`已修复/Reconciled: fixedBundles=${(report.fixedBundles ?? []).length} fixedRows=${report.fixedRows}`);
112
115
  break;
113
116
  }
114
117
  return 0;
package/lib/index.js CHANGED
@@ -40,32 +40,32 @@ export function apply(ctx, config) {
40
40
  assertPeerCompatible();
41
41
  ctx.tools.register(defineTool({
42
42
  name: 'unplug',
43
- description: 'Manage plugins: list every mounted layer, remove a plugin cleanly (bundles + patch rows + dependencies), '
44
- + 'disable/enable without deleting, and audit for orphaned/dangling plugin state. '
45
- + 'Read-only commands (list, audit) are always allowed. Destructive commands (remove) require `force: true`. '
46
- + 'Returns a dsh-unplug/v1 report.',
43
+ description: 'Manage DSH plugins / 插件生命周期管理: list every mounted layer, remove cleanly '
44
+ + '(bundles + patch rows + dependencies), disable/enable without deleting, audit and reconcile '
45
+ + 'orphaned/dangling state. Read-only commands (list, audit) are always allowed; destructive '
46
+ + 'commands (remove, reconcile) require `force: true`. Returns a dsh-unplug/v1 report.',
47
47
  parameters: {
48
48
  command: {
49
49
  type: 'string',
50
50
  required: true,
51
51
  enum: ['list', 'remove', 'disable', 'enable', 'audit', 'reconcile'],
52
- description: 'Action to perform',
52
+ description: 'Action to perform / 要执行的操作',
53
53
  },
54
54
  plugin: {
55
55
  type: 'string',
56
- description: 'Plugin id or package name to target (required for remove/disable/enable)',
56
+ description: 'Plugin id or package name / 插件 id 或包名 (required for remove/disable/enable)',
57
57
  },
58
58
  profile: {
59
59
  type: 'string',
60
- description: 'Profile name (defaults to the configured defaultProfile)',
60
+ description: 'Profile name / Profile 名 (defaults to the configured defaultProfile)',
61
61
  },
62
62
  force: {
63
63
  type: 'boolean',
64
- description: 'Required for remove: confirm the destructive operation',
64
+ description: 'Required for remove/reconcile: confirm the destructive operation / 确认破坏性操作',
65
65
  },
66
66
  home: {
67
67
  type: 'string',
68
- description: 'DSH_HOME path (defaults to env DSH_HOME or ~/.dsh)',
68
+ description: 'DSH_HOME path / DSH_HOME 路径 (defaults to env DSH_HOME or ~/.dsh)',
69
69
  },
70
70
  },
71
71
  output: {
@@ -92,6 +92,8 @@ export function apply(ctx, config) {
92
92
  },
93
93
  bundles: { type: 'array' },
94
94
  disabledBundles: { type: 'array' },
95
+ fixedBundles: { type: 'array' },
96
+ fixedRows: { type: 'number' },
95
97
  },
96
98
  },
97
99
  render: (_args, value) => [{ type: 'text', text: JSON.stringify(value, null, 2) }],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-unplug",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "Plug/unplug any DeepSeek Harness plugin cleanly: list every mounted layer, disable/enable without deleting, remove bundles + patch rows + dependencies in one pass, and audit for orphaned/dangling plugin state. Zero runtime dependencies; read-only by default.",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
@@ -12,6 +12,7 @@
12
12
  "lib",
13
13
  "cordis.patch.yml",
14
14
  "README.md",
15
+ "README.zh.md",
15
16
  "SECURITY.md",
16
17
  "CONTRIBUTING.md",
17
18
  "CHANGELOG.md"