@dsh-workbench/core 0.2.2 → 0.2.4
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 +77 -19
- package/dist/client/client.body.js +77 -19
- package/dist/client/index.js +77 -19
- package/dist/host/index.js +155 -47
- package/dist/types/app/client.d.ts +21 -3
- package/dist/types/app/layouts/sidebar/__tests__/workspace-groups.test.d.ts +1 -0
- package/dist/types/app/layouts/sidebar/workspace-groups.d.ts +13 -0
- package/dist/types/app/layouts/sidebar/workspace-items.d.ts +2 -1
- package/dist/types/modules/panels/__tests__/market-update.test.d.ts +1 -0
- package/dist/types/modules/panels/__tests__/plugin-tool-units-harness.d.ts +69 -0
- package/dist/types/modules/panels/model/market-route.d.ts +5 -0
- package/dist/types/shared/api/diy.d.ts +2 -0
- package/dist/types/shared/api/host/diy.d.ts +0 -1
- package/dist/types/shared/api/host/plugin-catalog.d.ts +5 -0
- package/dist/types/shared/api/host/plugin-tools.d.ts +5 -1
- package/dist/types/shared/api/host/plugin-units.d.ts +1 -0
- package/package.json +2 -2
package/dist/host/index.js
CHANGED
|
@@ -201,23 +201,37 @@ function quoteShellArg(value) {
|
|
|
201
201
|
function tailLines(text, lines = 6) {
|
|
202
202
|
return String(text ?? "").trim().split("\n").slice(-lines).join("\n");
|
|
203
203
|
}
|
|
204
|
+
function candidateStarts(raw) {
|
|
205
|
+
const starts = [];
|
|
206
|
+
for (let index = 0; index < raw.length; index += 1) {
|
|
207
|
+
const char = raw[index];
|
|
208
|
+
if (char !== "[" && char !== "{") continue;
|
|
209
|
+
if (index === 0 || raw[index - 1] === "\n") starts.push(index);
|
|
210
|
+
}
|
|
211
|
+
const earliest = [raw.indexOf("["), raw.indexOf("{")].filter((index) => index >= 0);
|
|
212
|
+
if (earliest.length > 0) {
|
|
213
|
+
const head = Math.min(...earliest);
|
|
214
|
+
if (!starts.includes(head)) starts.push(head);
|
|
215
|
+
}
|
|
216
|
+
return starts;
|
|
217
|
+
}
|
|
204
218
|
function parseJsonLoose(text) {
|
|
205
219
|
const raw = String(text ?? "").trim();
|
|
206
220
|
if (!raw) return void 0;
|
|
207
221
|
try {
|
|
208
222
|
return JSON.parse(raw);
|
|
209
223
|
} catch {
|
|
210
|
-
const
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
return;
|
|
224
|
+
for (const from of candidateStarts(raw)) {
|
|
225
|
+
const close = raw[from] === "[" ? "]" : "}";
|
|
226
|
+
const to = raw.lastIndexOf(close);
|
|
227
|
+
if (to <= from) continue;
|
|
228
|
+
try {
|
|
229
|
+
return JSON.parse(raw.slice(from, to + 1));
|
|
230
|
+
} catch {
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
220
233
|
}
|
|
234
|
+
return;
|
|
221
235
|
}
|
|
222
236
|
}
|
|
223
237
|
var PANEL_STATE_MAX_TEXT = 2e3;
|
|
@@ -2126,6 +2140,18 @@ function textOutput(text) {
|
|
|
2126
2140
|
text
|
|
2127
2141
|
}];
|
|
2128
2142
|
}
|
|
2143
|
+
function textRender(_args, value) {
|
|
2144
|
+
const text = value?.text;
|
|
2145
|
+
return textOutput(typeof text === "string" ? text : JSON.stringify(value));
|
|
2146
|
+
}
|
|
2147
|
+
var TEXT_OUTPUT = {
|
|
2148
|
+
schema: {
|
|
2149
|
+
type: "object",
|
|
2150
|
+
properties: {},
|
|
2151
|
+
additionalProperties: true
|
|
2152
|
+
},
|
|
2153
|
+
render: textRender
|
|
2154
|
+
};
|
|
2129
2155
|
function jsonText(value) {
|
|
2130
2156
|
return JSON.stringify(value);
|
|
2131
2157
|
}
|
|
@@ -2724,8 +2750,11 @@ function createRegistryNotebook(dir) {
|
|
|
2724
2750
|
};
|
|
2725
2751
|
}
|
|
2726
2752
|
//#endregion
|
|
2727
|
-
//#region src/shared/api/
|
|
2753
|
+
//#region src/shared/api/diy.ts
|
|
2728
2754
|
var WORKSHOP_RELATIVE = "workbench/diy";
|
|
2755
|
+
var WORKSHOP_TITLE = "工作台DIY";
|
|
2756
|
+
//#endregion
|
|
2757
|
+
//#region src/shared/api/host/diy.ts
|
|
2729
2758
|
function workshopPathOf(ctx) {
|
|
2730
2759
|
const homePath = ctx.get("dshHomePath");
|
|
2731
2760
|
if (typeof homePath !== "function") return null;
|
|
@@ -4353,13 +4382,39 @@ function outcomeOf(deps, pkg, change, plugin) {
|
|
|
4353
4382
|
};
|
|
4354
4383
|
}
|
|
4355
4384
|
async function installDshBundle(deps, spec, options) {
|
|
4356
|
-
|
|
4357
|
-
|
|
4385
|
+
return settle(deps, spec, options, await installOnce(deps, spec, options));
|
|
4386
|
+
}
|
|
4387
|
+
async function replaceDshBundle(deps, spec, options) {
|
|
4388
|
+
const first = await installOnce(deps, spec, options);
|
|
4389
|
+
if (first.errorCode !== "already-installed") return settle(deps, spec, options, first);
|
|
4390
|
+
const pkg = bundleNameOf(first, spec);
|
|
4391
|
+
const removed = await deps.remove(pkg);
|
|
4392
|
+
if (removed.application !== "applied") return {
|
|
4393
|
+
change: removed,
|
|
4394
|
+
module: deps.installed?.(pkg) ?? {
|
|
4395
|
+
kind: "unknown",
|
|
4396
|
+
pkg
|
|
4397
|
+
},
|
|
4398
|
+
supply: { state: "no-needs" }
|
|
4399
|
+
};
|
|
4400
|
+
return settle(deps, spec, options, await installOnce(deps, spec, options));
|
|
4401
|
+
}
|
|
4402
|
+
function installOptions(options) {
|
|
4403
|
+
return {
|
|
4358
4404
|
...options?.registry === void 0 ? {} : { registry: options.registry },
|
|
4359
4405
|
...options?.requestId === void 0 ? {} : { requestId: options.requestId },
|
|
4360
4406
|
...options?.approvedBuilds === void 0 ? {} : { approvedBuilds: options.approvedBuilds }
|
|
4407
|
+
};
|
|
4408
|
+
}
|
|
4409
|
+
async function installOnce(deps, spec, options) {
|
|
4410
|
+
const change = await deps.manager.install({
|
|
4411
|
+
spec,
|
|
4412
|
+
...installOptions(options)
|
|
4361
4413
|
});
|
|
4362
4414
|
if (change === null) throw new Error("插件管理器回的安装结果看不懂。");
|
|
4415
|
+
return change;
|
|
4416
|
+
}
|
|
4417
|
+
async function settle(deps, spec, options, change) {
|
|
4363
4418
|
const pkg = bundleNameOf(change, spec);
|
|
4364
4419
|
const module = deps.installed?.(pkg) ?? {
|
|
4365
4420
|
kind: "unknown",
|
|
@@ -4813,6 +4868,11 @@ function createMarketService(options) {
|
|
|
4813
4868
|
...registries === void 0 ? {} : { registries },
|
|
4814
4869
|
...logger === void 0 ? {} : { logger }
|
|
4815
4870
|
};
|
|
4871
|
+
async function removeInstalledBundle(manager, pkg) {
|
|
4872
|
+
const first = await manager.remove(pkg);
|
|
4873
|
+
if (first === null) throw new Error("插件管理器回的卸载结果看不懂。");
|
|
4874
|
+
return retryAfterRegistryFix(registryFix, manager, pkg, first);
|
|
4875
|
+
}
|
|
4816
4876
|
function routeDeps(manager) {
|
|
4817
4877
|
return {
|
|
4818
4878
|
manager,
|
|
@@ -4820,6 +4880,7 @@ function createMarketService(options) {
|
|
|
4820
4880
|
runAll,
|
|
4821
4881
|
rememberSource: (manager, pkg, registry) => rememberInstalledSource(registryFix, manager, pkg, registry),
|
|
4822
4882
|
supplyAfter,
|
|
4883
|
+
remove: (pkg) => removeInstalledBundle(manager, pkg),
|
|
4823
4884
|
...shell === void 0 ? {} : { shell },
|
|
4824
4885
|
...installed === void 0 ? {} : { installed },
|
|
4825
4886
|
...ledger === void 0 ? {} : { ledger },
|
|
@@ -4962,9 +5023,7 @@ function createMarketService(options) {
|
|
|
4962
5023
|
const unit = module.kind === "module" ? module.unit : void 0;
|
|
4963
5024
|
const manifest = unit === void 0 ? void 0 : catalog().find((item) => item.id === unit);
|
|
4964
5025
|
const before = unit === void 0 ? void 0 : await capabilityOf(unit, true);
|
|
4965
|
-
const
|
|
4966
|
-
if (first === null) throw new Error("插件管理器回的卸载结果看不懂。");
|
|
4967
|
-
const change = await retryAfterRegistryFix(registryFix, manager, pkg, first);
|
|
5026
|
+
const change = await removeInstalledBundle(manager, pkg);
|
|
4968
5027
|
if (change.application !== "applied" || unit === void 0) return {
|
|
4969
5028
|
change,
|
|
4970
5029
|
keptFor: []
|
|
@@ -4981,8 +5040,10 @@ function createMarketService(options) {
|
|
|
4981
5040
|
return requireBundles().cancel(requestId);
|
|
4982
5041
|
},
|
|
4983
5042
|
async updateBundle(unit) {
|
|
4984
|
-
const
|
|
4985
|
-
if (
|
|
5043
|
+
const found = (modules?.() ?? []).find((item) => item.unit === unit);
|
|
5044
|
+
if (found === void 0) return null;
|
|
5045
|
+
if (found.local === true) throw new Error(`这份模块装的是本地那一份(${found.pkg}),不从源上更新 —— 要更新先把它换成源上的版本。`);
|
|
5046
|
+
const pkg = found.pkg;
|
|
4986
5047
|
const read = installed?.(pkg) ?? {
|
|
4987
5048
|
kind: "unknown",
|
|
4988
5049
|
pkg
|
|
@@ -4995,7 +5056,7 @@ function createMarketService(options) {
|
|
|
4995
5056
|
force: true
|
|
4996
5057
|
});
|
|
4997
5058
|
const spec = latest === void 0 ? pkg : `${pkg}@${latest}`;
|
|
4998
|
-
const outcome = await
|
|
5059
|
+
const outcome = await replaceDshBundle(routeDeps(requireBundles()), spec, { ...registry === void 0 ? {} : { registry } });
|
|
4999
5060
|
await plugins.sweep();
|
|
5000
5061
|
await service.update(unit).catch(() => void 0);
|
|
5001
5062
|
return outcome;
|
|
@@ -5023,7 +5084,7 @@ function createMarketService(options) {
|
|
|
5023
5084
|
if (missing.length > 0) throw new Error(`源上已经有 ${read.pkg}@${latest},但这一份发布还没铺齐:${missing.join("、")} 在这一版上还拉不到。装上会缺依赖,稍等再试 —— 市场页那颗「重新检查」会重新探一次。`);
|
|
5024
5085
|
}
|
|
5025
5086
|
const spec = latest === void 0 ? `${read.pkg}@latest` : `${read.pkg}@${latest}`;
|
|
5026
|
-
const outcome = await
|
|
5087
|
+
const outcome = await replaceDshBundle(routeDeps(requireBundles()), spec, { ...registry === void 0 ? {} : { registry } });
|
|
5027
5088
|
logger?.info?.(`[dsh-workbench] 已更新工作台 ${read.version} → ${latest ?? "最新版"}`);
|
|
5028
5089
|
return outcome;
|
|
5029
5090
|
},
|
|
@@ -5162,8 +5223,19 @@ function render$1(entries, shared) {
|
|
|
5162
5223
|
if (shared.length === 0) return modules;
|
|
5163
5224
|
return `${modules}\n\n共用依赖(只有升级):\n${shared.map((dep) => `${dep.id} · ${stateOfDependency(dep)}${versionsOf(dep)}` + (dep.usedBy.length === 0 ? "" : ` · 供 ${dep.usedBy.join("、")} 使用`)).join("\n")}`;
|
|
5164
5225
|
}
|
|
5226
|
+
var REMOVE_BLOCKED = /* @__PURE__ */ new Set([
|
|
5227
|
+
"not-removable",
|
|
5228
|
+
"management-required",
|
|
5229
|
+
"stop-profile",
|
|
5230
|
+
"bundle-in-use"
|
|
5231
|
+
]);
|
|
5232
|
+
function failureText(change) {
|
|
5233
|
+
const code = change.errorCode ?? change.application;
|
|
5234
|
+
if (code === "already-installed") return "它已经在这份 profile 里,而这次没能把它卸下来(这一版 dsh 不肯就地覆盖装,得先卸再装)";
|
|
5235
|
+
return REMOVE_BLOCKED.has(code) ? "旧版卸不掉,而这一版 dsh 又不许就地覆盖装 —— 让用户重启一次 dsh,或者从终端更新" : code;
|
|
5236
|
+
}
|
|
5165
5237
|
function describeInstall(spec, module, supply, change) {
|
|
5166
|
-
return `${change.application === "applied" ? "装好了,已生效" : change.application === "restart-required" ? "装好了,要重启一次才生效" : `没成功:${change
|
|
5238
|
+
return `${change.application === "applied" ? "装好了,已生效" : change.application === "restart-required" ? "装好了,要重启一次才生效" : `没成功:${failureText(change)}`}:${module.kind === "module" ? `${module.unit}(${module.pkg})` : module.pkg}${supply.state === "installed" ? ";它要的 opencli 插件也装上了" : supply.state === "pending-restart" ? ";重启后再装它要的 opencli 插件" : supply.state === "not-a-module" ? ";但它不是工作台模块(没有 dsh.workbench 声明,不会出现在面板上)" : supply.state === "failed" ? `;但它要的插件没装上:${supply.reason}` : ""}(spec:${spec})`;
|
|
5167
5239
|
}
|
|
5168
5240
|
var OUTPUT_SCHEMA$1 = {
|
|
5169
5241
|
type: "object",
|
|
@@ -5191,7 +5263,7 @@ function describePluginUninstall(pkg, outcome) {
|
|
|
5191
5263
|
return `已从「你装的插件」里去掉 ${pkg}。${outcome.kept === void 0 ? "" : pluginKeptText(outcome.kept)}`;
|
|
5192
5264
|
}
|
|
5193
5265
|
function describeWorkbenchUpdate(change) {
|
|
5194
|
-
if (change.application === "failed" || change.application === "cancelled") return `没成功:${change
|
|
5266
|
+
if (change.application === "failed" || change.application === "cancelled") return `没成功:${failureText(change)}`;
|
|
5195
5267
|
return change.application === "restart-required" ? "工作台更新到新版了 —— 这一版要重启一次 dsh 才生效(重启由用户来,别自己重启)。" : "工作台更新到新版了 —— 客户端与宿主自己换上,不用重启。";
|
|
5196
5268
|
}
|
|
5197
5269
|
function usersOf(shared, names) {
|
|
@@ -6499,9 +6571,6 @@ function bundleInspectHandler(ctx) {
|
|
|
6499
6571
|
};
|
|
6500
6572
|
}
|
|
6501
6573
|
//#endregion
|
|
6502
|
-
//#region src/shared/api/diy.ts
|
|
6503
|
-
var WORKSHOP_TITLE = "工作台DIY";
|
|
6504
|
-
//#endregion
|
|
6505
6574
|
//#region src/shared/api/dsh-plugins.ts
|
|
6506
6575
|
var DSH_PLUGINS_ROUTE = "dsh-plugins";
|
|
6507
6576
|
//#endregion
|
|
@@ -7614,6 +7683,8 @@ function parseCommandRows(stdout) {
|
|
|
7614
7683
|
name,
|
|
7615
7684
|
description: textOf(record["description"]),
|
|
7616
7685
|
access: textOf(record["access"]),
|
|
7686
|
+
browser: record["browser"] === true,
|
|
7687
|
+
siteSession: textOf(record["siteSession"]),
|
|
7617
7688
|
...textOf(record["domain"]) === "" ? {} : { domain: textOf(record["domain"]) },
|
|
7618
7689
|
args: argsOf(record["args"])
|
|
7619
7690
|
});
|
|
@@ -7626,6 +7697,9 @@ function commandOf(plugin, row) {
|
|
|
7626
7697
|
name: row.name,
|
|
7627
7698
|
description: row.description,
|
|
7628
7699
|
access: row.access,
|
|
7700
|
+
browser: row.browser,
|
|
7701
|
+
siteSession: row.siteSession,
|
|
7702
|
+
...row.domain === void 0 ? {} : { domain: row.domain },
|
|
7629
7703
|
args: row.args
|
|
7630
7704
|
};
|
|
7631
7705
|
}
|
|
@@ -7799,6 +7873,8 @@ var SCHEMA_TYPE = {
|
|
|
7799
7873
|
string: "string"
|
|
7800
7874
|
};
|
|
7801
7875
|
var KEY_ARG_LIMIT = 3;
|
|
7876
|
+
var RUN_CODE_TOOL = "run_code";
|
|
7877
|
+
var PLUGIN_PROMPT_BUDGET = 4e3;
|
|
7802
7878
|
function pluginToolName(plugin, command) {
|
|
7803
7879
|
return `${plugin}_${command}`.toLowerCase().replace(/[^a-z0-9_]+/g, "_").replace(/_{2,}/g, "_").replace(/^_+|_+$/g, "");
|
|
7804
7880
|
}
|
|
@@ -7807,7 +7883,7 @@ function schemaTypeOf(arg) {
|
|
|
7807
7883
|
}
|
|
7808
7884
|
function propertyOf(arg) {
|
|
7809
7885
|
const type = schemaTypeOf(arg);
|
|
7810
|
-
const enumValues = arg.choices.length > 0 ? arg.choices
|
|
7886
|
+
const enumValues = type === "string" && arg.choices.length > 0 ? [...arg.choices] : void 0;
|
|
7811
7887
|
return {
|
|
7812
7888
|
type,
|
|
7813
7889
|
...arg.help.trim() === "" ? {} : { description: arg.help.trim() },
|
|
@@ -7815,6 +7891,9 @@ function propertyOf(arg) {
|
|
|
7815
7891
|
...arg.defaultValue === void 0 ? {} : { default: arg.defaultValue }
|
|
7816
7892
|
};
|
|
7817
7893
|
}
|
|
7894
|
+
function pluginPromptChars(command) {
|
|
7895
|
+
return pluginToolDescription(command).length + command.args.reduce((sum, arg) => sum + arg.help.trim().length, 0);
|
|
7896
|
+
}
|
|
7818
7897
|
function pluginToolParameters(command) {
|
|
7819
7898
|
const properties = {};
|
|
7820
7899
|
for (const arg of command.args) properties[arg.name] = propertyOf(arg);
|
|
@@ -7834,6 +7913,11 @@ function pluginToolDescription(command) {
|
|
|
7834
7913
|
function pluginToolWrites(command) {
|
|
7835
7914
|
return command.access !== "read";
|
|
7836
7915
|
}
|
|
7916
|
+
function pluginToolSession(command) {
|
|
7917
|
+
if (!command.browser) return "none";
|
|
7918
|
+
if (command.siteSession === "persistent" || command.siteSession === "ephemeral") return command.siteSession;
|
|
7919
|
+
return command.access === "read" ? "persistent" : "ephemeral";
|
|
7920
|
+
}
|
|
7837
7921
|
function valuesOf(raw) {
|
|
7838
7922
|
return typeof raw === "object" && raw !== null ? raw : {};
|
|
7839
7923
|
}
|
|
@@ -7850,9 +7934,9 @@ function pluginToolArgv(command, raw) {
|
|
|
7850
7934
|
if (arg.positional) continue;
|
|
7851
7935
|
const value = values[arg.name];
|
|
7852
7936
|
if (value === void 0 || value === null) continue;
|
|
7853
|
-
if (typeof value === "boolean") argv.push(`--${arg.name}
|
|
7854
|
-
else if (Array.isArray(value)) argv.push(`--${arg.name}
|
|
7855
|
-
else argv.push(`--${arg.name}
|
|
7937
|
+
if (typeof value === "boolean") argv.push(`--${arg.name}=${value ? "true" : "false"}`);
|
|
7938
|
+
else if (Array.isArray(value)) argv.push(`--${arg.name}=${value.map((item) => String(item)).join(",")}`);
|
|
7939
|
+
else argv.push(`--${arg.name}=${String(value)}`);
|
|
7856
7940
|
}
|
|
7857
7941
|
return argv;
|
|
7858
7942
|
}
|
|
@@ -7890,11 +7974,6 @@ function pluginApprovalFor(command) {
|
|
|
7890
7974
|
}
|
|
7891
7975
|
//#endregion
|
|
7892
7976
|
//#region src/shared/api/host/plugin-units.ts
|
|
7893
|
-
var TOOL_OUTPUT_SCHEMA = {
|
|
7894
|
-
type: "object",
|
|
7895
|
-
properties: {},
|
|
7896
|
-
additionalProperties: true
|
|
7897
|
-
};
|
|
7898
7977
|
function signatureOf(version, commands) {
|
|
7899
7978
|
return [version, ...commands.map((command) => `${command.name}:${command.access}:${command.args.map((arg) => `${arg.name}${arg.required ? "!" : ""}`).join("+")}`)].join("|");
|
|
7900
7979
|
}
|
|
@@ -7904,6 +7983,10 @@ function toolsOf(plugin, commands, taken) {
|
|
|
7904
7983
|
const claimed = /* @__PURE__ */ new Set();
|
|
7905
7984
|
for (const command of commands) {
|
|
7906
7985
|
const name = pluginToolName(plugin, command.name);
|
|
7986
|
+
if (name === "run_code") {
|
|
7987
|
+
problems.push(`工具名 ${RUN_CODE_TOOL}(${plugin} ${command.name})是 dsh 的保留名(PTC 的传送工具)—— 这条命令这次不合成`);
|
|
7988
|
+
continue;
|
|
7989
|
+
}
|
|
7907
7990
|
if (taken.has(name) || claimed.has(name)) {
|
|
7908
7991
|
problems.push(`工具名 ${name}(${plugin} ${command.name})已经被占着 —— 这条命令这次不合成(先来的那份说了算)`);
|
|
7909
7992
|
continue;
|
|
@@ -7946,12 +8029,15 @@ function planOf(options, registered) {
|
|
|
7946
8029
|
problems.push(...built.problems);
|
|
7947
8030
|
for (const tool of built.tools) taken.add(tool.name);
|
|
7948
8031
|
if (built.tools.length === 0 && commands.length === set.commands.length) problems.push(`「${plugin}」的命令一条都没能合成工具`);
|
|
8032
|
+
const chars = built.tools.reduce((sum, tool) => sum + pluginPromptChars(tool.command), 0);
|
|
8033
|
+
if (chars > 4e3) problems.push(`「${plugin}」合成出来的 ${String(built.tools.length)} 把工具,描述与参数说明合起来 ${String(chars)} 字,超过 ${String(PLUGIN_PROMPT_BUDGET)} 字的合成面预算 —— 这些字每一步请求都跟着走,插件该精简或按工作区少开一点`);
|
|
7949
8034
|
rows.push({
|
|
7950
8035
|
plugin,
|
|
7951
8036
|
pkg: row.pkg,
|
|
7952
8037
|
version: set.version,
|
|
7953
8038
|
commands: set.commands.length,
|
|
7954
8039
|
synthesized: built.tools.length,
|
|
8040
|
+
chars,
|
|
7955
8041
|
tools: built.tools.map((tool) => tool.name)
|
|
7956
8042
|
});
|
|
7957
8043
|
if (built.tools.length === 0) continue;
|
|
@@ -7972,7 +8058,7 @@ function planOf(options, registered) {
|
|
|
7972
8058
|
problems
|
|
7973
8059
|
};
|
|
7974
8060
|
}
|
|
7975
|
-
function faceOf(unit, opencliFor) {
|
|
8061
|
+
function faceOf(unit, opencliFor, note) {
|
|
7976
8062
|
const byTool = new Map(unit.tools.map((tool) => [tool.name, tool.command]));
|
|
7977
8063
|
const manifest = {
|
|
7978
8064
|
id: unit.id,
|
|
@@ -8000,14 +8086,14 @@ function faceOf(unit, opencliFor) {
|
|
|
8000
8086
|
name: tool.name,
|
|
8001
8087
|
description: pluginToolDescription(tool.command),
|
|
8002
8088
|
parameters: pluginToolParameters(tool.command),
|
|
8003
|
-
output:
|
|
8004
|
-
schema: TOOL_OUTPUT_SCHEMA,
|
|
8005
|
-
render: (_args, value) => textOutput(jsonText(value))
|
|
8006
|
-
},
|
|
8089
|
+
output: TEXT_OUTPUT,
|
|
8007
8090
|
async execute(raw, exec) {
|
|
8008
8091
|
const workspace = sessionWorkspace(exec);
|
|
8009
8092
|
try {
|
|
8010
|
-
return (await opencli.json([tool.command.name, ...pluginToolArgv(tool.command, raw)],
|
|
8093
|
+
return { text: jsonText((await opencli.json([tool.command.name, ...pluginToolArgv(tool.command, raw)], {
|
|
8094
|
+
session: pluginToolSession(tool.command),
|
|
8095
|
+
...workspace === null ? {} : { workdir: workspace }
|
|
8096
|
+
})).value) };
|
|
8011
8097
|
} catch (error) {
|
|
8012
8098
|
throw new Error(pluginLoginHint(error, tool.command.domain), { cause: error });
|
|
8013
8099
|
}
|
|
@@ -8016,7 +8102,15 @@ function faceOf(unit, opencliFor) {
|
|
|
8016
8102
|
return {
|
|
8017
8103
|
routes: {},
|
|
8018
8104
|
factsOf: () => [],
|
|
8019
|
-
registerTools: () =>
|
|
8105
|
+
registerTools: () => {
|
|
8106
|
+
const disposers = [];
|
|
8107
|
+
for (const definition of definitions) try {
|
|
8108
|
+
disposers.push(tools.register(definition));
|
|
8109
|
+
} catch (error) {
|
|
8110
|
+
note(`「${unit.plugin}」的 ${definition.name} 这把工具没注册上(${error instanceof Error ? error.message : String(error)})—— 只废这一把,同插件其余命令照常`);
|
|
8111
|
+
}
|
|
8112
|
+
return disposers;
|
|
8113
|
+
},
|
|
8020
8114
|
needsApproval: (call) => {
|
|
8021
8115
|
const command = call.name === void 0 ? void 0 : byTool.get(call.name);
|
|
8022
8116
|
return command === void 0 ? void 0 : pluginApprovalFor(command)(call);
|
|
@@ -8025,7 +8119,7 @@ function faceOf(unit, opencliFor) {
|
|
|
8025
8119
|
}
|
|
8026
8120
|
};
|
|
8027
8121
|
}
|
|
8028
|
-
function reconcile(registered, units, options) {
|
|
8122
|
+
function reconcile(registered, units, options, note) {
|
|
8029
8123
|
const wanted = new Map(units.map((unit) => [unit.id, unit]));
|
|
8030
8124
|
for (const [id, item] of [...registered]) {
|
|
8031
8125
|
const next = wanted.get(id);
|
|
@@ -8038,12 +8132,13 @@ function reconcile(registered, units, options) {
|
|
|
8038
8132
|
registered.set(unit.id, {
|
|
8039
8133
|
signature: unit.signature,
|
|
8040
8134
|
tools: unit.tools.map((tool) => tool.name),
|
|
8041
|
-
drop: options.registry.registerPlugin(faceOf(unit, options.opencliFor))
|
|
8135
|
+
drop: options.registry.registerPlugin(faceOf(unit, options.opencliFor, note))
|
|
8042
8136
|
});
|
|
8043
8137
|
}
|
|
8044
8138
|
}
|
|
8045
8139
|
function createPluginUnits(options) {
|
|
8046
8140
|
const registered = /* @__PURE__ */ new Map();
|
|
8141
|
+
const mountProblems = /* @__PURE__ */ new Set();
|
|
8047
8142
|
let report = {
|
|
8048
8143
|
ok: false,
|
|
8049
8144
|
at: 0,
|
|
@@ -8053,6 +8148,18 @@ function createPluginUnits(options) {
|
|
|
8053
8148
|
let inflight;
|
|
8054
8149
|
let lastTouch = 0;
|
|
8055
8150
|
let warned = "";
|
|
8151
|
+
function note(problem) {
|
|
8152
|
+
if (mountProblems.has(problem)) return;
|
|
8153
|
+
mountProblems.add(problem);
|
|
8154
|
+
options.logger?.warn?.(`[dsh-workbench] ${problem}`);
|
|
8155
|
+
}
|
|
8156
|
+
function snapshot() {
|
|
8157
|
+
const extra = [...mountProblems];
|
|
8158
|
+
return extra.length === 0 ? report : {
|
|
8159
|
+
...report,
|
|
8160
|
+
problems: [...report.problems, ...extra]
|
|
8161
|
+
};
|
|
8162
|
+
}
|
|
8056
8163
|
function warn(problems) {
|
|
8057
8164
|
const text = [...problems].sort().join("\n");
|
|
8058
8165
|
if (text === "" || text === warned) return;
|
|
@@ -8060,6 +8167,7 @@ function createPluginUnits(options) {
|
|
|
8060
8167
|
options.logger?.warn?.(`[dsh-workbench] opencli 插件命令面:\n${text}`);
|
|
8061
8168
|
}
|
|
8062
8169
|
async function run(force) {
|
|
8170
|
+
mountProblems.clear();
|
|
8063
8171
|
const probed = await options.catalog.refresh(force ? { force: true } : {});
|
|
8064
8172
|
if (!probed.ok) {
|
|
8065
8173
|
const problems = [...probed.problems, "这次探测没成功:上面这些插件行的工具面维持在上一份(不是\"这些插件没有命令\")"];
|
|
@@ -8070,10 +8178,10 @@ function createPluginUnits(options) {
|
|
|
8070
8178
|
problems
|
|
8071
8179
|
};
|
|
8072
8180
|
warn(problems);
|
|
8073
|
-
return
|
|
8181
|
+
return snapshot();
|
|
8074
8182
|
}
|
|
8075
8183
|
const plan = planOf(options, registered);
|
|
8076
|
-
reconcile(registered, plan.units, options);
|
|
8184
|
+
reconcile(registered, plan.units, options, note);
|
|
8077
8185
|
report = {
|
|
8078
8186
|
ok: true,
|
|
8079
8187
|
at: Date.now(),
|
|
@@ -8081,7 +8189,7 @@ function createPluginUnits(options) {
|
|
|
8081
8189
|
problems: plan.problems
|
|
8082
8190
|
};
|
|
8083
8191
|
warn(plan.problems);
|
|
8084
|
-
return
|
|
8192
|
+
return snapshot();
|
|
8085
8193
|
}
|
|
8086
8194
|
function refresh(callOptions = {}) {
|
|
8087
8195
|
if (inflight !== void 0) return inflight;
|
|
@@ -8102,7 +8210,7 @@ function createPluginUnits(options) {
|
|
|
8102
8210
|
options.logger?.warn?.(`[dsh-workbench] 探 opencli 插件命令面时抛了错:${String(error)}`);
|
|
8103
8211
|
});
|
|
8104
8212
|
},
|
|
8105
|
-
report: () =>
|
|
8213
|
+
report: () => snapshot(),
|
|
8106
8214
|
dispose() {
|
|
8107
8215
|
for (const item of registered.values()) item.drop();
|
|
8108
8216
|
registered.clear();
|