@dsh-workbench/core 0.2.3 → 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 +24 -10
- package/dist/client/client.body.js +24 -10
- package/dist/client/index.js +24 -10
- package/dist/host/index.js +97 -32
- package/dist/types/modules/panels/__tests__/plugin-tool-units-harness.d.ts +69 -0
- 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/client.js
CHANGED
|
@@ -2216,23 +2216,37 @@ window.__ModuleLoader__.load({
|
|
|
2216
2216
|
function tailLines(text, lines = 6) {
|
|
2217
2217
|
return String(text ?? "").trim().split("\n").slice(-lines).join("\n");
|
|
2218
2218
|
}
|
|
2219
|
+
function candidateStarts(raw) {
|
|
2220
|
+
const starts = [];
|
|
2221
|
+
for (let index = 0; index < raw.length; index += 1) {
|
|
2222
|
+
const char = raw[index];
|
|
2223
|
+
if (char !== "[" && char !== "{") continue;
|
|
2224
|
+
if (index === 0 || raw[index - 1] === "\n") starts.push(index);
|
|
2225
|
+
}
|
|
2226
|
+
const earliest = [raw.indexOf("["), raw.indexOf("{")].filter((index) => index >= 0);
|
|
2227
|
+
if (earliest.length > 0) {
|
|
2228
|
+
const head = Math.min(...earliest);
|
|
2229
|
+
if (!starts.includes(head)) starts.push(head);
|
|
2230
|
+
}
|
|
2231
|
+
return starts;
|
|
2232
|
+
}
|
|
2219
2233
|
function parseJsonLoose(text) {
|
|
2220
2234
|
const raw = String(text ?? "").trim();
|
|
2221
2235
|
if (!raw) return void 0;
|
|
2222
2236
|
try {
|
|
2223
2237
|
return JSON.parse(raw);
|
|
2224
2238
|
} catch {
|
|
2225
|
-
const
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
return;
|
|
2239
|
+
for (const from of candidateStarts(raw)) {
|
|
2240
|
+
const close = raw[from] === "[" ? "]" : "}";
|
|
2241
|
+
const to = raw.lastIndexOf(close);
|
|
2242
|
+
if (to <= from) continue;
|
|
2243
|
+
try {
|
|
2244
|
+
return JSON.parse(raw.slice(from, to + 1));
|
|
2245
|
+
} catch {
|
|
2246
|
+
continue;
|
|
2247
|
+
}
|
|
2235
2248
|
}
|
|
2249
|
+
return;
|
|
2236
2250
|
}
|
|
2237
2251
|
}
|
|
2238
2252
|
var MARKDOWN_IMAGE = /!\[[^\]]*\]\([^)]*\)/g;
|
|
@@ -2209,23 +2209,37 @@ function quoteShellArg(value) {
|
|
|
2209
2209
|
function tailLines(text, lines = 6) {
|
|
2210
2210
|
return String(text ?? "").trim().split("\n").slice(-lines).join("\n");
|
|
2211
2211
|
}
|
|
2212
|
+
function candidateStarts(raw) {
|
|
2213
|
+
const starts = [];
|
|
2214
|
+
for (let index = 0; index < raw.length; index += 1) {
|
|
2215
|
+
const char = raw[index];
|
|
2216
|
+
if (char !== "[" && char !== "{") continue;
|
|
2217
|
+
if (index === 0 || raw[index - 1] === "\n") starts.push(index);
|
|
2218
|
+
}
|
|
2219
|
+
const earliest = [raw.indexOf("["), raw.indexOf("{")].filter((index) => index >= 0);
|
|
2220
|
+
if (earliest.length > 0) {
|
|
2221
|
+
const head = Math.min(...earliest);
|
|
2222
|
+
if (!starts.includes(head)) starts.push(head);
|
|
2223
|
+
}
|
|
2224
|
+
return starts;
|
|
2225
|
+
}
|
|
2212
2226
|
function parseJsonLoose(text) {
|
|
2213
2227
|
const raw = String(text ?? "").trim();
|
|
2214
2228
|
if (!raw) return void 0;
|
|
2215
2229
|
try {
|
|
2216
2230
|
return JSON.parse(raw);
|
|
2217
2231
|
} catch {
|
|
2218
|
-
const
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
return;
|
|
2232
|
+
for (const from of candidateStarts(raw)) {
|
|
2233
|
+
const close = raw[from] === "[" ? "]" : "}";
|
|
2234
|
+
const to = raw.lastIndexOf(close);
|
|
2235
|
+
if (to <= from) continue;
|
|
2236
|
+
try {
|
|
2237
|
+
return JSON.parse(raw.slice(from, to + 1));
|
|
2238
|
+
} catch {
|
|
2239
|
+
continue;
|
|
2240
|
+
}
|
|
2228
2241
|
}
|
|
2242
|
+
return;
|
|
2229
2243
|
}
|
|
2230
2244
|
}
|
|
2231
2245
|
var MARKDOWN_IMAGE = /!\[[^\]]*\]\([^)]*\)/g;
|
package/dist/client/index.js
CHANGED
|
@@ -2212,23 +2212,37 @@ function quoteShellArg(value) {
|
|
|
2212
2212
|
function tailLines(text, lines = 6) {
|
|
2213
2213
|
return String(text ?? "").trim().split("\n").slice(-lines).join("\n");
|
|
2214
2214
|
}
|
|
2215
|
+
function candidateStarts(raw) {
|
|
2216
|
+
const starts = [];
|
|
2217
|
+
for (let index = 0; index < raw.length; index += 1) {
|
|
2218
|
+
const char = raw[index];
|
|
2219
|
+
if (char !== "[" && char !== "{") continue;
|
|
2220
|
+
if (index === 0 || raw[index - 1] === "\n") starts.push(index);
|
|
2221
|
+
}
|
|
2222
|
+
const earliest = [raw.indexOf("["), raw.indexOf("{")].filter((index) => index >= 0);
|
|
2223
|
+
if (earliest.length > 0) {
|
|
2224
|
+
const head = Math.min(...earliest);
|
|
2225
|
+
if (!starts.includes(head)) starts.push(head);
|
|
2226
|
+
}
|
|
2227
|
+
return starts;
|
|
2228
|
+
}
|
|
2215
2229
|
function parseJsonLoose(text) {
|
|
2216
2230
|
const raw = String(text ?? "").trim();
|
|
2217
2231
|
if (!raw) return void 0;
|
|
2218
2232
|
try {
|
|
2219
2233
|
return JSON.parse(raw);
|
|
2220
2234
|
} catch {
|
|
2221
|
-
const
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
return;
|
|
2235
|
+
for (const from of candidateStarts(raw)) {
|
|
2236
|
+
const close = raw[from] === "[" ? "]" : "}";
|
|
2237
|
+
const to = raw.lastIndexOf(close);
|
|
2238
|
+
if (to <= from) continue;
|
|
2239
|
+
try {
|
|
2240
|
+
return JSON.parse(raw.slice(from, to + 1));
|
|
2241
|
+
} catch {
|
|
2242
|
+
continue;
|
|
2243
|
+
}
|
|
2231
2244
|
}
|
|
2245
|
+
return;
|
|
2232
2246
|
}
|
|
2233
2247
|
}
|
|
2234
2248
|
var MARKDOWN_IMAGE = /!\[[^\]]*\]\([^)]*\)/g;
|
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
|
}
|
|
@@ -7657,6 +7683,8 @@ function parseCommandRows(stdout) {
|
|
|
7657
7683
|
name,
|
|
7658
7684
|
description: textOf(record["description"]),
|
|
7659
7685
|
access: textOf(record["access"]),
|
|
7686
|
+
browser: record["browser"] === true,
|
|
7687
|
+
siteSession: textOf(record["siteSession"]),
|
|
7660
7688
|
...textOf(record["domain"]) === "" ? {} : { domain: textOf(record["domain"]) },
|
|
7661
7689
|
args: argsOf(record["args"])
|
|
7662
7690
|
});
|
|
@@ -7669,6 +7697,9 @@ function commandOf(plugin, row) {
|
|
|
7669
7697
|
name: row.name,
|
|
7670
7698
|
description: row.description,
|
|
7671
7699
|
access: row.access,
|
|
7700
|
+
browser: row.browser,
|
|
7701
|
+
siteSession: row.siteSession,
|
|
7702
|
+
...row.domain === void 0 ? {} : { domain: row.domain },
|
|
7672
7703
|
args: row.args
|
|
7673
7704
|
};
|
|
7674
7705
|
}
|
|
@@ -7842,6 +7873,8 @@ var SCHEMA_TYPE = {
|
|
|
7842
7873
|
string: "string"
|
|
7843
7874
|
};
|
|
7844
7875
|
var KEY_ARG_LIMIT = 3;
|
|
7876
|
+
var RUN_CODE_TOOL = "run_code";
|
|
7877
|
+
var PLUGIN_PROMPT_BUDGET = 4e3;
|
|
7845
7878
|
function pluginToolName(plugin, command) {
|
|
7846
7879
|
return `${plugin}_${command}`.toLowerCase().replace(/[^a-z0-9_]+/g, "_").replace(/_{2,}/g, "_").replace(/^_+|_+$/g, "");
|
|
7847
7880
|
}
|
|
@@ -7850,7 +7883,7 @@ function schemaTypeOf(arg) {
|
|
|
7850
7883
|
}
|
|
7851
7884
|
function propertyOf(arg) {
|
|
7852
7885
|
const type = schemaTypeOf(arg);
|
|
7853
|
-
const enumValues = arg.choices.length > 0 ? arg.choices
|
|
7886
|
+
const enumValues = type === "string" && arg.choices.length > 0 ? [...arg.choices] : void 0;
|
|
7854
7887
|
return {
|
|
7855
7888
|
type,
|
|
7856
7889
|
...arg.help.trim() === "" ? {} : { description: arg.help.trim() },
|
|
@@ -7858,6 +7891,9 @@ function propertyOf(arg) {
|
|
|
7858
7891
|
...arg.defaultValue === void 0 ? {} : { default: arg.defaultValue }
|
|
7859
7892
|
};
|
|
7860
7893
|
}
|
|
7894
|
+
function pluginPromptChars(command) {
|
|
7895
|
+
return pluginToolDescription(command).length + command.args.reduce((sum, arg) => sum + arg.help.trim().length, 0);
|
|
7896
|
+
}
|
|
7861
7897
|
function pluginToolParameters(command) {
|
|
7862
7898
|
const properties = {};
|
|
7863
7899
|
for (const arg of command.args) properties[arg.name] = propertyOf(arg);
|
|
@@ -7877,6 +7913,11 @@ function pluginToolDescription(command) {
|
|
|
7877
7913
|
function pluginToolWrites(command) {
|
|
7878
7914
|
return command.access !== "read";
|
|
7879
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
|
+
}
|
|
7880
7921
|
function valuesOf(raw) {
|
|
7881
7922
|
return typeof raw === "object" && raw !== null ? raw : {};
|
|
7882
7923
|
}
|
|
@@ -7893,9 +7934,9 @@ function pluginToolArgv(command, raw) {
|
|
|
7893
7934
|
if (arg.positional) continue;
|
|
7894
7935
|
const value = values[arg.name];
|
|
7895
7936
|
if (value === void 0 || value === null) continue;
|
|
7896
|
-
if (typeof value === "boolean") argv.push(`--${arg.name}
|
|
7897
|
-
else if (Array.isArray(value)) argv.push(`--${arg.name}
|
|
7898
|
-
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)}`);
|
|
7899
7940
|
}
|
|
7900
7941
|
return argv;
|
|
7901
7942
|
}
|
|
@@ -7933,11 +7974,6 @@ function pluginApprovalFor(command) {
|
|
|
7933
7974
|
}
|
|
7934
7975
|
//#endregion
|
|
7935
7976
|
//#region src/shared/api/host/plugin-units.ts
|
|
7936
|
-
var TOOL_OUTPUT_SCHEMA = {
|
|
7937
|
-
type: "object",
|
|
7938
|
-
properties: {},
|
|
7939
|
-
additionalProperties: true
|
|
7940
|
-
};
|
|
7941
7977
|
function signatureOf(version, commands) {
|
|
7942
7978
|
return [version, ...commands.map((command) => `${command.name}:${command.access}:${command.args.map((arg) => `${arg.name}${arg.required ? "!" : ""}`).join("+")}`)].join("|");
|
|
7943
7979
|
}
|
|
@@ -7947,6 +7983,10 @@ function toolsOf(plugin, commands, taken) {
|
|
|
7947
7983
|
const claimed = /* @__PURE__ */ new Set();
|
|
7948
7984
|
for (const command of commands) {
|
|
7949
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
|
+
}
|
|
7950
7990
|
if (taken.has(name) || claimed.has(name)) {
|
|
7951
7991
|
problems.push(`工具名 ${name}(${plugin} ${command.name})已经被占着 —— 这条命令这次不合成(先来的那份说了算)`);
|
|
7952
7992
|
continue;
|
|
@@ -7989,12 +8029,15 @@ function planOf(options, registered) {
|
|
|
7989
8029
|
problems.push(...built.problems);
|
|
7990
8030
|
for (const tool of built.tools) taken.add(tool.name);
|
|
7991
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)} 字的合成面预算 —— 这些字每一步请求都跟着走,插件该精简或按工作区少开一点`);
|
|
7992
8034
|
rows.push({
|
|
7993
8035
|
plugin,
|
|
7994
8036
|
pkg: row.pkg,
|
|
7995
8037
|
version: set.version,
|
|
7996
8038
|
commands: set.commands.length,
|
|
7997
8039
|
synthesized: built.tools.length,
|
|
8040
|
+
chars,
|
|
7998
8041
|
tools: built.tools.map((tool) => tool.name)
|
|
7999
8042
|
});
|
|
8000
8043
|
if (built.tools.length === 0) continue;
|
|
@@ -8015,7 +8058,7 @@ function planOf(options, registered) {
|
|
|
8015
8058
|
problems
|
|
8016
8059
|
};
|
|
8017
8060
|
}
|
|
8018
|
-
function faceOf(unit, opencliFor) {
|
|
8061
|
+
function faceOf(unit, opencliFor, note) {
|
|
8019
8062
|
const byTool = new Map(unit.tools.map((tool) => [tool.name, tool.command]));
|
|
8020
8063
|
const manifest = {
|
|
8021
8064
|
id: unit.id,
|
|
@@ -8043,14 +8086,14 @@ function faceOf(unit, opencliFor) {
|
|
|
8043
8086
|
name: tool.name,
|
|
8044
8087
|
description: pluginToolDescription(tool.command),
|
|
8045
8088
|
parameters: pluginToolParameters(tool.command),
|
|
8046
|
-
output:
|
|
8047
|
-
schema: TOOL_OUTPUT_SCHEMA,
|
|
8048
|
-
render: (_args, value) => textOutput(jsonText(value))
|
|
8049
|
-
},
|
|
8089
|
+
output: TEXT_OUTPUT,
|
|
8050
8090
|
async execute(raw, exec) {
|
|
8051
8091
|
const workspace = sessionWorkspace(exec);
|
|
8052
8092
|
try {
|
|
8053
|
-
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) };
|
|
8054
8097
|
} catch (error) {
|
|
8055
8098
|
throw new Error(pluginLoginHint(error, tool.command.domain), { cause: error });
|
|
8056
8099
|
}
|
|
@@ -8059,7 +8102,15 @@ function faceOf(unit, opencliFor) {
|
|
|
8059
8102
|
return {
|
|
8060
8103
|
routes: {},
|
|
8061
8104
|
factsOf: () => [],
|
|
8062
|
-
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
|
+
},
|
|
8063
8114
|
needsApproval: (call) => {
|
|
8064
8115
|
const command = call.name === void 0 ? void 0 : byTool.get(call.name);
|
|
8065
8116
|
return command === void 0 ? void 0 : pluginApprovalFor(command)(call);
|
|
@@ -8068,7 +8119,7 @@ function faceOf(unit, opencliFor) {
|
|
|
8068
8119
|
}
|
|
8069
8120
|
};
|
|
8070
8121
|
}
|
|
8071
|
-
function reconcile(registered, units, options) {
|
|
8122
|
+
function reconcile(registered, units, options, note) {
|
|
8072
8123
|
const wanted = new Map(units.map((unit) => [unit.id, unit]));
|
|
8073
8124
|
for (const [id, item] of [...registered]) {
|
|
8074
8125
|
const next = wanted.get(id);
|
|
@@ -8081,12 +8132,13 @@ function reconcile(registered, units, options) {
|
|
|
8081
8132
|
registered.set(unit.id, {
|
|
8082
8133
|
signature: unit.signature,
|
|
8083
8134
|
tools: unit.tools.map((tool) => tool.name),
|
|
8084
|
-
drop: options.registry.registerPlugin(faceOf(unit, options.opencliFor))
|
|
8135
|
+
drop: options.registry.registerPlugin(faceOf(unit, options.opencliFor, note))
|
|
8085
8136
|
});
|
|
8086
8137
|
}
|
|
8087
8138
|
}
|
|
8088
8139
|
function createPluginUnits(options) {
|
|
8089
8140
|
const registered = /* @__PURE__ */ new Map();
|
|
8141
|
+
const mountProblems = /* @__PURE__ */ new Set();
|
|
8090
8142
|
let report = {
|
|
8091
8143
|
ok: false,
|
|
8092
8144
|
at: 0,
|
|
@@ -8096,6 +8148,18 @@ function createPluginUnits(options) {
|
|
|
8096
8148
|
let inflight;
|
|
8097
8149
|
let lastTouch = 0;
|
|
8098
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
|
+
}
|
|
8099
8163
|
function warn(problems) {
|
|
8100
8164
|
const text = [...problems].sort().join("\n");
|
|
8101
8165
|
if (text === "" || text === warned) return;
|
|
@@ -8103,6 +8167,7 @@ function createPluginUnits(options) {
|
|
|
8103
8167
|
options.logger?.warn?.(`[dsh-workbench] opencli 插件命令面:\n${text}`);
|
|
8104
8168
|
}
|
|
8105
8169
|
async function run(force) {
|
|
8170
|
+
mountProblems.clear();
|
|
8106
8171
|
const probed = await options.catalog.refresh(force ? { force: true } : {});
|
|
8107
8172
|
if (!probed.ok) {
|
|
8108
8173
|
const problems = [...probed.problems, "这次探测没成功:上面这些插件行的工具面维持在上一份(不是\"这些插件没有命令\")"];
|
|
@@ -8113,10 +8178,10 @@ function createPluginUnits(options) {
|
|
|
8113
8178
|
problems
|
|
8114
8179
|
};
|
|
8115
8180
|
warn(problems);
|
|
8116
|
-
return
|
|
8181
|
+
return snapshot();
|
|
8117
8182
|
}
|
|
8118
8183
|
const plan = planOf(options, registered);
|
|
8119
|
-
reconcile(registered, plan.units, options);
|
|
8184
|
+
reconcile(registered, plan.units, options, note);
|
|
8120
8185
|
report = {
|
|
8121
8186
|
ok: true,
|
|
8122
8187
|
at: Date.now(),
|
|
@@ -8124,7 +8189,7 @@ function createPluginUnits(options) {
|
|
|
8124
8189
|
problems: plan.problems
|
|
8125
8190
|
};
|
|
8126
8191
|
warn(plan.problems);
|
|
8127
|
-
return
|
|
8192
|
+
return snapshot();
|
|
8128
8193
|
}
|
|
8129
8194
|
function refresh(callOptions = {}) {
|
|
8130
8195
|
if (inflight !== void 0) return inflight;
|
|
@@ -8145,7 +8210,7 @@ function createPluginUnits(options) {
|
|
|
8145
8210
|
options.logger?.warn?.(`[dsh-workbench] 探 opencli 插件命令面时抛了错:${String(error)}`);
|
|
8146
8211
|
});
|
|
8147
8212
|
},
|
|
8148
|
-
report: () =>
|
|
8213
|
+
report: () => snapshot(),
|
|
8149
8214
|
dispose() {
|
|
8150
8215
|
for (const item of registered.values()) item.drop();
|
|
8151
8216
|
registered.clear();
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { DshToolDefinition } from '@dsh-workbench/shared';
|
|
2
|
+
import { type WorkspaceStore } from '@dsh-workbench/shared/host';
|
|
3
|
+
import { createPluginUnits } from '../../../shared/api/host/plugin-units';
|
|
4
|
+
import { type UnitRegistry } from '../../../shared/api/host/unit-registry';
|
|
5
|
+
import type { PluginLedger } from '../model/plugin-ledger';
|
|
6
|
+
import { type PanelsService } from '../model/service';
|
|
7
|
+
export declare const COMMANDS: ({
|
|
8
|
+
site: string;
|
|
9
|
+
name: string;
|
|
10
|
+
description: string;
|
|
11
|
+
access: string;
|
|
12
|
+
browser: boolean;
|
|
13
|
+
siteSession: string;
|
|
14
|
+
domain: string;
|
|
15
|
+
args: {
|
|
16
|
+
name: string;
|
|
17
|
+
type: string;
|
|
18
|
+
required: boolean;
|
|
19
|
+
help: string;
|
|
20
|
+
}[];
|
|
21
|
+
} | {
|
|
22
|
+
site: string;
|
|
23
|
+
name: string;
|
|
24
|
+
description: string;
|
|
25
|
+
access: string;
|
|
26
|
+
browser: boolean;
|
|
27
|
+
args: {
|
|
28
|
+
name: string;
|
|
29
|
+
type: string;
|
|
30
|
+
required: boolean;
|
|
31
|
+
help: string;
|
|
32
|
+
}[];
|
|
33
|
+
siteSession?: undefined;
|
|
34
|
+
domain?: undefined;
|
|
35
|
+
})[];
|
|
36
|
+
export interface Harness {
|
|
37
|
+
readonly registry: UnitRegistry;
|
|
38
|
+
readonly panels: PanelsService;
|
|
39
|
+
readonly tools: Map<string, DshToolDefinition>;
|
|
40
|
+
readonly gate: {
|
|
41
|
+
deniedTools(workspace: string | null): readonly string[];
|
|
42
|
+
};
|
|
43
|
+
readonly manager: ReturnType<typeof createPluginUnits>;
|
|
44
|
+
readonly problems: string[];
|
|
45
|
+
readonly definitions: () => DshToolDefinition[];
|
|
46
|
+
readonly commands: () => readonly string[];
|
|
47
|
+
readonly opencliCalls: () => readonly {
|
|
48
|
+
readonly args: readonly string[];
|
|
49
|
+
readonly workdir?: string;
|
|
50
|
+
readonly session?: string;
|
|
51
|
+
}[];
|
|
52
|
+
readonly toolOf: (name: string) => DshToolDefinition | undefined;
|
|
53
|
+
readonly ownerOf: (name: string) => {
|
|
54
|
+
readonly needsApproval?: unknown;
|
|
55
|
+
readonly manifest: unknown;
|
|
56
|
+
} | undefined;
|
|
57
|
+
readonly units: () => readonly string[];
|
|
58
|
+
}
|
|
59
|
+
export declare function deny(h: Harness, workspace: string): string[];
|
|
60
|
+
export declare function harnessOf(options: {
|
|
61
|
+
readonly store: WorkspaceStore;
|
|
62
|
+
readonly ledger: PluginLedger;
|
|
63
|
+
readonly pluginRows: () => unknown;
|
|
64
|
+
readonly commands?: unknown;
|
|
65
|
+
readonly declared?: ReadonlyMap<string, ReadonlySet<string>>;
|
|
66
|
+
readonly moduleTools?: readonly string[];
|
|
67
|
+
readonly opencliReplies?: readonly unknown[];
|
|
68
|
+
readonly failTools?: readonly string[];
|
|
69
|
+
}): Harness;
|
|
@@ -14,6 +14,8 @@ export interface PluginCommand {
|
|
|
14
14
|
readonly name: string;
|
|
15
15
|
readonly description: string;
|
|
16
16
|
readonly access: string;
|
|
17
|
+
readonly browser: boolean;
|
|
18
|
+
readonly siteSession: string;
|
|
17
19
|
readonly domain?: string;
|
|
18
20
|
readonly args: readonly PluginCommandArg[];
|
|
19
21
|
}
|
|
@@ -32,6 +34,9 @@ export interface CommandRow {
|
|
|
32
34
|
readonly name: string;
|
|
33
35
|
readonly description: string;
|
|
34
36
|
readonly access: string;
|
|
37
|
+
readonly browser: boolean;
|
|
38
|
+
readonly siteSession: string;
|
|
39
|
+
readonly domain?: string;
|
|
35
40
|
readonly args: readonly PluginCommandArg[];
|
|
36
41
|
}
|
|
37
42
|
export interface PluginCatalogSnapshot {
|
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
import type { ApprovalDetail, ApprovalPolicy } from '@dsh-workbench/shared/host';
|
|
1
|
+
import type { ApprovalDetail, ApprovalPolicy, OpencliSession } from '@dsh-workbench/shared/host';
|
|
2
2
|
import type { PluginCommand } from './plugin-catalog';
|
|
3
|
+
export declare const RUN_CODE_TOOL = "run_code";
|
|
4
|
+
export declare const PLUGIN_PROMPT_BUDGET = 4000;
|
|
3
5
|
export declare function pluginToolName(plugin: string, command: string): string;
|
|
6
|
+
export declare function pluginPromptChars(command: PluginCommand): number;
|
|
4
7
|
export declare function pluginToolParameters(command: PluginCommand): Record<string, unknown>;
|
|
5
8
|
export declare function pluginToolDescription(command: PluginCommand): string;
|
|
6
9
|
export declare function pluginToolWrites(command: PluginCommand): boolean;
|
|
10
|
+
export declare function pluginToolSession(command: PluginCommand): OpencliSession;
|
|
7
11
|
export declare function pluginToolArgv(command: PluginCommand, raw: unknown): string[];
|
|
8
12
|
export declare function pluginKeyArgs(command: PluginCommand, raw: unknown): string;
|
|
9
13
|
export declare function pluginApprovalQuestion(command: PluginCommand, raw: unknown): ApprovalDetail;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dsh-workbench/core",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"description": "个人工作台:Agent 工作台外壳(左栏 + 常驻对话 + 自研右侧数据面板)。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"icon": "./icon.svg",
|
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
"access": "public"
|
|
88
88
|
},
|
|
89
89
|
"dependencies": {
|
|
90
|
-
"@dsh-workbench/shared": "0.2.
|
|
90
|
+
"@dsh-workbench/shared": "0.2.4"
|
|
91
91
|
},
|
|
92
92
|
"scripts": {
|
|
93
93
|
"build": "node scripts/build.mjs && node scripts/build-types.mjs",
|