@dsh-workbench/core 0.1.16 → 0.1.17

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.
Files changed (66) hide show
  1. package/client.js +660 -128
  2. package/dist/client/client.body.js +660 -128
  3. package/dist/client/index.js +660 -128
  4. package/dist/host/index.js +1498 -263
  5. package/dist/types/app/client.d.ts +124 -9
  6. package/dist/types/app/layouts/market/add-module-text.d.ts +2 -0
  7. package/dist/types/app/layouts/market/use-add-module.d.ts +4 -3
  8. package/dist/types/app/layouts/market/use-module-versions.d.ts +2 -0
  9. package/dist/types/app/layouts/rightbar/MarketView.d.ts +3 -1
  10. package/dist/types/app/layouts/rightbar/__tests__/market-rows-plugins.test.d.ts +1 -0
  11. package/dist/types/app/layouts/rightbar/market-mock.d.ts +9 -0
  12. package/dist/types/app/layouts/rightbar/market-plugin-rows.d.ts +8 -0
  13. package/dist/types/app/layouts/rightbar/market-rows.d.ts +14 -3
  14. package/dist/types/app/layouts/rightbar/registry.d.ts +0 -1
  15. package/dist/types/app/units/__tests__/manifests.test.d.ts +1 -0
  16. package/dist/types/app/units/fixture-unit-mock.d.ts +3 -3
  17. package/dist/types/app/units/host.d.ts +2 -2
  18. package/dist/types/app/units/manifests.d.ts +5 -0
  19. package/dist/types/app/units/registry.d.ts +10 -2
  20. package/dist/types/modules/panels/__tests__/market-env.test.d.ts +1 -0
  21. package/dist/types/modules/panels/__tests__/market-plugin.test.d.ts +1 -0
  22. package/dist/types/modules/panels/__tests__/market-route.test.d.ts +1 -0
  23. package/dist/types/modules/panels/__tests__/plugin-actions.test.d.ts +1 -0
  24. package/dist/types/modules/panels/__tests__/plugin-ledger.test.d.ts +1 -0
  25. package/dist/types/modules/panels/__tests__/plugin-section.test.d.ts +1 -0
  26. package/dist/types/modules/panels/__tests__/scope.test.d.ts +1 -0
  27. package/dist/types/modules/panels/__tests__/service-release.test.d.ts +1 -0
  28. package/dist/types/modules/panels/index.d.ts +2 -2
  29. package/dist/types/modules/panels/model/config.d.ts +27 -9
  30. package/dist/types/modules/panels/model/market-dispatch.d.ts +9 -0
  31. package/dist/types/modules/panels/model/market-env.d.ts +20 -0
  32. package/dist/types/modules/panels/model/market-route.d.ts +26 -0
  33. package/dist/types/modules/panels/model/market-types.d.ts +71 -0
  34. package/dist/types/modules/panels/model/market.d.ts +7 -66
  35. package/dist/types/modules/panels/model/plugin-actions.d.ts +50 -0
  36. package/dist/types/modules/panels/model/plugin-ledger.d.ts +22 -0
  37. package/dist/types/modules/panels/model/plugin-name.d.ts +8 -0
  38. package/dist/types/modules/panels/model/plugin-name.test.d.ts +1 -0
  39. package/dist/types/modules/panels/model/plugin-section.d.ts +13 -0
  40. package/dist/types/modules/panels/model/service.d.ts +8 -6
  41. package/dist/types/shared/api/bundle-install.d.ts +8 -1
  42. package/dist/types/shared/api/host/__tests__/registry-declaration.test.d.ts +1 -0
  43. package/dist/types/shared/api/host/__tests__/unit-roster-facts.test.d.ts +1 -0
  44. package/dist/types/shared/api/host/bundle-routes.d.ts +1 -0
  45. package/dist/types/shared/api/host/installed-module.d.ts +7 -0
  46. package/dist/types/shared/api/host/mount-units.d.ts +5 -3
  47. package/dist/types/shared/api/host/package-content.d.ts +6 -0
  48. package/dist/types/shared/api/host/package-content.test.d.ts +1 -0
  49. package/dist/types/shared/api/host/package-kind.d.ts +21 -0
  50. package/dist/types/shared/api/host/package-kind.test.d.ts +1 -0
  51. package/dist/types/shared/api/host/package-route.d.ts +23 -0
  52. package/dist/types/shared/api/host/package-route.test.d.ts +1 -0
  53. package/dist/types/shared/api/host/registry-declaration.d.ts +23 -0
  54. package/dist/types/shared/api/host/unit-registry.d.ts +33 -4
  55. package/dist/types/shared/api/host/unit-roster-facts.d.ts +5 -0
  56. package/dist/types/shared/api/installed-plugins.d.ts +12 -0
  57. package/dist/types/shared/api/unit-manifests.d.ts +5 -0
  58. package/dist/types/shared/api/unit-manifests.test.d.ts +1 -0
  59. package/dist/types/shared/hooks/bundle-queries.d.ts +2 -0
  60. package/dist/types/shared/hooks/use-facts.d.ts +1 -0
  61. package/package.json +2 -2
  62. package/skills/workbench-module-diy/BUILD.md +5 -5
  63. package/skills/workbench-module-diy/DESIGN.md +7 -1
  64. package/skills/workbench-module-diy/REVIEW.md +3 -2
  65. package/skills/workbench-module-diy/TOOLING.md +2 -2
  66. package/skills/workbench-module-diy/TOOLS.md +9 -2
@@ -422,6 +422,121 @@ function probeKeyOf(error) {
422
422
  if (error === void 0) return null;
423
423
  return error.code === "" ? "unknown" : error.code;
424
424
  }
425
+ var SUPPORTED_API_VERSIONS = [1];
426
+ var DECLARATION_KEYS = [
427
+ "apiVersion",
428
+ "unit",
429
+ "card",
430
+ "tools",
431
+ "host",
432
+ "env"
433
+ ];
434
+ var DECLARATION_REQUIRED_KEYS = [
435
+ "apiVersion",
436
+ "unit",
437
+ "card",
438
+ "tools",
439
+ "host"
440
+ ];
441
+ var CARD_KEYS = ["titleKey", "order"];
442
+ var TOOL_KEYS = ["name", "writes"];
443
+ var HOST_KEYS = ["inject", "optional"];
444
+ function text(value) {
445
+ return typeof value === "string" ? value.trim() : "";
446
+ }
447
+ function isRecord(value) {
448
+ return typeof value === "object" && value !== null && !Array.isArray(value);
449
+ }
450
+ function outsideKeys(value, allowed) {
451
+ return Object.keys(value).filter((key) => !allowed.includes(key));
452
+ }
453
+ function listOf(keys) {
454
+ return keys.map((key) => JSON.stringify(key)).join(" / ");
455
+ }
456
+ function stringArrayProblems(at, value) {
457
+ if (!Array.isArray(value)) return [`${at} 要是一串字符串,现在是 ${JSON.stringify(value)}`];
458
+ return value.flatMap((item, index) => text(item) === "" ? [`${at}[${index}] 不是非空字符串:${JSON.stringify(item)}`] : []);
459
+ }
460
+ function declarationProblemsOf(subject, raw) {
461
+ if (!isRecord(raw)) return [`${subject}: dsh.workbench 不是一个对象 —— ${JSON.stringify(raw)}`];
462
+ const version = raw.apiVersion;
463
+ if (version === void 0) return [`${subject}: dsh.workbench 没有 apiVersion —— 协议从 v1 起,写 \`"apiVersion": 1\`。缺它 = 外壳不认这个模块(ADR-0038 §2.3)`];
464
+ if (!Number.isInteger(version) || !SUPPORTED_API_VERSIONS.includes(version)) return [`${subject}: dsh.workbench.apiVersion 是 ${JSON.stringify(version)},这里只认 ${SUPPORTED_API_VERSIONS.join(" / ")}(要整数)`];
465
+ const problems = [];
466
+ const unknown = outsideKeys(raw, DECLARATION_KEYS);
467
+ if (unknown.length > 0) problems.push(`${subject}: dsh.workbench 里有协议 v1 不认识的键 ${listOf(unknown)} —— 只有 ${listOf(DECLARATION_KEYS)}。(拼错的键会被外壳**静默忽略**:那句声明等于没写)`);
468
+ for (const key of DECLARATION_REQUIRED_KEYS) if (raw[key] === void 0) problems.push(`${subject}: dsh.workbench 缺 ${key}` + (key === "card" ? "(这个模块没有卡片就写 `\"card\": null`)" : ""));
469
+ const card = raw.card;
470
+ if (card !== void 0 && card !== null) {
471
+ if (!isRecord(card)) problems.push(`${subject}: dsh.workbench.card 要么是对象、要么是 null,现在是 ${JSON.stringify(card)}`);
472
+ else {
473
+ const extra = outsideKeys(card, CARD_KEYS);
474
+ if (extra.length > 0) problems.push(`${subject}: dsh.workbench.card 里有不认的键 ${listOf(extra)} —— card 只有 ${listOf(CARD_KEYS)}(卡片默认显不显示由运行期的面板配置决定,清单里没有这一位)`);
475
+ if (text(card.titleKey) === "") problems.push(`${subject}: dsh.workbench.card.titleKey 要是非空字符串(面板那一格的文案键)`);
476
+ if (typeof card.order !== "number" || !Number.isFinite(card.order)) problems.push(`${subject}: dsh.workbench.card.order 要是数字,现在是 ${JSON.stringify(card.order)}`);
477
+ }
478
+ }
479
+ const tools = raw.tools;
480
+ if (tools !== void 0) {
481
+ if (!Array.isArray(tools)) problems.push(`${subject}: dsh.workbench.tools 要是一串声明,现在是 ${JSON.stringify(tools)}`);
482
+ else {
483
+ const seen = /* @__PURE__ */ new Set();
484
+ tools.forEach((tool, index) => {
485
+ const at = `dsh.workbench.tools[${index}]`;
486
+ if (!isRecord(tool)) {
487
+ problems.push(`${subject}: ${at} 要是对象,现在是 ${JSON.stringify(tool)}`);
488
+ return;
489
+ }
490
+ const extra = outsideKeys(tool, TOOL_KEYS);
491
+ if (extra.length > 0) problems.push(`${subject}: ${at} 里有不认的键 ${listOf(extra)} —— tools 只有 ${listOf(TOOL_KEYS)}`);
492
+ const name = text(tool.name);
493
+ if (name === "") problems.push(`${subject}: ${at}.name 要是非空字符串`);
494
+ else if (seen.has(name)) problems.push(`${subject}: ${at}.name「${name}」与前面那条撞了 —— 工具名会进 dsh 的工具表,不许重`);
495
+ else seen.add(name);
496
+ if (typeof tool.writes !== "boolean") problems.push(`${subject}: ${at}.writes 要是 true / false(它是"这会写"的唯一声明,缺了审批无从认领)`);
497
+ });
498
+ }
499
+ }
500
+ const host = raw.host;
501
+ if (host !== void 0) {
502
+ if (!isRecord(host)) problems.push(`${subject}: dsh.workbench.host 要是对象,现在是 ${JSON.stringify(host)}`);
503
+ else {
504
+ const extra = outsideKeys(host, HOST_KEYS);
505
+ if (extra.length > 0) problems.push(`${subject}: dsh.workbench.host 里有不认的键 ${listOf(extra)} —— host 只有 ${listOf(HOST_KEYS)}`);
506
+ if (host.inject === void 0) problems.push(`${subject}: dsh.workbench.host.inject 没写 —— 它声明这个模块要外壳的哪几个服务,外壳靠它判"能不能挂"。一个都不要也要写 \`"inject": []\``);
507
+ else problems.push(...stringArrayProblems(`${subject}: dsh.workbench.host.inject`, host.inject));
508
+ if (host.optional !== void 0) problems.push(...stringArrayProblems(`${subject}: dsh.workbench.host.optional`, host.optional));
509
+ }
510
+ }
511
+ if (raw.env !== void 0 && !isRecord(raw.env)) problems.push(`${subject}: dsh.workbench.env 要是对象(command / plugins / libs)—— 语义由门禁的 env 判据查,这里只查形状`);
512
+ return problems;
513
+ }
514
+ function readDeclaration(subject, raw) {
515
+ const problems = declarationProblemsOf(subject, raw);
516
+ if (problems.length > 0) return { problems };
517
+ const declaration = raw;
518
+ const card = declaration.card;
519
+ return {
520
+ declaration,
521
+ problems: [],
522
+ manifest: {
523
+ id: text(declaration.unit),
524
+ card: card === null ? null : {
525
+ titleKey: text(card.titleKey),
526
+ order: card.order
527
+ },
528
+ tools: declaration.tools.map((tool) => ({
529
+ name: text(tool.name),
530
+ writes: tool.writes
531
+ })),
532
+ host: {
533
+ inject: [...declaration.host.inject ?? []],
534
+ ...declaration.host.optional === void 0 ? {} : { optional: [...declaration.host.optional] }
535
+ },
536
+ ...declaration.env === void 0 ? {} : { env: declaration.env }
537
+ }
538
+ };
539
+ }
425
540
  //#endregion
426
541
  //#region ../shared/dist/config/constants.js
427
542
  var PLUGIN_ID = "@dsh-workbench/core";
@@ -609,7 +724,7 @@ function ApprovalDetail(props) {
609
724
  if (owner?.approval !== void 0) {
610
725
  const Render = owner.approval.render;
611
726
  return h(CardBoundary, {
612
- unit: owner.manifest.id,
727
+ unit: owner.unit,
613
728
  resetKey: props.callId ?? "",
614
729
  t
615
730
  }, h(Render, {
@@ -1114,6 +1229,7 @@ var en = {
1114
1229
  "panels.market.sectionPending": "Not installed",
1115
1230
  "panels.market.sectionShared": "Shared dependencies",
1116
1231
  "panels.market.sharedUsedBy": "Used by {modules}",
1232
+ "panels.market.sharedFoot": "These cannot be uninstalled here: they come with modules, and would be reinstalled anyway. To stop using one, turn off the modules that use it.",
1117
1233
  "panels.market.listSeparator": ", ",
1118
1234
  "panels.market.sharedMissing": "not installed",
1119
1235
  "panels.market.sharedOutdated": "update available",
@@ -1141,8 +1257,18 @@ var en = {
1141
1257
  "panels.market.installedSection": "Installed",
1142
1258
  "panels.market.sectionLocal": "Linked locally",
1143
1259
  "panels.market.sectionUnlisted": "Not from the market",
1260
+ "panels.market.sectionPlugins": "Installed opencli plugins",
1144
1261
  "panels.market.moduleOutdated": "update available",
1262
+ "panels.market.moduleRefused": "This module was built for an older version of the workbench, so it does not work here. Update it, or uninstall.",
1263
+ "panels.market.moduleRefusedDetail": "Why it cannot be used: {reason}",
1145
1264
  "panels.market.moduleRestartHint": "installed but not active — restart dsh once to bring it up",
1265
+ "panels.market.pluginLocalNoUpdate": "Installed from a local folder, so there is nowhere to check for a newer version — uninstall only",
1266
+ "panels.market.pluginKeptInUse": "Files kept for now: {names} still uses it.",
1267
+ "panels.market.pluginKeptUnsure": "Files kept for now: some modules on this machine do not say what they use, so it is unclear who needs it.",
1268
+ "panels.market.pluginKeptHeld": "Files kept: this one is yours, and a module letting go will not remove it.",
1269
+ "panels.market.pluginKeptUnnamed": "Files kept for now: this one cannot be identified as a plugin, so it is unclear who needs it.",
1270
+ "panels.market.pluginAlsoKnownAs": "Its package is {pkg} (updates and uninstall use that)",
1271
+ "panels.market.pluginBroken": "This install is broken: it cannot be identified as a plugin. Uninstall it, or install it again by package name above.",
1146
1272
  "panels.market.restartNeeded": "The new version is installed — restart once to pick it up.",
1147
1273
  "panels.market.foot": "After installing, enable it in the panel page of that project.",
1148
1274
  "panels.market.recheck": "Check for updates",
@@ -1190,7 +1316,11 @@ var en = {
1190
1316
  "panels.market.add.problemInstalled": "This module is already installed",
1191
1317
  "panels.market.add.problemNotFound": "No such module found",
1192
1318
  "panels.market.add.problemNotPackage": "That path does not exist or is not a valid module package",
1193
- "panels.market.add.problemNotBundle": "This package declares no bundle, so it cannot be installed as a module: {reason}",
1319
+ "panels.market.add.problemNotBundle": "This package cannot be installed here: {reason}. If it is actually an opencli plugin, use its package name (for example opencli-plugin-cmdb) or a local folder — a git URL or tarball does not reveal what it is.",
1320
+ "panels.market.add.problemNotWorkbenchModule": "This package does not match the workbench you are running, so installing it would not work. Pick another version, or ask the module author.",
1321
+ "panels.market.add.problemNotModuleOrPlugin": "This package is neither a workbench module nor an opencli plugin, so installing it would do nothing. Pick another version, or ask the package author.",
1322
+ "panels.market.add.failureNotModuleOrPlugin": "This package is neither a workbench module nor an opencli plugin, so installing it would do nothing",
1323
+ "panels.market.add.installedPlugin": "Installed: the opencli plugin {name}",
1194
1324
  "panels.market.add.problemNetwork": "Cannot reach the module source; check the network and retry",
1195
1325
  "panels.market.add.problemUnknown": "Cannot fetch module information: {reason}",
1196
1326
  "panels.market.add.failureNetwork": "The network connection failed",
@@ -1221,6 +1351,7 @@ var en = {
1221
1351
  "panels.market.add.registryPnpm": "pnpm's own registry",
1222
1352
  "panels.market.add.check": "Check",
1223
1353
  "panels.market.add.checking": "Checking…",
1354
+ "panels.market.add.classifying": "Working out what it is…",
1224
1355
  "panels.market.add.change": "Edit",
1225
1356
  "panels.market.add.previewTitle": "About to install",
1226
1357
  "panels.market.add.fieldName": "Package",
@@ -1429,6 +1560,7 @@ var zh = {
1429
1560
  "panels.market.sectionPending": "未安装",
1430
1561
  "panels.market.sectionShared": "共用依赖",
1431
1562
  "panels.market.sharedUsedBy": "供 {modules} 使用",
1563
+ "panels.market.sharedFoot": "这一段不给卸载:它们跟着模块来,卸掉也会被装回来。要停用一份,就去关掉正在用它的那些模块。",
1432
1564
  "panels.market.listSeparator": "、",
1433
1565
  "panels.market.sharedMissing": "未装",
1434
1566
  "panels.market.sharedOutdated": "有新版",
@@ -1456,8 +1588,18 @@ var zh = {
1456
1588
  "panels.market.installedSection": "已安装",
1457
1589
  "panels.market.sectionLocal": "本地装的",
1458
1590
  "panels.market.sectionUnlisted": "不是从市场装的",
1591
+ "panels.market.sectionPlugins": "已安装 opencli 插件",
1459
1592
  "panels.market.moduleOutdated": "有新版",
1593
+ "panels.market.moduleRefused": "这个模块是给旧版本的工作台写的,现在用不了。更新它,或者卸载。",
1594
+ "panels.market.moduleRefusedDetail": "装不上的原因:{reason}",
1460
1595
  "panels.market.moduleRestartHint": "装好了但还没生效 —— 重启一次 dsh 就会出来",
1596
+ "panels.market.pluginLocalNoUpdate": "本地装的,没地方查新版,所以只给卸载",
1597
+ "panels.market.pluginKeptInUse": "文件先留着:{names} 还要用它。",
1598
+ "panels.market.pluginKeptUnsure": "文件先留着:这台机器上还有模块看不出用了什么,说不准谁在用它。",
1599
+ "panels.market.pluginKeptHeld": "文件留着:你自己装的那一份,模块放手不动它。",
1600
+ "panels.market.pluginKeptUnnamed": "文件先留着:看不出这是哪个插件,说不准谁在用它。",
1601
+ "panels.market.pluginAlsoKnownAs": "包名是 {pkg}(更新与卸载按它来)",
1602
+ "panels.market.pluginBroken": "这份装坏了:看不出它是个插件。可以卸载,或者去上面按包名再装一次。",
1461
1603
  "panels.market.restartNeeded": "新版装好了,重启一次才生效。",
1462
1604
  "panels.market.foot": "装好后到那个项目的面板页勾选它,模块才会出现。",
1463
1605
  "panels.market.recheck": "重新检查更新",
@@ -1505,7 +1647,11 @@ var zh = {
1505
1647
  "panels.market.add.problemInstalled": "该模块已安装",
1506
1648
  "panels.market.add.problemNotFound": "未找到相关模块",
1507
1649
  "panels.market.add.problemNotPackage": "该路径不存在或不是有效的模块包",
1508
- "panels.market.add.problemNotBundle": "这个包没有声明组合包,无法作为模块安装:{reason}",
1650
+ "panels.market.add.problemNotBundle": "这个包装不进这里:{reason}。要是它其实是个 opencli 插件,请改用包名(例如 opencli-plugin-cmdb)或者本地目录 —— 从 git 地址和 tarball 判断不出它是什么。",
1651
+ "panels.market.add.problemNotWorkbenchModule": "这个包跟现在的工作台对不上,装上也用不了。换一个版本,或者找这个模块的作者。",
1652
+ "panels.market.add.problemNotModuleOrPlugin": "这个包既不是工作台的模块,也不是 opencli 的插件,装了也用不上。换一个版本,或者找这个包的作者。",
1653
+ "panels.market.add.failureNotModuleOrPlugin": "这个包既不是工作台的模块,也不是 opencli 的插件,装了也用不上",
1654
+ "panels.market.add.installedPlugin": "装上了:opencli 插件 {name}",
1509
1655
  "panels.market.add.problemNetwork": "无法连接模块源,请检查网络后重试",
1510
1656
  "panels.market.add.problemUnknown": "无法获取模块信息:{reason}",
1511
1657
  "panels.market.add.failureNetwork": "网络连接失败",
@@ -1536,6 +1682,7 @@ var zh = {
1536
1682
  "panels.market.add.registryPnpm": "pnpm 自己配的源",
1537
1683
  "panels.market.add.check": "预检",
1538
1684
  "panels.market.add.checking": "正在预检…",
1685
+ "panels.market.add.classifying": "判定中…",
1539
1686
  "panels.market.add.change": "改一下",
1540
1687
  "panels.market.add.previewTitle": "将要安装",
1541
1688
  "panels.market.add.fieldName": "包名",
@@ -1812,6 +1959,8 @@ var dist_exports = /* @__PURE__ */ __exportAll({
1812
1959
  CenteredState: () => CenteredState,
1813
1960
  ChoiceGroup: () => ChoiceGroup,
1814
1961
  Component: () => Component,
1962
+ DECLARATION_KEYS: () => DECLARATION_KEYS,
1963
+ DECLARATION_REQUIRED_KEYS: () => DECLARATION_REQUIRED_KEYS,
1815
1964
  DEFAULT_WORKSPACE_TITLE: () => DEFAULT_WORKSPACE_TITLE,
1816
1965
  EVENTS_PATH: () => EVENTS_PATH,
1817
1966
  EmptyState: () => EmptyState,
@@ -1850,6 +1999,7 @@ var dist_exports = /* @__PURE__ */ __exportAll({
1850
1999
  STORAGE_KEY_PROJECT: () => STORAGE_KEY_PROJECT,
1851
2000
  STORAGE_KEY_RIGHTBAR: () => STORAGE_KEY_RIGHTBAR,
1852
2001
  STORAGE_KEY_RIGHTBAR_COLUMN: () => STORAGE_KEY_RIGHTBAR_COLUMN,
2002
+ SUPPORTED_API_VERSIONS: () => SUPPORTED_API_VERSIONS,
1853
2003
  SaveBar: () => SaveBar,
1854
2004
  SettingsSection: () => SettingsSection,
1855
2005
  SkeletonRows: () => SkeletonRows,
@@ -1860,6 +2010,7 @@ var dist_exports = /* @__PURE__ */ __exportAll({
1860
2010
  VERSION_CHECK_TIMEOUT_MS: () => VERSION_CHECK_TIMEOUT_MS,
1861
2011
  VERSION_CHECK_TTL_MS: () => VERSION_CHECK_TTL_MS,
1862
2012
  WARM_TIMEOUT_MS: () => WARM_TIMEOUT_MS,
2013
+ WORKBENCH_API_VERSION: () => 1,
1863
2014
  apiGet: () => apiGet,
1864
2015
  apiPost: () => apiPost,
1865
2016
  blockerActionLabel: () => blockerActionLabel,
@@ -1869,6 +2020,7 @@ var dist_exports = /* @__PURE__ */ __exportAll({
1869
2020
  buildMarker: () => buildMarker,
1870
2021
  createFactChannel: () => createFactChannel,
1871
2022
  cx: () => cx,
2023
+ declarationProblemsOf: () => declarationProblemsOf,
1872
2024
  decodeRef: () => decodeRef,
1873
2025
  dictionaries: () => dictionaries,
1874
2026
  en: () => en,
@@ -1892,6 +2044,7 @@ var dist_exports = /* @__PURE__ */ __exportAll({
1892
2044
  parseMarkers: () => parseMarkers,
1893
2045
  probeKeyOf: () => probeKeyOf,
1894
2046
  quoteShellArg: () => quoteShellArg,
2047
+ readDeclaration: () => readDeclaration,
1895
2048
  readFlag: () => readFlag,
1896
2049
  readText: () => readText,
1897
2050
  relativeTime: () => relativeTime,
@@ -2004,6 +2157,7 @@ function createAdaptiveTransport() {
2004
2157
  //#endregion
2005
2158
  //#region src/shared/hooks/use-facts.ts
2006
2159
  var use_facts_exports = /* @__PURE__ */ __exportAll({
2160
+ subscribeFactRevision: () => subscribeFactRevision,
2007
2161
  useFactInvalidate: () => useFactInvalidate,
2008
2162
  useFactRevision: () => useFactRevision
2009
2163
  });
@@ -2011,6 +2165,9 @@ var channel = createFactChannel({ transport: createAdaptiveTransport() });
2011
2165
  function useFactRevision(fact) {
2012
2166
  return useSyncExternalStore(useCallback((listener) => channel.subscribe(fact, listener), [fact]), useCallback(() => channel.revisionOf(fact), [fact]));
2013
2167
  }
2168
+ function subscribeFactRevision(fact, listener) {
2169
+ return channel.subscribe(fact, listener);
2170
+ }
2014
2171
  function useFactInvalidate() {
2015
2172
  return useCallback((fact) => channel.refresh(fact), []);
2016
2173
  }
@@ -2535,8 +2692,7 @@ function buildMarketMocks(roster) {
2535
2692
  ...mine,
2536
2693
  card: {
2537
2694
  titleKey: "一个名字特别特别长的模块用来验证省略号会不会把按钮挤下去",
2538
- order: 10,
2539
- enabledByDefault: true
2695
+ order: 10
2540
2696
  }
2541
2697
  }],
2542
2698
  capabilities: probe$1(id, "ok"),
@@ -2640,6 +2796,24 @@ function buildMarketMocks(roster) {
2640
2796
  installedActions: ["update-bundle", "remove-bundle"]
2641
2797
  }
2642
2798
  },
2799
+ {
2800
+ id: "installed-client-refused",
2801
+ label: "本机装了,但浏览器这半没挂上(拒因由客户端报告)",
2802
+ manifests: [found],
2803
+ capabilities: {},
2804
+ installed: [{
2805
+ unit: id,
2806
+ pkg: "@dsh-workbench/module-one",
2807
+ installed: "0.1.2",
2808
+ clientRefused: [`宿主没有担保 unit「${id}」的清单 —— 这个包要么没装进这份 profile,要么它的 dsh.workbench 没通过校验。卡片先不挂:清单只有一处真相(ADR-0038 §2.2)`]
2809
+ }],
2810
+ expect: {
2811
+ rows: 0,
2812
+ installed: 1,
2813
+ installedActions: ["remove-bundle"],
2814
+ installedNote: true
2815
+ }
2816
+ },
2643
2817
  {
2644
2818
  id: "installed-confirm",
2645
2819
  label: "卸载本机模块(Modal 确认,标题带模块名)",
@@ -2688,6 +2862,95 @@ function buildMarketMocks(roster) {
2688
2862
  actions: ["uninstall"]
2689
2863
  }
2690
2864
  },
2865
+ {
2866
+ id: "plugin-outdated",
2867
+ label: "用户装的 opencli 插件:有新版(给更新 / 卸载)",
2868
+ manifests: [],
2869
+ capabilities: {},
2870
+ plugins: [{
2871
+ pkg: "opencli-plugin-cmdb",
2872
+ name: "cmdb",
2873
+ installed: "1.0.24",
2874
+ latest: "1.0.25"
2875
+ }],
2876
+ expect: {
2877
+ rows: 0,
2878
+ plugins: 1,
2879
+ pluginActions: ["update-plugin", "uninstall-plugin"]
2880
+ }
2881
+ },
2882
+ {
2883
+ id: "plugin-local",
2884
+ label: "本地目录装的 opencli 插件:没有版本源(只给卸载,行上说清为什么)",
2885
+ manifests: [],
2886
+ capabilities: {},
2887
+ plugins: [{
2888
+ pkg: "/Users/me/my-local-plugin",
2889
+ name: "my-local-plugin",
2890
+ local: true
2891
+ }],
2892
+ expect: {
2893
+ rows: 0,
2894
+ plugins: 1,
2895
+ pluginActions: ["uninstall-plugin"],
2896
+ pluginNote: true,
2897
+ pluginNoteKey: "panels.market.pluginLocalNoUpdate"
2898
+ }
2899
+ },
2900
+ {
2901
+ id: "plugin-alias",
2902
+ label: "插件名 ≠ 包名:行上两个都写出来(更新 / 卸载按包名)",
2903
+ manifests: [],
2904
+ capabilities: {},
2905
+ plugins: [{
2906
+ pkg: "opencli-plugin-cmdb",
2907
+ name: "cmdb",
2908
+ installed: "1.0.24",
2909
+ latest: "1.0.25"
2910
+ }],
2911
+ expect: {
2912
+ rows: 0,
2913
+ plugins: 1,
2914
+ pluginActions: ["update-plugin", "uninstall-plugin"],
2915
+ pluginNoteKey: "panels.market.pluginAlsoKnownAs"
2916
+ }
2917
+ },
2918
+ {
2919
+ id: "plugin-broken",
2920
+ label: "装坏了的那一份(目录在但看不出是个插件):行上直说,给卸载与指路",
2921
+ manifests: [],
2922
+ capabilities: {},
2923
+ plugins: [{
2924
+ pkg: "opencli-plugin-cmdb",
2925
+ name: "cmdb",
2926
+ installed: "1.0.24",
2927
+ broken: true
2928
+ }],
2929
+ expect: {
2930
+ rows: 0,
2931
+ plugins: 1,
2932
+ pluginActions: ["uninstall-plugin"],
2933
+ pluginNoteKey: "panels.market.pluginBroken"
2934
+ }
2935
+ },
2936
+ {
2937
+ id: "plugin-kept",
2938
+ label: "卸掉用户装的插件,但还有模块在用:文件先留着(行上给一句为什么)",
2939
+ manifests: [],
2940
+ capabilities: {},
2941
+ plugins: [{
2942
+ pkg: "opencli-plugin-cmdb",
2943
+ name: "cmdb",
2944
+ installed: "1.0.24"
2945
+ }],
2946
+ notice: "文件先留着:cmdb、argocd 还要用它。",
2947
+ expect: {
2948
+ rows: 0,
2949
+ plugins: 1,
2950
+ pluginActions: ["uninstall-plugin"],
2951
+ notice: true
2952
+ }
2953
+ },
2691
2954
  {
2692
2955
  id: "empty",
2693
2956
  label: "市场空态",
@@ -2745,7 +3008,6 @@ function createBoardRegistry() {
2745
3008
  };
2746
3009
  },
2747
3010
  all: () => sorted,
2748
- visible: () => sorted.filter((module) => module.enabledByDefault),
2749
3011
  byId: (id) => index.get(id),
2750
3012
  stepOwner: (kind) => steps.get(kind),
2751
3013
  subscribe(listener) {
@@ -2757,20 +3019,21 @@ function createBoardRegistry() {
2757
3019
  }
2758
3020
  //#endregion
2759
3021
  //#region src/app/units/registry.ts
2760
- function toBoardModule(face) {
3022
+ function toBoardModule(face, manifest) {
2761
3023
  return {
2762
- id: face.manifest.id,
2763
- titleKey: face.manifest.card?.titleKey ?? face.manifest.id,
2764
- order: face.manifest.card?.order ?? 100,
2765
- enabledByDefault: face.manifest.card?.enabledByDefault ?? false,
3024
+ id: manifest.id,
3025
+ titleKey: manifest.card?.titleKey ?? manifest.id,
3026
+ order: manifest.card?.order ?? 100,
2766
3027
  View: face.card,
2767
3028
  ...face.steps === void 0 ? {} : { steps: face.steps }
2768
3029
  };
2769
3030
  }
2770
- function createClientUnitRegistry() {
2771
- const faces = [];
3031
+ function createClientUnitRegistry(options = {}) {
3032
+ const registrations = [];
3033
+ const refusals = [];
2772
3034
  const listeners = /* @__PURE__ */ new Set();
2773
3035
  const board = createBoardRegistry();
3036
+ let known = /* @__PURE__ */ new Map();
2774
3037
  let revision = 0;
2775
3038
  let manifestsCache;
2776
3039
  function notify() {
@@ -2781,28 +3044,86 @@ function createClientUnitRegistry() {
2781
3044
  console.warn(`[dsh-workbench] 套件注册的订阅者报错(不影响其它订阅者与这次注册):${String(error)}`);
2782
3045
  }
2783
3046
  }
3047
+ function warnRefusal(unit, reasons) {
3048
+ refusals.push({
3049
+ unit,
3050
+ reasons
3051
+ });
3052
+ console.warn(`[dsh-workbench] ${unit === "" ? "这个模块" : unit} 的卡片没挂上:${reasons.join(";")}`);
3053
+ }
3054
+ function takeBackRefusal(unit) {
3055
+ for (let at = refusals.length - 1; at >= 0; at -= 1) if (refusals[at]?.unit === unit) refusals.splice(at, 1);
3056
+ }
3057
+ function attach(entry) {
3058
+ const manifest = known.get(entry.unit);
3059
+ if (manifest === void 0) return false;
3060
+ entry.mounted = {
3061
+ manifest,
3062
+ unmount: board.register(toBoardModule(entry.face, manifest))
3063
+ };
3064
+ takeBackRefusal(entry.unit);
3065
+ return true;
3066
+ }
3067
+ function detach(entry) {
3068
+ entry.mounted?.unmount();
3069
+ entry.mounted = null;
3070
+ }
2784
3071
  return {
2785
3072
  register(face) {
2786
- const id = face.manifest.id;
2787
- if (faces.some((item) => item.manifest.id === id)) throw new Error(`套件 id 重复:${id}(id 会进持久化配置,不能撞)`);
2788
- const unregisterBoard = board.register(toBoardModule(face));
2789
- faces.push(face);
3073
+ const unit = typeof face?.unit === "string" ? face.unit.trim() : "";
3074
+ if (unit === "") {
3075
+ warnRefusal("", ["registerUnit({ unit, card }) 里的 unit 是空的 —— U1b 之前的旧形状是 registerUnit({ manifest, card });现在清单由外壳从**已装清单**读出来、按 unit 交给浏览器(ADR-0038 §2.2)"]);
3076
+ notify();
3077
+ return () => {};
3078
+ }
3079
+ if (registrations.some((entry) => entry.unit === unit)) throw new Error(`套件 id 重复:${unit}(id 会进持久化配置,不能撞)`);
3080
+ const entry = {
3081
+ face,
3082
+ unit,
3083
+ mounted: null
3084
+ };
3085
+ registrations.push(entry);
2790
3086
  manifestsCache = void 0;
3087
+ if (!attach(entry)) {
3088
+ warnRefusal(unit, [`宿主没有担保 unit「${unit}」的清单 —— 这个包要么没装进这份 profile,要么它的 dsh.workbench 没通过校验。卡片先不挂:清单只有一处真相(ADR-0038 §2.2)`]);
3089
+ options.onUnknownUnit?.(unit);
3090
+ }
2791
3091
  notify();
2792
3092
  return () => {
2793
- const at = faces.findIndex((item) => item.manifest.id === id);
3093
+ const at = registrations.indexOf(entry);
2794
3094
  if (at < 0) return;
2795
- faces.splice(at, 1);
3095
+ registrations.splice(at, 1);
3096
+ detach(entry);
3097
+ takeBackRefusal(unit);
2796
3098
  manifestsCache = void 0;
2797
- unregisterBoard();
2798
3099
  notify();
2799
3100
  };
2800
3101
  },
2801
- all: () => faces,
3102
+ all: () => registrations.map((entry) => entry.face),
2802
3103
  manifests: () => {
2803
- manifestsCache ??= faces.map((face) => face.manifest);
3104
+ manifestsCache ??= registrations.flatMap((entry) => entry.mounted === null ? [] : [entry.mounted.manifest]);
2804
3105
  return manifestsCache;
2805
3106
  },
3107
+ refusals: () => refusals,
3108
+ setManifests(manifests) {
3109
+ known = new Map(manifests.map((manifest) => [manifest.id, manifest]));
3110
+ let changed = false;
3111
+ for (const entry of registrations) {
3112
+ const next = known.get(entry.unit);
3113
+ if (entry.mounted === null) {
3114
+ if (next !== void 0 && attach(entry)) changed = true;
3115
+ continue;
3116
+ }
3117
+ if (next === void 0) {
3118
+ detach(entry);
3119
+ warnRefusal(entry.unit, [`宿主不再担保 unit「${entry.unit}」的清单(模块被卸了?)—— 这张卡片先摘下来`]);
3120
+ changed = true;
3121
+ }
3122
+ }
3123
+ if (!changed) return;
3124
+ manifestsCache = void 0;
3125
+ notify();
3126
+ },
2806
3127
  board,
2807
3128
  subscribe(listener) {
2808
3129
  listeners.add(listener);
@@ -2837,11 +3158,9 @@ var messages = {
2837
3158
  };
2838
3159
  var manifest = {
2839
3160
  id: FIXTURE_UNIT_ID,
2840
- kind: "board",
2841
3161
  card: {
2842
3162
  titleKey: KEY.cardTitle,
2843
- order: 900,
2844
- enabledByDefault: true
3163
+ order: 900
2845
3164
  },
2846
3165
  tools: [],
2847
3166
  host: { inject: [] }
@@ -2864,6 +3183,7 @@ function FixtureCard({ t, onRefresh }) {
2864
3183
  }))));
2865
3184
  }
2866
3185
  var FIXTURE_FACE = {
3186
+ unit: FIXTURE_UNIT_ID,
2867
3187
  manifest,
2868
3188
  messages,
2869
3189
  card: FixtureCard
@@ -2884,11 +3204,9 @@ var crashMessages = {
2884
3204
  };
2885
3205
  var crashManifest = {
2886
3206
  id: CRASH_UNIT_ID,
2887
- kind: "board",
2888
3207
  card: {
2889
3208
  titleKey: CRASH_KEY.cardTitle,
2890
- order: 899,
2891
- enabledByDefault: true
3209
+ order: 899
2892
3210
  },
2893
3211
  tools: [],
2894
3212
  host: { inject: [] }
@@ -2897,6 +3215,7 @@ function CrashingCard() {
2897
3215
  throw new Error("夹具:这张卡片按 wbCrash=1 故意渲染失败(守「一张卡片崩溃不带走面板」)");
2898
3216
  }
2899
3217
  var CRASH_FACE = {
3218
+ unit: CRASH_UNIT_ID,
2900
3219
  manifest: crashManifest,
2901
3220
  messages: crashMessages,
2902
3221
  card: CrashingCard
@@ -2909,8 +3228,8 @@ function fixtureRoster(roster) {
2909
3228
  return hasCard(roster) ? roster : SAMPLE_ROSTER;
2910
3229
  }
2911
3230
  function fixtureSeed(roster, all, crash = false) {
2912
- const base = hasCard(roster) ? all : [toBoardModule(FIXTURE_FACE)];
2913
- return crash ? [toBoardModule(CRASH_FACE), ...base] : base;
3231
+ const base = hasCard(roster) ? all : [toBoardModule(FIXTURE_FACE, FIXTURE_FACE.manifest)];
3232
+ return crash ? [toBoardModule(CRASH_FACE, CRASH_FACE.manifest), ...base] : base;
2914
3233
  }
2915
3234
  //#endregion
2916
3235
  //#region src/app/layouts/rightbar/market-rows.ts
@@ -2930,6 +3249,25 @@ var MARKET_DOT = {
2930
3249
  unchecked: "idle",
2931
3250
  unknown: "idle"
2932
3251
  };
3252
+ function marketRowTitle(row, t) {
3253
+ return row.label ?? t(row.titleKey);
3254
+ }
3255
+ function withClientRefusals(modules, refusals) {
3256
+ if (refusals.length === 0) return modules;
3257
+ const byUnit = new Map(refusals.map((one) => [one.unit, one.reasons]));
3258
+ return modules.map((module) => {
3259
+ const reasons = byUnit.get(module.unit);
3260
+ return reasons === void 0 ? module : {
3261
+ ...module,
3262
+ clientRefused: reasons
3263
+ };
3264
+ });
3265
+ }
3266
+ function refusalReasons(host, client) {
3267
+ const reported = host ?? [];
3268
+ if (reported.length > 0) return reported;
3269
+ return [...new Set(client ?? [])];
3270
+ }
2933
3271
  function mergeTitles(known, manifests) {
2934
3272
  let next = null;
2935
3273
  for (const manifest of manifests) {
@@ -2948,11 +3286,16 @@ function installedRows(modules, manifests, listed, known) {
2948
3286
  const latest = module.latest;
2949
3287
  const outdated = latest !== void 0 && latest !== module.installed;
2950
3288
  const loaded = titles.has(module.unit);
3289
+ const refused = refusalReasons(module.refused, module.clientRefused);
2951
3290
  rows.push({
2952
3291
  id: module.unit,
2953
3292
  titleKey: titles.get(module.unit) ?? known?.get(module.unit) ?? module.pkg,
2954
3293
  state: outdated ? "outdated" : "installed",
2955
- ...loaded ? {} : { hint: "panels.market.moduleRestartHint" },
3294
+ ...loaded || refused.length > 0 ? {} : { hint: "panels.market.moduleRestartHint" },
3295
+ ...refused.length === 0 ? {} : { note: {
3296
+ key: "panels.market.moduleRefused",
3297
+ params: { reason: refused.join(";") }
3298
+ } },
2956
3299
  ...module.local === true ? { local: true } : {},
2957
3300
  pkg: module.pkg,
2958
3301
  canInstall: false,
@@ -2971,6 +3314,7 @@ function installedRows(modules, manifests, listed, known) {
2971
3314
  return rows;
2972
3315
  }
2973
3316
  function marketActions$1(row) {
3317
+ if (row.plugin === true) return [...row.canUpdate ? ["update-plugin"] : [], ...row.canUninstall ? ["uninstall-plugin"] : []];
2974
3318
  return [
2975
3319
  ...row.canInstall ? ["install"] : [],
2976
3320
  ...row.moduleUpdate === void 0 ? row.canUpdate ? ["update"] : [] : ["update-bundle"],
@@ -2994,7 +3338,7 @@ function envNameOf(source) {
2994
3338
  if (source.kind === "npm") return source.registryEnv;
2995
3339
  return "";
2996
3340
  }
2997
- function noteOf(state, install, manifest) {
3341
+ function noteOf$1(state, install, manifest) {
2998
3342
  if (state === "installed") return void 0;
2999
3343
  if (install === "env-missing") return {
3000
3344
  key: "panels.market.needEnv",
@@ -3053,7 +3397,7 @@ function marketRows(manifests, capabilities, updates = {}) {
3053
3397
  const capability = capabilities?.[manifest.id];
3054
3398
  const install = capability?.install;
3055
3399
  const state = capabilities === null ? "checking" : stateOf(capability);
3056
- const note = noteOf(state, install, manifest);
3400
+ const note = noteOf$1(state, install, manifest);
3057
3401
  const onMachine = isOnMachine(state);
3058
3402
  const reAdopt = capability?.released === true && install === void 0;
3059
3403
  const entry = updates[manifest.id];
@@ -3225,6 +3569,63 @@ function useHostWrite(options) {
3225
3569
  };
3226
3570
  }
3227
3571
  //#endregion
3572
+ //#region src/app/layouts/rightbar/market-plugin-rows.ts
3573
+ function installedPluginKept(value) {
3574
+ if (typeof value !== "object" || value === null) return void 0;
3575
+ const kept = value.kept;
3576
+ if (typeof kept !== "object" || kept === null) return void 0;
3577
+ const kind = kept.kind;
3578
+ if (kind === "held") return { key: "panels.market.pluginKeptHeld" };
3579
+ if (kind === "unnamed") return { key: "panels.market.pluginKeptUnnamed" };
3580
+ if (kind === "unsure") return { key: "panels.market.pluginKeptUnsure" };
3581
+ if (kind !== "claimed") return void 0;
3582
+ const raw = kept.by;
3583
+ const names = Array.isArray(raw) ? raw.filter((item) => typeof item === "string") : [];
3584
+ return names.length === 0 ? { key: "panels.market.pluginKeptUnsure" } : {
3585
+ key: "panels.market.pluginKeptInUse",
3586
+ names
3587
+ };
3588
+ }
3589
+ function noteOf(plugin) {
3590
+ if (plugin.broken === true) return {
3591
+ key: "panels.market.pluginBroken",
3592
+ params: {}
3593
+ };
3594
+ if (plugin.local === true) return {
3595
+ key: "panels.market.pluginLocalNoUpdate",
3596
+ params: {}
3597
+ };
3598
+ if (plugin.name !== void 0 && plugin.name !== plugin.pkg) return {
3599
+ key: "panels.market.pluginAlsoKnownAs",
3600
+ params: { pkg: plugin.pkg }
3601
+ };
3602
+ }
3603
+ function installedPluginRows(plugins) {
3604
+ return plugins.map((plugin) => {
3605
+ const name = plugin.name ?? plugin.pkg;
3606
+ const outdated = plugin.installed !== void 0 && plugin.latest !== void 0 && plugin.latest !== plugin.installed;
3607
+ const note = noteOf(plugin);
3608
+ return {
3609
+ id: `plugin:${plugin.pkg}`,
3610
+ titleKey: plugin.pkg,
3611
+ label: name,
3612
+ plugin: true,
3613
+ state: outdated ? "outdated" : "installed",
3614
+ canInstall: false,
3615
+ canUpdate: outdated,
3616
+ canUninstall: true,
3617
+ ...plugin.local === true ? { local: true } : {},
3618
+ ...plugin.broken === true ? { broken: true } : {},
3619
+ ...note === void 0 ? {} : { note },
3620
+ pkg: plugin.pkg,
3621
+ ...plugin.installed === void 0 ? {} : { version: {
3622
+ installed: plugin.installed,
3623
+ ...plugin.latest === void 0 ? {} : { latest: plugin.latest }
3624
+ } }
3625
+ };
3626
+ });
3627
+ }
3628
+ //#endregion
3228
3629
  //#region src/app/layouts/market/add-module-text.ts
3229
3630
  var GUIDE_ITEMS = [
3230
3631
  {
@@ -3343,17 +3744,23 @@ var PROBLEM_KEYS = {
3343
3744
  "not-found": "panels.market.add.problemNotFound",
3344
3745
  "not-a-package": "panels.market.add.problemNotPackage",
3345
3746
  "not-a-bundle": "panels.market.add.problemNotBundle",
3747
+ "not-a-workbench-module": "panels.market.add.problemNotWorkbenchModule",
3748
+ "not-a-module-or-plugin": "panels.market.add.problemNotModuleOrPlugin",
3346
3749
  network: "panels.market.add.problemNetwork",
3347
3750
  unknown: "panels.market.add.problemUnknown"
3348
3751
  };
3349
3752
  function problemKey(problem) {
3350
3753
  return PROBLEM_KEYS[problem] ?? PROBLEM_KEYS.unknown;
3351
3754
  }
3755
+ function heldWizardPhase(phase, classifying) {
3756
+ return classifying && (phase === "preview" || phase === "idle") ? "inspecting" : phase;
3757
+ }
3352
3758
  var FAILURE_KEYS = {
3353
3759
  network: "panels.market.add.failureNetwork",
3354
3760
  "spec-host": "panels.market.add.failureNetworkHost",
3355
3761
  "not-found": "panels.market.add.failureNotFound",
3356
3762
  "no-matching-version": "panels.market.add.failureNoMatchingVersion",
3763
+ "not-a-module-or-plugin": "panels.market.add.failureNotModuleOrPlugin",
3357
3764
  "disk-full": "panels.market.add.failureDiskFull",
3358
3765
  permission: "panels.market.add.failurePermission",
3359
3766
  "build-blocked": "panels.market.add.failureBuildBlocked",
@@ -3450,6 +3857,16 @@ function MarketChecking({ t }) {
3450
3857
  function MarketEmpty({ t }) {
3451
3858
  return /* @__PURE__ */ h("div", { className: MarketPage_module_default.marketEmpty }, /* @__PURE__ */ h("div", { className: MarketPage_module_default.marketEmptyTitle }, t("panels.market.empty")));
3452
3859
  }
3860
+ var PanelFoot_module_default = {
3861
+ foot: "_foot_1us83_1",
3862
+ footText: "_footText_1us83_12",
3863
+ footTextMd: "_footTextMd_1us83_17"
3864
+ };
3865
+ //#endregion
3866
+ //#region src/shared/components/PanelFoot.tsx
3867
+ function PanelFoot({ text, size = "sm", children }) {
3868
+ return /* @__PURE__ */ h("footer", { className: PanelFoot_module_default.foot }, /* @__PURE__ */ h("span", { className: size === "md" ? PanelFoot_module_default.footTextMd : PanelFoot_module_default.footText }, text), children ?? null);
3869
+ }
3453
3870
  //#endregion
3454
3871
  //#region src/app/layouts/rightbar/market-view-text.ts
3455
3872
  var PROGRESS_KEY = {
@@ -3458,7 +3875,9 @@ var PROGRESS_KEY = {
3458
3875
  "update-bundle": "panels.market.updating",
3459
3876
  "remove-bundle": "panels.market.uninstalling",
3460
3877
  uninstall: "panels.market.uninstalling",
3461
- "update-dependency": "panels.market.updating"
3878
+ "update-dependency": "panels.market.updating",
3879
+ "update-plugin": "panels.market.updating",
3880
+ "uninstall-plugin": "panels.market.uninstalling"
3462
3881
  };
3463
3882
  var ACTION_LABEL_KEY = {
3464
3883
  install: "panels.market.install",
@@ -3466,7 +3885,9 @@ var ACTION_LABEL_KEY = {
3466
3885
  "update-bundle": "panels.market.update",
3467
3886
  "remove-bundle": "panels.market.uninstall",
3468
3887
  uninstall: "panels.market.uninstall",
3469
- "update-dependency": "panels.market.update"
3888
+ "update-dependency": "panels.market.update",
3889
+ "update-plugin": "panels.market.update",
3890
+ "uninstall-plugin": "panels.market.uninstall"
3470
3891
  };
3471
3892
  //#endregion
3472
3893
  //#region src/app/layouts/rightbar/SharedSection.tsx
@@ -3514,21 +3935,18 @@ function SharedSection({ t, rows, pending, failureOf, act }) {
3514
3935
  pending,
3515
3936
  failure: failureOf(row.id),
3516
3937
  onAct: (action) => void act(row.id, action)
3517
- }))));
3518
- }
3519
- var PanelFoot_module_default = {
3520
- foot: "_foot_1us83_1",
3521
- footText: "_footText_1us83_12",
3522
- footTextMd: "_footTextMd_1us83_17"
3523
- };
3524
- //#endregion
3525
- //#region src/shared/components/PanelFoot.tsx
3526
- function PanelFoot({ text, size = "sm", children }) {
3527
- return /* @__PURE__ */ h("footer", { className: PanelFoot_module_default.foot }, /* @__PURE__ */ h("span", { className: size === "md" ? PanelFoot_module_default.footTextMd : PanelFoot_module_default.footText }, text), children ?? null);
3938
+ }))), /* @__PURE__ */ h(PanelFoot, {
3939
+ size: "md",
3940
+ text: t("panels.market.sharedFoot")
3941
+ }));
3528
3942
  }
3529
3943
  //#endregion
3530
3944
  //#region src/app/layouts/rightbar/MarketView.tsx
3531
- var CONFIRM_UNINSTALL = ["uninstall", "remove-bundle"];
3945
+ var CONFIRM_UNINSTALL = [
3946
+ "uninstall",
3947
+ "remove-bundle",
3948
+ "uninstall-plugin"
3949
+ ];
3532
3950
  var CONFIRM_REMOVE = ["remove-bundle"];
3533
3951
  function MarketLine({ t, row, pending, failure, onAct }) {
3534
3952
  const running = pending !== null && pending.id === row.id ? pending : null;
@@ -3538,7 +3956,7 @@ function MarketLine({ t, row, pending, failure, onAct }) {
3538
3956
  return /* @__PURE__ */ h("li", { className: MarketPage_module_default.marketRow }, /* @__PURE__ */ h("span", {
3539
3957
  className: MarketPage_module_default.marketIcon,
3540
3958
  "aria-hidden": "true"
3541
- }, /* @__PURE__ */ h(IconModules, { size: 18 })), /* @__PURE__ */ h("div", { className: MarketPage_module_default.marketMain }, /* @__PURE__ */ h("span", { className: MarketPage_module_default.marketName }, t(row.titleKey), row.version === void 0 ? null : /* @__PURE__ */ h("span", { className: MarketPage_module_default.marketVersion }, row.version.installed !== void 0 && row.version.latest !== void 0 && row.version.installed !== row.version.latest ? t("panels.market.versionArrow", {
3959
+ }, /* @__PURE__ */ h(IconModules, { size: 18 })), /* @__PURE__ */ h("div", { className: MarketPage_module_default.marketMain }, /* @__PURE__ */ h("span", { className: MarketPage_module_default.marketName }, marketRowTitle(row, t), row.version === void 0 ? null : /* @__PURE__ */ h("span", { className: MarketPage_module_default.marketVersion }, row.version.installed !== void 0 && row.version.latest !== void 0 && row.version.installed !== row.version.latest ? t("panels.market.versionArrow", {
3542
3960
  from: row.version.installed,
3543
3961
  to: row.version.latest
3544
3962
  }) : row.version.installed ?? row.version.latest ?? "")), /* @__PURE__ */ h("span", {
@@ -3563,11 +3981,14 @@ function MarketLine({ t, row, pending, failure, onAct }) {
3563
3981
  variant: action === "install" ? "primary" : "outline",
3564
3982
  className: danger ? "wb-dangerAction" : void 0,
3565
3983
  icon: danger ? /* @__PURE__ */ h(IconTrashOutlineRegular, { size: 13 }) : void 0,
3566
- "aria-label": danger ? t("panels.market.uninstallLabel", { name: t(row.titleKey) }) : void 0,
3984
+ "aria-label": danger ? t("panels.market.uninstallLabel", { name: marketRowTitle(row, t) }) : void 0,
3567
3985
  disabled: locked,
3568
3986
  onClick: () => onAct(action)
3569
3987
  }, t(ACTION_LABEL_KEY[action]));
3570
- }))), row.note === void 0 ? null : /* @__PURE__ */ h("div", { className: MarketPage_module_default.marketNote }, t(row.note.key, row.note.params)), failure === null ? null : /* @__PURE__ */ h("div", { className: MarketPage_module_default.marketFailure }, failure));
3988
+ }))), row.note === void 0 ? null : /* @__PURE__ */ h("div", {
3989
+ className: MarketPage_module_default.marketNote,
3990
+ title: row.note.params.reason === void 0 ? void 0 : t("panels.market.moduleRefusedDetail", row.note.params)
3991
+ }, t(row.note.key, row.note.params)), failure === null ? null : /* @__PURE__ */ h("div", { className: MarketPage_module_default.marketFailure }, failure));
3571
3992
  }
3572
3993
  function ConfirmUninstall({ t, name, onConfirm, onCancel }) {
3573
3994
  const [acknowledged, setAcknowledged] = useState(false);
@@ -3596,7 +4017,48 @@ function MarketSection({ t, titleKey, rows, pending, failureOf, act, confirmActi
3596
4017
  onAct: (action) => confirmActions.includes(action) ? onConfirming(row.id) : void act(row.id, action)
3597
4018
  }))));
3598
4019
  }
3599
- function MarketView({ t, manifests, capabilities, freshness, onChanged, updates, installed, installedRead, settling, mock }) {
4020
+ function MarketBody({ t, shown, pluginList, installedList, shared, pending, failed, notice, act, onConfirming }) {
4021
+ const failureOf = (id) => failed?.id === id ? failed.message : null;
4022
+ return /* @__PURE__ */ h(Fragment, null, notice === null ? null : /* @__PURE__ */ h("div", { className: MarketPage_module_default.marketNote }, notice), marketSections(shown).map((section) => /* @__PURE__ */ h(MarketSection, {
4023
+ key: section.id,
4024
+ t,
4025
+ titleKey: section.titleKey,
4026
+ rows: section.rows,
4027
+ pending,
4028
+ failureOf,
4029
+ act,
4030
+ confirmActions: CONFIRM_UNINSTALL,
4031
+ onConfirming
4032
+ })), /* @__PURE__ */ h(MarketSection, {
4033
+ t,
4034
+ titleKey: "panels.market.sectionPlugins",
4035
+ rows: pluginList,
4036
+ pending,
4037
+ failureOf,
4038
+ act,
4039
+ confirmActions: CONFIRM_UNINSTALL,
4040
+ onConfirming
4041
+ }), /* @__PURE__ */ h(MarketSection, {
4042
+ t,
4043
+ titleKey: installedList.length > 0 && installedList.every((row) => row.local === true) ? "panels.market.sectionLocal" : "panels.market.sectionUnlisted",
4044
+ rows: installedList,
4045
+ pending,
4046
+ failureOf,
4047
+ act,
4048
+ confirmActions: CONFIRM_REMOVE,
4049
+ onConfirming
4050
+ }), /* @__PURE__ */ h(PanelFoot, {
4051
+ size: "md",
4052
+ text: t("panels.market.foot")
4053
+ }), /* @__PURE__ */ h(SharedSection, {
4054
+ t,
4055
+ rows: shared,
4056
+ pending,
4057
+ failureOf,
4058
+ act
4059
+ }));
4060
+ }
4061
+ function MarketView({ t, manifests, capabilities, freshness, onChanged, updates, installed, installedRead, plugins, settling, mock }) {
3600
4062
  const [titles, setTitles] = useState(/* @__PURE__ */ new Map());
3601
4063
  useEffect(() => {
3602
4064
  if (mock === void 0) setTitles((known) => mergeTitles(known, manifests));
@@ -3613,6 +4075,7 @@ function MarketView({ t, manifests, capabilities, freshness, onChanged, updates,
3613
4075
  });
3614
4076
  const [confirming, setConfirming] = useState(mock?.confirming ?? null);
3615
4077
  const [failed, setFailed] = useState(mock?.failure ?? null);
4078
+ const [notice, setNotice] = useState(mock?.notice ?? null);
3616
4079
  const removing = pending !== null && pending.action === "remove-bundle" && failed?.id !== pending.id ? pending.id : null;
3617
4080
  const installedList = installedRows((mock?.installed ?? installed ?? []).filter((module) => !(settling?.has(module.unit) ?? false) && module.unit !== removing), catalog, new Set(rows.map((row) => row.id)), titles);
3618
4081
  const pendingRow = removing === null || pending === null || rows.some((row) => row.id === removing) ? void 0 : {
@@ -3626,7 +4089,12 @@ function MarketView({ t, manifests, capabilities, freshness, onChanged, updates,
3626
4089
  ...pending.version === void 0 ? {} : { version: { installed: pending.version } }
3627
4090
  };
3628
4091
  const shown = pendingRow === void 0 ? rows : [...rows, pendingRow];
3629
- const rowById = new Map([...shown, ...installedList].map((row) => [row.id, row]));
4092
+ const pluginList = installedPluginRows(mock?.plugins ?? plugins ?? []);
4093
+ const rowById = new Map([
4094
+ ...shown,
4095
+ ...installedList,
4096
+ ...pluginList
4097
+ ].map((row) => [row.id, row]));
3630
4098
  const confirmingRow = confirming === null ? void 0 : rowById.get(confirming);
3631
4099
  const act = async (id, action) => {
3632
4100
  if (mock !== void 0) return;
@@ -3640,13 +4108,15 @@ function MarketView({ t, manifests, capabilities, freshness, onChanged, updates,
3640
4108
  });
3641
4109
  setConfirming(null);
3642
4110
  setFailed(null);
4111
+ if (action !== "uninstall-plugin") setNotice(null);
3643
4112
  const dependency = action === "update-dependency";
4113
+ const byName = action === "remove-bundle" || action === "update-plugin" || action === "uninstall-plugin";
3644
4114
  const outcome = await provision.send(dependency ? {
3645
4115
  action,
3646
4116
  id
3647
- } : action === "remove-bundle" ? {
4117
+ } : byName ? {
3648
4118
  action,
3649
- name: rowById.get(id)?.pkg ?? ""
4119
+ name: row?.pkg ?? ""
3650
4120
  } : {
3651
4121
  action,
3652
4122
  unit: id
@@ -3660,6 +4130,10 @@ function MarketView({ t, manifests, capabilities, freshness, onChanged, updates,
3660
4130
  });
3661
4131
  return;
3662
4132
  }
4133
+ if (action === "uninstall-plugin") {
4134
+ const kept = installedPluginKept(outcome.value);
4135
+ setNotice(kept === void 0 ? null : t(kept.key, kept.names === void 0 ? {} : { names: kept.names.join(t("panels.market.listSeparator")) }));
4136
+ }
3663
4137
  const reason = changeFailure(changeOf(outcome.value), t);
3664
4138
  onChanged();
3665
4139
  if (reason !== void 0) setFailed({
@@ -3667,46 +4141,32 @@ function MarketView({ t, manifests, capabilities, freshness, onChanged, updates,
3667
4141
  message: t("panels.market.failed", { reason })
3668
4142
  });
3669
4143
  };
3670
- if (!(freshness.loaded && installedRead !== false) || (settling?.size ?? 0) > 0 && shown.length === 0 && installedList.length === 0) return /* @__PURE__ */ h(MarketChecking, { t });
3671
- if (shown.length === 0 && installedList.length === 0) return /* @__PURE__ */ h(MarketEmpty, { t });
3672
- return /* @__PURE__ */ h(Fragment, null, marketSections(shown).map((section) => /* @__PURE__ */ h(MarketSection, {
3673
- key: section.id,
3674
- t,
3675
- titleKey: section.titleKey,
3676
- rows: section.rows,
3677
- pending,
3678
- failureOf: (id) => failed?.id === id ? failed.message : null,
3679
- act,
3680
- confirmActions: CONFIRM_UNINSTALL,
3681
- onConfirming: setConfirming
3682
- })), /* @__PURE__ */ h(MarketSection, {
4144
+ const settled = freshness.loaded && installedRead !== false;
4145
+ const nothing = shown.length === 0 && installedList.length === 0 && pluginList.length === 0;
4146
+ if (!settled || (settling?.size ?? 0) > 0 && shown.length === 0 && installedList.length === 0) return /* @__PURE__ */ h(MarketChecking, { t });
4147
+ if (nothing) return /* @__PURE__ */ h(MarketEmpty, { t });
4148
+ return /* @__PURE__ */ h(Fragment, null, /* @__PURE__ */ h(MarketBody, {
3683
4149
  t,
3684
- titleKey: installedList.length > 0 && installedList.every((row) => row.local === true) ? "panels.market.sectionLocal" : "panels.market.sectionUnlisted",
3685
- rows: installedList,
4150
+ shown,
4151
+ pluginList,
4152
+ installedList,
4153
+ shared,
3686
4154
  pending,
3687
- failureOf: (id) => failed?.id === id ? failed.message : null,
4155
+ failed,
4156
+ notice,
3688
4157
  act,
3689
- confirmActions: CONFIRM_REMOVE,
3690
4158
  onConfirming: setConfirming
3691
- }), /* @__PURE__ */ h(PanelFoot, {
3692
- size: "md",
3693
- text: t("panels.market.foot")
3694
- }), /* @__PURE__ */ h(SharedSection, {
3695
- t,
3696
- rows: shared,
3697
- pending,
3698
- failureOf: (id) => failed?.id === id ? failed.message : null,
3699
- act
3700
4159
  }), /* @__PURE__ */ h(ConfirmUninstall, {
3701
4160
  key: confirming ?? "",
3702
4161
  t,
3703
- name: confirmingRow === void 0 ? null : t(confirmingRow.titleKey),
4162
+ name: confirmingRow === void 0 ? null : marketRowTitle(confirmingRow, t),
3704
4163
  onCancel: () => setConfirming(null),
3705
4164
  onConfirm: () => {
3706
4165
  const id = confirming;
3707
4166
  setConfirming(null);
3708
4167
  if (id === null) return;
3709
- act(id, rowById.get(id)?.pkg === void 0 ? "uninstall" : "remove-bundle");
4168
+ const row = rowById.get(id);
4169
+ act(id, row?.plugin === true ? "uninstall-plugin" : row?.pkg === void 0 ? "uninstall" : "remove-bundle");
3710
4170
  }
3711
4171
  }));
3712
4172
  }
@@ -3716,6 +4176,9 @@ var BUNDLE_REGISTRIES_ROUTE = "bundle-registries";
3716
4176
  var BUNDLE_INSPECT_ROUTE = "bundle-inspect";
3717
4177
  var MODULE_VERSIONS_ROUTE = "module-versions";
3718
4178
  //#endregion
4179
+ //#region src/shared/api/installed-plugins.ts
4180
+ var INSTALLED_PLUGINS_ROUTE = "panels/plugins";
4181
+ //#endregion
3719
4182
  //#region src/shared/hooks/bundle-queries.ts
3720
4183
  function readBundleRegistries() {
3721
4184
  return apiGet(BUNDLE_REGISTRIES_ROUTE);
@@ -3729,10 +4192,14 @@ function readBundleInspection(spec, registry) {
3729
4192
  function readModuleVersions(force = false) {
3730
4193
  return apiGet(MODULE_VERSIONS_ROUTE, force ? { force: "1" } : void 0);
3731
4194
  }
4195
+ function readInstalledPlugins(force = false) {
4196
+ return apiGet(INSTALLED_PLUGINS_ROUTE, force ? { force: "1" } : void 0);
4197
+ }
3732
4198
  //#endregion
3733
4199
  //#region src/app/layouts/market/use-module-versions.ts
3734
4200
  var state = {
3735
4201
  modules: null,
4202
+ plugins: null,
3736
4203
  read: false,
3737
4204
  checkedAt: null
3738
4205
  };
@@ -3757,10 +4224,13 @@ function runModuleVersionsRead(force = false) {
3757
4224
  if (inFlight !== null && inFlight.force === force) return inFlight.promise;
3758
4225
  const seq = readSeq += 1;
3759
4226
  if (force) newestForceSeq = seq;
3760
- const promise = readModuleVersions(force).catch(() => null).then((response) => {
4227
+ const promise = Promise.all([readModuleVersions(force), readInstalledPlugins(force)]).catch(() => null).then((responses) => {
3761
4228
  if (!force && seq < newestForceSeq) return;
4229
+ const versions = responses?.[0];
4230
+ const plugins = responses?.[1];
3762
4231
  publish({
3763
- modules: response?.ok === true ? response.modules : state.modules,
4232
+ modules: versions?.ok === true ? versions.modules : state.modules,
4233
+ plugins: plugins?.ok === true ? plugins.plugins : state.plugins,
3764
4234
  read: true,
3765
4235
  checkedAt: Date.now()
3766
4236
  });
@@ -3792,6 +4262,7 @@ function useModuleVersions() {
3792
4262
  }, []);
3793
4263
  return {
3794
4264
  modules: value.modules,
4265
+ plugins: value.plugins,
3795
4266
  read: value.read,
3796
4267
  checkedAt: value.checkedAt,
3797
4268
  reload
@@ -4010,7 +4481,7 @@ function AddModulePending({ t, kind }) {
4010
4481
  })), /* @__PURE__ */ h("h2", {
4011
4482
  className: AddModule_module_default.pendingTitle,
4012
4483
  role: "status"
4013
- }, kind === "inspecting" ? t("panels.market.add.checking") : t("panels.market.add.installingTitle"))));
4484
+ }, kind === "inspecting" ? t("panels.market.add.classifying") : t("panels.market.add.installingTitle"))));
4014
4485
  }
4015
4486
  function AddModulePreview({ t, state }) {
4016
4487
  const preview = state.preview;
@@ -4028,6 +4499,7 @@ function AddModuleResult({ t, state }) {
4028
4499
  const restart = outcome.change.application === "restart-required";
4029
4500
  const cancelled = outcome.change.application === "cancelled";
4030
4501
  const notModule = outcome.supply.state === "not-a-module";
4502
+ const plugin = outcome.plugin;
4031
4503
  const name = outcome.module.kind === "module" ? outcome.module.unit : outcome.module.pkg;
4032
4504
  return /* @__PURE__ */ h("div", { className: AddModule_module_default.body }, /* @__PURE__ */ h("div", { className: AddModule_module_default.hero }, /* @__PURE__ */ h("span", {
4033
4505
  className: AddModule_module_default.heroIcon,
@@ -4039,7 +4511,7 @@ function AddModuleResult({ t, state }) {
4039
4511
  }) : /* @__PURE__ */ h(IconCheckCircleFillRegular, { size: 28 })), /* @__PURE__ */ h("h2", {
4040
4512
  className: AddModule_module_default.wizardTitle,
4041
4513
  role: failed ? "alert" : "status"
4042
- }, failed ? t("panels.market.add.failedTitle") : cancelled ? t("panels.market.add.cancelledTitle") : t("panels.market.add.installedTitle"))), /* @__PURE__ */ h("div", { className: AddModule_module_default.subject }, /* @__PURE__ */ h("p", { className: AddModule_module_default.subjectName }, outcome.module.pkg), name === outcome.module.pkg ? null : /* @__PURE__ */ h("p", { className: AddModule_module_default.subjectMeta }, name), outcome.module.version === void 0 ? null : /* @__PURE__ */ h("p", { className: AddModule_module_default.subjectMeta }, t("panels.market.add.installVersion", { version: outcome.module.version }))), failed ? /* @__PURE__ */ h("p", {
4514
+ }, failed ? t("panels.market.add.failedTitle") : cancelled ? t("panels.market.add.cancelledTitle") : t("panels.market.add.installedTitle"))), /* @__PURE__ */ h("div", { className: AddModule_module_default.subject }, /* @__PURE__ */ h("p", { className: AddModule_module_default.subjectName }, outcome.module.pkg), name === outcome.module.pkg ? null : /* @__PURE__ */ h("p", { className: AddModule_module_default.subjectMeta }, name), outcome.module.version === void 0 ? null : /* @__PURE__ */ h("p", { className: AddModule_module_default.subjectMeta }, t("panels.market.add.installVersion", { version: outcome.module.version }))), plugin !== void 0 ? /* @__PURE__ */ h("p", { className: AddModule_module_default.result }, t("panels.market.add.installedPlugin", { name: plugin.name ?? plugin.pkg })) : failed ? /* @__PURE__ */ h("p", {
4043
4515
  className: AddModule_module_default.resultWarn,
4044
4516
  role: "alert"
4045
4517
  }, t("panels.market.add.failed", { reason })) : restart ? /* @__PURE__ */ h("p", { className: AddModule_module_default.resultWarn }, t("panels.market.add.doneRestart")) : cancelled || notModule ? null : /* @__PURE__ */ h("p", { className: AddModule_module_default.result }, t("panels.market.add.tookEffect")), builds.length === 0 ? null : /* @__PURE__ */ h("div", { className: AddModule_module_default.approval }, /* @__PURE__ */ h("p", { className: AddModule_module_default.approvalTitle }, t("panels.market.add.approveTitle")), /* @__PURE__ */ h("p", { className: AddModule_module_default.approvalText }, t("panels.market.add.approveHint", { packages: builds.join("、") })), /* @__PURE__ */ h("p", { className: AddModule_module_default.approvalCaution }, t("panels.market.add.approveCaution"))), supply === void 0 || outcome.supply.state !== "failed" && (failed || cancelled) ? null : /* @__PURE__ */ h("p", { className: supplyTone(outcome.supply.state) }, t(supply, { reason: outcome.supply.reason ?? "" })), state.failure === null ? null : /* @__PURE__ */ h("p", { className: AddModule_module_default.problem }, state.failure), outcome.change.errorDetail === void 0 ? null : /* @__PURE__ */ h(Fragment, null, /* @__PURE__ */ h("p", { className: AddModule_module_default.detailLabel }, t("panels.market.add.details")), /* @__PURE__ */ h("p", { className: AddModule_module_default.detail }, outcome.change.errorDetail)));
@@ -4110,6 +4582,7 @@ var ADD_MODULE_MOCKS = [
4110
4582
  refused("not-found"),
4111
4583
  refused("not-a-package"),
4112
4584
  refused("not-a-bundle"),
4585
+ refused("not-a-module-or-plugin", "这个包既不是工作台的模块,也不是 opencli 的插件,装了也用不上"),
4113
4586
  refused("network", "getaddrinfo ENOTFOUND registry.example.com"),
4114
4587
  refused("unknown", "pnpm 的返回码是 1"),
4115
4588
  {
@@ -4191,6 +4664,25 @@ var ADD_MODULE_MOCKS = [
4191
4664
  spec: "@dsh-workbench/module-hello",
4192
4665
  outcome: outcome({})
4193
4666
  },
4667
+ {
4668
+ id: "done-plugin",
4669
+ label: "装好了(opencli 插件)",
4670
+ phase: "result",
4671
+ spec: "opencli-plugin-cmdb",
4672
+ outcome: {
4673
+ change: change({ target: "opencli-plugin-cmdb" }),
4674
+ module: {
4675
+ kind: "unknown",
4676
+ pkg: "opencli-plugin-cmdb"
4677
+ },
4678
+ supply: { state: "no-needs" },
4679
+ plugin: {
4680
+ kind: "opencli-plugin",
4681
+ pkg: "opencli-plugin-cmdb",
4682
+ name: "cmdb"
4683
+ }
4684
+ }
4685
+ },
4194
4686
  {
4195
4687
  id: "done-restart",
4196
4688
  label: "装好了(要重启)",
@@ -4285,6 +4777,42 @@ function stateOfMock(base, mock) {
4285
4777
  };
4286
4778
  }
4287
4779
  //#endregion
4780
+ //#region src/shared/hooks/use-visible-busy.ts
4781
+ var use_visible_busy_exports = /* @__PURE__ */ __exportAll({
4782
+ busyView: () => busyView,
4783
+ heldPhase: () => heldPhase,
4784
+ useVisibleBusy: () => useVisibleBusy
4785
+ });
4786
+ function heldPhase(phase, refreshing) {
4787
+ return refreshing && phase === "ready" ? "loading" : phase;
4788
+ }
4789
+ function busyView(active, visible) {
4790
+ return {
4791
+ busy: visible,
4792
+ settling: visible && !active
4793
+ };
4794
+ }
4795
+ function useVisibleBusy(active, floorMs) {
4796
+ const [visible, setVisible] = useState(active);
4797
+ const since = useRef(null);
4798
+ useEffect(() => {
4799
+ if (active) {
4800
+ if (since.current === null) since.current = Date.now();
4801
+ setVisible(true);
4802
+ return;
4803
+ }
4804
+ const held = holdBusy(since.current, Date.now(), floorMs);
4805
+ since.current = null;
4806
+ if (!held.visible) {
4807
+ setVisible(false);
4808
+ return;
4809
+ }
4810
+ const timer = setTimeout(() => setVisible(false), held.releaseInMs);
4811
+ return () => clearTimeout(timer);
4812
+ }, [active, floorMs]);
4813
+ return busyView(active, visible);
4814
+ }
4815
+ //#endregion
4288
4816
  //#region src/app/layouts/market/use-add-module.ts
4289
4817
  function newRequestId() {
4290
4818
  return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
@@ -4307,6 +4835,7 @@ function useAddModule(options) {
4307
4835
  const [failure, setFailure] = useState(null);
4308
4836
  const generationRef = useRef(0);
4309
4837
  const requestIdRef = useRef("");
4838
+ const { busy: classifying } = useVisibleBusy(phase === "inspecting", 500);
4310
4839
  const write = useHostWrite({
4311
4840
  channel: "provision",
4312
4841
  networkText: failedText
@@ -4404,7 +4933,8 @@ function useAddModule(options) {
4404
4933
  setOutcome({
4405
4934
  change: value.change,
4406
4935
  module: value.module,
4407
- supply: value.supply
4936
+ supply: value.supply,
4937
+ ...value.plugin === void 0 ? {} : { plugin: value.plugin }
4408
4938
  });
4409
4939
  setPhase("result");
4410
4940
  if (value.change.application === "applied" || value.change.application === "restart-required") onInstalled();
@@ -4449,7 +4979,7 @@ function useAddModule(options) {
4449
4979
  custom,
4450
4980
  registryOpen,
4451
4981
  guideOpen,
4452
- phase,
4982
+ phase: heldWizardPhase(phase, classifying),
4453
4983
  choices,
4454
4984
  problem,
4455
4985
  preview,
@@ -4607,10 +5137,10 @@ function makeMarketEntryIcon(units) {
4607
5137
  function MarketPanel({ t, units }) {
4608
5138
  const manifests = useLiveManifests(units);
4609
5139
  const { capabilities, checkedAt, checking, forceProbe, reload: reloadCapability } = useCapabilityMap(0);
4610
- const { modules, read: installedRead, reload: reloadVersions } = useModuleVersions();
5140
+ const { modules, plugins, read: installedRead, reload: reloadVersions } = useModuleVersions();
4611
5141
  const [adding, setAdding] = useState(false);
4612
5142
  const updates = useMemo(() => marketUpdatesOf(modules), [modules]);
4613
- const installed = modules ?? void 0;
5143
+ const installed = modules === null ? void 0 : withClientRefusals(modules, units.refusals());
4614
5144
  const reload = useCallback(() => {
4615
5145
  reloadCapability();
4616
5146
  reloadVersions();
@@ -4699,6 +5229,7 @@ function MarketPanel({ t, units }) {
4699
5229
  updates,
4700
5230
  installed,
4701
5231
  installedRead: mock === void 0 ? installedRead : mock.installedRead ?? true,
5232
+ plugins,
4702
5233
  settling: mock === void 0 ? settling : void 0,
4703
5234
  mock
4704
5235
  }), /* @__PURE__ */ h(AddModuleDialog, {
@@ -4754,6 +5285,41 @@ var CLIENT_UNITS = [];
4754
5285
  function assembleClientUnits(registry) {
4755
5286
  for (const face of CLIENT_UNITS) registry.register(face);
4756
5287
  }
5288
+ //#endregion
5289
+ //#region src/shared/api/unit-manifests.ts
5290
+ var UNIT_MANIFESTS_ROUTE = "unit-manifests";
5291
+ //#endregion
5292
+ //#region src/app/units/manifests.ts
5293
+ function createUnitManifestLoader(options = {}) {
5294
+ let inFlight = false;
5295
+ let queued = false;
5296
+ let watching = false;
5297
+ const subscribeFacts = options.subscribeFacts ?? subscribeFactRevision;
5298
+ const load = async (registry) => {
5299
+ if (inFlight) {
5300
+ queued = true;
5301
+ return;
5302
+ }
5303
+ inFlight = true;
5304
+ try {
5305
+ const response = await apiGet(UNIT_MANIFESTS_ROUTE).catch(() => null);
5306
+ if (response?.ok === true && Array.isArray(response.manifests)) registry.setManifests(response.manifests);
5307
+ } finally {
5308
+ inFlight = false;
5309
+ if (queued) {
5310
+ queued = false;
5311
+ load(registry);
5312
+ }
5313
+ }
5314
+ };
5315
+ return (registry) => {
5316
+ if (!watching) {
5317
+ watching = true;
5318
+ subscribeFacts(factOfRoute(UNIT_MANIFESTS_ROUTE), () => void load(registry));
5319
+ }
5320
+ load(registry);
5321
+ };
5322
+ }
4757
5323
  var BootGate_module_default = {
4758
5324
  actions: "_actions_jlw8j_1",
4759
5325
  progress: "_progress_jlw8j_2",
@@ -7431,42 +7997,6 @@ function useLongTask(options) {
7431
7997
  return { runs };
7432
7998
  }
7433
7999
  //#endregion
7434
- //#region src/shared/hooks/use-visible-busy.ts
7435
- var use_visible_busy_exports = /* @__PURE__ */ __exportAll({
7436
- busyView: () => busyView,
7437
- heldPhase: () => heldPhase,
7438
- useVisibleBusy: () => useVisibleBusy
7439
- });
7440
- function heldPhase(phase, refreshing) {
7441
- return refreshing && phase === "ready" ? "loading" : phase;
7442
- }
7443
- function busyView(active, visible) {
7444
- return {
7445
- busy: visible,
7446
- settling: visible && !active
7447
- };
7448
- }
7449
- function useVisibleBusy(active, floorMs) {
7450
- const [visible, setVisible] = useState(active);
7451
- const since = useRef(null);
7452
- useEffect(() => {
7453
- if (active) {
7454
- if (since.current === null) since.current = Date.now();
7455
- setVisible(true);
7456
- return;
7457
- }
7458
- const held = holdBusy(since.current, Date.now(), floorMs);
7459
- since.current = null;
7460
- if (!held.visible) {
7461
- setVisible(false);
7462
- return;
7463
- }
7464
- const timer = setTimeout(() => setVisible(false), held.releaseInMs);
7465
- return () => clearTimeout(timer);
7466
- }, [active, floorMs]);
7467
- return busyView(active, visible);
7468
- }
7469
- //#endregion
7470
8000
  //#region src/shared/hooks/use-unit-board.ts
7471
8001
  var use_unit_board_exports = /* @__PURE__ */ __exportAll({ useUnitBoard: () => useUnitBoard });
7472
8002
  function useUnitBoard(options) {
@@ -7680,7 +8210,7 @@ var kit = {
7680
8210
  };
7681
8211
  function messagesOf(units) {
7682
8212
  return units.map((face) => ({
7683
- unit: face.manifest.id,
8213
+ unit: face.unit,
7684
8214
  ...face.messages === void 0 ? {} : { messages: face.messages }
7685
8215
  }));
7686
8216
  }
@@ -7721,12 +8251,14 @@ function apply(ctx) {
7721
8251
  }
7722
8252
  }
7723
8253
  function mount(ctx) {
7724
- const units = createClientUnitRegistry();
8254
+ const loadUnitManifests = createUnitManifestLoader();
8255
+ const units = createClientUnitRegistry({ onUnknownUnit: () => loadUnitManifests(units) });
7725
8256
  ctx.provide(UNITS_SERVICE, {
7726
8257
  registerUnit: (face) => units.register(face),
7727
8258
  manifests: () => units.manifests()
7728
8259
  });
7729
8260
  assembleClientUnits(units);
8261
+ loadUnitManifests(units);
7730
8262
  const store = rightbarStore;
7731
8263
  const observable = {
7732
8264
  getSnapshot: () => store.getSnapshot(),