@dsh-workbench/core 0.1.9 → 0.1.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/bin/dsh-workbench +23 -0
- package/client.js +609 -84
- package/cordis.patch.yml +11 -3
- package/dist/client/client.body.js +609 -84
- package/dist/client/index.js +610 -85
- package/dist/host/index.js +406 -276
- package/dist/types/app/client.d.ts +140 -6
- package/dist/types/app/layouts/rightbar/BoardEmpty.d.ts +2 -1
- package/dist/types/app/layouts/rightbar/Rightbar.d.ts +1 -0
- 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/modules/panels/__tests__/approval.test.d.ts +1 -0
- package/dist/types/modules/panels/model/approval.d.ts +2 -0
- package/dist/types/shared/api/diy.d.ts +3 -0
- package/dist/types/shared/api/diy.test.d.ts +1 -0
- package/dist/types/shared/api/host/__tests__/approval-legacy.test.d.ts +1 -0
- package/dist/types/shared/api/host/approval-legacy.d.ts +2 -0
- package/dist/types/shared/api/host/diy.d.ts +3 -0
- package/dist/types/shared/api/host/diy.test.d.ts +1 -0
- 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 +13 -5
- package/preset/diy.patch.yml +156 -0
- package/scripts/seed-profile.sh +116 -0
- package/skills/workbench-module-diy/BUILD.md +179 -0
- package/skills/workbench-module-diy/DESIGN.md +81 -0
- package/skills/workbench-module-diy/LINKAGE.md +113 -0
- package/skills/workbench-module-diy/PANEL.md +124 -0
- package/skills/workbench-module-diy/REVIEW.md +31 -0
- package/skills/workbench-module-diy/SKILL.md +54 -0
- package/skills/workbench-module-diy/STEPS.md +93 -0
- package/skills/workbench-module-diy/TOOLS.md +112 -0
package/dist/host/index.js
CHANGED
|
@@ -892,171 +892,39 @@ function resolvePluginSource(source, env, options = {}) {
|
|
|
892
892
|
}
|
|
893
893
|
//#endregion
|
|
894
894
|
//#region ../shared/dist/host/tool-approval.js
|
|
895
|
-
function
|
|
896
|
-
|
|
897
|
-
return {
|
|
898
|
-
en: `${detail.en} — ${texts.question.en}`,
|
|
899
|
-
zh: `${detail.zh} —— ${texts.question.zh}`
|
|
900
|
-
};
|
|
895
|
+
function messageOf(error) {
|
|
896
|
+
return error instanceof Error ? error.message : String(error);
|
|
901
897
|
}
|
|
902
|
-
function
|
|
903
|
-
|
|
904
|
-
if (typeof raw !== "object" || raw === null) return {};
|
|
905
|
-
const value = raw;
|
|
898
|
+
function compose(detail, verdict) {
|
|
899
|
+
if (detail === void 0 || typeof detail.zh !== "string" || detail.zh.trim() === "") return verdict.fallback;
|
|
906
900
|
return {
|
|
907
|
-
|
|
908
|
-
|
|
901
|
+
en: `${detail.en} — ${verdict.question.en}`,
|
|
902
|
+
zh: `${detail.zh} —— ${verdict.question.zh}`
|
|
909
903
|
};
|
|
910
904
|
}
|
|
911
|
-
var READ_ONLY_ACTIONS = /* @__PURE__ */ new Set(["list", ""]);
|
|
912
|
-
var READ = { kind: "read" };
|
|
913
|
-
var UNKNOWN = { kind: "unknown" };
|
|
914
|
-
function ask(spec) {
|
|
915
|
-
return {
|
|
916
|
-
kind: "ask",
|
|
917
|
-
spec
|
|
918
|
-
};
|
|
919
|
-
}
|
|
920
|
-
function confirmed(call) {
|
|
921
|
-
const raw = call.arguments;
|
|
922
|
-
if (typeof raw !== "object" || raw === null) return void 0;
|
|
923
|
-
const value = raw.confirm;
|
|
924
|
-
return typeof value === "boolean" ? value : void 0;
|
|
925
|
-
}
|
|
926
|
-
function effectOf(call, context) {
|
|
927
|
-
const name = call.name ?? "";
|
|
928
|
-
const { action, id } = actionOf$1(call);
|
|
929
|
-
const readAction = action !== void 0 && action !== "" && READ_ONLY_ACTIONS.has(action);
|
|
930
|
-
const what = () => {
|
|
931
|
-
if (id === void 0 || id === "") return "一个模块";
|
|
932
|
-
return `「${context.titleOf?.(id) ?? id}」`;
|
|
933
|
-
};
|
|
934
|
-
if (name === "workbench_cmdb_release") {
|
|
935
|
-
if (confirmed(call) !== true) return READ;
|
|
936
|
-
return ask({
|
|
937
|
-
reason: "confirm=true releases a version to a real environment",
|
|
938
|
-
generic: {
|
|
939
|
-
en: "The agent wants to deploy a version for real (confirm: true) — it deploys on the platform (non-production). Allow?",
|
|
940
|
-
zh: "agent 想在非生产环境上**真的部署一个版本**(confirm: true)—— 会在平台上部署。允许吗?"
|
|
941
|
-
},
|
|
942
|
-
question: {
|
|
943
|
-
en: "it deploys on the platform for real (non-production). Allow?",
|
|
944
|
-
zh: "会在平台上真的部署一次(非生产环境)。允许吗?"
|
|
945
|
-
}
|
|
946
|
-
});
|
|
947
|
-
}
|
|
948
|
-
if (name === "workbench_coding_issue_comment" || name === "workbench_coding_issue_transfer") {
|
|
949
|
-
if (confirmed(call) !== true) return READ;
|
|
950
|
-
const comment = name === "workbench_coding_issue_comment";
|
|
951
|
-
return ask({
|
|
952
|
-
reason: comment ? "confirm=true posts a comment on the platform" : "confirm=true moves an issue to another status on the platform",
|
|
953
|
-
generic: comment ? {
|
|
954
|
-
en: "The agent wants to post a comment on the platform for real (confirm: true) — it writes on the platform. Allow?",
|
|
955
|
-
zh: "agent 想**真的给一条缺陷加评论**(confirm: true)—— 会写平台数据。允许吗?"
|
|
956
|
-
} : {
|
|
957
|
-
en: "The agent wants to move an issue to another status for real (confirm: true) — it writes on the platform. Allow?",
|
|
958
|
-
zh: "agent 想**真的把一条缺陷流转到别的状态**(confirm: true)—— 会写平台数据。允许吗?"
|
|
959
|
-
},
|
|
960
|
-
question: comment ? {
|
|
961
|
-
en: "it posts that comment on the platform for real. Allow?",
|
|
962
|
-
zh: "会在平台上真的发表这条评论。允许吗?"
|
|
963
|
-
} : {
|
|
964
|
-
en: "it changes that issue status on the platform for real. Allow?",
|
|
965
|
-
zh: "会在平台上真的改这条缺陷的状态。允许吗?"
|
|
966
|
-
}
|
|
967
|
-
});
|
|
968
|
-
}
|
|
969
|
-
if (name === "workbench_modules") {
|
|
970
|
-
if (readAction) return READ;
|
|
971
|
-
if (action === "update-dependency") return ask({
|
|
972
|
-
reason: `workbench_modules update-dependency ${id ?? ""} upgrades a shared dependency on this machine`,
|
|
973
|
-
generic: {
|
|
974
|
-
en: `The agent wants to upgrade the shared dependency ${what()} (it changes what is installed on this machine). Allow?`,
|
|
975
|
-
zh: `agent 想升级共用依赖 ${what()}(会改这台机器上装的东西)。允许吗?`
|
|
976
|
-
},
|
|
977
|
-
question: {
|
|
978
|
-
en: "it upgrades that shared dependency on this machine. Allow?",
|
|
979
|
-
zh: `会升级共用依赖 ${what()}。允许吗?`
|
|
980
|
-
}
|
|
981
|
-
});
|
|
982
|
-
const verb = action === "install" ? "装" : action === "uninstall" ? "卸载" : action === "update" ? "更新" : "装 / 更新 / 卸载";
|
|
983
|
-
return ask({
|
|
984
|
-
reason: `workbench_modules ${action ?? "(unknown action)"} ${id ?? ""} changes plugins on this machine`.trim(),
|
|
985
|
-
generic: {
|
|
986
|
-
en: `The agent wants to ${verb === "装" ? "install" : verb === "卸载" ? "remove" : verb === "更新" ? "update" : "install/update/remove"} the module ${what()} (it changes plugins on this machine). Allow?`,
|
|
987
|
-
zh: `agent 想${verb}模块 ${what()}(会改这台机器上的插件)。允许吗?`
|
|
988
|
-
},
|
|
989
|
-
question: {
|
|
990
|
-
en: "it changes plugins on this machine. Allow?",
|
|
991
|
-
zh: "会改这台机器上的插件。允许吗?"
|
|
992
|
-
}
|
|
993
|
-
});
|
|
994
|
-
}
|
|
995
|
-
if (name !== "workbench_panels") return UNKNOWN;
|
|
996
|
-
if (readAction) return READ;
|
|
997
|
-
if (action === "hide") return ask({
|
|
998
|
-
reason: "workbench_panels hide removes a module from the panel",
|
|
999
|
-
generic: {
|
|
1000
|
-
en: `The agent wants to remove ${what()} from this project's panel (its agent tools go offline here too). Allow?`,
|
|
1001
|
-
zh: `agent 想把 ${what()} 从这个项目的面板上收起来(这个项目里它的 agent 工具也一起下线)。允许吗?`
|
|
1002
|
-
},
|
|
1003
|
-
question: {
|
|
1004
|
-
en: "it takes that module off this panel (its agent tools go offline here too). Allow?",
|
|
1005
|
-
zh: `${what()}会从这个项目的面板上收起来(这个项目里它的 agent 工具也一起下线)。允许吗?`
|
|
1006
|
-
}
|
|
1007
|
-
});
|
|
1008
|
-
if (action === "move") return ask({
|
|
1009
|
-
reason: "workbench_panels move reorders the panel",
|
|
1010
|
-
generic: {
|
|
1011
|
-
en: `The agent wants to reorder this project's panel (put ${what()} first). Allow?`,
|
|
1012
|
-
zh: `agent 想调整这个项目面板的顺序(把 ${what()} 放前面)。允许吗?`
|
|
1013
|
-
},
|
|
1014
|
-
question: {
|
|
1015
|
-
en: `it reorders this panel (${what()} goes first). Allow?`,
|
|
1016
|
-
zh: `会调整这个项目面板的顺序(${what()}放前面)。允许吗?`
|
|
1017
|
-
}
|
|
1018
|
-
});
|
|
1019
|
-
if (action === "reset") return ask({
|
|
1020
|
-
reason: "workbench_panels reset clears the panel",
|
|
1021
|
-
generic: {
|
|
1022
|
-
en: "The agent wants to clear this project's panel (every module goes offline here). Allow?",
|
|
1023
|
-
zh: "agent 想清空这个项目的面板(所有模块在这个项目里都下线)。允许吗?"
|
|
1024
|
-
},
|
|
1025
|
-
question: {
|
|
1026
|
-
en: "it clears this panel (every module goes offline here). Allow?",
|
|
1027
|
-
zh: "会清空这个项目的面板(所有模块在这个项目里都下线)。允许吗?"
|
|
1028
|
-
}
|
|
1029
|
-
});
|
|
1030
|
-
return ask({
|
|
1031
|
-
reason: `workbench_panels ${action ?? "(unknown action)"} changes the user's panel`,
|
|
1032
|
-
generic: {
|
|
1033
|
-
en: `The agent wants to add ${what()} to this project's panel. Allow?`,
|
|
1034
|
-
zh: `agent 想把 ${what()} 加到**这个项目**的面板上。允许吗?`
|
|
1035
|
-
},
|
|
1036
|
-
question: {
|
|
1037
|
-
en: `it adds ${what()} to this project's panel. Allow?`,
|
|
1038
|
-
zh: `会把 ${what()} 加到**这个项目**的面板上。允许吗?`
|
|
1039
|
-
}
|
|
1040
|
-
});
|
|
1041
|
-
}
|
|
1042
905
|
async function approvalFor(call, context = {}) {
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
906
|
+
if (context.writes !== true) return void 0;
|
|
907
|
+
let verdict;
|
|
908
|
+
try {
|
|
909
|
+
verdict = context.policy?.(call);
|
|
910
|
+
} catch (error) {
|
|
1047
911
|
return {
|
|
1048
912
|
kind: "deny",
|
|
1049
|
-
reason:
|
|
913
|
+
reason: `问"要不要审批"的时候套件的策略抛了错,已经停下:${messageOf(error)}`
|
|
1050
914
|
};
|
|
1051
915
|
}
|
|
1052
|
-
|
|
916
|
+
if (verdict?.kind === "read") return void 0;
|
|
917
|
+
if (verdict?.kind !== "ask") return {
|
|
918
|
+
kind: "deny",
|
|
919
|
+
reason: `${call.name ?? "这把工具"} 在清单里声明会写东西,但它的套件没认领这次调用 —— 停下:在套件的 needsApproval 里补一条审批(含"这次会发生什么"),别让写静默过去`
|
|
920
|
+
};
|
|
1053
921
|
let facts;
|
|
1054
922
|
try {
|
|
1055
923
|
facts = await context.detailOf?.(call);
|
|
1056
924
|
} catch (error) {
|
|
1057
925
|
return {
|
|
1058
926
|
kind: "deny",
|
|
1059
|
-
reason: `拿不到"这次会发生什么",已经停下:${
|
|
927
|
+
reason: `拿不到"这次会发生什么",已经停下:${messageOf(error)}`
|
|
1060
928
|
};
|
|
1061
929
|
}
|
|
1062
930
|
if (facts !== void 0 && "blocked" in facts) return {
|
|
@@ -1065,8 +933,8 @@ async function approvalFor(call, context = {}) {
|
|
|
1065
933
|
};
|
|
1066
934
|
return {
|
|
1067
935
|
kind: "ask",
|
|
1068
|
-
reason:
|
|
1069
|
-
displayReason: compose(facts,
|
|
936
|
+
reason: verdict.reason,
|
|
937
|
+
displayReason: compose(facts, verdict)
|
|
1070
938
|
};
|
|
1071
939
|
}
|
|
1072
940
|
//#endregion
|
|
@@ -1588,6 +1456,101 @@ function createRegistryNotebook(dir) {
|
|
|
1588
1456
|
}
|
|
1589
1457
|
};
|
|
1590
1458
|
}
|
|
1459
|
+
var panelsUnit = {
|
|
1460
|
+
id: "panels",
|
|
1461
|
+
kind: "ui",
|
|
1462
|
+
card: null,
|
|
1463
|
+
tools: [{
|
|
1464
|
+
name: "workbench_panels",
|
|
1465
|
+
writes: true
|
|
1466
|
+
}, {
|
|
1467
|
+
name: "workbench_modules",
|
|
1468
|
+
writes: true
|
|
1469
|
+
}],
|
|
1470
|
+
host: {
|
|
1471
|
+
inject: [],
|
|
1472
|
+
optional: ["tools", "shell"]
|
|
1473
|
+
}
|
|
1474
|
+
};
|
|
1475
|
+
//#endregion
|
|
1476
|
+
//#region src/modules/panels/model/approval.ts
|
|
1477
|
+
var READ$1 = { kind: "read" };
|
|
1478
|
+
var READ_ONLY_ACTIONS = /* @__PURE__ */ new Set(["list", ""]);
|
|
1479
|
+
function actionOf$1(call) {
|
|
1480
|
+
const raw = call.arguments;
|
|
1481
|
+
if (typeof raw !== "object" || raw === null) return {};
|
|
1482
|
+
const value = raw;
|
|
1483
|
+
return {
|
|
1484
|
+
...typeof value.action === "string" ? { action: value.action } : {},
|
|
1485
|
+
...typeof value.id === "string" ? { id: value.id } : typeof value.unit === "string" ? { id: value.unit } : {}
|
|
1486
|
+
};
|
|
1487
|
+
}
|
|
1488
|
+
function whatOf(id) {
|
|
1489
|
+
if (id === void 0 || id === "") return "一个模块";
|
|
1490
|
+
return `「${id}」`;
|
|
1491
|
+
}
|
|
1492
|
+
function askOf(reason, question, fallback) {
|
|
1493
|
+
return {
|
|
1494
|
+
kind: "ask",
|
|
1495
|
+
reason,
|
|
1496
|
+
question,
|
|
1497
|
+
fallback
|
|
1498
|
+
};
|
|
1499
|
+
}
|
|
1500
|
+
var panelsApproval = (call) => {
|
|
1501
|
+
const { action, id } = actionOf$1(call);
|
|
1502
|
+
const readAction = action !== void 0 && action !== "" && READ_ONLY_ACTIONS.has(action);
|
|
1503
|
+
const what = whatOf(id);
|
|
1504
|
+
if (call.name === "workbench_modules") {
|
|
1505
|
+
if (readAction) return READ$1;
|
|
1506
|
+
if (action === "update-dependency") return askOf(`workbench_modules update-dependency ${id ?? ""} upgrades a shared dependency on this machine`, {
|
|
1507
|
+
en: "it upgrades that shared dependency on this machine. Allow?",
|
|
1508
|
+
zh: `会升级共用依赖 ${what}。允许吗?`
|
|
1509
|
+
}, {
|
|
1510
|
+
en: `The agent wants to upgrade the shared dependency ${what} (it changes what is installed on this machine). Allow?`,
|
|
1511
|
+
zh: `agent 想升级共用依赖 ${what}(会改这台机器上装的东西)。允许吗?`
|
|
1512
|
+
});
|
|
1513
|
+
const verb = action === "install" ? "装" : action === "uninstall" ? "卸载" : action === "update" ? "更新" : "装 / 更新 / 卸载";
|
|
1514
|
+
const verbEn = verb === "装" ? "install" : verb === "卸载" ? "remove" : verb === "更新" ? "update" : "install/update/remove";
|
|
1515
|
+
return askOf(`workbench_modules ${action ?? "(unknown action)"} ${id ?? ""} changes plugins on this machine`.trim(), {
|
|
1516
|
+
en: "it changes plugins on this machine. Allow?",
|
|
1517
|
+
zh: "会改这台机器上的插件。允许吗?"
|
|
1518
|
+
}, {
|
|
1519
|
+
en: `The agent wants to ${verbEn} the module ${what} (it changes plugins on this machine). Allow?`,
|
|
1520
|
+
zh: `agent 想${verb}模块 ${what}(会改这台机器上的插件)。允许吗?`
|
|
1521
|
+
});
|
|
1522
|
+
}
|
|
1523
|
+
if (call.name !== "workbench_panels") return void 0;
|
|
1524
|
+
if (readAction) return READ$1;
|
|
1525
|
+
if (action === "hide") return askOf("workbench_panels hide removes a module from the panel", {
|
|
1526
|
+
en: "it takes that module off this panel (its agent tools go offline here too). Allow?",
|
|
1527
|
+
zh: `${what}会从这个项目的面板上收起来(这个项目里它的 agent 工具也一起下线)。允许吗?`
|
|
1528
|
+
}, {
|
|
1529
|
+
en: `The agent wants to remove ${what} from this project's panel (its agent tools go offline here too). Allow?`,
|
|
1530
|
+
zh: `agent 想把 ${what} 从这个项目的面板上收起来(这个项目里它的 agent 工具也一起下线)。允许吗?`
|
|
1531
|
+
});
|
|
1532
|
+
if (action === "move") return askOf("workbench_panels move reorders the panel", {
|
|
1533
|
+
en: `it reorders this panel (${what} goes first). Allow?`,
|
|
1534
|
+
zh: `会调整这个项目面板的顺序(${what}放前面)。允许吗?`
|
|
1535
|
+
}, {
|
|
1536
|
+
en: `The agent wants to reorder this project's panel (put ${what} first). Allow?`,
|
|
1537
|
+
zh: `agent 想调整这个项目面板的顺序(把 ${what} 放前面)。允许吗?`
|
|
1538
|
+
});
|
|
1539
|
+
if (action === "reset") return askOf("workbench_panels reset clears the panel", {
|
|
1540
|
+
en: "it clears this panel (every module goes offline here). Allow?",
|
|
1541
|
+
zh: "会清空这个项目的面板(所有模块在这个项目里都下线)。允许吗?"
|
|
1542
|
+
}, {
|
|
1543
|
+
en: "The agent wants to clear this project's panel (every module goes offline here). Allow?",
|
|
1544
|
+
zh: "agent 想清空这个项目的面板(所有模块在这个项目里都下线)。允许吗?"
|
|
1545
|
+
});
|
|
1546
|
+
return askOf(`workbench_panels ${action ?? "(unknown action)"} changes the user's panel`, {
|
|
1547
|
+
en: `it adds ${what} to this project's panel. Allow?`,
|
|
1548
|
+
zh: `会把 ${what} 加到**这个项目**的面板上。允许吗?`
|
|
1549
|
+
}, {
|
|
1550
|
+
en: `The agent wants to add ${what} to this project's panel. Allow?`,
|
|
1551
|
+
zh: `agent 想把 ${what} 加到**这个项目**的面板上。允许吗?`
|
|
1552
|
+
});
|
|
1553
|
+
};
|
|
1591
1554
|
//#endregion
|
|
1592
1555
|
//#region src/shared/api/host/release.ts
|
|
1593
1556
|
function parseLedgerVersion(stdout, name) {
|
|
@@ -2432,22 +2395,6 @@ function applyPanelsPref(panels, payload) {
|
|
|
2432
2395
|
units: panels.move(action.id, action.index ?? 0, path)
|
|
2433
2396
|
};
|
|
2434
2397
|
}
|
|
2435
|
-
var panelsUnit = {
|
|
2436
|
-
id: "panels",
|
|
2437
|
-
kind: "ui",
|
|
2438
|
-
card: null,
|
|
2439
|
-
tools: [{
|
|
2440
|
-
name: "workbench_panels",
|
|
2441
|
-
writes: true
|
|
2442
|
-
}, {
|
|
2443
|
-
name: "workbench_modules",
|
|
2444
|
-
writes: true
|
|
2445
|
-
}],
|
|
2446
|
-
host: {
|
|
2447
|
-
inject: [],
|
|
2448
|
-
optional: ["tools", "shell"]
|
|
2449
|
-
}
|
|
2450
|
-
};
|
|
2451
2398
|
//#endregion
|
|
2452
2399
|
//#region src/modules/panels/model/handoff.ts
|
|
2453
2400
|
var PANELS_FACT = "panels";
|
|
@@ -2843,6 +2790,7 @@ var HOST_UNITS = [{
|
|
|
2843
2790
|
routes: panelRoutes(panels, values),
|
|
2844
2791
|
registerTools: () => [...registerPanelTools(ctx, panels, values), ...registerMarketTools(ctx, market)],
|
|
2845
2792
|
factsOf: (call) => panelsFactsOf(call, manifests()),
|
|
2793
|
+
needsApproval: panelsApproval,
|
|
2846
2794
|
gate: {
|
|
2847
2795
|
deniedTools: (workspace) => manifests().filter((manifest) => manifest.card !== null).filter((manifest) => !panels.isEnabled(manifest.id, workspace)).flatMap((manifest) => manifest.tools.map((tool) => tool.name)),
|
|
2848
2796
|
subscribe: (listener) => panels.subscribe(listener)
|
|
@@ -3094,6 +3042,21 @@ function bundleInspectHandler(ctx) {
|
|
|
3094
3042
|
};
|
|
3095
3043
|
}
|
|
3096
3044
|
//#endregion
|
|
3045
|
+
//#region src/shared/api/diy.ts
|
|
3046
|
+
var WORKSHOP_TITLE = "工作台DIY";
|
|
3047
|
+
//#endregion
|
|
3048
|
+
//#region src/shared/api/host/diy.ts
|
|
3049
|
+
var WORKSHOP_RELATIVE = "workbench/diy";
|
|
3050
|
+
function workshopPathOf(ctx) {
|
|
3051
|
+
const homePath = ctx.get("dshHomePath");
|
|
3052
|
+
if (typeof homePath !== "function") return null;
|
|
3053
|
+
try {
|
|
3054
|
+
return homePath(WORKSHOP_RELATIVE);
|
|
3055
|
+
} catch {
|
|
3056
|
+
return null;
|
|
3057
|
+
}
|
|
3058
|
+
}
|
|
3059
|
+
//#endregion
|
|
3097
3060
|
//#region src/shared/api/dsh-plugins.ts
|
|
3098
3061
|
var DSH_PLUGINS_ROUTE = "dsh-plugins";
|
|
3099
3062
|
//#endregion
|
|
@@ -3788,16 +3751,43 @@ function withRunsRoute(result, unit) {
|
|
|
3788
3751
|
}
|
|
3789
3752
|
};
|
|
3790
3753
|
}
|
|
3791
|
-
function
|
|
3754
|
+
function failureReasonOf(error) {
|
|
3755
|
+
if (error instanceof Error) return error.message;
|
|
3756
|
+
return typeof error === "string" ? error : String(error);
|
|
3757
|
+
}
|
|
3758
|
+
function fail(ledger, item, reason) {
|
|
3759
|
+
ledger.failed.add(item);
|
|
3760
|
+
ledger.failures.push({
|
|
3761
|
+
id: item.face.manifest.id,
|
|
3762
|
+
reason
|
|
3763
|
+
});
|
|
3764
|
+
}
|
|
3765
|
+
function collectRoutes(mounted, ledger) {
|
|
3792
3766
|
const routes = {};
|
|
3793
3767
|
const owner = /* @__PURE__ */ new Map();
|
|
3794
3768
|
const routesOfUnit = /* @__PURE__ */ new Map();
|
|
3795
3769
|
for (const item of mounted) {
|
|
3770
|
+
if (ledger.failed.has(item)) continue;
|
|
3796
3771
|
const unit = item.face.manifest.id;
|
|
3772
|
+
const accepted = [];
|
|
3773
|
+
let problem;
|
|
3797
3774
|
for (const [key, handler] of Object.entries(item.result.routes)) {
|
|
3798
|
-
if (key !== unit && !key.startsWith(`${unit}/`))
|
|
3775
|
+
if (key !== unit && !key.startsWith(`${unit}/`)) {
|
|
3776
|
+
problem = `路由名要住在自己那一格的命名空间里(${unit} 或 ${unit}/…):${key} 不属于 ${unit} —— 装 / 升 / 卸时点名不到它,那个模块的数据会停在旧值`;
|
|
3777
|
+
break;
|
|
3778
|
+
}
|
|
3799
3779
|
const previous = owner.get(key);
|
|
3800
|
-
if (previous !== void 0)
|
|
3780
|
+
if (previous !== void 0) {
|
|
3781
|
+
problem = `路由名冲突:${key} 由套件 ${previous} 与 ${unit} 同时声明`;
|
|
3782
|
+
break;
|
|
3783
|
+
}
|
|
3784
|
+
accepted.push([key, handler]);
|
|
3785
|
+
}
|
|
3786
|
+
if (problem !== void 0) {
|
|
3787
|
+
fail(ledger, item, problem);
|
|
3788
|
+
continue;
|
|
3789
|
+
}
|
|
3790
|
+
for (const [key, handler] of accepted) {
|
|
3801
3791
|
owner.set(key, unit);
|
|
3802
3792
|
routes[key] = handler;
|
|
3803
3793
|
const own = routesOfUnit.get(unit);
|
|
@@ -3811,45 +3801,64 @@ function collectRoutes(mounted) {
|
|
|
3811
3801
|
routesOfUnit
|
|
3812
3802
|
};
|
|
3813
3803
|
}
|
|
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) {
|
|
3804
|
+
function collectNamed(mounted, ledger, pickMany, label) {
|
|
3825
3805
|
const owner = /* @__PURE__ */ new Map();
|
|
3826
|
-
const
|
|
3806
|
+
const out = [];
|
|
3827
3807
|
for (const item of mounted) {
|
|
3828
|
-
|
|
3829
|
-
|
|
3830
|
-
const
|
|
3831
|
-
if (
|
|
3832
|
-
owner.
|
|
3833
|
-
|
|
3834
|
-
|
|
3835
|
-
|
|
3836
|
-
}
|
|
3808
|
+
if (ledger.failed.has(item)) continue;
|
|
3809
|
+
const unit = item.face.manifest.id;
|
|
3810
|
+
const entries = pickMany(item);
|
|
3811
|
+
if (entries.length === 0) continue;
|
|
3812
|
+
const clash = entries.find((entry) => owner.has(entry.resource));
|
|
3813
|
+
if (clash !== void 0) {
|
|
3814
|
+
fail(ledger, item, `${label}名冲突:${clash.resource} 由套件 ${owner.get(clash.resource)} 与 ${unit} 同时声明`);
|
|
3815
|
+
continue;
|
|
3816
|
+
}
|
|
3817
|
+
for (const entry of entries) {
|
|
3818
|
+
owner.set(entry.resource, unit);
|
|
3819
|
+
out.push({
|
|
3820
|
+
...entry,
|
|
3821
|
+
unit
|
|
3822
|
+
});
|
|
3823
|
+
}
|
|
3837
3824
|
}
|
|
3838
|
-
return
|
|
3825
|
+
return out;
|
|
3839
3826
|
}
|
|
3840
|
-
function
|
|
3827
|
+
function collectContextRenderers(mounted, ledger) {
|
|
3828
|
+
const table = /* @__PURE__ */ new Map();
|
|
3841
3829
|
const owner = /* @__PURE__ */ new Map();
|
|
3842
|
-
const
|
|
3843
|
-
|
|
3844
|
-
const
|
|
3845
|
-
|
|
3846
|
-
|
|
3847
|
-
|
|
3848
|
-
|
|
3849
|
-
|
|
3850
|
-
|
|
3830
|
+
for (const item of mounted) {
|
|
3831
|
+
if (ledger.failed.has(item)) continue;
|
|
3832
|
+
const unit = item.face.manifest.id;
|
|
3833
|
+
const context = item.result.context;
|
|
3834
|
+
if (context === void 0) continue;
|
|
3835
|
+
const clash = context.kinds.find((kind) => owner.has(kind));
|
|
3836
|
+
if (clash !== void 0) {
|
|
3837
|
+
fail(ledger, item, `对话引用的 kind 冲突:${clash} 由套件 ${owner.get(clash)} 与 ${unit} 同时认领`);
|
|
3838
|
+
continue;
|
|
3839
|
+
}
|
|
3840
|
+
for (const kind of context.kinds) {
|
|
3841
|
+
owner.set(kind, unit);
|
|
3842
|
+
table.set(kind, (ref) => context.render(ref));
|
|
3843
|
+
}
|
|
3844
|
+
}
|
|
3845
|
+
return table;
|
|
3846
|
+
}
|
|
3847
|
+
function pickProvider(mounted, ledger, pick, label) {
|
|
3848
|
+
let chosen;
|
|
3849
|
+
let chosenBy;
|
|
3850
|
+
for (const item of mounted) {
|
|
3851
|
+
if (ledger.failed.has(item)) continue;
|
|
3852
|
+
const value = pick(item);
|
|
3853
|
+
if (value === void 0) continue;
|
|
3854
|
+
if (chosen === void 0) {
|
|
3855
|
+
chosen = value;
|
|
3856
|
+
chosenBy = item.face.manifest.id;
|
|
3857
|
+
continue;
|
|
3858
|
+
}
|
|
3859
|
+
fail(ledger, item, `${label}只能有一个提供者,现在是:${chosenBy}、${item.face.manifest.id}`);
|
|
3851
3860
|
}
|
|
3852
|
-
return
|
|
3861
|
+
return chosen;
|
|
3853
3862
|
}
|
|
3854
3863
|
function collectWarmReads(mounted) {
|
|
3855
3864
|
const declarations = mounted.map((item) => item.result.warmReads).filter((declare) => declare !== void 0);
|
|
@@ -3865,26 +3874,15 @@ function collectWarmReads(mounted) {
|
|
|
3865
3874
|
return reads;
|
|
3866
3875
|
};
|
|
3867
3876
|
}
|
|
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
3877
|
function mountUnits(faces, deps) {
|
|
3884
3878
|
const store = deps.store ?? createWorkspaceStore({ root: null });
|
|
3885
3879
|
const mounted = [];
|
|
3886
3880
|
const skipped = [];
|
|
3887
|
-
const longTaskDisposers =
|
|
3881
|
+
const longTaskDisposers = /* @__PURE__ */ new Map();
|
|
3882
|
+
const ledger = {
|
|
3883
|
+
failed: /* @__PURE__ */ new Set(),
|
|
3884
|
+
failures: []
|
|
3885
|
+
};
|
|
3888
3886
|
for (const face of faces) {
|
|
3889
3887
|
const readiness = unitReadiness(face.manifest, (dep) => deps.ctx.get(dep));
|
|
3890
3888
|
if (!readiness.canMount) {
|
|
@@ -3900,48 +3898,71 @@ function mountUnits(faces, deps) {
|
|
|
3900
3898
|
unit,
|
|
3901
3899
|
bump: deps.longTasks.bump
|
|
3902
3900
|
});
|
|
3903
|
-
|
|
3904
|
-
|
|
3905
|
-
|
|
3906
|
-
|
|
3907
|
-
|
|
3908
|
-
|
|
3909
|
-
|
|
3910
|
-
|
|
3911
|
-
|
|
3912
|
-
|
|
3913
|
-
|
|
3914
|
-
|
|
3901
|
+
let result;
|
|
3902
|
+
try {
|
|
3903
|
+
result = face.mount({
|
|
3904
|
+
ctx: deps.ctx,
|
|
3905
|
+
logger: deps.logger,
|
|
3906
|
+
manifests: deps.manifests,
|
|
3907
|
+
...deps.opencliCommand === void 0 ? {} : { opencliCommand: deps.opencliCommand },
|
|
3908
|
+
...deps.probe === void 0 ? {} : { probe: deps.probe },
|
|
3909
|
+
...deps.values === void 0 ? {} : { values: deps.values },
|
|
3910
|
+
...longTasks === void 0 ? {} : { longTasks: longTasks.host },
|
|
3911
|
+
store
|
|
3912
|
+
});
|
|
3913
|
+
} catch (error) {
|
|
3914
|
+
longTasks?.dispose();
|
|
3915
|
+
ledger.failures.push({
|
|
3916
|
+
id: unit,
|
|
3917
|
+
reason: failureReasonOf(error)
|
|
3918
|
+
});
|
|
3919
|
+
continue;
|
|
3920
|
+
}
|
|
3921
|
+
const item = {
|
|
3915
3922
|
face,
|
|
3916
3923
|
readiness,
|
|
3917
3924
|
result: withRunsRoute(result, unit)
|
|
3918
|
-
}
|
|
3925
|
+
};
|
|
3926
|
+
mounted.push(item);
|
|
3927
|
+
if (longTasks !== void 0) longTaskDisposers.set(item, longTasks.dispose);
|
|
3919
3928
|
}
|
|
3920
|
-
const collected = collectRoutes(mounted);
|
|
3921
|
-
const prefs =
|
|
3922
|
-
const actions =
|
|
3929
|
+
const collected = collectRoutes(mounted, ledger);
|
|
3930
|
+
const prefs = collectNamed(mounted, ledger, (item) => item.result.prefs === void 0 ? [] : [item.result.prefs], "偏好资源");
|
|
3931
|
+
const actions = collectNamed(mounted, ledger, (item) => item.result.actions ?? [], "动作资源");
|
|
3923
3932
|
const owners = new Map(collected.owners);
|
|
3924
3933
|
for (const entry of [...prefs, ...actions]) owners.set(entry.resource, entry.unit);
|
|
3925
3934
|
const factsOf = /* @__PURE__ */ new Map();
|
|
3926
3935
|
for (const item of mounted) {
|
|
3936
|
+
if (ledger.failed.has(item)) continue;
|
|
3927
3937
|
const declare = item.result.factsOf;
|
|
3928
3938
|
if (declare !== void 0) factsOf.set(item.face.manifest.id, declare);
|
|
3929
3939
|
}
|
|
3940
|
+
const gate = pickProvider(mounted, ledger, (item) => item.result.gate, "启停闸门");
|
|
3941
|
+
const provision = pickProvider(mounted, ledger, (item) => item.result.provision, "机器供给");
|
|
3942
|
+
const contextRenderers = collectContextRenderers(mounted, ledger);
|
|
3943
|
+
const alive = mounted.filter((item) => !ledger.failed.has(item));
|
|
3944
|
+
for (const item of mounted) {
|
|
3945
|
+
if (!ledger.failed.has(item)) continue;
|
|
3946
|
+
longTaskDisposers.get(item)?.();
|
|
3947
|
+
longTaskDisposers.delete(item);
|
|
3948
|
+
}
|
|
3930
3949
|
return {
|
|
3931
|
-
mounted,
|
|
3950
|
+
mounted: alive,
|
|
3932
3951
|
routes: collected.routes,
|
|
3933
3952
|
owners,
|
|
3934
3953
|
routesOfUnit: collected.routesOfUnit,
|
|
3935
3954
|
factsOf,
|
|
3936
|
-
gate
|
|
3955
|
+
gate,
|
|
3937
3956
|
prefs,
|
|
3938
3957
|
actions,
|
|
3939
|
-
provision
|
|
3940
|
-
contextRenderers
|
|
3958
|
+
provision,
|
|
3959
|
+
contextRenderers,
|
|
3941
3960
|
skipped,
|
|
3942
|
-
|
|
3961
|
+
failed: ledger.failures,
|
|
3962
|
+
warmReads: collectWarmReads(alive),
|
|
3943
3963
|
disposeLongTasks: () => {
|
|
3944
|
-
for (const dispose of longTaskDisposers.
|
|
3964
|
+
for (const dispose of [...longTaskDisposers.values()]) dispose();
|
|
3965
|
+
longTaskDisposers.clear();
|
|
3945
3966
|
}
|
|
3946
3967
|
};
|
|
3947
3968
|
}
|
|
@@ -3978,6 +3999,54 @@ function createUnitRegistry() {
|
|
|
3978
3999
|
};
|
|
3979
4000
|
}
|
|
3980
4001
|
//#endregion
|
|
4002
|
+
//#region src/shared/api/host/approval-legacy.ts
|
|
4003
|
+
var READ = { kind: "read" };
|
|
4004
|
+
function confirmed(call) {
|
|
4005
|
+
const raw = call.arguments;
|
|
4006
|
+
if (typeof raw !== "object" || raw === null) return void 0;
|
|
4007
|
+
const value = raw.confirm;
|
|
4008
|
+
return typeof value === "boolean" ? value : void 0;
|
|
4009
|
+
}
|
|
4010
|
+
var legacyApproval = (call) => {
|
|
4011
|
+
const name = call.name ?? "";
|
|
4012
|
+
if (name === "workbench_cmdb_release") {
|
|
4013
|
+
if (confirmed(call) !== true) return READ;
|
|
4014
|
+
return {
|
|
4015
|
+
kind: "ask",
|
|
4016
|
+
reason: "confirm=true releases a version to a real environment",
|
|
4017
|
+
question: {
|
|
4018
|
+
en: "it deploys on the platform for real (non-production). Allow?",
|
|
4019
|
+
zh: "会在平台上真的部署一次(非生产环境)。允许吗?"
|
|
4020
|
+
},
|
|
4021
|
+
fallback: {
|
|
4022
|
+
en: "The agent wants to deploy a version for real (confirm: true) — it deploys on the platform (non-production). Allow?",
|
|
4023
|
+
zh: "agent 想在非生产环境上**真的部署一个版本**(confirm: true)—— 会在平台上部署。允许吗?"
|
|
4024
|
+
}
|
|
4025
|
+
};
|
|
4026
|
+
}
|
|
4027
|
+
if (name !== "workbench_coding_issue_comment" && name !== "workbench_coding_issue_transfer") return void 0;
|
|
4028
|
+
if (confirmed(call) !== true) return READ;
|
|
4029
|
+
const comment = name === "workbench_coding_issue_comment";
|
|
4030
|
+
return {
|
|
4031
|
+
kind: "ask",
|
|
4032
|
+
reason: comment ? "confirm=true posts a comment on the platform" : "confirm=true moves an issue to another status on the platform",
|
|
4033
|
+
question: comment ? {
|
|
4034
|
+
en: "it posts that comment on the platform for real. Allow?",
|
|
4035
|
+
zh: "会在平台上真的发表这条评论。允许吗?"
|
|
4036
|
+
} : {
|
|
4037
|
+
en: "it changes that issue status on the platform for real. Allow?",
|
|
4038
|
+
zh: "会在平台上真的改这条缺陷的状态。允许吗?"
|
|
4039
|
+
},
|
|
4040
|
+
fallback: comment ? {
|
|
4041
|
+
en: "The agent wants to post a comment on the platform for real (confirm: true) — it writes on the platform. Allow?",
|
|
4042
|
+
zh: "agent 想**真的给一条缺陷加评论**(confirm: true)—— 会写平台数据。允许吗?"
|
|
4043
|
+
} : {
|
|
4044
|
+
en: "The agent wants to move an issue to another status for real (confirm: true) — it writes on the platform. Allow?",
|
|
4045
|
+
zh: "agent 想**真的把一条缺陷流转到别的状态**(confirm: true)—— 会写平台数据。允许吗?"
|
|
4046
|
+
}
|
|
4047
|
+
};
|
|
4048
|
+
};
|
|
4049
|
+
//#endregion
|
|
3981
4050
|
//#region src/shared/api/host/tool-scope.ts
|
|
3982
4051
|
function agentOf(value) {
|
|
3983
4052
|
return typeof value === "object" && value !== null ? value : void 0;
|
|
@@ -4082,6 +4151,14 @@ function apply(ctx) {
|
|
|
4082
4151
|
const units = createUnitRegistry();
|
|
4083
4152
|
ctx.provide(UNITS_SERVICE, units);
|
|
4084
4153
|
assembleHostUnits(units);
|
|
4154
|
+
ctx.inject(["workspaceRegistry"], (scoped) => {
|
|
4155
|
+
const registry = scoped.get("workspaceRegistry");
|
|
4156
|
+
const workshop = workshopPathOf(scoped);
|
|
4157
|
+
if (registry === void 0 || workshop === null) return;
|
|
4158
|
+
registry.create(workshop, WORKSHOP_TITLE).catch((error) => {
|
|
4159
|
+
ctx.logger?.warn?.(`dsh-workbench: 工坊没能登记成工作区 —— ${String(error)}`);
|
|
4160
|
+
});
|
|
4161
|
+
});
|
|
4085
4162
|
const opencliEnv = process.env.DSH_WORKBENCH_OPENCLI;
|
|
4086
4163
|
const installEnv = process.env.DSH_WORKBENCH_OPENCLI_INSTALL;
|
|
4087
4164
|
const liveManifests = () => units.manifests();
|
|
@@ -4116,6 +4193,7 @@ function apply(ctx) {
|
|
|
4116
4193
|
logger: ctx.logger
|
|
4117
4194
|
});
|
|
4118
4195
|
const mounted = /* @__PURE__ */ new Map();
|
|
4196
|
+
const mountFailures = /* @__PURE__ */ new Map();
|
|
4119
4197
|
const factsOfMap = /* @__PURE__ */ new Map();
|
|
4120
4198
|
const routesOfUnitMap = /* @__PURE__ */ new Map();
|
|
4121
4199
|
const ownersMap = /* @__PURE__ */ new Map();
|
|
@@ -4127,6 +4205,7 @@ function apply(ctx) {
|
|
|
4127
4205
|
const item = mounted.get(id);
|
|
4128
4206
|
if (item === void 0) return;
|
|
4129
4207
|
mounted.delete(id);
|
|
4208
|
+
mountFailures.delete(id);
|
|
4130
4209
|
for (const dispose of item.toolDisposers) dispose?.();
|
|
4131
4210
|
item.gateOff?.();
|
|
4132
4211
|
item.plan.disposeLongTasks();
|
|
@@ -4137,34 +4216,72 @@ function apply(ctx) {
|
|
|
4137
4216
|
for (const resource of item.plan.owners.keys()) ownersMap.delete(resource);
|
|
4138
4217
|
}
|
|
4139
4218
|
function mountUnit(face) {
|
|
4140
|
-
const
|
|
4141
|
-
|
|
4142
|
-
|
|
4143
|
-
|
|
4144
|
-
|
|
4145
|
-
|
|
4146
|
-
|
|
4147
|
-
|
|
4148
|
-
|
|
4149
|
-
|
|
4150
|
-
|
|
4151
|
-
|
|
4152
|
-
|
|
4219
|
+
const id = face.manifest.id;
|
|
4220
|
+
let one;
|
|
4221
|
+
try {
|
|
4222
|
+
one = mountUnits([face], {
|
|
4223
|
+
ctx,
|
|
4224
|
+
logger: ctx.logger,
|
|
4225
|
+
manifests: liveManifests,
|
|
4226
|
+
store,
|
|
4227
|
+
...opencliEnv === void 0 ? {} : { opencliCommand: opencliEnv },
|
|
4228
|
+
probe: (unit, options) => probeOne(unit, options?.force ?? false),
|
|
4229
|
+
values,
|
|
4230
|
+
longTasks: {
|
|
4231
|
+
scope: process.env["DSH_HOME"] ?? "",
|
|
4232
|
+
bump: (names) => facts.bump(names)
|
|
4233
|
+
}
|
|
4234
|
+
});
|
|
4235
|
+
} catch (error) {
|
|
4236
|
+
mountFailures.set(id, {
|
|
4237
|
+
reason: failureReasonOf(error),
|
|
4238
|
+
face
|
|
4239
|
+
});
|
|
4240
|
+
ctx.logger?.warn?.(`[dsh-workbench] ${id} 套件起不来(装配期):${failureReasonOf(error)}`);
|
|
4241
|
+
return;
|
|
4242
|
+
}
|
|
4153
4243
|
for (const item of one.skipped) ctx.logger?.warn?.(`[dsh-workbench] ${item.id} 套件缺硬依赖,跳过:${item.missing.join(", ")}`);
|
|
4244
|
+
for (const failure of one.failed) {
|
|
4245
|
+
mountFailures.set(failure.id, {
|
|
4246
|
+
reason: failure.reason,
|
|
4247
|
+
face
|
|
4248
|
+
});
|
|
4249
|
+
ctx.logger?.warn?.(`[dsh-workbench] ${failure.id} 套件起不来,已摘掉它这一份:${failure.reason}`);
|
|
4250
|
+
}
|
|
4154
4251
|
const slot = one.mounted[0];
|
|
4155
|
-
if (slot === void 0)
|
|
4252
|
+
if (slot === void 0) {
|
|
4253
|
+
one.disposeLongTasks();
|
|
4254
|
+
return;
|
|
4255
|
+
}
|
|
4156
4256
|
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
|
-
|
|
4257
|
+
const added = [];
|
|
4258
|
+
try {
|
|
4259
|
+
Object.assign(routes, one.routes);
|
|
4260
|
+
added.push(...Object.keys(one.routes));
|
|
4261
|
+
for (const [kind, render] of one.contextRenderers) renderers.set(kind, render);
|
|
4262
|
+
for (const [unit, fn] of one.factsOf) factsOfMap.set(unit, fn);
|
|
4263
|
+
for (const [unit, list] of one.routesOfUnit) routesOfUnitMap.set(unit, list);
|
|
4264
|
+
for (const [resource, unit] of one.owners) ownersMap.set(resource, unit);
|
|
4265
|
+
mounted.set(face.manifest.id, {
|
|
4266
|
+
result: slot.result,
|
|
4267
|
+
plan: one,
|
|
4268
|
+
toolDisposers: slot.result.registerTools(),
|
|
4269
|
+
gateOff: one.gate?.subscribe(() => toolScope.reapply())
|
|
4270
|
+
});
|
|
4271
|
+
mountFailures.delete(id);
|
|
4272
|
+
} catch (error) {
|
|
4273
|
+
for (const route of added) delete routes[route];
|
|
4274
|
+
for (const kind of one.contextRenderers.keys()) renderers.delete(kind);
|
|
4275
|
+
for (const unit of one.factsOf.keys()) factsOfMap.delete(unit);
|
|
4276
|
+
for (const unit of one.routesOfUnit.keys()) routesOfUnitMap.delete(unit);
|
|
4277
|
+
for (const [resource, unit] of one.owners) if (ownersMap.get(resource) === unit) ownersMap.delete(resource);
|
|
4278
|
+
one.disposeLongTasks();
|
|
4279
|
+
mountFailures.set(id, {
|
|
4280
|
+
reason: failureReasonOf(error),
|
|
4281
|
+
face
|
|
4282
|
+
});
|
|
4283
|
+
ctx.logger?.warn?.(`[dsh-workbench] ${id} 套件起不来(注册期):${failureReasonOf(error)}`);
|
|
4284
|
+
}
|
|
4168
4285
|
}
|
|
4169
4286
|
function rebindPost() {
|
|
4170
4287
|
for (const dispose of undoPost.reverse()) dispose?.();
|
|
@@ -4187,7 +4304,13 @@ function apply(ctx) {
|
|
|
4187
4304
|
function sync() {
|
|
4188
4305
|
const present = new Set(units.all().map((face) => face.manifest.id));
|
|
4189
4306
|
for (const id of [...mounted.keys()]) if (!present.has(id)) unmountUnit(id);
|
|
4190
|
-
for (const
|
|
4307
|
+
for (const id of [...mountFailures.keys()]) if (!present.has(id)) mountFailures.delete(id);
|
|
4308
|
+
for (const face of units.all()) {
|
|
4309
|
+
if (mounted.has(face.manifest.id)) continue;
|
|
4310
|
+
const already = mountFailures.get(face.manifest.id);
|
|
4311
|
+
if (already !== void 0 && already.face === face) continue;
|
|
4312
|
+
mountUnit(face);
|
|
4313
|
+
}
|
|
4191
4314
|
rebindPost();
|
|
4192
4315
|
}
|
|
4193
4316
|
if (shell === void 0) ctx.logger?.warn?.("[dsh-workbench] 没有 shell 服务:需要执行缝的套件会降级");
|
|
@@ -4209,6 +4332,14 @@ function apply(ctx) {
|
|
|
4209
4332
|
...item,
|
|
4210
4333
|
released: releasedOf(item.unit)
|
|
4211
4334
|
})) };
|
|
4335
|
+
const failure = mountFailures.get(unit);
|
|
4336
|
+
if (failure !== void 0) return {
|
|
4337
|
+
unit,
|
|
4338
|
+
status: "failed",
|
|
4339
|
+
required: [],
|
|
4340
|
+
missing: [],
|
|
4341
|
+
detail: failure.reason
|
|
4342
|
+
};
|
|
4212
4343
|
return probeOne(unit, force);
|
|
4213
4344
|
});
|
|
4214
4345
|
}
|
|
@@ -4253,20 +4384,19 @@ function apply(ctx) {
|
|
|
4253
4384
|
const off = ctx.on?.("tools/pre-execute", async (exec, next) => {
|
|
4254
4385
|
const decision = await next();
|
|
4255
4386
|
if (decision.kind !== "allow") return decision;
|
|
4256
|
-
const
|
|
4257
|
-
|
|
4258
|
-
|
|
4259
|
-
|
|
4260
|
-
}
|
|
4261
|
-
};
|
|
4387
|
+
const name = exec.name === void 0 ? void 0 : String(exec.name);
|
|
4388
|
+
const tool = name === void 0 ? void 0 : unitsOfTool().get(name);
|
|
4389
|
+
const owner = tool === void 0 ? void 0 : mounted.get(tool.unit)?.result;
|
|
4390
|
+
const detailOf = owner === void 0 ? void 0 : (call) => owner.approvalDetail?.(call);
|
|
4262
4391
|
const workspace = sessionWorkspace(exec) ?? void 0;
|
|
4263
4392
|
return await approvalFor({
|
|
4264
|
-
...
|
|
4393
|
+
...name === void 0 ? {} : { name },
|
|
4265
4394
|
arguments: exec.arguments,
|
|
4266
4395
|
...workspace === void 0 ? {} : { workspace }
|
|
4267
4396
|
}, {
|
|
4268
4397
|
detailOf,
|
|
4269
|
-
|
|
4398
|
+
policy: owner?.needsApproval ?? legacyApproval,
|
|
4399
|
+
writes: tool?.writes ?? false
|
|
4270
4400
|
}) ?? decision;
|
|
4271
4401
|
});
|
|
4272
4402
|
return () => off?.();
|