dshmarket 1.66.22 → 1.66.23
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/client/client.js +23 -4
- package/lib/install.js +31 -5
- package/package.json +1 -1
- package/src/client/MarketSection.tsx +28 -3
- package/src/client/locales.ts +2 -0
- package/src/install.ts +29 -5
package/client/client.js
CHANGED
|
@@ -557,6 +557,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
557
557
|
marketUpdate: "更新插件市场",
|
|
558
558
|
updateAll: "全部更新",
|
|
559
559
|
heldReleaseNotice: "已安装,但不是最新版:这个 profile 的 minimumReleaseAge 挡住了 {0},安装的是 {1}。",
|
|
560
|
+
installedDependencyNote: "另有 {0} 个包是插件带进来的依赖,不是插件,未列在上方。",
|
|
560
561
|
heldReleaseAction: "仍安装 {0}",
|
|
561
562
|
ignoreUpdateNotice: "重启前不再提醒",
|
|
562
563
|
ignoreAllUpdateNotices: "重启前都不再提醒",
|
|
@@ -1273,6 +1274,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
1273
1274
|
marketUpdate: "Update the plugin market",
|
|
1274
1275
|
updateAll: "Update all",
|
|
1275
1276
|
heldReleaseNotice: "Installed, but not the newest: this profile's minimumReleaseAge held {0} back, so {1} was installed.",
|
|
1277
|
+
installedDependencyNote: "{0} more packages came in as dependencies of plugins — they are not plugins, so they are not listed above.",
|
|
1276
1278
|
heldReleaseAction: "Install {0} anyway",
|
|
1277
1279
|
ignoreUpdateNotice: "Don't remind until restart",
|
|
1278
1280
|
ignoreAllUpdateNotices: "Don't remind any until restart",
|
|
@@ -10641,7 +10643,19 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
10641
10643
|
const reminderUpdatableNames = updatableNames.filter((name) => !quietUpdateSet.has(name) && !installedBlocked(name));
|
|
10642
10644
|
const reminderBatchUpdatableNames = batchUpdatableNames.filter((name) => !quietUpdateSet.has(name) && !installedBlocked(name));
|
|
10643
10645
|
const reminderUpdateNames = [...updates[selfName]?.updateAvailable === true && !updatedNames.includes(selfName) ? [selfName] : [], ...updatableNames].filter((name) => !quietUpdateSet.has(name) && !installedBlocked(name));
|
|
10644
|
-
|
|
10646
|
+
/**
|
|
10647
|
+
* Installed packages that are not plugins at all: a plain library some
|
|
10648
|
+
* other plugin pulled in — zustand, bufferutil, a peer of ws (#634's
|
|
10649
|
+
* `dependencyOf`, #857). They were rendered as plugin cards with a
|
|
10650
|
+
* working uninstall, which is a real remove path for something a plugin
|
|
10651
|
+
* needs. Out of the list; the count stays visible in one quiet line, so the
|
|
10652
|
+
* list is not silently shorter than package.json.
|
|
10653
|
+
*/
|
|
10654
|
+
const dependencyOnlyNames = (0, react.useMemo)(() => new Set(Object.keys(installed).filter((name) => {
|
|
10655
|
+
const act = activations[name];
|
|
10656
|
+
return act?.state === "inert" && act.dependencyOf !== void 0;
|
|
10657
|
+
})), [installed, activations]);
|
|
10658
|
+
const installedOtherCount = Object.keys(installed).filter((name) => name !== selfName && !dependencyOnlyNames.has(name)).length;
|
|
10645
10659
|
const ignoreUpdateNotices = (0, react.useCallback)((names) => {
|
|
10646
10660
|
if (bootId === null || names.length === 0) return;
|
|
10647
10661
|
setIgnoredUpdateNames((current) => {
|
|
@@ -10936,7 +10950,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
10936
10950
|
const isInstalledListActive = tab === "installed" && installedView === "list";
|
|
10937
10951
|
const updatesLoaded = Object.keys(updates).length > 0;
|
|
10938
10952
|
const orderedInstalledEntries = (0, react.useMemo)(() => {
|
|
10939
|
-
return Object.entries(displayedInstalled).filter(([name]) => name !== selfName).sort(([nameA, specA], [nameB, specB]) => {
|
|
10953
|
+
return Object.entries(displayedInstalled).filter(([name]) => name !== selfName).filter(([name]) => !dependencyOnlyNames.has(name)).sort(([nameA, specA], [nameB, specB]) => {
|
|
10940
10954
|
const aOn = effectiveDisabledSet.has(nameA) ? 0 : 1;
|
|
10941
10955
|
const bOn = effectiveDisabledSet.has(nameB) ? 0 : 1;
|
|
10942
10956
|
if (aOn !== bOn) return bOn - aOn;
|
|
@@ -10948,7 +10962,8 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
10948
10962
|
displayedInstalled,
|
|
10949
10963
|
selfName,
|
|
10950
10964
|
updatesLoaded,
|
|
10951
|
-
effectiveDisabledSet
|
|
10965
|
+
effectiveDisabledSet,
|
|
10966
|
+
dependencyOnlyNames
|
|
10952
10967
|
]);
|
|
10953
10968
|
const missingRestoreCount = Object.keys(pendingDependencies).filter((name) => !installedFiles.includes(name)).length;
|
|
10954
10969
|
const hasUpdates = reminderUpdatableNames.length > 0;
|
|
@@ -11770,7 +11785,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
11770
11785
|
*/
|
|
11771
11786
|
const pendingRefreshNames = (0, react.useMemo)(() => [.../* @__PURE__ */ new Set([...hotNames, ...refreshNames])], [hotNames, refreshNames]);
|
|
11772
11787
|
/** Installed plugins the market itself cannot group (#60). */
|
|
11773
|
-
const groupableNames = Object.keys(installed).filter((name) => name !== "dsh-market" && name !== "dshmarket");
|
|
11788
|
+
const groupableNames = Object.keys(installed).filter((name) => name !== "dsh-market" && name !== "dshmarket" && !dependencyOnlyNames.has(name));
|
|
11774
11789
|
/** Names already inside some group; everything else shows under "ungrouped". */
|
|
11775
11790
|
const groupedNames = (0, react.useMemo)(() => new Set(Object.values(groups).flat()), [groups]);
|
|
11776
11791
|
const ungroupedNames = groupableNames.filter((name) => !groupedNames.has(name));
|
|
@@ -13641,6 +13656,10 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
13641
13656
|
})]
|
|
13642
13657
|
}, name);
|
|
13643
13658
|
}
|
|
13659
|
+
}),
|
|
13660
|
+
dependencyOnlyNames.size > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
13661
|
+
className: Market_module_css_default.groupOrgHint,
|
|
13662
|
+
children: t("installedDependencyNote").replace("{0}", String(dependencyOnlyNames.size))
|
|
13644
13663
|
})
|
|
13645
13664
|
] })
|
|
13646
13665
|
}),
|
package/lib/install.js
CHANGED
|
@@ -328,10 +328,16 @@ export async function withHoistRecovery(run, profile, pluginArgs, profileDirecto
|
|
|
328
328
|
// no options from us — but the classified message above says the market
|
|
329
329
|
// retried. Say that it did not, or the user reads a retry that never
|
|
330
330
|
// happened and looks for the wrong cause.
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
331
|
+
//
|
|
332
|
+
// The wait on a fresh release is the one of these where "no retry" leaves
|
|
333
|
+
// the user with nothing to do at all: the plugin IS published, pnpm just
|
|
334
|
+
// will not take it yet, and the door the market would open on a plain
|
|
335
|
+
// `dsh web` host is shut here — so say when the same button starts
|
|
336
|
+
// working, and what to use meanwhile (#852).
|
|
337
|
+
const note = unavailableOption === RELEASE_AGE_OVERRIDE
|
|
338
|
+
? `这个插件的新版本比本 profile 的 minimumReleaseAge(新版本等待期)还新,pnpm 因此拒绝了本次改动(改别的插件也一样)。官方桌面端由应用自己执行安装,不接受市场的临时放行参数(${unavailableOption}),所以这里没有自动重试。**等这个版本过了等待期再更新一次即可**;想现在就更新,可以在普通的 dsh web 里装。 / The plugin's new version is younger than this profile's minimumReleaseAge, so pnpm refused this change (a change to another plugin too). The official desktop app runs the install itself and takes no one-shot bypass from the market (${unavailableOption}), so no automatic retry happens here. **Update again once the version is past the wait**; to update right now, install from plain dsh web.`
|
|
339
|
+
: `这台宿主(官方桌面端)自己执行安装,不接受市场附加的 pnpm 参数(${unavailableOption}),所以这一步没有自动重试。 / This host (the official desktop app) runs the install itself and takes no pnpm options from the market (${unavailableOption}), so that automatic retry could not be attempted.`;
|
|
340
|
+
result = { ...result, stderr: `${result.stderr}\n\n${note}` };
|
|
335
341
|
}
|
|
336
342
|
return result;
|
|
337
343
|
}
|
|
@@ -426,7 +432,27 @@ export function failureDetail(result, limit = 300) {
|
|
|
426
432
|
const code = result.pnpmErrorCode === undefined ? '' : `${result.pnpmErrorCode}: `;
|
|
427
433
|
return `${code}${result.pnpmError}`.slice(0, limit);
|
|
428
434
|
}
|
|
429
|
-
|
|
435
|
+
const text = (result.stderr || result.stdout).trim();
|
|
436
|
+
if (text.length <= limit)
|
|
437
|
+
return text;
|
|
438
|
+
const tail = text.slice(-limit);
|
|
439
|
+
// Cut at a sentence end instead of mid-word, and say that something was
|
|
440
|
+
// dropped (#852). The market appends its own explanation to pnpm's output,
|
|
441
|
+
// and this tail is catalogued into user-facing sentences — including inside
|
|
442
|
+
// a parenthesis. A blunt cut landed inside the previous sentence and welded
|
|
443
|
+
// the fragment to the next one: the reporter's log read
|
|
444
|
+
// `(is, export the log and report it这台宿主…`, which is not a sentence in
|
|
445
|
+
// either language and says nothing about what to do.
|
|
446
|
+
const sentenceEnd = /[.!?。!?]["')\])]?[\s\n]+/gu;
|
|
447
|
+
const match = sentenceEnd.exec(tail);
|
|
448
|
+
if (match !== null) {
|
|
449
|
+
const rest = tail.slice(match.index + match[0].length).trim();
|
|
450
|
+
// A boundary so near the end would leave a word or two; the raw tail is
|
|
451
|
+
// more use than the stub.
|
|
452
|
+
if (rest.length >= 40)
|
|
453
|
+
return `… ${rest}`;
|
|
454
|
+
}
|
|
455
|
+
return `…${tail.trim()}`;
|
|
430
456
|
}
|
|
431
457
|
/**
|
|
432
458
|
* Some registry entries point at collection repos whose actual plugin lives
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dshmarket",
|
|
3
3
|
"description": "Visual plugin market inside DeepSeek Harness — browse, search, and one-click install community plugins. · DSH 可视化插件市场:逛一逛,点一下,装好。",
|
|
4
|
-
"version": "1.66.
|
|
4
|
+
"version": "1.66.23",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
7
7
|
"types": "lib/types/index.d.ts",
|
|
@@ -4462,7 +4462,23 @@ export function MarketSection(props: MarketSectionProps) {
|
|
|
4462
4462
|
// The market manages itself from its own settings card (Settings → Plugins
|
|
4463
4463
|
// → Plugin configuration), not as a row here — listing it in both places
|
|
4464
4464
|
// read as two different controls for the same thing.
|
|
4465
|
-
|
|
4465
|
+
/**
|
|
4466
|
+
* Installed packages that are not plugins at all: a plain library some
|
|
4467
|
+
* other plugin pulled in — zustand, bufferutil, a peer of ws (#634's
|
|
4468
|
+
* `dependencyOf`, #857). They were rendered as plugin cards with a
|
|
4469
|
+
* working uninstall, which is a real remove path for something a plugin
|
|
4470
|
+
* needs. Out of the list; the count stays visible in one quiet line, so the
|
|
4471
|
+
* list is not silently shorter than package.json.
|
|
4472
|
+
*/
|
|
4473
|
+
const dependencyOnlyNames = useMemo(
|
|
4474
|
+
() => new Set(Object.keys(installed).filter(name => {
|
|
4475
|
+
const act = activations[name]
|
|
4476
|
+
return act?.state === 'inert' && act.dependencyOf !== undefined
|
|
4477
|
+
})),
|
|
4478
|
+
[installed, activations],
|
|
4479
|
+
)
|
|
4480
|
+
const installedOtherCount = Object.keys(installed)
|
|
4481
|
+
.filter(name => name !== selfName && !dependencyOnlyNames.has(name)).length
|
|
4466
4482
|
|
|
4467
4483
|
const ignoreUpdateNotices = useCallback((names: string[]) => {
|
|
4468
4484
|
if (bootId === null || names.length === 0) return
|
|
@@ -4759,6 +4775,7 @@ export function MarketSection(props: MarketSectionProps) {
|
|
|
4759
4775
|
const orderedInstalledEntries = useMemo(() => {
|
|
4760
4776
|
return Object.entries(displayedInstalled)
|
|
4761
4777
|
.filter(([name]) => name !== selfName)
|
|
4778
|
+
.filter(([name]) => !dependencyOnlyNames.has(name))
|
|
4762
4779
|
.sort(([nameA, specA], [nameB, specB]) => {
|
|
4763
4780
|
// The list reads as "what is running", so a plugin that is off sinks
|
|
4764
4781
|
// below every one that is on (#745) — even a disabled row with a
|
|
@@ -4771,7 +4788,7 @@ export function MarketSection(props: MarketSectionProps) {
|
|
|
4771
4788
|
return bUp - aUp
|
|
4772
4789
|
})
|
|
4773
4790
|
// eslint-disable-next-line react-hooks/exhaustive-deps -- `updatesLoaded` stands in for `updates`/`updatedNames`: reorder when the check lands, then hold (#631). `effectiveDisabledSet` only re-runs this when a disable state actually changed; the toggled row is the only one that moves.
|
|
4774
|
-
}, [isInstalledListActive, displayedInstalled, selfName, updatesLoaded, effectiveDisabledSet])
|
|
4791
|
+
}, [isInstalledListActive, displayedInstalled, selfName, updatesLoaded, effectiveDisabledSet, dependencyOnlyNames])
|
|
4775
4792
|
const missingRestoreCount = Object.keys(pendingDependencies).filter(name => !installedFiles.includes(name)).length
|
|
4776
4793
|
// Self-update lives in the header button and the settings card, not this
|
|
4777
4794
|
// tab's row list (the market itself is filtered out below) — so a pending
|
|
@@ -5520,7 +5537,8 @@ export function MarketSection(props: MarketSectionProps) {
|
|
|
5520
5537
|
)
|
|
5521
5538
|
|
|
5522
5539
|
/** Installed plugins the market itself cannot group (#60). */
|
|
5523
|
-
const groupableNames = Object.keys(installed)
|
|
5540
|
+
const groupableNames = Object.keys(installed)
|
|
5541
|
+
.filter(name => name !== 'dsh-market' && name !== 'dshmarket' && !dependencyOnlyNames.has(name))
|
|
5524
5542
|
/** Names already inside some group; everything else shows under "ungrouped". */
|
|
5525
5543
|
const groupedNames = useMemo(() => new Set(Object.values(groups).flat()), [groups])
|
|
5526
5544
|
const ungroupedNames = groupableNames.filter(name => !groupedNames.has(name))
|
|
@@ -7045,6 +7063,13 @@ export function MarketSection(props: MarketSectionProps) {
|
|
|
7045
7063
|
}}
|
|
7046
7064
|
/>
|
|
7047
7065
|
)}
|
|
7066
|
+
{dependencyOnlyNames.size > 0 && (
|
|
7067
|
+
// The list is complete as a list of PLUGINS; the count keeps it
|
|
7068
|
+
// from looking like packages went missing (#857).
|
|
7069
|
+
<p className={css.groupOrgHint}>
|
|
7070
|
+
{t('installedDependencyNote').replace('{0}', String(dependencyOnlyNames.size))}
|
|
7071
|
+
</p>
|
|
7072
|
+
)}
|
|
7048
7073
|
</>
|
|
7049
7074
|
)}
|
|
7050
7075
|
</div>
|
package/src/client/locales.ts
CHANGED
|
@@ -366,6 +366,7 @@ export const zh = {
|
|
|
366
366
|
marketUpdate: '更新插件市场',
|
|
367
367
|
updateAll: '全部更新',
|
|
368
368
|
heldReleaseNotice: '已安装,但不是最新版:这个 profile 的 minimumReleaseAge 挡住了 {0},安装的是 {1}。',
|
|
369
|
+
installedDependencyNote: '另有 {0} 个包是插件带进来的依赖,不是插件,未列在上方。',
|
|
369
370
|
heldReleaseAction: '仍安装 {0}',
|
|
370
371
|
ignoreUpdateNotice: '重启前不再提醒',
|
|
371
372
|
ignoreAllUpdateNotices: '重启前都不再提醒',
|
|
@@ -1096,6 +1097,7 @@ export const en: Record<MarketKey, string> = {
|
|
|
1096
1097
|
marketUpdate: 'Update the plugin market',
|
|
1097
1098
|
updateAll: 'Update all',
|
|
1098
1099
|
heldReleaseNotice: 'Installed, but not the newest: this profile\'s minimumReleaseAge held {0} back, so {1} was installed.',
|
|
1100
|
+
installedDependencyNote: '{0} more packages came in as dependencies of plugins — they are not plugins, so they are not listed above.',
|
|
1099
1101
|
heldReleaseAction: 'Install {0} anyway',
|
|
1100
1102
|
ignoreUpdateNotice: "Don't remind until restart",
|
|
1101
1103
|
ignoreAllUpdateNotices: "Don't remind any until restart",
|
package/src/install.ts
CHANGED
|
@@ -334,10 +334,16 @@ export async function withHoistRecovery(
|
|
|
334
334
|
// no options from us — but the classified message above says the market
|
|
335
335
|
// retried. Say that it did not, or the user reads a retry that never
|
|
336
336
|
// happened and looks for the wrong cause.
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
337
|
+
//
|
|
338
|
+
// The wait on a fresh release is the one of these where "no retry" leaves
|
|
339
|
+
// the user with nothing to do at all: the plugin IS published, pnpm just
|
|
340
|
+
// will not take it yet, and the door the market would open on a plain
|
|
341
|
+
// `dsh web` host is shut here — so say when the same button starts
|
|
342
|
+
// working, and what to use meanwhile (#852).
|
|
343
|
+
const note = unavailableOption === RELEASE_AGE_OVERRIDE
|
|
344
|
+
? `这个插件的新版本比本 profile 的 minimumReleaseAge(新版本等待期)还新,pnpm 因此拒绝了本次改动(改别的插件也一样)。官方桌面端由应用自己执行安装,不接受市场的临时放行参数(${unavailableOption}),所以这里没有自动重试。**等这个版本过了等待期再更新一次即可**;想现在就更新,可以在普通的 dsh web 里装。 / The plugin's new version is younger than this profile's minimumReleaseAge, so pnpm refused this change (a change to another plugin too). The official desktop app runs the install itself and takes no one-shot bypass from the market (${unavailableOption}), so no automatic retry happens here. **Update again once the version is past the wait**; to update right now, install from plain dsh web.`
|
|
345
|
+
: `这台宿主(官方桌面端)自己执行安装,不接受市场附加的 pnpm 参数(${unavailableOption}),所以这一步没有自动重试。 / This host (the official desktop app) runs the install itself and takes no pnpm options from the market (${unavailableOption}), so that automatic retry could not be attempted.`
|
|
346
|
+
result = { ...result, stderr: `${result.stderr}\n\n${note}` }
|
|
341
347
|
}
|
|
342
348
|
return result
|
|
343
349
|
}
|
|
@@ -432,7 +438,25 @@ export function failureDetail(result: InstallResult, limit = 300): string {
|
|
|
432
438
|
const code = result.pnpmErrorCode === undefined ? '' : `${result.pnpmErrorCode}: `
|
|
433
439
|
return `${code}${result.pnpmError}`.slice(0, limit)
|
|
434
440
|
}
|
|
435
|
-
|
|
441
|
+
const text = (result.stderr || result.stdout).trim()
|
|
442
|
+
if (text.length <= limit) return text
|
|
443
|
+
const tail = text.slice(-limit)
|
|
444
|
+
// Cut at a sentence end instead of mid-word, and say that something was
|
|
445
|
+
// dropped (#852). The market appends its own explanation to pnpm's output,
|
|
446
|
+
// and this tail is catalogued into user-facing sentences — including inside
|
|
447
|
+
// a parenthesis. A blunt cut landed inside the previous sentence and welded
|
|
448
|
+
// the fragment to the next one: the reporter's log read
|
|
449
|
+
// `(is, export the log and report it这台宿主…`, which is not a sentence in
|
|
450
|
+
// either language and says nothing about what to do.
|
|
451
|
+
const sentenceEnd = /[.!?。!?]["')\])]?[\s\n]+/gu
|
|
452
|
+
const match = sentenceEnd.exec(tail)
|
|
453
|
+
if (match !== null) {
|
|
454
|
+
const rest = tail.slice(match.index + match[0].length).trim()
|
|
455
|
+
// A boundary so near the end would leave a word or two; the raw tail is
|
|
456
|
+
// more use than the stub.
|
|
457
|
+
if (rest.length >= 40) return `… ${rest}`
|
|
458
|
+
}
|
|
459
|
+
return `…${tail.trim()}`
|
|
436
460
|
}
|
|
437
461
|
|
|
438
462
|
/**
|