dsh-m 0.10.1 → 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 +24 -0
- package/lib/client.js +36 -46
- package/lib/core/host-api.js +6 -4
- package/lib/core/profile-ops.js +30 -2
- package/package.json +1 -1
- package/registry.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,18 @@ 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
|
+
|
|
17
|
+
### 0.10.2 修复:D3 自升级 post-write 伪失败账实改判 + 静默自升级(0.10.0→0.10.1 dogfood 实证轮)
|
|
18
|
+
|
|
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 引入的自升级确认框破坏既有「点击即升级」体验(主人裁决撤除)。
|
|
20
|
+
- **方案**:① **D3 终态失败一律账实复读改判**——实读 listInstalled:目标版已写入 = 升级事实成立,按成功改判(needsRestart=true 提示重启激活,output 留改判痕);未到目标 = 真失败原语义;profileDir 自 host-api/两处缝透传。② **静默自升级**——确认框整体撤除(受控态/Modal/文案键/SSR 钉),角标点击直接升级,结局由成功/失败横幅如实报告。ADR-0022 增补决议 7(spike 推断修正 + 改判 + UX 裁决入册)。
|
|
21
|
+
- **验证**:typecheck 零错误;全量测试(新增 2 钉 T-D1 改判成功/T-D2 真失败双形态,静默结构钉替换确认框钉;18 例既有失败 028 本机环境清单零新增);真机事件本身即第一份 dogfood 数据:0.10.1 经「重启激活」到位,重启后守卫锚点干净。
|
|
22
|
+
|
|
11
23
|
### 0.10.1 修复:0.10.0 真机 E2E 实证缺陷三连——enable 竞速重试普适化 + 回装失败账实复读 + 守卫命中一律两步化
|
|
12
24
|
|
|
13
25
|
- **需求(2026-10-17,0.10.0 装机当日 E2E 实证,真机 skip-auth@0.4.1 与卸载→重装两个事件)**:①插件树重载窗口的 enable 阶段激活竞速(`pending (waiting for service: webRuntime)`)会让两步升级的第二腿、兜底回装腿与 D3 自升级通道直接终态失败——0.9.94 时代的「enable 失败自动重试一次(重试即愈)」本地增强只覆盖了首腿;②回装腿报失败 ≠ 真缺席——pnpm 可能已写入账面(激活阶段失败),此时建议「手动重装旧版」会误导用户降级;③卸载后同会话重装:宿主活跃态/manifest 字面仍视其在装(守卫命中),而 previousVersion 探测口径为「未安装」,0.10.0 的 previousVersion 前置门使守卫命中原样透传 already-installed。
|
|
@@ -673,6 +685,18 @@ The full release history of dsh-m, maintained bilingually: **Chinese first, Engl
|
|
|
673
685
|
|
|
674
686
|
## English
|
|
675
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
|
+
|
|
694
|
+
### Fixes in 0.10.2 — account-reality reconciliation for D3 self-upgrade post-write pseudo-failure + silent self-upgrade (first D3 dogfood round)
|
|
695
|
+
|
|
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).
|
|
697
|
+
- **Approach**: ① **reconcile on any D3 terminal failure** — re-read listInstalled: if the target version is already written, the upgrade factually happened and the result is re-judged as success (needsRestart=true prompting the activating restart, with the reconciliation noted in output); if the target is absent, the genuine-failure semantics stand; profileDir is threaded from host-api and both seams. ② **silent self-upgrade** — the confirmation dialog is removed wholesale (controlled state / modal / copy keys / SSR pin); the chip click upgrades directly and outcomes are still reported truthfully via banners. ADR-0022 decision 7 records the spike-inference correction, the reconciliation, and the UX ruling.
|
|
698
|
+
- **Verification**: typecheck clean; full suite (2 new pins T-D1 reconciled-success / T-D2 genuine-failure, silent structure pins replacing the confirmation pins; 18 pre-existing failures are the 028 machine-environment set, zero new); the real-machine event itself is the first dogfood datum: 0.10.1 landed via "restart to activate", guard journal anchors clean after restart.
|
|
699
|
+
|
|
676
700
|
### Fixes in 0.10.1 — three defects proven by same-day real-machine E2E of 0.10.0: enable-race retry universalized + account-reality re-read on rollback failure + guard hit always two-steps
|
|
677
701
|
|
|
678
702
|
- **Need (2026-10-17, proven during the same-day real-machine E2E of 0.10.0 — the skip-auth@0.4.1 upgrade event and the uninstall→reinstall event)**: ① the enable-stage activation race during plugin-tree reload windows (`pending (waiting for service: webRuntime)`) made the two-step upgrade's second leg, the rollback reinstall leg, and the D3 self-upgrade channel fail terminally — the 0.9.94-era "retry enable failures once (retry heals)" local enhancement covered only the first leg; ② a failed reinstall leg ≠ true absence — pnpm may have already written the package (activation failed afterwards), where advising "manually reinstall the old version" would mislead the user into a downgrade; ③ uninstall followed by a same-session reinstall: the host's live state / literal manifest still considers the package installed (guard fires) while the previousVersion probe reports "not installed", so 0.10.0's previousVersion precondition let the raw already-installed error surface.
|
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 });
|
|
@@ -2351,9 +2369,6 @@ var ZH = {
|
|
|
2351
2369
|
"op.degraded": "\u5347\u7EA7\u5931\u8D25\uFF1A\u65B0\u7248\u5B89\u88C5\u672A\u6210\u529F\uFF0C\u5DF2\u81EA\u52A8\u6062\u590D\u65E7\u7248 {restoredTo}\u2014\u2014\u63D2\u4EF6\u5F53\u524D\u53EF\u7528\uFF0C\u53EF\u7A0D\u540E\u91CD\u8BD5\u3002",
|
|
2352
2370
|
"notify.selfupgraded": "dsh-m \u5DF2\u5347\u7EA7\uFF08v{from} \u2192 v{to}\uFF09",
|
|
2353
2371
|
"notify.selfupgraded.failed": "dsh-m \u5347\u7EA7\u5931\u8D25\uFF1A{err}",
|
|
2354
|
-
"selfupgrade.confirm": "\u5C06\u901A\u8FC7 tarball \u76F4\u88C5\u901A\u9053\u628A dsh-m \u5347\u7EA7\u5230 {version}\uFF1A\u4E0D\u7ECF\u8FC7\u5378\u8F7D\uFF0C\u5931\u8D25\u65F6\u5F53\u524D\u7248\u672C\u4E0D\u53D7\u5F71\u54CD\uFF1B\u5B8C\u6210\u540E\u9700\u91CD\u542F Desktop \u751F\u6548\u3002",
|
|
2355
|
-
"selfupgrade.confirm.noversion": "\u5C06\u901A\u8FC7 tarball \u76F4\u88C5\u901A\u9053\u5347\u7EA7 dsh-m\uFF1A\u4E0D\u7ECF\u8FC7\u5378\u8F7D\uFF0C\u5931\u8D25\u65F6\u5F53\u524D\u7248\u672C\u4E0D\u53D7\u5F71\u54CD\uFF1B\u5B8C\u6210\u540E\u9700\u91CD\u542F Desktop \u751F\u6548\u3002",
|
|
2356
|
-
"selfupgrade.go": "\u5347\u7EA7",
|
|
2357
2372
|
"failed.install": "\u5B89\u88C5\u5931\u8D25\uFF1A{err}",
|
|
2358
2373
|
"failed.uninstall": "\u5378\u8F7D\u5931\u8D25\uFF1A{err}",
|
|
2359
2374
|
"failed.upgrade": "\u5347\u7EA7\u5931\u8D25\uFF1A{err}",
|
|
@@ -2655,9 +2670,6 @@ var EN = {
|
|
|
2655
2670
|
"op.degraded": "Upgrade failed: the new version did not install \u2014 rolled back to {restoredTo}. The plugin still works; you can retry later.",
|
|
2656
2671
|
"notify.selfupgraded": "dsh-m upgraded (v{from} \u2192 v{to})",
|
|
2657
2672
|
"notify.selfupgraded.failed": "dsh-m upgrade failed: {err}",
|
|
2658
|
-
"selfupgrade.confirm": "Upgrade dsh-m to {version} via the tarball direct-install channel: no uninstall involved, the current version stays intact on failure; a Desktop restart is needed afterwards.",
|
|
2659
|
-
"selfupgrade.confirm.noversion": "Upgrade dsh-m via the tarball direct-install channel: no uninstall involved, the current version stays intact on failure; a Desktop restart is needed afterwards.",
|
|
2660
|
-
"selfupgrade.go": "Upgrade",
|
|
2661
2673
|
"failed.install": "Install failed: {err}",
|
|
2662
2674
|
"failed.uninstall": "Uninstall failed: {err}",
|
|
2663
2675
|
"failed.upgrade": "Upgrade failed: {err}",
|
|
@@ -4174,7 +4186,7 @@ function MarketTab({ notify, markets, onMutation, ops, favorites, profileKind, o
|
|
|
4174
4186
|
const r = await api("upgrade", { pkg: it.installedPkg });
|
|
4175
4187
|
const m = opUpgradeMeta2(r);
|
|
4176
4188
|
return m ? { ...r, opMeta: m } : r;
|
|
4177
|
-
});
|
|
4189
|
+
}, { toVersion: it.latest });
|
|
4178
4190
|
const degraded = oc.degradedOutcome(res);
|
|
4179
4191
|
if (degraded) {
|
|
4180
4192
|
notify({ kind: "warn", text: degraded.text });
|
|
@@ -4576,7 +4588,7 @@ function InstalledTab({ notify, installed, updates, onMutation, ops }) {
|
|
|
4576
4588
|
const r = await api("upgrade", { pkg: it.pkg });
|
|
4577
4589
|
const m = opUpgradeMeta2(r);
|
|
4578
4590
|
return m ? { ...r, opMeta: m } : r;
|
|
4579
|
-
});
|
|
4591
|
+
}, { toVersion: it.latestVersion });
|
|
4580
4592
|
const degraded = oc.degradedOutcome(res);
|
|
4581
4593
|
if (degraded) {
|
|
4582
4594
|
notify({ kind: "warn", text: degraded.text });
|
|
@@ -5191,12 +5203,11 @@ var TABS = [
|
|
|
5191
5203
|
["installed", "tab.installed", "installed"],
|
|
5192
5204
|
["settings", "tab.settings", null]
|
|
5193
5205
|
];
|
|
5194
|
-
function DshmVersionChip({ version, notify, initialCheck, ops
|
|
5206
|
+
function DshmVersionChip({ version, notify, initialCheck, ops }) {
|
|
5195
5207
|
const [check, setCheck] = useState(
|
|
5196
5208
|
() => initialCheck !== void 0 ? initialCheck : typeof window !== "undefined" && window.localStorage ? readSelfCheckCache2(window.localStorage, { version }) : null
|
|
5197
5209
|
);
|
|
5198
5210
|
const [busy, setBusy] = useState(false);
|
|
5199
|
-
const [confirming, setConfirming] = useState(initialConfirm === true);
|
|
5200
5211
|
useEffect(() => {
|
|
5201
5212
|
if (initialCheck !== void 0) return;
|
|
5202
5213
|
let live = true;
|
|
@@ -5214,17 +5225,16 @@ function DshmVersionChip({ version, notify, initialCheck, ops, initialConfirm })
|
|
|
5214
5225
|
}, [initialCheck]);
|
|
5215
5226
|
const doUpgrade = async () => {
|
|
5216
5227
|
if (busy) return;
|
|
5217
|
-
|
|
5228
|
+
return performUpgrade();
|
|
5218
5229
|
};
|
|
5219
5230
|
const performUpgrade = async () => {
|
|
5220
5231
|
if (busy) return;
|
|
5221
|
-
setConfirming(false);
|
|
5222
5232
|
setBusy(true);
|
|
5223
5233
|
try {
|
|
5224
5234
|
const res = await (ops ? ops.runOp("upgrade", "dsh-m", async () => {
|
|
5225
5235
|
const r = await api("self-upgrade");
|
|
5226
5236
|
return { ...r, opMeta: { from: version, to: r.version || "latest" } };
|
|
5227
|
-
}, { npm: "dsh-m" }) : api("self-upgrade"));
|
|
5237
|
+
}, { npm: "dsh-m", toVersion: state.latest }) : api("self-upgrade"));
|
|
5228
5238
|
clearSelfCheckCache2(typeof window !== "undefined" && window.localStorage ? window.localStorage : null);
|
|
5229
5239
|
setCheck({ current: version, latest: null, outdated: false, ahead: false });
|
|
5230
5240
|
notify({
|
|
@@ -5247,36 +5257,6 @@ function DshmVersionChip({ version, notify, initialCheck, ops, initialConfirm })
|
|
|
5247
5257
|
};
|
|
5248
5258
|
const state = deriveChipState2(check, version);
|
|
5249
5259
|
if (state.kind === "outdated") {
|
|
5250
|
-
if (confirming) {
|
|
5251
|
-
return h(
|
|
5252
|
-
"div",
|
|
5253
|
-
{ className: "dshm-compat-overlay", ...backdropCloseHandlers2(() => setConfirming(false)) },
|
|
5254
|
-
h(
|
|
5255
|
-
"div",
|
|
5256
|
-
{ className: "dshm-compat-dialog", onClick: (e) => e.stopPropagation() },
|
|
5257
|
-
h("div", { className: "dshm-compat-title" }, lookup("selfupdate.available", { v: state.latest || "?" })),
|
|
5258
|
-
h(
|
|
5259
|
-
"div",
|
|
5260
|
-
{ className: "dshm-compat-body" },
|
|
5261
|
-
state.latest ? lookup("selfupgrade.confirm", { version: `v${state.latest}` }) : lookup("selfupgrade.confirm.noversion")
|
|
5262
|
-
),
|
|
5263
|
-
h(
|
|
5264
|
-
"div",
|
|
5265
|
-
{ className: "dshm-actions" },
|
|
5266
|
-
h(
|
|
5267
|
-
"button",
|
|
5268
|
-
{ className: "dshm-btn", onClick: () => setConfirming(false) },
|
|
5269
|
-
lookup("common.later")
|
|
5270
|
-
),
|
|
5271
|
-
h(
|
|
5272
|
-
"button",
|
|
5273
|
-
{ className: "dshm-btn primary", onClick: performUpgrade, disabled: busy },
|
|
5274
|
-
lookup("selfupgrade.go")
|
|
5275
|
-
)
|
|
5276
|
-
)
|
|
5277
|
-
)
|
|
5278
|
-
);
|
|
5279
|
-
}
|
|
5280
5260
|
return h(
|
|
5281
5261
|
"button",
|
|
5282
5262
|
{
|
|
@@ -5770,19 +5750,29 @@ function MarketPanel({ onClose }) {
|
|
|
5770
5750
|
if (opsPumpCtx && opsPumpCtx.syncOps === syncOps) opsPumpCtx = null;
|
|
5771
5751
|
};
|
|
5772
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
|
+
}, []);
|
|
5773
5763
|
const restoredRef = useRef(false);
|
|
5774
5764
|
useEffect(() => {
|
|
5775
5765
|
if (restoredRef.current || !installed.data) return;
|
|
5776
5766
|
restoredRef.current = true;
|
|
5777
5767
|
void (async () => {
|
|
5778
|
-
const restored = await restoreRecords2(opsStore.list(), stillApplies);
|
|
5768
|
+
const restored = await restoreRecords2(opsStore.list(), stillApplies, installedVersionOf);
|
|
5779
5769
|
opsStore.replaceAll(restored);
|
|
5780
5770
|
syncOps();
|
|
5781
5771
|
if (restored.some((r) => r.status === "queued")) {
|
|
5782
5772
|
void opsPump.kick();
|
|
5783
5773
|
}
|
|
5784
5774
|
})();
|
|
5785
|
-
}, [installed.data, stillApplies, syncOps]);
|
|
5775
|
+
}, [installed.data, stillApplies, installedVersionOf, syncOps]);
|
|
5786
5776
|
const counts = {
|
|
5787
5777
|
market: marketCommunity.data ? marketCommunity.data.total : null,
|
|
5788
5778
|
installed: installed.data ? installed.data.items.length : null
|
package/lib/core/host-api.js
CHANGED
|
@@ -302,14 +302,16 @@ export function createApiDispatcher(ctx) {
|
|
|
302
302
|
}
|
|
303
303
|
case 'self-upgrade': {
|
|
304
304
|
assertWriteAllowed(profile, 'self-upgrade');
|
|
305
|
-
// 0.10.0 D3 自升级专用通道(desktop):tarball
|
|
306
|
-
//
|
|
307
|
-
//
|
|
308
|
-
//
|
|
305
|
+
// 0.10.0 D3 自升级专用通道(desktop):tarball 直装。0.10.2 实证修订:0.2.1 守卫经
|
|
306
|
+
// specPackageName 对 tarball URL 同样解析包名(自升级写穿后宿主完成路径自触守卫 = post-write
|
|
307
|
+
// 伪失败),由 D3 的账实复读改判兜住;通道分治不变——remove+registry-spec 通用两步仍不达自升级。
|
|
308
|
+
// 恒 panel 语义零外部日志(ADR-0018),intent 预写/收口在 core 层。
|
|
309
309
|
if (profile.kind !== 'web') {
|
|
310
310
|
const managed = await d.desktopSelfUpgradeViaTarball(ctx.pkg.name, ctx.pkg.version, {
|
|
311
311
|
timeoutMs: cfg().timeoutMs,
|
|
312
312
|
signal,
|
|
313
|
+
// 0.10.2:账实复读(post-write 伪失败改判)需要 profile 目录
|
|
314
|
+
profileDir: profile.dir,
|
|
313
315
|
}, {
|
|
314
316
|
getService: d.getService,
|
|
315
317
|
ensureService: d.ensureService,
|
package/lib/core/profile-ops.js
CHANGED
|
@@ -194,7 +194,7 @@ async function desktopInstallLocked(id, cfg, opts, deps) {
|
|
|
194
194
|
// 0.10.0 R6(install 臂):dsh-m 已装态下的 install 调用实为升级(守卫必拦)→ 改道 D3;
|
|
195
195
|
// 全新安装(未装)走既有单步——守卫不触发,R1「新装路径不动」。
|
|
196
196
|
if (pkg === SELF_PKG && previousVersion !== undefined) {
|
|
197
|
-
return desktopSelfUpgradeViaTarballLocked(pkg, previousVersion, { timeoutMs, signal: opts.signal }, {
|
|
197
|
+
return desktopSelfUpgradeViaTarballLocked(pkg, previousVersion, { timeoutMs, signal: opts.signal, profileDir: opts.profileDir }, {
|
|
198
198
|
getService: () => service,
|
|
199
199
|
npmLatest: deps.npmLatest,
|
|
200
200
|
npmTarballUrl: deps.npmTarballUrl,
|
|
@@ -671,6 +671,34 @@ async function desktopSelfUpgradeViaTarballLocked(pkgName, currentVersion, opts,
|
|
|
671
671
|
change = changeOf(await service.installBundle(spec, { enabled: true }));
|
|
672
672
|
}
|
|
673
673
|
if (isTerminalFailure(change)) {
|
|
674
|
+
// 0.10.2(D3 dogfood 实证,0.10.0→0.10.1 真机事件):宿主对自身 bundle 换装存在 post-write 伪失败——
|
|
675
|
+
// installBundle 已写穿三面账(manifest/node_modules/lock 均为目标版)却回传 failed/already-installed
|
|
676
|
+
// (自指操作伪影:写完后 manifest 含该名,宿主完成路径自触守卫)。终态失败一律实读账面:
|
|
677
|
+
// 目标版已写入 = 升级事实成立,按成功改判(needsRestart=true,重启激活);否则真失败(原语义)。
|
|
678
|
+
let installedVersion;
|
|
679
|
+
if (opts.profileDir && deps.listInstalled) {
|
|
680
|
+
try {
|
|
681
|
+
const row = (await deps.listInstalled(opts.profileDir)).items.find((it) => it.pkg === pkgName);
|
|
682
|
+
installedVersion = row?.version;
|
|
683
|
+
}
|
|
684
|
+
catch {
|
|
685
|
+
// 复读失败按真失败处理
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
if (installedVersion === latest.version) {
|
|
689
|
+
await resolveIntent({ ok: true, installedVersion: latest.version });
|
|
690
|
+
return {
|
|
691
|
+
id: pkgName,
|
|
692
|
+
pkg: pkgName,
|
|
693
|
+
spec,
|
|
694
|
+
version: latest.version,
|
|
695
|
+
buildApprovals: Array.isArray(change.approvedBuilds) ? change.approvedBuilds : [],
|
|
696
|
+
fallbackAllBuilds: false,
|
|
697
|
+
needsRestart: true,
|
|
698
|
+
output: `official pluginManager (self-upgrade via tarball): application=${change.application ?? 'failed'}、error=${change.error?.code ?? 'terminal-failure'} 经账实复读改判成功——目标版 ${latest.version} 已写入(宿主自升级 post-write 伪失败),重启 Desktop 激活`,
|
|
699
|
+
via: 'desktop-manager',
|
|
700
|
+
};
|
|
701
|
+
}
|
|
674
702
|
const pending = pendingOf(change);
|
|
675
703
|
if (change.application === 'cancelled') {
|
|
676
704
|
throw new DesktopOpsError('install-refused', `自升级已被取消(${pkgName}):当前版本 ${currentVersion} 不受影响`);
|
|
@@ -729,7 +757,7 @@ async function desktopUpgradeLocked(pkg, cfg, opts, deps) {
|
|
|
729
757
|
const selfTarget = items.find((it) => it.pkg === pkg);
|
|
730
758
|
if (!selfTarget)
|
|
731
759
|
throw new DesktopOpsError('install-refused', `desktop profile 未安装该插件: ${pkg}(升级目标必须是已装插件)`);
|
|
732
|
-
return desktopSelfUpgradeViaTarballLocked(pkg, selfTarget.version, { timeoutMs, signal: opts.signal }, {
|
|
760
|
+
return desktopSelfUpgradeViaTarballLocked(pkg, selfTarget.version, { timeoutMs, signal: opts.signal, profileDir: opts.profileDir }, {
|
|
733
761
|
getService: () => service,
|
|
734
762
|
npmLatest: deps.npmLatest,
|
|
735
763
|
npmTarballUrl: deps.npmTarballUrl,
|
package/package.json
CHANGED
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",
|