@dsh-workbench/core 1.1.6 → 1.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/client.js CHANGED
@@ -2809,6 +2809,15 @@ window.__ModuleLoader__.load({
2809
2809
  }
2810
2810
  return errors;
2811
2811
  }
2812
+ function libRunsProblemsOf(raw, at) {
2813
+ if (raw === void 0) return [];
2814
+ if (!Array.isArray(raw)) return [`${at}.runs 要是数组`];
2815
+ if (raw.length === 0) return [`${at}.runs 是空数组 —— 不自己跑命令就整条删掉`];
2816
+ const names = raw.map((one) => text(one));
2817
+ if (names.some((one) => one === "")) return [`${at}.runs 里有空字符串`];
2818
+ if (new Set(names).size !== names.length) return [`${at}.runs 里有重复的运行时`];
2819
+ return [];
2820
+ }
2812
2821
  function perKindProblemsOf(kind, raw, at) {
2813
2822
  const errors = [];
2814
2823
  if (kind === "bin" || kind === "lib" || kind === "env") {
@@ -2816,6 +2825,7 @@ window.__ModuleLoader__.load({
2816
2825
  }
2817
2826
  if (kind === "bin") errors.push(...binInstallProblemsOf(raw["install"], at));
2818
2827
  if (raw["docs"] !== void 0 && text(raw["docs"]) === "") errors.push(`${at}.docs 是空串`);
2828
+ if (kind === "lib") errors.push(...libRunsProblemsOf(raw["runs"], at));
2819
2829
  if (kind === "extension") {
2820
2830
  if (text(raw["runtime"]) === "") errors.push(`${at}.runtime 没写 —— 扩展属于哪个运行时(如 opencli)`);
2821
2831
  if (text(raw["name"]) === "") errors.push(`${at}.name 没写`);
@@ -3372,7 +3382,7 @@ window.__ModuleLoader__.load({
3372
3382
  "panels.discover.missingIndex": "This repository has no {path} yet.",
3373
3383
  "panels.discover.initTitle": "Initialize this repository as a module market index?",
3374
3384
  "panels.discover.initCta": "Initialize market index",
3375
- "panels.discover.initWhat": "It will write the index directory market/ and README.md on {branch}, commit once, and push. Modules you publish from this workbench will commit their build files under artifacts/<package-name>/<version>/ and their entry under market/<package-name>/<version>.json. The repository stays owned by its owner.",
3385
+ "panels.discover.initWhat": "It will write the index directory market/ and README.md on {branch}, commit once, and push. Modules you publish from this workbench will commit their build files under artifacts/<package-name>/ and their entry in market/<package-name>.json. The repository stays owned by its owner.",
3376
3386
  "panels.discover.initBranch": "Branch",
3377
3387
  "panels.discover.initBranchHint": "The index and build files go to this branch; an empty repository gets it created.",
3378
3388
  "panels.discover.initBranchBad": "Use only letters, digits, dots, underscores, slashes, or dashes in a branch name.",
@@ -3703,6 +3713,8 @@ window.__ModuleLoader__.load({
3703
3713
  "approval.publish.version": "Version",
3704
3714
  "approval.publish.author": "Author",
3705
3715
  "approval.publish.authorMissing": "unsigned",
3716
+ "approval.publish.labels": "Labels",
3717
+ "approval.publish.labelsMissing": "none yet (1–2 picked on publish)",
3706
3718
  "approval.publish.owner": "Owner",
3707
3719
  "approval.publish.ownerUnowned": "originally unattributed",
3708
3720
  "approval.publish.ownerTaken": "Owned by {owner}",
@@ -4118,7 +4130,7 @@ window.__ModuleLoader__.load({
4118
4130
  "panels.discover.missingIndex": "仓库里还没有索引文件 {path}",
4119
4131
  "panels.discover.initTitle": "把这个仓库初始化成模块市场索引?",
4120
4132
  "panels.discover.initCta": "初始化成市场索引",
4121
- "panels.discover.initWhat": "会在 {branch} 分支写索引目录 market/ 与 README.md,提交一次并推上去;之后从这个工作台发布的模块会把打包好的文件提交到 artifacts/<包名>/<版本>/,条目写到 market/<包名>/<版本>.json。仓库的写权限归它的所有者。",
4133
+ "panels.discover.initWhat": "会在 {branch} 分支写索引目录 market/ 与 README.md,提交一次并推上去;之后从这个工作台发布的模块会把打包好的文件提交到 artifacts/<包名>/,条目写到 market/<包名>.json。仓库的写权限归它的所有者。",
4122
4134
  "panels.discover.initBranch": "分支",
4123
4135
  "panels.discover.initBranchHint": "索引和打包文件都发到这个分支;空仓库会新建它。",
4124
4136
  "panels.discover.initBranchBad": "分支名只能用字母、数字、点、下划线、斜杠或短横线",
@@ -4449,6 +4461,8 @@ window.__ModuleLoader__.load({
4449
4461
  "approval.publish.version": "版本",
4450
4462
  "approval.publish.author": "作者",
4451
4463
  "approval.publish.authorMissing": "未署名",
4464
+ "approval.publish.labels": "标签",
4465
+ "approval.publish.labelsMissing": "还没有(发布到市场时补 1–2 个)",
4452
4466
  "approval.publish.owner": "认领人",
4453
4467
  "approval.publish.ownerUnowned": "原来没署名",
4454
4468
  "approval.publish.ownerTaken": "已有主人:{owner}",
@@ -13237,6 +13251,11 @@ window.__ModuleLoader__.load({
13237
13251
  const value = args[key];
13238
13252
  return typeof value === "string" ? value.replace(/\s+/g, " ").trim() : "";
13239
13253
  }
13254
+ function labelsOf(args) {
13255
+ const value = args["labels"];
13256
+ if (!Array.isArray(value)) return [];
13257
+ return [...new Set(value.flatMap((one) => typeof one === "string" && one.trim() !== "" ? [one.trim()] : []))];
13258
+ }
13240
13259
  function recordApprovalRows(args, t) {
13241
13260
  const unit = textOf(args, "unit");
13242
13261
  const doing = textOf(args, "doing");
@@ -13308,6 +13327,14 @@ window.__ModuleLoader__.load({
13308
13327
  value: author !== "" ? author : preview === void 0 ? t("approval.publish.reading") : preview?.author === void 0 || preview.author === "" ? t("approval.publish.authorMissing") : preview.author
13309
13328
  }
13310
13329
  ];
13330
+ if (target === "market" || target === "" && preview?.market !== void 0) {
13331
+ const asked = labelsOf(args);
13332
+ const labels = asked.length > 0 ? asked : preview?.labels ?? [];
13333
+ rows.push({
13334
+ label: t("approval.publish.labels"),
13335
+ value: preview === void 0 && asked.length === 0 ? t("approval.publish.reading") : labels.length === 0 ? t("approval.publish.labelsMissing") : labels.join(" · ")
13336
+ });
13337
+ }
13311
13338
  const claim = preview?.claim;
13312
13339
  if (claim !== void 0 && claim.state !== "new" && claim.state !== "unknown") {
13313
13340
  if (claim.state === "unit-taken") rows.push({
@@ -2802,6 +2802,15 @@ function binInstallProblemsOf(raw, at) {
2802
2802
  }
2803
2803
  return errors;
2804
2804
  }
2805
+ function libRunsProblemsOf(raw, at) {
2806
+ if (raw === void 0) return [];
2807
+ if (!Array.isArray(raw)) return [`${at}.runs 要是数组`];
2808
+ if (raw.length === 0) return [`${at}.runs 是空数组 —— 不自己跑命令就整条删掉`];
2809
+ const names = raw.map((one) => text(one));
2810
+ if (names.some((one) => one === "")) return [`${at}.runs 里有空字符串`];
2811
+ if (new Set(names).size !== names.length) return [`${at}.runs 里有重复的运行时`];
2812
+ return [];
2813
+ }
2805
2814
  function perKindProblemsOf(kind, raw, at) {
2806
2815
  const errors = [];
2807
2816
  if (kind === "bin" || kind === "lib" || kind === "env") {
@@ -2809,6 +2818,7 @@ function perKindProblemsOf(kind, raw, at) {
2809
2818
  }
2810
2819
  if (kind === "bin") errors.push(...binInstallProblemsOf(raw["install"], at));
2811
2820
  if (raw["docs"] !== void 0 && text(raw["docs"]) === "") errors.push(`${at}.docs 是空串`);
2821
+ if (kind === "lib") errors.push(...libRunsProblemsOf(raw["runs"], at));
2812
2822
  if (kind === "extension") {
2813
2823
  if (text(raw["runtime"]) === "") errors.push(`${at}.runtime 没写 —— 扩展属于哪个运行时(如 opencli)`);
2814
2824
  if (text(raw["name"]) === "") errors.push(`${at}.name 没写`);
@@ -3365,7 +3375,7 @@ var en = {
3365
3375
  "panels.discover.missingIndex": "This repository has no {path} yet.",
3366
3376
  "panels.discover.initTitle": "Initialize this repository as a module market index?",
3367
3377
  "panels.discover.initCta": "Initialize market index",
3368
- "panels.discover.initWhat": "It will write the index directory market/ and README.md on {branch}, commit once, and push. Modules you publish from this workbench will commit their build files under artifacts/<package-name>/<version>/ and their entry under market/<package-name>/<version>.json. The repository stays owned by its owner.",
3378
+ "panels.discover.initWhat": "It will write the index directory market/ and README.md on {branch}, commit once, and push. Modules you publish from this workbench will commit their build files under artifacts/<package-name>/ and their entry in market/<package-name>.json. The repository stays owned by its owner.",
3369
3379
  "panels.discover.initBranch": "Branch",
3370
3380
  "panels.discover.initBranchHint": "The index and build files go to this branch; an empty repository gets it created.",
3371
3381
  "panels.discover.initBranchBad": "Use only letters, digits, dots, underscores, slashes, or dashes in a branch name.",
@@ -3696,6 +3706,8 @@ var en = {
3696
3706
  "approval.publish.version": "Version",
3697
3707
  "approval.publish.author": "Author",
3698
3708
  "approval.publish.authorMissing": "unsigned",
3709
+ "approval.publish.labels": "Labels",
3710
+ "approval.publish.labelsMissing": "none yet (1–2 picked on publish)",
3699
3711
  "approval.publish.owner": "Owner",
3700
3712
  "approval.publish.ownerUnowned": "originally unattributed",
3701
3713
  "approval.publish.ownerTaken": "Owned by {owner}",
@@ -4111,7 +4123,7 @@ var dictionaries = {
4111
4123
  "panels.discover.missingIndex": "仓库里还没有索引文件 {path}",
4112
4124
  "panels.discover.initTitle": "把这个仓库初始化成模块市场索引?",
4113
4125
  "panels.discover.initCta": "初始化成市场索引",
4114
- "panels.discover.initWhat": "会在 {branch} 分支写索引目录 market/ 与 README.md,提交一次并推上去;之后从这个工作台发布的模块会把打包好的文件提交到 artifacts/<包名>/<版本>/,条目写到 market/<包名>/<版本>.json。仓库的写权限归它的所有者。",
4126
+ "panels.discover.initWhat": "会在 {branch} 分支写索引目录 market/ 与 README.md,提交一次并推上去;之后从这个工作台发布的模块会把打包好的文件提交到 artifacts/<包名>/,条目写到 market/<包名>.json。仓库的写权限归它的所有者。",
4115
4127
  "panels.discover.initBranch": "分支",
4116
4128
  "panels.discover.initBranchHint": "索引和打包文件都发到这个分支;空仓库会新建它。",
4117
4129
  "panels.discover.initBranchBad": "分支名只能用字母、数字、点、下划线、斜杠或短横线",
@@ -4442,6 +4454,8 @@ var dictionaries = {
4442
4454
  "approval.publish.version": "版本",
4443
4455
  "approval.publish.author": "作者",
4444
4456
  "approval.publish.authorMissing": "未署名",
4457
+ "approval.publish.labels": "标签",
4458
+ "approval.publish.labelsMissing": "还没有(发布到市场时补 1–2 个)",
4445
4459
  "approval.publish.owner": "认领人",
4446
4460
  "approval.publish.ownerUnowned": "原来没署名",
4447
4461
  "approval.publish.ownerTaken": "已有主人:{owner}",
@@ -13230,6 +13244,11 @@ function textOf(args, key) {
13230
13244
  const value = args[key];
13231
13245
  return typeof value === "string" ? value.replace(/\s+/g, " ").trim() : "";
13232
13246
  }
13247
+ function labelsOf(args) {
13248
+ const value = args["labels"];
13249
+ if (!Array.isArray(value)) return [];
13250
+ return [...new Set(value.flatMap((one) => typeof one === "string" && one.trim() !== "" ? [one.trim()] : []))];
13251
+ }
13233
13252
  function recordApprovalRows(args, t) {
13234
13253
  const unit = textOf(args, "unit");
13235
13254
  const doing = textOf(args, "doing");
@@ -13301,6 +13320,14 @@ function publishRows(args, preview, t) {
13301
13320
  value: author !== "" ? author : preview === void 0 ? t("approval.publish.reading") : preview?.author === void 0 || preview.author === "" ? t("approval.publish.authorMissing") : preview.author
13302
13321
  }
13303
13322
  ];
13323
+ if (target === "market" || target === "" && preview?.market !== void 0) {
13324
+ const asked = labelsOf(args);
13325
+ const labels = asked.length > 0 ? asked : preview?.labels ?? [];
13326
+ rows.push({
13327
+ label: t("approval.publish.labels"),
13328
+ value: preview === void 0 && asked.length === 0 ? t("approval.publish.reading") : labels.length === 0 ? t("approval.publish.labelsMissing") : labels.join(" · ")
13329
+ });
13330
+ }
13304
13331
  const claim = preview?.claim;
13305
13332
  if (claim !== void 0 && claim.state !== "new" && claim.state !== "unknown") {
13306
13333
  if (claim.state === "unit-taken") rows.push({
@@ -2805,6 +2805,15 @@ function binInstallProblemsOf(raw, at) {
2805
2805
  }
2806
2806
  return errors;
2807
2807
  }
2808
+ function libRunsProblemsOf(raw, at) {
2809
+ if (raw === void 0) return [];
2810
+ if (!Array.isArray(raw)) return [`${at}.runs 要是数组`];
2811
+ if (raw.length === 0) return [`${at}.runs 是空数组 —— 不自己跑命令就整条删掉`];
2812
+ const names = raw.map((one) => text(one));
2813
+ if (names.some((one) => one === "")) return [`${at}.runs 里有空字符串`];
2814
+ if (new Set(names).size !== names.length) return [`${at}.runs 里有重复的运行时`];
2815
+ return [];
2816
+ }
2808
2817
  function perKindProblemsOf(kind, raw, at) {
2809
2818
  const errors = [];
2810
2819
  if (kind === "bin" || kind === "lib" || kind === "env") {
@@ -2812,6 +2821,7 @@ function perKindProblemsOf(kind, raw, at) {
2812
2821
  }
2813
2822
  if (kind === "bin") errors.push(...binInstallProblemsOf(raw["install"], at));
2814
2823
  if (raw["docs"] !== void 0 && text(raw["docs"]) === "") errors.push(`${at}.docs 是空串`);
2824
+ if (kind === "lib") errors.push(...libRunsProblemsOf(raw["runs"], at));
2815
2825
  if (kind === "extension") {
2816
2826
  if (text(raw["runtime"]) === "") errors.push(`${at}.runtime 没写 —— 扩展属于哪个运行时(如 opencli)`);
2817
2827
  if (text(raw["name"]) === "") errors.push(`${at}.name 没写`);
@@ -3368,7 +3378,7 @@ var en = {
3368
3378
  "panels.discover.missingIndex": "This repository has no {path} yet.",
3369
3379
  "panels.discover.initTitle": "Initialize this repository as a module market index?",
3370
3380
  "panels.discover.initCta": "Initialize market index",
3371
- "panels.discover.initWhat": "It will write the index directory market/ and README.md on {branch}, commit once, and push. Modules you publish from this workbench will commit their build files under artifacts/<package-name>/<version>/ and their entry under market/<package-name>/<version>.json. The repository stays owned by its owner.",
3381
+ "panels.discover.initWhat": "It will write the index directory market/ and README.md on {branch}, commit once, and push. Modules you publish from this workbench will commit their build files under artifacts/<package-name>/ and their entry in market/<package-name>.json. The repository stays owned by its owner.",
3372
3382
  "panels.discover.initBranch": "Branch",
3373
3383
  "panels.discover.initBranchHint": "The index and build files go to this branch; an empty repository gets it created.",
3374
3384
  "panels.discover.initBranchBad": "Use only letters, digits, dots, underscores, slashes, or dashes in a branch name.",
@@ -3699,6 +3709,8 @@ var en = {
3699
3709
  "approval.publish.version": "Version",
3700
3710
  "approval.publish.author": "Author",
3701
3711
  "approval.publish.authorMissing": "unsigned",
3712
+ "approval.publish.labels": "Labels",
3713
+ "approval.publish.labelsMissing": "none yet (1–2 picked on publish)",
3702
3714
  "approval.publish.owner": "Owner",
3703
3715
  "approval.publish.ownerUnowned": "originally unattributed",
3704
3716
  "approval.publish.ownerTaken": "Owned by {owner}",
@@ -4114,7 +4126,7 @@ var dictionaries = {
4114
4126
  "panels.discover.missingIndex": "仓库里还没有索引文件 {path}",
4115
4127
  "panels.discover.initTitle": "把这个仓库初始化成模块市场索引?",
4116
4128
  "panels.discover.initCta": "初始化成市场索引",
4117
- "panels.discover.initWhat": "会在 {branch} 分支写索引目录 market/ 与 README.md,提交一次并推上去;之后从这个工作台发布的模块会把打包好的文件提交到 artifacts/<包名>/<版本>/,条目写到 market/<包名>/<版本>.json。仓库的写权限归它的所有者。",
4129
+ "panels.discover.initWhat": "会在 {branch} 分支写索引目录 market/ 与 README.md,提交一次并推上去;之后从这个工作台发布的模块会把打包好的文件提交到 artifacts/<包名>/,条目写到 market/<包名>.json。仓库的写权限归它的所有者。",
4118
4130
  "panels.discover.initBranch": "分支",
4119
4131
  "panels.discover.initBranchHint": "索引和打包文件都发到这个分支;空仓库会新建它。",
4120
4132
  "panels.discover.initBranchBad": "分支名只能用字母、数字、点、下划线、斜杠或短横线",
@@ -4445,6 +4457,8 @@ var dictionaries = {
4445
4457
  "approval.publish.version": "版本",
4446
4458
  "approval.publish.author": "作者",
4447
4459
  "approval.publish.authorMissing": "未署名",
4460
+ "approval.publish.labels": "标签",
4461
+ "approval.publish.labelsMissing": "还没有(发布到市场时补 1–2 个)",
4448
4462
  "approval.publish.owner": "认领人",
4449
4463
  "approval.publish.ownerUnowned": "原来没署名",
4450
4464
  "approval.publish.ownerTaken": "已有主人:{owner}",
@@ -13233,6 +13247,11 @@ function textOf(args, key) {
13233
13247
  const value = args[key];
13234
13248
  return typeof value === "string" ? value.replace(/\s+/g, " ").trim() : "";
13235
13249
  }
13250
+ function labelsOf(args) {
13251
+ const value = args["labels"];
13252
+ if (!Array.isArray(value)) return [];
13253
+ return [...new Set(value.flatMap((one) => typeof one === "string" && one.trim() !== "" ? [one.trim()] : []))];
13254
+ }
13236
13255
  function recordApprovalRows(args, t) {
13237
13256
  const unit = textOf(args, "unit");
13238
13257
  const doing = textOf(args, "doing");
@@ -13304,6 +13323,14 @@ function publishRows(args, preview, t) {
13304
13323
  value: author !== "" ? author : preview === void 0 ? t("approval.publish.reading") : preview?.author === void 0 || preview.author === "" ? t("approval.publish.authorMissing") : preview.author
13305
13324
  }
13306
13325
  ];
13326
+ if (target === "market" || target === "" && preview?.market !== void 0) {
13327
+ const asked = labelsOf(args);
13328
+ const labels = asked.length > 0 ? asked : preview?.labels ?? [];
13329
+ rows.push({
13330
+ label: t("approval.publish.labels"),
13331
+ value: preview === void 0 && asked.length === 0 ? t("approval.publish.reading") : labels.length === 0 ? t("approval.publish.labelsMissing") : labels.join(" · ")
13332
+ });
13333
+ }
13307
13334
  const claim = preview?.claim;
13308
13335
  if (claim !== void 0 && claim.state !== "new" && claim.state !== "unknown") {
13309
13336
  if (claim.state === "unit-taken") rows.push({
@@ -144,7 +144,8 @@ var NEED_KEYS = [
144
144
  "sources",
145
145
  "secret",
146
146
  "install",
147
- "docs"
147
+ "docs",
148
+ "runs"
148
149
  ];
149
150
  var SOURCE_KEYS = [
150
151
  "kind",
@@ -251,6 +252,15 @@ function binInstallProblemsOf(raw, at) {
251
252
  }
252
253
  return errors;
253
254
  }
255
+ function libRunsProblemsOf(raw, at) {
256
+ if (raw === void 0) return [];
257
+ if (!Array.isArray(raw)) return [`${at}.runs 要是数组`];
258
+ if (raw.length === 0) return [`${at}.runs 是空数组 —— 不自己跑命令就整条删掉`];
259
+ const names = raw.map((one) => text$3(one));
260
+ if (names.some((one) => one === "")) return [`${at}.runs 里有空字符串`];
261
+ if (new Set(names).size !== names.length) return [`${at}.runs 里有重复的运行时`];
262
+ return [];
263
+ }
254
264
  function perKindProblemsOf(kind, raw, at) {
255
265
  const errors = [];
256
266
  if (kind === "bin" || kind === "lib" || kind === "env") {
@@ -258,6 +268,7 @@ function perKindProblemsOf(kind, raw, at) {
258
268
  }
259
269
  if (kind === "bin") errors.push(...binInstallProblemsOf(raw["install"], at));
260
270
  if (raw["docs"] !== void 0 && text$3(raw["docs"]) === "") errors.push(`${at}.docs 是空串`);
271
+ if (kind === "lib") errors.push(...libRunsProblemsOf(raw["runs"], at));
261
272
  if (kind === "extension") {
262
273
  if (text$3(raw["runtime"]) === "") errors.push(`${at}.runtime 没写 —— 扩展属于哪个运行时(如 opencli)`);
263
274
  if (text$3(raw["name"]) === "") errors.push(`${at}.name 没写`);
@@ -1134,7 +1145,7 @@ var PHASES = [
1134
1145
  function asRecord$7(value) {
1135
1146
  return typeof value === "object" && value !== null ? value : void 0;
1136
1147
  }
1137
- function textOf$5(value, max) {
1148
+ function textOf$6(value, max) {
1138
1149
  if (typeof value !== "string") return "";
1139
1150
  const trimmed = value.trim();
1140
1151
  return trimmed.length > max ? trimmed.slice(0, max) : trimmed;
@@ -1147,8 +1158,8 @@ function atOf(value) {
1147
1158
  function errorOf(raw) {
1148
1159
  const record = asRecord$7(raw);
1149
1160
  if (record === void 0) return void 0;
1150
- const code = textOf$5(record["code"], 120);
1151
- const message = textOf$5(record["message"], PANEL_STATE_MAX_TEXT);
1161
+ const code = textOf$6(record["code"], 120);
1162
+ const message = textOf$6(record["message"], PANEL_STATE_MAX_TEXT);
1152
1163
  if (code === "" && message === "") return void 0;
1153
1164
  return {
1154
1165
  code: code === "" ? "unknown" : code,
@@ -1167,7 +1178,7 @@ function parseCardsReport(payload) {
1167
1178
  ok: false,
1168
1179
  message: "请求体要是一个对象"
1169
1180
  };
1170
- const workspace = textOf$5(record["workspace"], PANEL_STATE_MAX_TEXT);
1181
+ const workspace = textOf$6(record["workspace"], PANEL_STATE_MAX_TEXT);
1171
1182
  if (workspace === "") return {
1172
1183
  ok: false,
1173
1184
  message: "workspace 不能是空的 —— 面板按工作区存"
@@ -1181,9 +1192,9 @@ function parseCardsReport(payload) {
1181
1192
  for (const item of raw.slice(0, 32)) {
1182
1193
  const card = asRecord$7(item);
1183
1194
  if (card === void 0) continue;
1184
- const unit = textOf$5(card["unit"], 200);
1185
- const route = textOf$5(card["route"], 400);
1186
- const phase = textOf$5(card["phase"], 20);
1195
+ const unit = textOf$6(card["unit"], 200);
1196
+ const route = textOf$6(card["route"], 400);
1197
+ const phase = textOf$6(card["phase"], 20);
1187
1198
  const at = atOf(card["at"]);
1188
1199
  if (unit === "" || route === "" || at === null || !PHASES.includes(phase)) continue;
1189
1200
  const error = errorOf(card["error"]);
@@ -1218,9 +1229,9 @@ function parseCrashReport(payload) {
1218
1229
  ok: false,
1219
1230
  message: "请求体要是一个对象"
1220
1231
  };
1221
- const workspace = textOf$5(record["workspace"], PANEL_STATE_MAX_TEXT);
1222
- const unit = textOf$5(record["unit"], 200);
1223
- const reason = textOf$5(record["reason"], PANEL_STATE_MAX_TEXT);
1232
+ const workspace = textOf$6(record["workspace"], PANEL_STATE_MAX_TEXT);
1233
+ const unit = textOf$6(record["unit"], 200);
1234
+ const reason = textOf$6(record["reason"], PANEL_STATE_MAX_TEXT);
1224
1235
  if (workspace === "") return {
1225
1236
  ok: false,
1226
1237
  message: "workspace 不能是空的"
@@ -2033,7 +2044,7 @@ var PLUGIN_LEDGER_FILE = "plugins.json";
2033
2044
  function ledgerKeyOf(entry) {
2034
2045
  return `${entry.opencliHome}\u0000${entry.package}`;
2035
2046
  }
2036
- function textOf$4(value) {
2047
+ function textOf$5(value) {
2037
2048
  if (typeof value !== "string") return void 0;
2038
2049
  const trimmed = value.trim();
2039
2050
  return trimmed === "" ? void 0 : trimmed;
@@ -2041,13 +2052,13 @@ function textOf$4(value) {
2041
2052
  function entryOf$3(value) {
2042
2053
  if (typeof value !== "object" || value === null) return void 0;
2043
2054
  const box = value;
2044
- const opencliHome = textOf$4(box["opencliHome"]);
2045
- const pkg = textOf$4(box["package"]);
2046
- const installedAt = textOf$4(box["installedAt"]);
2055
+ const opencliHome = textOf$5(box["opencliHome"]);
2056
+ const pkg = textOf$5(box["package"]);
2057
+ const installedAt = textOf$5(box["installedAt"]);
2047
2058
  if (opencliHome === void 0 || pkg === void 0 || installedAt === void 0) return void 0;
2048
- const name = textOf$4(box["name"]);
2049
- const registry = textOf$4(box["registry"]);
2050
- const releasedAt = textOf$4(box["releasedAt"]);
2059
+ const name = textOf$5(box["name"]);
2060
+ const registry = textOf$5(box["registry"]);
2061
+ const releasedAt = textOf$5(box["releasedAt"]);
2051
2062
  return {
2052
2063
  opencliHome,
2053
2064
  package: pkg,
@@ -2350,6 +2361,93 @@ function sessionIdOf(exec) {
2350
2361
  return typeof id === "string" && id.trim() !== "" ? id.trim() : null;
2351
2362
  }
2352
2363
  //#endregion
2364
+ //#region ../shared/dist/host/opencli-runner.js
2365
+ var AUTH_REQUIRED_EXIT_CODE = 77;
2366
+ function textOf$4(value) {
2367
+ return typeof value === "string" ? value : "";
2368
+ }
2369
+ function failedOf(args, error) {
2370
+ const head = `Command failed: opencli ${args.join(" ")}`;
2371
+ const auth = error?.pageCode === "auth-required";
2372
+ const helpUrl = textOf$4(error?.helpUrl);
2373
+ const detail = textOf$4(error?.detail);
2374
+ const hint = textOf$4(error?.hint);
2375
+ const failed = new Error([
2376
+ head,
2377
+ ...auth ? ["code: AUTH_REQUIRED", `message: ${textOf$4(error?.message)}`] : [textOf$4(error?.message) || "opencli 这条命令没跑通"],
2378
+ ...detail === "" ? [] : [detail],
2379
+ ...hint === "" ? [] : [hint],
2380
+ ...auth && helpUrl !== "" ? [`help: Please open Chrome or Chromium and log in to ${helpUrl}`] : []
2381
+ ].join("\n"));
2382
+ if (auth) failed.code = AUTH_REQUIRED_EXIT_CODE;
2383
+ return failed;
2384
+ }
2385
+ /**
2386
+ * 把读缝包成一条 opencli 命令的执行器:给还按 `execFile('opencli', args)` 收结果的编排库用,
2387
+ * 让它们跑在面板用的那份 opencli 上(同一套插件、同一份登录态)。
2388
+ *
2389
+ * 失败按 opencli 自己的约定还原:未登录是 `code: AUTH_REQUIRED` + 退出码 77,编排库的
2390
+ * 「等登录再重试」才接得上;其它失败保留 `Command failed: opencli …` 那句外壳。
2391
+ * @param read 模块手里的读缝(`data.read`)。
2392
+ * @param options `timeoutMs` 透传给读缝;不传就用读缝自己的默认值。
2393
+ * @returns 执行器;直接交给编排库的 `setOpencliRunner`。
2394
+ */
2395
+ function opencliRunnerOf(read, options = {}) {
2396
+ return async (args) => {
2397
+ const result = await read({
2398
+ kind: "command",
2399
+ adapter: "opencli",
2400
+ argv: [...args],
2401
+ ...options.timeoutMs === void 0 ? {} : { timeoutMs: options.timeoutMs }
2402
+ });
2403
+ if (result.ok) return { stdout: JSON.stringify(result.data) };
2404
+ throw failedOf(args, result.error);
2405
+ };
2406
+ }
2407
+ //#endregion
2408
+ //#region ../shared/dist/host/lib-runners.js
2409
+ function runnerOf(runtimes, runtime) {
2410
+ return runtime === "opencli" ? runtimes.opencli : void 0;
2411
+ }
2412
+ function setterNameOf(runtime) {
2413
+ return `set${runtime.charAt(0).toUpperCase()}${runtime.slice(1)}Runner`;
2414
+ }
2415
+ /**
2416
+ * 给声明了 `runs` 的 lib 注入「跑这个运行时」的执行器:库侧按约定暴露 `setOpencliRunner`
2417
+ * (运行时名字首字母大写 + `Runner`),外壳在每次 `load` 之后把执行器交给它。
2418
+ *
2419
+ * 没暴露的(版本旧)就保持它自己的行为(按 PATH 找),只记一条 warn;不熟悉的运行时同样只 warn。
2420
+ * @param libs 原来的读库口。
2421
+ * @param runtimes 外壳手上有的执行器,按运行时名字给。
2422
+ * @param logger 记 warn 的地方(默认不记)。
2423
+ * @returns 包好的读库口;`load` 的签名与返回不变。
2424
+ */
2425
+ function withLibRunners(libs, runtimes, logger) {
2426
+ const warned = /* @__PURE__ */ new Set();
2427
+ const warnOnce = (key, message) => {
2428
+ if (warned.has(key)) return;
2429
+ warned.add(key);
2430
+ logger?.warn?.(message);
2431
+ };
2432
+ return { async load(need, entry) {
2433
+ const module = await libs.load(need, entry);
2434
+ for (const runtime of need.runs ?? []) {
2435
+ const runner = runnerOf(runtimes, runtime);
2436
+ if (runner === void 0) {
2437
+ warnOnce(`${need.name}:${runtime}:unsupported`, `[dsh-workbench] ${need.name} 声明了自己会跑 ${runtime},但工作台没有这个执行器 —— 它会按自己的方式找`);
2438
+ continue;
2439
+ }
2440
+ const setter = typeof module === "object" && module !== null ? module[setterNameOf(runtime)] : void 0;
2441
+ if (typeof setter !== "function") {
2442
+ warnOnce(`${need.name}:${entry}:${runtime}:missing`, `[dsh-workbench] ${need.name} 声明了自己会跑 ${runtime},但这一版没有 ${setterNameOf(runtime)} —— 它会按 PATH 找`);
2443
+ continue;
2444
+ }
2445
+ setter.call(module, runner);
2446
+ }
2447
+ return module;
2448
+ } };
2449
+ }
2450
+ //#endregion
2353
2451
  //#region ../shared/dist/host/value-handoff.js
2354
2452
  function handoffId(entry) {
2355
2453
  return `${String(entry.fact.length)}:${entry.fact}${entry.key}`;
@@ -4909,6 +5007,84 @@ var MARKET_PUBLISH_PREVIEW_ROUTE = "panels/market-publish-preview";
4909
5007
  var MARKET_SOURCES_RESOURCE = "market-sources";
4910
5008
  var MARKET_SOURCES_ROUTE = "panels/market-sources";
4911
5009
  //#endregion
5010
+ //#region ../shared/dist/host/market-index-claim.js
5011
+ function foldedName(name) {
5012
+ return name.replace(/\s+/gu, " ").trim().toLowerCase();
5013
+ }
5014
+ function publisherIdentityOf(text) {
5015
+ const raw = (text ?? "").trim();
5016
+ if (raw === "") return void 0;
5017
+ const match = /^(.*?)\s*<([^<>]*)>\s*$/u.exec(raw);
5018
+ const name = (match === null ? raw : match[1]).trim();
5019
+ const email = match === null ? "" : match[2].trim().toLowerCase();
5020
+ if (name === "") return void 0;
5021
+ return email === "" ? { name } : {
5022
+ name,
5023
+ email
5024
+ };
5025
+ }
5026
+ function samePublisher(left, right) {
5027
+ const a = publisherIdentityOf(left);
5028
+ const b = publisherIdentityOf(right);
5029
+ if (a === void 0 || b === void 0) return false;
5030
+ if (a.email !== void 0 && b.email !== void 0) return a.email === b.email;
5031
+ return foldedName(a.name) === foldedName(b.name);
5032
+ }
5033
+ function entryOwnerOf(entry) {
5034
+ const owner = (entry.owner ?? "").trim();
5035
+ if (owner !== "") return owner;
5036
+ const author = (entry.author ?? "").trim();
5037
+ return author === "" ? void 0 : author;
5038
+ }
5039
+ function claimOfEntry(entry, publisher) {
5040
+ if (entry === void 0) return { state: "new" };
5041
+ const owner = entryOwnerOf(entry);
5042
+ if (owner === void 0) return { state: "unowned" };
5043
+ if (publisher === void 0 || publisher.trim() === "") return { state: "unknown" };
5044
+ return samePublisher(owner, publisher) ? {
5045
+ state: "owned",
5046
+ owner
5047
+ } : {
5048
+ state: "conflict",
5049
+ owner
5050
+ };
5051
+ }
5052
+ function marketArtifactRoot(name) {
5053
+ return `${MARKET_ARTIFACTS_DIR}/${name}`;
5054
+ }
5055
+ function entryUnitOf(entry) {
5056
+ const unit = entry.metadata?.unit?.trim();
5057
+ if (unit !== void 0 && unit !== "") return unit;
5058
+ for (const version of entry.versions) {
5059
+ if (version.source.type !== "git") continue;
5060
+ const legacy = /^packages\/([^/]+)$/u.exec(version.source.path ?? "")?.[1];
5061
+ if (legacy !== void 0) return legacy;
5062
+ }
5063
+ }
5064
+ function claimOf(index, input) {
5065
+ const base = claimOfEntry(index.plugins.find((one) => one.name === input.name), input.publisher);
5066
+ if (base.state === "conflict" || base.state === "unknown") return base;
5067
+ const unit = (input.unit ?? "").trim();
5068
+ if (unit !== "") for (const other of index.plugins) {
5069
+ if (other.name === input.name) continue;
5070
+ if (entryUnitOf(other) !== unit) continue;
5071
+ return {
5072
+ state: "unit-taken",
5073
+ entry: other.name
5074
+ };
5075
+ }
5076
+ const path = (input.artifactPath ?? "").trim();
5077
+ if (path !== "") for (const other of index.plugins) {
5078
+ if (other.name === input.name) continue;
5079
+ if (!other.versions.some((one) => one.source.type === "git" && (one.source.path ?? "") === path)) continue;
5080
+ return {
5081
+ state: "path-taken",
5082
+ entry: other.name
5083
+ };
5084
+ }
5085
+ return base;
5086
+ }
5087
+ //#endregion
4912
5088
  //#region ../shared/dist/lib/market-index.js
4913
5089
  var BRANCH = /^[A-Za-z0-9][A-Za-z0-9._/-]*$/;
4914
5090
  function marketBranchOk(value) {
@@ -5265,115 +5441,49 @@ function parseSourceConfig(raw) {
5265
5441
  }
5266
5442
  };
5267
5443
  }
5268
- function docFieldsOf(record, at) {
5269
- const name = asText$4(record["name"]);
5270
- if (name === "" || name.length > 214 || !NPM_NAME.test(name)) return problem$1("name", `不是合法 npm 包名:${JSON.stringify(name)}`, at);
5271
- const icon = asText$4(record["icon"]);
5272
- if (icon !== "") {
5273
- const badIcon = iconProblem(icon);
5274
- if (badIcon !== void 0) return badIcon;
5275
- }
5276
- const owner = asText$4(record["owner"]);
5277
- if (owner !== "") {
5278
- const badOwner = ownerProblem(owner);
5279
- if (badOwner !== void 0) return badOwner;
5280
- }
5281
- const metadata = metadataOf(record["metadata"]);
5282
- if (metadata?.unit !== void 0 && !UNIT_ID.test(metadata.unit)) return problem$1("unit", `metadata.unit 只能是小写字母开头的 a-z0-9-(现在是 ${JSON.stringify(metadata.unit)})`, at);
5283
- const title = asLocalized(record["title"]);
5284
- const description = asLocalized(record["description"]);
5285
- const author = asText$4(record["author"]);
5286
- const homepage = asText$4(record["homepage"]);
5287
- return {
5288
- name,
5289
- ...title === void 0 ? {} : { title },
5290
- ...description === void 0 ? {} : { description },
5291
- ...author === "" ? {} : { author },
5292
- ...owner === "" ? {} : { owner },
5293
- ...homepage === "" ? {} : { homepage },
5294
- ...icon === "" ? {} : { icon },
5295
- ...metadata === void 0 ? {} : { metadata }
5296
- };
5444
+ function indexPathBase(dir) {
5445
+ return dir.replace(/^\/+|\/+$/g, "") || "market";
5297
5446
  }
5298
- function parseMarketEntryDoc(raw) {
5299
- const record = asRecord$4(raw);
5300
- if (record === void 0) return {
5301
- ok: false,
5302
- problems: [problem$1("entry", "条目文件必须是一个 JSON 对象")]
5303
- };
5304
- const fields = docFieldsOf(record, "entry");
5305
- if ("kind" in fields) return {
5306
- ok: false,
5307
- problems: [fields]
5308
- };
5309
- const version = asText$4(record["version"]);
5310
- const timestamp = record["publishTimestamp"];
5311
- if (timestamp !== void 0 && (!Number.isInteger(timestamp) || timestamp < 0)) return {
5312
- ok: false,
5313
- problems: [problem$1("timestamp", "publishTimestamp 必须是 Unix 秒整数", "entry")]
5314
- };
5315
- if (version === "") {
5316
- if (timestamp === void 0) return {
5317
- ok: false,
5318
- problems: [problem$1("timestamp", "元数据文件要有 publishTimestamp", "entry")]
5319
- };
5320
- const epoch = record["epoch"];
5321
- if (epoch !== void 0 && (!Number.isInteger(epoch) || epoch < 0)) return {
5322
- ok: false,
5323
- problems: [problem$1("timestamp", "epoch 必须是非负整数", "entry")]
5324
- };
5447
+ function marketEntryPath(dir, name) {
5448
+ if (!NPM_NAME.test(name)) throw new Error(`不是合法包名:${JSON.stringify(name)}`);
5449
+ return `${indexPathBase(dir)}/${name}.json`;
5450
+ }
5451
+ function parseMarketEntryJson(text) {
5452
+ let raw;
5453
+ try {
5454
+ raw = JSON.parse(text);
5455
+ } catch (error) {
5325
5456
  return {
5326
- ok: true,
5327
- doc: {
5328
- ...fields,
5329
- publishTimestamp: timestamp,
5330
- ...epoch === void 0 ? {} : { epoch }
5331
- }
5457
+ ok: false,
5458
+ problems: [problem$1("not-json", `JSON 解析失败:${error instanceof Error ? error.message : String(error)}`, "entry")]
5332
5459
  };
5333
5460
  }
5334
- if (!isValidVersion(version)) return {
5461
+ const parsed = entryOf$1(raw, "entry");
5462
+ if ("kind" in parsed) return {
5335
5463
  ok: false,
5336
- problems: [problem$1("version", `版本号不是合法 SemVer:${JSON.stringify(version)}`, "entry")]
5464
+ problems: [parsed]
5337
5465
  };
5338
- const source = sourceOf(record["source"], "entry.source");
5339
- if ("kind" in source) return {
5340
- ok: false,
5341
- problems: [source]
5342
- };
5343
- const engines = asRecord$4(record["engines"]);
5344
- const dsh = engines === void 0 ? "" : asText$4(engines["dsh"]);
5345
5466
  return {
5346
5467
  ok: true,
5347
- doc: {
5348
- ...fields,
5349
- version,
5350
- source,
5351
- ...timestamp === void 0 ? {} : { publishTimestamp: timestamp },
5352
- ...dsh === "" ? {} : { engines: { dsh } }
5353
- }
5468
+ entry: parsed
5354
5469
  };
5355
5470
  }
5356
- function indexPathBase(dir) {
5357
- return dir.replace(/^\/+|\/+$/g, "") || "market";
5358
- }
5359
- function marketEntryPath(dir, name, version) {
5360
- if (!NPM_NAME.test(name)) throw new Error(`不是合法包名:${JSON.stringify(name)}`);
5361
- if (!isValidVersion(version)) throw new Error(`不是合法版本号:${JSON.stringify(version)}`);
5362
- return `${indexPathBase(dir)}/${name}/${version}.json`;
5363
- }
5364
5471
  //#endregion
5365
5472
  //#region ../shared/dist/host/market-index.js
5366
5473
  var MARKET_ENTRIES_README_LINES = [
5367
5474
  "# 索引目录",
5368
5475
  "",
5369
- "一个包一个目录,一个版本一个文件:`market/<包名>/<版本>.json`;产物在 `artifacts/<包名>/<版本>/`。",
5476
+ "一个包一个文件:`market/<包名>.json`,里面是这一个包的元数据与所有版本;",
5370
5477
  "",
5371
- "`meta-<epoch>-<随机后缀>.json` 是只改标题 / 署名 / 说明时追加的元数据快照,读取时按 epoch 取最新的一份。"
5478
+ "产物在 `artifacts/<包名>/`(只放最新一版,老版本按条目里的 commit 取历史)。",
5479
+ "",
5480
+ "发布时只改自己包的文件;包与包之间不共享文件。"
5372
5481
  ];
5373
5482
  var MARKET_INDEX_README_LINES = [
5374
5483
  "# 模块市场索引",
5375
5484
  "",
5376
- "这个仓库给 DeepSeek Harness 工作台当模块市场索引:条目在 `market/<包名>/<版本>.json`,产物在 `artifacts/<包名>/<版本>/`。",
5485
+ "这个仓库给 DeepSeek Harness 工作台当模块市场索引:一个包一个文件 `market/<包名>.json`,",
5486
+ "产物在 `artifacts/<包名>/`;老仓库的 `market.json` 会在第一次发布时自动拆开。",
5377
5487
  "",
5378
5488
  "## 发布模块",
5379
5489
  "",
@@ -5383,8 +5493,7 @@ var MARKET_INDEX_README_LINES = [
5383
5493
  "dsh-wb-module release --index <本仓库地址> --index-policy artifacts-in-repo",
5384
5494
  "```",
5385
5495
  "",
5386
- "产物会提交到 `artifacts/<包名>/<版本>/`,条目提交到 `market/<包名>/<版本>.json`。",
5387
- "发布只新增文件、不改已有文件,两台机器同时发也不会冲突;老条目的 `packages/<包名>/` 路径继续可用。",
5496
+ "发布只会改自己包的那一个文件;包与包之间不会碰同一个文件。",
5388
5497
  "",
5389
5498
  "一个包名归第一次发布的人(条目文件里的 `owner`)。换一个署名发同名会被拒;要换人,先把这一条的 `owner` 改成新的人。",
5390
5499
  "同一个市场里,一个模块 id(`metadata.unit`)只能被一个条目使用;另一个包名想用同一个 id / 产物目录也会被拒。",
@@ -5401,37 +5510,13 @@ function problem(kind, detail, at) {
5401
5510
  ...at === void 0 ? {} : { at }
5402
5511
  };
5403
5512
  }
5404
- function docFieldsFromEntry(entry) {
5405
- return {
5406
- name: entry.name,
5407
- ...entry.title === void 0 ? {} : { title: entry.title },
5408
- ...entry.description === void 0 ? {} : { description: entry.description },
5409
- ...entry.author === void 0 ? {} : { author: entry.author },
5410
- ...entry.owner === void 0 ? {} : { owner: entry.owner },
5411
- ...entry.homepage === void 0 ? {} : { homepage: entry.homepage },
5412
- ...entry.icon === void 0 ? {} : { icon: entry.icon },
5413
- ...entry.metadata === void 0 ? {} : { metadata: entry.metadata }
5414
- };
5415
- }
5416
- function marketVersionDocOf(entry, version) {
5417
- return {
5418
- ...docFieldsFromEntry(entry),
5419
- ...version
5420
- };
5421
- }
5422
5513
  function assembleMarketIndex(files) {
5423
5514
  const problems = [];
5424
- const groups = /* @__PURE__ */ new Map();
5515
+ const entries = /* @__PURE__ */ new Map();
5425
5516
  const ordered = [...files].sort((left, right) => left.path < right.path ? -1 : left.path > right.path ? 1 : 0);
5426
5517
  for (const file of ordered) {
5427
- let raw;
5428
- try {
5429
- raw = JSON.parse(file.text);
5430
- } catch (error) {
5431
- problems.push(problem("not-json", `JSON 解析失败:${error instanceof Error ? error.message : String(error)}`, file.path));
5432
- continue;
5433
- }
5434
- const parsed = parseMarketEntryDoc(raw);
5518
+ if (!file.path.endsWith(".json")) continue;
5519
+ const parsed = parseMarketEntryJson(file.text);
5435
5520
  if (!parsed.ok) {
5436
5521
  for (const one of parsed.problems) problems.push({
5437
5522
  ...one,
@@ -5439,71 +5524,47 @@ function assembleMarketIndex(files) {
5439
5524
  });
5440
5525
  continue;
5441
5526
  }
5442
- const doc = parsed.doc;
5443
- const group = groups.get(doc.name) ?? {
5444
- versions: /* @__PURE__ */ new Map(),
5445
- meta: void 0,
5446
- fallback: void 0
5447
- };
5448
- const at = doc.publishTimestamp ?? 0;
5449
- if ("version" in doc) {
5450
- if (group.versions.has(doc.version)) problems.push(problem("duplicate-version", `版本重复:${doc.version}`, file.path));
5451
- group.versions.set(doc.version, {
5452
- version: doc.version,
5453
- source: doc.source,
5454
- ...doc.publishTimestamp === void 0 ? {} : { publishTimestamp: doc.publishTimestamp },
5455
- ...doc.engines === void 0 ? {} : { engines: doc.engines }
5456
- });
5457
- if (group.fallback === void 0 || at > group.fallback.at || at === group.fallback.at && file.path > group.fallback.path) group.fallback = {
5458
- at,
5459
- path: file.path,
5460
- doc
5461
- };
5462
- } else {
5463
- const epoch = doc.epoch ?? 0;
5464
- if (group.meta === void 0 || epoch > group.meta.epoch || epoch === group.meta.epoch && at > group.meta.at || epoch === group.meta.epoch && at === group.meta.at && file.path > group.meta.path) group.meta = {
5465
- epoch,
5466
- at,
5467
- path: file.path,
5468
- doc
5469
- };
5527
+ const entry = parsed.entry;
5528
+ if (entries.has(entry.name)) {
5529
+ problems.push(problem("duplicate-name", `插件名重复:${entry.name}`, file.path));
5530
+ continue;
5470
5531
  }
5471
- groups.set(doc.name, group);
5532
+ entries.set(entry.name, {
5533
+ ...entry,
5534
+ versions: sortMarketVersions(entry.versions)
5535
+ });
5472
5536
  }
5473
5537
  if (problems.length > 0) return {
5474
5538
  ok: false,
5475
5539
  problems
5476
5540
  };
5477
- const plugins = [...groups.entries()].map(([name, group]) => {
5478
- const meta = group.meta?.doc ?? group.fallback?.doc;
5479
- return {
5480
- name,
5481
- versions: sortMarketVersions([...group.versions.values()]),
5482
- ...meta?.title === void 0 ? {} : { title: meta.title },
5483
- ...meta?.description === void 0 ? {} : { description: meta.description },
5484
- ...meta?.author === void 0 ? {} : { author: meta.author },
5485
- ...meta?.owner === void 0 ? {} : { owner: meta.owner },
5486
- ...meta?.homepage === void 0 ? {} : { homepage: meta.homepage },
5487
- ...meta?.icon === void 0 ? {} : { icon: meta.icon },
5488
- ...meta?.metadata === void 0 ? {} : { metadata: meta.metadata }
5489
- };
5490
- });
5491
- plugins.sort((left, right) => left.name < right.name ? -1 : left.name > right.name ? 1 : 0);
5492
5541
  return {
5493
5542
  ok: true,
5494
5543
  index: {
5495
5544
  format: 1,
5496
- plugins
5545
+ plugins: [...entries.values()].sort((left, right) => left.name < right.name ? -1 : left.name > right.name ? 1 : 0)
5497
5546
  }
5498
5547
  };
5499
5548
  }
5549
+ function marketEntryFileOf(entry, dir = MARKET_INDEX_DIR) {
5550
+ return {
5551
+ path: marketEntryPath(dir, entry.name),
5552
+ text: `${JSON.stringify(entry, null, 2)}\n`
5553
+ };
5554
+ }
5500
5555
  function marketEntryFilesOf(index, dir = MARKET_INDEX_DIR) {
5501
- const files = [];
5502
- for (const entry of index.plugins) for (const version of entry.versions) files.push({
5503
- path: marketEntryPath(dir, entry.name, version.version),
5504
- text: `${JSON.stringify(marketVersionDocOf(entry, version), null, 2)}\n`
5505
- });
5506
- return files;
5556
+ return index.plugins.map((entry) => marketEntryFileOf(healedUnit(entry), dir));
5557
+ }
5558
+ function healedUnit(entry) {
5559
+ if (entry.metadata?.unit !== void 0) return entry;
5560
+ const unit = entryUnitOf(entry);
5561
+ return unit === void 0 ? entry : {
5562
+ ...entry,
5563
+ metadata: {
5564
+ ...entry.metadata,
5565
+ unit
5566
+ }
5567
+ };
5507
5568
  }
5508
5569
  function collectMarketEntryFiles(dir) {
5509
5570
  if (!existsSync(dir)) return [];
@@ -5531,87 +5592,6 @@ function marketEntryFilesOfLegacy(text, dir = MARKET_INDEX_DIR) {
5531
5592
  return marketEntryFilesOf(parsed.index, dir);
5532
5593
  }
5533
5594
  //#endregion
5534
- //#region ../shared/dist/host/market-index-claim.js
5535
- function foldedName(name) {
5536
- return name.replace(/\s+/gu, " ").trim().toLowerCase();
5537
- }
5538
- function publisherIdentityOf(text) {
5539
- const raw = (text ?? "").trim();
5540
- if (raw === "") return void 0;
5541
- const match = /^(.*?)\s*<([^<>]*)>\s*$/u.exec(raw);
5542
- const name = (match === null ? raw : match[1]).trim();
5543
- const email = match === null ? "" : match[2].trim().toLowerCase();
5544
- if (name === "") return void 0;
5545
- return email === "" ? { name } : {
5546
- name,
5547
- email
5548
- };
5549
- }
5550
- function samePublisher(left, right) {
5551
- const a = publisherIdentityOf(left);
5552
- const b = publisherIdentityOf(right);
5553
- if (a === void 0 || b === void 0) return false;
5554
- if (a.email !== void 0 && b.email !== void 0) return a.email === b.email;
5555
- return foldedName(a.name) === foldedName(b.name);
5556
- }
5557
- function entryOwnerOf(entry) {
5558
- const owner = (entry.owner ?? "").trim();
5559
- if (owner !== "") return owner;
5560
- const author = (entry.author ?? "").trim();
5561
- return author === "" ? void 0 : author;
5562
- }
5563
- function claimOfEntry(entry, publisher) {
5564
- if (entry === void 0) return { state: "new" };
5565
- const owner = entryOwnerOf(entry);
5566
- if (owner === void 0) return { state: "unowned" };
5567
- if (publisher === void 0 || publisher.trim() === "") return { state: "unknown" };
5568
- return samePublisher(owner, publisher) ? {
5569
- state: "owned",
5570
- owner
5571
- } : {
5572
- state: "conflict",
5573
- owner
5574
- };
5575
- }
5576
- function marketArtifactRoot(name) {
5577
- return `${MARKET_ARTIFACTS_DIR}/${name}`;
5578
- }
5579
- function marketArtifactPathFor(name, version) {
5580
- return `${MARKET_ARTIFACTS_DIR}/${name}/${version}`;
5581
- }
5582
- function entryUnitOf(entry) {
5583
- const unit = entry.metadata?.unit?.trim();
5584
- if (unit !== void 0 && unit !== "") return unit;
5585
- for (const version of entry.versions) {
5586
- if (version.source.type !== "git") continue;
5587
- const legacy = /^packages\/([^/]+)$/u.exec(version.source.path ?? "")?.[1];
5588
- if (legacy !== void 0) return legacy;
5589
- }
5590
- }
5591
- function claimOf(index, input) {
5592
- const base = claimOfEntry(index.plugins.find((one) => one.name === input.name), input.publisher);
5593
- if (base.state === "conflict" || base.state === "unknown") return base;
5594
- const unit = (input.unit ?? "").trim();
5595
- if (unit !== "") for (const other of index.plugins) {
5596
- if (other.name === input.name) continue;
5597
- if (entryUnitOf(other) !== unit) continue;
5598
- return {
5599
- state: "unit-taken",
5600
- entry: other.name
5601
- };
5602
- }
5603
- const path = (input.artifactPath ?? "").trim();
5604
- if (path !== "") for (const other of index.plugins) {
5605
- if (other.name === input.name) continue;
5606
- if (!other.versions.some((one) => one.source.type === "git" && (one.source.path ?? "") === path)) continue;
5607
- return {
5608
- state: "path-taken",
5609
- entry: other.name
5610
- };
5611
- }
5612
- return base;
5613
- }
5614
- //#endregion
5615
5595
  //#region ../shared/dist/host/changelog.js
5616
5596
  var CHANGELOG_FILE = "CHANGELOG.md";
5617
5597
  var CHANGELOG_KINDS = [
@@ -6725,6 +6705,36 @@ function publishClaimDenyOf(claim, name) {
6725
6705
  if (claim.state === "conflict") return `市场里 ${name} 已经有主了(${claim.owner})—— 同一个名字不能换人发。换一个带团队 scope 的包名;你就是原来的作者(只是换了机器或署名),用 author 参数带上原来的署名;确实是接手,让索引维护者改 market/<包名>/ 条目文件里的 owner。`;
6726
6706
  }
6727
6707
  //#endregion
6708
+ //#region src/modules/panels/model/approval-questions.ts
6709
+ function copiesOf(label, labelEn) {
6710
+ return {
6711
+ team: {
6712
+ zh: `把${label}发到团队源,只发构建产物,不发源码,允许吗?`,
6713
+ en: `Publish ${labelEn} to the team registry; only built artifacts, never the source. Allow?`
6714
+ },
6715
+ public: {
6716
+ zh: `把${label}公开发到 npm,任何人都能安装,允许吗?`,
6717
+ en: `Publish ${labelEn} publicly to npm; anyone can install it. Allow?`
6718
+ },
6719
+ tarball: {
6720
+ zh: `给${label}打一个安装包,只写本机不发源码,允许吗?`,
6721
+ en: `Pack ${labelEn} into a local tarball; nothing leaves this machine. Allow?`
6722
+ },
6723
+ git: {
6724
+ zh: `把${label}提交并推到 git,源码也会一起推送,允许吗?`,
6725
+ en: `Commit and push ${labelEn} to git; the source is pushed too. Allow?`
6726
+ },
6727
+ market: {
6728
+ zh: `把${label}发到市场仓库,产物与索引一起提交,允许吗?`,
6729
+ en: `Publish ${labelEn} to the market repository; artifacts and the index are committed together. Allow?`
6730
+ },
6731
+ local: {
6732
+ zh: `把${label}留在本机,不发,允许吗?`,
6733
+ en: `Keep ${labelEn} local and publish nothing. Allow?`
6734
+ }
6735
+ };
6736
+ }
6737
+ //#endregion
6728
6738
  //#region src/modules/panels/model/approval.ts
6729
6739
  var SPEC_LIMIT = 80;
6730
6740
  var TARGET_LIMIT = 20;
@@ -6810,6 +6820,11 @@ function clipped$1(text) {
6810
6820
  const chars = [...text];
6811
6821
  return chars.length > TARGET_LIMIT ? `${chars.slice(0, TARGET_LIMIT).join("")}…` : text;
6812
6822
  }
6823
+ function labelsOfArgs(raw) {
6824
+ const value = raw["labels"];
6825
+ if (!Array.isArray(value)) return [];
6826
+ return [...new Set(value.flatMap((one) => typeof one === "string" && one.trim() !== "" ? [one.trim()] : []))];
6827
+ }
6813
6828
  function stopVerdict(call, runs) {
6814
6829
  const raw = argsOf$1(call);
6815
6830
  const unit = textOf$3(raw, "unit");
@@ -6847,35 +6862,19 @@ function publishVerdict(call, preview) {
6847
6862
  kind: "deny",
6848
6863
  reason: `这一版还没有更新日志(${found.changelog.version})—— 带上 changelogNote(一行一条)再调,发布时会一起写进 CHANGELOG.md 并随包发`
6849
6864
  };
6850
- const copies = {
6851
- team: {
6852
- zh: `把${label}发到团队源,只发构建产物,不发源码,允许吗?`,
6853
- en: `Publish ${labelEn} to the team registry; only built artifacts, never the source. Allow?`
6854
- },
6855
- public: {
6856
- zh: `把${label}公开发到 npm,任何人都能安装,允许吗?`,
6857
- en: `Publish ${labelEn} publicly to npm; anyone can install it. Allow?`
6858
- },
6859
- tarball: {
6860
- zh: `给${label}打一个安装包,只写本机不发源码,允许吗?`,
6861
- en: `Pack ${labelEn} into a local tarball; nothing leaves this machine. Allow?`
6862
- },
6863
- git: {
6864
- zh: `把${label}提交并推到 git,源码也会一起推送,允许吗?`,
6865
- en: `Commit and push ${labelEn} to git; the source is pushed too. Allow?`
6866
- },
6867
- market: {
6868
- zh: `把${label}发到市场仓库,产物与索引一起提交,允许吗?`,
6869
- en: `Publish ${labelEn} to the market repository; artifacts and the index are committed together. Allow?`
6870
- },
6871
- local: {
6872
- zh: `把${label}留在本机,不发,允许吗?`,
6873
- en: `Keep ${labelEn} local and publish nothing. Allow?`
6874
- }
6865
+ const labels = labelsOfArgs(raw);
6866
+ if (labels.length > 2) return {
6867
+ kind: "deny",
6868
+ reason: `标签最多两个(收到 ${String(labels.length)} 个)—— 挑最能说明这个模块干什么的 1–2 个`
6869
+ };
6870
+ if (target === "market" && labels.length === 0 && (found?.labels ?? []).length === 0) return {
6871
+ kind: "deny",
6872
+ reason: "这个模块还没有标签 —— 发布到市场时给它 1–2 个短词(labels,说它干什么,比如「发布编排」「构建状态」);已经有标签就不用传"
6875
6873
  };
6874
+ const copies = copiesOf(label, labelEn);
6876
6875
  const copy = copies[target] ?? copies["team"];
6877
6876
  const targetLabel = found === null ? target : target === "market" && found.market !== void 0 ? `${found.name}@${found.version} → market (${found.market.url})` : `${found.name}@${found.version} → ${target}${found.registry === void 0 ? "" : ` (${found.registry})`}`;
6878
- const question = refresh ? pair(`只刷新${label}在市集里的元数据(标题 / 作者 / 说明),不升版本、不重发产物,允许吗?`, `Only refresh ${labelEn}'s market metadata (title, author, description); no version bump, no artifacts. Allow?`) : pair(copy.zh, copy.en);
6877
+ const question = refresh ? pair(`只刷新${label}在市集里的元数据(标题 / 作者 / 说明 / 标签),不升版本、不重发产物,允许吗?`, `Only refresh ${labelEn}'s market metadata (title, author, description, labels); no version bump, no artifacts. Allow?`) : pair(copy.zh, copy.en);
6879
6878
  return askOf(`${DIY_PUBLISH_TOOL} ${targetLabel}${refresh ? "(元数据)" : ""}`, question, question);
6880
6879
  }
6881
6880
  function approvalVerdict(call, marketSource) {
@@ -9491,7 +9490,7 @@ var PUBLISH_TIMEOUT_MS = 18e5;
9491
9490
  function registerPublishTool(ctx, tools, deps) {
9492
9491
  const publishTool = {
9493
9492
  name: DIY_PUBLISH_TOOL,
9494
- description: "用户说“发布”后才用:把这一格发到 target 指定的出口(不填按环境默认)。这一版还没有更新日志时把 changelogNote 一起带上 —— 发布时写进 CHANGELOG.md,随包发。",
9493
+ description: "用户说“发布”后才用:把这一格发到 target 指定的出口(不填按环境默认)。这一版还没有更新日志时把 changelogNote 一起带上 —— 发布时写进 CHANGELOG.md,随包发。这个模块还没有市集标签时把 labels 带上(1–2 个短词)。",
9495
9494
  parameters: {
9496
9495
  type: "object",
9497
9496
  properties: {
@@ -9508,6 +9507,11 @@ function registerPublishTool(ctx, tools, deps) {
9508
9507
  enum: [...CHANGELOG_KINDS],
9509
9508
  description: "分类,不填按 changed。"
9510
9509
  },
9510
+ labels: {
9511
+ type: "array",
9512
+ items: { type: "string" },
9513
+ description: "市集条目的标签,1–2 个短词(说它干什么,比如「发布编排」「构建状态」)。模块还没有标签时必填;已有可省,传了会替换掉原来的。"
9514
+ },
9511
9515
  target: {
9512
9516
  type: "string",
9513
9517
  enum: [
@@ -9546,7 +9550,7 @@ function registerPublishTool(ctx, tools, deps) {
9546
9550
  },
9547
9551
  refresh: {
9548
9552
  type: "boolean",
9549
- description: "只刷市集元数据(标题/作者/说明),不升版本、不重发产物。"
9553
+ description: "只刷市集元数据(标题/作者/说明/标签),不升版本、不重发产物。"
9550
9554
  }
9551
9555
  },
9552
9556
  required: ["unit"],
@@ -9566,6 +9570,7 @@ function registerPublishTool(ctx, tools, deps) {
9566
9570
  const license = asText(asRecord$1(raw)["license"]);
9567
9571
  const changelogNote = asText(asRecord$1(raw)["changelogNote"]);
9568
9572
  const changelogType = asText(asRecord$1(raw)["changelogType"]);
9573
+ const labels = labelsOf(asRecord$1(raw)["labels"]);
9569
9574
  let author = asText(asRecord$1(raw)["author"]);
9570
9575
  const verify = asRecord$1(raw)["verify"] === true;
9571
9576
  const resume = asRecord$1(raw)["resume"] === true;
@@ -9587,6 +9592,7 @@ function registerPublishTool(ctx, tools, deps) {
9587
9592
  if (author !== "") argv.push("--author", author);
9588
9593
  if (changelogNote !== "") argv.push("--changelog-note", changelogNote);
9589
9594
  if (changelogType !== "") argv.push("--changelog-type", changelogType);
9595
+ for (const label of labels) argv.push("--label", label);
9590
9596
  if (asRecord$1(raw)["refresh"] === true) argv.push("--refresh");
9591
9597
  const result = await runShell(shell, argv.map((one) => quoteShellArg(one)).join(" "), {
9592
9598
  workdir: root,
@@ -9646,15 +9652,23 @@ function registerPublishTool(ctx, tools, deps) {
9646
9652
  "包内容已经从源上核过(dist/host.js / client.js / cordis.patch.yml 都在)。"
9647
9653
  ].join("\n");
9648
9654
  const changelog = asRecord$1(payload["changelog"]);
9649
- const changelogLine = asText(changelog["action"]) === "written" ? `更新日志:已写进 ${CHANGELOG_FILE} 的 ${asText(changelog["version"])}` : asText(changelog["action"]) === "kept" ? `更新日志:这一版已有(${asText(changelog["version"])}),没动` : "";
9655
+ const tail = [asText(changelog["action"]) === "written" ? `更新日志:已写进 ${CHANGELOG_FILE} 的 ${asText(changelog["version"])}` : asText(changelog["action"]) === "kept" ? `更新日志:这一版已有(${asText(changelog["version"])}),没动` : "", labels.length === 0 || targetOfPayload !== "market" && payload["refresh"] !== true ? "" : `标签:${labels.join(" · ")}`].filter((one) => one !== "").join("\n");
9650
9656
  return plainJson({
9651
9657
  ...payload,
9652
- text: changelogLine === "" ? text : `${text}\n${changelogLine}`
9658
+ text: tail === "" ? text : `${text}\n${tail}`
9653
9659
  });
9654
9660
  }
9655
9661
  };
9656
9662
  return tools.register(publishTool);
9657
9663
  }
9664
+ function labelsOf(value) {
9665
+ if (!Array.isArray(value) || value.length === 0) return [];
9666
+ const labels = value.flatMap((one) => typeof one === "string" ? [one.trim()] : []);
9667
+ if (labels.length !== value.length || labels.some((one) => one === "" || /[\r\n]/u.test(one))) throw new Error("标签是 1–2 个短词:每个都得是一行非空文字");
9668
+ const unique = [...new Set(labels)];
9669
+ if (unique.length > 2) throw new Error(`标签最多两个(收到 ${String(unique.length)} 个)—— 挑最能说明这个模块干什么的`);
9670
+ return unique;
9671
+ }
9658
9672
  //#endregion
9659
9673
  //#region src/shared/api/host/diy-recon.ts
9660
9674
  var SITE_LIMIT = 6;
@@ -10096,7 +10110,11 @@ function renderStatus(root, lines, options = {}) {
10096
10110
  }
10097
10111
  function publishStatusOf(preview) {
10098
10112
  if (preview === null) return "";
10099
- return [preview.market === void 0 ? preview.registry === void 0 ? "发布出口:安装包(这个环境没配可写市场索引源,模块也没声明 publishConfig.registry)" : `发布出口:团队源 ${preview.registry}(package.json 的 publishConfig.registry)` : `发布出口:市场索引 ${preview.market.url}${preview.market.ref === void 0 ? "" : `(${preview.market.ref})`}—— 不填 target 时默认发这里;这一版会发 ${preview.market.nextVersion ?? preview.version}`, preview.changelog === void 0 ? void 0 : preview.changelog.missing ? `发布前置:CHANGELOG 还差 ${preview.changelog.version} 这一版 —— 发布时带 changelogNote(会先建文件)` : `发布前置:CHANGELOG 里已有 ${preview.changelog.version}`].filter((one) => one !== void 0).join("\n");
10113
+ return [
10114
+ preview.market === void 0 ? preview.registry === void 0 ? "发布出口:安装包(这个环境没配可写市场索引源,模块也没声明 publishConfig.registry)" : `发布出口:团队源 ${preview.registry}(package.json 的 publishConfig.registry)` : `发布出口:市场索引 ${preview.market.url}${preview.market.ref === void 0 ? "" : `(${preview.market.ref})`}—— 不填 target 时默认发这里;这一版会发 ${preview.market.nextVersion ?? preview.version}`,
10115
+ preview.market === void 0 ? void 0 : preview.labels === void 0 || preview.labels.length === 0 ? "标签:还没有 —— 发布到市场时带上 1–2 个(labels)" : `标签:${preview.labels.join(" · ")}`,
10116
+ preview.changelog === void 0 ? void 0 : preview.changelog.missing ? `发布前置:CHANGELOG 还差 ${preview.changelog.version} 这一版 —— 发布时带 changelogNote(会先建文件)` : `发布前置:CHANGELOG 里已有 ${preview.changelog.version}`
10117
+ ].filter((one) => one !== void 0).join("\n");
10100
10118
  }
10101
10119
  function renderList(root, modules, shape = "bare") {
10102
10120
  if (modules.length === 0) return [
@@ -10451,7 +10469,7 @@ function marketOf(dir, name, version) {
10451
10469
  url: source.url,
10452
10470
  ...source.ref === void 0 ? {} : { ref: source.ref },
10453
10471
  indexPath: source.path ?? "market",
10454
- artifactPath: marketArtifactPathFor(name, nextVersion ?? version),
10472
+ artifactPath: marketArtifactRoot(name),
10455
10473
  files: ARTIFACTS.filter((one) => existsSync(join(dir, one))),
10456
10474
  ...nextVersion === void 0 ? {} : { nextVersion }
10457
10475
  },
@@ -10541,6 +10559,9 @@ function publishPreviewOf(root, unit, options = {}) {
10541
10559
  const publishConfig = record["publishConfig"];
10542
10560
  const registry = typeof publishConfig === "object" && publishConfig !== null ? publishConfig["registry"] : void 0;
10543
10561
  const market = marketOf(found.dir, name, version);
10562
+ const marketEntry = market === void 0 ? void 0 : publishedEntryOf(market.index, name);
10563
+ const declaredLabels = labelsOfManifest(record);
10564
+ const labels = declaredLabels.length > 0 || marketEntry === void 0 ? declaredLabels : marketEntryLabels(marketEntry);
10544
10565
  const target = targetVersionOf(version, (options.version ?? "").trim(), market?.market);
10545
10566
  const askedAuthor = (options.author ?? "").trim();
10546
10567
  const author = askedAuthor === "" ? authorOf(record) : askedAuthor;
@@ -10554,12 +10575,21 @@ function publishPreviewOf(root, unit, options = {}) {
10554
10575
  name,
10555
10576
  version,
10556
10577
  ...author === "" ? {} : { author },
10578
+ ...labels.length === 0 ? {} : { labels },
10557
10579
  ...typeof registry === "string" && registry !== "" ? { registry } : {},
10558
10580
  ...market === void 0 ? {} : { market: market.market },
10559
10581
  ...claim === void 0 ? {} : { claim },
10560
10582
  changelog: changelogOf(found.dir, target, (options.changelog ?? "").trim(), kindOf(options.changelogType))
10561
10583
  };
10562
10584
  }
10585
+ function labelsOfManifest(record) {
10586
+ const dsh = record["dsh"];
10587
+ const workbench = dsh !== null && typeof dsh === "object" ? dsh["workbench"] : void 0;
10588
+ const market = workbench !== null && typeof workbench === "object" ? workbench["market"] : void 0;
10589
+ const labels = market !== null && typeof market === "object" ? market["labels"] : void 0;
10590
+ if (!Array.isArray(labels)) return [];
10591
+ return [...new Set(labels.flatMap((one) => typeof one === "string" && one.trim() !== "" ? [one.trim()] : []))];
10592
+ }
10563
10593
  function authorOf(manifest) {
10564
10594
  const author = manifest["author"];
10565
10595
  if (typeof author === "string") return author.trim();
@@ -17486,6 +17516,7 @@ function notifyLongTaskStop(agents, unit, change) {
17486
17516
  //#endregion
17487
17517
  //#region src/app/host.ts
17488
17518
  var name = "dsh-workbench";
17519
+ var LIB_OPENCLI_TIMEOUT_MS = 18e5;
17489
17520
  var inject = ["webServer"];
17490
17521
  async function defaultAdapterSet(ctx) {
17491
17522
  return (await import("@dsh-workbench/adapters-default")).createAdapterSet(ctx);
@@ -17506,6 +17537,7 @@ async function apply(ctx, config) {
17506
17537
  else if (loaded.failure !== "not-configured") ctx.logger?.warn?.(`[dsh-workbench] 适配器集合没生效(${loaded.failure}):${loaded.detail};先用默认集合`);
17507
17538
  ctx.provide(WORKBENCH_ADAPTERS, adapters);
17508
17539
  const opencli = adapters.runtime.opencliCommand(ctx);
17540
+ const libRunners = adapters.libs === void 0 ? void 0 : withLibRunners(adapters.libs, { opencli: opencliRunnerOf((request) => adapters.data.read(request), { timeoutMs: LIB_OPENCLI_TIMEOUT_MS }) }, ctx.logger);
17509
17541
  const shell = ctx.get("shell");
17510
17542
  const routes = createHostRoutes({
17511
17543
  ctx,
@@ -17682,7 +17714,7 @@ async function apply(ctx, config) {
17682
17714
  installable: () => installableUnitsOf(units),
17683
17715
  store,
17684
17716
  data: adapters.data,
17685
- libs: adapters.libs,
17717
+ libs: libRunners,
17686
17718
  git: adapters.git,
17687
17719
  commands: adapters.commands,
17688
17720
  probe: (unit, options) => probeOne(unit, options?.force ?? false),
@@ -0,0 +1,6 @@
1
+ interface ApprovalCopy {
2
+ readonly zh: string;
3
+ readonly en: string;
4
+ }
5
+ export declare function copiesOf(label: string, labelEn: string): Record<string, ApprovalCopy>;
6
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dsh-workbench/core",
3
- "version": "1.1.6",
3
+ "version": "1.1.8",
4
4
  "description": "个人工作台:Agent 工作台(左栏 + 常驻对话 + 自研右侧数据面板)。",
5
5
  "type": "module",
6
6
  "icon": "./icon.svg",
@@ -100,8 +100,8 @@
100
100
  "proper-lockfile": "^4.1.2",
101
101
  "which": "^7.0.0",
102
102
  "write-file-atomic": "^8.0.0",
103
- "@dsh-workbench/shared": "1.1.6",
104
- "@dsh-workbench/adapters-default": "1.1.6"
103
+ "@dsh-workbench/shared": "1.1.8",
104
+ "@dsh-workbench/adapters-default": "1.1.8"
105
105
  },
106
106
  "license": "MIT",
107
107
  "repository": {
@@ -45,5 +45,6 @@
45
45
  ## 4 发布
46
46
 
47
47
  只在用户明确说「帮我发布」后调。这一版还没有更新日志(`_status` 会说)时,把改了什么写进 `changelogNote`(一行一条,`changelogType` 选分类,缺省 changed):审批屏会展示将写进 `CHANGELOG.md` 的那一段,用户点了头才落盘,文件不在会先建。这一版已有内容就不用传,带了也不追加。
48
+ 这个模块还没有市集标签(`_status` 会说)时,自己给它想 1–2 个短词放进 `labels`(说它干什么,比如「发布编排」「构建状态」);已有标签就不用传,传了会替换原来的。
48
49
  出口、署名、标题、安装命令由工具与审批屏处理,不用问、不用补;没写作者时审批屏显示推断的署名(市集里上次的 / 同工坊的 / 本机 git 身份),用户觉得不对就拒绝后再说,他点名了才传 `author=…`。
49
50
  需要用户接管时返回 `needsUser: { step, text, command? }`:把 `text` 说给用户,等「好了」再跑;不向用户要 token。
@@ -47,6 +47,7 @@ description: 在工作台里把当前面板调明白,或者给它造一块新
47
47
  审批项标注「要你真用一次」,不打勾。结论只报:已装、在面板哪一格。
48
48
  8. **发布** —— 只在用户说「帮我发布」之后:`workbench_diy_publish`(`unit=…`);这一版还没有更新日志就带上 `changelogNote`(一行一条),
49
49
  发布时一起写进 `CHANGELOG.md` 并随包发,审批屏会展示将写入的那一段。
50
+ 还没有市集标签就自己给 1–2 个短词放进 `labels`(说它干什么,比如「发布编排」「构建状态」);已有标签就不用传。
50
51
  不手改 `package.json`、不补标题/署名、不问出口:工具与审批屏已经处理;他明确点名安装包 / 公开 / git 才传 target。
51
52
  他说要换作者才传 `author="姓名 <邮箱>"`,别自己编一个;没写作者时审批屏显示推断的署名,他拒绝后再说。
52
53
  市场里一个包名归第一次发布的人:换署名发同名会被拒;真是接手,让维护者先改那一条的 `owner`。
@@ -107,7 +107,13 @@
107
107
  { "kind": "local", "env": "ACME_PLUGIN_PATH" }
108
108
  ]
109
109
  },
110
- { "kind": "lib", "name": "opencli-workflow", "purpose": "发布编排" },
110
+ {
111
+ "kind": "lib",
112
+ "name": "opencli-workflow",
113
+ "version": "^1.1.25",
114
+ "runs": ["opencli"],
115
+ "purpose": "发布编排"
116
+ },
111
117
  {
112
118
  "kind": "bin",
113
119
  "name": "acme",
@@ -122,6 +128,10 @@
122
128
  - `sources` 按顺序试(本地 → 私有 → 公共)。没写 `sources` 就是「我自己装,你只帮我判」——外壳只探不代装。
123
129
  - `bin` 想让人一键装,就写 `install.line`(一条能直接粘进终端的命令,`platforms` 可限定平台);
124
130
  不写就只显示「缺这条命令」,按钮都不会有。`docs` 是给人和 agent 看的补充链接。
131
+ - `lib` 自己起运行时的命令(比如发布编排库自己 `execFile('opencli')`)就写 `runs: ["opencli"]`:
132
+ 外壳把它手上那份「跑 opencli」的执行器注入进去(库侧约定暴露 `setOpencliRunner`),
133
+ 于是编排与面板用同一份 opencli(同一套插件、同一份登录态)。不写 `runs` 就按库自己的 PATH 找。
134
+ 库版本太旧、没有 `setOpencliRunner` 时外壳只记一条 warn,照旧按 PATH 跑;用 `version` 卡住那一版即可。
125
135
  - `extension` 的 `sources[].kind` 只有 `npm` / `git` / `local`;`lib` 只认 `npm`。
126
136
  未知 `kind` 或 `source.kind` 判红;need 里未知字段只警告,`x-` 前缀忽略。
127
137
  - 未装好文案由模块写:`libInstallCommand({ need, source })`(`@dsh-workbench/shared/host`)拼好源与缓存目录,
@@ -74,6 +74,8 @@ DIY 族仅在选了 DIY 模式的会话出现(按模式,不按工作区)
74
74
  用户真是接手的人,让他先找索引维护者改那一条的 `owner`,别自己改成对方的署名去绕。
75
75
  一个模块 id(`dsh.workbench.unit`)在同一个市场里只能有一个条目:换包名、沿用旧 unit 会被拒 ——
76
76
  换包名时把 unit 也换掉,别为了保留 id 去改别人的条目。
77
+ 这个模块还没有标签时(`workbench_diy_status` 会说),自己给它想 1–2 个短词放进 `labels`(说它干什么,比如「发布编排」「构建状态」),
78
+ 别再问用户;已经有标签就不用传,传了会替换掉原来的(仍是最多两个)。发布时会把模块里的标签并进索引(只碰标签)。
77
79
  2. 工具回 `needsUser` 时照 `text` 转述,不在对话里要 token / OTP;`otp` 交接后 `verify=true` 只核不发。
78
- 3. 只改市集元数据(标题 / 作者 / 说明)不升版本:`refresh=true`(换作者时同时传 `author`,仍要过 `owner` 检查)。
79
- 发布新版本不会改这些元数据(工具沿用远端条目当前的值),别指望发一版顺手把标题改掉。
80
+ 3. 只改市集元数据(标题 / 作者 / 说明 / 标签)不升版本:`refresh=true`(换作者时同时传 `author`,仍要过 `owner` 检查)。
81
+ 发布新版本不会改这些元数据(工具沿用远端条目当前的值),别指望发一版顺手把标题改掉;标签是例外 —— 发布总会照模块里的标签并一次。