@dsh-workbench/core 1.1.1 → 1.1.3
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/README.md +14 -5
- package/bin/dsh-workbench +7 -1
- package/client.js +1118 -429
- package/dist/client/client.body.js +1118 -429
- package/dist/client/index.js +970 -281
- package/dist/host/index.js +788 -383
- package/dist/types/app/layouts/approval-detail.d.ts +2 -1
- package/dist/types/app/layouts/market/discover-confirm.d.ts +1 -1
- package/dist/types/app/layouts/market/discover-detail.d.ts +1 -0
- package/dist/types/app/layouts/market/discover-installing.d.ts +8 -0
- package/dist/types/app/layouts/market/discover-rows.d.ts +4 -2
- package/dist/types/app/layouts/market/discover-source-item.d.ts +26 -0
- package/dist/types/app/layouts/market/discover-sources-dialog.d.ts +4 -0
- package/dist/types/app/layouts/market/discover-states.d.ts +6 -0
- package/dist/types/app/layouts/market/discover-transport.d.ts +7 -0
- package/dist/types/app/layouts/market/discover-versions.d.ts +2 -1
- package/dist/types/app/layouts/market/discover-view.d.ts +2 -0
- package/dist/types/app/layouts/market/use-discover.d.ts +11 -1
- package/dist/types/app/layouts/market/use-git-transport.d.ts +19 -0
- package/dist/types/app/layouts/market/use-module-versions.d.ts +1 -0
- package/dist/types/kernel/contract/market-index.d.ts +2 -2
- package/dist/types/modules/panels/client.d.ts +1 -1
- package/dist/types/modules/panels/model/approval.d.ts +4 -2
- package/dist/types/modules/panels/model/diy-publish.d.ts +10 -0
- package/dist/types/modules/panels/model/diy-tools.d.ts +0 -1
- package/dist/types/modules/panels/model/market-sources-act.d.ts +2 -1
- package/dist/types/modules/panels/model/market-sources-tool.d.ts +3 -0
- package/dist/types/modules/panels/model/market-sources-tool.test.d.ts +1 -0
- package/dist/types/modules/panels/model/market-tools.d.ts +8 -1
- package/dist/types/modules/panels/model/publish-claim.d.ts +2 -0
- package/dist/types/modules/panels/unit.d.ts +7 -5
- package/dist/types/shared/api/host/diy-publish-preview.d.ts +2 -0
- package/dist/types/shared/api/host/git-exec.d.ts +2 -0
- package/dist/types/shared/api/host/git-probe.d.ts +6 -0
- package/dist/types/shared/api/host/git-routes.d.ts +3 -0
- package/dist/types/shared/api/host/market-source-init.d.ts +1 -0
- package/dist/types/shared/api/host/market-sources-store.d.ts +2 -0
- package/dist/types/shared/hooks/market-queries.d.ts +3 -2
- package/package.json +3 -3
- package/skills/workbench-module-diy/FAMILY.md +3 -4
- package/skills/workbench-module-diy/SKILL.md +4 -1
- package/skills/workbench-module-diy/WIRING.md +9 -2
- package/dist/types/modules/panels/model/diy-changelog.d.ts +0 -2
- package/dist/types/shared/api/host/diy-changelog.d.ts +0 -13
package/dist/host/index.js
CHANGED
|
@@ -4545,6 +4545,7 @@ function checkVersionRange(contract, version) {
|
|
|
4545
4545
|
}
|
|
4546
4546
|
var MARKET_DISCOVER_ROUTE = "panels/market-discover";
|
|
4547
4547
|
var MARKET_DOC_ROUTE = "panels/market-doc";
|
|
4548
|
+
var MARKET_GIT_PROBE_ROUTE = "panels/git-probe";
|
|
4548
4549
|
var MARKET_PUBLISH_PREVIEW_ROUTE = "panels/market-publish-preview";
|
|
4549
4550
|
var MARKET_SOURCES_RESOURCE = "market-sources";
|
|
4550
4551
|
var MARKET_SOURCES_ROUTE = "panels/market-sources";
|
|
@@ -4577,7 +4578,10 @@ var MARKET_INDEX_README_LINES = [
|
|
|
4577
4578
|
"dsh-wb-module release --index <本仓库地址> --index-policy artifacts-in-repo",
|
|
4578
4579
|
"```",
|
|
4579
4580
|
"",
|
|
4580
|
-
"产物会提交到 `packages
|
|
4581
|
+
"产物会提交到 `packages/<包名>/`(带 scope 时是 `packages/@scope/名字/`),并更新 `market.json`。",
|
|
4582
|
+
"",
|
|
4583
|
+
"一个包名归第一次发布的人(`market.json` 里的 `owner`)。换一个署名发同名会被拒;要换人,先把这一条的 `owner` 改成新的人。",
|
|
4584
|
+
"同一个市场里,一个模块 id(`metadata.unit`)只能被一个条目使用;另一个包名想用同一个 id / 产物目录也会被拒。",
|
|
4581
4585
|
"",
|
|
4582
4586
|
"## 使用这个索引",
|
|
4583
4587
|
"",
|
|
@@ -4683,15 +4687,25 @@ function iconProblem(icon) {
|
|
|
4683
4687
|
if (/^https?:\/\//i.test(icon)) return void 0;
|
|
4684
4688
|
return problem("icon", "icon 只能是 base64 data URL 或 http(s) URL");
|
|
4685
4689
|
}
|
|
4690
|
+
var MAX_OWNER_CHARS = 200;
|
|
4691
|
+
var UNIT_ID = /^[a-z][a-z0-9-]*$/;
|
|
4692
|
+
function ownerProblem(owner) {
|
|
4693
|
+
if (/[\r\n]/u.test(owner)) return problem("owner", "owner 只能是一行署名");
|
|
4694
|
+
if (owner.length > MAX_OWNER_CHARS) return problem("owner", "owner 超过 200 字");
|
|
4695
|
+
}
|
|
4686
4696
|
function metadataOf(raw) {
|
|
4687
4697
|
const record = asRecord$3(raw);
|
|
4688
4698
|
if (record === void 0) return void 0;
|
|
4699
|
+
const workbench = record["workbench"] === true;
|
|
4700
|
+
const unit = asText$3(record["unit"]);
|
|
4689
4701
|
const category = asText$3(record["category"]);
|
|
4690
4702
|
const labels = asTextArray(record["labels"]);
|
|
4691
4703
|
const keywords = asTextArray(record["keywords"]);
|
|
4692
4704
|
const sortKeysRecord = asRecord$3(record["sortKeys"]);
|
|
4693
4705
|
const sortKeys = sortKeysRecord === void 0 ? void 0 : Object.fromEntries(Object.entries(sortKeysRecord).flatMap(([key, value]) => typeof value === "string" || typeof value === "number" ? [[key, value]] : []));
|
|
4694
4706
|
return {
|
|
4707
|
+
...workbench ? { workbench: true } : {},
|
|
4708
|
+
...unit === "" ? {} : { unit },
|
|
4695
4709
|
...category === "" ? {} : { category },
|
|
4696
4710
|
...labels.length === 0 ? {} : { labels },
|
|
4697
4711
|
...keywords.length === 0 ? {} : { keywords },
|
|
@@ -4713,14 +4727,21 @@ function entryOf$1(raw, at) {
|
|
|
4713
4727
|
const title = asLocalized(record["title"]);
|
|
4714
4728
|
const description = asLocalized(record["description"]);
|
|
4715
4729
|
const author = asText$3(record["author"]);
|
|
4730
|
+
const owner = asText$3(record["owner"]);
|
|
4731
|
+
if (owner !== "") {
|
|
4732
|
+
const badOwner = ownerProblem(owner);
|
|
4733
|
+
if (badOwner !== void 0) return badOwner;
|
|
4734
|
+
}
|
|
4716
4735
|
const homepage = asText$3(record["homepage"]);
|
|
4717
4736
|
const metadata = metadataOf(record["metadata"]);
|
|
4737
|
+
if (metadata?.unit !== void 0 && !UNIT_ID.test(metadata.unit)) return problem("unit", `metadata.unit 只能是小写字母开头的 a-z0-9-(现在是 ${JSON.stringify(metadata.unit)})`, at);
|
|
4718
4738
|
return {
|
|
4719
4739
|
name,
|
|
4720
4740
|
versions,
|
|
4721
4741
|
...title === void 0 ? {} : { title },
|
|
4722
4742
|
...description === void 0 ? {} : { description },
|
|
4723
4743
|
...author === "" ? {} : { author },
|
|
4744
|
+
...owner === "" ? {} : { owner },
|
|
4724
4745
|
...homepage === "" ? {} : { homepage },
|
|
4725
4746
|
...icon === "" ? {} : { icon },
|
|
4726
4747
|
...metadata === void 0 ? {} : { metadata }
|
|
@@ -4907,6 +4928,84 @@ function gitUrlOk(url) {
|
|
|
4907
4928
|
return true;
|
|
4908
4929
|
}
|
|
4909
4930
|
//#endregion
|
|
4931
|
+
//#region ../shared/dist/host/market-index-claim.js
|
|
4932
|
+
function foldedName(name) {
|
|
4933
|
+
return name.replace(/\s+/gu, " ").trim().toLowerCase();
|
|
4934
|
+
}
|
|
4935
|
+
function publisherIdentityOf(text) {
|
|
4936
|
+
const raw = (text ?? "").trim();
|
|
4937
|
+
if (raw === "") return void 0;
|
|
4938
|
+
const match = /^(.*?)\s*<([^<>]*)>\s*$/u.exec(raw);
|
|
4939
|
+
const name = (match === null ? raw : match[1]).trim();
|
|
4940
|
+
const email = match === null ? "" : match[2].trim().toLowerCase();
|
|
4941
|
+
if (name === "") return void 0;
|
|
4942
|
+
return email === "" ? { name } : {
|
|
4943
|
+
name,
|
|
4944
|
+
email
|
|
4945
|
+
};
|
|
4946
|
+
}
|
|
4947
|
+
function samePublisher(left, right) {
|
|
4948
|
+
const a = publisherIdentityOf(left);
|
|
4949
|
+
const b = publisherIdentityOf(right);
|
|
4950
|
+
if (a === void 0 || b === void 0) return false;
|
|
4951
|
+
if (a.email !== void 0 && b.email !== void 0) return a.email === b.email;
|
|
4952
|
+
return foldedName(a.name) === foldedName(b.name);
|
|
4953
|
+
}
|
|
4954
|
+
function entryOwnerOf(entry) {
|
|
4955
|
+
const owner = (entry.owner ?? "").trim();
|
|
4956
|
+
if (owner !== "") return owner;
|
|
4957
|
+
const author = (entry.author ?? "").trim();
|
|
4958
|
+
return author === "" ? void 0 : author;
|
|
4959
|
+
}
|
|
4960
|
+
function claimOfEntry(entry, publisher) {
|
|
4961
|
+
if (entry === void 0) return { state: "new" };
|
|
4962
|
+
const owner = entryOwnerOf(entry);
|
|
4963
|
+
if (owner === void 0) return { state: "unowned" };
|
|
4964
|
+
if (publisher === void 0 || publisher.trim() === "") return { state: "unknown" };
|
|
4965
|
+
return samePublisher(owner, publisher) ? {
|
|
4966
|
+
state: "owned",
|
|
4967
|
+
owner
|
|
4968
|
+
} : {
|
|
4969
|
+
state: "conflict",
|
|
4970
|
+
owner
|
|
4971
|
+
};
|
|
4972
|
+
}
|
|
4973
|
+
function marketArtifactPath(name) {
|
|
4974
|
+
return `packages/${name}`;
|
|
4975
|
+
}
|
|
4976
|
+
function entryUnitOf(entry) {
|
|
4977
|
+
const unit = entry.metadata?.unit?.trim();
|
|
4978
|
+
if (unit !== void 0 && unit !== "") return unit;
|
|
4979
|
+
for (const version of entry.versions) {
|
|
4980
|
+
if (version.source.type !== "git") continue;
|
|
4981
|
+
const legacy = /^packages\/([^/]+)$/u.exec(version.source.path ?? "")?.[1];
|
|
4982
|
+
if (legacy !== void 0) return legacy;
|
|
4983
|
+
}
|
|
4984
|
+
}
|
|
4985
|
+
function claimOf(index, input) {
|
|
4986
|
+
const base = claimOfEntry(index.plugins.find((one) => one.name === input.name), input.publisher);
|
|
4987
|
+
if (base.state === "conflict" || base.state === "unknown") return base;
|
|
4988
|
+
const unit = (input.unit ?? "").trim();
|
|
4989
|
+
if (unit !== "") for (const other of index.plugins) {
|
|
4990
|
+
if (other.name === input.name) continue;
|
|
4991
|
+
if (entryUnitOf(other) !== unit) continue;
|
|
4992
|
+
return {
|
|
4993
|
+
state: "unit-taken",
|
|
4994
|
+
entry: other.name
|
|
4995
|
+
};
|
|
4996
|
+
}
|
|
4997
|
+
const path = (input.artifactPath ?? "").trim();
|
|
4998
|
+
if (path !== "") for (const other of index.plugins) {
|
|
4999
|
+
if (other.name === input.name) continue;
|
|
5000
|
+
if (!other.versions.some((one) => one.source.type === "git" && (one.source.path ?? "") === path)) continue;
|
|
5001
|
+
return {
|
|
5002
|
+
state: "path-taken",
|
|
5003
|
+
entry: other.name
|
|
5004
|
+
};
|
|
5005
|
+
}
|
|
5006
|
+
return base;
|
|
5007
|
+
}
|
|
5008
|
+
//#endregion
|
|
4910
5009
|
//#region ../shared/dist/host/changelog.js
|
|
4911
5010
|
var CHANGELOG_FILE = "CHANGELOG.md";
|
|
4912
5011
|
var CHANGELOG_KINDS = [
|
|
@@ -5064,6 +5163,25 @@ function appendChangelogEntry(text, options) {
|
|
|
5064
5163
|
out.splice(at, 0, ...bullets);
|
|
5065
5164
|
return `${normalizeWhitespace(out)}\n`;
|
|
5066
5165
|
}
|
|
5166
|
+
function planChangelog(text, options) {
|
|
5167
|
+
const source = normalizeChangelogText(text);
|
|
5168
|
+
const version = changelogVersion(options.version);
|
|
5169
|
+
const section = changelogSectionOf(source, version);
|
|
5170
|
+
if (section !== void 0 && changelogHasEntry(source, version)) return {
|
|
5171
|
+
action: "kept",
|
|
5172
|
+
version,
|
|
5173
|
+
text: source,
|
|
5174
|
+
section
|
|
5175
|
+
};
|
|
5176
|
+
if (bulletsOf(options.note).length === 0) return void 0;
|
|
5177
|
+
const next = appendChangelogEntry(source, options);
|
|
5178
|
+
return {
|
|
5179
|
+
action: "written",
|
|
5180
|
+
version,
|
|
5181
|
+
text: next,
|
|
5182
|
+
section: changelogSectionOf(next, version) ?? ""
|
|
5183
|
+
};
|
|
5184
|
+
}
|
|
5067
5185
|
function normalizeWhitespace(rows) {
|
|
5068
5186
|
const out = [];
|
|
5069
5187
|
for (const row of rows) {
|
|
@@ -5416,6 +5534,80 @@ function bundleInspectHandler(ctx) {
|
|
|
5416
5534
|
};
|
|
5417
5535
|
}
|
|
5418
5536
|
//#endregion
|
|
5537
|
+
//#region src/shared/api/host/git-exec.ts
|
|
5538
|
+
var NO_PROMPT_ENV = [
|
|
5539
|
+
"GIT_TERMINAL_PROMPT=0",
|
|
5540
|
+
"GIT_ASKPASS=/usr/bin/false",
|
|
5541
|
+
"SSH_ASKPASS=/usr/bin/false",
|
|
5542
|
+
"SSH_ASKPASS_REQUIRE=never",
|
|
5543
|
+
"GCM_INTERACTIVE=never",
|
|
5544
|
+
"GIT_SSH_COMMAND=ssh -o BatchMode=yes -o StrictHostKeyChecking=accept-new"
|
|
5545
|
+
];
|
|
5546
|
+
function gitNoPromptPrefix() {
|
|
5547
|
+
return [quoteShellArg("env"), ...NO_PROMPT_ENV.map((one) => quoteShellArg(one))].join(" ");
|
|
5548
|
+
}
|
|
5549
|
+
function withoutAskpassNoise(text) {
|
|
5550
|
+
return text.split("\n").filter((line) => !/unable to read askpass response/i.test(line)).join("\n").trim();
|
|
5551
|
+
}
|
|
5552
|
+
//#endregion
|
|
5553
|
+
//#region src/shared/api/host/git-probe.ts
|
|
5554
|
+
var PROBE_TIMEOUT_MS = 1e4;
|
|
5555
|
+
var AUTH_TEXT = /authentication failed|could not read (username|password)|permission denied|terminal prompts disabled|host key verification failed|repository not found|no such identity|access denied|unauthorized|forbidden/;
|
|
5556
|
+
function classifyGitProbe(stderr, timedOut) {
|
|
5557
|
+
if (timedOut) return "unreachable";
|
|
5558
|
+
return AUTH_TEXT.test(stderr.toLowerCase()) ? "auth" : "unreachable";
|
|
5559
|
+
}
|
|
5560
|
+
async function probeGitAddress(shell, url, options = {}) {
|
|
5561
|
+
const line = [
|
|
5562
|
+
gitNoPromptPrefix(),
|
|
5563
|
+
quoteShellArg("git"),
|
|
5564
|
+
quoteShellArg("ls-remote"),
|
|
5565
|
+
quoteShellArg(url),
|
|
5566
|
+
quoteShellArg("HEAD")
|
|
5567
|
+
].join(" ");
|
|
5568
|
+
let result;
|
|
5569
|
+
try {
|
|
5570
|
+
result = await runShell(shell, line, { timeoutMs: options.timeoutMs ?? PROBE_TIMEOUT_MS });
|
|
5571
|
+
} catch (error) {
|
|
5572
|
+
return {
|
|
5573
|
+
status: "unreachable",
|
|
5574
|
+
detail: error instanceof Error ? error.message : String(error)
|
|
5575
|
+
};
|
|
5576
|
+
}
|
|
5577
|
+
if (result.exitCode === 0) return { status: "ok" };
|
|
5578
|
+
const detail = tailLines(withoutAskpassNoise(result.stderr || result.stdout), 3);
|
|
5579
|
+
return {
|
|
5580
|
+
status: classifyGitProbe(`${result.stderr}\n${result.stdout}`, result.timedOut),
|
|
5581
|
+
...detail === "" ? {} : { detail }
|
|
5582
|
+
};
|
|
5583
|
+
}
|
|
5584
|
+
//#endregion
|
|
5585
|
+
//#region src/shared/api/host/git-routes.ts
|
|
5586
|
+
function gitProbeHandler(ctx) {
|
|
5587
|
+
return async (search) => {
|
|
5588
|
+
const url = param(search, "url");
|
|
5589
|
+
if (url === void 0) return {
|
|
5590
|
+
ok: false,
|
|
5591
|
+
error: {
|
|
5592
|
+
code: "workbench/no-url",
|
|
5593
|
+
message: "要探哪个地址?缺 url。"
|
|
5594
|
+
}
|
|
5595
|
+
};
|
|
5596
|
+
const shell = ctx.get("shell");
|
|
5597
|
+
if (shell === void 0) return {
|
|
5598
|
+
ok: false,
|
|
5599
|
+
error: {
|
|
5600
|
+
code: "workbench/no-shell",
|
|
5601
|
+
message: "这台机器上没有执行缝,探不了 git 地址"
|
|
5602
|
+
}
|
|
5603
|
+
};
|
|
5604
|
+
return {
|
|
5605
|
+
ok: true,
|
|
5606
|
+
...await probeGitAddress(shell, url)
|
|
5607
|
+
};
|
|
5608
|
+
};
|
|
5609
|
+
}
|
|
5610
|
+
//#endregion
|
|
5419
5611
|
//#region src/shared/api/host/host-routes.ts
|
|
5420
5612
|
function createHostRoutes(input) {
|
|
5421
5613
|
const { ctx, facts, opencli, running, profile } = input;
|
|
@@ -5425,6 +5617,7 @@ function createHostRoutes(input) {
|
|
|
5425
5617
|
[DSH_PLUGINS_ROUTE]: profile.dshPlugins(ctx),
|
|
5426
5618
|
[BUNDLE_REGISTRIES_ROUTE]: bundleRegistriesHandler(ctx),
|
|
5427
5619
|
[BUNDLE_INSPECT_ROUTE]: bundleInspectHandler(ctx),
|
|
5620
|
+
[MARKET_GIT_PROBE_ROUTE]: gitProbeHandler(ctx),
|
|
5428
5621
|
[MODULE_VERSIONS_ROUTE]: moduleVersionsHandler(ctx, ctx.get("shell"), running, () => profile.selfUpdateView(dshHome(), basename(profile.dirOf(ctx) ?? "")))
|
|
5429
5622
|
};
|
|
5430
5623
|
}
|
|
@@ -5458,12 +5651,14 @@ var MODULES_UPDATE_DEPENDENCY_TOOL = "workbench_modules_update_dependency";
|
|
|
5458
5651
|
var MODULES_UPDATE_PLUGIN_TOOL = "workbench_modules_update_plugin";
|
|
5459
5652
|
var MODULES_UNINSTALL_PLUGIN_TOOL = "workbench_modules_uninstall_plugin";
|
|
5460
5653
|
var MODULES_UPDATE_WORKBENCH_TOOL = "workbench_modules_update_workbench";
|
|
5654
|
+
var MARKET_SOURCES_TOOL = "workbench_market_sources";
|
|
5655
|
+
var MARKET_ENABLE_TOOL = "workbench_market_enable";
|
|
5656
|
+
var MARKET_DISABLE_TOOL = "workbench_market_disable";
|
|
5461
5657
|
var DIY_STATUS_TOOL = "workbench_diy_status";
|
|
5462
5658
|
var DIY_PANEL_TOOL = "workbench_diy_panel";
|
|
5463
5659
|
var DIY_COMPONENTS_TOOL = "workbench_diy_components";
|
|
5464
5660
|
var DIY_RECON_TOOL = "workbench_diy_recon";
|
|
5465
5661
|
var DIY_SPEC_TOOL = "workbench_diy_spec";
|
|
5466
|
-
var DIY_CHANGELOG_TOOL = "workbench_diy_changelog";
|
|
5467
5662
|
var DIY_INSTALL_TOOL = "workbench_diy_install";
|
|
5468
5663
|
var DIY_PUBLISH_TOOL = "workbench_diy_publish";
|
|
5469
5664
|
var DIY_SHOW_TOOL = "workbench_diy_show";
|
|
@@ -5497,6 +5692,7 @@ var DIY_DEBUG_STOP_TOOL = "workbench_diy_debug_stop";
|
|
|
5497
5692
|
var READ_TOOLS = [
|
|
5498
5693
|
PANELS_LIST_TOOL,
|
|
5499
5694
|
MODULES_LIST_TOOL,
|
|
5695
|
+
MARKET_SOURCES_TOOL,
|
|
5500
5696
|
DIY_STATUS_TOOL,
|
|
5501
5697
|
DIY_PANEL_TOOL,
|
|
5502
5698
|
DIY_COMPONENTS_TOOL,
|
|
@@ -5538,7 +5734,8 @@ var WRITE_TOOLS = [
|
|
|
5538
5734
|
MODULES_UPDATE_PLUGIN_TOOL,
|
|
5539
5735
|
MODULES_UNINSTALL_PLUGIN_TOOL,
|
|
5540
5736
|
MODULES_UPDATE_WORKBENCH_TOOL,
|
|
5541
|
-
|
|
5737
|
+
MARKET_ENABLE_TOOL,
|
|
5738
|
+
MARKET_DISABLE_TOOL,
|
|
5542
5739
|
DIY_INSTALL_TOOL,
|
|
5543
5740
|
DIY_PUBLISH_TOOL,
|
|
5544
5741
|
DIY_SHOW_TOOL,
|
|
@@ -5555,7 +5752,6 @@ var DIY_TOOLS = [
|
|
|
5555
5752
|
DIY_COMPONENTS_TOOL,
|
|
5556
5753
|
DIY_RECON_TOOL,
|
|
5557
5754
|
DIY_SPEC_TOOL,
|
|
5558
|
-
DIY_CHANGELOG_TOOL,
|
|
5559
5755
|
DIY_INSTALL_TOOL,
|
|
5560
5756
|
DIY_PUBLISH_TOOL,
|
|
5561
5757
|
DIY_SHOW_TOOL,
|
|
@@ -5832,6 +6028,14 @@ function readDomainsOf(design) {
|
|
|
5832
6028
|
return [...found];
|
|
5833
6029
|
}
|
|
5834
6030
|
//#endregion
|
|
6031
|
+
//#region src/modules/panels/model/publish-claim.ts
|
|
6032
|
+
function publishClaimDenyOf(claim, name) {
|
|
6033
|
+
if (claim === void 0) return void 0;
|
|
6034
|
+
if (claim.state === "unit-taken") return `市场里 ${claim.entry} 已经用了这个模块 id —— 两个模块不能共用一个,装在一起会撞。给这个模块换一个 unit(dsh.workbench.unit)再发。`;
|
|
6035
|
+
if (claim.state === "path-taken") return `市场仓库里的产物目录已经被 ${claim.entry} 占了 —— 换一个包名再发。`;
|
|
6036
|
+
if (claim.state === "conflict") return `市场里 ${name} 已经有主了(${claim.owner})—— 同一个名字不能换人发。换一个带团队 scope 的包名;你就是原来的作者(只是换了机器或署名),用 author 参数带上原来的署名;确实是接手,让索引维护者改 market.json 里这一条的 owner。`;
|
|
6037
|
+
}
|
|
6038
|
+
//#endregion
|
|
5835
6039
|
//#region src/modules/panels/model/approval.ts
|
|
5836
6040
|
var SPEC_LIMIT = 80;
|
|
5837
6041
|
var TARGET_LIMIT = 20;
|
|
@@ -5938,11 +6142,22 @@ function publishVerdict(call, preview) {
|
|
|
5938
6142
|
if (raw["verify"] === true || raw["target"] === "local") return { kind: "allow" };
|
|
5939
6143
|
const refresh = raw["refresh"] === true;
|
|
5940
6144
|
const unit = textOf$3(raw, "unit");
|
|
5941
|
-
const
|
|
6145
|
+
const askedAuthor = textOf$3(raw, "author");
|
|
6146
|
+
const found = unit === "" ? null : preview?.(unit, askedAuthor === "" ? void 0 : askedAuthor) ?? null;
|
|
5942
6147
|
const asked = textOf$3(raw, "target");
|
|
5943
6148
|
const target = refresh ? "market" : asked === "" ? found?.market === void 0 ? found?.registry === void 0 ? "tarball" : "team" : "market" : asked;
|
|
6149
|
+
const source = textOf$3(raw, "source");
|
|
6150
|
+
const claimReason = publishClaimDenyOf(found?.claim, found?.name ?? unit);
|
|
6151
|
+
if (source === "" && target !== "tarball" && target !== "local" && claimReason !== void 0) return {
|
|
6152
|
+
kind: "deny",
|
|
6153
|
+
reason: claimReason
|
|
6154
|
+
};
|
|
5944
6155
|
const label = unit === "" ? "工作台模块" : `工作台模块 [${unit}]`;
|
|
5945
6156
|
const labelEn = unit === "" ? "the workbench module" : `the workbench module [${unit}]`;
|
|
6157
|
+
if (!refresh && found?.changelog?.missing === true && textOf$3(raw, "changelogNote") === "") return {
|
|
6158
|
+
kind: "deny",
|
|
6159
|
+
reason: `这一版还没有更新日志(${found.changelog.version})—— 带上 changelogNote(一行一条)再调,发布时会一起写进 CHANGELOG.md 并随包发`
|
|
6160
|
+
};
|
|
5946
6161
|
const copies = {
|
|
5947
6162
|
team: {
|
|
5948
6163
|
zh: `把${label}发到团队源,只发构建产物,不发源码,允许吗?`,
|
|
@@ -5974,7 +6189,7 @@ function publishVerdict(call, preview) {
|
|
|
5974
6189
|
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);
|
|
5975
6190
|
return askOf(`${DIY_PUBLISH_TOOL} ${targetLabel}${refresh ? "(元数据)" : ""}`, question, question);
|
|
5976
6191
|
}
|
|
5977
|
-
|
|
6192
|
+
function approvalVerdict(call, marketSource) {
|
|
5978
6193
|
if (call.name === "workbench_long_tasks_stop") return stopVerdict(call, void 0);
|
|
5979
6194
|
if (call.name === "workbench_diy_publish") return publishVerdict(call);
|
|
5980
6195
|
if (call.name === "workbench_diy_debug_start" || call.name === "workbench_diy_debug_resume") {
|
|
@@ -6045,9 +6260,41 @@ var panelsApproval = (call) => {
|
|
|
6045
6260
|
return askOf(`${MODULES_UNINSTALL_PLUGIN_TOOL} ${plugin ?? ""} uninstalls an opencli plugin on this machine`, pair(`会卸载${target.zh},允许吗?`, `it uninstalls ${target.en}. Allow?`), pair(`agent 想卸载${target.zh},允许吗?`, `The agent wants to uninstall ${target.en}. Allow?`));
|
|
6046
6261
|
}
|
|
6047
6262
|
case MODULES_UPDATE_WORKBENCH_TOOL: return askOf(`${MODULES_UPDATE_WORKBENCH_TOOL} replaces the workbench itself with the new version from the registry`, pair("会把工作台本身更新到源上的新版,允许吗?", "it updates the workbench itself to the new version from the registry. Allow?"), pair("agent 想把工作台本身更新到源上的新版,允许吗?", "The agent wants to update the workbench itself from the registry. Allow?"));
|
|
6263
|
+
case MARKET_ENABLE_TOOL: {
|
|
6264
|
+
const id = text("id");
|
|
6265
|
+
const source = marketSource?.(id);
|
|
6266
|
+
if (marketSource !== void 0 && source === void 0) return {
|
|
6267
|
+
kind: "deny",
|
|
6268
|
+
reason: id === void 0 ? "这台机器上还没有选中的索引源 —— 先在「模块市场 → 发现」里添加并选中一个" : `没有这个索引源:${id}`
|
|
6269
|
+
};
|
|
6270
|
+
if (source !== void 0 && source.policy === "artifacts-in-repo") return { kind: "allow" };
|
|
6271
|
+
if (source !== void 0 && source.kind === "http") return {
|
|
6272
|
+
kind: "deny",
|
|
6273
|
+
reason: "http 索引源只能读,不能当发布目的地"
|
|
6274
|
+
};
|
|
6275
|
+
const where = source === void 0 ? {
|
|
6276
|
+
zh: id === void 0 ? "工作台当前选中的索引源" : `工作台的索引源「${id}」`,
|
|
6277
|
+
en: id === void 0 ? "the selected workbench index source" : `the workbench index source "${id}"`
|
|
6278
|
+
} : {
|
|
6279
|
+
zh: `工作台的索引源「${source.label}」`,
|
|
6280
|
+
en: `the workbench index source "${source.label}"`
|
|
6281
|
+
};
|
|
6282
|
+
return askOf(`${MARKET_ENABLE_TOOL}${source === void 0 ? "" : ` ${source.url}`} marks a market index source as a publish destination on this machine`, pair(`把${where.zh}设为可发布,允许吗?`, `Make ${where.en} a publish destination. Allow?`), pair(`会把${where.zh}设为可发布,只改本机配置,不碰仓库,允许吗?`, `It makes ${where.en} a publish destination on this machine, without touching the repository. Allow?`));
|
|
6283
|
+
}
|
|
6284
|
+
case MARKET_DISABLE_TOOL: {
|
|
6285
|
+
const id = text("id");
|
|
6286
|
+
const source = marketSource?.(id);
|
|
6287
|
+
if (marketSource !== void 0 && source === void 0) return {
|
|
6288
|
+
kind: "deny",
|
|
6289
|
+
reason: id === void 0 ? "这台机器上还没有选中的索引源 —— 先在「模块市场 → 发现」里添加并选中一个" : `没有这个索引源:${id}`
|
|
6290
|
+
};
|
|
6291
|
+
if (source === void 0) return askOf(`${MARKET_DISABLE_TOOL} stops using a market index source as a publish destination on this machine`, pair("把工作台当前选中的索引源改回只读,允许吗?", "Make the selected workbench index source read-only again. Allow?"), pair("会把工作台当前选中的索引源改回只读,只改本机配置,不碰仓库,允许吗?", "It makes the selected workbench index source read-only again on this machine, without touching the repository. Allow?"));
|
|
6292
|
+
if (source.kind !== "git" || source.policy !== "artifacts-in-repo") return { kind: "allow" };
|
|
6293
|
+
return askOf(`${MARKET_DISABLE_TOOL} ${source.url} stops using a market index source as a publish destination on this machine`, pair(`把工作台的索引源「${source.label}」改回只读,允许吗?`, `Make the workbench index source "${source.label}" read-only again. Allow?`), pair(`会把工作台的索引源「${source.label}」改回只读,只改本机配置,不碰仓库,允许吗?`, `It makes the workbench index source "${source.label}" read-only again on this machine, without touching the repository. Allow?`));
|
|
6294
|
+
}
|
|
6048
6295
|
default: return;
|
|
6049
6296
|
}
|
|
6050
|
-
}
|
|
6297
|
+
}
|
|
6051
6298
|
function recordHeldVerdict(call, recording) {
|
|
6052
6299
|
if (call.name !== "workbench_diy_record_prepare" || recording === void 0) return void 0;
|
|
6053
6300
|
const held = recording();
|
|
@@ -6057,11 +6304,16 @@ function recordHeldVerdict(call, recording) {
|
|
|
6057
6304
|
reason: recordRefusalText(held.sessionId === call.session ? "already-held" : "held-by-other", held)
|
|
6058
6305
|
};
|
|
6059
6306
|
}
|
|
6060
|
-
function panelsApprovalFor(longTaskRuns, recording, publishPreview) {
|
|
6307
|
+
function panelsApprovalFor(longTaskRuns, recording, publishPreview, marketSources) {
|
|
6308
|
+
const sourceOf = marketSources === void 0 ? void 0 : (id) => {
|
|
6309
|
+
const payload = marketSources.read();
|
|
6310
|
+
const wanted = id === void 0 || id === "" ? payload.selected : id;
|
|
6311
|
+
return wanted === null ? void 0 : payload.sources.find((one) => one.id === wanted);
|
|
6312
|
+
};
|
|
6061
6313
|
return (call) => {
|
|
6062
6314
|
if (call.name === "workbench_long_tasks_stop") return stopVerdict(call, longTaskRuns);
|
|
6063
6315
|
if (call.name === "workbench_diy_publish") return publishVerdict(call, publishPreview);
|
|
6064
|
-
return recordHeldVerdict(call, recording) ??
|
|
6316
|
+
return recordHeldVerdict(call, recording) ?? approvalVerdict(call, sourceOf);
|
|
6065
6317
|
};
|
|
6066
6318
|
}
|
|
6067
6319
|
//#endregion
|
|
@@ -6978,7 +7230,7 @@ async function sessionWorkspaceOf(ctx, workspace) {
|
|
|
6978
7230
|
dir = parent;
|
|
6979
7231
|
}
|
|
6980
7232
|
}
|
|
6981
|
-
var OUTPUT$
|
|
7233
|
+
var OUTPUT$3 = {
|
|
6982
7234
|
schema: {
|
|
6983
7235
|
type: "object",
|
|
6984
7236
|
properties: {
|
|
@@ -7123,7 +7375,7 @@ function componentsTool(ctx) {
|
|
|
7123
7375
|
},
|
|
7124
7376
|
additionalProperties: false
|
|
7125
7377
|
},
|
|
7126
|
-
output: OUTPUT$
|
|
7378
|
+
output: OUTPUT$3,
|
|
7127
7379
|
async execute(raw, exec) {
|
|
7128
7380
|
const { root } = await workspaceOf(ctx, exec);
|
|
7129
7381
|
const args = asRecord$1(raw);
|
|
@@ -7221,97 +7473,6 @@ function registerComponentsTool(ctx, tools) {
|
|
|
7221
7473
|
return [tools.register(componentsTool(ctx))];
|
|
7222
7474
|
}
|
|
7223
7475
|
//#endregion
|
|
7224
|
-
//#region src/shared/api/host/diy-changelog.ts
|
|
7225
|
-
function moduleVersionOf(dir) {
|
|
7226
|
-
try {
|
|
7227
|
-
const version = JSON.parse(readFileSync(join(dir, "package.json"), "utf8")).version;
|
|
7228
|
-
return typeof version === "string" ? version.trim() : "";
|
|
7229
|
-
} catch {
|
|
7230
|
-
return "";
|
|
7231
|
-
}
|
|
7232
|
-
}
|
|
7233
|
-
function writeChangelogEntry(dir, input) {
|
|
7234
|
-
const file = join(dir, CHANGELOG_FILE);
|
|
7235
|
-
const text = appendChangelogEntry(existsSync(file) ? readFileSync(file, "utf8") : changelogSkeleton(), {
|
|
7236
|
-
version: input.version,
|
|
7237
|
-
kind: input.kind,
|
|
7238
|
-
note: input.note,
|
|
7239
|
-
date: input.date ?? changelogDate()
|
|
7240
|
-
});
|
|
7241
|
-
writeFileSync(file, text);
|
|
7242
|
-
return {
|
|
7243
|
-
file,
|
|
7244
|
-
section: changelogSectionOf(text, input.version) ?? "",
|
|
7245
|
-
text
|
|
7246
|
-
};
|
|
7247
|
-
}
|
|
7248
|
-
//#endregion
|
|
7249
|
-
//#region src/modules/panels/model/diy-changelog.ts
|
|
7250
|
-
function toolOf(ctx) {
|
|
7251
|
-
return {
|
|
7252
|
-
name: DIY_CHANGELOG_TOOL,
|
|
7253
|
-
description: `发布前把这一版写进 ${CHANGELOG_FILE}(\`## v0.1.0\` + \`### ✨ 新增\` 这种小节):传 note 就记一条,文件不在就先建。没写这一版时发布会被拦下。`,
|
|
7254
|
-
parameters: {
|
|
7255
|
-
type: "object",
|
|
7256
|
-
properties: {
|
|
7257
|
-
unit: {
|
|
7258
|
-
type: "string",
|
|
7259
|
-
description: "模块 id(workbench_diy_status 会给)。"
|
|
7260
|
-
},
|
|
7261
|
-
version: {
|
|
7262
|
-
type: "string",
|
|
7263
|
-
description: "要写的版本;不填用 package.json 里的 version。"
|
|
7264
|
-
},
|
|
7265
|
-
type: {
|
|
7266
|
-
type: "string",
|
|
7267
|
-
enum: [...CHANGELOG_KINDS],
|
|
7268
|
-
description: "分类:added 新增 / changed 改进 / fixed 修复 / removed 移除 / security 安全 / deprecated 弃用。"
|
|
7269
|
-
},
|
|
7270
|
-
note: {
|
|
7271
|
-
type: "string",
|
|
7272
|
-
description: "这一版改了什么;多行时一行一条(必填)。"
|
|
7273
|
-
}
|
|
7274
|
-
},
|
|
7275
|
-
required: ["unit", "note"],
|
|
7276
|
-
additionalProperties: false
|
|
7277
|
-
},
|
|
7278
|
-
output: OUTPUT$2,
|
|
7279
|
-
async execute(raw, exec) {
|
|
7280
|
-
const { root } = await workspaceOf(ctx, exec);
|
|
7281
|
-
const args = asRecord$1(raw);
|
|
7282
|
-
const unit = asText(args["unit"]);
|
|
7283
|
-
const { units } = unitsOf(ctx, root);
|
|
7284
|
-
if (unit === "") throw new Error(`要一个 unit(这个工作区里:${units.map((one) => one.unit).join(", ") || "(空)"})`);
|
|
7285
|
-
const found = units.find((one) => one.unit === unit && one.dir !== "");
|
|
7286
|
-
if (found === void 0) throw new Error(`这个工作区里没有单元 id 为「${unit}」的模块(可用的:${units.map((one) => one.unit).join(", ") || "(空)"})`);
|
|
7287
|
-
if (!insideRoot(root, found.dir)) throw new Error(`这个模块不在这个工作区里(${found.dir})`);
|
|
7288
|
-
const note = asText(args["note"]).trim();
|
|
7289
|
-
if (note === "") throw new Error("要一句 note:这一版改了什么");
|
|
7290
|
-
const version = (asText(args["version"]) || moduleVersionOf(found.dir)).replace(/^v/, "");
|
|
7291
|
-
if (!isValidVersion(version)) throw new Error(`版本要写成 x.y.z(收到「${version}」)—— 也可以不填,用 package.json 里的`);
|
|
7292
|
-
const kind = asText(args["type"]) || "changed";
|
|
7293
|
-
if (!CHANGELOG_KINDS.includes(kind)) throw new Error(`type 只认 ${CHANGELOG_KINDS.join(" / ")}(收到「${kind}」)`);
|
|
7294
|
-
const written = writeChangelogEntry(found.dir, {
|
|
7295
|
-
version,
|
|
7296
|
-
kind,
|
|
7297
|
-
note
|
|
7298
|
-
});
|
|
7299
|
-
return plainJson({
|
|
7300
|
-
ok: true,
|
|
7301
|
-
unit,
|
|
7302
|
-
version,
|
|
7303
|
-
type: kind,
|
|
7304
|
-
path: written.file,
|
|
7305
|
-
section: written.section,
|
|
7306
|
-
text: `${CHANGELOG_FILE} 已记下 ${version}(${kind})。发布时会带进包和市场索引,审批屏会展示它。`
|
|
7307
|
-
});
|
|
7308
|
-
}
|
|
7309
|
-
};
|
|
7310
|
-
}
|
|
7311
|
-
function registerChangelogTool(ctx, tools) {
|
|
7312
|
-
return [tools.register(toolOf(ctx))];
|
|
7313
|
-
}
|
|
7314
|
-
//#endregion
|
|
7315
7476
|
//#region src/shared/api/host/diy-artifacts.ts
|
|
7316
7477
|
function artifactsDirOf(ctx, root) {
|
|
7317
7478
|
const homePath = ctx.get("dshHomePath");
|
|
@@ -7598,7 +7759,7 @@ function registerDebugTools(ctx, tools, store) {
|
|
|
7598
7759
|
required: [],
|
|
7599
7760
|
additionalProperties: false
|
|
7600
7761
|
},
|
|
7601
|
-
output: OUTPUT$
|
|
7762
|
+
output: OUTPUT$3,
|
|
7602
7763
|
async execute(raw, exec) {
|
|
7603
7764
|
const { root, title } = await workspaceOf(ctx, exec);
|
|
7604
7765
|
const { units } = unitsOf(ctx, root);
|
|
@@ -7633,7 +7794,7 @@ function registerDebugTools(ctx, tools, store) {
|
|
|
7633
7794
|
name: DIY_DEBUG_PAUSE_TOOL,
|
|
7634
7795
|
description: "暂停调试(不审批):屏工具停用,不再拿屏当目标。要接着看用 debug_resume。",
|
|
7635
7796
|
parameters: EMPTY,
|
|
7636
|
-
output: OUTPUT$
|
|
7797
|
+
output: OUTPUT$3,
|
|
7637
7798
|
async execute(_raw, exec) {
|
|
7638
7799
|
const { root } = await workspaceOf(ctx, exec);
|
|
7639
7800
|
const held = store.live(Date.now());
|
|
@@ -7651,7 +7812,7 @@ function registerDebugTools(ctx, tools, store) {
|
|
|
7651
7812
|
name: DIY_DEBUG_RESUME_TOOL,
|
|
7652
7813
|
description: "继续调试(要点头一次):请用户回到这一场调试所在的那一屏。",
|
|
7653
7814
|
parameters: EMPTY,
|
|
7654
|
-
output: OUTPUT$
|
|
7815
|
+
output: OUTPUT$3,
|
|
7655
7816
|
async execute(_raw, exec) {
|
|
7656
7817
|
const { root } = await workspaceOf(ctx, exec);
|
|
7657
7818
|
const held = store.live(Date.now());
|
|
@@ -7675,7 +7836,7 @@ function registerDebugTools(ctx, tools, store) {
|
|
|
7675
7836
|
name: DIY_DEBUG_STOP_TOOL,
|
|
7676
7837
|
description: "结束调试(不审批):清掉\"占用用户那一屏\"这件事。收工用它。",
|
|
7677
7838
|
parameters: EMPTY,
|
|
7678
|
-
output: OUTPUT$
|
|
7839
|
+
output: OUTPUT$3,
|
|
7679
7840
|
async execute(_raw, exec) {
|
|
7680
7841
|
const { root } = await workspaceOf(ctx, exec);
|
|
7681
7842
|
const held = store.live(Date.now());
|
|
@@ -7865,7 +8026,7 @@ function registerLogTools(ctx, tools) {
|
|
|
7865
8026
|
name: DIY_LOGS_WATCH_TOOL,
|
|
7866
8027
|
description: "把这一页的控制台听上(每页最多 200 条、单条截 400 字,随页面刷新消失)。",
|
|
7867
8028
|
parameters: schema,
|
|
7868
|
-
output: OUTPUT$
|
|
8029
|
+
output: OUTPUT$3,
|
|
7869
8030
|
async execute(raw, exec) {
|
|
7870
8031
|
const { page, step } = await run(exec, raw, LOGS_ARM_SCRIPT);
|
|
7871
8032
|
const error = actErrorOf(step);
|
|
@@ -7885,7 +8046,7 @@ function registerLogTools(ctx, tools) {
|
|
|
7885
8046
|
name: DIY_LOGS_READ_TOOL,
|
|
7886
8047
|
description: "读刚才听下来的控制台(最近 50 条;没装钩子会说清,不假装是\"没有报错\")。",
|
|
7887
8048
|
parameters: schema,
|
|
7888
|
-
output: OUTPUT$
|
|
8049
|
+
output: OUTPUT$3,
|
|
7889
8050
|
async execute(raw, exec) {
|
|
7890
8051
|
const { page, step } = await run(exec, raw, LOGS_READ_SCRIPT);
|
|
7891
8052
|
const error = actErrorOf(step);
|
|
@@ -7904,7 +8065,7 @@ function registerLogTools(ctx, tools) {
|
|
|
7904
8065
|
name: DIY_LOGS_STOP_TOOL,
|
|
7905
8066
|
description: "控制台收听收工:卸掉钩子、扔掉攒下的记录。",
|
|
7906
8067
|
parameters: schema,
|
|
7907
|
-
output: OUTPUT$
|
|
8068
|
+
output: OUTPUT$3,
|
|
7908
8069
|
async execute(raw, exec) {
|
|
7909
8070
|
const { page, step } = await run(exec, raw, LOGS_STOP_SCRIPT);
|
|
7910
8071
|
const error = actErrorOf(step);
|
|
@@ -8570,7 +8731,7 @@ function registerBrowserTools(ctx, tools) {
|
|
|
8570
8731
|
name: row.tool,
|
|
8571
8732
|
description: row.description,
|
|
8572
8733
|
parameters: parametersOf(row),
|
|
8573
|
-
output: OUTPUT$
|
|
8734
|
+
output: OUTPUT$3,
|
|
8574
8735
|
execute: async (raw, exec) => plainJson(await runBrowserTool(row, ctx, raw, exec))
|
|
8575
8736
|
};
|
|
8576
8737
|
return tools.register(definition);
|
|
@@ -8609,7 +8770,7 @@ function specTool(ctx) {
|
|
|
8609
8770
|
required: ["command"],
|
|
8610
8771
|
additionalProperties: false
|
|
8611
8772
|
},
|
|
8612
|
-
output: OUTPUT$
|
|
8773
|
+
output: OUTPUT$3,
|
|
8613
8774
|
async execute(raw, _exec) {
|
|
8614
8775
|
const args = asRecord$1(raw);
|
|
8615
8776
|
const argv = specArgvOf(asText(args["command"]));
|
|
@@ -8636,6 +8797,176 @@ function registerSpecTool(ctx, tools) {
|
|
|
8636
8797
|
return [tools.register(specTool(ctx))];
|
|
8637
8798
|
}
|
|
8638
8799
|
//#endregion
|
|
8800
|
+
//#region src/modules/panels/model/diy-publish.ts
|
|
8801
|
+
var PUBLISH_TIMEOUT_MS = 18e5;
|
|
8802
|
+
function registerPublishTool(ctx, tools, deps) {
|
|
8803
|
+
const publishTool = {
|
|
8804
|
+
name: DIY_PUBLISH_TOOL,
|
|
8805
|
+
description: "用户说“发布”后才用:把这一格发到 target 指定的出口(不填按环境默认)。这一版还没有更新日志时把 changelogNote 一起带上 —— 发布时写进 CHANGELOG.md,随包发。",
|
|
8806
|
+
parameters: {
|
|
8807
|
+
type: "object",
|
|
8808
|
+
properties: {
|
|
8809
|
+
unit: {
|
|
8810
|
+
type: "string",
|
|
8811
|
+
description: "模块 id(workbench_diy_status 会给)。"
|
|
8812
|
+
},
|
|
8813
|
+
changelogNote: {
|
|
8814
|
+
type: "string",
|
|
8815
|
+
description: "这一版改了什么,一行一条;这一版还没有更新日志时必填(文件不在会先建)。"
|
|
8816
|
+
},
|
|
8817
|
+
changelogType: {
|
|
8818
|
+
type: "string",
|
|
8819
|
+
enum: [...CHANGELOG_KINDS],
|
|
8820
|
+
description: "分类,不填按 changed。"
|
|
8821
|
+
},
|
|
8822
|
+
target: {
|
|
8823
|
+
type: "string",
|
|
8824
|
+
enum: [
|
|
8825
|
+
"team",
|
|
8826
|
+
"public",
|
|
8827
|
+
"tarball",
|
|
8828
|
+
"git",
|
|
8829
|
+
"market",
|
|
8830
|
+
"local"
|
|
8831
|
+
],
|
|
8832
|
+
description: "发到哪:团队源 / 公共 npm / 安装包 / git / 模块市场索引;不填按环境默认(有可写索引走市场,有私源走团队源,否则安装包)。"
|
|
8833
|
+
},
|
|
8834
|
+
version: {
|
|
8835
|
+
type: "string",
|
|
8836
|
+
description: "可选:patch / minor / major / x.y.z;不填首次用当前版本,之后自动 patch。"
|
|
8837
|
+
},
|
|
8838
|
+
source: {
|
|
8839
|
+
type: "string",
|
|
8840
|
+
description: "发布到哪个索引源(workbench_market_sources 会给 id);不填用唯一可发布的源。"
|
|
8841
|
+
},
|
|
8842
|
+
verify: {
|
|
8843
|
+
type: "boolean",
|
|
8844
|
+
description: "只核已发布的包(交接验证码后用),不再发;不用审批。"
|
|
8845
|
+
},
|
|
8846
|
+
resume: {
|
|
8847
|
+
type: "boolean",
|
|
8848
|
+
description: "中断后接着发(用记录里的出口与版本)。"
|
|
8849
|
+
},
|
|
8850
|
+
license: {
|
|
8851
|
+
type: "string",
|
|
8852
|
+
description: "公开发布用的许可证(MIT / Apache-2.0 / 仓库已有 LICENSE)。"
|
|
8853
|
+
},
|
|
8854
|
+
author: {
|
|
8855
|
+
type: "string",
|
|
8856
|
+
description: "署谁的名(姓名,或 姓名 <邮箱>);用户点了名才传,不传按模块里写的,没写用推断的署名。"
|
|
8857
|
+
},
|
|
8858
|
+
refresh: {
|
|
8859
|
+
type: "boolean",
|
|
8860
|
+
description: "只刷市集元数据(标题/作者/说明),不升版本、不重发产物。"
|
|
8861
|
+
}
|
|
8862
|
+
},
|
|
8863
|
+
required: ["unit"],
|
|
8864
|
+
additionalProperties: false
|
|
8865
|
+
},
|
|
8866
|
+
output: OUTPUT$3,
|
|
8867
|
+
async execute(raw, exec) {
|
|
8868
|
+
const { root } = await workspaceOf(ctx, exec);
|
|
8869
|
+
const found = deps.resolve(root, raw);
|
|
8870
|
+
const shell = ctx.get("shell");
|
|
8871
|
+
if (shell === void 0) throw new Error("这台机器上没有 shell 服务,发布跑不起来");
|
|
8872
|
+
const bin = toolchainBinOf(root) ?? toolchainBinOf(found.dir);
|
|
8873
|
+
if (bin === null) throw new Error(`这个工作区里没有 dsh-wb-module(${join(root, "node_modules")} 下没有)—— 先 pnpm install`);
|
|
8874
|
+
const target = asText(asRecord$1(raw)["target"]);
|
|
8875
|
+
const source = asText(asRecord$1(raw)["source"]);
|
|
8876
|
+
const version = asText(asRecord$1(raw)["version"]);
|
|
8877
|
+
const license = asText(asRecord$1(raw)["license"]);
|
|
8878
|
+
const changelogNote = asText(asRecord$1(raw)["changelogNote"]);
|
|
8879
|
+
const changelogType = asText(asRecord$1(raw)["changelogType"]);
|
|
8880
|
+
let author = asText(asRecord$1(raw)["author"]);
|
|
8881
|
+
const verify = asRecord$1(raw)["verify"] === true;
|
|
8882
|
+
const resume = asRecord$1(raw)["resume"] === true;
|
|
8883
|
+
if (!verify && target !== "local" && author === "" && (deps.previewOf(found.unit)?.author ?? "") === "") author = await deps.inferredAuthorOf(found.unit) ?? "";
|
|
8884
|
+
const argv = [
|
|
8885
|
+
bin,
|
|
8886
|
+
"release",
|
|
8887
|
+
"--cwd",
|
|
8888
|
+
found.dir,
|
|
8889
|
+
"--json"
|
|
8890
|
+
];
|
|
8891
|
+
if (verify) argv.push("--verify");
|
|
8892
|
+
else argv.push("--yes");
|
|
8893
|
+
if (resume) argv.push("--resume");
|
|
8894
|
+
if (target !== "") argv.push("--target", target);
|
|
8895
|
+
if (source !== "") argv.push("--index-source", source);
|
|
8896
|
+
if (version !== "") argv.push("--version", version);
|
|
8897
|
+
if (license !== "") argv.push("--license", license);
|
|
8898
|
+
if (author !== "") argv.push("--author", author);
|
|
8899
|
+
if (changelogNote !== "") argv.push("--changelog-note", changelogNote);
|
|
8900
|
+
if (changelogType !== "") argv.push("--changelog-type", changelogType);
|
|
8901
|
+
if (asRecord$1(raw)["refresh"] === true) argv.push("--refresh");
|
|
8902
|
+
const result = await runShell(shell, argv.map((one) => quoteShellArg(one)).join(" "), {
|
|
8903
|
+
workdir: root,
|
|
8904
|
+
timeoutMs: PUBLISH_TIMEOUT_MS
|
|
8905
|
+
});
|
|
8906
|
+
const payload = jsonOf(result.stdout);
|
|
8907
|
+
if (result.exitCode === 3 && payload !== void 0) {
|
|
8908
|
+
const needs = asRecord$1(payload["needsUser"]);
|
|
8909
|
+
const stepText = asText(needs["text"]);
|
|
8910
|
+
const command = asText(needs["command"]);
|
|
8911
|
+
return plainJson({
|
|
8912
|
+
...payload,
|
|
8913
|
+
text: [
|
|
8914
|
+
`还差一步:${stepText}`,
|
|
8915
|
+
...command === "" ? [] : [`命令:${command}`],
|
|
8916
|
+
"做完跟我说「好了」,我接着发。"
|
|
8917
|
+
].join("\n")
|
|
8918
|
+
});
|
|
8919
|
+
}
|
|
8920
|
+
if (result.exitCode === 4 && payload !== void 0) {
|
|
8921
|
+
const resumeInfo = asRecord$1(payload["resume"]);
|
|
8922
|
+
return plainJson({
|
|
8923
|
+
...payload,
|
|
8924
|
+
text: [`发布中断在第 ${asText(resumeInfo["phase"])} 步:${asText(payload["text"])}`, `再调一次 workbench_diy_publish(unit=${found.unit}, resume=true)就能接着发。`].join("\n")
|
|
8925
|
+
});
|
|
8926
|
+
}
|
|
8927
|
+
if (result.exitCode !== 0 || payload === void 0) {
|
|
8928
|
+
const tail = `${result.stderr}\n${result.stdout}`.trim().split("\n").slice(-6).join(" | ");
|
|
8929
|
+
throw new Error(`发布没走通(exit ${String(result.exitCode)})${tail === "" ? "" : `:${tail}`}`);
|
|
8930
|
+
}
|
|
8931
|
+
const name = asText(payload["name"]);
|
|
8932
|
+
const released = asText(payload["version"]);
|
|
8933
|
+
const registry = asText(payload["registry"]);
|
|
8934
|
+
const file = asText(payload["file"]);
|
|
8935
|
+
const install = asText(payload["install"]);
|
|
8936
|
+
const git = asRecord$1(payload["git"]);
|
|
8937
|
+
const targetOfPayload = asText(payload["target"]);
|
|
8938
|
+
const text = verify ? [
|
|
8939
|
+
`已核过 ${name}@${released}`,
|
|
8940
|
+
`安装:${install}`,
|
|
8941
|
+
"没有重新发布。"
|
|
8942
|
+
].join("\n") : payload["refresh"] === true ? [payload["refreshed"] === true ? `已刷新 ${name} 的市集元数据(版本 ${released} 不变)` : `${name} 的市集元数据本来就是这样,没动`, `市场索引:${asText(asRecord$1(payload["market"])["url"])}`].join("\n") : targetOfPayload === "tarball" ? [
|
|
8943
|
+
`安装包在 ${file}`,
|
|
8944
|
+
`本机装:${install}`,
|
|
8945
|
+
"文件可以从对话里带走,发给同事。"
|
|
8946
|
+
].join("\n") : targetOfPayload === "git" ? [
|
|
8947
|
+
`已推到 ${asText(git["url"])}(tag ${asText(git["tag"])})`,
|
|
8948
|
+
`安装:${install}`,
|
|
8949
|
+
"已核过 tag 里的产物。"
|
|
8950
|
+
].join("\n") : targetOfPayload === "market" ? [
|
|
8951
|
+
`已发到市场索引 ${asText(asRecord$1(payload["market"])["url"])}`,
|
|
8952
|
+
`安装:${install}`,
|
|
8953
|
+
"已从索引仓库侧核过产物。"
|
|
8954
|
+
].join("\n") : targetOfPayload === "local" ? "没发,留在本机。" : [
|
|
8955
|
+
`已发布 ${name}@${released} → ${registry}`,
|
|
8956
|
+
`同事安装:${install}`,
|
|
8957
|
+
"包内容已经从源上核过(dist/host.js / client.js / cordis.patch.yml 都在)。"
|
|
8958
|
+
].join("\n");
|
|
8959
|
+
const changelog = asRecord$1(payload["changelog"]);
|
|
8960
|
+
const changelogLine = asText(changelog["action"]) === "written" ? `更新日志:已写进 ${CHANGELOG_FILE} 的 ${asText(changelog["version"])}` : asText(changelog["action"]) === "kept" ? `更新日志:这一版已有(${asText(changelog["version"])}),没动` : "";
|
|
8961
|
+
return plainJson({
|
|
8962
|
+
...payload,
|
|
8963
|
+
text: changelogLine === "" ? text : `${text}\n${changelogLine}`
|
|
8964
|
+
});
|
|
8965
|
+
}
|
|
8966
|
+
};
|
|
8967
|
+
return tools.register(publishTool);
|
|
8968
|
+
}
|
|
8969
|
+
//#endregion
|
|
8639
8970
|
//#region src/shared/api/host/diy-recon.ts
|
|
8640
8971
|
var SITE_LIMIT = 6;
|
|
8641
8972
|
var COMMAND_LIMIT = 12;
|
|
@@ -9076,7 +9407,7 @@ function renderStatus(root, lines, options = {}) {
|
|
|
9076
9407
|
}
|
|
9077
9408
|
function publishStatusOf(preview) {
|
|
9078
9409
|
if (preview === null) return "";
|
|
9079
|
-
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} 这一版 ——
|
|
9410
|
+
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");
|
|
9080
9411
|
}
|
|
9081
9412
|
function renderList(root, modules, shape = "bare") {
|
|
9082
9413
|
if (modules.length === 0) return [
|
|
@@ -9091,7 +9422,6 @@ function renderList(root, modules, shape = "bare") {
|
|
|
9091
9422
|
}
|
|
9092
9423
|
//#endregion
|
|
9093
9424
|
//#region src/modules/panels/model/diy-tools.ts
|
|
9094
|
-
var PUBLISH_TIMEOUT_MS = 18e5;
|
|
9095
9425
|
function registerDiyTools(ctx, market, panels, debug, previewOf = () => null, inferredAuthorOf = async () => void 0) {
|
|
9096
9426
|
const supply = supplyPortOf(ctx);
|
|
9097
9427
|
const tools = ctx.get("tools");
|
|
@@ -9111,7 +9441,7 @@ function registerDiyTools(ctx, market, panels, debug, previewOf = () => null, in
|
|
|
9111
9441
|
required: [],
|
|
9112
9442
|
additionalProperties: false
|
|
9113
9443
|
},
|
|
9114
|
-
output: OUTPUT$
|
|
9444
|
+
output: OUTPUT$3,
|
|
9115
9445
|
async execute(raw, exec) {
|
|
9116
9446
|
const { root } = await workspaceOf(ctx, exec);
|
|
9117
9447
|
const { units } = unitsOf(ctx, root);
|
|
@@ -9154,7 +9484,7 @@ function registerDiyTools(ctx, market, panels, debug, previewOf = () => null, in
|
|
|
9154
9484
|
} },
|
|
9155
9485
|
additionalProperties: false
|
|
9156
9486
|
},
|
|
9157
|
-
output: OUTPUT$
|
|
9487
|
+
output: OUTPUT$3,
|
|
9158
9488
|
async execute(raw, exec) {
|
|
9159
9489
|
const { root } = await workspaceOf(ctx, exec);
|
|
9160
9490
|
const { installed, units } = unitsOf(ctx, root);
|
|
@@ -9220,7 +9550,7 @@ function registerDiyTools(ctx, market, panels, debug, previewOf = () => null, in
|
|
|
9220
9550
|
required: ["keyword"],
|
|
9221
9551
|
additionalProperties: false
|
|
9222
9552
|
},
|
|
9223
|
-
output: OUTPUT$
|
|
9553
|
+
output: OUTPUT$3,
|
|
9224
9554
|
async execute(raw, _exec) {
|
|
9225
9555
|
const args = asRecord$1(raw);
|
|
9226
9556
|
const keywords = keywordsOf(asText(args["keyword"]), asText(args["url"]));
|
|
@@ -9256,220 +9586,77 @@ function registerDiyTools(ctx, market, panels, debug, previewOf = () => null, in
|
|
|
9256
9586
|
parameters: {
|
|
9257
9587
|
type: "object",
|
|
9258
9588
|
properties: { unit: {
|
|
9259
|
-
type: "string",
|
|
9260
|
-
description: "模块 id(workbench_diy_status 会给)。"
|
|
9261
|
-
} },
|
|
9262
|
-
required: ["unit"],
|
|
9263
|
-
additionalProperties: false
|
|
9264
|
-
},
|
|
9265
|
-
output: OUTPUT$2,
|
|
9266
|
-
async execute(raw, exec) {
|
|
9267
|
-
const { root } = await workspaceOf(ctx, exec);
|
|
9268
|
-
const { units } = unitsOf(ctx, root);
|
|
9269
|
-
const found = unitAmong(units, raw, "workbench_diy_show");
|
|
9270
|
-
if (!found.installed) throw new Error(`${found.unit} 还没装 —— 只上板的前提是它装过了。先用 workbench_diy_install(第一次)`);
|
|
9271
|
-
const panel = showOrReason(panels, found.unit, root);
|
|
9272
|
-
const text = panel.ok ? `面板上已经打开它了(${root})—— 验收就走这一张卡(你自己走一遍)` : `面板上还没打开:${panel.reason}。这就是它的下一步(workbench_diy_status 会给出同样的判断)`;
|
|
9273
|
-
return plainJson({
|
|
9274
|
-
workspace: root,
|
|
9275
|
-
unit: found.unit,
|
|
9276
|
-
path: found.dir,
|
|
9277
|
-
panel,
|
|
9278
|
-
text
|
|
9279
|
-
});
|
|
9280
|
-
}
|
|
9281
|
-
};
|
|
9282
|
-
const installTool = {
|
|
9283
|
-
name: DIY_INSTALL_TOOL,
|
|
9284
|
-
description: "把这个工作区里造好的模块装上并上到当前工作区的面板。这是持久变更,一个模块只装一次:之后改源码只需 dsh-wb-module build(宿主侧秒级热换)。",
|
|
9285
|
-
parameters: {
|
|
9286
|
-
type: "object",
|
|
9287
|
-
properties: { unit: {
|
|
9288
|
-
type: "string",
|
|
9289
|
-
description: "模块 id(workbench_diy_status 会给)。"
|
|
9290
|
-
} },
|
|
9291
|
-
required: ["unit"],
|
|
9292
|
-
additionalProperties: false
|
|
9293
|
-
},
|
|
9294
|
-
output: OUTPUT$2,
|
|
9295
|
-
async execute(raw, exec) {
|
|
9296
|
-
const { root } = await workspaceOf(ctx, exec);
|
|
9297
|
-
const found = unitOf(root, raw, "workbench_diy_install");
|
|
9298
|
-
if (found.installed) {
|
|
9299
|
-
const panel = showOrReason(panels, found.unit, root);
|
|
9300
|
-
const text = ["它已经装过了(就是这个工作区里这一份)—— **不要再装**:改源码 + dsh-wb-module build(宿主侧与 client.js 都秒级热换 —— dsh-client-hmr 盯着每个 bundle 的 lib/client.js,重建了就换进已打开的页面)。", panel.ok ? `面板上已经打开它了(${root})—— 验收就走这一张卡(你自己走一遍)` : `面板上还没打开:${panel.reason}。调 workbench_diy_show(unit=${found.unit})`].join("\n");
|
|
9301
|
-
return plainJson({
|
|
9302
|
-
workspace: root,
|
|
9303
|
-
unit: found.unit,
|
|
9304
|
-
path: found.dir,
|
|
9305
|
-
alreadyInstalled: true,
|
|
9306
|
-
panel,
|
|
9307
|
-
text
|
|
9308
|
-
});
|
|
9309
|
-
}
|
|
9310
|
-
const outcome = await market.installBundle(found.dir);
|
|
9311
|
-
const verdict = verdictOf(outcome.change);
|
|
9312
|
-
const restartRequired = outcome.change.application === "restart-required";
|
|
9313
|
-
const panel = outcome.change.application === "applied" ? showOrReason(panels, found.unit, root) : {
|
|
9314
|
-
ok: false,
|
|
9315
|
-
reason: `安装结果是 ${outcome.change.application},还没生效`
|
|
9316
|
-
};
|
|
9317
|
-
const panelText = panel.ok ? `面板上已经打开它了(${root})—— 验收就走这一张卡(你自己走一遍)` : outcome.change.application === "applied" ? `面板上还没打开:${panel.reason}。调 workbench_diy_show(unit=${found.unit})试试。` : restartRequired ? `面板上还没打开(${panel.reason}):模块要**重启一次工作台**才注册进面板 —— 把这句话转给用户,重启后再调 workbench_diy_show(unit=${found.unit})。` : `面板上还没打开:${panel.reason}。先把上面那句"没装成"处理掉,再谈上板。`;
|
|
9318
|
-
const text = [
|
|
9319
|
-
`${verdict}:${found.unit}(${found.name})`,
|
|
9320
|
-
panelText,
|
|
9321
|
-
"之后只改源码 + dsh-wb-module build(宿主侧与 client.js 都秒级热换 —— dsh-client-hmr 盯着每个 bundle 的 lib/client.js,重建了就换进已打开的页面):不要再装一遍。"
|
|
9322
|
-
].join("\n");
|
|
9323
|
-
return plainJson({
|
|
9324
|
-
workspace: root,
|
|
9325
|
-
unit: found.unit,
|
|
9326
|
-
path: found.dir,
|
|
9327
|
-
install: outcome.change,
|
|
9328
|
-
module: outcome.module,
|
|
9329
|
-
panel,
|
|
9330
|
-
text
|
|
9331
|
-
});
|
|
9332
|
-
}
|
|
9333
|
-
};
|
|
9334
|
-
const publishTool = {
|
|
9335
|
-
name: DIY_PUBLISH_TOOL,
|
|
9336
|
-
description: "用户说“发布”后才用:把这一格发到 target 指定的出口(不填按环境默认)。",
|
|
9337
|
-
parameters: {
|
|
9338
|
-
type: "object",
|
|
9339
|
-
properties: {
|
|
9340
|
-
unit: {
|
|
9341
|
-
type: "string",
|
|
9342
|
-
description: "模块 id(workbench_diy_status 会给)。"
|
|
9343
|
-
},
|
|
9344
|
-
target: {
|
|
9345
|
-
type: "string",
|
|
9346
|
-
enum: [
|
|
9347
|
-
"team",
|
|
9348
|
-
"public",
|
|
9349
|
-
"tarball",
|
|
9350
|
-
"git",
|
|
9351
|
-
"market",
|
|
9352
|
-
"local"
|
|
9353
|
-
],
|
|
9354
|
-
description: "发到哪:团队源 / 公共 npm / 安装包 / git / 模块市场索引;不填按环境默认(有可写索引走市场,有私源走团队源,否则安装包)。"
|
|
9355
|
-
},
|
|
9356
|
-
version: {
|
|
9357
|
-
type: "string",
|
|
9358
|
-
description: "可选:patch / minor / major / x.y.z;不填首次用当前版本,之后自动 patch。"
|
|
9359
|
-
},
|
|
9360
|
-
verify: {
|
|
9361
|
-
type: "boolean",
|
|
9362
|
-
description: "只核已发布的包(交接验证码后用),不再发;不用审批。"
|
|
9363
|
-
},
|
|
9364
|
-
resume: {
|
|
9365
|
-
type: "boolean",
|
|
9366
|
-
description: "中断后接着发(用记录里的出口与版本)。"
|
|
9367
|
-
},
|
|
9368
|
-
license: {
|
|
9369
|
-
type: "string",
|
|
9370
|
-
description: "公开发布用的许可证(MIT / Apache-2.0 / 仓库已有 LICENSE)。"
|
|
9371
|
-
},
|
|
9372
|
-
author: {
|
|
9373
|
-
type: "string",
|
|
9374
|
-
description: "署谁的名(姓名,或 姓名 <邮箱>);用户点了名才传,不传按模块里写的,没写用推断的署名。"
|
|
9375
|
-
},
|
|
9376
|
-
refresh: {
|
|
9377
|
-
type: "boolean",
|
|
9378
|
-
description: "只刷市集元数据(标题/作者/说明),不升版本、不重发产物。"
|
|
9379
|
-
}
|
|
9380
|
-
},
|
|
9589
|
+
type: "string",
|
|
9590
|
+
description: "模块 id(workbench_diy_status 会给)。"
|
|
9591
|
+
} },
|
|
9381
9592
|
required: ["unit"],
|
|
9382
9593
|
additionalProperties: false
|
|
9383
9594
|
},
|
|
9384
|
-
output: OUTPUT$
|
|
9595
|
+
output: OUTPUT$3,
|
|
9385
9596
|
async execute(raw, exec) {
|
|
9386
9597
|
const { root } = await workspaceOf(ctx, exec);
|
|
9387
|
-
const
|
|
9388
|
-
const
|
|
9389
|
-
if (
|
|
9390
|
-
const
|
|
9391
|
-
|
|
9392
|
-
|
|
9393
|
-
|
|
9394
|
-
|
|
9395
|
-
|
|
9396
|
-
|
|
9397
|
-
|
|
9398
|
-
if (!verify && target !== "local" && author === "" && (previewOf(found.unit)?.author ?? "") === "") author = await inferredAuthorOf(found.unit) ?? "";
|
|
9399
|
-
const argv = [
|
|
9400
|
-
bin,
|
|
9401
|
-
"release",
|
|
9402
|
-
"--cwd",
|
|
9403
|
-
found.dir,
|
|
9404
|
-
"--json"
|
|
9405
|
-
];
|
|
9406
|
-
if (verify) argv.push("--verify");
|
|
9407
|
-
else argv.push("--yes");
|
|
9408
|
-
if (resume) argv.push("--resume");
|
|
9409
|
-
if (target !== "") argv.push("--target", target);
|
|
9410
|
-
if (version !== "") argv.push("--version", version);
|
|
9411
|
-
if (license !== "") argv.push("--license", license);
|
|
9412
|
-
if (author !== "") argv.push("--author", author);
|
|
9413
|
-
if (asRecord$1(raw)["refresh"] === true) argv.push("--refresh");
|
|
9414
|
-
const result = await runShell(shell, argv.map((one) => quoteShellArg(one)).join(" "), {
|
|
9415
|
-
workdir: root,
|
|
9416
|
-
timeoutMs: PUBLISH_TIMEOUT_MS
|
|
9598
|
+
const { units } = unitsOf(ctx, root);
|
|
9599
|
+
const found = unitAmong(units, raw, "workbench_diy_show");
|
|
9600
|
+
if (!found.installed) throw new Error(`${found.unit} 还没装 —— 只上板的前提是它装过了。先用 workbench_diy_install(第一次)`);
|
|
9601
|
+
const panel = showOrReason(panels, found.unit, root);
|
|
9602
|
+
const text = panel.ok ? `面板上已经打开它了(${root})—— 验收就走这一张卡(你自己走一遍)` : `面板上还没打开:${panel.reason}。这就是它的下一步(workbench_diy_status 会给出同样的判断)`;
|
|
9603
|
+
return plainJson({
|
|
9604
|
+
workspace: root,
|
|
9605
|
+
unit: found.unit,
|
|
9606
|
+
path: found.dir,
|
|
9607
|
+
panel,
|
|
9608
|
+
text
|
|
9417
9609
|
});
|
|
9418
|
-
|
|
9419
|
-
|
|
9420
|
-
|
|
9421
|
-
|
|
9422
|
-
|
|
9423
|
-
|
|
9424
|
-
|
|
9425
|
-
|
|
9426
|
-
|
|
9427
|
-
|
|
9428
|
-
|
|
9429
|
-
|
|
9430
|
-
|
|
9431
|
-
|
|
9432
|
-
|
|
9433
|
-
|
|
9610
|
+
}
|
|
9611
|
+
};
|
|
9612
|
+
const installTool = {
|
|
9613
|
+
name: DIY_INSTALL_TOOL,
|
|
9614
|
+
description: "把这个工作区里造好的模块装上并上到当前工作区的面板。这是持久变更,一个模块只装一次:之后改源码只需 dsh-wb-module build(宿主侧秒级热换)。",
|
|
9615
|
+
parameters: {
|
|
9616
|
+
type: "object",
|
|
9617
|
+
properties: { unit: {
|
|
9618
|
+
type: "string",
|
|
9619
|
+
description: "模块 id(workbench_diy_status 会给)。"
|
|
9620
|
+
} },
|
|
9621
|
+
required: ["unit"],
|
|
9622
|
+
additionalProperties: false
|
|
9623
|
+
},
|
|
9624
|
+
output: OUTPUT$3,
|
|
9625
|
+
async execute(raw, exec) {
|
|
9626
|
+
const { root } = await workspaceOf(ctx, exec);
|
|
9627
|
+
const found = unitOf(root, raw, "workbench_diy_install");
|
|
9628
|
+
if (found.installed) {
|
|
9629
|
+
const panel = showOrReason(panels, found.unit, root);
|
|
9630
|
+
const text = ["它已经装过了(就是这个工作区里这一份)—— **不要再装**:改源码 + dsh-wb-module build(宿主侧与 client.js 都秒级热换 —— dsh-client-hmr 盯着每个 bundle 的 lib/client.js,重建了就换进已打开的页面)。", panel.ok ? `面板上已经打开它了(${root})—— 验收就走这一张卡(你自己走一遍)` : `面板上还没打开:${panel.reason}。调 workbench_diy_show(unit=${found.unit})`].join("\n");
|
|
9434
9631
|
return plainJson({
|
|
9435
|
-
|
|
9436
|
-
|
|
9632
|
+
workspace: root,
|
|
9633
|
+
unit: found.unit,
|
|
9634
|
+
path: found.dir,
|
|
9635
|
+
alreadyInstalled: true,
|
|
9636
|
+
panel,
|
|
9637
|
+
text
|
|
9437
9638
|
});
|
|
9438
9639
|
}
|
|
9439
|
-
|
|
9440
|
-
|
|
9441
|
-
|
|
9442
|
-
|
|
9443
|
-
|
|
9444
|
-
|
|
9445
|
-
|
|
9446
|
-
const
|
|
9447
|
-
const
|
|
9448
|
-
|
|
9449
|
-
|
|
9450
|
-
|
|
9451
|
-
`已核过 ${name}@${released}`,
|
|
9452
|
-
`安装:${install}`,
|
|
9453
|
-
"没有重新发布。"
|
|
9454
|
-
].join("\n") : payload["refresh"] === true ? [payload["refreshed"] === true ? `已刷新 ${name} 的市集元数据(版本 ${released} 不变)` : `${name} 的市集元数据本来就是这样,没动`, `市场索引:${asText(asRecord$1(payload["market"])["url"])}`].join("\n") : targetOfPayload === "tarball" ? [
|
|
9455
|
-
`安装包在 ${file}`,
|
|
9456
|
-
`本机装:${install}`,
|
|
9457
|
-
"文件可以从对话里带走,发给同事。"
|
|
9458
|
-
].join("\n") : targetOfPayload === "git" ? [
|
|
9459
|
-
`已推到 ${asText(git["url"])}(tag ${asText(git["tag"])})`,
|
|
9460
|
-
`安装:${install}`,
|
|
9461
|
-
"已核过 tag 里的产物。"
|
|
9462
|
-
].join("\n") : targetOfPayload === "market" ? [
|
|
9463
|
-
`已发到市场索引 ${asText(asRecord$1(payload["market"])["url"])}`,
|
|
9464
|
-
`安装:${install}`,
|
|
9465
|
-
"已从索引仓库侧核过产物。"
|
|
9466
|
-
].join("\n") : targetOfPayload === "local" ? "没发,留在本机。" : [
|
|
9467
|
-
`已发布 ${name}@${released} → ${registry}`,
|
|
9468
|
-
`同事安装:${install}`,
|
|
9469
|
-
"包内容已经从源上核过(dist/host.js / client.js / cordis.patch.yml 都在)。"
|
|
9640
|
+
const outcome = await market.installBundle(found.dir);
|
|
9641
|
+
const verdict = verdictOf(outcome.change);
|
|
9642
|
+
const restartRequired = outcome.change.application === "restart-required";
|
|
9643
|
+
const panel = outcome.change.application === "applied" ? showOrReason(panels, found.unit, root) : {
|
|
9644
|
+
ok: false,
|
|
9645
|
+
reason: `安装结果是 ${outcome.change.application},还没生效`
|
|
9646
|
+
};
|
|
9647
|
+
const panelText = panel.ok ? `面板上已经打开它了(${root})—— 验收就走这一张卡(你自己走一遍)` : outcome.change.application === "applied" ? `面板上还没打开:${panel.reason}。调 workbench_diy_show(unit=${found.unit})试试。` : restartRequired ? `面板上还没打开(${panel.reason}):模块要**重启一次工作台**才注册进面板 —— 把这句话转给用户,重启后再调 workbench_diy_show(unit=${found.unit})。` : `面板上还没打开:${panel.reason}。先把上面那句"没装成"处理掉,再谈上板。`;
|
|
9648
|
+
const text = [
|
|
9649
|
+
`${verdict}:${found.unit}(${found.name})`,
|
|
9650
|
+
panelText,
|
|
9651
|
+
"之后只改源码 + dsh-wb-module build(宿主侧与 client.js 都秒级热换 —— dsh-client-hmr 盯着每个 bundle 的 lib/client.js,重建了就换进已打开的页面):不要再装一遍。"
|
|
9470
9652
|
].join("\n");
|
|
9471
9653
|
return plainJson({
|
|
9472
|
-
|
|
9654
|
+
workspace: root,
|
|
9655
|
+
unit: found.unit,
|
|
9656
|
+
path: found.dir,
|
|
9657
|
+
install: outcome.change,
|
|
9658
|
+
module: outcome.module,
|
|
9659
|
+
panel,
|
|
9473
9660
|
text
|
|
9474
9661
|
});
|
|
9475
9662
|
}
|
|
@@ -9480,13 +9667,16 @@ function registerDiyTools(ctx, market, panels, debug, previewOf = () => null, in
|
|
|
9480
9667
|
...registerComponentsTool(ctx, tools),
|
|
9481
9668
|
tools.register(reconTool),
|
|
9482
9669
|
...registerSpecTool(ctx, tools),
|
|
9483
|
-
...registerChangelogTool(ctx, tools),
|
|
9484
9670
|
...registerLogTools(ctx, tools),
|
|
9485
9671
|
...registerBrowserTools(ctx, tools),
|
|
9486
9672
|
...registerDebugTools(ctx, tools, debug),
|
|
9487
9673
|
tools.register(showTool),
|
|
9488
9674
|
tools.register(installTool),
|
|
9489
|
-
tools
|
|
9675
|
+
registerPublishTool(ctx, tools, {
|
|
9676
|
+
resolve: (root, raw) => unitOf(root, raw, "workbench_diy_publish"),
|
|
9677
|
+
previewOf,
|
|
9678
|
+
inferredAuthorOf
|
|
9679
|
+
})
|
|
9490
9680
|
];
|
|
9491
9681
|
}
|
|
9492
9682
|
//#endregion
|
|
@@ -9516,27 +9706,22 @@ function selectedGitSource() {
|
|
|
9516
9706
|
return parsed.source.policy === "artifacts-in-repo" ? parsed.source : void 0;
|
|
9517
9707
|
}
|
|
9518
9708
|
}
|
|
9519
|
-
|
|
9709
|
+
var EMPTY_INDEX = {
|
|
9710
|
+
format: 1,
|
|
9711
|
+
plugins: []
|
|
9712
|
+
};
|
|
9713
|
+
function publishedIndexOf(source) {
|
|
9520
9714
|
const file = join(workbenchRoot(), "market-index", marketSourceKey(source), "worktree", source.path ?? "market.json");
|
|
9521
9715
|
if (!existsSync(file)) return void 0;
|
|
9522
9716
|
try {
|
|
9523
9717
|
const parsed = parseMarketIndexJson(readFileSync(file, "utf8"));
|
|
9524
|
-
|
|
9525
|
-
const entry = parsed.index.plugins.find((one) => one.name === name);
|
|
9526
|
-
if (entry === void 0) return {
|
|
9527
|
-
versions: [],
|
|
9528
|
-
author: ""
|
|
9529
|
-
};
|
|
9530
|
-
return {
|
|
9531
|
-
versions: entry.versions.map((one) => one.version),
|
|
9532
|
-
author: typeof entry.author === "string" ? entry.author.trim() : ""
|
|
9533
|
-
};
|
|
9718
|
+
return parsed.ok ? parsed.index : void 0;
|
|
9534
9719
|
} catch {
|
|
9535
9720
|
return;
|
|
9536
9721
|
}
|
|
9537
9722
|
}
|
|
9538
|
-
function
|
|
9539
|
-
return
|
|
9723
|
+
function publishedEntryOf(index, name) {
|
|
9724
|
+
return index?.plugins.find((one) => one.name === name);
|
|
9540
9725
|
}
|
|
9541
9726
|
function bumped(version, kind) {
|
|
9542
9727
|
const match = SEMVER.exec(version);
|
|
@@ -9561,17 +9746,21 @@ function nextVersionOf(version, published) {
|
|
|
9561
9746
|
if (!exists(candidate)) return candidate;
|
|
9562
9747
|
}
|
|
9563
9748
|
}
|
|
9564
|
-
function marketOf(
|
|
9749
|
+
function marketOf(dir, name, version) {
|
|
9565
9750
|
const source = selectedGitSource();
|
|
9566
9751
|
if (source === void 0) return void 0;
|
|
9567
|
-
const
|
|
9752
|
+
const index = publishedIndexOf(source);
|
|
9753
|
+
const nextVersion = nextVersionOf(version, publishedEntryOf(index, name)?.versions.map((one) => one.version));
|
|
9568
9754
|
return {
|
|
9569
|
-
|
|
9570
|
-
|
|
9571
|
-
|
|
9572
|
-
|
|
9573
|
-
|
|
9574
|
-
|
|
9755
|
+
market: {
|
|
9756
|
+
url: source.url,
|
|
9757
|
+
...source.ref === void 0 ? {} : { ref: source.ref },
|
|
9758
|
+
indexPath: source.path ?? "market.json",
|
|
9759
|
+
artifactPath: marketArtifactPath(name),
|
|
9760
|
+
files: ARTIFACTS.filter((one) => existsSync(join(dir, one))),
|
|
9761
|
+
...nextVersion === void 0 ? {} : { nextVersion }
|
|
9762
|
+
},
|
|
9763
|
+
...index === void 0 ? {} : { index }
|
|
9575
9764
|
};
|
|
9576
9765
|
}
|
|
9577
9766
|
function moduleFactOf(root, unit) {
|
|
@@ -9630,7 +9819,7 @@ async function inferredAuthorOf(root, unit, shell) {
|
|
|
9630
9819
|
if (fact.author !== "") return fact.author;
|
|
9631
9820
|
const source = selectedGitSource();
|
|
9632
9821
|
if (source !== void 0 && fact.name !== "") {
|
|
9633
|
-
const published = publishedEntryOf(source, fact.name)?.author ?? "";
|
|
9822
|
+
const published = publishedEntryOf(publishedIndexOf(source), fact.name)?.author ?? "";
|
|
9634
9823
|
if (published !== "") return published;
|
|
9635
9824
|
}
|
|
9636
9825
|
const sibling = root === null || root === void 0 ? void 0 : siblingAuthorOf(root, unit);
|
|
@@ -9656,17 +9845,24 @@ function publishPreviewOf(root, unit, options = {}) {
|
|
|
9656
9845
|
if (name === "" || version === "") return null;
|
|
9657
9846
|
const publishConfig = record["publishConfig"];
|
|
9658
9847
|
const registry = typeof publishConfig === "object" && publishConfig !== null ? publishConfig["registry"] : void 0;
|
|
9659
|
-
const market = marketOf(found.
|
|
9660
|
-
const target = targetVersionOf(version, (options.version ?? "").trim(), market);
|
|
9848
|
+
const market = marketOf(found.dir, name, version);
|
|
9849
|
+
const target = targetVersionOf(version, (options.version ?? "").trim(), market?.market);
|
|
9661
9850
|
const askedAuthor = (options.author ?? "").trim();
|
|
9662
9851
|
const author = askedAuthor === "" ? authorOf(record) : askedAuthor;
|
|
9852
|
+
const claim = market === void 0 ? void 0 : claimOf(market.index ?? EMPTY_INDEX, {
|
|
9853
|
+
name,
|
|
9854
|
+
publisher: author,
|
|
9855
|
+
unit,
|
|
9856
|
+
artifactPath: marketArtifactPath(name)
|
|
9857
|
+
});
|
|
9663
9858
|
return {
|
|
9664
9859
|
name,
|
|
9665
9860
|
version,
|
|
9666
9861
|
...author === "" ? {} : { author },
|
|
9667
9862
|
...typeof registry === "string" && registry !== "" ? { registry } : {},
|
|
9668
|
-
...market === void 0 ? {} : { market },
|
|
9669
|
-
|
|
9863
|
+
...market === void 0 ? {} : { market: market.market },
|
|
9864
|
+
...claim === void 0 ? {} : { claim },
|
|
9865
|
+
changelog: changelogOf(found.dir, target, (options.changelog ?? "").trim(), kindOf(options.changelogType))
|
|
9670
9866
|
};
|
|
9671
9867
|
}
|
|
9672
9868
|
function authorOf(manifest) {
|
|
@@ -9684,13 +9880,30 @@ function targetVersionOf(version, asked, market) {
|
|
|
9684
9880
|
if (/^(major|minor|patch)$/.test(asked)) return bumped(version, asked) ?? version;
|
|
9685
9881
|
return asked;
|
|
9686
9882
|
}
|
|
9687
|
-
function
|
|
9883
|
+
function kindOf(given) {
|
|
9884
|
+
const wanted = (given ?? "").trim();
|
|
9885
|
+
return CHANGELOG_KINDS.includes(wanted) ? wanted : "changed";
|
|
9886
|
+
}
|
|
9887
|
+
function changelogOf(dir, version, note, kind) {
|
|
9688
9888
|
let text;
|
|
9689
9889
|
try {
|
|
9690
9890
|
text = readFileSync(join(dir, CHANGELOG_FILE), "utf8");
|
|
9691
9891
|
} catch {
|
|
9692
9892
|
text = void 0;
|
|
9693
9893
|
}
|
|
9894
|
+
if (note !== "") {
|
|
9895
|
+
const plan = planChangelog(text ?? "", {
|
|
9896
|
+
version,
|
|
9897
|
+
kind,
|
|
9898
|
+
note,
|
|
9899
|
+
date: changelogDate()
|
|
9900
|
+
});
|
|
9901
|
+
if (plan !== void 0) return {
|
|
9902
|
+
version: plan.version,
|
|
9903
|
+
text: plan.section,
|
|
9904
|
+
...plan.action === "written" ? { pending: true } : {}
|
|
9905
|
+
};
|
|
9906
|
+
}
|
|
9694
9907
|
if (text === void 0 || !changelogHasEntry(text, version)) return {
|
|
9695
9908
|
version,
|
|
9696
9909
|
missing: true
|
|
@@ -11013,7 +11226,7 @@ function registerRecordTools(ctx, store) {
|
|
|
11013
11226
|
required: ["url"],
|
|
11014
11227
|
additionalProperties: false
|
|
11015
11228
|
},
|
|
11016
|
-
output: OUTPUT$
|
|
11229
|
+
output: OUTPUT$3,
|
|
11017
11230
|
async execute(raw, exec) {
|
|
11018
11231
|
const { root } = await workspaceOf(ctx, exec);
|
|
11019
11232
|
const artifactsDir = artifactsDirOf(ctx, root);
|
|
@@ -11113,7 +11326,7 @@ function registerRecordTools(ctx, store) {
|
|
|
11113
11326
|
} },
|
|
11114
11327
|
additionalProperties: false
|
|
11115
11328
|
},
|
|
11116
|
-
output: OUTPUT$
|
|
11329
|
+
output: OUTPUT$3,
|
|
11117
11330
|
async execute(raw, exec) {
|
|
11118
11331
|
const shell = ctx.get("shell");
|
|
11119
11332
|
if (shell === void 0) throw new Error("这台机器上没有 shell 服务,读不了录制");
|
|
@@ -11243,7 +11456,7 @@ function registerRecordTools(ctx, store) {
|
|
|
11243
11456
|
},
|
|
11244
11457
|
additionalProperties: false
|
|
11245
11458
|
},
|
|
11246
|
-
output: OUTPUT$
|
|
11459
|
+
output: OUTPUT$3,
|
|
11247
11460
|
async execute(raw, exec) {
|
|
11248
11461
|
const { root } = await workspaceOf(ctx, exec);
|
|
11249
11462
|
const artifactsDir = artifactsDirOf(ctx, root);
|
|
@@ -11325,7 +11538,7 @@ function registerRecordTools(ctx, store) {
|
|
|
11325
11538
|
properties: {},
|
|
11326
11539
|
additionalProperties: false
|
|
11327
11540
|
},
|
|
11328
|
-
output: OUTPUT$
|
|
11541
|
+
output: OUTPUT$3,
|
|
11329
11542
|
async execute(_raw, exec) {
|
|
11330
11543
|
const shell = ctx.get("shell");
|
|
11331
11544
|
if (shell === void 0) throw new Error("这台机器上没有 shell 服务,收不了工");
|
|
@@ -12566,6 +12779,7 @@ function normalizedRepo(value) {
|
|
|
12566
12779
|
return value.trim().replace(/^git\+/, "").replace(/\.git$/, "").toLowerCase();
|
|
12567
12780
|
}
|
|
12568
12781
|
function isWorkbenchEntry(entry) {
|
|
12782
|
+
if (entry.metadata?.workbench === true) return true;
|
|
12569
12783
|
const labels = marketEntryLabels(entry);
|
|
12570
12784
|
if (labels.includes("workbench")) return true;
|
|
12571
12785
|
return entry.metadata?.category === "workbench" && labels.length === 0;
|
|
@@ -12823,37 +13037,66 @@ function parseMarketSourcesAction(payload) {
|
|
|
12823
13037
|
id: id.trim()
|
|
12824
13038
|
};
|
|
12825
13039
|
}
|
|
13040
|
+
if (action === "read-only") {
|
|
13041
|
+
const id = record["id"];
|
|
13042
|
+
if (typeof id !== "string" || id.trim() === "") throw new Error("read-only 需要 id");
|
|
13043
|
+
return {
|
|
13044
|
+
action,
|
|
13045
|
+
id: id.trim()
|
|
13046
|
+
};
|
|
13047
|
+
}
|
|
12826
13048
|
if (action === "init") {
|
|
12827
13049
|
const id = record["id"];
|
|
12828
13050
|
if (typeof id !== "string" || id.trim() === "") throw new Error("init 需要 id");
|
|
12829
13051
|
const ref = typeof record["ref"] === "string" ? record["ref"].trim() : "";
|
|
12830
13052
|
if (ref !== "" && !marketBranchOk(ref)) throw new Error(`分支名不合格:${ref}`);
|
|
13053
|
+
const stampOnly = record["stampOnly"] === true;
|
|
12831
13054
|
return {
|
|
12832
13055
|
action,
|
|
12833
13056
|
id: id.trim(),
|
|
12834
|
-
...ref === "" ? {} : { ref }
|
|
13057
|
+
...ref === "" ? {} : { ref },
|
|
13058
|
+
...stampOnly ? { stampOnly } : {}
|
|
12835
13059
|
};
|
|
12836
13060
|
}
|
|
12837
13061
|
throw new Error(`不认识的索引源动作:${String(action)}`);
|
|
12838
13062
|
}
|
|
13063
|
+
async function markSourceReadOnly(store, id) {
|
|
13064
|
+
const source = store.read().sources.find((one) => one.id === id);
|
|
13065
|
+
if (source === void 0) throw new Error("这个索引源已经不在了 —— 刷新后再试");
|
|
13066
|
+
if (source.kind !== "git") throw new Error("http 索引源本来就是只读");
|
|
13067
|
+
const next = {
|
|
13068
|
+
...source,
|
|
13069
|
+
policy: "catalog-only"
|
|
13070
|
+
};
|
|
13071
|
+
if (source.policy !== "catalog-only") await store.apply({
|
|
13072
|
+
action: "save",
|
|
13073
|
+
source: next
|
|
13074
|
+
});
|
|
13075
|
+
return next;
|
|
13076
|
+
}
|
|
12839
13077
|
function marketSourcesAction(store, init) {
|
|
12840
13078
|
return {
|
|
12841
13079
|
resource: MARKET_SOURCES_RESOURCE,
|
|
12842
13080
|
async handle(payload) {
|
|
12843
13081
|
const action = parseMarketSourcesAction(payload);
|
|
13082
|
+
if (action.action === "read-only") {
|
|
13083
|
+
const source = await markSourceReadOnly(store, action.id);
|
|
13084
|
+
return {
|
|
13085
|
+
ok: true,
|
|
13086
|
+
...store.read(),
|
|
13087
|
+
source
|
|
13088
|
+
};
|
|
13089
|
+
}
|
|
12844
13090
|
if (action.action === "init") {
|
|
12845
13091
|
if (init === void 0) throw new Error("这台机器上没有 shell 服务,初始化不了索引仓库");
|
|
12846
13092
|
const result = await init({
|
|
12847
13093
|
id: action.id,
|
|
12848
|
-
...action.ref === void 0 ? {} : { ref: action.ref }
|
|
13094
|
+
...action.ref === void 0 ? {} : { ref: action.ref },
|
|
13095
|
+
...action.stampOnly === true ? { stampOnly: true } : {}
|
|
12849
13096
|
});
|
|
12850
13097
|
return {
|
|
12851
13098
|
ok: true,
|
|
12852
|
-
...
|
|
12853
|
-
action: "save",
|
|
12854
|
-
source: result.source,
|
|
12855
|
-
select: true
|
|
12856
|
-
}),
|
|
13099
|
+
...store.read(),
|
|
12857
13100
|
branch: result.branch,
|
|
12858
13101
|
commit: result.commit,
|
|
12859
13102
|
created: result.created
|
|
@@ -12873,20 +13116,29 @@ function publishPreviewRoutes(workshop, inferredAuthorOf = async () => void 0) {
|
|
|
12873
13116
|
const unit = (param(search, "unit") ?? "").trim();
|
|
12874
13117
|
const version = (param(search, "version") ?? "").trim();
|
|
12875
13118
|
const author = (param(search, "author") ?? "").trim();
|
|
13119
|
+
const changelog = param(search, "changelog") ?? "";
|
|
13120
|
+
const changelogType = (param(search, "changelogType") ?? "").trim();
|
|
12876
13121
|
if (unit === "") return {
|
|
12877
13122
|
ok: true,
|
|
12878
13123
|
preview: null
|
|
12879
13124
|
};
|
|
12880
13125
|
let preview = publishPreviewOf(workshop, unit, {
|
|
12881
13126
|
version,
|
|
12882
|
-
author
|
|
13127
|
+
author,
|
|
13128
|
+
changelog,
|
|
13129
|
+
changelogType
|
|
12883
13130
|
});
|
|
12884
13131
|
if (preview !== null && author === "" && (preview.author === void 0 || preview.author === "")) {
|
|
12885
13132
|
const inferred = await inferredAuthorOf(unit);
|
|
12886
|
-
if (inferred !== void 0 && inferred !== "")
|
|
12887
|
-
|
|
12888
|
-
|
|
12889
|
-
|
|
13133
|
+
if (inferred !== void 0 && inferred !== "") {
|
|
13134
|
+
const again = publishPreviewOf(workshop, unit, {
|
|
13135
|
+
version,
|
|
13136
|
+
author: inferred,
|
|
13137
|
+
changelog,
|
|
13138
|
+
changelogType
|
|
13139
|
+
});
|
|
13140
|
+
if (again !== null) preview = again;
|
|
13141
|
+
}
|
|
12890
13142
|
}
|
|
12891
13143
|
return {
|
|
12892
13144
|
ok: true,
|
|
@@ -12899,7 +13151,6 @@ function publishPreviewRoutes(workshop, inferredAuthorOf = async () => void 0) {
|
|
|
12899
13151
|
var DEFAULT_TTL_MS = 3e5;
|
|
12900
13152
|
var DEFAULT_TIMEOUT_MS$2 = 3e4;
|
|
12901
13153
|
var DEFAULT_MAX_BYTES$1 = 4194304;
|
|
12902
|
-
var GIT_NO_PROMPT = `${quoteShellArg("env")} GIT_TERMINAL_PROMPT=0`;
|
|
12903
13154
|
function messageOf$1(error) {
|
|
12904
13155
|
return error instanceof Error ? error.message : String(error);
|
|
12905
13156
|
}
|
|
@@ -12961,7 +13212,7 @@ function gitProblemOf(source) {
|
|
|
12961
13212
|
};
|
|
12962
13213
|
}
|
|
12963
13214
|
function tail(text) {
|
|
12964
|
-
return text
|
|
13215
|
+
return withoutAskpassNoise(text).split("\n").filter((line) => line !== "").slice(-3).join(" ");
|
|
12965
13216
|
}
|
|
12966
13217
|
function classifyGitError(stderr, timedOut) {
|
|
12967
13218
|
if (timedOut) return {
|
|
@@ -13065,7 +13316,7 @@ function createMarketIndexReader(options) {
|
|
|
13065
13316
|
}
|
|
13066
13317
|
};
|
|
13067
13318
|
try {
|
|
13068
|
-
const result = await runShell(shell, `${
|
|
13319
|
+
const result = await runShell(shell, `${gitNoPromptPrefix()} ${line}`, { timeoutMs });
|
|
13069
13320
|
if (result.exitCode !== 0) return {
|
|
13070
13321
|
ok: false,
|
|
13071
13322
|
problem: classifyGitError(result.stderr, result.timedOut),
|
|
@@ -13513,17 +13764,21 @@ function createMarketSourceInitializer(options) {
|
|
|
13513
13764
|
if (created.exitCode !== 0) throw new Error(`建分支 ${branch} 没过:${tailLines(created.stderr, 4)}`);
|
|
13514
13765
|
}
|
|
13515
13766
|
const indexPath = (source.path ?? "market.json").replace(/^\/+/, "") || "market.json";
|
|
13516
|
-
const written = [];
|
|
13517
13767
|
const indexFile = join(workdir, indexPath);
|
|
13518
|
-
|
|
13519
|
-
|
|
13520
|
-
|
|
13521
|
-
|
|
13522
|
-
|
|
13523
|
-
|
|
13524
|
-
|
|
13525
|
-
|
|
13526
|
-
|
|
13768
|
+
const stampOnly = request.stampOnly === true;
|
|
13769
|
+
if (stampOnly && !existsSync(indexFile)) throw new Error(`仓库里还没有 ${indexPath} —— 先选中这个源,按发现页的提示把它初始化成索引`);
|
|
13770
|
+
const written = [];
|
|
13771
|
+
if (!stampOnly) {
|
|
13772
|
+
if (!existsSync(indexFile)) {
|
|
13773
|
+
mkdirSync(dirname(indexFile), { recursive: true });
|
|
13774
|
+
writeFileSync(indexFile, MARKET_INDEX_SEED);
|
|
13775
|
+
written.push(indexPath);
|
|
13776
|
+
}
|
|
13777
|
+
const readmeFile = join(workdir, "README.md");
|
|
13778
|
+
if (!existsSync(readmeFile)) {
|
|
13779
|
+
writeFileSync(readmeFile, MARKET_INDEX_README_LINES.join("\n"));
|
|
13780
|
+
written.push("README.md");
|
|
13781
|
+
}
|
|
13527
13782
|
}
|
|
13528
13783
|
if (written.length > 0) {
|
|
13529
13784
|
const added = await git(["add", ...written], workdir);
|
|
@@ -13550,8 +13805,7 @@ function createMarketSourceInitializer(options) {
|
|
|
13550
13805
|
};
|
|
13551
13806
|
await options.store.apply({
|
|
13552
13807
|
action: "save",
|
|
13553
|
-
source: next
|
|
13554
|
-
select: true
|
|
13808
|
+
source: next
|
|
13555
13809
|
});
|
|
13556
13810
|
forget(source, next);
|
|
13557
13811
|
return {
|
|
@@ -13678,6 +13932,73 @@ async function dispatchMarket(market, request) {
|
|
|
13678
13932
|
};
|
|
13679
13933
|
}
|
|
13680
13934
|
//#endregion
|
|
13935
|
+
//#region src/modules/panels/model/market-sources-tool.ts
|
|
13936
|
+
var OUTPUT$2 = {
|
|
13937
|
+
schema: {
|
|
13938
|
+
type: "object",
|
|
13939
|
+
properties: {
|
|
13940
|
+
text: { type: "string" },
|
|
13941
|
+
sources: {
|
|
13942
|
+
type: "array",
|
|
13943
|
+
items: {
|
|
13944
|
+
type: "object",
|
|
13945
|
+
additionalProperties: true
|
|
13946
|
+
}
|
|
13947
|
+
}
|
|
13948
|
+
},
|
|
13949
|
+
additionalProperties: true
|
|
13950
|
+
},
|
|
13951
|
+
render: (_args, value) => {
|
|
13952
|
+
const payload = value;
|
|
13953
|
+
return [{
|
|
13954
|
+
type: "text",
|
|
13955
|
+
text: typeof payload?.text === "string" ? payload.text : JSON.stringify(value)
|
|
13956
|
+
}];
|
|
13957
|
+
}
|
|
13958
|
+
};
|
|
13959
|
+
function marketSourcesTool(read) {
|
|
13960
|
+
return {
|
|
13961
|
+
name: MARKET_SOURCES_TOOL,
|
|
13962
|
+
description: "看本机的索引源:id、地址、是否可发布、当前用的是哪个。",
|
|
13963
|
+
parameters: {
|
|
13964
|
+
type: "object",
|
|
13965
|
+
properties: {},
|
|
13966
|
+
additionalProperties: false
|
|
13967
|
+
},
|
|
13968
|
+
output: OUTPUT$2,
|
|
13969
|
+
async execute() {
|
|
13970
|
+
if (read === void 0) throw new Error("这台机器上没有索引源服务,看不了");
|
|
13971
|
+
const payload = read();
|
|
13972
|
+
const rows = payload.sources.map((source) => ({
|
|
13973
|
+
id: source.id,
|
|
13974
|
+
label: source.label,
|
|
13975
|
+
kind: source.kind,
|
|
13976
|
+
url: source.url,
|
|
13977
|
+
policy: source.policy ?? "catalog-only",
|
|
13978
|
+
ref: source.ref ?? null,
|
|
13979
|
+
path: source.path ?? null,
|
|
13980
|
+
selected: source.id === payload.selected
|
|
13981
|
+
}));
|
|
13982
|
+
if (rows.length === 0) return {
|
|
13983
|
+
sources: rows,
|
|
13984
|
+
selected: payload.selected,
|
|
13985
|
+
text: "这台机器还没有索引源 —— 在「模块市场 → 发现 → 索引源」里加一个。"
|
|
13986
|
+
};
|
|
13987
|
+
const current = rows.find((one) => one.selected);
|
|
13988
|
+
const head = current === void 0 ? "当前没有选中索引源" : `当前:${current.label}(${current.url})`;
|
|
13989
|
+
const lines = rows.map((one) => {
|
|
13990
|
+
const state = one.policy === "artifacts-in-repo" ? "可发布" : "仅读取模块列表";
|
|
13991
|
+
return `${one.selected ? "●" : "○"} ${one.id} · ${one.label} · ${one.kind} · ${state} · ${one.url}`;
|
|
13992
|
+
});
|
|
13993
|
+
return {
|
|
13994
|
+
sources: rows,
|
|
13995
|
+
selected: payload.selected,
|
|
13996
|
+
text: [head, ...lines].join("\n")
|
|
13997
|
+
};
|
|
13998
|
+
}
|
|
13999
|
+
};
|
|
14000
|
+
}
|
|
14001
|
+
//#endregion
|
|
13681
14002
|
//#region src/modules/panels/model/market-tools.ts
|
|
13682
14003
|
function supplyNamesOf(entry) {
|
|
13683
14004
|
return entry.needs.filter((need) => need.kind === "extension" || need.kind === "lib").map((need) => need.name);
|
|
@@ -13773,7 +14094,7 @@ function usersOf(shared, names) {
|
|
|
13773
14094
|
if (hit === void 0 || hit.usedBy.length === 0) return "";
|
|
13774
14095
|
return `它被 ${hit.usedBy.join("、")} 用着(动的是它们的供给,它们的状态跟着重探了一遍)`;
|
|
13775
14096
|
}
|
|
13776
|
-
function registerMarketTools(ctx, market) {
|
|
14097
|
+
function registerMarketTools(ctx, market, sources) {
|
|
13777
14098
|
const tools = ctx.get("tools");
|
|
13778
14099
|
if (tools === void 0) {
|
|
13779
14100
|
ctx.logger?.info?.("[dsh-workbench] 没有 tools 服务,跳过模块市场工具注册");
|
|
@@ -13972,6 +14293,82 @@ function registerMarketTools(ctx, market) {
|
|
|
13972
14293
|
};
|
|
13973
14294
|
}
|
|
13974
14295
|
};
|
|
14296
|
+
const enableTool = {
|
|
14297
|
+
name: MARKET_ENABLE_TOOL,
|
|
14298
|
+
description: "把索引源设为可发布(只改本机配置,不碰仓库);要用户审批。",
|
|
14299
|
+
parameters: {
|
|
14300
|
+
type: "object",
|
|
14301
|
+
properties: { id: {
|
|
14302
|
+
type: "string",
|
|
14303
|
+
description: "索引源 id;不填=当前选中的那个。"
|
|
14304
|
+
} },
|
|
14305
|
+
additionalProperties: false
|
|
14306
|
+
},
|
|
14307
|
+
output: OUTPUT$1,
|
|
14308
|
+
async execute(raw) {
|
|
14309
|
+
if (sources === void 0) throw new Error("这台机器上没有索引源服务,设不了可发布");
|
|
14310
|
+
const payload = sources.read();
|
|
14311
|
+
const asked = textArg(raw, "id");
|
|
14312
|
+
const id = asked === "" ? payload.selected : asked;
|
|
14313
|
+
const source = id === null ? void 0 : payload.sources.find((one) => one.id === id);
|
|
14314
|
+
if (source === void 0) {
|
|
14315
|
+
const known = payload.sources.map((one) => one.id).join("、") || "(空)";
|
|
14316
|
+
throw new Error(`没有这个索引源${asked === "" ? "" : `:${asked}`}。现有的:${known};先在「模块市场 → 发现 → 索引源」里加一个。`);
|
|
14317
|
+
}
|
|
14318
|
+
if (source.kind !== "git") throw new Error(`索引源 ${source.id} 是 http 地址,只能读,不能当发布目的地`);
|
|
14319
|
+
if (source.policy === "artifacts-in-repo") return {
|
|
14320
|
+
source,
|
|
14321
|
+
changed: false,
|
|
14322
|
+
text: `已经是可发布:${source.label}(${source.url})`
|
|
14323
|
+
};
|
|
14324
|
+
const result = await sources.init({
|
|
14325
|
+
id: source.id,
|
|
14326
|
+
stampOnly: true
|
|
14327
|
+
});
|
|
14328
|
+
return {
|
|
14329
|
+
source: result.source,
|
|
14330
|
+
branch: result.branch,
|
|
14331
|
+
commit: result.commit,
|
|
14332
|
+
changed: true,
|
|
14333
|
+
text: `已把「${source.label}」设为可发布(${source.url},分支 ${result.branch})—— 仓库本身没动。之后发布可以落到它的 ${source.path ?? "market.json"}。`
|
|
14334
|
+
};
|
|
14335
|
+
}
|
|
14336
|
+
};
|
|
14337
|
+
const readOnlyTool = {
|
|
14338
|
+
name: MARKET_DISABLE_TOOL,
|
|
14339
|
+
description: "把索引源改回只读(不再作为发布目的地;只改本机配置)。",
|
|
14340
|
+
parameters: {
|
|
14341
|
+
type: "object",
|
|
14342
|
+
properties: { id: {
|
|
14343
|
+
type: "string",
|
|
14344
|
+
description: "索引源 id;不填=当前选中的那个。"
|
|
14345
|
+
} },
|
|
14346
|
+
additionalProperties: false
|
|
14347
|
+
},
|
|
14348
|
+
output: OUTPUT$1,
|
|
14349
|
+
async execute(raw) {
|
|
14350
|
+
if (sources === void 0) throw new Error("这台机器上没有索引源服务,改不了");
|
|
14351
|
+
const payload = sources.read();
|
|
14352
|
+
const asked = textArg(raw, "id");
|
|
14353
|
+
const id = asked === "" ? payload.selected : asked;
|
|
14354
|
+
const source = id === null ? void 0 : payload.sources.find((one) => one.id === id);
|
|
14355
|
+
if (source === void 0) {
|
|
14356
|
+
const known = payload.sources.map((one) => one.id).join("、") || "(空)";
|
|
14357
|
+
throw new Error(`没有这个索引源${asked === "" ? "" : `:${asked}`}。现有的:${known};先在「模块市场 → 发现 → 索引源」里加一个。`);
|
|
14358
|
+
}
|
|
14359
|
+
if (source.kind !== "git") throw new Error(`索引源 ${source.id} 是 http 地址,本来就是只读`);
|
|
14360
|
+
if (source.policy === "catalog-only") return {
|
|
14361
|
+
source,
|
|
14362
|
+
changed: false,
|
|
14363
|
+
text: `已经是只读:${source.label}(${source.url})`
|
|
14364
|
+
};
|
|
14365
|
+
return {
|
|
14366
|
+
source: await sources.readOnly(source.id),
|
|
14367
|
+
changed: true,
|
|
14368
|
+
text: `已把「${source.label}」设为只读(${source.url})—— 发布不会再落到它。`
|
|
14369
|
+
};
|
|
14370
|
+
}
|
|
14371
|
+
};
|
|
13975
14372
|
return [
|
|
13976
14373
|
tools.register(listTool),
|
|
13977
14374
|
tools.register(installTool),
|
|
@@ -13981,7 +14378,10 @@ function registerMarketTools(ctx, market) {
|
|
|
13981
14378
|
tools.register(updateDependencyTool),
|
|
13982
14379
|
tools.register(updatePluginTool),
|
|
13983
14380
|
tools.register(uninstallPluginTool),
|
|
13984
|
-
tools.register(updateWorkbenchTool)
|
|
14381
|
+
tools.register(updateWorkbenchTool),
|
|
14382
|
+
tools.register(marketSourcesTool(sources === void 0 ? void 0 : () => sources.read())),
|
|
14383
|
+
tools.register(enableTool),
|
|
14384
|
+
tools.register(readOnlyTool)
|
|
13985
14385
|
];
|
|
13986
14386
|
}
|
|
13987
14387
|
//#endregion
|
|
@@ -14099,6 +14499,7 @@ function listedRunUnits(result) {
|
|
|
14099
14499
|
}
|
|
14100
14500
|
function panelsFactsOf(call, manifests) {
|
|
14101
14501
|
if (call.source === "workbench_panels_list") return [PANELS_FACT];
|
|
14502
|
+
if (call.source === "market-sources") return [PANELS_FACT];
|
|
14102
14503
|
if (call.source === "workbench_long_tasks_list") return listedRunUnits(call.result).map(runsRouteOf);
|
|
14103
14504
|
if (call.source === "workbench_modules_list") return [PANELS_FACT, CAPABILITY_FACT];
|
|
14104
14505
|
if (call.source === "workbench_modules_update_workbench") return [PANELS_FACT, CAPABILITY_FACT];
|
|
@@ -14793,13 +15194,17 @@ var OWNED = [{
|
|
|
14793
15194
|
},
|
|
14794
15195
|
registerTools: () => [
|
|
14795
15196
|
...registerPanelTools(ctx, panels, values),
|
|
14796
|
-
...registerMarketTools(ctx, market
|
|
15197
|
+
...registerMarketTools(ctx, market, {
|
|
15198
|
+
read: () => marketSources.read(),
|
|
15199
|
+
init: marketInit,
|
|
15200
|
+
readOnly: (id) => markSourceReadOnly(marketSources, id)
|
|
15201
|
+
}),
|
|
14797
15202
|
...registerDiyTools(ctx, market, panels, debug, (unit) => publishPreviewOf(workshopPathOf(ctx), unit), (unit) => inferredAuthorOf(workshopPathOf(ctx), unit, shell)),
|
|
14798
15203
|
...registerRecordTools(ctx, record),
|
|
14799
15204
|
...registerLongTaskTools(ctx, longTaskRuns)
|
|
14800
15205
|
],
|
|
14801
15206
|
factsOf: (call) => panelsFactsOf(call, manifests()),
|
|
14802
|
-
needsApproval: panelsApprovalFor(longTaskRuns, () => record.live(Date.now()), (unit) => publishPreviewOf(workshopPathOf(ctx), unit)),
|
|
15207
|
+
needsApproval: panelsApprovalFor(longTaskRuns, () => record.live(Date.now()), (unit, author) => publishPreviewOf(workshopPathOf(ctx), unit, author === void 0 ? {} : { author }), marketSources),
|
|
14803
15208
|
gate: {
|
|
14804
15209
|
deniedTools: (context) => {
|
|
14805
15210
|
const boards = panels.boards(context.workspace);
|