@dsh-workbench/core 1.1.9 → 1.1.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/README.md +3 -3
  2. package/client.js +1166 -841
  3. package/dist/client/client.body.js +1166 -841
  4. package/dist/client/index.js +1034 -709
  5. package/dist/host/index.js +223 -130
  6. package/dist/types/app/layouts/env-gate/gate-text.d.ts +1 -0
  7. package/dist/types/app/layouts/market/discover-view.d.ts +1 -0
  8. package/dist/types/app/layouts/rightbar/MarketView.d.ts +2 -23
  9. package/dist/types/app/layouts/rightbar/market-body.d.ts +25 -0
  10. package/dist/types/app/layouts/rightbar/market-detail-facts.d.ts +14 -0
  11. package/dist/types/app/layouts/rightbar/market-detail-page.d.ts +20 -0
  12. package/dist/types/app/layouts/rightbar/market-detail.d.ts +17 -0
  13. package/dist/types/app/layouts/rightbar/market-row-types.d.ts +7 -0
  14. package/dist/types/app/layouts/rightbar/market-rows.d.ts +2 -0
  15. package/dist/types/app/layouts/rightbar/market-scene-view.d.ts +33 -0
  16. package/dist/types/app/layouts/rightbar/market-section.d.ts +23 -4
  17. package/dist/types/app/layouts/rightbar/market-view-text.d.ts +1 -0
  18. package/dist/types/app/layouts/sidebar/workspace-groups.d.ts +1 -1
  19. package/dist/types/modules/panels/model/market-discover.d.ts +1 -0
  20. package/dist/types/shared/api/host/diy-publish-preview.d.ts +4 -4
  21. package/dist/types/shared/api/host/git-exec.d.ts +1 -0
  22. package/dist/types/shared/api/host/git-probe.d.ts +6 -6
  23. package/dist/types/shared/api/host/git-process.d.ts +13 -0
  24. package/dist/types/shared/api/host/git-routes.d.ts +5 -2
  25. package/dist/types/shared/api/host/market-doc.d.ts +2 -2
  26. package/dist/types/shared/api/host/market-index-fetch.d.ts +2 -2
  27. package/dist/types/shared/api/host/market-source-init.d.ts +2 -2
  28. package/dist/types/shared/api/installed-plugins.d.ts +2 -0
  29. package/package.json +4 -4
@@ -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$2 = 8388608;
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$2,
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$2(error) {
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$2(error)}`
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$2(error)}`
4643
+ reason: `拿不到"这次会发生什么",已经停下:${messageOf$3(error)}`
4644
4644
  };
4645
4645
  }
4646
4646
  if (facts !== void 0 && "blocked" in facts) return {
@@ -6501,6 +6501,22 @@ function migrationFollowUp(input) {
6501
6501
  } : void 0;
6502
6502
  }
6503
6503
  //#endregion
6504
+ //#region src/shared/api/host/profile-dependencies.ts
6505
+ function dependencyReader(profileDir) {
6506
+ if (profileDir === null) return () => void 0;
6507
+ let dependencies;
6508
+ return (pkg) => {
6509
+ if (dependencies === void 0) try {
6510
+ const raw = JSON.parse(readFileSync(join(profileDir, "package.json"), "utf8")).dependencies;
6511
+ dependencies = typeof raw === "object" && raw !== null ? raw : {};
6512
+ } catch {
6513
+ dependencies = {};
6514
+ }
6515
+ const value = dependencies[pkg];
6516
+ return typeof value === "string" ? value : void 0;
6517
+ };
6518
+ }
6519
+ //#endregion
6504
6520
  //#region src/shared/api/host/bundle-routes.ts
6505
6521
  function registryOf(search) {
6506
6522
  const raw = param(search, "registry");
@@ -6564,6 +6580,7 @@ async function latestIfReleaseReady(supply, input) {
6564
6580
  async function workbenchVersion(supply, input) {
6565
6581
  const read = supply.readProfilePackage(input.dir, PLUGIN_ID);
6566
6582
  if (read === void 0) return void 0;
6583
+ const spec = dependencyReader(input.dir)(PLUGIN_ID);
6567
6584
  const registry = read.registry ?? input.fallback;
6568
6585
  const shell = input.shell;
6569
6586
  const queried = read.local === true || shell === void 0 || registry === void 0 ? void 0 : await supply.latestVersion({
@@ -6586,7 +6603,9 @@ async function workbenchVersion(supply, input) {
6586
6603
  ...latest === void 0 ? {} : { latest },
6587
6604
  ...input.running === void 0 ? {} : { running: input.running },
6588
6605
  ...read.local === true ? { local: true } : {},
6589
- ...input.followUp === void 0 ? {} : { followUp: input.followUp }
6606
+ ...input.followUp === void 0 ? {} : { followUp: input.followUp },
6607
+ ...spec === void 0 ? {} : { spec },
6608
+ ...registry === void 0 || read.local === true ? {} : { registry }
6590
6609
  };
6591
6610
  }
6592
6611
  function moduleVersionsHandler(ctx, shell, running, selfUpdate) {
@@ -6602,10 +6621,12 @@ function moduleVersionsHandler(ctx, shell, running, selfUpdate) {
6602
6621
  const refusals = new Map((ctx.get("workbenchUnits")?.refusals() ?? []).filter((one) => one.unit !== "").map((one) => [one.unit, one.reasons]));
6603
6622
  const force = param(search, "force") === "1";
6604
6623
  const fallback = (await manager.registries())?.resolved ?? void 0;
6624
+ const dependencyOf = dependencyReader(dir);
6605
6625
  const modules = await Promise.all(found.map(async (module) => {
6606
6626
  const local = module.local === true;
6607
6627
  const fromRegistry = module.fromRegistry !== false;
6608
6628
  const registry = fromRegistry ? module.registry ?? fallback : void 0;
6629
+ const spec = dependencyOf(module.pkg);
6609
6630
  const latest = local || !fromRegistry || shell === void 0 || registry === void 0 ? void 0 : await supply.latestVersion({
6610
6631
  shell,
6611
6632
  name: module.pkg,
@@ -6642,7 +6663,9 @@ function moduleVersionsHandler(ctx, shell, running, selfUpdate) {
6642
6663
  local: true,
6643
6664
  latestUnavailable: "local"
6644
6665
  } : latest !== void 0 ? {} : { latestUnavailable: !fromRegistry ? "not-registry" : registry === void 0 ? "no-registry" : "probe-failed" },
6645
- ...refused === void 0 ? {} : { refused }
6666
+ ...refused === void 0 ? {} : { refused },
6667
+ ...spec === void 0 ? {} : { spec },
6668
+ ...registry === void 0 ? {} : { registry }
6646
6669
  };
6647
6670
  }));
6648
6671
  const selfUpdateNow = selfUpdate?.();
@@ -6754,21 +6777,42 @@ function bundleInspectHandler(ctx) {
6754
6777
  }
6755
6778
  //#endregion
6756
6779
  //#region src/shared/api/host/git-exec.ts
6757
- var 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
- ];
6765
- function gitNoPromptPrefix() {
6766
- return [quoteShellArg("env"), ...NO_PROMPT_ENV.map((one) => quoteShellArg(one))].join(" ");
6767
- }
6780
+ var GIT_NO_PROMPT_ENV = {
6781
+ GIT_TERMINAL_PROMPT: "0",
6782
+ GIT_ASKPASS: "/usr/bin/false",
6783
+ SSH_ASKPASS: "/usr/bin/false",
6784
+ SSH_ASKPASS_REQUIRE: "never",
6785
+ GCM_INTERACTIVE: "never",
6786
+ GIT_SSH_COMMAND: "ssh -o BatchMode=yes -o StrictHostKeyChecking=accept-new"
6787
+ };
6768
6788
  function withoutAskpassNoise(text) {
6769
6789
  return text.split("\n").filter((line) => !/unable to read askpass response/i.test(line)).join("\n").trim();
6770
6790
  }
6771
6791
  //#endregion
6792
+ //#region src/shared/api/host/git-process.ts
6793
+ var DEFAULT_MAX_BYTES$2 = 8388608;
6794
+ var runGitProcess = async (args, options = {}) => {
6795
+ const result = await execa("git", [...args], {
6796
+ ...options.cwd === void 0 ? {} : { cwd: options.cwd },
6797
+ env: {
6798
+ ...process.env,
6799
+ ...GIT_NO_PROMPT_ENV
6800
+ },
6801
+ stdin: "ignore",
6802
+ reject: false,
6803
+ ...options.timeoutMs === void 0 ? {} : { timeout: options.timeoutMs },
6804
+ killSignal: "SIGKILL",
6805
+ maxBuffer: options.maxBytes ?? DEFAULT_MAX_BYTES$2,
6806
+ stripFinalNewline: false
6807
+ });
6808
+ return {
6809
+ exitCode: result.exitCode ?? null,
6810
+ stdout: result.stdout ?? "",
6811
+ stderr: result.stderr ?? "",
6812
+ timedOut: result.timedOut === true
6813
+ };
6814
+ };
6815
+ //#endregion
6772
6816
  //#region src/shared/api/host/git-probe.ts
6773
6817
  var PROBE_TIMEOUT_MS = 1e4;
6774
6818
  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 +6820,15 @@ function classifyGitProbe(stderr, timedOut) {
6776
6820
  if (timedOut) return "unreachable";
6777
6821
  return AUTH_TEXT.test(stderr.toLowerCase()) ? "auth" : "unreachable";
6778
6822
  }
6779
- async function probeGitAddress(shell, url, options = {}) {
6780
- const line = [
6781
- gitNoPromptPrefix(),
6782
- quoteShellArg("git"),
6783
- quoteShellArg("ls-remote"),
6784
- quoteShellArg(url),
6785
- quoteShellArg("HEAD")
6786
- ].join(" ");
6823
+ async function probeGitAddress(url, options = {}) {
6824
+ const runGit = options.runGit ?? runGitProcess;
6787
6825
  let result;
6788
6826
  try {
6789
- result = await runShell(shell, line, { timeoutMs: options.timeoutMs ?? PROBE_TIMEOUT_MS });
6827
+ result = await runGit([
6828
+ "ls-remote",
6829
+ url,
6830
+ "HEAD"
6831
+ ], { timeoutMs: options.timeoutMs ?? PROBE_TIMEOUT_MS });
6790
6832
  } catch (error) {
6791
6833
  return {
6792
6834
  status: "unreachable",
@@ -6802,10 +6844,10 @@ async function probeGitAddress(shell, url, options = {}) {
6802
6844
  }
6803
6845
  var PROBE_CACHE_MS = 6e4;
6804
6846
  var probeCache = /* @__PURE__ */ new Map();
6805
- async function probeGitAddressCached(shell, url, options = {}) {
6847
+ async function probeGitAddressCached(url, options = {}) {
6806
6848
  const hit = probeCache.get(url);
6807
6849
  if (hit !== void 0 && Date.now() - hit.at < PROBE_CACHE_MS) return hit.payload;
6808
- const payload = await probeGitAddress(shell, url, options);
6850
+ const payload = await probeGitAddress(url, options);
6809
6851
  probeCache.set(url, {
6810
6852
  at: Date.now(),
6811
6853
  payload
@@ -6814,7 +6856,7 @@ async function probeGitAddressCached(shell, url, options = {}) {
6814
6856
  }
6815
6857
  //#endregion
6816
6858
  //#region src/shared/api/host/git-routes.ts
6817
- function gitProbeHandler(ctx) {
6859
+ function gitProbeHandler(options = {}) {
6818
6860
  return async (search) => {
6819
6861
  const url = param(search, "url");
6820
6862
  if (url === void 0) return {
@@ -6824,17 +6866,9 @@ function gitProbeHandler(ctx) {
6824
6866
  message: "要探哪个地址?缺 url。"
6825
6867
  }
6826
6868
  };
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
6869
  return {
6836
6870
  ok: true,
6837
- ...await probeGitAddress(shell, url)
6871
+ ...await probeGitAddress(url, options)
6838
6872
  };
6839
6873
  };
6840
6874
  }
@@ -6848,7 +6882,7 @@ function createHostRoutes(input) {
6848
6882
  [DSH_PLUGINS_ROUTE]: profile.dshPlugins(ctx),
6849
6883
  [BUNDLE_REGISTRIES_ROUTE]: bundleRegistriesHandler(ctx),
6850
6884
  [BUNDLE_INSPECT_ROUTE]: bundleInspectHandler(ctx),
6851
- [MARKET_GIT_PROBE_ROUTE]: gitProbeHandler(ctx),
6885
+ [MARKET_GIT_PROBE_ROUTE]: gitProbeHandler(),
6852
6886
  [MODULE_VERSIONS_ROUTE]: moduleVersionsHandler(ctx, ctx.get("shell"), running, () => profile.selfUpdateView(dshHome(), basename(profile.dirOf(ctx) ?? "")))
6853
6887
  };
6854
6888
  }
@@ -11096,24 +11130,34 @@ function siblingAuthorOf(root, unit) {
11096
11130
  }
11097
11131
  return authors.size === 1 ? [...authors][0] : void 0;
11098
11132
  }
11099
- async function localGitIdentityOf(shell, dir) {
11100
- if (shell === void 0) return void 0;
11101
- const read = async (argv) => {
11102
- const result = await runShell(shell, `git -C ${quoteShellArg(dir)} ${argv}`, { workdir: dir });
11103
- return result.exitCode === 0 ? result.stdout.trim() : "";
11133
+ async function localGitIdentityOf(dir, runGit = runGitProcess) {
11134
+ const read = async (args) => {
11135
+ try {
11136
+ const result = await runGit(args, { cwd: dir });
11137
+ return result.exitCode === 0 ? result.stdout.trim() : "";
11138
+ } catch {
11139
+ return "";
11140
+ }
11104
11141
  };
11105
- const name = await read(`config ${quoteShellArg("user.name")}`);
11142
+ const name = await read(["config", "user.name"]);
11106
11143
  if (name === "") return void 0;
11107
- const email = await read(`config ${quoteShellArg("user.email")}`);
11144
+ const email = await read(["config", "user.email"]);
11108
11145
  return email === "" ? name : `${name} <${email}>`;
11109
11146
  }
11110
- async function lastCommitAuthorOf(shell, dir) {
11111
- if (shell === void 0) return void 0;
11112
- const result = await runShell(shell, `git -C ${quoteShellArg(dir)} log -1 --format=${quoteShellArg("%an <%ae>")}`, { workdir: dir });
11113
- const author = result.exitCode === 0 ? result.stdout.trim() : "";
11114
- return author === "" ? void 0 : author;
11147
+ async function lastCommitAuthorOf(dir, runGit = runGitProcess) {
11148
+ try {
11149
+ const result = await runGit([
11150
+ "log",
11151
+ "-1",
11152
+ "--format=%an <%ae>"
11153
+ ], { cwd: dir });
11154
+ const author = result.exitCode === 0 ? result.stdout.trim() : "";
11155
+ return author === "" ? void 0 : author;
11156
+ } catch {
11157
+ return;
11158
+ }
11115
11159
  }
11116
- async function inferredAuthorOf(root, unit, shell) {
11160
+ async function inferredAuthorOf(root, unit, runGit = runGitProcess) {
11117
11161
  const fact = moduleFactOf(root, unit);
11118
11162
  if (fact === null) return void 0;
11119
11163
  if (fact.author !== "") return fact.author;
@@ -11124,9 +11168,9 @@ async function inferredAuthorOf(root, unit, shell) {
11124
11168
  }
11125
11169
  const sibling = root === null || root === void 0 ? void 0 : siblingAuthorOf(root, unit);
11126
11170
  if (sibling !== void 0) return sibling;
11127
- const local = await localGitIdentityOf(shell, fact.dir);
11171
+ const local = await localGitIdentityOf(fact.dir, runGit);
11128
11172
  if (local !== void 0) return local;
11129
- return lastCommitAuthorOf(shell, fact.dir);
11173
+ return lastCommitAuthorOf(fact.dir, runGit);
11130
11174
  }
11131
11175
  function publishPreviewOf(root, unit, options = {}) {
11132
11176
  if (root === null || root === void 0 || unit === "") return null;
@@ -14325,6 +14369,20 @@ function createMarketService(options) {
14325
14369
  }
14326
14370
  //#endregion
14327
14371
  //#region src/modules/panels/model/market-discover.ts
14372
+ var SANDBOX_BLOCK = [
14373
+ "- id: sandbox-policy",
14374
+ " config:",
14375
+ " mode: !!js process.env.DSH_PERMISSION_MODE ?? 'workspace-write'",
14376
+ " workspaceRoot: !!js dshHomePath('workbench')"
14377
+ ].join("\n");
14378
+ function explainProblem(problem, profilePath) {
14379
+ if (problem.kind !== "sandbox" || profilePath === void 0 || profilePath === "") return problem;
14380
+ const file = join(profilePath, "cordis.patch.yml");
14381
+ return {
14382
+ ...problem,
14383
+ detail: `被系统拦住了:这个 profile 的可写根盖不住工作台的缓存目录。\n退出 dsh 后,把下面这段加进 ${file},再启动:\n${SANDBOX_BLOCK}`
14384
+ };
14385
+ }
14328
14386
  var DEFAULT_PEER_TTL_MS = 6e5;
14329
14387
  var DEFAULT_TIMEOUT_MS$3 = 15e3;
14330
14388
  var CORE_PEER = "@dsh-workbench/core";
@@ -14476,12 +14534,12 @@ function createMarketDiscover(options) {
14476
14534
  sources: rows,
14477
14535
  selected: source.id,
14478
14536
  entries: [],
14479
- problem: read.problem
14537
+ problem: explainProblem(read.problem, options.profilePath)
14480
14538
  };
14481
14539
  return {
14482
14540
  ...await payloadOf(source, read.cached.index, rows, source.id, filter, read.cached.fetchedAt, read.cached.commit),
14483
14541
  stale: true,
14484
- problem: read.problem
14542
+ problem: explainProblem(read.problem, options.profilePath)
14485
14543
  };
14486
14544
  }
14487
14545
  return payloadOf(source, read.index, rows, source.id, filter, read.fetchedAt, read.commit);
@@ -14611,22 +14669,6 @@ function transportOfSpec(spec) {
14611
14669
  };
14612
14670
  }
14613
14671
  //#endregion
14614
- //#region src/shared/api/host/profile-dependencies.ts
14615
- function dependencyReader(profileDir) {
14616
- if (profileDir === null) return () => void 0;
14617
- let dependencies;
14618
- return (pkg) => {
14619
- if (dependencies === void 0) try {
14620
- const raw = JSON.parse(readFileSync(join(profileDir, "package.json"), "utf8")).dependencies;
14621
- dependencies = typeof raw === "object" && raw !== null ? raw : {};
14622
- } catch {
14623
- dependencies = {};
14624
- }
14625
- const value = dependencies[pkg];
14626
- return typeof value === "string" ? value : void 0;
14627
- };
14628
- }
14629
- //#endregion
14630
14672
  //#region src/modules/panels/model/market-sources-act.ts
14631
14673
  function marketSourcesRoutes(store) {
14632
14674
  return { [MARKET_SOURCES_ROUTE]: async () => ({
@@ -14784,7 +14826,7 @@ function publishPreviewRoutes(workshop, inferredAuthorOf = async () => void 0) {
14784
14826
  var DEFAULT_TTL_MS = 3e5;
14785
14827
  var DEFAULT_TIMEOUT_MS$2 = 3e4;
14786
14828
  var DEFAULT_MAX_BYTES$1 = 4194304;
14787
- function messageOf$1(error) {
14829
+ function messageOf$2(error) {
14788
14830
  return error instanceof Error ? error.message : String(error);
14789
14831
  }
14790
14832
  function directoryOf(root, source) {
@@ -14853,6 +14895,10 @@ function classifyGitError(stderr, timedOut) {
14853
14895
  detail: "git 拉取超时"
14854
14896
  };
14855
14897
  const text = stderr.toLowerCase();
14898
+ if (text.includes("operation not permitted") || /\beperm\b/.test(text)) return {
14899
+ kind: "sandbox",
14900
+ detail: "被系统拦住了:这个 profile 的可写根盖不住工作台的缓存目录"
14901
+ };
14856
14902
  if (/couldn'?t find remote ref\s+["']?head/.test(text) || /could not find remote ref\s+["']?head/.test(text)) return {
14857
14903
  kind: "git-empty",
14858
14904
  detail: "仓库还没有任何提交"
@@ -14880,6 +14926,7 @@ function createMarketIndexReader(options) {
14880
14926
  const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS$2;
14881
14927
  const maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES$1;
14882
14928
  const fetchImpl = options.fetchImpl ?? globalThis.fetch;
14929
+ const runGit = options.runGit ?? runGitProcess;
14883
14930
  const inFlight = /* @__PURE__ */ new Map();
14884
14931
  async function readHttp(source) {
14885
14932
  const bad = httpProblemOf(source.url);
@@ -14902,7 +14949,7 @@ function createMarketIndexReader(options) {
14902
14949
  detail: `拉索引超过 ${String(Math.round(timeoutMs / 1e3))} 秒`
14903
14950
  } : {
14904
14951
  kind: "http-network",
14905
- detail: messageOf$1(error)
14952
+ detail: messageOf$2(error)
14906
14953
  }
14907
14954
  };
14908
14955
  }
@@ -14939,17 +14986,13 @@ function createMarketIndexReader(options) {
14939
14986
  fetchedAt
14940
14987
  };
14941
14988
  }
14942
- async function run(line) {
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
- };
14989
+ async function run(args, cwd) {
14951
14990
  try {
14952
- const result = await runShell(shell, `${gitNoPromptPrefix()} ${line}`, { timeoutMs });
14991
+ const result = await runGit(args, {
14992
+ ...cwd === void 0 ? {} : { cwd },
14993
+ timeoutMs,
14994
+ maxBytes
14995
+ });
14953
14996
  if (result.exitCode !== 0) return {
14954
14997
  ok: false,
14955
14998
  problem: classifyGitError(result.stderr, result.timedOut),
@@ -14960,7 +15003,7 @@ function createMarketIndexReader(options) {
14960
15003
  stdout: result.stdout
14961
15004
  };
14962
15005
  } catch (error) {
14963
- const text = messageOf$1(error);
15006
+ const text = messageOf$2(error);
14964
15007
  if (/not found|no such file|ENOENT/i.test(text)) return {
14965
15008
  ok: false,
14966
15009
  problem: {
@@ -14978,7 +15021,11 @@ function createMarketIndexReader(options) {
14978
15021
  }
14979
15022
  }
14980
15023
  async function branchOf(repo) {
14981
- const result = await run(`git -C ${quoteShellArg(repo)} symbolic-ref --short HEAD`);
15024
+ const result = await run([
15025
+ "symbolic-ref",
15026
+ "--short",
15027
+ "HEAD"
15028
+ ], repo);
14982
15029
  const branch = result.ok ? result.stdout.trim() : "";
14983
15030
  return branch === "" ? void 0 : branch;
14984
15031
  }
@@ -14999,20 +15046,21 @@ function createMarketIndexReader(options) {
14999
15046
  ok: false,
15000
15047
  problem: bad
15001
15048
  };
15002
- if (options.shell === void 0) return {
15003
- ok: false,
15004
- problem: {
15005
- kind: "git-missing",
15006
- detail: "没有 git 执行缝"
15007
- }
15008
- };
15009
15049
  const repo = repoOf(options.root, source);
15010
15050
  const path = ((source.path ?? "market").replace(/^\/+/, "") || "market").replace(/\/+$/, "");
15011
15051
  const ref = (source.ref ?? "").trim();
15012
15052
  let revision = "FETCH_HEAD";
15013
15053
  mkdirSync(directoryOf(options.root, source), { recursive: true });
15014
15054
  if (!existsSync(repo)) {
15015
- const cloned = await run(`git clone --bare --depth 1 ${ref === "" ? "" : `--branch ${quoteShellArg(ref)} `}${quoteShellArg(source.url)} ${quoteShellArg(repo)}`);
15055
+ const cloned = await run([
15056
+ "clone",
15057
+ "--bare",
15058
+ "--depth",
15059
+ "1",
15060
+ ...ref === "" ? [] : ["--branch", ref],
15061
+ source.url,
15062
+ repo
15063
+ ]);
15016
15064
  if (!cloned.ok) {
15017
15065
  rmSync(repo, {
15018
15066
  recursive: true,
@@ -15022,17 +15070,27 @@ function createMarketIndexReader(options) {
15022
15070
  }
15023
15071
  revision = "HEAD";
15024
15072
  } else {
15025
- const fetched = await run(`git -C ${quoteShellArg(repo)} fetch --depth 1 origin ${quoteShellArg(ref === "" ? "HEAD" : ref)}`);
15073
+ const fetched = await run([
15074
+ "fetch",
15075
+ "--depth",
15076
+ "1",
15077
+ "origin",
15078
+ ref === "" ? "HEAD" : ref
15079
+ ], repo);
15026
15080
  if (!fetched.ok) return withBranch(fetched, repo);
15027
15081
  }
15028
- if (!(await run(`git -C ${quoteShellArg(repo)} rev-parse --verify HEAD`)).ok) return withBranch({
15082
+ if (!(await run([
15083
+ "rev-parse",
15084
+ "--verify",
15085
+ "HEAD"
15086
+ ], repo)).ok) return withBranch({
15029
15087
  ok: false,
15030
15088
  problem: {
15031
15089
  kind: "git-empty",
15032
15090
  detail: "仓库还没有任何提交"
15033
15091
  }
15034
15092
  }, repo);
15035
- const head = await run(`git -C ${quoteShellArg(repo)} rev-parse ${revision}`);
15093
+ const head = await run(["rev-parse", revision], repo);
15036
15094
  if (!head.ok) return head;
15037
15095
  const commit = head.stdout.trim();
15038
15096
  if (!/^[0-9a-f]{40}$/.test(commit)) return {
@@ -15042,7 +15100,13 @@ function createMarketIndexReader(options) {
15042
15100
  detail: `读到的 commit 不是 40 位:${commit}`
15043
15101
  }
15044
15102
  };
15045
- const listed = await run(`git -C ${quoteShellArg(repo)} ls-tree -r ${quoteShellArg(commit)} -- ${quoteShellArg(path)}`);
15103
+ const listed = await run([
15104
+ "ls-tree",
15105
+ "-r",
15106
+ commit,
15107
+ "--",
15108
+ path
15109
+ ], repo);
15046
15110
  if (!listed.ok) {
15047
15111
  if (listed.problem.kind === "git-file") return withBranch({
15048
15112
  ok: false,
@@ -15078,7 +15142,7 @@ function createMarketIndexReader(options) {
15078
15142
  };
15079
15143
  };
15080
15144
  const readLegacy = async (file) => {
15081
- const shown = await run(`git -C ${quoteShellArg(repo)} show ${quoteShellArg(commit)}:${quoteShellArg(file)}`);
15145
+ const shown = await run(["show", `${commit}:${file}`], repo);
15082
15146
  if (!shown.ok) return void 0;
15083
15147
  const parsed = parseMarketIndexJson(shown.stdout);
15084
15148
  if (!parsed.ok) return {
@@ -15102,7 +15166,7 @@ function createMarketIndexReader(options) {
15102
15166
  for (;;) {
15103
15167
  const next = queue.shift();
15104
15168
  if (next === void 0 || failed !== void 0) return;
15105
- const shown = await run(`git -C ${quoteShellArg(repo)} show ${quoteShellArg(commit)}:${quoteShellArg(next.file)}`);
15169
+ const shown = await run(["show", `${commit}:${next.file}`], repo);
15106
15170
  if (!shown.ok) {
15107
15171
  failed = shown;
15108
15172
  return;
@@ -15155,7 +15219,7 @@ function createMarketIndexReader(options) {
15155
15219
  ok: false,
15156
15220
  problem: {
15157
15221
  kind: "unknown",
15158
- detail: messageOf$1(error)
15222
+ detail: messageOf$2(error)
15159
15223
  }
15160
15224
  })).then((result) => {
15161
15225
  if (result.ok) return result;
@@ -15184,7 +15248,7 @@ var FILES = {
15184
15248
  var DEFAULT_TIMEOUT_MS$1 = 15e3;
15185
15249
  var DEFAULT_MAX_BYTES = 204800;
15186
15250
  var DEFAULT_REGISTRY = "https://registry.npmjs.org";
15187
- function messageOf(error) {
15251
+ function messageOf$1(error) {
15188
15252
  return error instanceof Error ? error.message : String(error);
15189
15253
  }
15190
15254
  function clipped(text, maxBytes) {
@@ -15199,6 +15263,7 @@ function createMarketDocReader(options) {
15199
15263
  const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS$1;
15200
15264
  const maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES;
15201
15265
  const fetchImpl = options.fetchImpl ?? globalThis.fetch;
15266
+ const runGit = options.runGit ?? runGitProcess;
15202
15267
  const cache = /* @__PURE__ */ new Map();
15203
15268
  function fail(kind, version, reason, detail) {
15204
15269
  return {
@@ -15216,22 +15281,40 @@ function createMarketDocReader(options) {
15216
15281
  async function readGit(source, target, kind) {
15217
15282
  const git = target.source;
15218
15283
  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
15284
  const key = `${git.commit}|${git.path ?? ""}|${kind}`;
15222
15285
  const cached = cache.get(key);
15223
15286
  if (cached !== void 0) return cached;
15224
15287
  const directory = (git.path ?? "").replace(/^\/+|\/+$/g, "");
15225
15288
  const file = directory === "" ? FILES[kind] : `${directory}/${FILES[kind]}`;
15226
15289
  const repo = join(options.root, "market-index", marketSourceKey(source), "repo.git");
15227
- const show = () => runShell(shell, `git -C ${quoteShellArg(repo)} show ${git.commit}:${quoteShellArg(file)}`, { timeoutMs });
15290
+ const show = () => runGit(["show", `${git.commit}:${file}`], {
15291
+ cwd: repo,
15292
+ timeoutMs,
15293
+ maxBytes
15294
+ });
15228
15295
  const hasCommit = async () => {
15229
- return (await runShell(shell, `git -C ${quoteShellArg(repo)} cat-file -e ${quoteShellArg(`${git.commit}^{commit}`)}`, { timeoutMs })).exitCode === 0;
15296
+ return (await runGit([
15297
+ "cat-file",
15298
+ "-e",
15299
+ `${git.commit}^{commit}`
15300
+ ], {
15301
+ cwd: repo,
15302
+ timeoutMs
15303
+ })).exitCode === 0;
15230
15304
  };
15231
15305
  try {
15232
15306
  let result = await show();
15233
15307
  if (result.exitCode !== 0 && !await hasCommit()) {
15234
- if ((await runShell(shell, `git -C ${quoteShellArg(repo)} fetch --depth 1 origin ${git.commit}`, { timeoutMs })).exitCode === 0) result = await show();
15308
+ if ((await runGit([
15309
+ "fetch",
15310
+ "--depth",
15311
+ "1",
15312
+ "origin",
15313
+ git.commit
15314
+ ], {
15315
+ cwd: repo,
15316
+ timeoutMs
15317
+ })).exitCode === 0) result = await show();
15235
15318
  }
15236
15319
  if (result.exitCode !== 0) {
15237
15320
  const text = result.stderr.trim();
@@ -15244,8 +15327,8 @@ function createMarketDocReader(options) {
15244
15327
  text: clipped(result.stdout, maxBytes)
15245
15328
  });
15246
15329
  } catch (error) {
15247
- options.logger?.warn?.(`[dsh-workbench] 读 ${file} 失败:${messageOf(error)}`);
15248
- return fail(kind, target.version, "unavailable", messageOf(error));
15330
+ options.logger?.warn?.(`[dsh-workbench] 读 ${file} 失败:${messageOf$1(error)}`);
15331
+ return fail(kind, target.version, "unavailable", messageOf$1(error));
15249
15332
  }
15250
15333
  }
15251
15334
  async function readNpm(target, kind) {
@@ -15271,8 +15354,8 @@ function createMarketDocReader(options) {
15271
15354
  text: clipped(text, maxBytes)
15272
15355
  });
15273
15356
  } catch (error) {
15274
- options.logger?.warn?.(`[dsh-workbench] 读 ${target.name} 的说明失败:${messageOf(error)}`);
15275
- return fail(kind, target.version, "unavailable", messageOf(error));
15357
+ options.logger?.warn?.(`[dsh-workbench] 读 ${target.name} 的说明失败:${messageOf$1(error)}`);
15358
+ return fail(kind, target.version, "unavailable", messageOf$1(error));
15276
15359
  }
15277
15360
  }
15278
15361
  return { read: (source, target, kind) => target.source.type === "git" ? readGit(source, target, kind) : readNpm(target, kind) };
@@ -15391,8 +15474,17 @@ var CACHE_FILES = [
15391
15474
  "index.json",
15392
15475
  "meta.json"
15393
15476
  ];
15477
+ function messageOf(error) {
15478
+ return error instanceof Error ? error.message : String(error);
15479
+ }
15480
+ var SANDBOX_TEXT = "被系统拦住了:这个 profile 的可写根盖不住工作台的缓存目录";
15481
+ function sandboxBlocked(text) {
15482
+ const lower = text.toLowerCase();
15483
+ return lower.includes("operation not permitted") || /\beperm\b/.test(lower);
15484
+ }
15394
15485
  function createMarketSourceInitializer(options) {
15395
15486
  const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
15487
+ const runGit = options.runGit ?? runGitProcess;
15396
15488
  function forget(source, next) {
15397
15489
  const base = join(options.root, "market-index");
15398
15490
  const oldKey = marketSourceKey(source);
@@ -15415,22 +15507,22 @@ function createMarketSourceInitializer(options) {
15415
15507
  });
15416
15508
  }
15417
15509
  return async (request) => {
15418
- const shell = options.shell;
15419
- if (shell === void 0) throw new Error("这台机器上没有 shell 服务,初始化不了索引仓库");
15420
15510
  const source = options.store.read().sources.find((one) => one.id === request.id);
15421
15511
  if (source === void 0) throw new Error("这个索引源已经不在了 —— 刷新后再试");
15422
15512
  if (source.kind !== "git") throw new Error("只有 git 仓库能初始化成市场索引");
15423
15513
  if (!gitUrlOk(source.url)) throw new Error(`这个 git 地址不合格:${source.url}`);
15424
15514
  const asked = (request.ref ?? "").trim();
15425
15515
  if (asked !== "" && !marketBranchOk(asked)) throw new Error(`分支名不合格:${asked}`);
15426
- const git = (argv, workdir) => runShell(shell, [
15427
- "git",
15428
- argv[0],
15429
- ...argv.slice(1).map((one) => quoteShellArg(one))
15430
- ].join(" "), {
15431
- ...workdir === void 0 ? {} : { workdir },
15432
- timeoutMs
15433
- });
15516
+ const git = async (args, workdir) => {
15517
+ try {
15518
+ return await runGit(args, {
15519
+ ...workdir === void 0 ? {} : { cwd: workdir },
15520
+ timeoutMs
15521
+ });
15522
+ } catch (error) {
15523
+ throw new Error(`git 跑不起来:${messageOf(error)}`, { cause: error });
15524
+ }
15525
+ };
15434
15526
  const workdir = join(options.root, "market-index", marketSourceKey(source), "worktree");
15435
15527
  mkdirSync(dirname(workdir), { recursive: true });
15436
15528
  if (!existsSync(join(workdir, ".git"))) {
@@ -15444,6 +15536,7 @@ function createMarketSourceInitializer(options) {
15444
15536
  recursive: true,
15445
15537
  force: true
15446
15538
  });
15539
+ if (sandboxBlocked(cloned.stderr)) throw new Error(SANDBOX_TEXT);
15447
15540
  throw new Error(`索引仓库克隆不下来:${tailLines(cloned.stderr || cloned.stdout, 4)}`);
15448
15541
  }
15449
15542
  }
@@ -16568,6 +16661,8 @@ async function installedPlugins(options) {
16568
16661
  ...release.latest === void 0 ? {} : { latest: release.latest }
16569
16662
  },
16570
16663
  ...entry.local === true ? { local: true } : {},
16664
+ ...entry.registry === void 0 ? {} : { registry: entry.registry },
16665
+ ...entry.installedAt === void 0 ? {} : { installedAt: entry.installedAt },
16571
16666
  ...pluginOnDisk(entry, ledger.pluginFiles) ? {} : { broken: true }
16572
16667
  });
16573
16668
  }
@@ -16912,24 +17007,22 @@ var OWNED = [{
16912
17007
  });
16913
17008
  const marketIndex = createMarketIndexReader({
16914
17009
  root: marketRoot,
16915
- shell,
16916
17010
  ...logger === void 0 ? {} : { logger }
16917
17011
  });
16918
17012
  const marketDocs = createMarketDocReader({
16919
17013
  root: marketRoot,
16920
- shell,
16921
17014
  ...logger === void 0 ? {} : { logger }
16922
17015
  });
16923
17016
  const marketInit = createMarketSourceInitializer({
16924
17017
  root: marketRoot,
16925
- store: marketSources,
16926
- ...shell === void 0 ? {} : { shell }
17018
+ store: marketSources
16927
17019
  });
16928
17020
  const discover = createMarketDiscover({
16929
17021
  store: marketSources,
16930
17022
  reader: marketIndex,
16931
17023
  docs: marketDocs,
16932
17024
  modules: () => supply.profileModules(profileDir),
17025
+ ...profileDir === null ? {} : { profilePath: profileDir },
16933
17026
  defaultRegistry: async () => {
16934
17027
  try {
16935
17028
  return (await bundles?.registries())?.resolved ?? void 0;
@@ -16959,9 +17052,9 @@ var OWNED = [{
16959
17052
  dependencyOf: dependencyReader(profileDir),
16960
17053
  isNewer: supply.isNewerVersion,
16961
17054
  preferred: (host) => marketSources.read().transports?.[host],
16962
- ...shell === void 0 ? {} : { probe: (url) => probeGitAddressCached(shell, url, { timeoutMs: 4e3 }).then((one) => one.status) }
17055
+ probe: (url) => probeGitAddressCached(url, { timeoutMs: 4e3 }).then((one) => one.status)
16963
17056
  }) })),
16964
- ...publishPreviewRoutes(workshopPathOf(ctx), (unit) => inferredAuthorOf(workshopPathOf(ctx), unit, shell))
17057
+ ...publishPreviewRoutes(workshopPathOf(ctx), (unit) => inferredAuthorOf(workshopPathOf(ctx), unit))
16965
17058
  },
16966
17059
  registerTools: () => [
16967
17060
  ...registerPanelTools(ctx, panels, values),
@@ -16970,7 +17063,7 @@ var OWNED = [{
16970
17063
  init: marketInit,
16971
17064
  readOnly: (id) => markSourceReadOnly(marketSources, id)
16972
17065
  }),
16973
- ...registerDiyTools(ctx, market, panels, debug, (unit) => publishPreviewOf(workshopPathOf(ctx), unit), (unit) => inferredAuthorOf(workshopPathOf(ctx), unit, shell)),
17066
+ ...registerDiyTools(ctx, market, panels, debug, (unit) => publishPreviewOf(workshopPathOf(ctx), unit), (unit) => inferredAuthorOf(workshopPathOf(ctx), unit)),
16974
17067
  ...registerRecordTools(ctx, record),
16975
17068
  ...registerLongTaskTools(ctx, longTaskRuns)
16976
17069
  ],