@noob-stupid/dsh-plugin-console 0.5.87 → 0.5.92
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 +64 -4
- package/lib/client.js +24 -8
- package/lib/server/domain/framework.js +7 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -461,12 +461,72 @@ Verification matrix, raw logs and the one framework-side caveat (`0.1.2-rc.1` sh
|
|
|
461
461
|
|
|
462
462
|
---
|
|
463
463
|
|
|
464
|
+
### Update integrity
|
|
465
|
+
|
|
466
|
+
An update can be requested for a specific version. That version is carried into every download channel; if
|
|
467
|
+
a channel ends up with a different version, the job reports a failure with both versions named, and the
|
|
468
|
+
existing copy on disk is kept rather than replaced. The manifest and lock record a **version number** for
|
|
469
|
+
such packages — a normal install does not produce a `link:`.
|
|
470
|
+
|
|
471
|
+
Installs and updates are tracked per target: two different plugins can update at the same time, while the
|
|
472
|
+
same plugin cannot be started twice.
|
|
473
|
+
|
|
474
|
+
A finished install leaves two small records under `<DSH_HOME>/plugin-console/`:
|
|
475
|
+
|
|
476
|
+
- `pending-restart.json` — plugins that are installed but not yet loaded, so the panel can keep showing
|
|
477
|
+
"installed · takes effect after restart" across a host restart. Entries are dropped once the plugin is
|
|
478
|
+
actually loaded.
|
|
479
|
+
- `install-jobs.json` — the last fifty settled jobs, with the requested version, the version that landed,
|
|
480
|
+
and the error if any. A failure can therefore still be explained after the process that produced it is gone.
|
|
481
|
+
|
|
482
|
+
Drift between the manifest and the lock is reconciled in the background with a cooldown, without blocking
|
|
483
|
+
`/state`. Source-type dependencies (`link:`, `file:`, git) are excluded from that automation. A mismatch is
|
|
484
|
+
reported as a failure only when it would actually lose the plugin; a lock or version drift is shown as a
|
|
485
|
+
collapsible note instead.
|
|
486
|
+
|
|
487
|
+
### Dev links (`link`)
|
|
488
|
+
|
|
489
|
+
`link:` is a **development** mechanism — ordinary download installs and updates do not produce it. The
|
|
490
|
+
`link` entry in the feature-pack toolbar is the working surface for it:
|
|
491
|
+
|
|
492
|
+
- pick a registered dev root from the dropdown, or type an absolute path;
|
|
493
|
+
- **Pin** is a two-step action: it first returns a read-only plan, and executes only after you confirm. No
|
|
494
|
+
code path skips that confirmation;
|
|
495
|
+
- each row shows the target directory and its last-modified time, which is how you tell whether it is the
|
|
496
|
+
directory you are editing right now;
|
|
497
|
+
- per-row actions appear only when they apply — **fill dependencies**, **build shims** (no pnpm run), and
|
|
498
|
+
**unpin**;
|
|
499
|
+
- **Browse…** is rendered only when the desktop preload bridge is present. On a web instance it is not
|
|
500
|
+
rendered, rather than shown as a button that cannot work.
|
|
501
|
+
|
|
502
|
+
### Disable provenance
|
|
503
|
+
|
|
504
|
+
A row can be off for different reasons, and the panel distinguishes them:
|
|
505
|
+
|
|
506
|
+
- **disabled by this console's patch** — removing the patch block enables it normally;
|
|
507
|
+
- **disabled by the plugin or the framework default** — the console can only write an explicit
|
|
508
|
+
`disabled: false` override, which is what the **forced on by patch** badge refers to;
|
|
509
|
+
- **force-enable had no effect** — the override exists but the row still is not running, and no peer veto
|
|
510
|
+
explains it. That override can be revoked from the row.
|
|
511
|
+
|
|
512
|
+
### Operational details
|
|
513
|
+
|
|
514
|
+
- Market enrichment runs behind a single limiter: four concurrent requests, one in flight per URL, a
|
|
515
|
+
ten-minute memory for failures and a five-minute success cache. A batch of unreachable mirrors therefore
|
|
516
|
+
cannot saturate the connection or delay installs.
|
|
517
|
+
- `Disk audit` lists what occupies `<DSH_HOME>/plugin-console` and deletes only after an explicit
|
|
518
|
+
confirmation. The framework rollback point counts as protected.
|
|
519
|
+
- The gate panel shows the current pending adaptations up front and keeps its history collapsed.
|
|
520
|
+
|
|
464
521
|
## Known limitations
|
|
465
522
|
|
|
466
|
-
- Host code changes require a **service restart
|
|
467
|
-
**
|
|
468
|
-
|
|
469
|
-
|
|
523
|
+
- Host code changes require a **service restart**; client changes only need a page refresh.
|
|
524
|
+
- On a **desktop-hosted** instance the console **refuses** to restart and says so: the official path is to
|
|
525
|
+
fully quit and reopen the client. It never kills or spawns a process there — a manual relaunch would
|
|
526
|
+
fight the host for the port and produce "The application could not start or stopped unexpectedly".
|
|
527
|
+
- On a **standalone (web) instance** the restart button is available: it relaunches detached, waits for
|
|
528
|
+
the port to free, and lets the old process exit gracefully. The toolbar entry is rendered only where it
|
|
529
|
+
can work — a desktop-hosted instance does not show it.
|
|
470
530
|
- Live GitHub search depends on GitHub reachability (browser-direct + server fallback;
|
|
471
531
|
during network-blackout windows retry later);
|
|
472
532
|
- Version detection works for npm-published packages; skill-type repos have no version concept;
|
package/lib/client.js
CHANGED
|
@@ -464,9 +464,9 @@ window.__ModuleLoader__.load({
|
|
|
464
464
|
stageInstalling: "下载安装中(可离开本页,后台继续)",
|
|
465
465
|
stageConfiguring: "写入启用配置",
|
|
466
466
|
stageRepairing: "本地 AI 接管安装中…",
|
|
467
|
-
restartService: "
|
|
467
|
+
restartService: "重启服务",
|
|
468
468
|
restartHostedNotice: "本实例由桌面端外壳托管 —— 请在桌面端内重启:完全退出 DeepSeek Harness 再打开(控制台不自行 kill / spawn,以免与宿主争端口)。",
|
|
469
|
-
restarting: "
|
|
469
|
+
restarting: "正在处理重启请求…",
|
|
470
470
|
autoReload: "页面即将自动刷新…",
|
|
471
471
|
aiRepaired: "本地 AI 已接管并完成修复,请刷新页面查看",
|
|
472
472
|
deletePlugin: "删除插件(移除配置并卸载包)",
|
|
@@ -1111,9 +1111,9 @@ window.__ModuleLoader__.load({
|
|
|
1111
1111
|
stageInstalling: "Downloading & installing (safe to leave this page)",
|
|
1112
1112
|
stageConfiguring: "Writing enable config",
|
|
1113
1113
|
stageRepairing: "Local AI is taking over the install…",
|
|
1114
|
-
restartService: "Restart service
|
|
1114
|
+
restartService: "Restart service",
|
|
1115
1115
|
restartHostedNotice: "This instance is hosted by the desktop shell - restart it there by fully quitting and reopening DeepSeek Harness.",
|
|
1116
|
-
restarting: "Handling the restart request
|
|
1116
|
+
restarting: "Handling the restart request…",
|
|
1117
1117
|
autoReload: "Page will auto-reload…",
|
|
1118
1118
|
aiRepaired: "Local AI took over and finished the repair; refresh the page",
|
|
1119
1119
|
deletePlugin: "Delete plugin (remove config and uninstall package)",
|
|
@@ -1771,12 +1771,24 @@ function healthSignature(health) {
|
|
|
1771
1771
|
}
|
|
1772
1772
|
/** 重启服务(按钮 / 工具项 / 自更新后共用):服务端在「本实例由桌面端外壳托管」等场景会**拒绝**
|
|
1773
1773
|
* 并回结构化短句 —— 必须把它显示出来,否则按钮看起来是「点了没反应」(旧实现把错误吞掉了)。 */
|
|
1774
|
+
// ★ 0.5.92:本函数是模块级的,**不能用组件的 t()** —— 用了就抛 ReferenceError,
|
|
1775
|
+
// 点击直接异常、请求都发不出去(这正是"点了没反应"的真因)。文案用常量,永不抛。
|
|
1776
|
+
const RESTART_IN_PROGRESS_NOTE = "正在处理重启请求…";
|
|
1777
|
+
const RESTART_FAILED_NOTE = "重启请求失败";
|
|
1774
1778
|
function restartServiceViaServer(setMessage, options) {
|
|
1775
1779
|
const reload = (options ?? {}).reload !== false;
|
|
1776
|
-
if (reload) setMessage(
|
|
1780
|
+
if (reload) setMessage(RESTART_IN_PROGRESS_NOTE);
|
|
1777
1781
|
call("/plugin-console/restart", {}).then(
|
|
1778
|
-
() => {
|
|
1779
|
-
|
|
1782
|
+
(data) => {
|
|
1783
|
+
// ★ 0.5.89:显示服务端那段说明(发生了什么、要不要等、等多久)
|
|
1784
|
+
const note = data !== null && typeof data === "object" && typeof data.message === "string" && data.message !== ""
|
|
1785
|
+
? data.message
|
|
1786
|
+
: RESTART_IN_PROGRESS_NOTE;
|
|
1787
|
+
setMessage(note);
|
|
1788
|
+
if (reload) window.setTimeout(() => window.location.reload(), 12000);
|
|
1789
|
+
else if (typeof options?.onDone === "function") options.onDone(data);
|
|
1790
|
+
},
|
|
1791
|
+
(error) => { setMessage(error !== null && typeof error.message === "string" && error.message !== "" ? error.message : RESTART_FAILED_NOTE); },
|
|
1780
1792
|
);
|
|
1781
1793
|
}
|
|
1782
1794
|
/** 超时类错误附上可操作提示(网络黑洞期的最常见表现)。 */
|
|
@@ -5748,9 +5760,12 @@ function healthSignature(health) {
|
|
|
5748
5760
|
dragRef.current.base = cur;
|
|
5749
5761
|
dragRef.current.active = false;
|
|
5750
5762
|
dragRef.current.justDragged = false;
|
|
5751
|
-
|
|
5763
|
+
// ★ 0.5.91:不要在这里捕获指针(会把内部按钮的 click 吞到容器上)。先记下,长按确认拖动后再捕获。
|
|
5764
|
+
dragRef.current.captureEl = e.currentTarget;
|
|
5765
|
+
dragRef.current.captureId = e.pointerId;
|
|
5752
5766
|
dragRef.current.long = window.setTimeout(() => {
|
|
5753
5767
|
dragRef.current.active = true;
|
|
5768
|
+
try { dragRef.current.captureEl?.setPointerCapture?.(dragRef.current.captureId); } catch {}
|
|
5754
5769
|
setDragPos(cur);
|
|
5755
5770
|
}, 450);
|
|
5756
5771
|
},
|
|
@@ -5766,6 +5781,7 @@ function healthSignature(health) {
|
|
|
5766
5781
|
},
|
|
5767
5782
|
onPointerUp: () => {
|
|
5768
5783
|
if (dragRef.current.long !== null) { window.clearTimeout(dragRef.current.long); dragRef.current.long = null; }
|
|
5784
|
+
try { dragRef.current.captureEl?.releasePointerCapture?.(dragRef.current.captureId); } catch {}
|
|
5769
5785
|
if (dragRef.current.active) {
|
|
5770
5786
|
const p = dragPos;
|
|
5771
5787
|
if (p !== null) {
|
|
@@ -19,6 +19,13 @@ function resolveDshBin() {
|
|
|
19
19
|
const requireLocal = createRequire(join(pluginRoot(), 'package.json'))
|
|
20
20
|
return join(dirname(requireLocal.resolve('@deepseek-ai/dsh/package.json')), 'lib', 'bin.js')
|
|
21
21
|
} catch {
|
|
22
|
+
// ★ 0.5.88:npx / 启动器拉起的实例,插件根里没有 @deepseek-ai/dsh,上面必然失败。
|
|
23
|
+
// 此时用**当前进程自己**的入口反推 —— process.argv[1] 就是拉起本进程的那个脚本。
|
|
24
|
+
// 只在它确实存在且是文件时采用(绝不凭空造一个路径),否则仍如实返回 null。
|
|
25
|
+
try {
|
|
26
|
+
const entry = typeof process.argv[1] === 'string' ? process.argv[1] : ''
|
|
27
|
+
if (entry !== '' && /[\\/]bin\.js$/u.test(entry) && existsSync(entry)) return entry
|
|
28
|
+
} catch {}
|
|
22
29
|
return null
|
|
23
30
|
}
|
|
24
31
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@noob-stupid/dsh-plugin-console",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.92",
|
|
4
4
|
"description": "DSH 框架升级安全与插件升级门控:一键升级、失败自动回滚、升级后回滚上版、旧插件不适配自动禁用;内置多源插件市场为发现层,插件源全部可自定义,可指向公司内网私有源 / 私有索引 / 本地 Git 仓库,纯内网离线可用 | Framework upgrade safety & plugin version gating for DSH, with a customizable multi-source plugin market: point every source at internal mirrors or a local file:// repo for intranet-only, offline installs.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|