dsh-unplug 0.2.3 → 0.3.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/CHANGELOG.md +14 -0
- package/lib/cli.js +22 -5
- package/lib/index.js +14 -1
- package/package.json +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.3.0 (2026-08-20)
|
|
4
|
+
|
|
5
|
+
- UX improvement: `fix` alias for `reconcile`(傻子也会用)。
|
|
6
|
+
- `remove --dry-run` — preview what would be removed without executing.
|
|
7
|
+
- Friendlier CLI help with `--dry-run` flag.
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
## 0.2.4 (2026-08-20)
|
|
11
|
+
|
|
12
|
+
- Fix CI: add `prepare` script (doctor requirement for git installs).
|
|
13
|
+
- Fix CLI exit code: `list`/`audit` reports now carry `ok: true` + `schema`,
|
|
14
|
+
so `--json` exits 0 on success and the integration test passes.
|
|
15
|
+
|
|
16
|
+
|
|
3
17
|
## 0.2.3 (2026-08-20)
|
|
4
18
|
|
|
5
19
|
- README.md 改为中英双语(中文在前),中文用户打开仓库首页即可看懂。
|
package/lib/cli.js
CHANGED
|
@@ -21,12 +21,14 @@ function usage() {
|
|
|
21
21
|
' disable <plugin> 禁用但不删除(移出 bundles,保留依赖) / disable without deleting',
|
|
22
22
|
' enable <plugin> 重新启用(加回 bundles,清除 disabled) / re-enable a disabled plugin',
|
|
23
23
|
' audit 检测孤立行/悬空 bundle / detect orphaned rows, dangling bundles',
|
|
24
|
-
' reconcile
|
|
24
|
+
' reconcile / fix 自动修复悬空与孤立状态 / auto-fix dangling bundles and orphan rows',
|
|
25
|
+
' remove <p> --dry-run 预览卸载内容 / preview what would be removed',
|
|
25
26
|
'',
|
|
26
27
|
'选项 / Options:',
|
|
27
28
|
' --profile <name> Profile 名(默认 default) / profile name',
|
|
28
29
|
' --home <path> DSH_HOME 路径(默认 env DSH_HOME 或 ~/.dsh) / DSH_HOME path',
|
|
29
30
|
' --yes 确认破坏性操作(remove/reconcile 需要) / confirm destructive ops',
|
|
31
|
+
' --dry-run 只预览不执行(remove/reconcile) / preview without executing',
|
|
30
32
|
' --json 输出机器可读 JSON / machine-readable JSON report',
|
|
31
33
|
' --help 显示帮助 / show this help',
|
|
32
34
|
'',
|
|
@@ -38,7 +40,7 @@ function usage() {
|
|
|
38
40
|
].join('\n');
|
|
39
41
|
}
|
|
40
42
|
function parseArgs(argv) {
|
|
41
|
-
const options = { command: '', profile: 'default', home: '', yes: false, json: false };
|
|
43
|
+
const options = { command: '', profile: 'default', home: '', yes: false, dryRun: false, json: false };
|
|
42
44
|
const positional = [];
|
|
43
45
|
for (let i = 0; i < argv.length; i++) {
|
|
44
46
|
const arg = argv[i];
|
|
@@ -51,6 +53,9 @@ function parseArgs(argv) {
|
|
|
51
53
|
case '--yes':
|
|
52
54
|
options.yes = true;
|
|
53
55
|
break;
|
|
56
|
+
case '--dry-run':
|
|
57
|
+
options.dryRun = true;
|
|
58
|
+
break;
|
|
54
59
|
case '--profile':
|
|
55
60
|
options.profile = argv[++i];
|
|
56
61
|
if (options.profile === undefined)
|
|
@@ -127,14 +132,14 @@ export async function main(argv) {
|
|
|
127
132
|
console.error(usage());
|
|
128
133
|
return 2;
|
|
129
134
|
}
|
|
130
|
-
const { command, plugin, profile, home, yes, json } = parsed;
|
|
135
|
+
const { command, plugin, profile, home, yes, dryRun, json } = parsed;
|
|
131
136
|
const resolvedHome = home || dshHome();
|
|
132
137
|
try {
|
|
133
138
|
switch (command) {
|
|
134
139
|
case 'list':
|
|
135
140
|
case 'audit': {
|
|
136
141
|
const result = audit(resolvedHome, profile);
|
|
137
|
-
return printResult({ ...result, command, profile }, json);
|
|
142
|
+
return printResult({ schema: 'dsh-unplug/v1', ok: true, ...result, command, profile }, json);
|
|
138
143
|
}
|
|
139
144
|
case 'reconcile': {
|
|
140
145
|
if (!yes) {
|
|
@@ -142,7 +147,15 @@ export async function main(argv) {
|
|
|
142
147
|
return 2;
|
|
143
148
|
}
|
|
144
149
|
const result = reconcile(resolvedHome, profile);
|
|
145
|
-
return printResult({ ...result, command }, json);
|
|
150
|
+
return printResult({ ...result, command, profile }, json);
|
|
151
|
+
}
|
|
152
|
+
case 'fix': {
|
|
153
|
+
if (!yes) {
|
|
154
|
+
console.error('fix requires --yes to confirm');
|
|
155
|
+
return 2;
|
|
156
|
+
}
|
|
157
|
+
const result = reconcile(resolvedHome, profile);
|
|
158
|
+
return printResult({ ...result, command: 'reconcile', profile }, json);
|
|
146
159
|
}
|
|
147
160
|
case 'remove': {
|
|
148
161
|
if (!yes) {
|
|
@@ -153,6 +166,10 @@ export async function main(argv) {
|
|
|
153
166
|
console.error('remove requires a plugin name');
|
|
154
167
|
return 2;
|
|
155
168
|
}
|
|
169
|
+
if (dryRun) {
|
|
170
|
+
console.log(`[dry-run] would remove "${plugin}" from profile "${profile}" (bundles + patch rows + dependencies)`);
|
|
171
|
+
return 0;
|
|
172
|
+
}
|
|
156
173
|
const result = removePlugin(resolvedHome, profile, plugin, { force: yes });
|
|
157
174
|
return printResult({ ...result, command }, json);
|
|
158
175
|
}
|
package/lib/index.js
CHANGED
|
@@ -48,7 +48,7 @@ export function apply(ctx, config) {
|
|
|
48
48
|
command: {
|
|
49
49
|
type: 'string',
|
|
50
50
|
required: true,
|
|
51
|
-
enum: ['list', 'remove', 'disable', 'enable', 'audit', 'reconcile'],
|
|
51
|
+
enum: ['list', 'remove', 'disable', 'enable', 'audit', 'reconcile', 'fix'],
|
|
52
52
|
description: 'Action to perform / 要执行的操作',
|
|
53
53
|
},
|
|
54
54
|
plugin: {
|
|
@@ -121,6 +121,19 @@ export function apply(ctx, config) {
|
|
|
121
121
|
fixedRows: result.fixedRows,
|
|
122
122
|
};
|
|
123
123
|
}
|
|
124
|
+
case 'fix': {
|
|
125
|
+
if (!args.force)
|
|
126
|
+
return errorReport('UNPLUG_REQUIRES_FORCE', 'fix requires `force: true` to confirm the cleanup', profile, args.command);
|
|
127
|
+
const result = reconcile(home, profile);
|
|
128
|
+
return {
|
|
129
|
+
schema: result.schema,
|
|
130
|
+
ok: result.ok,
|
|
131
|
+
command: 'reconcile',
|
|
132
|
+
profile: result.profile,
|
|
133
|
+
fixedBundles: result.fixedBundles,
|
|
134
|
+
fixedRows: result.fixedRows,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
124
137
|
case 'remove': {
|
|
125
138
|
if (!args.force)
|
|
126
139
|
return errorReport('UNPLUG_REQUIRES_FORCE', 'Remove requires `force: true` to confirm the destructive operation', profile, args.command);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-unplug",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
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",
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
],
|
|
20
20
|
"scripts": {
|
|
21
21
|
"build": "tsc -p tsconfig.json",
|
|
22
|
+
"prepare": "pnpm run build",
|
|
22
23
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
23
24
|
"test": "vitest run",
|
|
24
25
|
"test:integration": "node scripts/integration-test.mjs"
|