dshmarket 1.66.10 → 1.66.11
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/lib/check.js +70 -37
- package/lib/routes.js +30 -2
- package/package.json +1 -1
- package/src/check.ts +77 -34
- package/src/routes.ts +31 -2
package/lib/check.js
CHANGED
|
@@ -924,47 +924,80 @@ export function buildBundleLayers(profileDirectory, bundleNames, specs, dshInsta
|
|
|
924
924
|
* @param dshInstall - install directory the analysis located, or null.
|
|
925
925
|
* @returns the overlay layer, or null when this installation declares none.
|
|
926
926
|
*/
|
|
927
|
-
function installOverlayLayer(dshInstall) {
|
|
927
|
+
function installOverlayLayer(dshInstall, profileDirectory, declaredBundles) {
|
|
928
928
|
for (const directory of desktopApplicationRoots(dshInstall)) {
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
if (
|
|
954
|
-
|
|
955
|
-
const label = typeof manifest.name === 'string' && manifest.name !== '' ? manifest.name : 'install-overlay';
|
|
956
|
-
const paths = declaredList.map(relative => join(directory, relative));
|
|
957
|
-
if (paths.some(path => !existsSync(path))) {
|
|
958
|
-
return { label, kind: 'bundle', patches: [], parseError: 'declared patch is missing' };
|
|
959
|
-
}
|
|
960
|
-
const parsed = paths.map(path => parsePatchFile(path));
|
|
961
|
-
if (parsed.some(patches => patches === null)) {
|
|
962
|
-
return { label, kind: 'bundle', patches: [], parseError: 'patch file is not a valid entry list' };
|
|
929
|
+
// A DSH installation ships the in-box web bundle, and the launcher splices
|
|
930
|
+
// this very overlay directly behind that bundle's layer — where it is
|
|
931
|
+
// absent, the launcher applies no overlay either, so composing one here
|
|
932
|
+
// would describe a composition nobody runs (#749 review).
|
|
933
|
+
const layer = overlayFromDirectory(directory, manifest => readNodeModulesVersion(directory, '@deepseek-ai/dsh-web-app') !== null);
|
|
934
|
+
if (layer !== null)
|
|
935
|
+
return layer;
|
|
936
|
+
}
|
|
937
|
+
// The official Desktop shell plugin's own patch (#807). On a build that packs
|
|
938
|
+
// the whole runtime into one app.asar, no application-root candidate declares
|
|
939
|
+
// it: the asar's root is `@deepseek-ai/dsh-desktop` and the nested
|
|
940
|
+
// `app.asar/dsh` is `@deepseek-ai/dsh-desktop-runtime`, neither with a
|
|
941
|
+
// `dsh.bundle.patch`, while the file that really supplies the shell's rows
|
|
942
|
+
// (`desktop-shell`, `desktop-notifications`, …) is this package's own
|
|
943
|
+
// `cordis.patch.yml`. Without it every user-patch row aimed at a shell row is
|
|
944
|
+
// reported as an orphan, and a user who believes the warning deletes rows
|
|
945
|
+
// that carry the window material and the notification preferences.
|
|
946
|
+
//
|
|
947
|
+
// Bounded by identity, not by location: the candidate must BE that package,
|
|
948
|
+
// resolved from the profile's own module search, and must declare a patch.
|
|
949
|
+
// A profile that lists it in `dsh.profile.bundles` gets it as an ordinary
|
|
950
|
+
// bundle layer instead — composing both would add every row twice.
|
|
951
|
+
if (!declaredBundles.includes(DESKTOP_SHELL_PLUGIN)) {
|
|
952
|
+
const directory = resolvePackageDir(join(profileDirectory, 'package.json'), DESKTOP_SHELL_PLUGIN);
|
|
953
|
+
if (directory !== null) {
|
|
954
|
+
return overlayFromDirectory(directory, manifest => manifest.name === DESKTOP_SHELL_PLUGIN);
|
|
963
955
|
}
|
|
964
|
-
return { label, kind: 'bundle', patches: parsed.flatMap(patches => patches), parseError: null };
|
|
965
956
|
}
|
|
966
957
|
return null;
|
|
967
958
|
}
|
|
959
|
+
/** The official Desktop shell plugin, whose patch the launcher applies by hand (#807). */
|
|
960
|
+
const DESKTOP_SHELL_PLUGIN = 'dsh-plugin-desktop';
|
|
961
|
+
/**
|
|
962
|
+
* The overlay one candidate directory declares, or null when it declares none.
|
|
963
|
+
*
|
|
964
|
+
* `accept` is the caller's bound on what may stand in for the installation;
|
|
965
|
+
* resolution and parsing are shared, because a second parsing path would be a
|
|
966
|
+
* second set of answers about the same file.
|
|
967
|
+
*/
|
|
968
|
+
function overlayFromDirectory(directory, accept) {
|
|
969
|
+
let manifest;
|
|
970
|
+
try {
|
|
971
|
+
manifest = JSON.parse(readFileSync(join(directory, 'package.json'), 'utf8'));
|
|
972
|
+
}
|
|
973
|
+
catch {
|
|
974
|
+
return null;
|
|
975
|
+
}
|
|
976
|
+
const declared = manifest.dsh?.bundle?.patch;
|
|
977
|
+
const declaredList = typeof declared === 'string'
|
|
978
|
+
? [declared]
|
|
979
|
+
: Array.isArray(declared)
|
|
980
|
+
? declared.filter((relative) => typeof relative === 'string')
|
|
981
|
+
: [];
|
|
982
|
+
// A bundle patch alone does not make a directory an installation: ANY package
|
|
983
|
+
// can declare one — this repository does, and so does every plugin repo.
|
|
984
|
+
// Without the caller's bound the ancestor walk accepted the nearest such
|
|
985
|
+
// project above the install directory and composed its rows as if they were
|
|
986
|
+
// the installation's own, which invents rows and can mask a real orphan
|
|
987
|
+
// warning (#749 review).
|
|
988
|
+
if (declaredList.length === 0 || !accept(manifest))
|
|
989
|
+
return null;
|
|
990
|
+
const label = typeof manifest.name === 'string' && manifest.name !== '' ? manifest.name : 'install-overlay';
|
|
991
|
+
const paths = declaredList.map(relative => join(directory, relative));
|
|
992
|
+
if (paths.some(path => !existsSync(path))) {
|
|
993
|
+
return { label, kind: 'bundle', patches: [], parseError: 'declared patch is missing' };
|
|
994
|
+
}
|
|
995
|
+
const parsed = paths.map(path => parsePatchFile(path));
|
|
996
|
+
if (parsed.some(patches => patches === null)) {
|
|
997
|
+
return { label, kind: 'bundle', patches: [], parseError: 'patch file is not a valid entry list' };
|
|
998
|
+
}
|
|
999
|
+
return { label, kind: 'bundle', patches: parsed.flatMap(patches => patches), parseError: null };
|
|
1000
|
+
}
|
|
968
1001
|
/**
|
|
969
1002
|
* Which directories in `node_modules` are leftovers (#663).
|
|
970
1003
|
*
|
|
@@ -1080,7 +1113,7 @@ export function analyzeProfile(profileDirectory, options = {}) {
|
|
|
1080
1113
|
// The installation's own overlay rides directly behind the bundle the
|
|
1081
1114
|
// Desktop launcher keys off, exactly where the launcher splices it — see
|
|
1082
1115
|
// installOverlayLayer.
|
|
1083
|
-
const installOverlay = installOverlayLayer(dshInstall);
|
|
1116
|
+
const installOverlay = installOverlayLayer(dshInstall, profileDirectory, bundleNames);
|
|
1084
1117
|
if (installOverlay !== null) {
|
|
1085
1118
|
const overlayAfter = bundleLayers.findIndex(layer => layer.label === '@deepseek-ai/dsh-web-app');
|
|
1086
1119
|
if (overlayAfter < 0)
|
package/lib/routes.js
CHANGED
|
@@ -224,6 +224,28 @@ function blockedBuilds(result) {
|
|
|
224
224
|
printedBuildKeys.set(pending, parsePrepareKey(result.stdout, result.stderr));
|
|
225
225
|
return [pending];
|
|
226
226
|
}
|
|
227
|
+
/**
|
|
228
|
+
* Whether a FAILED run failed BECAUSE pnpm skipped a build script (#754).
|
|
229
|
+
*
|
|
230
|
+
* `blockedBuilds` answers a different question — "did pnpm skip anything" —
|
|
231
|
+
* and pnpm reports skipped builds for transitive dependencies on almost any
|
|
232
|
+
* run. So a failure with an unrelated cause (a peer-resolution refusal, a 404,
|
|
233
|
+
* an OOM) still came back carrying the approve-and-retry banner, and pressing
|
|
234
|
+
* it re-ran the same command to the same failure. The reporter's case is the
|
|
235
|
+
* sharp end: the skipped package was a transitive `@types/*` that is not in
|
|
236
|
+
* the profile and not in the catalog, so approval had nothing to approve and
|
|
237
|
+
* the button answered `no installed packages given` — while the real cause
|
|
238
|
+
* (`generation peer validation failed`) was buried under it.
|
|
239
|
+
*
|
|
240
|
+
* The classifier already decides this from pnpm's own output, so ask it rather
|
|
241
|
+
* than pattern-matching a second time. `git-prepare-not-allowed` is the same
|
|
242
|
+
* refusal for a git dependency, which is the other code the approval path can
|
|
243
|
+
* clear.
|
|
244
|
+
*/
|
|
245
|
+
function failedOnBlockedBuilds(result) {
|
|
246
|
+
const code = classifyPnpmFailure(`${result.stderr}\n${result.stdout}`, result.exitCode)?.code;
|
|
247
|
+
return code === 'ignored-builds' || code === 'git-prepare-not-allowed';
|
|
248
|
+
}
|
|
227
249
|
/**
|
|
228
250
|
* Register the market's HTTP routes.
|
|
229
251
|
* @param host - Acquired webServer + shell services.
|
|
@@ -4526,7 +4548,10 @@ export function mountMarketRoutes(host, config, commandRuntime, agentsLookup, ho
|
|
|
4526
4548
|
// build-required dep fails the add with ERR_PNPM_IGNORED_BUILDS.
|
|
4527
4549
|
// Reporting the blocked packages here gives the client the same
|
|
4528
4550
|
// approve-and-retry banner the install flow has had since #6.
|
|
4529
|
-
|
|
4551
|
+
// Same rule as the install route (#754): a failure that merely
|
|
4552
|
+
// MENTIONS a skipped build is not a failure ABOUT one, and offering
|
|
4553
|
+
// to approve it sends the user to press a button that cannot help.
|
|
4554
|
+
const ignoredBuilds = ok || cancelled || !failedOnBlockedBuilds(result) ? undefined : blockedBuilds(result);
|
|
4530
4555
|
if (ok)
|
|
4531
4556
|
clearBrokenPlugin(name);
|
|
4532
4557
|
// A package still installed but no longer in dsh.profile.bundles
|
|
@@ -5884,7 +5909,10 @@ export function mountMarketRoutes(host, config, commandRuntime, agentsLookup, ho
|
|
|
5884
5909
|
if (ok)
|
|
5885
5910
|
clearBrokenPlugin(entry.name);
|
|
5886
5911
|
logEvent(ok || cancelled ? 'info' : 'error', 'install', `${target} exit=${String(result.exitCode)}${result.timedOut ? ' TIMEOUT' : ''}${cancelled ? ' CANCELLED' : ''}${ok ? ` hot=${String(hot)}` : cancelled ? '' : ` err=${failureDetail(result)}`}`);
|
|
5887
|
-
|
|
5912
|
+
// On success a skipped build is a notice (#6); after a FAILURE the
|
|
5913
|
+
// list is what offers the approve-and-retry banner, so it is sent
|
|
5914
|
+
// only when the blocked build IS why the run failed (#754).
|
|
5915
|
+
const ignoredBuilds = ok || cancelled || failedOnBlockedBuilds(result) ? blockedBuilds(result) : undefined;
|
|
5888
5916
|
sendJson(response, ok || cancelled ? 200 : result.busy === true ? 409 : 502, {
|
|
5889
5917
|
ok,
|
|
5890
5918
|
cancelled: cancelled || undefined,
|
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.11",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
7
7
|
"types": "lib/types/index.d.ts",
|
package/src/check.ts
CHANGED
|
@@ -1145,45 +1145,88 @@ export function buildBundleLayers(
|
|
|
1145
1145
|
* @param dshInstall - install directory the analysis located, or null.
|
|
1146
1146
|
* @returns the overlay layer, or null when this installation declares none.
|
|
1147
1147
|
*/
|
|
1148
|
-
function installOverlayLayer(
|
|
1148
|
+
function installOverlayLayer(
|
|
1149
|
+
dshInstall: string | null,
|
|
1150
|
+
profileDirectory: string,
|
|
1151
|
+
declaredBundles: readonly string[],
|
|
1152
|
+
): LayerInput | null {
|
|
1149
1153
|
for (const directory of desktopApplicationRoots(dshInstall)) {
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
const
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
return { label, kind: 'bundle', patches: [], parseError: 'declared patch is missing' }
|
|
1177
|
-
}
|
|
1178
|
-
const parsed = paths.map(path => parsePatchFile(path))
|
|
1179
|
-
if (parsed.some(patches => patches === null)) {
|
|
1180
|
-
return { label, kind: 'bundle', patches: [], parseError: 'patch file is not a valid entry list' }
|
|
1154
|
+
// A DSH installation ships the in-box web bundle, and the launcher splices
|
|
1155
|
+
// this very overlay directly behind that bundle's layer — where it is
|
|
1156
|
+
// absent, the launcher applies no overlay either, so composing one here
|
|
1157
|
+
// would describe a composition nobody runs (#749 review).
|
|
1158
|
+
const layer = overlayFromDirectory(directory, manifest =>
|
|
1159
|
+
readNodeModulesVersion(directory, '@deepseek-ai/dsh-web-app') !== null)
|
|
1160
|
+
if (layer !== null) return layer
|
|
1161
|
+
}
|
|
1162
|
+
// The official Desktop shell plugin's own patch (#807). On a build that packs
|
|
1163
|
+
// the whole runtime into one app.asar, no application-root candidate declares
|
|
1164
|
+
// it: the asar's root is `@deepseek-ai/dsh-desktop` and the nested
|
|
1165
|
+
// `app.asar/dsh` is `@deepseek-ai/dsh-desktop-runtime`, neither with a
|
|
1166
|
+
// `dsh.bundle.patch`, while the file that really supplies the shell's rows
|
|
1167
|
+
// (`desktop-shell`, `desktop-notifications`, …) is this package's own
|
|
1168
|
+
// `cordis.patch.yml`. Without it every user-patch row aimed at a shell row is
|
|
1169
|
+
// reported as an orphan, and a user who believes the warning deletes rows
|
|
1170
|
+
// that carry the window material and the notification preferences.
|
|
1171
|
+
//
|
|
1172
|
+
// Bounded by identity, not by location: the candidate must BE that package,
|
|
1173
|
+
// resolved from the profile's own module search, and must declare a patch.
|
|
1174
|
+
// A profile that lists it in `dsh.profile.bundles` gets it as an ordinary
|
|
1175
|
+
// bundle layer instead — composing both would add every row twice.
|
|
1176
|
+
if (!declaredBundles.includes(DESKTOP_SHELL_PLUGIN)) {
|
|
1177
|
+
const directory = resolvePackageDir(join(profileDirectory, 'package.json'), DESKTOP_SHELL_PLUGIN)
|
|
1178
|
+
if (directory !== null) {
|
|
1179
|
+
return overlayFromDirectory(directory, manifest => manifest.name === DESKTOP_SHELL_PLUGIN)
|
|
1181
1180
|
}
|
|
1182
|
-
return { label, kind: 'bundle', patches: parsed.flatMap(patches => patches), parseError: null }
|
|
1183
1181
|
}
|
|
1184
1182
|
return null
|
|
1185
1183
|
}
|
|
1186
1184
|
|
|
1185
|
+
/** The official Desktop shell plugin, whose patch the launcher applies by hand (#807). */
|
|
1186
|
+
const DESKTOP_SHELL_PLUGIN = 'dsh-plugin-desktop'
|
|
1187
|
+
|
|
1188
|
+
/**
|
|
1189
|
+
* The overlay one candidate directory declares, or null when it declares none.
|
|
1190
|
+
*
|
|
1191
|
+
* `accept` is the caller's bound on what may stand in for the installation;
|
|
1192
|
+
* resolution and parsing are shared, because a second parsing path would be a
|
|
1193
|
+
* second set of answers about the same file.
|
|
1194
|
+
*/
|
|
1195
|
+
function overlayFromDirectory(
|
|
1196
|
+
directory: string,
|
|
1197
|
+
accept: (manifest: { name?: unknown }) => boolean,
|
|
1198
|
+
): LayerInput | null {
|
|
1199
|
+
let manifest: { name?: unknown; dsh?: { bundle?: { patch?: unknown } } }
|
|
1200
|
+
try {
|
|
1201
|
+
manifest = JSON.parse(readFileSync(join(directory, 'package.json'), 'utf8')) as typeof manifest
|
|
1202
|
+
} catch {
|
|
1203
|
+
return null
|
|
1204
|
+
}
|
|
1205
|
+
const declared = manifest.dsh?.bundle?.patch
|
|
1206
|
+
const declaredList = typeof declared === 'string'
|
|
1207
|
+
? [declared]
|
|
1208
|
+
: Array.isArray(declared)
|
|
1209
|
+
? declared.filter((relative): relative is string => typeof relative === 'string')
|
|
1210
|
+
: []
|
|
1211
|
+
// A bundle patch alone does not make a directory an installation: ANY package
|
|
1212
|
+
// can declare one — this repository does, and so does every plugin repo.
|
|
1213
|
+
// Without the caller's bound the ancestor walk accepted the nearest such
|
|
1214
|
+
// project above the install directory and composed its rows as if they were
|
|
1215
|
+
// the installation's own, which invents rows and can mask a real orphan
|
|
1216
|
+
// warning (#749 review).
|
|
1217
|
+
if (declaredList.length === 0 || !accept(manifest)) return null
|
|
1218
|
+
const label = typeof manifest.name === 'string' && manifest.name !== '' ? manifest.name : 'install-overlay'
|
|
1219
|
+
const paths = declaredList.map(relative => join(directory, relative))
|
|
1220
|
+
if (paths.some(path => !existsSync(path))) {
|
|
1221
|
+
return { label, kind: 'bundle', patches: [], parseError: 'declared patch is missing' }
|
|
1222
|
+
}
|
|
1223
|
+
const parsed = paths.map(path => parsePatchFile(path))
|
|
1224
|
+
if (parsed.some(patches => patches === null)) {
|
|
1225
|
+
return { label, kind: 'bundle', patches: [], parseError: 'patch file is not a valid entry list' }
|
|
1226
|
+
}
|
|
1227
|
+
return { label, kind: 'bundle', patches: parsed.flatMap(patches => patches), parseError: null }
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1187
1230
|
/**
|
|
1188
1231
|
* Which directories in `node_modules` are leftovers (#663).
|
|
1189
1232
|
*
|
|
@@ -1299,7 +1342,7 @@ export function analyzeProfile(profileDirectory: string, options: CheckOptions =
|
|
|
1299
1342
|
// The installation's own overlay rides directly behind the bundle the
|
|
1300
1343
|
// Desktop launcher keys off, exactly where the launcher splices it — see
|
|
1301
1344
|
// installOverlayLayer.
|
|
1302
|
-
const installOverlay = installOverlayLayer(dshInstall)
|
|
1345
|
+
const installOverlay = installOverlayLayer(dshInstall, profileDirectory, bundleNames)
|
|
1303
1346
|
if (installOverlay !== null) {
|
|
1304
1347
|
const overlayAfter = bundleLayers.findIndex(layer => layer.label === '@deepseek-ai/dsh-web-app')
|
|
1305
1348
|
if (overlayAfter < 0) bundleLayers.push(installOverlay)
|
package/src/routes.ts
CHANGED
|
@@ -315,6 +315,29 @@ function blockedBuilds(result: { ignoredBuilds?: unknown; stdout: string; stderr
|
|
|
315
315
|
return [pending]
|
|
316
316
|
}
|
|
317
317
|
|
|
318
|
+
/**
|
|
319
|
+
* Whether a FAILED run failed BECAUSE pnpm skipped a build script (#754).
|
|
320
|
+
*
|
|
321
|
+
* `blockedBuilds` answers a different question — "did pnpm skip anything" —
|
|
322
|
+
* and pnpm reports skipped builds for transitive dependencies on almost any
|
|
323
|
+
* run. So a failure with an unrelated cause (a peer-resolution refusal, a 404,
|
|
324
|
+
* an OOM) still came back carrying the approve-and-retry banner, and pressing
|
|
325
|
+
* it re-ran the same command to the same failure. The reporter's case is the
|
|
326
|
+
* sharp end: the skipped package was a transitive `@types/*` that is not in
|
|
327
|
+
* the profile and not in the catalog, so approval had nothing to approve and
|
|
328
|
+
* the button answered `no installed packages given` — while the real cause
|
|
329
|
+
* (`generation peer validation failed`) was buried under it.
|
|
330
|
+
*
|
|
331
|
+
* The classifier already decides this from pnpm's own output, so ask it rather
|
|
332
|
+
* than pattern-matching a second time. `git-prepare-not-allowed` is the same
|
|
333
|
+
* refusal for a git dependency, which is the other code the approval path can
|
|
334
|
+
* clear.
|
|
335
|
+
*/
|
|
336
|
+
function failedOnBlockedBuilds(result: { exitCode: number | null; stdout: string; stderr: string }): boolean {
|
|
337
|
+
const code = classifyPnpmFailure(`${result.stderr}\n${result.stdout}`, result.exitCode)?.code
|
|
338
|
+
return code === 'ignored-builds' || code === 'git-prepare-not-allowed'
|
|
339
|
+
}
|
|
340
|
+
|
|
318
341
|
/**
|
|
319
342
|
* Register the market's HTTP routes.
|
|
320
343
|
* @param host - Acquired webServer + shell services.
|
|
@@ -4709,7 +4732,10 @@ sendJson(response, 200, { updates })
|
|
|
4709
4732
|
// build-required dep fails the add with ERR_PNPM_IGNORED_BUILDS.
|
|
4710
4733
|
// Reporting the blocked packages here gives the client the same
|
|
4711
4734
|
// approve-and-retry banner the install flow has had since #6.
|
|
4712
|
-
|
|
4735
|
+
// Same rule as the install route (#754): a failure that merely
|
|
4736
|
+
// MENTIONS a skipped build is not a failure ABOUT one, and offering
|
|
4737
|
+
// to approve it sends the user to press a button that cannot help.
|
|
4738
|
+
const ignoredBuilds = ok || cancelled || !failedOnBlockedBuilds(result) ? undefined : blockedBuilds(result)
|
|
4713
4739
|
if (ok) clearBrokenPlugin(name)
|
|
4714
4740
|
// A package still installed but no longer in dsh.profile.bundles
|
|
4715
4741
|
// after this run stops loading and says nothing (#720). The market
|
|
@@ -6068,7 +6094,10 @@ sendJson(response, 200, { updates })
|
|
|
6068
6094
|
if (ok) clearBrokenPlugin(entry.name)
|
|
6069
6095
|
logEvent(ok || cancelled ? 'info' : 'error', 'install',
|
|
6070
6096
|
`${target} exit=${String(result.exitCode)}${result.timedOut ? ' TIMEOUT' : ''}${cancelled ? ' CANCELLED' : ''}${ok ? ` hot=${String(hot)}` : cancelled ? '' : ` err=${failureDetail(result)}`}`)
|
|
6071
|
-
|
|
6097
|
+
// On success a skipped build is a notice (#6); after a FAILURE the
|
|
6098
|
+
// list is what offers the approve-and-retry banner, so it is sent
|
|
6099
|
+
// only when the blocked build IS why the run failed (#754).
|
|
6100
|
+
const ignoredBuilds = ok || cancelled || failedOnBlockedBuilds(result) ? blockedBuilds(result) : undefined
|
|
6072
6101
|
sendJson(response, ok || cancelled ? 200 : result.busy === true ? 409 : 502, {
|
|
6073
6102
|
ok,
|
|
6074
6103
|
cancelled: cancelled || undefined,
|