@dsh-workbench/core 0.1.9 → 0.1.10
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.js +529 -61
- package/dist/client/client.body.js +529 -61
- package/dist/client/index.js +530 -62
- package/dist/host/index.js +212 -100
- package/dist/types/app/client.d.ts +134 -6
- package/dist/types/app/layouts/rightbar/board-plan.d.ts +2 -0
- package/dist/types/app/layouts/sidebar/ProjectSwitcher.d.ts +2 -2
- package/dist/types/app/layouts/sidebar/Sidebar.d.ts +1 -1
- package/dist/types/app/layouts/sidebar/WorkspaceRenameDialog.d.ts +8 -0
- package/dist/types/app/layouts/sidebar/WorkspaceRowAction.d.ts +7 -0
- package/dist/types/app/layouts/sidebar/WorkspaceRowLabel.d.ts +8 -0
- package/dist/types/app/layouts/sidebar/WorkspaceSearchField.d.ts +9 -0
- package/dist/types/app/layouts/sidebar/__tests__/workspace-name.test.d.ts +1 -0
- package/dist/types/app/layouts/sidebar/workspace-items.d.ts +11 -0
- package/dist/types/app/layouts/sidebar/workspace-name.d.ts +16 -0
- package/dist/types/app/units/__tests__/registry.test.d.ts +1 -0
- package/dist/types/app/units/fixture-unit-mock.d.ts +3 -1
- package/dist/types/shared/api/host/mount-units.d.ts +13 -6
- package/dist/types/shared/hooks/mock-mode.d.ts +1 -0
- package/package.json +2 -2
package/dist/host/index.js
CHANGED
|
@@ -3788,16 +3788,43 @@ function withRunsRoute(result, unit) {
|
|
|
3788
3788
|
}
|
|
3789
3789
|
};
|
|
3790
3790
|
}
|
|
3791
|
-
function
|
|
3791
|
+
function failureReasonOf(error) {
|
|
3792
|
+
if (error instanceof Error) return error.message;
|
|
3793
|
+
return typeof error === "string" ? error : String(error);
|
|
3794
|
+
}
|
|
3795
|
+
function fail(ledger, item, reason) {
|
|
3796
|
+
ledger.failed.add(item);
|
|
3797
|
+
ledger.failures.push({
|
|
3798
|
+
id: item.face.manifest.id,
|
|
3799
|
+
reason
|
|
3800
|
+
});
|
|
3801
|
+
}
|
|
3802
|
+
function collectRoutes(mounted, ledger) {
|
|
3792
3803
|
const routes = {};
|
|
3793
3804
|
const owner = /* @__PURE__ */ new Map();
|
|
3794
3805
|
const routesOfUnit = /* @__PURE__ */ new Map();
|
|
3795
3806
|
for (const item of mounted) {
|
|
3807
|
+
if (ledger.failed.has(item)) continue;
|
|
3796
3808
|
const unit = item.face.manifest.id;
|
|
3809
|
+
const accepted = [];
|
|
3810
|
+
let problem;
|
|
3797
3811
|
for (const [key, handler] of Object.entries(item.result.routes)) {
|
|
3798
|
-
if (key !== unit && !key.startsWith(`${unit}/`))
|
|
3812
|
+
if (key !== unit && !key.startsWith(`${unit}/`)) {
|
|
3813
|
+
problem = `路由名要住在自己那一格的命名空间里(${unit} 或 ${unit}/…):${key} 不属于 ${unit} —— 装 / 升 / 卸时点名不到它,那个模块的数据会停在旧值`;
|
|
3814
|
+
break;
|
|
3815
|
+
}
|
|
3799
3816
|
const previous = owner.get(key);
|
|
3800
|
-
if (previous !== void 0)
|
|
3817
|
+
if (previous !== void 0) {
|
|
3818
|
+
problem = `路由名冲突:${key} 由套件 ${previous} 与 ${unit} 同时声明`;
|
|
3819
|
+
break;
|
|
3820
|
+
}
|
|
3821
|
+
accepted.push([key, handler]);
|
|
3822
|
+
}
|
|
3823
|
+
if (problem !== void 0) {
|
|
3824
|
+
fail(ledger, item, problem);
|
|
3825
|
+
continue;
|
|
3826
|
+
}
|
|
3827
|
+
for (const [key, handler] of accepted) {
|
|
3801
3828
|
owner.set(key, unit);
|
|
3802
3829
|
routes[key] = handler;
|
|
3803
3830
|
const own = routesOfUnit.get(unit);
|
|
@@ -3811,45 +3838,64 @@ function collectRoutes(mounted) {
|
|
|
3811
3838
|
routesOfUnit
|
|
3812
3839
|
};
|
|
3813
3840
|
}
|
|
3814
|
-
function
|
|
3815
|
-
const providers = mounted.filter((item) => item.result.gate !== void 0);
|
|
3816
|
-
if (providers.length > 1) throw new Error(`启停闸门只能有一个提供者,现在是:${providers.map((item) => item.face.manifest.id).join("、")}`);
|
|
3817
|
-
return providers[0]?.result.gate;
|
|
3818
|
-
}
|
|
3819
|
-
function pickProvision(mounted) {
|
|
3820
|
-
const providers = mounted.filter((item) => item.result.provision !== void 0);
|
|
3821
|
-
if (providers.length > 1) throw new Error(`机器供给只能有一个提供者,现在是:${providers.map((item) => item.face.manifest.id).join("、")}`);
|
|
3822
|
-
return providers[0]?.result.provision;
|
|
3823
|
-
}
|
|
3824
|
-
function collectPrefs(mounted) {
|
|
3841
|
+
function collectNamed(mounted, ledger, pickMany, label) {
|
|
3825
3842
|
const owner = /* @__PURE__ */ new Map();
|
|
3826
|
-
const
|
|
3843
|
+
const out = [];
|
|
3827
3844
|
for (const item of mounted) {
|
|
3828
|
-
|
|
3829
|
-
|
|
3830
|
-
const
|
|
3831
|
-
if (
|
|
3832
|
-
owner.
|
|
3833
|
-
|
|
3834
|
-
|
|
3835
|
-
|
|
3836
|
-
}
|
|
3845
|
+
if (ledger.failed.has(item)) continue;
|
|
3846
|
+
const unit = item.face.manifest.id;
|
|
3847
|
+
const entries = pickMany(item);
|
|
3848
|
+
if (entries.length === 0) continue;
|
|
3849
|
+
const clash = entries.find((entry) => owner.has(entry.resource));
|
|
3850
|
+
if (clash !== void 0) {
|
|
3851
|
+
fail(ledger, item, `${label}名冲突:${clash.resource} 由套件 ${owner.get(clash.resource)} 与 ${unit} 同时声明`);
|
|
3852
|
+
continue;
|
|
3853
|
+
}
|
|
3854
|
+
for (const entry of entries) {
|
|
3855
|
+
owner.set(entry.resource, unit);
|
|
3856
|
+
out.push({
|
|
3857
|
+
...entry,
|
|
3858
|
+
unit
|
|
3859
|
+
});
|
|
3860
|
+
}
|
|
3837
3861
|
}
|
|
3838
|
-
return
|
|
3862
|
+
return out;
|
|
3839
3863
|
}
|
|
3840
|
-
function
|
|
3864
|
+
function collectContextRenderers(mounted, ledger) {
|
|
3865
|
+
const table = /* @__PURE__ */ new Map();
|
|
3841
3866
|
const owner = /* @__PURE__ */ new Map();
|
|
3842
|
-
const
|
|
3843
|
-
|
|
3844
|
-
const
|
|
3845
|
-
|
|
3846
|
-
|
|
3847
|
-
|
|
3848
|
-
|
|
3849
|
-
|
|
3850
|
-
|
|
3867
|
+
for (const item of mounted) {
|
|
3868
|
+
if (ledger.failed.has(item)) continue;
|
|
3869
|
+
const unit = item.face.manifest.id;
|
|
3870
|
+
const context = item.result.context;
|
|
3871
|
+
if (context === void 0) continue;
|
|
3872
|
+
const clash = context.kinds.find((kind) => owner.has(kind));
|
|
3873
|
+
if (clash !== void 0) {
|
|
3874
|
+
fail(ledger, item, `对话引用的 kind 冲突:${clash} 由套件 ${owner.get(clash)} 与 ${unit} 同时认领`);
|
|
3875
|
+
continue;
|
|
3876
|
+
}
|
|
3877
|
+
for (const kind of context.kinds) {
|
|
3878
|
+
owner.set(kind, unit);
|
|
3879
|
+
table.set(kind, (ref) => context.render(ref));
|
|
3880
|
+
}
|
|
3881
|
+
}
|
|
3882
|
+
return table;
|
|
3883
|
+
}
|
|
3884
|
+
function pickProvider(mounted, ledger, pick, label) {
|
|
3885
|
+
let chosen;
|
|
3886
|
+
let chosenBy;
|
|
3887
|
+
for (const item of mounted) {
|
|
3888
|
+
if (ledger.failed.has(item)) continue;
|
|
3889
|
+
const value = pick(item);
|
|
3890
|
+
if (value === void 0) continue;
|
|
3891
|
+
if (chosen === void 0) {
|
|
3892
|
+
chosen = value;
|
|
3893
|
+
chosenBy = item.face.manifest.id;
|
|
3894
|
+
continue;
|
|
3895
|
+
}
|
|
3896
|
+
fail(ledger, item, `${label}只能有一个提供者,现在是:${chosenBy}、${item.face.manifest.id}`);
|
|
3851
3897
|
}
|
|
3852
|
-
return
|
|
3898
|
+
return chosen;
|
|
3853
3899
|
}
|
|
3854
3900
|
function collectWarmReads(mounted) {
|
|
3855
3901
|
const declarations = mounted.map((item) => item.result.warmReads).filter((declare) => declare !== void 0);
|
|
@@ -3865,26 +3911,15 @@ function collectWarmReads(mounted) {
|
|
|
3865
3911
|
return reads;
|
|
3866
3912
|
};
|
|
3867
3913
|
}
|
|
3868
|
-
function collectContextRenderers(mounted) {
|
|
3869
|
-
const table = /* @__PURE__ */ new Map();
|
|
3870
|
-
const owner = /* @__PURE__ */ new Map();
|
|
3871
|
-
for (const item of mounted) {
|
|
3872
|
-
const context = item.result.context;
|
|
3873
|
-
if (context === void 0) continue;
|
|
3874
|
-
for (const kind of context.kinds) {
|
|
3875
|
-
const previous = owner.get(kind);
|
|
3876
|
-
if (previous !== void 0) throw new Error(`对话引用的 kind 冲突:${kind} 由套件 ${previous} 与 ${item.face.manifest.id} 同时认领`);
|
|
3877
|
-
owner.set(kind, item.face.manifest.id);
|
|
3878
|
-
table.set(kind, (ref) => context.render(ref));
|
|
3879
|
-
}
|
|
3880
|
-
}
|
|
3881
|
-
return table;
|
|
3882
|
-
}
|
|
3883
3914
|
function mountUnits(faces, deps) {
|
|
3884
3915
|
const store = deps.store ?? createWorkspaceStore({ root: null });
|
|
3885
3916
|
const mounted = [];
|
|
3886
3917
|
const skipped = [];
|
|
3887
|
-
const longTaskDisposers =
|
|
3918
|
+
const longTaskDisposers = /* @__PURE__ */ new Map();
|
|
3919
|
+
const ledger = {
|
|
3920
|
+
failed: /* @__PURE__ */ new Set(),
|
|
3921
|
+
failures: []
|
|
3922
|
+
};
|
|
3888
3923
|
for (const face of faces) {
|
|
3889
3924
|
const readiness = unitReadiness(face.manifest, (dep) => deps.ctx.get(dep));
|
|
3890
3925
|
if (!readiness.canMount) {
|
|
@@ -3900,48 +3935,71 @@ function mountUnits(faces, deps) {
|
|
|
3900
3935
|
unit,
|
|
3901
3936
|
bump: deps.longTasks.bump
|
|
3902
3937
|
});
|
|
3903
|
-
|
|
3904
|
-
|
|
3905
|
-
|
|
3906
|
-
|
|
3907
|
-
|
|
3908
|
-
|
|
3909
|
-
|
|
3910
|
-
|
|
3911
|
-
|
|
3912
|
-
|
|
3913
|
-
|
|
3914
|
-
|
|
3938
|
+
let result;
|
|
3939
|
+
try {
|
|
3940
|
+
result = face.mount({
|
|
3941
|
+
ctx: deps.ctx,
|
|
3942
|
+
logger: deps.logger,
|
|
3943
|
+
manifests: deps.manifests,
|
|
3944
|
+
...deps.opencliCommand === void 0 ? {} : { opencliCommand: deps.opencliCommand },
|
|
3945
|
+
...deps.probe === void 0 ? {} : { probe: deps.probe },
|
|
3946
|
+
...deps.values === void 0 ? {} : { values: deps.values },
|
|
3947
|
+
...longTasks === void 0 ? {} : { longTasks: longTasks.host },
|
|
3948
|
+
store
|
|
3949
|
+
});
|
|
3950
|
+
} catch (error) {
|
|
3951
|
+
longTasks?.dispose();
|
|
3952
|
+
ledger.failures.push({
|
|
3953
|
+
id: unit,
|
|
3954
|
+
reason: failureReasonOf(error)
|
|
3955
|
+
});
|
|
3956
|
+
continue;
|
|
3957
|
+
}
|
|
3958
|
+
const item = {
|
|
3915
3959
|
face,
|
|
3916
3960
|
readiness,
|
|
3917
3961
|
result: withRunsRoute(result, unit)
|
|
3918
|
-
}
|
|
3962
|
+
};
|
|
3963
|
+
mounted.push(item);
|
|
3964
|
+
if (longTasks !== void 0) longTaskDisposers.set(item, longTasks.dispose);
|
|
3919
3965
|
}
|
|
3920
|
-
const collected = collectRoutes(mounted);
|
|
3921
|
-
const prefs =
|
|
3922
|
-
const actions =
|
|
3966
|
+
const collected = collectRoutes(mounted, ledger);
|
|
3967
|
+
const prefs = collectNamed(mounted, ledger, (item) => item.result.prefs === void 0 ? [] : [item.result.prefs], "偏好资源");
|
|
3968
|
+
const actions = collectNamed(mounted, ledger, (item) => item.result.actions ?? [], "动作资源");
|
|
3923
3969
|
const owners = new Map(collected.owners);
|
|
3924
3970
|
for (const entry of [...prefs, ...actions]) owners.set(entry.resource, entry.unit);
|
|
3925
3971
|
const factsOf = /* @__PURE__ */ new Map();
|
|
3926
3972
|
for (const item of mounted) {
|
|
3973
|
+
if (ledger.failed.has(item)) continue;
|
|
3927
3974
|
const declare = item.result.factsOf;
|
|
3928
3975
|
if (declare !== void 0) factsOf.set(item.face.manifest.id, declare);
|
|
3929
3976
|
}
|
|
3977
|
+
const gate = pickProvider(mounted, ledger, (item) => item.result.gate, "启停闸门");
|
|
3978
|
+
const provision = pickProvider(mounted, ledger, (item) => item.result.provision, "机器供给");
|
|
3979
|
+
const contextRenderers = collectContextRenderers(mounted, ledger);
|
|
3980
|
+
const alive = mounted.filter((item) => !ledger.failed.has(item));
|
|
3981
|
+
for (const item of mounted) {
|
|
3982
|
+
if (!ledger.failed.has(item)) continue;
|
|
3983
|
+
longTaskDisposers.get(item)?.();
|
|
3984
|
+
longTaskDisposers.delete(item);
|
|
3985
|
+
}
|
|
3930
3986
|
return {
|
|
3931
|
-
mounted,
|
|
3987
|
+
mounted: alive,
|
|
3932
3988
|
routes: collected.routes,
|
|
3933
3989
|
owners,
|
|
3934
3990
|
routesOfUnit: collected.routesOfUnit,
|
|
3935
3991
|
factsOf,
|
|
3936
|
-
gate
|
|
3992
|
+
gate,
|
|
3937
3993
|
prefs,
|
|
3938
3994
|
actions,
|
|
3939
|
-
provision
|
|
3940
|
-
contextRenderers
|
|
3995
|
+
provision,
|
|
3996
|
+
contextRenderers,
|
|
3941
3997
|
skipped,
|
|
3942
|
-
|
|
3998
|
+
failed: ledger.failures,
|
|
3999
|
+
warmReads: collectWarmReads(alive),
|
|
3943
4000
|
disposeLongTasks: () => {
|
|
3944
|
-
for (const dispose of longTaskDisposers.
|
|
4001
|
+
for (const dispose of [...longTaskDisposers.values()]) dispose();
|
|
4002
|
+
longTaskDisposers.clear();
|
|
3945
4003
|
}
|
|
3946
4004
|
};
|
|
3947
4005
|
}
|
|
@@ -4116,6 +4174,7 @@ function apply(ctx) {
|
|
|
4116
4174
|
logger: ctx.logger
|
|
4117
4175
|
});
|
|
4118
4176
|
const mounted = /* @__PURE__ */ new Map();
|
|
4177
|
+
const mountFailures = /* @__PURE__ */ new Map();
|
|
4119
4178
|
const factsOfMap = /* @__PURE__ */ new Map();
|
|
4120
4179
|
const routesOfUnitMap = /* @__PURE__ */ new Map();
|
|
4121
4180
|
const ownersMap = /* @__PURE__ */ new Map();
|
|
@@ -4127,6 +4186,7 @@ function apply(ctx) {
|
|
|
4127
4186
|
const item = mounted.get(id);
|
|
4128
4187
|
if (item === void 0) return;
|
|
4129
4188
|
mounted.delete(id);
|
|
4189
|
+
mountFailures.delete(id);
|
|
4130
4190
|
for (const dispose of item.toolDisposers) dispose?.();
|
|
4131
4191
|
item.gateOff?.();
|
|
4132
4192
|
item.plan.disposeLongTasks();
|
|
@@ -4137,34 +4197,72 @@ function apply(ctx) {
|
|
|
4137
4197
|
for (const resource of item.plan.owners.keys()) ownersMap.delete(resource);
|
|
4138
4198
|
}
|
|
4139
4199
|
function mountUnit(face) {
|
|
4140
|
-
const
|
|
4141
|
-
|
|
4142
|
-
|
|
4143
|
-
|
|
4144
|
-
|
|
4145
|
-
|
|
4146
|
-
|
|
4147
|
-
|
|
4148
|
-
|
|
4149
|
-
|
|
4150
|
-
|
|
4151
|
-
|
|
4152
|
-
|
|
4200
|
+
const id = face.manifest.id;
|
|
4201
|
+
let one;
|
|
4202
|
+
try {
|
|
4203
|
+
one = mountUnits([face], {
|
|
4204
|
+
ctx,
|
|
4205
|
+
logger: ctx.logger,
|
|
4206
|
+
manifests: liveManifests,
|
|
4207
|
+
store,
|
|
4208
|
+
...opencliEnv === void 0 ? {} : { opencliCommand: opencliEnv },
|
|
4209
|
+
probe: (unit, options) => probeOne(unit, options?.force ?? false),
|
|
4210
|
+
values,
|
|
4211
|
+
longTasks: {
|
|
4212
|
+
scope: process.env["DSH_HOME"] ?? "",
|
|
4213
|
+
bump: (names) => facts.bump(names)
|
|
4214
|
+
}
|
|
4215
|
+
});
|
|
4216
|
+
} catch (error) {
|
|
4217
|
+
mountFailures.set(id, {
|
|
4218
|
+
reason: failureReasonOf(error),
|
|
4219
|
+
face
|
|
4220
|
+
});
|
|
4221
|
+
ctx.logger?.warn?.(`[dsh-workbench] ${id} 套件起不来(装配期):${failureReasonOf(error)}`);
|
|
4222
|
+
return;
|
|
4223
|
+
}
|
|
4153
4224
|
for (const item of one.skipped) ctx.logger?.warn?.(`[dsh-workbench] ${item.id} 套件缺硬依赖,跳过:${item.missing.join(", ")}`);
|
|
4225
|
+
for (const failure of one.failed) {
|
|
4226
|
+
mountFailures.set(failure.id, {
|
|
4227
|
+
reason: failure.reason,
|
|
4228
|
+
face
|
|
4229
|
+
});
|
|
4230
|
+
ctx.logger?.warn?.(`[dsh-workbench] ${failure.id} 套件起不来,已摘掉它这一份:${failure.reason}`);
|
|
4231
|
+
}
|
|
4154
4232
|
const slot = one.mounted[0];
|
|
4155
|
-
if (slot === void 0)
|
|
4233
|
+
if (slot === void 0) {
|
|
4234
|
+
one.disposeLongTasks();
|
|
4235
|
+
return;
|
|
4236
|
+
}
|
|
4156
4237
|
if (slot.readiness.missingSoft.length > 0) ctx.logger?.warn?.(`[dsh-workbench] ${face.manifest.id} 套件降级:缺 ${slot.readiness.missingSoft.join(", ")}`);
|
|
4157
|
-
|
|
4158
|
-
|
|
4159
|
-
|
|
4160
|
-
|
|
4161
|
-
|
|
4162
|
-
|
|
4163
|
-
|
|
4164
|
-
|
|
4165
|
-
|
|
4166
|
-
|
|
4167
|
-
|
|
4238
|
+
const added = [];
|
|
4239
|
+
try {
|
|
4240
|
+
Object.assign(routes, one.routes);
|
|
4241
|
+
added.push(...Object.keys(one.routes));
|
|
4242
|
+
for (const [kind, render] of one.contextRenderers) renderers.set(kind, render);
|
|
4243
|
+
for (const [unit, fn] of one.factsOf) factsOfMap.set(unit, fn);
|
|
4244
|
+
for (const [unit, list] of one.routesOfUnit) routesOfUnitMap.set(unit, list);
|
|
4245
|
+
for (const [resource, unit] of one.owners) ownersMap.set(resource, unit);
|
|
4246
|
+
mounted.set(face.manifest.id, {
|
|
4247
|
+
result: slot.result,
|
|
4248
|
+
plan: one,
|
|
4249
|
+
toolDisposers: slot.result.registerTools(),
|
|
4250
|
+
gateOff: one.gate?.subscribe(() => toolScope.reapply())
|
|
4251
|
+
});
|
|
4252
|
+
mountFailures.delete(id);
|
|
4253
|
+
} catch (error) {
|
|
4254
|
+
for (const route of added) delete routes[route];
|
|
4255
|
+
for (const kind of one.contextRenderers.keys()) renderers.delete(kind);
|
|
4256
|
+
for (const unit of one.factsOf.keys()) factsOfMap.delete(unit);
|
|
4257
|
+
for (const unit of one.routesOfUnit.keys()) routesOfUnitMap.delete(unit);
|
|
4258
|
+
for (const [resource, unit] of one.owners) if (ownersMap.get(resource) === unit) ownersMap.delete(resource);
|
|
4259
|
+
one.disposeLongTasks();
|
|
4260
|
+
mountFailures.set(id, {
|
|
4261
|
+
reason: failureReasonOf(error),
|
|
4262
|
+
face
|
|
4263
|
+
});
|
|
4264
|
+
ctx.logger?.warn?.(`[dsh-workbench] ${id} 套件起不来(注册期):${failureReasonOf(error)}`);
|
|
4265
|
+
}
|
|
4168
4266
|
}
|
|
4169
4267
|
function rebindPost() {
|
|
4170
4268
|
for (const dispose of undoPost.reverse()) dispose?.();
|
|
@@ -4187,7 +4285,13 @@ function apply(ctx) {
|
|
|
4187
4285
|
function sync() {
|
|
4188
4286
|
const present = new Set(units.all().map((face) => face.manifest.id));
|
|
4189
4287
|
for (const id of [...mounted.keys()]) if (!present.has(id)) unmountUnit(id);
|
|
4190
|
-
for (const
|
|
4288
|
+
for (const id of [...mountFailures.keys()]) if (!present.has(id)) mountFailures.delete(id);
|
|
4289
|
+
for (const face of units.all()) {
|
|
4290
|
+
if (mounted.has(face.manifest.id)) continue;
|
|
4291
|
+
const already = mountFailures.get(face.manifest.id);
|
|
4292
|
+
if (already !== void 0 && already.face === face) continue;
|
|
4293
|
+
mountUnit(face);
|
|
4294
|
+
}
|
|
4191
4295
|
rebindPost();
|
|
4192
4296
|
}
|
|
4193
4297
|
if (shell === void 0) ctx.logger?.warn?.("[dsh-workbench] 没有 shell 服务:需要执行缝的套件会降级");
|
|
@@ -4209,6 +4313,14 @@ function apply(ctx) {
|
|
|
4209
4313
|
...item,
|
|
4210
4314
|
released: releasedOf(item.unit)
|
|
4211
4315
|
})) };
|
|
4316
|
+
const failure = mountFailures.get(unit);
|
|
4317
|
+
if (failure !== void 0) return {
|
|
4318
|
+
unit,
|
|
4319
|
+
status: "failed",
|
|
4320
|
+
required: [],
|
|
4321
|
+
missing: [],
|
|
4322
|
+
detail: failure.reason
|
|
4323
|
+
};
|
|
4212
4324
|
return probeOne(unit, force);
|
|
4213
4325
|
});
|
|
4214
4326
|
}
|