@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 +29 -2
- package/dist/client/client.body.js +29 -2
- package/dist/client/index.js +29 -2
- package/dist/host/index.js +333 -301
- package/dist/types/modules/panels/model/approval-questions.d.ts +6 -0
- package/package.json +3 -3
- package/skills/workbench-module-diy/FAMILY.md +1 -0
- package/skills/workbench-module-diy/SKILL.md +1 -0
- package/skills/workbench-module-diy/TOOLS.md +11 -1
- package/skills/workbench-module-diy/WIRING.md +4 -2
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
|
|
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
|
|
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
|
|
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
|
|
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({
|
package/dist/client/index.js
CHANGED
|
@@ -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
|
|
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
|
|
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({
|
package/dist/host/index.js
CHANGED
|
@@ -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$
|
|
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$
|
|
1151
|
-
const message = textOf$
|
|
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$
|
|
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$
|
|
1185
|
-
const route = textOf$
|
|
1186
|
-
const phase = textOf$
|
|
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$
|
|
1222
|
-
const unit = textOf$
|
|
1223
|
-
const reason = textOf$
|
|
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$
|
|
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$
|
|
2045
|
-
const pkg = textOf$
|
|
2046
|
-
const installedAt = textOf$
|
|
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$
|
|
2049
|
-
const registry = textOf$
|
|
2050
|
-
const releasedAt = textOf$
|
|
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
|
|
5269
|
-
|
|
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
|
|
5299
|
-
|
|
5300
|
-
|
|
5301
|
-
|
|
5302
|
-
|
|
5303
|
-
|
|
5304
|
-
|
|
5305
|
-
|
|
5306
|
-
|
|
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:
|
|
5327
|
-
|
|
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
|
-
|
|
5461
|
+
const parsed = entryOf$1(raw, "entry");
|
|
5462
|
+
if ("kind" in parsed) return {
|
|
5335
5463
|
ok: false,
|
|
5336
|
-
problems: [
|
|
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
|
-
|
|
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
|
-
"
|
|
5476
|
+
"一个包一个文件:`market/<包名>.json`,里面是这一个包的元数据与所有版本;",
|
|
5370
5477
|
"",
|
|
5371
|
-
"`
|
|
5478
|
+
"产物在 `artifacts/<包名>/`(只放最新一版,老版本按条目里的 commit 取历史)。",
|
|
5479
|
+
"",
|
|
5480
|
+
"发布时只改自己包的文件;包与包之间不共享文件。"
|
|
5372
5481
|
];
|
|
5373
5482
|
var MARKET_INDEX_README_LINES = [
|
|
5374
5483
|
"# 模块市场索引",
|
|
5375
5484
|
"",
|
|
5376
|
-
"这个仓库给 DeepSeek Harness
|
|
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
|
-
"
|
|
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
|
|
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
|
-
|
|
5428
|
-
|
|
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
|
|
5443
|
-
|
|
5444
|
-
|
|
5445
|
-
|
|
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
|
-
|
|
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
|
-
|
|
5502
|
-
|
|
5503
|
-
|
|
5504
|
-
|
|
5505
|
-
|
|
5506
|
-
return
|
|
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
|
|
6851
|
-
|
|
6852
|
-
|
|
6853
|
-
|
|
6854
|
-
|
|
6855
|
-
|
|
6856
|
-
|
|
6857
|
-
|
|
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}在市集里的元数据(标题 / 作者 /
|
|
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
|
|
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:
|
|
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 [
|
|
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:
|
|
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:
|
|
17717
|
+
libs: libRunners,
|
|
17686
17718
|
git: adapters.git,
|
|
17687
17719
|
commands: adapters.commands,
|
|
17688
17720
|
probe: (unit, options) => probeOne(unit, options?.force ?? false),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dsh-workbench/core",
|
|
3
|
-
"version": "1.1.
|
|
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.
|
|
104
|
-
"@dsh-workbench/adapters-default": "1.1.
|
|
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
|
-
{
|
|
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. 只改市集元数据(标题 / 作者 /
|
|
79
|
-
|
|
80
|
+
3. 只改市集元数据(标题 / 作者 / 说明 / 标签)不升版本:`refresh=true`(换作者时同时传 `author`,仍要过 `owner` 检查)。
|
|
81
|
+
发布新版本不会改这些元数据(工具沿用远端条目当前的值),别指望发一版顺手把标题改掉;标签是例外 —— 发布总会照模块里的标签并一次。
|