@dsh-workbench/core 0.1.15 → 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 (74) hide show
  1. package/README.md +19 -0
  2. package/bin/dsh-workbench +5 -1
  3. package/client.js +660 -128
  4. package/cordis.patch.yml +22 -0
  5. package/dist/client/client.body.js +660 -128
  6. package/dist/client/index.js +660 -128
  7. package/dist/host/index.js +1733 -324
  8. package/dist/types/app/client.d.ts +124 -9
  9. package/dist/types/app/layouts/market/add-module-text.d.ts +2 -0
  10. package/dist/types/app/layouts/market/use-add-module.d.ts +4 -3
  11. package/dist/types/app/layouts/market/use-module-versions.d.ts +2 -0
  12. package/dist/types/app/layouts/rightbar/MarketView.d.ts +3 -1
  13. package/dist/types/app/layouts/rightbar/__tests__/market-rows-plugins.test.d.ts +1 -0
  14. package/dist/types/app/layouts/rightbar/market-mock.d.ts +9 -0
  15. package/dist/types/app/layouts/rightbar/market-plugin-rows.d.ts +8 -0
  16. package/dist/types/app/layouts/rightbar/market-rows.d.ts +14 -3
  17. package/dist/types/app/layouts/rightbar/registry.d.ts +0 -1
  18. package/dist/types/app/units/__tests__/manifests.test.d.ts +1 -0
  19. package/dist/types/app/units/fixture-unit-mock.d.ts +3 -3
  20. package/dist/types/app/units/host.d.ts +2 -2
  21. package/dist/types/app/units/manifests.d.ts +5 -0
  22. package/dist/types/app/units/registry.d.ts +10 -2
  23. package/dist/types/modules/panels/__tests__/market-env.test.d.ts +1 -0
  24. package/dist/types/modules/panels/__tests__/market-plugin.test.d.ts +1 -0
  25. package/dist/types/modules/panels/__tests__/market-route.test.d.ts +1 -0
  26. package/dist/types/modules/panels/__tests__/plugin-actions.test.d.ts +1 -0
  27. package/dist/types/modules/panels/__tests__/plugin-ledger.test.d.ts +1 -0
  28. package/dist/types/modules/panels/__tests__/plugin-section.test.d.ts +1 -0
  29. package/dist/types/modules/panels/__tests__/scope.test.d.ts +1 -0
  30. package/dist/types/modules/panels/__tests__/service-release.test.d.ts +1 -0
  31. package/dist/types/modules/panels/index.d.ts +2 -2
  32. package/dist/types/modules/panels/model/config.d.ts +27 -9
  33. package/dist/types/modules/panels/model/market-dispatch.d.ts +9 -0
  34. package/dist/types/modules/panels/model/market-env.d.ts +20 -0
  35. package/dist/types/modules/panels/model/market-route.d.ts +26 -0
  36. package/dist/types/modules/panels/model/market-types.d.ts +71 -0
  37. package/dist/types/modules/panels/model/market.d.ts +7 -66
  38. package/dist/types/modules/panels/model/plugin-actions.d.ts +50 -0
  39. package/dist/types/modules/panels/model/plugin-ledger.d.ts +22 -0
  40. package/dist/types/modules/panels/model/plugin-name.d.ts +8 -0
  41. package/dist/types/modules/panels/model/plugin-name.test.d.ts +1 -0
  42. package/dist/types/modules/panels/model/plugin-section.d.ts +13 -0
  43. package/dist/types/modules/panels/model/service.d.ts +8 -6
  44. package/dist/types/shared/api/bundle-install.d.ts +8 -1
  45. package/dist/types/shared/api/host/__tests__/registry-declaration.test.d.ts +1 -0
  46. package/dist/types/shared/api/host/__tests__/unit-roster-facts.test.d.ts +1 -0
  47. package/dist/types/shared/api/host/bundle-routes.d.ts +1 -0
  48. package/dist/types/shared/api/host/installed-module.d.ts +7 -0
  49. package/dist/types/shared/api/host/mount-units.d.ts +5 -3
  50. package/dist/types/shared/api/host/package-content.d.ts +6 -0
  51. package/dist/types/shared/api/host/package-content.test.d.ts +1 -0
  52. package/dist/types/shared/api/host/package-kind.d.ts +21 -0
  53. package/dist/types/shared/api/host/package-kind.test.d.ts +1 -0
  54. package/dist/types/shared/api/host/package-route.d.ts +23 -0
  55. package/dist/types/shared/api/host/package-route.test.d.ts +1 -0
  56. package/dist/types/shared/api/host/registry-declaration.d.ts +23 -0
  57. package/dist/types/shared/api/host/runtime-seed.d.ts +40 -0
  58. package/dist/types/shared/api/host/runtime-seed.test.d.ts +1 -0
  59. package/dist/types/shared/api/host/unit-registry.d.ts +33 -4
  60. package/dist/types/shared/api/host/unit-roster-facts.d.ts +5 -0
  61. package/dist/types/shared/api/installed-plugins.d.ts +12 -0
  62. package/dist/types/shared/api/unit-manifests.d.ts +5 -0
  63. package/dist/types/shared/api/unit-manifests.test.d.ts +1 -0
  64. package/dist/types/shared/hooks/bundle-queries.d.ts +2 -0
  65. package/dist/types/shared/hooks/use-facts.d.ts +1 -0
  66. package/docs/HANDOFF.md +82 -44
  67. package/docs/OPERATIONS.md +22 -1
  68. package/package.json +5 -4
  69. package/scripts/seed-workshop.sh +216 -0
  70. package/skills/workbench-module-diy/BUILD.md +5 -5
  71. package/skills/workbench-module-diy/DESIGN.md +7 -1
  72. package/skills/workbench-module-diy/REVIEW.md +3 -2
  73. package/skills/workbench-module-diy/TOOLING.md +2 -2
  74. package/skills/workbench-module-diy/TOOLS.md +9 -2
package/client.js CHANGED
@@ -426,6 +426,121 @@ window.__ModuleLoader__.load({
426
426
  if (error === void 0) return null;
427
427
  return error.code === "" ? "unknown" : error.code;
428
428
  }
429
+ var SUPPORTED_API_VERSIONS = [1];
430
+ var DECLARATION_KEYS = [
431
+ "apiVersion",
432
+ "unit",
433
+ "card",
434
+ "tools",
435
+ "host",
436
+ "env"
437
+ ];
438
+ var DECLARATION_REQUIRED_KEYS = [
439
+ "apiVersion",
440
+ "unit",
441
+ "card",
442
+ "tools",
443
+ "host"
444
+ ];
445
+ var CARD_KEYS = ["titleKey", "order"];
446
+ var TOOL_KEYS = ["name", "writes"];
447
+ var HOST_KEYS = ["inject", "optional"];
448
+ function text(value) {
449
+ return typeof value === "string" ? value.trim() : "";
450
+ }
451
+ function isRecord(value) {
452
+ return typeof value === "object" && value !== null && !Array.isArray(value);
453
+ }
454
+ function outsideKeys(value, allowed) {
455
+ return Object.keys(value).filter((key) => !allowed.includes(key));
456
+ }
457
+ function listOf(keys) {
458
+ return keys.map((key) => JSON.stringify(key)).join(" / ");
459
+ }
460
+ function stringArrayProblems(at, value) {
461
+ if (!Array.isArray(value)) return [`${at} 要是一串字符串,现在是 ${JSON.stringify(value)}`];
462
+ return value.flatMap((item, index) => text(item) === "" ? [`${at}[${index}] 不是非空字符串:${JSON.stringify(item)}`] : []);
463
+ }
464
+ function declarationProblemsOf(subject, raw) {
465
+ if (!isRecord(raw)) return [`${subject}: dsh.workbench 不是一个对象 —— ${JSON.stringify(raw)}`];
466
+ const version = raw.apiVersion;
467
+ if (version === void 0) return [`${subject}: dsh.workbench 没有 apiVersion —— 协议从 v1 起,写 \`"apiVersion": 1\`。缺它 = 外壳不认这个模块(ADR-0038 §2.3)`];
468
+ if (!Number.isInteger(version) || !SUPPORTED_API_VERSIONS.includes(version)) return [`${subject}: dsh.workbench.apiVersion 是 ${JSON.stringify(version)},这里只认 ${SUPPORTED_API_VERSIONS.join(" / ")}(要整数)`];
469
+ const problems = [];
470
+ const unknown = outsideKeys(raw, DECLARATION_KEYS);
471
+ if (unknown.length > 0) problems.push(`${subject}: dsh.workbench 里有协议 v1 不认识的键 ${listOf(unknown)} —— 只有 ${listOf(DECLARATION_KEYS)}。(拼错的键会被外壳**静默忽略**:那句声明等于没写)`);
472
+ for (const key of DECLARATION_REQUIRED_KEYS) if (raw[key] === void 0) problems.push(`${subject}: dsh.workbench 缺 ${key}` + (key === "card" ? "(这个模块没有卡片就写 `\"card\": null`)" : ""));
473
+ const card = raw.card;
474
+ if (card !== void 0 && card !== null) {
475
+ if (!isRecord(card)) problems.push(`${subject}: dsh.workbench.card 要么是对象、要么是 null,现在是 ${JSON.stringify(card)}`);
476
+ else {
477
+ const extra = outsideKeys(card, CARD_KEYS);
478
+ if (extra.length > 0) problems.push(`${subject}: dsh.workbench.card 里有不认的键 ${listOf(extra)} —— card 只有 ${listOf(CARD_KEYS)}(卡片默认显不显示由运行期的面板配置决定,清单里没有这一位)`);
479
+ if (text(card.titleKey) === "") problems.push(`${subject}: dsh.workbench.card.titleKey 要是非空字符串(面板那一格的文案键)`);
480
+ if (typeof card.order !== "number" || !Number.isFinite(card.order)) problems.push(`${subject}: dsh.workbench.card.order 要是数字,现在是 ${JSON.stringify(card.order)}`);
481
+ }
482
+ }
483
+ const tools = raw.tools;
484
+ if (tools !== void 0) {
485
+ if (!Array.isArray(tools)) problems.push(`${subject}: dsh.workbench.tools 要是一串声明,现在是 ${JSON.stringify(tools)}`);
486
+ else {
487
+ const seen = /* @__PURE__ */ new Set();
488
+ tools.forEach((tool, index) => {
489
+ const at = `dsh.workbench.tools[${index}]`;
490
+ if (!isRecord(tool)) {
491
+ problems.push(`${subject}: ${at} 要是对象,现在是 ${JSON.stringify(tool)}`);
492
+ return;
493
+ }
494
+ const extra = outsideKeys(tool, TOOL_KEYS);
495
+ if (extra.length > 0) problems.push(`${subject}: ${at} 里有不认的键 ${listOf(extra)} —— tools 只有 ${listOf(TOOL_KEYS)}`);
496
+ const name = text(tool.name);
497
+ if (name === "") problems.push(`${subject}: ${at}.name 要是非空字符串`);
498
+ else if (seen.has(name)) problems.push(`${subject}: ${at}.name「${name}」与前面那条撞了 —— 工具名会进 dsh 的工具表,不许重`);
499
+ else seen.add(name);
500
+ if (typeof tool.writes !== "boolean") problems.push(`${subject}: ${at}.writes 要是 true / false(它是"这会写"的唯一声明,缺了审批无从认领)`);
501
+ });
502
+ }
503
+ }
504
+ const host = raw.host;
505
+ if (host !== void 0) {
506
+ if (!isRecord(host)) problems.push(`${subject}: dsh.workbench.host 要是对象,现在是 ${JSON.stringify(host)}`);
507
+ else {
508
+ const extra = outsideKeys(host, HOST_KEYS);
509
+ if (extra.length > 0) problems.push(`${subject}: dsh.workbench.host 里有不认的键 ${listOf(extra)} —— host 只有 ${listOf(HOST_KEYS)}`);
510
+ if (host.inject === void 0) problems.push(`${subject}: dsh.workbench.host.inject 没写 —— 它声明这个模块要外壳的哪几个服务,外壳靠它判"能不能挂"。一个都不要也要写 \`"inject": []\``);
511
+ else problems.push(...stringArrayProblems(`${subject}: dsh.workbench.host.inject`, host.inject));
512
+ if (host.optional !== void 0) problems.push(...stringArrayProblems(`${subject}: dsh.workbench.host.optional`, host.optional));
513
+ }
514
+ }
515
+ if (raw.env !== void 0 && !isRecord(raw.env)) problems.push(`${subject}: dsh.workbench.env 要是对象(command / plugins / libs)—— 语义由门禁的 env 判据查,这里只查形状`);
516
+ return problems;
517
+ }
518
+ function readDeclaration(subject, raw) {
519
+ const problems = declarationProblemsOf(subject, raw);
520
+ if (problems.length > 0) return { problems };
521
+ const declaration = raw;
522
+ const card = declaration.card;
523
+ return {
524
+ declaration,
525
+ problems: [],
526
+ manifest: {
527
+ id: text(declaration.unit),
528
+ card: card === null ? null : {
529
+ titleKey: text(card.titleKey),
530
+ order: card.order
531
+ },
532
+ tools: declaration.tools.map((tool) => ({
533
+ name: text(tool.name),
534
+ writes: tool.writes
535
+ })),
536
+ host: {
537
+ inject: [...declaration.host.inject ?? []],
538
+ ...declaration.host.optional === void 0 ? {} : { optional: [...declaration.host.optional] }
539
+ },
540
+ ...declaration.env === void 0 ? {} : { env: declaration.env }
541
+ }
542
+ };
543
+ }
429
544
  //#endregion
430
545
  //#region ../shared/dist/config/constants.js
431
546
  var PLUGIN_ID = "@dsh-workbench/core";
@@ -613,7 +728,7 @@ window.__ModuleLoader__.load({
613
728
  if (owner?.approval !== void 0) {
614
729
  const Render = owner.approval.render;
615
730
  return h(CardBoundary, {
616
- unit: owner.manifest.id,
731
+ unit: owner.unit,
617
732
  resetKey: props.callId ?? "",
618
733
  t
619
734
  }, h(Render, {
@@ -1118,6 +1233,7 @@ window.__ModuleLoader__.load({
1118
1233
  "panels.market.sectionPending": "Not installed",
1119
1234
  "panels.market.sectionShared": "Shared dependencies",
1120
1235
  "panels.market.sharedUsedBy": "Used by {modules}",
1236
+ "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.",
1121
1237
  "panels.market.listSeparator": ", ",
1122
1238
  "panels.market.sharedMissing": "not installed",
1123
1239
  "panels.market.sharedOutdated": "update available",
@@ -1145,8 +1261,18 @@ window.__ModuleLoader__.load({
1145
1261
  "panels.market.installedSection": "Installed",
1146
1262
  "panels.market.sectionLocal": "Linked locally",
1147
1263
  "panels.market.sectionUnlisted": "Not from the market",
1264
+ "panels.market.sectionPlugins": "Installed opencli plugins",
1148
1265
  "panels.market.moduleOutdated": "update available",
1266
+ "panels.market.moduleRefused": "This module was built for an older version of the workbench, so it does not work here. Update it, or uninstall.",
1267
+ "panels.market.moduleRefusedDetail": "Why it cannot be used: {reason}",
1149
1268
  "panels.market.moduleRestartHint": "installed but not active — restart dsh once to bring it up",
1269
+ "panels.market.pluginLocalNoUpdate": "Installed from a local folder, so there is nowhere to check for a newer version — uninstall only",
1270
+ "panels.market.pluginKeptInUse": "Files kept for now: {names} still uses it.",
1271
+ "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.",
1272
+ "panels.market.pluginKeptHeld": "Files kept: this one is yours, and a module letting go will not remove it.",
1273
+ "panels.market.pluginKeptUnnamed": "Files kept for now: this one cannot be identified as a plugin, so it is unclear who needs it.",
1274
+ "panels.market.pluginAlsoKnownAs": "Its package is {pkg} (updates and uninstall use that)",
1275
+ "panels.market.pluginBroken": "This install is broken: it cannot be identified as a plugin. Uninstall it, or install it again by package name above.",
1150
1276
  "panels.market.restartNeeded": "The new version is installed — restart once to pick it up.",
1151
1277
  "panels.market.foot": "After installing, enable it in the panel page of that project.",
1152
1278
  "panels.market.recheck": "Check for updates",
@@ -1194,7 +1320,11 @@ window.__ModuleLoader__.load({
1194
1320
  "panels.market.add.problemInstalled": "This module is already installed",
1195
1321
  "panels.market.add.problemNotFound": "No such module found",
1196
1322
  "panels.market.add.problemNotPackage": "That path does not exist or is not a valid module package",
1197
- "panels.market.add.problemNotBundle": "This package declares no bundle, so it cannot be installed as a module: {reason}",
1323
+ "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.",
1324
+ "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.",
1325
+ "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.",
1326
+ "panels.market.add.failureNotModuleOrPlugin": "This package is neither a workbench module nor an opencli plugin, so installing it would do nothing",
1327
+ "panels.market.add.installedPlugin": "Installed: the opencli plugin {name}",
1198
1328
  "panels.market.add.problemNetwork": "Cannot reach the module source; check the network and retry",
1199
1329
  "panels.market.add.problemUnknown": "Cannot fetch module information: {reason}",
1200
1330
  "panels.market.add.failureNetwork": "The network connection failed",
@@ -1225,6 +1355,7 @@ window.__ModuleLoader__.load({
1225
1355
  "panels.market.add.registryPnpm": "pnpm's own registry",
1226
1356
  "panels.market.add.check": "Check",
1227
1357
  "panels.market.add.checking": "Checking…",
1358
+ "panels.market.add.classifying": "Working out what it is…",
1228
1359
  "panels.market.add.change": "Edit",
1229
1360
  "panels.market.add.previewTitle": "About to install",
1230
1361
  "panels.market.add.fieldName": "Package",
@@ -1433,6 +1564,7 @@ window.__ModuleLoader__.load({
1433
1564
  "panels.market.sectionPending": "未安装",
1434
1565
  "panels.market.sectionShared": "共用依赖",
1435
1566
  "panels.market.sharedUsedBy": "供 {modules} 使用",
1567
+ "panels.market.sharedFoot": "这一段不给卸载:它们跟着模块来,卸掉也会被装回来。要停用一份,就去关掉正在用它的那些模块。",
1436
1568
  "panels.market.listSeparator": "、",
1437
1569
  "panels.market.sharedMissing": "未装",
1438
1570
  "panels.market.sharedOutdated": "有新版",
@@ -1460,8 +1592,18 @@ window.__ModuleLoader__.load({
1460
1592
  "panels.market.installedSection": "已安装",
1461
1593
  "panels.market.sectionLocal": "本地装的",
1462
1594
  "panels.market.sectionUnlisted": "不是从市场装的",
1595
+ "panels.market.sectionPlugins": "已安装 opencli 插件",
1463
1596
  "panels.market.moduleOutdated": "有新版",
1597
+ "panels.market.moduleRefused": "这个模块是给旧版本的工作台写的,现在用不了。更新它,或者卸载。",
1598
+ "panels.market.moduleRefusedDetail": "装不上的原因:{reason}",
1464
1599
  "panels.market.moduleRestartHint": "装好了但还没生效 —— 重启一次 dsh 就会出来",
1600
+ "panels.market.pluginLocalNoUpdate": "本地装的,没地方查新版,所以只给卸载",
1601
+ "panels.market.pluginKeptInUse": "文件先留着:{names} 还要用它。",
1602
+ "panels.market.pluginKeptUnsure": "文件先留着:这台机器上还有模块看不出用了什么,说不准谁在用它。",
1603
+ "panels.market.pluginKeptHeld": "文件留着:你自己装的那一份,模块放手不动它。",
1604
+ "panels.market.pluginKeptUnnamed": "文件先留着:看不出这是哪个插件,说不准谁在用它。",
1605
+ "panels.market.pluginAlsoKnownAs": "包名是 {pkg}(更新与卸载按它来)",
1606
+ "panels.market.pluginBroken": "这份装坏了:看不出它是个插件。可以卸载,或者去上面按包名再装一次。",
1465
1607
  "panels.market.restartNeeded": "新版装好了,重启一次才生效。",
1466
1608
  "panels.market.foot": "装好后到那个项目的面板页勾选它,模块才会出现。",
1467
1609
  "panels.market.recheck": "重新检查更新",
@@ -1509,7 +1651,11 @@ window.__ModuleLoader__.load({
1509
1651
  "panels.market.add.problemInstalled": "该模块已安装",
1510
1652
  "panels.market.add.problemNotFound": "未找到相关模块",
1511
1653
  "panels.market.add.problemNotPackage": "该路径不存在或不是有效的模块包",
1512
- "panels.market.add.problemNotBundle": "这个包没有声明组合包,无法作为模块安装:{reason}",
1654
+ "panels.market.add.problemNotBundle": "这个包装不进这里:{reason}。要是它其实是个 opencli 插件,请改用包名(例如 opencli-plugin-cmdb)或者本地目录 —— 从 git 地址和 tarball 判断不出它是什么。",
1655
+ "panels.market.add.problemNotWorkbenchModule": "这个包跟现在的工作台对不上,装上也用不了。换一个版本,或者找这个模块的作者。",
1656
+ "panels.market.add.problemNotModuleOrPlugin": "这个包既不是工作台的模块,也不是 opencli 的插件,装了也用不上。换一个版本,或者找这个包的作者。",
1657
+ "panels.market.add.failureNotModuleOrPlugin": "这个包既不是工作台的模块,也不是 opencli 的插件,装了也用不上",
1658
+ "panels.market.add.installedPlugin": "装上了:opencli 插件 {name}",
1513
1659
  "panels.market.add.problemNetwork": "无法连接模块源,请检查网络后重试",
1514
1660
  "panels.market.add.problemUnknown": "无法获取模块信息:{reason}",
1515
1661
  "panels.market.add.failureNetwork": "网络连接失败",
@@ -1540,6 +1686,7 @@ window.__ModuleLoader__.load({
1540
1686
  "panels.market.add.registryPnpm": "pnpm 自己配的源",
1541
1687
  "panels.market.add.check": "预检",
1542
1688
  "panels.market.add.checking": "正在预检…",
1689
+ "panels.market.add.classifying": "判定中…",
1543
1690
  "panels.market.add.change": "改一下",
1544
1691
  "panels.market.add.previewTitle": "将要安装",
1545
1692
  "panels.market.add.fieldName": "包名",
@@ -1816,6 +1963,8 @@ window.__ModuleLoader__.load({
1816
1963
  CenteredState: () => CenteredState,
1817
1964
  ChoiceGroup: () => ChoiceGroup,
1818
1965
  Component: () => Component,
1966
+ DECLARATION_KEYS: () => DECLARATION_KEYS,
1967
+ DECLARATION_REQUIRED_KEYS: () => DECLARATION_REQUIRED_KEYS,
1819
1968
  DEFAULT_WORKSPACE_TITLE: () => DEFAULT_WORKSPACE_TITLE,
1820
1969
  EVENTS_PATH: () => EVENTS_PATH,
1821
1970
  EmptyState: () => EmptyState,
@@ -1854,6 +2003,7 @@ window.__ModuleLoader__.load({
1854
2003
  STORAGE_KEY_PROJECT: () => STORAGE_KEY_PROJECT,
1855
2004
  STORAGE_KEY_RIGHTBAR: () => STORAGE_KEY_RIGHTBAR,
1856
2005
  STORAGE_KEY_RIGHTBAR_COLUMN: () => STORAGE_KEY_RIGHTBAR_COLUMN,
2006
+ SUPPORTED_API_VERSIONS: () => SUPPORTED_API_VERSIONS,
1857
2007
  SaveBar: () => SaveBar,
1858
2008
  SettingsSection: () => SettingsSection,
1859
2009
  SkeletonRows: () => SkeletonRows,
@@ -1864,6 +2014,7 @@ window.__ModuleLoader__.load({
1864
2014
  VERSION_CHECK_TIMEOUT_MS: () => VERSION_CHECK_TIMEOUT_MS,
1865
2015
  VERSION_CHECK_TTL_MS: () => VERSION_CHECK_TTL_MS,
1866
2016
  WARM_TIMEOUT_MS: () => WARM_TIMEOUT_MS,
2017
+ WORKBENCH_API_VERSION: () => 1,
1867
2018
  apiGet: () => apiGet,
1868
2019
  apiPost: () => apiPost,
1869
2020
  blockerActionLabel: () => blockerActionLabel,
@@ -1873,6 +2024,7 @@ window.__ModuleLoader__.load({
1873
2024
  buildMarker: () => buildMarker,
1874
2025
  createFactChannel: () => createFactChannel,
1875
2026
  cx: () => cx,
2027
+ declarationProblemsOf: () => declarationProblemsOf,
1876
2028
  decodeRef: () => decodeRef,
1877
2029
  dictionaries: () => dictionaries,
1878
2030
  en: () => en,
@@ -1896,6 +2048,7 @@ window.__ModuleLoader__.load({
1896
2048
  parseMarkers: () => parseMarkers,
1897
2049
  probeKeyOf: () => probeKeyOf,
1898
2050
  quoteShellArg: () => quoteShellArg,
2051
+ readDeclaration: () => readDeclaration,
1899
2052
  readFlag: () => readFlag,
1900
2053
  readText: () => readText,
1901
2054
  relativeTime: () => relativeTime,
@@ -2008,6 +2161,7 @@ window.__ModuleLoader__.load({
2008
2161
  //#endregion
2009
2162
  //#region src/shared/hooks/use-facts.ts
2010
2163
  var use_facts_exports = /* @__PURE__ */ __exportAll({
2164
+ subscribeFactRevision: () => subscribeFactRevision,
2011
2165
  useFactInvalidate: () => useFactInvalidate,
2012
2166
  useFactRevision: () => useFactRevision
2013
2167
  });
@@ -2015,6 +2169,9 @@ window.__ModuleLoader__.load({
2015
2169
  function useFactRevision(fact) {
2016
2170
  return useSyncExternalStore(useCallback((listener) => channel.subscribe(fact, listener), [fact]), useCallback(() => channel.revisionOf(fact), [fact]));
2017
2171
  }
2172
+ function subscribeFactRevision(fact, listener) {
2173
+ return channel.subscribe(fact, listener);
2174
+ }
2018
2175
  function useFactInvalidate() {
2019
2176
  return useCallback((fact) => channel.refresh(fact), []);
2020
2177
  }
@@ -2539,8 +2696,7 @@ window.__ModuleLoader__.load({
2539
2696
  ...mine,
2540
2697
  card: {
2541
2698
  titleKey: "一个名字特别特别长的模块用来验证省略号会不会把按钮挤下去",
2542
- order: 10,
2543
- enabledByDefault: true
2699
+ order: 10
2544
2700
  }
2545
2701
  }],
2546
2702
  capabilities: probe$1(id, "ok"),
@@ -2644,6 +2800,24 @@ window.__ModuleLoader__.load({
2644
2800
  installedActions: ["update-bundle", "remove-bundle"]
2645
2801
  }
2646
2802
  },
2803
+ {
2804
+ id: "installed-client-refused",
2805
+ label: "本机装了,但浏览器这半没挂上(拒因由客户端报告)",
2806
+ manifests: [found],
2807
+ capabilities: {},
2808
+ installed: [{
2809
+ unit: id,
2810
+ pkg: "@dsh-workbench/module-one",
2811
+ installed: "0.1.2",
2812
+ clientRefused: [`宿主没有担保 unit「${id}」的清单 —— 这个包要么没装进这份 profile,要么它的 dsh.workbench 没通过校验。卡片先不挂:清单只有一处真相(ADR-0038 §2.2)`]
2813
+ }],
2814
+ expect: {
2815
+ rows: 0,
2816
+ installed: 1,
2817
+ installedActions: ["remove-bundle"],
2818
+ installedNote: true
2819
+ }
2820
+ },
2647
2821
  {
2648
2822
  id: "installed-confirm",
2649
2823
  label: "卸载本机模块(Modal 确认,标题带模块名)",
@@ -2692,6 +2866,95 @@ window.__ModuleLoader__.load({
2692
2866
  actions: ["uninstall"]
2693
2867
  }
2694
2868
  },
2869
+ {
2870
+ id: "plugin-outdated",
2871
+ label: "用户装的 opencli 插件:有新版(给更新 / 卸载)",
2872
+ manifests: [],
2873
+ capabilities: {},
2874
+ plugins: [{
2875
+ pkg: "opencli-plugin-cmdb",
2876
+ name: "cmdb",
2877
+ installed: "1.0.24",
2878
+ latest: "1.0.25"
2879
+ }],
2880
+ expect: {
2881
+ rows: 0,
2882
+ plugins: 1,
2883
+ pluginActions: ["update-plugin", "uninstall-plugin"]
2884
+ }
2885
+ },
2886
+ {
2887
+ id: "plugin-local",
2888
+ label: "本地目录装的 opencli 插件:没有版本源(只给卸载,行上说清为什么)",
2889
+ manifests: [],
2890
+ capabilities: {},
2891
+ plugins: [{
2892
+ pkg: "/Users/me/my-local-plugin",
2893
+ name: "my-local-plugin",
2894
+ local: true
2895
+ }],
2896
+ expect: {
2897
+ rows: 0,
2898
+ plugins: 1,
2899
+ pluginActions: ["uninstall-plugin"],
2900
+ pluginNote: true,
2901
+ pluginNoteKey: "panels.market.pluginLocalNoUpdate"
2902
+ }
2903
+ },
2904
+ {
2905
+ id: "plugin-alias",
2906
+ label: "插件名 ≠ 包名:行上两个都写出来(更新 / 卸载按包名)",
2907
+ manifests: [],
2908
+ capabilities: {},
2909
+ plugins: [{
2910
+ pkg: "opencli-plugin-cmdb",
2911
+ name: "cmdb",
2912
+ installed: "1.0.24",
2913
+ latest: "1.0.25"
2914
+ }],
2915
+ expect: {
2916
+ rows: 0,
2917
+ plugins: 1,
2918
+ pluginActions: ["update-plugin", "uninstall-plugin"],
2919
+ pluginNoteKey: "panels.market.pluginAlsoKnownAs"
2920
+ }
2921
+ },
2922
+ {
2923
+ id: "plugin-broken",
2924
+ label: "装坏了的那一份(目录在但看不出是个插件):行上直说,给卸载与指路",
2925
+ manifests: [],
2926
+ capabilities: {},
2927
+ plugins: [{
2928
+ pkg: "opencli-plugin-cmdb",
2929
+ name: "cmdb",
2930
+ installed: "1.0.24",
2931
+ broken: true
2932
+ }],
2933
+ expect: {
2934
+ rows: 0,
2935
+ plugins: 1,
2936
+ pluginActions: ["uninstall-plugin"],
2937
+ pluginNoteKey: "panels.market.pluginBroken"
2938
+ }
2939
+ },
2940
+ {
2941
+ id: "plugin-kept",
2942
+ label: "卸掉用户装的插件,但还有模块在用:文件先留着(行上给一句为什么)",
2943
+ manifests: [],
2944
+ capabilities: {},
2945
+ plugins: [{
2946
+ pkg: "opencli-plugin-cmdb",
2947
+ name: "cmdb",
2948
+ installed: "1.0.24"
2949
+ }],
2950
+ notice: "文件先留着:cmdb、argocd 还要用它。",
2951
+ expect: {
2952
+ rows: 0,
2953
+ plugins: 1,
2954
+ pluginActions: ["uninstall-plugin"],
2955
+ notice: true
2956
+ }
2957
+ },
2695
2958
  {
2696
2959
  id: "empty",
2697
2960
  label: "市场空态",
@@ -2749,7 +3012,6 @@ window.__ModuleLoader__.load({
2749
3012
  };
2750
3013
  },
2751
3014
  all: () => sorted,
2752
- visible: () => sorted.filter((module) => module.enabledByDefault),
2753
3015
  byId: (id) => index.get(id),
2754
3016
  stepOwner: (kind) => steps.get(kind),
2755
3017
  subscribe(listener) {
@@ -2761,20 +3023,21 @@ window.__ModuleLoader__.load({
2761
3023
  }
2762
3024
  //#endregion
2763
3025
  //#region src/app/units/registry.ts
2764
- function toBoardModule(face) {
3026
+ function toBoardModule(face, manifest) {
2765
3027
  return {
2766
- id: face.manifest.id,
2767
- titleKey: face.manifest.card?.titleKey ?? face.manifest.id,
2768
- order: face.manifest.card?.order ?? 100,
2769
- enabledByDefault: face.manifest.card?.enabledByDefault ?? false,
3028
+ id: manifest.id,
3029
+ titleKey: manifest.card?.titleKey ?? manifest.id,
3030
+ order: manifest.card?.order ?? 100,
2770
3031
  View: face.card,
2771
3032
  ...face.steps === void 0 ? {} : { steps: face.steps }
2772
3033
  };
2773
3034
  }
2774
- function createClientUnitRegistry() {
2775
- const faces = [];
3035
+ function createClientUnitRegistry(options = {}) {
3036
+ const registrations = [];
3037
+ const refusals = [];
2776
3038
  const listeners = /* @__PURE__ */ new Set();
2777
3039
  const board = createBoardRegistry();
3040
+ let known = /* @__PURE__ */ new Map();
2778
3041
  let revision = 0;
2779
3042
  let manifestsCache;
2780
3043
  function notify() {
@@ -2785,28 +3048,86 @@ window.__ModuleLoader__.load({
2785
3048
  console.warn(`[dsh-workbench] 套件注册的订阅者报错(不影响其它订阅者与这次注册):${String(error)}`);
2786
3049
  }
2787
3050
  }
3051
+ function warnRefusal(unit, reasons) {
3052
+ refusals.push({
3053
+ unit,
3054
+ reasons
3055
+ });
3056
+ console.warn(`[dsh-workbench] ${unit === "" ? "这个模块" : unit} 的卡片没挂上:${reasons.join(";")}`);
3057
+ }
3058
+ function takeBackRefusal(unit) {
3059
+ for (let at = refusals.length - 1; at >= 0; at -= 1) if (refusals[at]?.unit === unit) refusals.splice(at, 1);
3060
+ }
3061
+ function attach(entry) {
3062
+ const manifest = known.get(entry.unit);
3063
+ if (manifest === void 0) return false;
3064
+ entry.mounted = {
3065
+ manifest,
3066
+ unmount: board.register(toBoardModule(entry.face, manifest))
3067
+ };
3068
+ takeBackRefusal(entry.unit);
3069
+ return true;
3070
+ }
3071
+ function detach(entry) {
3072
+ entry.mounted?.unmount();
3073
+ entry.mounted = null;
3074
+ }
2788
3075
  return {
2789
3076
  register(face) {
2790
- const id = face.manifest.id;
2791
- if (faces.some((item) => item.manifest.id === id)) throw new Error(`套件 id 重复:${id}(id 会进持久化配置,不能撞)`);
2792
- const unregisterBoard = board.register(toBoardModule(face));
2793
- faces.push(face);
3077
+ const unit = typeof face?.unit === "string" ? face.unit.trim() : "";
3078
+ if (unit === "") {
3079
+ warnRefusal("", ["registerUnit({ unit, card }) 里的 unit 是空的 —— U1b 之前的旧形状是 registerUnit({ manifest, card });现在清单由外壳从**已装清单**读出来、按 unit 交给浏览器(ADR-0038 §2.2)"]);
3080
+ notify();
3081
+ return () => {};
3082
+ }
3083
+ if (registrations.some((entry) => entry.unit === unit)) throw new Error(`套件 id 重复:${unit}(id 会进持久化配置,不能撞)`);
3084
+ const entry = {
3085
+ face,
3086
+ unit,
3087
+ mounted: null
3088
+ };
3089
+ registrations.push(entry);
2794
3090
  manifestsCache = void 0;
3091
+ if (!attach(entry)) {
3092
+ warnRefusal(unit, [`宿主没有担保 unit「${unit}」的清单 —— 这个包要么没装进这份 profile,要么它的 dsh.workbench 没通过校验。卡片先不挂:清单只有一处真相(ADR-0038 §2.2)`]);
3093
+ options.onUnknownUnit?.(unit);
3094
+ }
2795
3095
  notify();
2796
3096
  return () => {
2797
- const at = faces.findIndex((item) => item.manifest.id === id);
3097
+ const at = registrations.indexOf(entry);
2798
3098
  if (at < 0) return;
2799
- faces.splice(at, 1);
3099
+ registrations.splice(at, 1);
3100
+ detach(entry);
3101
+ takeBackRefusal(unit);
2800
3102
  manifestsCache = void 0;
2801
- unregisterBoard();
2802
3103
  notify();
2803
3104
  };
2804
3105
  },
2805
- all: () => faces,
3106
+ all: () => registrations.map((entry) => entry.face),
2806
3107
  manifests: () => {
2807
- manifestsCache ??= faces.map((face) => face.manifest);
3108
+ manifestsCache ??= registrations.flatMap((entry) => entry.mounted === null ? [] : [entry.mounted.manifest]);
2808
3109
  return manifestsCache;
2809
3110
  },
3111
+ refusals: () => refusals,
3112
+ setManifests(manifests) {
3113
+ known = new Map(manifests.map((manifest) => [manifest.id, manifest]));
3114
+ let changed = false;
3115
+ for (const entry of registrations) {
3116
+ const next = known.get(entry.unit);
3117
+ if (entry.mounted === null) {
3118
+ if (next !== void 0 && attach(entry)) changed = true;
3119
+ continue;
3120
+ }
3121
+ if (next === void 0) {
3122
+ detach(entry);
3123
+ warnRefusal(entry.unit, [`宿主不再担保 unit「${entry.unit}」的清单(模块被卸了?)—— 这张卡片先摘下来`]);
3124
+ changed = true;
3125
+ }
3126
+ }
3127
+ if (!changed) return;
3128
+ manifestsCache = void 0;
3129
+ notify();
3130
+ },
2810
3131
  board,
2811
3132
  subscribe(listener) {
2812
3133
  listeners.add(listener);
@@ -2841,11 +3162,9 @@ window.__ModuleLoader__.load({
2841
3162
  };
2842
3163
  var manifest = {
2843
3164
  id: FIXTURE_UNIT_ID,
2844
- kind: "board",
2845
3165
  card: {
2846
3166
  titleKey: KEY.cardTitle,
2847
- order: 900,
2848
- enabledByDefault: true
3167
+ order: 900
2849
3168
  },
2850
3169
  tools: [],
2851
3170
  host: { inject: [] }
@@ -2868,6 +3187,7 @@ window.__ModuleLoader__.load({
2868
3187
  }))));
2869
3188
  }
2870
3189
  var FIXTURE_FACE = {
3190
+ unit: FIXTURE_UNIT_ID,
2871
3191
  manifest,
2872
3192
  messages,
2873
3193
  card: FixtureCard
@@ -2888,11 +3208,9 @@ window.__ModuleLoader__.load({
2888
3208
  };
2889
3209
  var crashManifest = {
2890
3210
  id: CRASH_UNIT_ID,
2891
- kind: "board",
2892
3211
  card: {
2893
3212
  titleKey: CRASH_KEY.cardTitle,
2894
- order: 899,
2895
- enabledByDefault: true
3213
+ order: 899
2896
3214
  },
2897
3215
  tools: [],
2898
3216
  host: { inject: [] }
@@ -2901,6 +3219,7 @@ window.__ModuleLoader__.load({
2901
3219
  throw new Error("夹具:这张卡片按 wbCrash=1 故意渲染失败(守「一张卡片崩溃不带走面板」)");
2902
3220
  }
2903
3221
  var CRASH_FACE = {
3222
+ unit: CRASH_UNIT_ID,
2904
3223
  manifest: crashManifest,
2905
3224
  messages: crashMessages,
2906
3225
  card: CrashingCard
@@ -2913,8 +3232,8 @@ window.__ModuleLoader__.load({
2913
3232
  return hasCard(roster) ? roster : SAMPLE_ROSTER;
2914
3233
  }
2915
3234
  function fixtureSeed(roster, all, crash = false) {
2916
- const base = hasCard(roster) ? all : [toBoardModule(FIXTURE_FACE)];
2917
- return crash ? [toBoardModule(CRASH_FACE), ...base] : base;
3235
+ const base = hasCard(roster) ? all : [toBoardModule(FIXTURE_FACE, FIXTURE_FACE.manifest)];
3236
+ return crash ? [toBoardModule(CRASH_FACE, CRASH_FACE.manifest), ...base] : base;
2918
3237
  }
2919
3238
  //#endregion
2920
3239
  //#region src/app/layouts/rightbar/market-rows.ts
@@ -2934,6 +3253,25 @@ window.__ModuleLoader__.load({
2934
3253
  unchecked: "idle",
2935
3254
  unknown: "idle"
2936
3255
  };
3256
+ function marketRowTitle(row, t) {
3257
+ return row.label ?? t(row.titleKey);
3258
+ }
3259
+ function withClientRefusals(modules, refusals) {
3260
+ if (refusals.length === 0) return modules;
3261
+ const byUnit = new Map(refusals.map((one) => [one.unit, one.reasons]));
3262
+ return modules.map((module) => {
3263
+ const reasons = byUnit.get(module.unit);
3264
+ return reasons === void 0 ? module : {
3265
+ ...module,
3266
+ clientRefused: reasons
3267
+ };
3268
+ });
3269
+ }
3270
+ function refusalReasons(host, client) {
3271
+ const reported = host ?? [];
3272
+ if (reported.length > 0) return reported;
3273
+ return [...new Set(client ?? [])];
3274
+ }
2937
3275
  function mergeTitles(known, manifests) {
2938
3276
  let next = null;
2939
3277
  for (const manifest of manifests) {
@@ -2952,11 +3290,16 @@ window.__ModuleLoader__.load({
2952
3290
  const latest = module.latest;
2953
3291
  const outdated = latest !== void 0 && latest !== module.installed;
2954
3292
  const loaded = titles.has(module.unit);
3293
+ const refused = refusalReasons(module.refused, module.clientRefused);
2955
3294
  rows.push({
2956
3295
  id: module.unit,
2957
3296
  titleKey: titles.get(module.unit) ?? known?.get(module.unit) ?? module.pkg,
2958
3297
  state: outdated ? "outdated" : "installed",
2959
- ...loaded ? {} : { hint: "panels.market.moduleRestartHint" },
3298
+ ...loaded || refused.length > 0 ? {} : { hint: "panels.market.moduleRestartHint" },
3299
+ ...refused.length === 0 ? {} : { note: {
3300
+ key: "panels.market.moduleRefused",
3301
+ params: { reason: refused.join(";") }
3302
+ } },
2960
3303
  ...module.local === true ? { local: true } : {},
2961
3304
  pkg: module.pkg,
2962
3305
  canInstall: false,
@@ -2975,6 +3318,7 @@ window.__ModuleLoader__.load({
2975
3318
  return rows;
2976
3319
  }
2977
3320
  function marketActions$1(row) {
3321
+ if (row.plugin === true) return [...row.canUpdate ? ["update-plugin"] : [], ...row.canUninstall ? ["uninstall-plugin"] : []];
2978
3322
  return [
2979
3323
  ...row.canInstall ? ["install"] : [],
2980
3324
  ...row.moduleUpdate === void 0 ? row.canUpdate ? ["update"] : [] : ["update-bundle"],
@@ -2998,7 +3342,7 @@ window.__ModuleLoader__.load({
2998
3342
  if (source.kind === "npm") return source.registryEnv;
2999
3343
  return "";
3000
3344
  }
3001
- function noteOf(state, install, manifest) {
3345
+ function noteOf$1(state, install, manifest) {
3002
3346
  if (state === "installed") return void 0;
3003
3347
  if (install === "env-missing") return {
3004
3348
  key: "panels.market.needEnv",
@@ -3057,7 +3401,7 @@ window.__ModuleLoader__.load({
3057
3401
  const capability = capabilities?.[manifest.id];
3058
3402
  const install = capability?.install;
3059
3403
  const state = capabilities === null ? "checking" : stateOf(capability);
3060
- const note = noteOf(state, install, manifest);
3404
+ const note = noteOf$1(state, install, manifest);
3061
3405
  const onMachine = isOnMachine(state);
3062
3406
  const reAdopt = capability?.released === true && install === void 0;
3063
3407
  const entry = updates[manifest.id];
@@ -3229,6 +3573,63 @@ window.__ModuleLoader__.load({
3229
3573
  };
3230
3574
  }
3231
3575
  //#endregion
3576
+ //#region src/app/layouts/rightbar/market-plugin-rows.ts
3577
+ function installedPluginKept(value) {
3578
+ if (typeof value !== "object" || value === null) return void 0;
3579
+ const kept = value.kept;
3580
+ if (typeof kept !== "object" || kept === null) return void 0;
3581
+ const kind = kept.kind;
3582
+ if (kind === "held") return { key: "panels.market.pluginKeptHeld" };
3583
+ if (kind === "unnamed") return { key: "panels.market.pluginKeptUnnamed" };
3584
+ if (kind === "unsure") return { key: "panels.market.pluginKeptUnsure" };
3585
+ if (kind !== "claimed") return void 0;
3586
+ const raw = kept.by;
3587
+ const names = Array.isArray(raw) ? raw.filter((item) => typeof item === "string") : [];
3588
+ return names.length === 0 ? { key: "panels.market.pluginKeptUnsure" } : {
3589
+ key: "panels.market.pluginKeptInUse",
3590
+ names
3591
+ };
3592
+ }
3593
+ function noteOf(plugin) {
3594
+ if (plugin.broken === true) return {
3595
+ key: "panels.market.pluginBroken",
3596
+ params: {}
3597
+ };
3598
+ if (plugin.local === true) return {
3599
+ key: "panels.market.pluginLocalNoUpdate",
3600
+ params: {}
3601
+ };
3602
+ if (plugin.name !== void 0 && plugin.name !== plugin.pkg) return {
3603
+ key: "panels.market.pluginAlsoKnownAs",
3604
+ params: { pkg: plugin.pkg }
3605
+ };
3606
+ }
3607
+ function installedPluginRows(plugins) {
3608
+ return plugins.map((plugin) => {
3609
+ const name = plugin.name ?? plugin.pkg;
3610
+ const outdated = plugin.installed !== void 0 && plugin.latest !== void 0 && plugin.latest !== plugin.installed;
3611
+ const note = noteOf(plugin);
3612
+ return {
3613
+ id: `plugin:${plugin.pkg}`,
3614
+ titleKey: plugin.pkg,
3615
+ label: name,
3616
+ plugin: true,
3617
+ state: outdated ? "outdated" : "installed",
3618
+ canInstall: false,
3619
+ canUpdate: outdated,
3620
+ canUninstall: true,
3621
+ ...plugin.local === true ? { local: true } : {},
3622
+ ...plugin.broken === true ? { broken: true } : {},
3623
+ ...note === void 0 ? {} : { note },
3624
+ pkg: plugin.pkg,
3625
+ ...plugin.installed === void 0 ? {} : { version: {
3626
+ installed: plugin.installed,
3627
+ ...plugin.latest === void 0 ? {} : { latest: plugin.latest }
3628
+ } }
3629
+ };
3630
+ });
3631
+ }
3632
+ //#endregion
3232
3633
  //#region src/app/layouts/market/add-module-text.ts
3233
3634
  var GUIDE_ITEMS = [
3234
3635
  {
@@ -3347,17 +3748,23 @@ window.__ModuleLoader__.load({
3347
3748
  "not-found": "panels.market.add.problemNotFound",
3348
3749
  "not-a-package": "panels.market.add.problemNotPackage",
3349
3750
  "not-a-bundle": "panels.market.add.problemNotBundle",
3751
+ "not-a-workbench-module": "panels.market.add.problemNotWorkbenchModule",
3752
+ "not-a-module-or-plugin": "panels.market.add.problemNotModuleOrPlugin",
3350
3753
  network: "panels.market.add.problemNetwork",
3351
3754
  unknown: "panels.market.add.problemUnknown"
3352
3755
  };
3353
3756
  function problemKey(problem) {
3354
3757
  return PROBLEM_KEYS[problem] ?? PROBLEM_KEYS.unknown;
3355
3758
  }
3759
+ function heldWizardPhase(phase, classifying) {
3760
+ return classifying && (phase === "preview" || phase === "idle") ? "inspecting" : phase;
3761
+ }
3356
3762
  var FAILURE_KEYS = {
3357
3763
  network: "panels.market.add.failureNetwork",
3358
3764
  "spec-host": "panels.market.add.failureNetworkHost",
3359
3765
  "not-found": "panels.market.add.failureNotFound",
3360
3766
  "no-matching-version": "panels.market.add.failureNoMatchingVersion",
3767
+ "not-a-module-or-plugin": "panels.market.add.failureNotModuleOrPlugin",
3361
3768
  "disk-full": "panels.market.add.failureDiskFull",
3362
3769
  permission: "panels.market.add.failurePermission",
3363
3770
  "build-blocked": "panels.market.add.failureBuildBlocked",
@@ -3454,6 +3861,16 @@ window.__ModuleLoader__.load({
3454
3861
  function MarketEmpty({ t }) {
3455
3862
  return /* @__PURE__ */ h("div", { className: MarketPage_module_default.marketEmpty }, /* @__PURE__ */ h("div", { className: MarketPage_module_default.marketEmptyTitle }, t("panels.market.empty")));
3456
3863
  }
3864
+ var PanelFoot_module_default = {
3865
+ foot: "_foot_1us83_1",
3866
+ footText: "_footText_1us83_12",
3867
+ footTextMd: "_footTextMd_1us83_17"
3868
+ };
3869
+ //#endregion
3870
+ //#region src/shared/components/PanelFoot.tsx
3871
+ function PanelFoot({ text, size = "sm", children }) {
3872
+ 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);
3873
+ }
3457
3874
  //#endregion
3458
3875
  //#region src/app/layouts/rightbar/market-view-text.ts
3459
3876
  var PROGRESS_KEY = {
@@ -3462,7 +3879,9 @@ window.__ModuleLoader__.load({
3462
3879
  "update-bundle": "panels.market.updating",
3463
3880
  "remove-bundle": "panels.market.uninstalling",
3464
3881
  uninstall: "panels.market.uninstalling",
3465
- "update-dependency": "panels.market.updating"
3882
+ "update-dependency": "panels.market.updating",
3883
+ "update-plugin": "panels.market.updating",
3884
+ "uninstall-plugin": "panels.market.uninstalling"
3466
3885
  };
3467
3886
  var ACTION_LABEL_KEY = {
3468
3887
  install: "panels.market.install",
@@ -3470,7 +3889,9 @@ window.__ModuleLoader__.load({
3470
3889
  "update-bundle": "panels.market.update",
3471
3890
  "remove-bundle": "panels.market.uninstall",
3472
3891
  uninstall: "panels.market.uninstall",
3473
- "update-dependency": "panels.market.update"
3892
+ "update-dependency": "panels.market.update",
3893
+ "update-plugin": "panels.market.update",
3894
+ "uninstall-plugin": "panels.market.uninstall"
3474
3895
  };
3475
3896
  //#endregion
3476
3897
  //#region src/app/layouts/rightbar/SharedSection.tsx
@@ -3518,21 +3939,18 @@ window.__ModuleLoader__.load({
3518
3939
  pending,
3519
3940
  failure: failureOf(row.id),
3520
3941
  onAct: (action) => void act(row.id, action)
3521
- }))));
3522
- }
3523
- var PanelFoot_module_default = {
3524
- foot: "_foot_1us83_1",
3525
- footText: "_footText_1us83_12",
3526
- footTextMd: "_footTextMd_1us83_17"
3527
- };
3528
- //#endregion
3529
- //#region src/shared/components/PanelFoot.tsx
3530
- function PanelFoot({ text, size = "sm", children }) {
3531
- 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);
3942
+ }))), /* @__PURE__ */ h(PanelFoot, {
3943
+ size: "md",
3944
+ text: t("panels.market.sharedFoot")
3945
+ }));
3532
3946
  }
3533
3947
  //#endregion
3534
3948
  //#region src/app/layouts/rightbar/MarketView.tsx
3535
- var CONFIRM_UNINSTALL = ["uninstall", "remove-bundle"];
3949
+ var CONFIRM_UNINSTALL = [
3950
+ "uninstall",
3951
+ "remove-bundle",
3952
+ "uninstall-plugin"
3953
+ ];
3536
3954
  var CONFIRM_REMOVE = ["remove-bundle"];
3537
3955
  function MarketLine({ t, row, pending, failure, onAct }) {
3538
3956
  const running = pending !== null && pending.id === row.id ? pending : null;
@@ -3542,7 +3960,7 @@ window.__ModuleLoader__.load({
3542
3960
  return /* @__PURE__ */ h("li", { className: MarketPage_module_default.marketRow }, /* @__PURE__ */ h("span", {
3543
3961
  className: MarketPage_module_default.marketIcon,
3544
3962
  "aria-hidden": "true"
3545
- }, /* @__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", {
3963
+ }, /* @__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", {
3546
3964
  from: row.version.installed,
3547
3965
  to: row.version.latest
3548
3966
  }) : row.version.installed ?? row.version.latest ?? "")), /* @__PURE__ */ h("span", {
@@ -3567,11 +3985,14 @@ window.__ModuleLoader__.load({
3567
3985
  variant: action === "install" ? "primary" : "outline",
3568
3986
  className: danger ? "wb-dangerAction" : void 0,
3569
3987
  icon: danger ? /* @__PURE__ */ h(_deepseek_ai_dsh_client_ui_primitives.IconTrashOutlineRegular, { size: 13 }) : void 0,
3570
- "aria-label": danger ? t("panels.market.uninstallLabel", { name: t(row.titleKey) }) : void 0,
3988
+ "aria-label": danger ? t("panels.market.uninstallLabel", { name: marketRowTitle(row, t) }) : void 0,
3571
3989
  disabled: locked,
3572
3990
  onClick: () => onAct(action)
3573
3991
  }, t(ACTION_LABEL_KEY[action]));
3574
- }))), 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));
3992
+ }))), row.note === void 0 ? null : /* @__PURE__ */ h("div", {
3993
+ className: MarketPage_module_default.marketNote,
3994
+ title: row.note.params.reason === void 0 ? void 0 : t("panels.market.moduleRefusedDetail", row.note.params)
3995
+ }, t(row.note.key, row.note.params)), failure === null ? null : /* @__PURE__ */ h("div", { className: MarketPage_module_default.marketFailure }, failure));
3575
3996
  }
3576
3997
  function ConfirmUninstall({ t, name, onConfirm, onCancel }) {
3577
3998
  const [acknowledged, setAcknowledged] = useState(false);
@@ -3600,7 +4021,48 @@ window.__ModuleLoader__.load({
3600
4021
  onAct: (action) => confirmActions.includes(action) ? onConfirming(row.id) : void act(row.id, action)
3601
4022
  }))));
3602
4023
  }
3603
- function MarketView({ t, manifests, capabilities, freshness, onChanged, updates, installed, installedRead, settling, mock }) {
4024
+ function MarketBody({ t, shown, pluginList, installedList, shared, pending, failed, notice, act, onConfirming }) {
4025
+ const failureOf = (id) => failed?.id === id ? failed.message : null;
4026
+ return /* @__PURE__ */ h(Fragment, null, notice === null ? null : /* @__PURE__ */ h("div", { className: MarketPage_module_default.marketNote }, notice), marketSections(shown).map((section) => /* @__PURE__ */ h(MarketSection, {
4027
+ key: section.id,
4028
+ t,
4029
+ titleKey: section.titleKey,
4030
+ rows: section.rows,
4031
+ pending,
4032
+ failureOf,
4033
+ act,
4034
+ confirmActions: CONFIRM_UNINSTALL,
4035
+ onConfirming
4036
+ })), /* @__PURE__ */ h(MarketSection, {
4037
+ t,
4038
+ titleKey: "panels.market.sectionPlugins",
4039
+ rows: pluginList,
4040
+ pending,
4041
+ failureOf,
4042
+ act,
4043
+ confirmActions: CONFIRM_UNINSTALL,
4044
+ onConfirming
4045
+ }), /* @__PURE__ */ h(MarketSection, {
4046
+ t,
4047
+ titleKey: installedList.length > 0 && installedList.every((row) => row.local === true) ? "panels.market.sectionLocal" : "panels.market.sectionUnlisted",
4048
+ rows: installedList,
4049
+ pending,
4050
+ failureOf,
4051
+ act,
4052
+ confirmActions: CONFIRM_REMOVE,
4053
+ onConfirming
4054
+ }), /* @__PURE__ */ h(PanelFoot, {
4055
+ size: "md",
4056
+ text: t("panels.market.foot")
4057
+ }), /* @__PURE__ */ h(SharedSection, {
4058
+ t,
4059
+ rows: shared,
4060
+ pending,
4061
+ failureOf,
4062
+ act
4063
+ }));
4064
+ }
4065
+ function MarketView({ t, manifests, capabilities, freshness, onChanged, updates, installed, installedRead, plugins, settling, mock }) {
3604
4066
  const [titles, setTitles] = useState(/* @__PURE__ */ new Map());
3605
4067
  useEffect(() => {
3606
4068
  if (mock === void 0) setTitles((known) => mergeTitles(known, manifests));
@@ -3617,6 +4079,7 @@ window.__ModuleLoader__.load({
3617
4079
  });
3618
4080
  const [confirming, setConfirming] = useState(mock?.confirming ?? null);
3619
4081
  const [failed, setFailed] = useState(mock?.failure ?? null);
4082
+ const [notice, setNotice] = useState(mock?.notice ?? null);
3620
4083
  const removing = pending !== null && pending.action === "remove-bundle" && failed?.id !== pending.id ? pending.id : null;
3621
4084
  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);
3622
4085
  const pendingRow = removing === null || pending === null || rows.some((row) => row.id === removing) ? void 0 : {
@@ -3630,7 +4093,12 @@ window.__ModuleLoader__.load({
3630
4093
  ...pending.version === void 0 ? {} : { version: { installed: pending.version } }
3631
4094
  };
3632
4095
  const shown = pendingRow === void 0 ? rows : [...rows, pendingRow];
3633
- const rowById = new Map([...shown, ...installedList].map((row) => [row.id, row]));
4096
+ const pluginList = installedPluginRows(mock?.plugins ?? plugins ?? []);
4097
+ const rowById = new Map([
4098
+ ...shown,
4099
+ ...installedList,
4100
+ ...pluginList
4101
+ ].map((row) => [row.id, row]));
3634
4102
  const confirmingRow = confirming === null ? void 0 : rowById.get(confirming);
3635
4103
  const act = async (id, action) => {
3636
4104
  if (mock !== void 0) return;
@@ -3644,13 +4112,15 @@ window.__ModuleLoader__.load({
3644
4112
  });
3645
4113
  setConfirming(null);
3646
4114
  setFailed(null);
4115
+ if (action !== "uninstall-plugin") setNotice(null);
3647
4116
  const dependency = action === "update-dependency";
4117
+ const byName = action === "remove-bundle" || action === "update-plugin" || action === "uninstall-plugin";
3648
4118
  const outcome = await provision.send(dependency ? {
3649
4119
  action,
3650
4120
  id
3651
- } : action === "remove-bundle" ? {
4121
+ } : byName ? {
3652
4122
  action,
3653
- name: rowById.get(id)?.pkg ?? ""
4123
+ name: row?.pkg ?? ""
3654
4124
  } : {
3655
4125
  action,
3656
4126
  unit: id
@@ -3664,6 +4134,10 @@ window.__ModuleLoader__.load({
3664
4134
  });
3665
4135
  return;
3666
4136
  }
4137
+ if (action === "uninstall-plugin") {
4138
+ const kept = installedPluginKept(outcome.value);
4139
+ setNotice(kept === void 0 ? null : t(kept.key, kept.names === void 0 ? {} : { names: kept.names.join(t("panels.market.listSeparator")) }));
4140
+ }
3667
4141
  const reason = changeFailure(changeOf(outcome.value), t);
3668
4142
  onChanged();
3669
4143
  if (reason !== void 0) setFailed({
@@ -3671,46 +4145,32 @@ window.__ModuleLoader__.load({
3671
4145
  message: t("panels.market.failed", { reason })
3672
4146
  });
3673
4147
  };
3674
- if (!(freshness.loaded && installedRead !== false) || (settling?.size ?? 0) > 0 && shown.length === 0 && installedList.length === 0) return /* @__PURE__ */ h(MarketChecking, { t });
3675
- if (shown.length === 0 && installedList.length === 0) return /* @__PURE__ */ h(MarketEmpty, { t });
3676
- return /* @__PURE__ */ h(Fragment, null, marketSections(shown).map((section) => /* @__PURE__ */ h(MarketSection, {
3677
- key: section.id,
3678
- t,
3679
- titleKey: section.titleKey,
3680
- rows: section.rows,
3681
- pending,
3682
- failureOf: (id) => failed?.id === id ? failed.message : null,
3683
- act,
3684
- confirmActions: CONFIRM_UNINSTALL,
3685
- onConfirming: setConfirming
3686
- })), /* @__PURE__ */ h(MarketSection, {
4148
+ const settled = freshness.loaded && installedRead !== false;
4149
+ const nothing = shown.length === 0 && installedList.length === 0 && pluginList.length === 0;
4150
+ if (!settled || (settling?.size ?? 0) > 0 && shown.length === 0 && installedList.length === 0) return /* @__PURE__ */ h(MarketChecking, { t });
4151
+ if (nothing) return /* @__PURE__ */ h(MarketEmpty, { t });
4152
+ return /* @__PURE__ */ h(Fragment, null, /* @__PURE__ */ h(MarketBody, {
3687
4153
  t,
3688
- titleKey: installedList.length > 0 && installedList.every((row) => row.local === true) ? "panels.market.sectionLocal" : "panels.market.sectionUnlisted",
3689
- rows: installedList,
4154
+ shown,
4155
+ pluginList,
4156
+ installedList,
4157
+ shared,
3690
4158
  pending,
3691
- failureOf: (id) => failed?.id === id ? failed.message : null,
4159
+ failed,
4160
+ notice,
3692
4161
  act,
3693
- confirmActions: CONFIRM_REMOVE,
3694
4162
  onConfirming: setConfirming
3695
- }), /* @__PURE__ */ h(PanelFoot, {
3696
- size: "md",
3697
- text: t("panels.market.foot")
3698
- }), /* @__PURE__ */ h(SharedSection, {
3699
- t,
3700
- rows: shared,
3701
- pending,
3702
- failureOf: (id) => failed?.id === id ? failed.message : null,
3703
- act
3704
4163
  }), /* @__PURE__ */ h(ConfirmUninstall, {
3705
4164
  key: confirming ?? "",
3706
4165
  t,
3707
- name: confirmingRow === void 0 ? null : t(confirmingRow.titleKey),
4166
+ name: confirmingRow === void 0 ? null : marketRowTitle(confirmingRow, t),
3708
4167
  onCancel: () => setConfirming(null),
3709
4168
  onConfirm: () => {
3710
4169
  const id = confirming;
3711
4170
  setConfirming(null);
3712
4171
  if (id === null) return;
3713
- act(id, rowById.get(id)?.pkg === void 0 ? "uninstall" : "remove-bundle");
4172
+ const row = rowById.get(id);
4173
+ act(id, row?.plugin === true ? "uninstall-plugin" : row?.pkg === void 0 ? "uninstall" : "remove-bundle");
3714
4174
  }
3715
4175
  }));
3716
4176
  }
@@ -3720,6 +4180,9 @@ window.__ModuleLoader__.load({
3720
4180
  var BUNDLE_INSPECT_ROUTE = "bundle-inspect";
3721
4181
  var MODULE_VERSIONS_ROUTE = "module-versions";
3722
4182
  //#endregion
4183
+ //#region src/shared/api/installed-plugins.ts
4184
+ var INSTALLED_PLUGINS_ROUTE = "panels/plugins";
4185
+ //#endregion
3723
4186
  //#region src/shared/hooks/bundle-queries.ts
3724
4187
  function readBundleRegistries() {
3725
4188
  return apiGet(BUNDLE_REGISTRIES_ROUTE);
@@ -3733,10 +4196,14 @@ window.__ModuleLoader__.load({
3733
4196
  function readModuleVersions(force = false) {
3734
4197
  return apiGet(MODULE_VERSIONS_ROUTE, force ? { force: "1" } : void 0);
3735
4198
  }
4199
+ function readInstalledPlugins(force = false) {
4200
+ return apiGet(INSTALLED_PLUGINS_ROUTE, force ? { force: "1" } : void 0);
4201
+ }
3736
4202
  //#endregion
3737
4203
  //#region src/app/layouts/market/use-module-versions.ts
3738
4204
  var state = {
3739
4205
  modules: null,
4206
+ plugins: null,
3740
4207
  read: false,
3741
4208
  checkedAt: null
3742
4209
  };
@@ -3761,10 +4228,13 @@ window.__ModuleLoader__.load({
3761
4228
  if (inFlight !== null && inFlight.force === force) return inFlight.promise;
3762
4229
  const seq = readSeq += 1;
3763
4230
  if (force) newestForceSeq = seq;
3764
- const promise = readModuleVersions(force).catch(() => null).then((response) => {
4231
+ const promise = Promise.all([readModuleVersions(force), readInstalledPlugins(force)]).catch(() => null).then((responses) => {
3765
4232
  if (!force && seq < newestForceSeq) return;
4233
+ const versions = responses?.[0];
4234
+ const plugins = responses?.[1];
3766
4235
  publish({
3767
- modules: response?.ok === true ? response.modules : state.modules,
4236
+ modules: versions?.ok === true ? versions.modules : state.modules,
4237
+ plugins: plugins?.ok === true ? plugins.plugins : state.plugins,
3768
4238
  read: true,
3769
4239
  checkedAt: Date.now()
3770
4240
  });
@@ -3796,6 +4266,7 @@ window.__ModuleLoader__.load({
3796
4266
  }, []);
3797
4267
  return {
3798
4268
  modules: value.modules,
4269
+ plugins: value.plugins,
3799
4270
  read: value.read,
3800
4271
  checkedAt: value.checkedAt,
3801
4272
  reload
@@ -4014,7 +4485,7 @@ window.__ModuleLoader__.load({
4014
4485
  })), /* @__PURE__ */ h("h2", {
4015
4486
  className: AddModule_module_default.pendingTitle,
4016
4487
  role: "status"
4017
- }, kind === "inspecting" ? t("panels.market.add.checking") : t("panels.market.add.installingTitle"))));
4488
+ }, kind === "inspecting" ? t("panels.market.add.classifying") : t("panels.market.add.installingTitle"))));
4018
4489
  }
4019
4490
  function AddModulePreview({ t, state }) {
4020
4491
  const preview = state.preview;
@@ -4032,6 +4503,7 @@ window.__ModuleLoader__.load({
4032
4503
  const restart = outcome.change.application === "restart-required";
4033
4504
  const cancelled = outcome.change.application === "cancelled";
4034
4505
  const notModule = outcome.supply.state === "not-a-module";
4506
+ const plugin = outcome.plugin;
4035
4507
  const name = outcome.module.kind === "module" ? outcome.module.unit : outcome.module.pkg;
4036
4508
  return /* @__PURE__ */ h("div", { className: AddModule_module_default.body }, /* @__PURE__ */ h("div", { className: AddModule_module_default.hero }, /* @__PURE__ */ h("span", {
4037
4509
  className: AddModule_module_default.heroIcon,
@@ -4043,7 +4515,7 @@ window.__ModuleLoader__.load({
4043
4515
  }) : /* @__PURE__ */ h(_deepseek_ai_dsh_client_ui_primitives.IconCheckCircleFillRegular, { size: 28 })), /* @__PURE__ */ h("h2", {
4044
4516
  className: AddModule_module_default.wizardTitle,
4045
4517
  role: failed ? "alert" : "status"
4046
- }, 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", {
4518
+ }, 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", {
4047
4519
  className: AddModule_module_default.resultWarn,
4048
4520
  role: "alert"
4049
4521
  }, 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)));
@@ -4114,6 +4586,7 @@ window.__ModuleLoader__.load({
4114
4586
  refused("not-found"),
4115
4587
  refused("not-a-package"),
4116
4588
  refused("not-a-bundle"),
4589
+ refused("not-a-module-or-plugin", "这个包既不是工作台的模块,也不是 opencli 的插件,装了也用不上"),
4117
4590
  refused("network", "getaddrinfo ENOTFOUND registry.example.com"),
4118
4591
  refused("unknown", "pnpm 的返回码是 1"),
4119
4592
  {
@@ -4195,6 +4668,25 @@ window.__ModuleLoader__.load({
4195
4668
  spec: "@dsh-workbench/module-hello",
4196
4669
  outcome: outcome({})
4197
4670
  },
4671
+ {
4672
+ id: "done-plugin",
4673
+ label: "装好了(opencli 插件)",
4674
+ phase: "result",
4675
+ spec: "opencli-plugin-cmdb",
4676
+ outcome: {
4677
+ change: change({ target: "opencli-plugin-cmdb" }),
4678
+ module: {
4679
+ kind: "unknown",
4680
+ pkg: "opencli-plugin-cmdb"
4681
+ },
4682
+ supply: { state: "no-needs" },
4683
+ plugin: {
4684
+ kind: "opencli-plugin",
4685
+ pkg: "opencli-plugin-cmdb",
4686
+ name: "cmdb"
4687
+ }
4688
+ }
4689
+ },
4198
4690
  {
4199
4691
  id: "done-restart",
4200
4692
  label: "装好了(要重启)",
@@ -4289,6 +4781,42 @@ window.__ModuleLoader__.load({
4289
4781
  };
4290
4782
  }
4291
4783
  //#endregion
4784
+ //#region src/shared/hooks/use-visible-busy.ts
4785
+ var use_visible_busy_exports = /* @__PURE__ */ __exportAll({
4786
+ busyView: () => busyView,
4787
+ heldPhase: () => heldPhase,
4788
+ useVisibleBusy: () => useVisibleBusy
4789
+ });
4790
+ function heldPhase(phase, refreshing) {
4791
+ return refreshing && phase === "ready" ? "loading" : phase;
4792
+ }
4793
+ function busyView(active, visible) {
4794
+ return {
4795
+ busy: visible,
4796
+ settling: visible && !active
4797
+ };
4798
+ }
4799
+ function useVisibleBusy(active, floorMs) {
4800
+ const [visible, setVisible] = useState(active);
4801
+ const since = useRef(null);
4802
+ useEffect(() => {
4803
+ if (active) {
4804
+ if (since.current === null) since.current = Date.now();
4805
+ setVisible(true);
4806
+ return;
4807
+ }
4808
+ const held = holdBusy(since.current, Date.now(), floorMs);
4809
+ since.current = null;
4810
+ if (!held.visible) {
4811
+ setVisible(false);
4812
+ return;
4813
+ }
4814
+ const timer = setTimeout(() => setVisible(false), held.releaseInMs);
4815
+ return () => clearTimeout(timer);
4816
+ }, [active, floorMs]);
4817
+ return busyView(active, visible);
4818
+ }
4819
+ //#endregion
4292
4820
  //#region src/app/layouts/market/use-add-module.ts
4293
4821
  function newRequestId() {
4294
4822
  return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
@@ -4311,6 +4839,7 @@ window.__ModuleLoader__.load({
4311
4839
  const [failure, setFailure] = useState(null);
4312
4840
  const generationRef = useRef(0);
4313
4841
  const requestIdRef = useRef("");
4842
+ const { busy: classifying } = useVisibleBusy(phase === "inspecting", 500);
4314
4843
  const write = useHostWrite({
4315
4844
  channel: "provision",
4316
4845
  networkText: failedText
@@ -4408,7 +4937,8 @@ window.__ModuleLoader__.load({
4408
4937
  setOutcome({
4409
4938
  change: value.change,
4410
4939
  module: value.module,
4411
- supply: value.supply
4940
+ supply: value.supply,
4941
+ ...value.plugin === void 0 ? {} : { plugin: value.plugin }
4412
4942
  });
4413
4943
  setPhase("result");
4414
4944
  if (value.change.application === "applied" || value.change.application === "restart-required") onInstalled();
@@ -4453,7 +4983,7 @@ window.__ModuleLoader__.load({
4453
4983
  custom,
4454
4984
  registryOpen,
4455
4985
  guideOpen,
4456
- phase,
4986
+ phase: heldWizardPhase(phase, classifying),
4457
4987
  choices,
4458
4988
  problem,
4459
4989
  preview,
@@ -4611,10 +5141,10 @@ window.__ModuleLoader__.load({
4611
5141
  function MarketPanel({ t, units }) {
4612
5142
  const manifests = useLiveManifests(units);
4613
5143
  const { capabilities, checkedAt, checking, forceProbe, reload: reloadCapability } = useCapabilityMap(0);
4614
- const { modules, read: installedRead, reload: reloadVersions } = useModuleVersions();
5144
+ const { modules, plugins, read: installedRead, reload: reloadVersions } = useModuleVersions();
4615
5145
  const [adding, setAdding] = useState(false);
4616
5146
  const updates = useMemo(() => marketUpdatesOf(modules), [modules]);
4617
- const installed = modules ?? void 0;
5147
+ const installed = modules === null ? void 0 : withClientRefusals(modules, units.refusals());
4618
5148
  const reload = useCallback(() => {
4619
5149
  reloadCapability();
4620
5150
  reloadVersions();
@@ -4703,6 +5233,7 @@ window.__ModuleLoader__.load({
4703
5233
  updates,
4704
5234
  installed,
4705
5235
  installedRead: mock === void 0 ? installedRead : mock.installedRead ?? true,
5236
+ plugins,
4706
5237
  settling: mock === void 0 ? settling : void 0,
4707
5238
  mock
4708
5239
  }), /* @__PURE__ */ h(AddModuleDialog, {
@@ -4758,6 +5289,41 @@ window.__ModuleLoader__.load({
4758
5289
  function assembleClientUnits(registry) {
4759
5290
  for (const face of CLIENT_UNITS) registry.register(face);
4760
5291
  }
5292
+ //#endregion
5293
+ //#region src/shared/api/unit-manifests.ts
5294
+ var UNIT_MANIFESTS_ROUTE = "unit-manifests";
5295
+ //#endregion
5296
+ //#region src/app/units/manifests.ts
5297
+ function createUnitManifestLoader(options = {}) {
5298
+ let inFlight = false;
5299
+ let queued = false;
5300
+ let watching = false;
5301
+ const subscribeFacts = options.subscribeFacts ?? subscribeFactRevision;
5302
+ const load = async (registry) => {
5303
+ if (inFlight) {
5304
+ queued = true;
5305
+ return;
5306
+ }
5307
+ inFlight = true;
5308
+ try {
5309
+ const response = await apiGet(UNIT_MANIFESTS_ROUTE).catch(() => null);
5310
+ if (response?.ok === true && Array.isArray(response.manifests)) registry.setManifests(response.manifests);
5311
+ } finally {
5312
+ inFlight = false;
5313
+ if (queued) {
5314
+ queued = false;
5315
+ load(registry);
5316
+ }
5317
+ }
5318
+ };
5319
+ return (registry) => {
5320
+ if (!watching) {
5321
+ watching = true;
5322
+ subscribeFacts(factOfRoute(UNIT_MANIFESTS_ROUTE), () => void load(registry));
5323
+ }
5324
+ load(registry);
5325
+ };
5326
+ }
4761
5327
  var BootGate_module_default = {
4762
5328
  actions: "_actions_jlw8j_1",
4763
5329
  progress: "_progress_jlw8j_2",
@@ -7435,42 +8001,6 @@ window.__ModuleLoader__.load({
7435
8001
  return { runs };
7436
8002
  }
7437
8003
  //#endregion
7438
- //#region src/shared/hooks/use-visible-busy.ts
7439
- var use_visible_busy_exports = /* @__PURE__ */ __exportAll({
7440
- busyView: () => busyView,
7441
- heldPhase: () => heldPhase,
7442
- useVisibleBusy: () => useVisibleBusy
7443
- });
7444
- function heldPhase(phase, refreshing) {
7445
- return refreshing && phase === "ready" ? "loading" : phase;
7446
- }
7447
- function busyView(active, visible) {
7448
- return {
7449
- busy: visible,
7450
- settling: visible && !active
7451
- };
7452
- }
7453
- function useVisibleBusy(active, floorMs) {
7454
- const [visible, setVisible] = useState(active);
7455
- const since = useRef(null);
7456
- useEffect(() => {
7457
- if (active) {
7458
- if (since.current === null) since.current = Date.now();
7459
- setVisible(true);
7460
- return;
7461
- }
7462
- const held = holdBusy(since.current, Date.now(), floorMs);
7463
- since.current = null;
7464
- if (!held.visible) {
7465
- setVisible(false);
7466
- return;
7467
- }
7468
- const timer = setTimeout(() => setVisible(false), held.releaseInMs);
7469
- return () => clearTimeout(timer);
7470
- }, [active, floorMs]);
7471
- return busyView(active, visible);
7472
- }
7473
- //#endregion
7474
8004
  //#region src/shared/hooks/use-unit-board.ts
7475
8005
  var use_unit_board_exports = /* @__PURE__ */ __exportAll({ useUnitBoard: () => useUnitBoard });
7476
8006
  function useUnitBoard(options) {
@@ -7684,7 +8214,7 @@ window.__ModuleLoader__.load({
7684
8214
  };
7685
8215
  function messagesOf(units) {
7686
8216
  return units.map((face) => ({
7687
- unit: face.manifest.id,
8217
+ unit: face.unit,
7688
8218
  ...face.messages === void 0 ? {} : { messages: face.messages }
7689
8219
  }));
7690
8220
  }
@@ -7725,12 +8255,14 @@ window.__ModuleLoader__.load({
7725
8255
  }
7726
8256
  }
7727
8257
  function mount(ctx) {
7728
- const units = createClientUnitRegistry();
8258
+ const loadUnitManifests = createUnitManifestLoader();
8259
+ const units = createClientUnitRegistry({ onUnknownUnit: () => loadUnitManifests(units) });
7729
8260
  ctx.provide(UNITS_SERVICE, {
7730
8261
  registerUnit: (face) => units.register(face),
7731
8262
  manifests: () => units.manifests()
7732
8263
  });
7733
8264
  assembleClientUnits(units);
8265
+ loadUnitManifests(units);
7734
8266
  const store = rightbarStore;
7735
8267
  const observable = {
7736
8268
  getSnapshot: () => store.getSnapshot(),