dsh-m 0.10.2 → 0.10.3

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
@@ -8,6 +8,12 @@ The full release history of dsh-m, maintained bilingually: **Chinese first, Engl
8
8
 
9
9
  ## 中文
10
10
 
11
+ ### 0.10.3 修复:操作泵恢复记账对账(挂账 1)+ D3 applied core 直钉(挂账 3)
12
+
13
+ - **需求(2026-10-18,0.10.2 dogfood 收尾盘点挂账)**:面板随宿主换装重载会打断泵的最后落账,残留的 running 记录被恢复流程一律标「进程重启中断」——0.10.2 自升级事件中升级实际成功(intent ledger resolved ok + 三面账写穿)却被记为失败,审计误导;另:D3 `applied → needsRestart=false` 缺 core 层直接钉(此前仅 client 层间接覆盖,评审挂账 3)。
14
+ - **方案**:① `restoreRecords` 增第三参 `installedVersionOf`(账实复读缝,main.jsx 以 `api("installed")` 实读实现,与 stillApplies 同款实读纪律)——升级类 running 残留若账面已到 `meta.toVersion` → 改判 done(`meta.reconciledAfterRestart` 留痕);未到目标保持中断原语义;不传第三参行为不变(既有调用方零迁移)。② 三处升级站点 enqueue meta 携带 `toVersion`(chip=state.latest、已装列表=it.latestVersion、市场卡=it.latest)——中断恢复对账的比对依据。
15
+ - **验证**:typecheck 零错误;全量测试(新增 6:T-D3 applied core 直钉 + 恢复对账改判/未到/向后兼容三形态 + 三站点 meta 单行锚;18 例既有失败 028 本机环境清单零新增)。
16
+
11
17
  ### 0.10.2 修复:D3 自升级 post-write 伪失败账实改判 + 静默自升级(0.10.0→0.10.1 dogfood 实证轮)
12
18
 
13
19
  - **需求(2026-10-18 凌晨,首次 D3 真机 dogfood——0.10.0→0.10.1 自升级事件)**:自升级报失败(`application=failed、error=already-installed`)但三面账(manifest/node_modules/lock)均已写入 0.10.1——宿主对自身 bundle 换装存在 **post-write 伪失败**:installBundle 写穿后 manifest 含该名,宿主完成路径自触守卫(自指操作伪影;守卫源码 `specPackageName` 对 tarball URL 同样可解析包名)。另:0.10.1 引入的自升级确认框破坏既有「点击即升级」体验(主人裁决撤除)。
@@ -679,6 +685,12 @@ The full release history of dsh-m, maintained bilingually: **Chinese first, Engl
679
685
 
680
686
  ## English
681
687
 
688
+ ### Fixes in 0.10.3 — operation-pump restore ledger reconciliation (pending item 1) + D3 applied core-level pin (pending item 3)
689
+
690
+ - **Need (2026-10-18, pending items from the 0.10.2 dogfood wrap-up)**: a panel reload during the host's own bundle swap interrupts the pump's final ledger write, and the leftover running record is unconditionally labeled「进程重启中断」(process-restart interrupted) by the restore flow — in the 0.10.2 self-upgrade event the upgrade had actually succeeded (intent ledger resolved ok + all three ledgers written through) yet was recorded as failed, misleading the audit trail. Separately: D3 `applied → needsRestart=false` lacked a core-level pin (previously covered only indirectly at the client layer; review pending item 3).
691
+ - **Approach**: ① `restoreRecords` gains a third parameter `installedVersionOf` (an account-reality re-read seam implemented in main.jsx via `api("installed")`, same live-read discipline as stillApplies) — an upgrade-kind running leftover whose ledger has reached `meta.toVersion` is re-judged as done (`meta.reconciledAfterRestart` recorded); anything else keeps the interrupted semantics; omitting the third parameter preserves the old behavior (zero migration for existing callers). ② the three upgrade sites now carry `toVersion` in the enqueue meta (chip=state.latest, installed list=it.latestVersion, market card=it.latest) — the comparison basis for the restore reconciliation.
692
+ - **Verification**: typecheck clean; full suite (6 new: T-D3 applied core-level pin + three restore-reconciliation shapes + three site meta anchors; 18 pre-existing failures are the 028 machine-environment set, zero new).
693
+
682
694
  ### Fixes in 0.10.2 — account-reality reconciliation for D3 self-upgrade post-write pseudo-failure + silent self-upgrade (first D3 dogfood round)
683
695
 
684
696
  - **Need (2026-10-18 early morning, first real-machine D3 dogfood — the 0.10.0→0.10.1 self-upgrade event)**: the self-upgrade reported failure (`application=failed、error=already-installed`) while all three ledgers (manifest/node_modules/lock) had already been written to 0.10.1 — the host has a **post-write pseudo-failure** for its own bundle swap: installBundle writes through, the manifest then contains the name, and the host's completion path trips its own guard (self-referential artifact; the guard's `specPackageName` resolves package names from tarball URLs too). Separately: the 0.10.1 self-upgrade confirmation dialog broke the existing "click to upgrade" experience (owner ordered its removal).
package/lib/client.js CHANGED
@@ -1562,7 +1562,7 @@ function createOperationsStore(storage) {
1562
1562
  }
1563
1563
  };
1564
1564
  }
1565
- async function restoreRecords(records, stillApplies) {
1565
+ async function restoreRecords(records, stillApplies, installedVersionOf) {
1566
1566
  const list = Array.isArray(records) ? records : [];
1567
1567
  const out = [];
1568
1568
  for (const rec of list) {
@@ -1584,6 +1584,24 @@ async function restoreRecords(records, stillApplies) {
1584
1584
  } else if (rec.status === "input") {
1585
1585
  out.push({ ...rec, status: "failed", error: "\u5F85\u51B3\u786E\u8BA4\u4E0D\u53EF\u6062\u590D\uFF0C\u8BF7\u91CD\u65B0\u53D1\u8D77", updatedAt: Date.now() });
1586
1586
  } else if (rec.status === "running") {
1587
+ if (rec.kind === "upgrade" && rec.meta && typeof rec.meta.toVersion === "string" && rec.meta.toVersion !== "" && typeof installedVersionOf === "function") {
1588
+ let installed;
1589
+ try {
1590
+ installed = await installedVersionOf(rec);
1591
+ } catch {
1592
+ installed = void 0;
1593
+ }
1594
+ if (installed === rec.meta.toVersion) {
1595
+ out.push({
1596
+ ...rec,
1597
+ status: "done",
1598
+ error: void 0,
1599
+ meta: { ...rec.meta, reconciledAfterRestart: true },
1600
+ updatedAt: Date.now()
1601
+ });
1602
+ continue;
1603
+ }
1604
+ }
1587
1605
  out.push({ ...rec, status: "failed", error: "\u8FDB\u7A0B\u91CD\u542F\u4E2D\u65AD", updatedAt: Date.now() });
1588
1606
  } else {
1589
1607
  out.push({ ...rec });
@@ -4168,7 +4186,7 @@ function MarketTab({ notify, markets, onMutation, ops, favorites, profileKind, o
4168
4186
  const r = await api("upgrade", { pkg: it.installedPkg });
4169
4187
  const m = opUpgradeMeta2(r);
4170
4188
  return m ? { ...r, opMeta: m } : r;
4171
- });
4189
+ }, { toVersion: it.latest });
4172
4190
  const degraded = oc.degradedOutcome(res);
4173
4191
  if (degraded) {
4174
4192
  notify({ kind: "warn", text: degraded.text });
@@ -4570,7 +4588,7 @@ function InstalledTab({ notify, installed, updates, onMutation, ops }) {
4570
4588
  const r = await api("upgrade", { pkg: it.pkg });
4571
4589
  const m = opUpgradeMeta2(r);
4572
4590
  return m ? { ...r, opMeta: m } : r;
4573
- });
4591
+ }, { toVersion: it.latestVersion });
4574
4592
  const degraded = oc.degradedOutcome(res);
4575
4593
  if (degraded) {
4576
4594
  notify({ kind: "warn", text: degraded.text });
@@ -5216,7 +5234,7 @@ function DshmVersionChip({ version, notify, initialCheck, ops }) {
5216
5234
  const res = await (ops ? ops.runOp("upgrade", "dsh-m", async () => {
5217
5235
  const r = await api("self-upgrade");
5218
5236
  return { ...r, opMeta: { from: version, to: r.version || "latest" } };
5219
- }, { npm: "dsh-m" }) : api("self-upgrade"));
5237
+ }, { npm: "dsh-m", toVersion: state.latest }) : api("self-upgrade"));
5220
5238
  clearSelfCheckCache2(typeof window !== "undefined" && window.localStorage ? window.localStorage : null);
5221
5239
  setCheck({ current: version, latest: null, outdated: false, ahead: false });
5222
5240
  notify({
@@ -5732,19 +5750,29 @@ function MarketPanel({ onClose }) {
5732
5750
  if (opsPumpCtx && opsPumpCtx.syncOps === syncOps) opsPumpCtx = null;
5733
5751
  };
5734
5752
  }, [stillApplies, dispatchRestored, syncOps, refreshViews]);
5753
+ const installedVersionOf = useCallback(async (r) => {
5754
+ try {
5755
+ const fresh = await api("installed", { probe: false });
5756
+ const items = fresh && Array.isArray(fresh.items) ? fresh.items : [];
5757
+ const row = items.find((it) => it && it.pkg === r.target);
5758
+ return row && typeof row.version === "string" ? row.version : void 0;
5759
+ } catch {
5760
+ return void 0;
5761
+ }
5762
+ }, []);
5735
5763
  const restoredRef = useRef(false);
5736
5764
  useEffect(() => {
5737
5765
  if (restoredRef.current || !installed.data) return;
5738
5766
  restoredRef.current = true;
5739
5767
  void (async () => {
5740
- const restored = await restoreRecords2(opsStore.list(), stillApplies);
5768
+ const restored = await restoreRecords2(opsStore.list(), stillApplies, installedVersionOf);
5741
5769
  opsStore.replaceAll(restored);
5742
5770
  syncOps();
5743
5771
  if (restored.some((r) => r.status === "queued")) {
5744
5772
  void opsPump.kick();
5745
5773
  }
5746
5774
  })();
5747
- }, [installed.data, stillApplies, syncOps]);
5775
+ }, [installed.data, stillApplies, installedVersionOf, syncOps]);
5748
5776
  const counts = {
5749
5777
  market: marketCommunity.data ? marketCommunity.data.total : null,
5750
5778
  installed: installed.data ? installed.data.items.length : null
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-m",
3
- "version": "0.10.2",
3
+ "version": "0.10.3",
4
4
  "description": "可自定义收录清单的 DSH 插件市场:收录、安装、卸载、升级一站完成,附 agent 工具与 dshm CLI。",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/registry.json CHANGED
@@ -8,7 +8,7 @@
8
8
  "category": "essentials",
9
9
  "alsoCategories": ["self-dev"],
10
10
  "tags": ["市场", "插件管理"],
11
- "verified": ["0.1.2-rc.1", "0.1.5-rc.1", "0.1.5-rc.2", "0.1.7-rc.1", "0.1.7-rc.2", "0.2.0-rc.1", "0.2.0-rc.2"],
11
+ "verified": ["0.1.2-rc.1", "0.1.5-rc.1", "0.1.5-rc.2", "0.1.7-rc.1", "0.1.7-rc.2", "0.2.0-rc.1", "0.2.0-rc.2", "0.2.1-rc.2"],
12
12
  "source": "npm",
13
13
  "npm": "dsh-m",
14
14
  "github": "iasiv5/dsh-m",
@@ -91,7 +91,7 @@
91
91
  "description": "替换官方 Connection 跳过 BrowserAuth,免 Token;已适配七个已审计精确版本对,详见仓库。仅支持 web profile;desktop 宿主一律自动休眠(多进程树判别),desktop 用户请保持最新版。",
92
92
  "category": "self-dev",
93
93
  "tags": ["BrowserAuth", "连接", "安全", "工具"],
94
- "verified": ["0.1.2-rc.1", "0.1.5-rc.1", "0.1.5-rc.2", "0.1.7-rc.1", "0.1.7-rc.2", "0.2.0-rc.1", "0.2.0-rc.2"],
94
+ "verified": ["0.1.2-rc.1", "0.1.5-rc.1", "0.1.5-rc.2", "0.1.7-rc.1", "0.1.7-rc.2", "0.2.0-rc.1", "0.2.0-rc.2", "0.2.1-rc.2"],
95
95
  "source": "npm",
96
96
  "npm": "@iasiv5/dsh-skip-browser-auth",
97
97
  "github": "iasiv5/dsh-skip-browser-auth",