@dsh-workbench/core 1.1.9 → 1.1.10
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 +3 -3
- package/client.js +196 -163
- package/dist/client/client.body.js +196 -163
- package/dist/client/index.js +196 -163
- package/dist/host/index.js +196 -112
- package/dist/types/app/layouts/env-gate/gate-text.d.ts +1 -0
- package/dist/types/app/layouts/market/discover-view.d.ts +1 -0
- package/dist/types/app/layouts/sidebar/workspace-groups.d.ts +1 -1
- package/dist/types/modules/panels/model/market-discover.d.ts +1 -0
- package/dist/types/shared/api/host/diy-publish-preview.d.ts +4 -4
- package/dist/types/shared/api/host/git-exec.d.ts +1 -0
- package/dist/types/shared/api/host/git-probe.d.ts +6 -6
- package/dist/types/shared/api/host/git-process.d.ts +13 -0
- package/dist/types/shared/api/host/git-routes.d.ts +5 -2
- package/dist/types/shared/api/host/market-doc.d.ts +2 -2
- package/dist/types/shared/api/host/market-index-fetch.d.ts +2 -2
- package/dist/types/shared/api/host/market-source-init.d.ts +2 -2
- package/package.json +3 -3
package/dist/host/index.js
CHANGED
|
@@ -8,8 +8,8 @@ import { createHash, randomUUID } from "node:crypto";
|
|
|
8
8
|
import { isDeepStrictEqual } from "node:util";
|
|
9
9
|
import { createRequire } from "node:module";
|
|
10
10
|
import writeFileAtomic from "write-file-atomic";
|
|
11
|
-
import { deflateSync, inflateSync } from "node:zlib";
|
|
12
11
|
import { execa } from "execa";
|
|
12
|
+
import { deflateSync, inflateSync } from "node:zlib";
|
|
13
13
|
//#region \0rolldown/runtime.js
|
|
14
14
|
var __create = Object.create;
|
|
15
15
|
var __defProp = Object.defineProperty;
|
|
@@ -842,7 +842,7 @@ function refusalReason() {
|
|
|
842
842
|
}
|
|
843
843
|
//#endregion
|
|
844
844
|
//#region ../shared/dist/host/shell.js
|
|
845
|
-
var DEFAULT_MAX_BYTES$
|
|
845
|
+
var DEFAULT_MAX_BYTES$3 = 8388608;
|
|
846
846
|
async function runShell(shell, command, options = {}) {
|
|
847
847
|
const { workdir, timeoutMs = GIT_TIMEOUT_MS, signal } = options;
|
|
848
848
|
const spec = shell.resolve({
|
|
@@ -850,7 +850,7 @@ async function runShell(shell, command, options = {}) {
|
|
|
850
850
|
...workdir === void 0 ? {} : { workdir },
|
|
851
851
|
timeoutMs,
|
|
852
852
|
onExpiry: "kill",
|
|
853
|
-
stdoutMaxBytes: DEFAULT_MAX_BYTES$
|
|
853
|
+
stdoutMaxBytes: DEFAULT_MAX_BYTES$3,
|
|
854
854
|
...signal === void 0 ? {} : { signal }
|
|
855
855
|
});
|
|
856
856
|
const result = await (await shell.execute(spec)).result();
|
|
@@ -4597,7 +4597,7 @@ function approvalNoteOf(call) {
|
|
|
4597
4597
|
if (line === "") return void 0;
|
|
4598
4598
|
return line.length > 40 ? `${line.slice(0, 40)}…` : line;
|
|
4599
4599
|
}
|
|
4600
|
-
function messageOf$
|
|
4600
|
+
function messageOf$3(error) {
|
|
4601
4601
|
return error instanceof Error ? error.message : String(error);
|
|
4602
4602
|
}
|
|
4603
4603
|
function compose(detail, verdict, note) {
|
|
@@ -4622,7 +4622,7 @@ async function approvalFor(call, context = {}) {
|
|
|
4622
4622
|
} catch (error) {
|
|
4623
4623
|
return {
|
|
4624
4624
|
kind: "deny",
|
|
4625
|
-
reason: `问"要不要审批"的时候套件的策略抛了错,已经停下:${messageOf$
|
|
4625
|
+
reason: `问"要不要审批"的时候套件的策略抛了错,已经停下:${messageOf$3(error)}`
|
|
4626
4626
|
};
|
|
4627
4627
|
}
|
|
4628
4628
|
if (verdict?.kind === "read" || verdict?.kind === "allow") return void 0;
|
|
@@ -4640,7 +4640,7 @@ async function approvalFor(call, context = {}) {
|
|
|
4640
4640
|
} catch (error) {
|
|
4641
4641
|
return {
|
|
4642
4642
|
kind: "deny",
|
|
4643
|
-
reason: `拿不到"这次会发生什么",已经停下:${messageOf$
|
|
4643
|
+
reason: `拿不到"这次会发生什么",已经停下:${messageOf$3(error)}`
|
|
4644
4644
|
};
|
|
4645
4645
|
}
|
|
4646
4646
|
if (facts !== void 0 && "blocked" in facts) return {
|
|
@@ -6754,21 +6754,42 @@ function bundleInspectHandler(ctx) {
|
|
|
6754
6754
|
}
|
|
6755
6755
|
//#endregion
|
|
6756
6756
|
//#region src/shared/api/host/git-exec.ts
|
|
6757
|
-
var
|
|
6758
|
-
"
|
|
6759
|
-
"
|
|
6760
|
-
"
|
|
6761
|
-
"
|
|
6762
|
-
"
|
|
6763
|
-
"
|
|
6764
|
-
|
|
6765
|
-
function gitNoPromptPrefix() {
|
|
6766
|
-
return [quoteShellArg("env"), ...NO_PROMPT_ENV.map((one) => quoteShellArg(one))].join(" ");
|
|
6767
|
-
}
|
|
6757
|
+
var GIT_NO_PROMPT_ENV = {
|
|
6758
|
+
GIT_TERMINAL_PROMPT: "0",
|
|
6759
|
+
GIT_ASKPASS: "/usr/bin/false",
|
|
6760
|
+
SSH_ASKPASS: "/usr/bin/false",
|
|
6761
|
+
SSH_ASKPASS_REQUIRE: "never",
|
|
6762
|
+
GCM_INTERACTIVE: "never",
|
|
6763
|
+
GIT_SSH_COMMAND: "ssh -o BatchMode=yes -o StrictHostKeyChecking=accept-new"
|
|
6764
|
+
};
|
|
6768
6765
|
function withoutAskpassNoise(text) {
|
|
6769
6766
|
return text.split("\n").filter((line) => !/unable to read askpass response/i.test(line)).join("\n").trim();
|
|
6770
6767
|
}
|
|
6771
6768
|
//#endregion
|
|
6769
|
+
//#region src/shared/api/host/git-process.ts
|
|
6770
|
+
var DEFAULT_MAX_BYTES$2 = 8388608;
|
|
6771
|
+
var runGitProcess = async (args, options = {}) => {
|
|
6772
|
+
const result = await execa("git", [...args], {
|
|
6773
|
+
...options.cwd === void 0 ? {} : { cwd: options.cwd },
|
|
6774
|
+
env: {
|
|
6775
|
+
...process.env,
|
|
6776
|
+
...GIT_NO_PROMPT_ENV
|
|
6777
|
+
},
|
|
6778
|
+
stdin: "ignore",
|
|
6779
|
+
reject: false,
|
|
6780
|
+
...options.timeoutMs === void 0 ? {} : { timeout: options.timeoutMs },
|
|
6781
|
+
killSignal: "SIGKILL",
|
|
6782
|
+
maxBuffer: options.maxBytes ?? DEFAULT_MAX_BYTES$2,
|
|
6783
|
+
stripFinalNewline: false
|
|
6784
|
+
});
|
|
6785
|
+
return {
|
|
6786
|
+
exitCode: result.exitCode ?? null,
|
|
6787
|
+
stdout: result.stdout ?? "",
|
|
6788
|
+
stderr: result.stderr ?? "",
|
|
6789
|
+
timedOut: result.timedOut === true
|
|
6790
|
+
};
|
|
6791
|
+
};
|
|
6792
|
+
//#endregion
|
|
6772
6793
|
//#region src/shared/api/host/git-probe.ts
|
|
6773
6794
|
var PROBE_TIMEOUT_MS = 1e4;
|
|
6774
6795
|
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/;
|
|
@@ -6776,17 +6797,15 @@ function classifyGitProbe(stderr, timedOut) {
|
|
|
6776
6797
|
if (timedOut) return "unreachable";
|
|
6777
6798
|
return AUTH_TEXT.test(stderr.toLowerCase()) ? "auth" : "unreachable";
|
|
6778
6799
|
}
|
|
6779
|
-
async function probeGitAddress(
|
|
6780
|
-
const
|
|
6781
|
-
gitNoPromptPrefix(),
|
|
6782
|
-
quoteShellArg("git"),
|
|
6783
|
-
quoteShellArg("ls-remote"),
|
|
6784
|
-
quoteShellArg(url),
|
|
6785
|
-
quoteShellArg("HEAD")
|
|
6786
|
-
].join(" ");
|
|
6800
|
+
async function probeGitAddress(url, options = {}) {
|
|
6801
|
+
const runGit = options.runGit ?? runGitProcess;
|
|
6787
6802
|
let result;
|
|
6788
6803
|
try {
|
|
6789
|
-
result = await
|
|
6804
|
+
result = await runGit([
|
|
6805
|
+
"ls-remote",
|
|
6806
|
+
url,
|
|
6807
|
+
"HEAD"
|
|
6808
|
+
], { timeoutMs: options.timeoutMs ?? PROBE_TIMEOUT_MS });
|
|
6790
6809
|
} catch (error) {
|
|
6791
6810
|
return {
|
|
6792
6811
|
status: "unreachable",
|
|
@@ -6802,10 +6821,10 @@ async function probeGitAddress(shell, url, options = {}) {
|
|
|
6802
6821
|
}
|
|
6803
6822
|
var PROBE_CACHE_MS = 6e4;
|
|
6804
6823
|
var probeCache = /* @__PURE__ */ new Map();
|
|
6805
|
-
async function probeGitAddressCached(
|
|
6824
|
+
async function probeGitAddressCached(url, options = {}) {
|
|
6806
6825
|
const hit = probeCache.get(url);
|
|
6807
6826
|
if (hit !== void 0 && Date.now() - hit.at < PROBE_CACHE_MS) return hit.payload;
|
|
6808
|
-
const payload = await probeGitAddress(
|
|
6827
|
+
const payload = await probeGitAddress(url, options);
|
|
6809
6828
|
probeCache.set(url, {
|
|
6810
6829
|
at: Date.now(),
|
|
6811
6830
|
payload
|
|
@@ -6814,7 +6833,7 @@ async function probeGitAddressCached(shell, url, options = {}) {
|
|
|
6814
6833
|
}
|
|
6815
6834
|
//#endregion
|
|
6816
6835
|
//#region src/shared/api/host/git-routes.ts
|
|
6817
|
-
function gitProbeHandler(
|
|
6836
|
+
function gitProbeHandler(options = {}) {
|
|
6818
6837
|
return async (search) => {
|
|
6819
6838
|
const url = param(search, "url");
|
|
6820
6839
|
if (url === void 0) return {
|
|
@@ -6824,17 +6843,9 @@ function gitProbeHandler(ctx) {
|
|
|
6824
6843
|
message: "要探哪个地址?缺 url。"
|
|
6825
6844
|
}
|
|
6826
6845
|
};
|
|
6827
|
-
const shell = ctx.get("shell");
|
|
6828
|
-
if (shell === void 0) return {
|
|
6829
|
-
ok: false,
|
|
6830
|
-
error: {
|
|
6831
|
-
code: "workbench/no-shell",
|
|
6832
|
-
message: "这台机器上没有执行缝,探不了 git 地址"
|
|
6833
|
-
}
|
|
6834
|
-
};
|
|
6835
6846
|
return {
|
|
6836
6847
|
ok: true,
|
|
6837
|
-
...await probeGitAddress(
|
|
6848
|
+
...await probeGitAddress(url, options)
|
|
6838
6849
|
};
|
|
6839
6850
|
};
|
|
6840
6851
|
}
|
|
@@ -6848,7 +6859,7 @@ function createHostRoutes(input) {
|
|
|
6848
6859
|
[DSH_PLUGINS_ROUTE]: profile.dshPlugins(ctx),
|
|
6849
6860
|
[BUNDLE_REGISTRIES_ROUTE]: bundleRegistriesHandler(ctx),
|
|
6850
6861
|
[BUNDLE_INSPECT_ROUTE]: bundleInspectHandler(ctx),
|
|
6851
|
-
[MARKET_GIT_PROBE_ROUTE]: gitProbeHandler(
|
|
6862
|
+
[MARKET_GIT_PROBE_ROUTE]: gitProbeHandler(),
|
|
6852
6863
|
[MODULE_VERSIONS_ROUTE]: moduleVersionsHandler(ctx, ctx.get("shell"), running, () => profile.selfUpdateView(dshHome(), basename(profile.dirOf(ctx) ?? "")))
|
|
6853
6864
|
};
|
|
6854
6865
|
}
|
|
@@ -11096,24 +11107,34 @@ function siblingAuthorOf(root, unit) {
|
|
|
11096
11107
|
}
|
|
11097
11108
|
return authors.size === 1 ? [...authors][0] : void 0;
|
|
11098
11109
|
}
|
|
11099
|
-
async function localGitIdentityOf(
|
|
11100
|
-
|
|
11101
|
-
|
|
11102
|
-
|
|
11103
|
-
|
|
11110
|
+
async function localGitIdentityOf(dir, runGit = runGitProcess) {
|
|
11111
|
+
const read = async (args) => {
|
|
11112
|
+
try {
|
|
11113
|
+
const result = await runGit(args, { cwd: dir });
|
|
11114
|
+
return result.exitCode === 0 ? result.stdout.trim() : "";
|
|
11115
|
+
} catch {
|
|
11116
|
+
return "";
|
|
11117
|
+
}
|
|
11104
11118
|
};
|
|
11105
|
-
const name = await read(
|
|
11119
|
+
const name = await read(["config", "user.name"]);
|
|
11106
11120
|
if (name === "") return void 0;
|
|
11107
|
-
const email = await read(
|
|
11121
|
+
const email = await read(["config", "user.email"]);
|
|
11108
11122
|
return email === "" ? name : `${name} <${email}>`;
|
|
11109
11123
|
}
|
|
11110
|
-
async function lastCommitAuthorOf(
|
|
11111
|
-
|
|
11112
|
-
|
|
11113
|
-
|
|
11114
|
-
|
|
11124
|
+
async function lastCommitAuthorOf(dir, runGit = runGitProcess) {
|
|
11125
|
+
try {
|
|
11126
|
+
const result = await runGit([
|
|
11127
|
+
"log",
|
|
11128
|
+
"-1",
|
|
11129
|
+
"--format=%an <%ae>"
|
|
11130
|
+
], { cwd: dir });
|
|
11131
|
+
const author = result.exitCode === 0 ? result.stdout.trim() : "";
|
|
11132
|
+
return author === "" ? void 0 : author;
|
|
11133
|
+
} catch {
|
|
11134
|
+
return;
|
|
11135
|
+
}
|
|
11115
11136
|
}
|
|
11116
|
-
async function inferredAuthorOf(root, unit,
|
|
11137
|
+
async function inferredAuthorOf(root, unit, runGit = runGitProcess) {
|
|
11117
11138
|
const fact = moduleFactOf(root, unit);
|
|
11118
11139
|
if (fact === null) return void 0;
|
|
11119
11140
|
if (fact.author !== "") return fact.author;
|
|
@@ -11124,9 +11145,9 @@ async function inferredAuthorOf(root, unit, shell) {
|
|
|
11124
11145
|
}
|
|
11125
11146
|
const sibling = root === null || root === void 0 ? void 0 : siblingAuthorOf(root, unit);
|
|
11126
11147
|
if (sibling !== void 0) return sibling;
|
|
11127
|
-
const local = await localGitIdentityOf(
|
|
11148
|
+
const local = await localGitIdentityOf(fact.dir, runGit);
|
|
11128
11149
|
if (local !== void 0) return local;
|
|
11129
|
-
return lastCommitAuthorOf(
|
|
11150
|
+
return lastCommitAuthorOf(fact.dir, runGit);
|
|
11130
11151
|
}
|
|
11131
11152
|
function publishPreviewOf(root, unit, options = {}) {
|
|
11132
11153
|
if (root === null || root === void 0 || unit === "") return null;
|
|
@@ -14325,6 +14346,20 @@ function createMarketService(options) {
|
|
|
14325
14346
|
}
|
|
14326
14347
|
//#endregion
|
|
14327
14348
|
//#region src/modules/panels/model/market-discover.ts
|
|
14349
|
+
var SANDBOX_BLOCK = [
|
|
14350
|
+
"- id: sandbox-policy",
|
|
14351
|
+
" config:",
|
|
14352
|
+
" mode: !!js process.env.DSH_PERMISSION_MODE ?? 'workspace-write'",
|
|
14353
|
+
" workspaceRoot: !!js dshHomePath('workbench')"
|
|
14354
|
+
].join("\n");
|
|
14355
|
+
function explainProblem(problem, profilePath) {
|
|
14356
|
+
if (problem.kind !== "sandbox" || profilePath === void 0 || profilePath === "") return problem;
|
|
14357
|
+
const file = join(profilePath, "cordis.patch.yml");
|
|
14358
|
+
return {
|
|
14359
|
+
...problem,
|
|
14360
|
+
detail: `被系统拦住了:这个 profile 的可写根盖不住工作台的缓存目录。\n退出 dsh 后,把下面这段加进 ${file},再启动:\n${SANDBOX_BLOCK}`
|
|
14361
|
+
};
|
|
14362
|
+
}
|
|
14328
14363
|
var DEFAULT_PEER_TTL_MS = 6e5;
|
|
14329
14364
|
var DEFAULT_TIMEOUT_MS$3 = 15e3;
|
|
14330
14365
|
var CORE_PEER = "@dsh-workbench/core";
|
|
@@ -14476,12 +14511,12 @@ function createMarketDiscover(options) {
|
|
|
14476
14511
|
sources: rows,
|
|
14477
14512
|
selected: source.id,
|
|
14478
14513
|
entries: [],
|
|
14479
|
-
problem: read.problem
|
|
14514
|
+
problem: explainProblem(read.problem, options.profilePath)
|
|
14480
14515
|
};
|
|
14481
14516
|
return {
|
|
14482
14517
|
...await payloadOf(source, read.cached.index, rows, source.id, filter, read.cached.fetchedAt, read.cached.commit),
|
|
14483
14518
|
stale: true,
|
|
14484
|
-
problem: read.problem
|
|
14519
|
+
problem: explainProblem(read.problem, options.profilePath)
|
|
14485
14520
|
};
|
|
14486
14521
|
}
|
|
14487
14522
|
return payloadOf(source, read.index, rows, source.id, filter, read.fetchedAt, read.commit);
|
|
@@ -14784,7 +14819,7 @@ function publishPreviewRoutes(workshop, inferredAuthorOf = async () => void 0) {
|
|
|
14784
14819
|
var DEFAULT_TTL_MS = 3e5;
|
|
14785
14820
|
var DEFAULT_TIMEOUT_MS$2 = 3e4;
|
|
14786
14821
|
var DEFAULT_MAX_BYTES$1 = 4194304;
|
|
14787
|
-
function messageOf$
|
|
14822
|
+
function messageOf$2(error) {
|
|
14788
14823
|
return error instanceof Error ? error.message : String(error);
|
|
14789
14824
|
}
|
|
14790
14825
|
function directoryOf(root, source) {
|
|
@@ -14853,6 +14888,10 @@ function classifyGitError(stderr, timedOut) {
|
|
|
14853
14888
|
detail: "git 拉取超时"
|
|
14854
14889
|
};
|
|
14855
14890
|
const text = stderr.toLowerCase();
|
|
14891
|
+
if (text.includes("operation not permitted") || /\beperm\b/.test(text)) return {
|
|
14892
|
+
kind: "sandbox",
|
|
14893
|
+
detail: "被系统拦住了:这个 profile 的可写根盖不住工作台的缓存目录"
|
|
14894
|
+
};
|
|
14856
14895
|
if (/couldn'?t find remote ref\s+["']?head/.test(text) || /could not find remote ref\s+["']?head/.test(text)) return {
|
|
14857
14896
|
kind: "git-empty",
|
|
14858
14897
|
detail: "仓库还没有任何提交"
|
|
@@ -14880,6 +14919,7 @@ function createMarketIndexReader(options) {
|
|
|
14880
14919
|
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS$2;
|
|
14881
14920
|
const maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES$1;
|
|
14882
14921
|
const fetchImpl = options.fetchImpl ?? globalThis.fetch;
|
|
14922
|
+
const runGit = options.runGit ?? runGitProcess;
|
|
14883
14923
|
const inFlight = /* @__PURE__ */ new Map();
|
|
14884
14924
|
async function readHttp(source) {
|
|
14885
14925
|
const bad = httpProblemOf(source.url);
|
|
@@ -14902,7 +14942,7 @@ function createMarketIndexReader(options) {
|
|
|
14902
14942
|
detail: `拉索引超过 ${String(Math.round(timeoutMs / 1e3))} 秒`
|
|
14903
14943
|
} : {
|
|
14904
14944
|
kind: "http-network",
|
|
14905
|
-
detail: messageOf$
|
|
14945
|
+
detail: messageOf$2(error)
|
|
14906
14946
|
}
|
|
14907
14947
|
};
|
|
14908
14948
|
}
|
|
@@ -14939,17 +14979,13 @@ function createMarketIndexReader(options) {
|
|
|
14939
14979
|
fetchedAt
|
|
14940
14980
|
};
|
|
14941
14981
|
}
|
|
14942
|
-
async function run(
|
|
14943
|
-
const shell = options.shell;
|
|
14944
|
-
if (shell === void 0) return {
|
|
14945
|
-
ok: false,
|
|
14946
|
-
problem: {
|
|
14947
|
-
kind: "git-missing",
|
|
14948
|
-
detail: "没有执行缝,读不了 git 索引"
|
|
14949
|
-
}
|
|
14950
|
-
};
|
|
14982
|
+
async function run(args, cwd) {
|
|
14951
14983
|
try {
|
|
14952
|
-
const result = await
|
|
14984
|
+
const result = await runGit(args, {
|
|
14985
|
+
...cwd === void 0 ? {} : { cwd },
|
|
14986
|
+
timeoutMs,
|
|
14987
|
+
maxBytes
|
|
14988
|
+
});
|
|
14953
14989
|
if (result.exitCode !== 0) return {
|
|
14954
14990
|
ok: false,
|
|
14955
14991
|
problem: classifyGitError(result.stderr, result.timedOut),
|
|
@@ -14960,7 +14996,7 @@ function createMarketIndexReader(options) {
|
|
|
14960
14996
|
stdout: result.stdout
|
|
14961
14997
|
};
|
|
14962
14998
|
} catch (error) {
|
|
14963
|
-
const text = messageOf$
|
|
14999
|
+
const text = messageOf$2(error);
|
|
14964
15000
|
if (/not found|no such file|ENOENT/i.test(text)) return {
|
|
14965
15001
|
ok: false,
|
|
14966
15002
|
problem: {
|
|
@@ -14978,7 +15014,11 @@ function createMarketIndexReader(options) {
|
|
|
14978
15014
|
}
|
|
14979
15015
|
}
|
|
14980
15016
|
async function branchOf(repo) {
|
|
14981
|
-
const result = await run(
|
|
15017
|
+
const result = await run([
|
|
15018
|
+
"symbolic-ref",
|
|
15019
|
+
"--short",
|
|
15020
|
+
"HEAD"
|
|
15021
|
+
], repo);
|
|
14982
15022
|
const branch = result.ok ? result.stdout.trim() : "";
|
|
14983
15023
|
return branch === "" ? void 0 : branch;
|
|
14984
15024
|
}
|
|
@@ -14999,20 +15039,21 @@ function createMarketIndexReader(options) {
|
|
|
14999
15039
|
ok: false,
|
|
15000
15040
|
problem: bad
|
|
15001
15041
|
};
|
|
15002
|
-
if (options.shell === void 0) return {
|
|
15003
|
-
ok: false,
|
|
15004
|
-
problem: {
|
|
15005
|
-
kind: "git-missing",
|
|
15006
|
-
detail: "没有 git 执行缝"
|
|
15007
|
-
}
|
|
15008
|
-
};
|
|
15009
15042
|
const repo = repoOf(options.root, source);
|
|
15010
15043
|
const path = ((source.path ?? "market").replace(/^\/+/, "") || "market").replace(/\/+$/, "");
|
|
15011
15044
|
const ref = (source.ref ?? "").trim();
|
|
15012
15045
|
let revision = "FETCH_HEAD";
|
|
15013
15046
|
mkdirSync(directoryOf(options.root, source), { recursive: true });
|
|
15014
15047
|
if (!existsSync(repo)) {
|
|
15015
|
-
const cloned = await run(
|
|
15048
|
+
const cloned = await run([
|
|
15049
|
+
"clone",
|
|
15050
|
+
"--bare",
|
|
15051
|
+
"--depth",
|
|
15052
|
+
"1",
|
|
15053
|
+
...ref === "" ? [] : ["--branch", ref],
|
|
15054
|
+
source.url,
|
|
15055
|
+
repo
|
|
15056
|
+
]);
|
|
15016
15057
|
if (!cloned.ok) {
|
|
15017
15058
|
rmSync(repo, {
|
|
15018
15059
|
recursive: true,
|
|
@@ -15022,17 +15063,27 @@ function createMarketIndexReader(options) {
|
|
|
15022
15063
|
}
|
|
15023
15064
|
revision = "HEAD";
|
|
15024
15065
|
} else {
|
|
15025
|
-
const fetched = await run(
|
|
15066
|
+
const fetched = await run([
|
|
15067
|
+
"fetch",
|
|
15068
|
+
"--depth",
|
|
15069
|
+
"1",
|
|
15070
|
+
"origin",
|
|
15071
|
+
ref === "" ? "HEAD" : ref
|
|
15072
|
+
], repo);
|
|
15026
15073
|
if (!fetched.ok) return withBranch(fetched, repo);
|
|
15027
15074
|
}
|
|
15028
|
-
if (!(await run(
|
|
15075
|
+
if (!(await run([
|
|
15076
|
+
"rev-parse",
|
|
15077
|
+
"--verify",
|
|
15078
|
+
"HEAD"
|
|
15079
|
+
], repo)).ok) return withBranch({
|
|
15029
15080
|
ok: false,
|
|
15030
15081
|
problem: {
|
|
15031
15082
|
kind: "git-empty",
|
|
15032
15083
|
detail: "仓库还没有任何提交"
|
|
15033
15084
|
}
|
|
15034
15085
|
}, repo);
|
|
15035
|
-
const head = await run(
|
|
15086
|
+
const head = await run(["rev-parse", revision], repo);
|
|
15036
15087
|
if (!head.ok) return head;
|
|
15037
15088
|
const commit = head.stdout.trim();
|
|
15038
15089
|
if (!/^[0-9a-f]{40}$/.test(commit)) return {
|
|
@@ -15042,7 +15093,13 @@ function createMarketIndexReader(options) {
|
|
|
15042
15093
|
detail: `读到的 commit 不是 40 位:${commit}`
|
|
15043
15094
|
}
|
|
15044
15095
|
};
|
|
15045
|
-
const listed = await run(
|
|
15096
|
+
const listed = await run([
|
|
15097
|
+
"ls-tree",
|
|
15098
|
+
"-r",
|
|
15099
|
+
commit,
|
|
15100
|
+
"--",
|
|
15101
|
+
path
|
|
15102
|
+
], repo);
|
|
15046
15103
|
if (!listed.ok) {
|
|
15047
15104
|
if (listed.problem.kind === "git-file") return withBranch({
|
|
15048
15105
|
ok: false,
|
|
@@ -15078,7 +15135,7 @@ function createMarketIndexReader(options) {
|
|
|
15078
15135
|
};
|
|
15079
15136
|
};
|
|
15080
15137
|
const readLegacy = async (file) => {
|
|
15081
|
-
const shown = await run(
|
|
15138
|
+
const shown = await run(["show", `${commit}:${file}`], repo);
|
|
15082
15139
|
if (!shown.ok) return void 0;
|
|
15083
15140
|
const parsed = parseMarketIndexJson(shown.stdout);
|
|
15084
15141
|
if (!parsed.ok) return {
|
|
@@ -15102,7 +15159,7 @@ function createMarketIndexReader(options) {
|
|
|
15102
15159
|
for (;;) {
|
|
15103
15160
|
const next = queue.shift();
|
|
15104
15161
|
if (next === void 0 || failed !== void 0) return;
|
|
15105
|
-
const shown = await run(
|
|
15162
|
+
const shown = await run(["show", `${commit}:${next.file}`], repo);
|
|
15106
15163
|
if (!shown.ok) {
|
|
15107
15164
|
failed = shown;
|
|
15108
15165
|
return;
|
|
@@ -15155,7 +15212,7 @@ function createMarketIndexReader(options) {
|
|
|
15155
15212
|
ok: false,
|
|
15156
15213
|
problem: {
|
|
15157
15214
|
kind: "unknown",
|
|
15158
|
-
detail: messageOf$
|
|
15215
|
+
detail: messageOf$2(error)
|
|
15159
15216
|
}
|
|
15160
15217
|
})).then((result) => {
|
|
15161
15218
|
if (result.ok) return result;
|
|
@@ -15184,7 +15241,7 @@ var FILES = {
|
|
|
15184
15241
|
var DEFAULT_TIMEOUT_MS$1 = 15e3;
|
|
15185
15242
|
var DEFAULT_MAX_BYTES = 204800;
|
|
15186
15243
|
var DEFAULT_REGISTRY = "https://registry.npmjs.org";
|
|
15187
|
-
function messageOf(error) {
|
|
15244
|
+
function messageOf$1(error) {
|
|
15188
15245
|
return error instanceof Error ? error.message : String(error);
|
|
15189
15246
|
}
|
|
15190
15247
|
function clipped(text, maxBytes) {
|
|
@@ -15199,6 +15256,7 @@ function createMarketDocReader(options) {
|
|
|
15199
15256
|
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS$1;
|
|
15200
15257
|
const maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES;
|
|
15201
15258
|
const fetchImpl = options.fetchImpl ?? globalThis.fetch;
|
|
15259
|
+
const runGit = options.runGit ?? runGitProcess;
|
|
15202
15260
|
const cache = /* @__PURE__ */ new Map();
|
|
15203
15261
|
function fail(kind, version, reason, detail) {
|
|
15204
15262
|
return {
|
|
@@ -15216,22 +15274,40 @@ function createMarketDocReader(options) {
|
|
|
15216
15274
|
async function readGit(source, target, kind) {
|
|
15217
15275
|
const git = target.source;
|
|
15218
15276
|
if (git.type !== "git") return fail(kind, target.version, "missing");
|
|
15219
|
-
const shell = options.shell;
|
|
15220
|
-
if (shell === void 0) return fail(kind, target.version, "unavailable", "没有 git 执行缝");
|
|
15221
15277
|
const key = `${git.commit}|${git.path ?? ""}|${kind}`;
|
|
15222
15278
|
const cached = cache.get(key);
|
|
15223
15279
|
if (cached !== void 0) return cached;
|
|
15224
15280
|
const directory = (git.path ?? "").replace(/^\/+|\/+$/g, "");
|
|
15225
15281
|
const file = directory === "" ? FILES[kind] : `${directory}/${FILES[kind]}`;
|
|
15226
15282
|
const repo = join(options.root, "market-index", marketSourceKey(source), "repo.git");
|
|
15227
|
-
const show = () =>
|
|
15283
|
+
const show = () => runGit(["show", `${git.commit}:${file}`], {
|
|
15284
|
+
cwd: repo,
|
|
15285
|
+
timeoutMs,
|
|
15286
|
+
maxBytes
|
|
15287
|
+
});
|
|
15228
15288
|
const hasCommit = async () => {
|
|
15229
|
-
return (await
|
|
15289
|
+
return (await runGit([
|
|
15290
|
+
"cat-file",
|
|
15291
|
+
"-e",
|
|
15292
|
+
`${git.commit}^{commit}`
|
|
15293
|
+
], {
|
|
15294
|
+
cwd: repo,
|
|
15295
|
+
timeoutMs
|
|
15296
|
+
})).exitCode === 0;
|
|
15230
15297
|
};
|
|
15231
15298
|
try {
|
|
15232
15299
|
let result = await show();
|
|
15233
15300
|
if (result.exitCode !== 0 && !await hasCommit()) {
|
|
15234
|
-
if ((await
|
|
15301
|
+
if ((await runGit([
|
|
15302
|
+
"fetch",
|
|
15303
|
+
"--depth",
|
|
15304
|
+
"1",
|
|
15305
|
+
"origin",
|
|
15306
|
+
git.commit
|
|
15307
|
+
], {
|
|
15308
|
+
cwd: repo,
|
|
15309
|
+
timeoutMs
|
|
15310
|
+
})).exitCode === 0) result = await show();
|
|
15235
15311
|
}
|
|
15236
15312
|
if (result.exitCode !== 0) {
|
|
15237
15313
|
const text = result.stderr.trim();
|
|
@@ -15244,8 +15320,8 @@ function createMarketDocReader(options) {
|
|
|
15244
15320
|
text: clipped(result.stdout, maxBytes)
|
|
15245
15321
|
});
|
|
15246
15322
|
} catch (error) {
|
|
15247
|
-
options.logger?.warn?.(`[dsh-workbench] 读 ${file} 失败:${messageOf(error)}`);
|
|
15248
|
-
return fail(kind, target.version, "unavailable", messageOf(error));
|
|
15323
|
+
options.logger?.warn?.(`[dsh-workbench] 读 ${file} 失败:${messageOf$1(error)}`);
|
|
15324
|
+
return fail(kind, target.version, "unavailable", messageOf$1(error));
|
|
15249
15325
|
}
|
|
15250
15326
|
}
|
|
15251
15327
|
async function readNpm(target, kind) {
|
|
@@ -15271,8 +15347,8 @@ function createMarketDocReader(options) {
|
|
|
15271
15347
|
text: clipped(text, maxBytes)
|
|
15272
15348
|
});
|
|
15273
15349
|
} catch (error) {
|
|
15274
|
-
options.logger?.warn?.(`[dsh-workbench] 读 ${target.name} 的说明失败:${messageOf(error)}`);
|
|
15275
|
-
return fail(kind, target.version, "unavailable", messageOf(error));
|
|
15350
|
+
options.logger?.warn?.(`[dsh-workbench] 读 ${target.name} 的说明失败:${messageOf$1(error)}`);
|
|
15351
|
+
return fail(kind, target.version, "unavailable", messageOf$1(error));
|
|
15276
15352
|
}
|
|
15277
15353
|
}
|
|
15278
15354
|
return { read: (source, target, kind) => target.source.type === "git" ? readGit(source, target, kind) : readNpm(target, kind) };
|
|
@@ -15391,8 +15467,17 @@ var CACHE_FILES = [
|
|
|
15391
15467
|
"index.json",
|
|
15392
15468
|
"meta.json"
|
|
15393
15469
|
];
|
|
15470
|
+
function messageOf(error) {
|
|
15471
|
+
return error instanceof Error ? error.message : String(error);
|
|
15472
|
+
}
|
|
15473
|
+
var SANDBOX_TEXT = "被系统拦住了:这个 profile 的可写根盖不住工作台的缓存目录";
|
|
15474
|
+
function sandboxBlocked(text) {
|
|
15475
|
+
const lower = text.toLowerCase();
|
|
15476
|
+
return lower.includes("operation not permitted") || /\beperm\b/.test(lower);
|
|
15477
|
+
}
|
|
15394
15478
|
function createMarketSourceInitializer(options) {
|
|
15395
15479
|
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
15480
|
+
const runGit = options.runGit ?? runGitProcess;
|
|
15396
15481
|
function forget(source, next) {
|
|
15397
15482
|
const base = join(options.root, "market-index");
|
|
15398
15483
|
const oldKey = marketSourceKey(source);
|
|
@@ -15415,22 +15500,22 @@ function createMarketSourceInitializer(options) {
|
|
|
15415
15500
|
});
|
|
15416
15501
|
}
|
|
15417
15502
|
return async (request) => {
|
|
15418
|
-
const shell = options.shell;
|
|
15419
|
-
if (shell === void 0) throw new Error("这台机器上没有 shell 服务,初始化不了索引仓库");
|
|
15420
15503
|
const source = options.store.read().sources.find((one) => one.id === request.id);
|
|
15421
15504
|
if (source === void 0) throw new Error("这个索引源已经不在了 —— 刷新后再试");
|
|
15422
15505
|
if (source.kind !== "git") throw new Error("只有 git 仓库能初始化成市场索引");
|
|
15423
15506
|
if (!gitUrlOk(source.url)) throw new Error(`这个 git 地址不合格:${source.url}`);
|
|
15424
15507
|
const asked = (request.ref ?? "").trim();
|
|
15425
15508
|
if (asked !== "" && !marketBranchOk(asked)) throw new Error(`分支名不合格:${asked}`);
|
|
15426
|
-
const git = (
|
|
15427
|
-
|
|
15428
|
-
|
|
15429
|
-
|
|
15430
|
-
|
|
15431
|
-
|
|
15432
|
-
|
|
15433
|
-
|
|
15509
|
+
const git = async (args, workdir) => {
|
|
15510
|
+
try {
|
|
15511
|
+
return await runGit(args, {
|
|
15512
|
+
...workdir === void 0 ? {} : { cwd: workdir },
|
|
15513
|
+
timeoutMs
|
|
15514
|
+
});
|
|
15515
|
+
} catch (error) {
|
|
15516
|
+
throw new Error(`git 跑不起来:${messageOf(error)}`, { cause: error });
|
|
15517
|
+
}
|
|
15518
|
+
};
|
|
15434
15519
|
const workdir = join(options.root, "market-index", marketSourceKey(source), "worktree");
|
|
15435
15520
|
mkdirSync(dirname(workdir), { recursive: true });
|
|
15436
15521
|
if (!existsSync(join(workdir, ".git"))) {
|
|
@@ -15444,6 +15529,7 @@ function createMarketSourceInitializer(options) {
|
|
|
15444
15529
|
recursive: true,
|
|
15445
15530
|
force: true
|
|
15446
15531
|
});
|
|
15532
|
+
if (sandboxBlocked(cloned.stderr)) throw new Error(SANDBOX_TEXT);
|
|
15447
15533
|
throw new Error(`索引仓库克隆不下来:${tailLines(cloned.stderr || cloned.stdout, 4)}`);
|
|
15448
15534
|
}
|
|
15449
15535
|
}
|
|
@@ -16912,24 +16998,22 @@ var OWNED = [{
|
|
|
16912
16998
|
});
|
|
16913
16999
|
const marketIndex = createMarketIndexReader({
|
|
16914
17000
|
root: marketRoot,
|
|
16915
|
-
shell,
|
|
16916
17001
|
...logger === void 0 ? {} : { logger }
|
|
16917
17002
|
});
|
|
16918
17003
|
const marketDocs = createMarketDocReader({
|
|
16919
17004
|
root: marketRoot,
|
|
16920
|
-
shell,
|
|
16921
17005
|
...logger === void 0 ? {} : { logger }
|
|
16922
17006
|
});
|
|
16923
17007
|
const marketInit = createMarketSourceInitializer({
|
|
16924
17008
|
root: marketRoot,
|
|
16925
|
-
store: marketSources
|
|
16926
|
-
...shell === void 0 ? {} : { shell }
|
|
17009
|
+
store: marketSources
|
|
16927
17010
|
});
|
|
16928
17011
|
const discover = createMarketDiscover({
|
|
16929
17012
|
store: marketSources,
|
|
16930
17013
|
reader: marketIndex,
|
|
16931
17014
|
docs: marketDocs,
|
|
16932
17015
|
modules: () => supply.profileModules(profileDir),
|
|
17016
|
+
...profileDir === null ? {} : { profilePath: profileDir },
|
|
16933
17017
|
defaultRegistry: async () => {
|
|
16934
17018
|
try {
|
|
16935
17019
|
return (await bundles?.registries())?.resolved ?? void 0;
|
|
@@ -16959,9 +17043,9 @@ var OWNED = [{
|
|
|
16959
17043
|
dependencyOf: dependencyReader(profileDir),
|
|
16960
17044
|
isNewer: supply.isNewerVersion,
|
|
16961
17045
|
preferred: (host) => marketSources.read().transports?.[host],
|
|
16962
|
-
|
|
17046
|
+
probe: (url) => probeGitAddressCached(url, { timeoutMs: 4e3 }).then((one) => one.status)
|
|
16963
17047
|
}) })),
|
|
16964
|
-
...publishPreviewRoutes(workshopPathOf(ctx), (unit) => inferredAuthorOf(workshopPathOf(ctx), unit
|
|
17048
|
+
...publishPreviewRoutes(workshopPathOf(ctx), (unit) => inferredAuthorOf(workshopPathOf(ctx), unit))
|
|
16965
17049
|
},
|
|
16966
17050
|
registerTools: () => [
|
|
16967
17051
|
...registerPanelTools(ctx, panels, values),
|
|
@@ -16970,7 +17054,7 @@ var OWNED = [{
|
|
|
16970
17054
|
init: marketInit,
|
|
16971
17055
|
readOnly: (id) => markSourceReadOnly(marketSources, id)
|
|
16972
17056
|
}),
|
|
16973
|
-
...registerDiyTools(ctx, market, panels, debug, (unit) => publishPreviewOf(workshopPathOf(ctx), unit), (unit) => inferredAuthorOf(workshopPathOf(ctx), unit
|
|
17057
|
+
...registerDiyTools(ctx, market, panels, debug, (unit) => publishPreviewOf(workshopPathOf(ctx), unit), (unit) => inferredAuthorOf(workshopPathOf(ctx), unit)),
|
|
16974
17058
|
...registerRecordTools(ctx, record),
|
|
16975
17059
|
...registerLongTaskTools(ctx, longTaskRuns)
|
|
16976
17060
|
],
|
|
@@ -3,6 +3,7 @@ import type { PreflightBridgeIssue, PreflightGuidance, PreflightSnapshot, Prefli
|
|
|
3
3
|
import type { RuntimeProfile } from '@dsh-workbench/shared';
|
|
4
4
|
export declare function failedStepText(guidance: PreflightGuidance | undefined, t: Translate): string;
|
|
5
5
|
export declare function stepDetailText(step: PreflightStep, snapshot: PreflightSnapshot, t: Translate): string;
|
|
6
|
+
export declare function gateHintOf(snapshot: PreflightSnapshot, t: Translate): string;
|
|
6
7
|
export declare function showsRawDetails(snapshot: PreflightSnapshot): boolean;
|
|
7
8
|
export declare function showsRawAll(snapshot: PreflightSnapshot, panelShown: boolean): boolean;
|
|
8
9
|
export interface BridgeAdvice {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import 'dayjs/locale/zh-cn';
|
|
2
2
|
import type { DiscoverEntry, DiscoverSourceRow, DiscoverVersionRow, MarketSourceConfig } from '../../../kernel/contract/market-index';
|
|
3
|
+
export declare function localeNow(): string;
|
|
3
4
|
export type DiscoverSort = 'default' | 'published';
|
|
4
5
|
export declare const DISCOVER_PAGE_SIZE = 50;
|
|
5
6
|
export interface DiscoverFilterState {
|
|
@@ -10,7 +10,7 @@ export interface WorkspaceSectionPlan<T> {
|
|
|
10
10
|
readonly items: readonly T[];
|
|
11
11
|
}
|
|
12
12
|
export interface WorkspaceSectionOptions<T> {
|
|
13
|
-
readonly rankOf?: ((item: T) => number) | undefined;
|
|
13
|
+
readonly rankOf?: ((item: T) => number | null) | undefined;
|
|
14
14
|
}
|
|
15
15
|
export declare function workspaceSections<T extends {
|
|
16
16
|
readonly path: string;
|