@dsh-workbench/core 0.1.8 → 0.1.9

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.
@@ -1380,7 +1380,7 @@ function readBundleManager(ctx) {
1380
1380
  }
1381
1381
  //#endregion
1382
1382
  //#region src/shared/api/host/installed-module.ts
1383
- var PACKAGE_NAME = /^(?:@[a-z0-9][a-z0-9._~-]*\/)?[a-z0-9][a-z0-9._~-]*$/;
1383
+ var PACKAGE_NAME$1 = /^(?:@[a-z0-9][a-z0-9._~-]*\/)?[a-z0-9][a-z0-9._~-]*$/;
1384
1384
  function asRecord$1(value) {
1385
1385
  return typeof value === "object" && value !== null ? value : void 0;
1386
1386
  }
@@ -1388,7 +1388,7 @@ function asText$1(value) {
1388
1388
  return typeof value === "string" ? value : "";
1389
1389
  }
1390
1390
  function isPackageName(value) {
1391
- return value.length <= 214 && PACKAGE_NAME.test(value);
1391
+ return value.length <= 214 && PACKAGE_NAME$1.test(value);
1392
1392
  }
1393
1393
  function profileDirOf(ctx) {
1394
1394
  const profile = ctx.get("profileContext");
@@ -1477,6 +1477,118 @@ function readInstalledModule(profileDir, pkg) {
1477
1477
  };
1478
1478
  }
1479
1479
  //#endregion
1480
+ //#region src/shared/api/host/profile-registries.ts
1481
+ var REGISTRY_MARKER = "# dsh-workbench 写的:这一行的包只在这个源上(dsh 卸载没有源参数,pnpm 得问得到)";
1482
+ function scopeOf(pkg) {
1483
+ const slash = pkg.indexOf("/");
1484
+ return pkg.startsWith("@") && slash > 1 ? pkg.slice(0, slash) : null;
1485
+ }
1486
+ function normalizeRegistry(url) {
1487
+ const trimmed = url.trim();
1488
+ return trimmed.endsWith("/") ? trimmed : `${trimmed}/`;
1489
+ }
1490
+ function sameRegistry(a, b) {
1491
+ if (a === null || a === void 0 || b === null || b === void 0) return false;
1492
+ if (a.trim() === "" || b.trim() === "") return false;
1493
+ return normalizeRegistry(a) === normalizeRegistry(b);
1494
+ }
1495
+ function registryRootOf(name, tarball) {
1496
+ const at = tarball.indexOf(`/${name}/-/`);
1497
+ if (at > 0) return normalizeRegistry(tarball.slice(0, at));
1498
+ try {
1499
+ return normalizeRegistry(new URL(tarball).origin);
1500
+ } catch {
1501
+ return null;
1502
+ }
1503
+ }
1504
+ var PACKAGE_KEY = /^ {2}'?(\S+)'?:\s*$/;
1505
+ var PACKAGE_NAME = /^(?:@[^/\s]+\/)?[^/\s@]+$/;
1506
+ var TARBALL = /tarball:\s*(\S+?)\}?\s*$/;
1507
+ function sourcesFromLockfile(text) {
1508
+ const found = /* @__PURE__ */ new Map();
1509
+ let name = null;
1510
+ for (const line of text.split("\n")) {
1511
+ const key = PACKAGE_KEY.exec(line);
1512
+ if (key !== null) {
1513
+ const raw = key[1] ?? "";
1514
+ const at = raw.lastIndexOf("@");
1515
+ const candidate = at > 0 ? raw.slice(0, at) : "";
1516
+ name = PACKAGE_NAME.test(candidate) ? candidate : null;
1517
+ continue;
1518
+ }
1519
+ if (name === null) continue;
1520
+ const tarball = TARBALL.exec(line);
1521
+ if (tarball === null) continue;
1522
+ const scope = scopeOf(name);
1523
+ const root = registryRootOf(name, tarball[1] ?? "");
1524
+ name = null;
1525
+ if (scope === null || root === null) continue;
1526
+ const seen = found.get(scope);
1527
+ if (seen === void 0) found.set(scope, root);
1528
+ else if (!sameRegistry(seen, root)) found.set(scope, null);
1529
+ }
1530
+ return [...found.entries()].filter((entry) => entry[1] !== null).map(([scope, registry]) => ({
1531
+ scope,
1532
+ registry
1533
+ }));
1534
+ }
1535
+ function mergeRegistryConfig(text, entries) {
1536
+ const lines = text.split("\n");
1537
+ const present = (key) => lines.some((line) => line.trim().startsWith(`${key}=`));
1538
+ const appended = [];
1539
+ const added = [];
1540
+ for (const entry of entries) {
1541
+ const key = `${entry.scope}:registry`;
1542
+ if (entry.registry.trim() === "" || present(key)) continue;
1543
+ lines.push(`${key}=${normalizeRegistry(entry.registry)}`);
1544
+ appended.push(`${key}=${normalizeRegistry(entry.registry)}`);
1545
+ added.push(key);
1546
+ }
1547
+ if (appended.length === 0) return {
1548
+ text,
1549
+ added: []
1550
+ };
1551
+ const base = text === "" ? "" : text.endsWith("\n") ? text : `${text}\n`;
1552
+ return {
1553
+ text: `${base}${base.includes("# dsh-workbench 写的:这一行的包只在这个源上(dsh 卸载没有源参数,pnpm 得问得到)") ? "" : `${REGISTRY_MARKER}\n`}${appended.join("\n")}\n`,
1554
+ added
1555
+ };
1556
+ }
1557
+ function registryFailure(change) {
1558
+ if (change.application !== "failed") return false;
1559
+ if (change.packageResult?.kind === "not-found") return true;
1560
+ const output = change.packageResult?.output ?? change.errorDetail ?? "";
1561
+ return /ERR_PNPM_[A-Z_]*FETCH/.test(output);
1562
+ }
1563
+ function createRegistryNotebook(dir) {
1564
+ return {
1565
+ sources() {
1566
+ if (dir === null) return [];
1567
+ try {
1568
+ return sourcesFromLockfile(fs.readFileSync(path.join(dir, "pnpm-lock.yaml"), "utf8"));
1569
+ } catch {
1570
+ return [];
1571
+ }
1572
+ },
1573
+ remember(entries) {
1574
+ if (dir === null || entries.length === 0) return [];
1575
+ const file = path.join(dir, ".npmrc");
1576
+ let before;
1577
+ try {
1578
+ before = fs.readFileSync(file, "utf8");
1579
+ } catch {
1580
+ before = "";
1581
+ }
1582
+ const merged = mergeRegistryConfig(before, entries);
1583
+ if (merged.added.length === 0) return [];
1584
+ const temp = `${file}.dsh-workbench.tmp`;
1585
+ fs.writeFileSync(temp, merged.text, { mode: 384 });
1586
+ fs.renameSync(temp, file);
1587
+ return merged.added;
1588
+ }
1589
+ };
1590
+ }
1591
+ //#endregion
1480
1592
  //#region src/shared/api/host/release.ts
1481
1593
  function parseLedgerVersion(stdout, name) {
1482
1594
  const parsed = parseJsonLoose(stdout);
@@ -1703,7 +1815,7 @@ function bundleNameOf(change, spec) {
1703
1815
  return at > 0 ? spec.slice(0, at) : spec;
1704
1816
  }
1705
1817
  function createMarketService(options) {
1706
- const { manifests, manifestsNow, probe, shell, logger, onInstalled, onUninstalled, isReleased, bundles, installed, modules } = options;
1818
+ const { manifests, manifestsNow, probe, shell, logger, onInstalled, onUninstalled, isReleased, bundles, installed, modules, registries } = options;
1707
1819
  const command = options.command ?? "opencli";
1708
1820
  const catalog = () => (manifestsNow?.() ?? manifests).filter((manifest) => (manifest.env?.plugins ?? []).length > 0 || (manifest.env?.libs ?? []).length > 0);
1709
1821
  function requireEntry(unit) {
@@ -1850,6 +1962,38 @@ function createMarketService(options) {
1850
1962
  };
1851
1963
  }
1852
1964
  }
1965
+ async function rememberInstalledSource(manager, pkg, registry) {
1966
+ if (registries === void 0 || registry === void 0) return;
1967
+ const scope = scopeOf(pkg);
1968
+ if (scope === null) return;
1969
+ const known = await manager.registries().catch(() => null);
1970
+ if (known !== null && sameRegistry(known.resolved, registry)) return;
1971
+ try {
1972
+ const added = registries.remember([{
1973
+ scope,
1974
+ registry
1975
+ }]);
1976
+ if (added.length > 0) logger?.info?.(`[dsh-workbench] 把 ${added.join("、")} 记进 profile 的 .npmrc(卸载只认 pnpm 的配置)`);
1977
+ } catch (error) {
1978
+ logger?.warn?.(`[dsh-workbench] 记这个 scope 的源失败:${String(error)}`);
1979
+ }
1980
+ }
1981
+ async function retryAfterRegistryFix(manager, pkg, change) {
1982
+ if (registries === void 0 || !registryFailure(change)) return change;
1983
+ const known = await manager.registries().catch(() => null);
1984
+ const missing = registries.sources().filter((entry) => !sameRegistry(entry.registry, known?.resolved ?? null));
1985
+ if (missing.length === 0) return change;
1986
+ let added;
1987
+ try {
1988
+ added = registries.remember(missing);
1989
+ } catch (error) {
1990
+ logger?.warn?.(`[dsh-workbench] 卸 ${pkg} 撞上源,但补配置失败:${String(error)}`);
1991
+ return change;
1992
+ }
1993
+ if (added.length === 0) return change;
1994
+ logger?.warn?.(`[dsh-workbench] 卸 ${pkg} 撞上源:补 ${added.join("、")} 后重试一次`);
1995
+ return await manager.remove(pkg).catch(() => null) ?? change;
1996
+ }
1853
1997
  const service = {
1854
1998
  async list() {
1855
1999
  return snapshot();
@@ -1955,7 +2099,8 @@ function createMarketService(options) {
1955
2099
  };
1956
2100
  },
1957
2101
  async installBundle(spec, options) {
1958
- const change = await requireBundles().install({
2102
+ const manager = requireBundles();
2103
+ const change = await manager.install({
1959
2104
  spec,
1960
2105
  ...options?.registry === void 0 ? {} : { registry: options.registry },
1961
2106
  ...options?.requestId === void 0 ? {} : { requestId: options.requestId },
@@ -1967,6 +2112,7 @@ function createMarketService(options) {
1967
2112
  kind: "unknown",
1968
2113
  pkg
1969
2114
  };
2115
+ await rememberInstalledSource(manager, pkg, options?.registry);
1970
2116
  return {
1971
2117
  change,
1972
2118
  module,
@@ -1982,8 +2128,9 @@ function createMarketService(options) {
1982
2128
  const unit = module.kind === "module" ? module.unit : void 0;
1983
2129
  const manifest = unit === void 0 ? void 0 : catalog().find((item) => item.id === unit);
1984
2130
  const before = unit === void 0 ? void 0 : await capabilityOf(unit, true);
1985
- const change = await manager.remove(pkg);
1986
- if (change === null) throw new Error("插件管理器回的卸载结果看不懂。");
2131
+ const first = await manager.remove(pkg);
2132
+ if (first === null) throw new Error("插件管理器回的卸载结果看不懂。");
2133
+ const change = await retryAfterRegistryFix(manager, pkg, first);
1987
2134
  if (change.application !== "applied" || unit === void 0) return {
1988
2135
  change,
1989
2136
  keptFor: []
@@ -2682,6 +2829,7 @@ var HOST_UNITS = [{
2682
2829
  bundles: readBundleManager(ctx),
2683
2830
  installed: (pkg) => readInstalledModule(profileDir, pkg),
2684
2831
  modules: () => profileModules(profileDir),
2832
+ registries: createRegistryNotebook(profileDir),
2685
2833
  onUninstalled: (unit) => {
2686
2834
  panels.release(unit);
2687
2835
  },
@@ -251,7 +251,7 @@ export declare const kit: {
251
251
  readonly "panels.market.empty": "\u6682\u65E0\u53EF\u7528\u6A21\u5757";
252
252
  readonly "panels.market.installedSection": "\u5DF2\u88C5";
253
253
  readonly "panels.market.moduleOutdated": "\u6709\u65B0\u7248";
254
- readonly "panels.market.moduleRestartHint": "\u5B89\u88C5\u5B8C\u6210\u540E\u53EF\u80FD\u9700\u8981\u91CD\u542F\u624D\u751F\u6548";
254
+ readonly "panels.market.moduleRestartHint": "\u88C5\u597D\u4E86\u4F46\u8FD8\u6CA1\u751F\u6548 \u2014\u2014 \u91CD\u542F\u4E00\u6B21 dsh \u5C31\u4F1A\u51FA\u6765";
255
255
  readonly "panels.market.restartNeeded": "\u65B0\u7248\u88C5\u597D\u4E86\uFF0C\u91CD\u542F\u4E00\u6B21\u624D\u751F\u6548\u3002";
256
256
  readonly "panels.market.foot": "\u88C5\u597D\u540E\u5230\u90A3\u4E2A\u9879\u76EE\u7684\u9762\u677F\u9875\u52FE\u9009\u5B83\uFF0C\u6A21\u5757\u624D\u4F1A\u51FA\u73B0\u3002";
257
257
  readonly "panels.market.recheck": "\u91CD\u65B0\u68C0\u67E5\u66F4\u65B0";
@@ -544,7 +544,7 @@ export declare const kit: {
544
544
  readonly "panels.market.empty": "\u6682\u65E0\u53EF\u7528\u6A21\u5757";
545
545
  readonly "panels.market.installedSection": "\u5DF2\u88C5";
546
546
  readonly "panels.market.moduleOutdated": "\u6709\u65B0\u7248";
547
- readonly "panels.market.moduleRestartHint": "\u5B89\u88C5\u5B8C\u6210\u540E\u53EF\u80FD\u9700\u8981\u91CD\u542F\u624D\u751F\u6548";
547
+ readonly "panels.market.moduleRestartHint": "\u88C5\u597D\u4E86\u4F46\u8FD8\u6CA1\u751F\u6548 \u2014\u2014 \u91CD\u542F\u4E00\u6B21 dsh \u5C31\u4F1A\u51FA\u6765";
548
548
  readonly "panels.market.restartNeeded": "\u65B0\u7248\u88C5\u597D\u4E86\uFF0C\u91CD\u542F\u4E00\u6B21\u624D\u751F\u6548\u3002";
549
549
  readonly "panels.market.foot": "\u88C5\u597D\u540E\u5230\u90A3\u4E2A\u9879\u76EE\u7684\u9762\u677F\u9875\u52FE\u9009\u5B83\uFF0C\u6A21\u5757\u624D\u4F1A\u51FA\u73B0\u3002";
550
550
  readonly "panels.market.recheck": "\u91CD\u65B0\u68C0\u67E5\u66F4\u65B0";
@@ -976,7 +976,7 @@ export declare const kit: {
976
976
  readonly "panels.market.empty": "\u6682\u65E0\u53EF\u7528\u6A21\u5757";
977
977
  readonly "panels.market.installedSection": "\u5DF2\u88C5";
978
978
  readonly "panels.market.moduleOutdated": "\u6709\u65B0\u7248";
979
- readonly "panels.market.moduleRestartHint": "\u5B89\u88C5\u5B8C\u6210\u540E\u53EF\u80FD\u9700\u8981\u91CD\u542F\u624D\u751F\u6548";
979
+ readonly "panels.market.moduleRestartHint": "\u88C5\u597D\u4E86\u4F46\u8FD8\u6CA1\u751F\u6548 \u2014\u2014 \u91CD\u542F\u4E00\u6B21 dsh \u5C31\u4F1A\u51FA\u6765";
980
980
  readonly "panels.market.restartNeeded": "\u65B0\u7248\u88C5\u597D\u4E86\uFF0C\u91CD\u542F\u4E00\u6B21\u624D\u751F\u6548\u3002";
981
981
  readonly "panels.market.foot": "\u88C5\u597D\u540E\u5230\u90A3\u4E2A\u9879\u76EE\u7684\u9762\u677F\u9875\u52FE\u9009\u5B83\uFF0C\u6A21\u5757\u624D\u4F1A\u51FA\u73B0\u3002";
982
982
  readonly "panels.market.recheck": "\u91CD\u65B0\u68C0\u67E5\u66F4\u65B0";
@@ -1269,7 +1269,7 @@ export declare const kit: {
1269
1269
  readonly "panels.market.empty": "\u6682\u65E0\u53EF\u7528\u6A21\u5757";
1270
1270
  readonly "panels.market.installedSection": "\u5DF2\u88C5";
1271
1271
  readonly "panels.market.moduleOutdated": "\u6709\u65B0\u7248";
1272
- readonly "panels.market.moduleRestartHint": "\u5B89\u88C5\u5B8C\u6210\u540E\u53EF\u80FD\u9700\u8981\u91CD\u542F\u624D\u751F\u6548";
1272
+ readonly "panels.market.moduleRestartHint": "\u88C5\u597D\u4E86\u4F46\u8FD8\u6CA1\u751F\u6548 \u2014\u2014 \u91CD\u542F\u4E00\u6B21 dsh \u5C31\u4F1A\u51FA\u6765";
1273
1273
  readonly "panels.market.restartNeeded": "\u65B0\u7248\u88C5\u597D\u4E86\uFF0C\u91CD\u542F\u4E00\u6B21\u624D\u751F\u6548\u3002";
1274
1274
  readonly "panels.market.foot": "\u88C5\u597D\u540E\u5230\u90A3\u4E2A\u9879\u76EE\u7684\u9762\u677F\u9875\u52FE\u9009\u5B83\uFF0C\u6A21\u5757\u624D\u4F1A\u51FA\u73B0\u3002";
1275
1275
  readonly "panels.market.recheck": "\u91CD\u65B0\u68C0\u67E5\u66F4\u65B0";
@@ -1696,7 +1696,7 @@ export declare const kit: {
1696
1696
  readonly "panels.market.empty": "\u6682\u65E0\u53EF\u7528\u6A21\u5757";
1697
1697
  readonly "panels.market.installedSection": "\u5DF2\u88C5";
1698
1698
  readonly "panels.market.moduleOutdated": "\u6709\u65B0\u7248";
1699
- readonly "panels.market.moduleRestartHint": "\u5B89\u88C5\u5B8C\u6210\u540E\u53EF\u80FD\u9700\u8981\u91CD\u542F\u624D\u751F\u6548";
1699
+ readonly "panels.market.moduleRestartHint": "\u88C5\u597D\u4E86\u4F46\u8FD8\u6CA1\u751F\u6548 \u2014\u2014 \u91CD\u542F\u4E00\u6B21 dsh \u5C31\u4F1A\u51FA\u6765";
1700
1700
  readonly "panels.market.restartNeeded": "\u65B0\u7248\u88C5\u597D\u4E86\uFF0C\u91CD\u542F\u4E00\u6B21\u624D\u751F\u6548\u3002";
1701
1701
  readonly "panels.market.foot": "\u88C5\u597D\u540E\u5230\u90A3\u4E2A\u9879\u76EE\u7684\u9762\u677F\u9875\u52FE\u9009\u5B83\uFF0C\u6A21\u5757\u624D\u4F1A\u51FA\u73B0\u3002";
1702
1702
  readonly "panels.market.recheck": "\u91CD\u65B0\u68C0\u67E5\u66F4\u65B0";
@@ -1989,7 +1989,7 @@ export declare const kit: {
1989
1989
  readonly "panels.market.empty": "\u6682\u65E0\u53EF\u7528\u6A21\u5757";
1990
1990
  readonly "panels.market.installedSection": "\u5DF2\u88C5";
1991
1991
  readonly "panels.market.moduleOutdated": "\u6709\u65B0\u7248";
1992
- readonly "panels.market.moduleRestartHint": "\u5B89\u88C5\u5B8C\u6210\u540E\u53EF\u80FD\u9700\u8981\u91CD\u542F\u624D\u751F\u6548";
1992
+ readonly "panels.market.moduleRestartHint": "\u88C5\u597D\u4E86\u4F46\u8FD8\u6CA1\u751F\u6548 \u2014\u2014 \u91CD\u542F\u4E00\u6B21 dsh \u5C31\u4F1A\u51FA\u6765";
1993
1993
  readonly "panels.market.restartNeeded": "\u65B0\u7248\u88C5\u597D\u4E86\uFF0C\u91CD\u542F\u4E00\u6B21\u624D\u751F\u6548\u3002";
1994
1994
  readonly "panels.market.foot": "\u88C5\u597D\u540E\u5230\u90A3\u4E2A\u9879\u76EE\u7684\u9762\u677F\u9875\u52FE\u9009\u5B83\uFF0C\u6A21\u5757\u624D\u4F1A\u51FA\u73B0\u3002";
1995
1995
  readonly "panels.market.recheck": "\u91CD\u65B0\u68C0\u67E5\u66F4\u65B0";
@@ -0,0 +1,4 @@
1
+ export interface GateDeadline {
2
+ disarm(): void;
3
+ }
4
+ export declare function createGateDeadline(giveUpMs: number, expire: () => void): GateDeadline;
@@ -0,0 +1,7 @@
1
+ import type { Translate } from '@dsh-workbench/shared';
2
+ export declare function MarketChecking({ t }: {
3
+ readonly t: Translate;
4
+ }): JSX.Element;
5
+ export declare function MarketEmpty({ t }: {
6
+ readonly t: Translate;
7
+ }): JSX.Element;
@@ -14,6 +14,7 @@ export interface MarketViewProps {
14
14
  readonly updates?: ModuleUpdateMap | undefined;
15
15
  readonly installed?: readonly InstalledWorkbenchModule[] | undefined;
16
16
  readonly installedRead?: boolean | undefined;
17
+ readonly settling?: ReadonlySet<string> | undefined;
17
18
  readonly mock?: MarketMock | undefined;
18
19
  }
19
- export declare function MarketView({ t, manifests, capabilities, freshness, onChanged, updates, installed, installedRead, mock, }: MarketViewProps): JSX.Element;
20
+ export declare function MarketView({ t, manifests, capabilities, freshness, onChanged, updates, installed, installedRead, settling, mock, }: MarketViewProps): JSX.Element;
@@ -0,0 +1,11 @@
1
+ import type { Translate } from '@dsh-workbench/shared';
2
+ import { type SharedRow } from './market-rows';
3
+ import { type Pending } from './market-view-text';
4
+ import type { MarketRowAction } from './market-rows';
5
+ export declare function SharedSection({ t, rows, pending, failureOf, act, }: {
6
+ readonly t: Translate;
7
+ readonly rows: readonly SharedRow[];
8
+ readonly pending: Pending | null;
9
+ readonly failureOf: (id: string) => string | null;
10
+ readonly act: (id: string, action: MarketRowAction) => Promise<void>;
11
+ }): JSX.Element | null;
@@ -0,0 +1,4 @@
1
+ import type { Translate } from '@dsh-workbench/shared';
2
+ import type { BundleChange } from '../../../shared/api/bundle-install';
3
+ export declare function changeOf(value: unknown): BundleChange | undefined;
4
+ export declare function changeFailure(change: BundleChange | undefined, t: Translate): string | undefined;
@@ -36,8 +36,10 @@ export interface InstalledWorkbenchModule {
36
36
  readonly installed: string;
37
37
  readonly latest?: string | undefined;
38
38
  }
39
- export declare function installedRows(modules: readonly InstalledWorkbenchModule[], manifests: readonly UnitManifest[], listed: ReadonlySet<string>): MarketRow[];
39
+ export declare function mergeTitles(known: ReadonlyMap<string, string>, manifests: readonly UnitManifest[]): ReadonlyMap<string, string>;
40
+ export declare function installedRows(modules: readonly InstalledWorkbenchModule[], manifests: readonly UnitManifest[], listed: ReadonlySet<string>, known?: ReadonlyMap<string, string> | undefined): MarketRow[];
40
41
  export declare function marketActions(row: MarketRow): MarketRowAction[];
42
+ export declare function liveManifests(manifests: readonly UnitManifest[], capabilities: CapabilityMap | null, installed: ReadonlySet<string> | null): readonly UnitManifest[];
41
43
  export declare function marketHasUpdates(rows: readonly MarketRow[], shared?: readonly SharedRow[]): boolean;
42
44
  export interface MarketSection {
43
45
  readonly id: 'installed' | 'not-installed';
@@ -0,0 +1,2 @@
1
+ export declare const MODULE_SETTLE_MS = 15000;
2
+ export declare function holdBack(installed: readonly string[], roster: ReadonlySet<string>, active: ReadonlySet<string>, previous: ReadonlySet<string> | null): readonly string[];
@@ -0,0 +1,10 @@
1
+ import type { MarketRowAction } from './market-rows';
2
+ export declare const PROGRESS_KEY: Readonly<Record<MarketRowAction, string>>;
3
+ export declare const ACTION_LABEL_KEY: Readonly<Record<MarketRowAction, string>>;
4
+ export interface Pending {
5
+ readonly id: string;
6
+ readonly action: MarketRowAction;
7
+ readonly titleKey?: string | undefined;
8
+ readonly pkg?: string | undefined;
9
+ readonly version?: string | undefined;
10
+ }
@@ -3,6 +3,7 @@ import type { PluginSource, UnitManifest } from '@dsh-workbench/shared';
3
3
  import type { BundleCancellation, BundleChange } from '../../../shared/api/bundle-install';
4
4
  import type { BundleManager } from '../../../shared/api/host/bundle-manager';
5
5
  import type { InstalledModule, ProfileModule } from '../../../shared/api/host/installed-module';
6
+ import { type RegistryNotebook } from '../../../shared/api/host/profile-registries';
6
7
  import type { UnitCapability } from '../../../shared/api/host/probe-units';
7
8
  import type { ProvisionAction } from '@dsh-workbench/shared/host';
8
9
  import type { UnitMountDeps } from '@dsh-workbench/shared/host';
@@ -81,6 +82,7 @@ export declare function createMarketService(options: {
81
82
  bundles?: BundleManager | undefined;
82
83
  installed?: ((pkg: string) => InstalledModule) | undefined;
83
84
  modules?: (() => readonly ProfileModule[]) | undefined;
85
+ registries?: RegistryNotebook | undefined;
84
86
  logger?: {
85
87
  info?(message: string): void;
86
88
  warn?(message: string): void;
@@ -0,0 +1,21 @@
1
+ import type { BundleChange } from '../bundle-install.js';
2
+ export interface RegistryEntry {
3
+ readonly scope: string;
4
+ readonly registry: string;
5
+ }
6
+ export interface RegistryNotebook {
7
+ sources(): readonly RegistryEntry[];
8
+ remember(entries: readonly RegistryEntry[]): readonly string[];
9
+ }
10
+ export declare const REGISTRY_MARKER = "# dsh-workbench \u5199\u7684\uFF1A\u8FD9\u4E00\u884C\u7684\u5305\u53EA\u5728\u8FD9\u4E2A\u6E90\u4E0A\uFF08dsh \u5378\u8F7D\u6CA1\u6709\u6E90\u53C2\u6570\uFF0Cpnpm \u5F97\u95EE\u5F97\u5230\uFF09";
11
+ export declare function scopeOf(pkg: string): string | null;
12
+ export declare function normalizeRegistry(url: string): string;
13
+ export declare function sameRegistry(a: string | null | undefined, b: string | null | undefined): boolean;
14
+ export declare function sourcesFromLockfile(text: string): readonly RegistryEntry[];
15
+ export interface RegistryConfigMerge {
16
+ readonly text: string;
17
+ readonly added: readonly string[];
18
+ }
19
+ export declare function mergeRegistryConfig(text: string, entries: readonly RegistryEntry[]): RegistryConfigMerge;
20
+ export declare function registryFailure(change: BundleChange): boolean;
21
+ export declare function createRegistryNotebook(dir: string | null): RegistryNotebook;
@@ -103,6 +103,7 @@ WORKBENCH_PORT=3091 pnpm run dev # 换端口(监听与实例同一个端口
103
103
  | API 凭据 | ❌ **有意共享** | `~/.dsh/.credentials.yaml`,两边同一把 key |
104
104
  | opencli 运行时(CLI + 插件) | ✅ | `~/.dsh/workbench/opencli/`(`HOME` 指到 `…/home`,见 [ADR-0014](../../../docs/adr/0014-opencli-cost-has-one-owner.md) §2.2) |
105
105
  | opencli **daemon** | ❌ **整机一个,隔离不了** | 端口 **19825 被扩展写死**(`background.js` 里 `DAEMON_PORT = 19825`;CLI 侧 `OPENCLI_DAEMON_PORT` 设非默认值直接报错)。所以本机的全局 opencli 与工作台的隔离运行时**抢同一个 daemon**:两边版本不一致时,谁的命令后跑谁就把 daemon 重启成自己那版 |
106
+ | profile 的 pnpm 源(私有 scope) | ⚠️ **由工作台写进去** | `<profile>/.npmrc` 里的 `@scope:registry=…`,前面带一行 `# dsh-workbench 写的…` 标记。**为什么在工作台这一侧写**:dsh 的卸载没有源参数(`runPnpm(['remove', name])`),pnpm 只能从 profile 的 `.npmrc` 链知道源;不写它,装私有源的模块能成、卸不了。规则与边界见 [ADR-0030](../../../docs/adr/0030-private-registries-live-in-the-profile-pnpm-config.md):只加不改、只写 scope 行、不碰 `~/.npmrc`。**删了会怎样**:下次从这个源装会再写回来;已经装着的那种,点卸载时撞 404 会自愈补回再重试一次 |
106
107
 
107
108
  ## 排障
108
109
 
@@ -113,6 +114,7 @@ WORKBENCH_PORT=3091 pnpm run dev # 换端口(监听与实例同一个端口
113
114
  | 面板显示"这个项目不是 Coding 仓库" | 该工作区的 git `origin` 不指向 `e.coding.net`(或没有 origin) |
114
115
  | 打开面板/按刷新要等 5–8 秒 | 正常:opencli 每次调用有**固定约 5 秒**开销(起浏览器会话;接口本身只要 ~260ms)。**没有缓存**——数据一律实时,列表 = 缺陷 + 状态目录两次调用(限并发 2,实测约 7 秒) |
115
116
  | 改了源码没变化 | 忘了 `pnpm run build`,或没重启进程(宿主缓存已加载的包) |
117
+ | 市场页点「卸载」报 `没成功:… ERR_PNPM_FETCH_404 GET https://registry.npmjs.org/@你的私有 scope/…` 之类 | 这个 profile 里的私有包不在 pnpm 默认源上,而 dsh 的卸载**不带源**。工作台会自己补上 `<profile>/.npmrc` 的 `@scope:registry=` 再重试一次([ADR-0030](../../../docs/adr/0030-private-registries-live-in-the-profile-pnpm-config.md));**还失败**说明那个包没有 scope(一行 scope 行表达不了),这时才需要人/agent 上手:`dsh plugin --profile <p> remove '<包名>' --config.registry=<那个源>`(`pnpm remove` 不认 `--registry=`),或者给 profile 自己配一行默认 `registry=` |
116
118
  | 体检那屏「检测浏览器通道 · 没连上」,可面板照样能用 | 本机全局 opencli 与隔离运行时版本不一致 ⇒ daemon 被顶成对方那版(`Stale daemon detected: daemon vX != CLI vY`)。下一条浏览器命令会自动把它重启回来,体检也会复检后改回「已连接」([ADR-0024](../../../docs/adr/0024-warm-the-sites-before-the-panel.md) §3.2.1)。**要彻底不抖**:让两边同版本 —— 把 `OPENCLI_PIN`(`src/shared/config/constants.ts`)对齐到 `opencli --version`,再 `npm i --prefix ~/.dsh/workbench/opencli/toolchain @jackwener/opencli@<那个版本> --cache ~/.dsh/workbench/opencli/npm-cache` |
117
119
  | Settings 页报 `overridden by a home patch` | 想在 Settings 里改的行被 `$DSH_HOME/cordis.patch.yml` 或 `--patch` 覆盖了 |
118
120
  | **别人机器上** `npx @dsh-workbench/core setup` 报 `scripts/seed-profile.sh: Permission denied`(或体检永远说"隔离运行时没装好") | 发出去的包里**随包脚本丢了 x 位**:`pnpm publish` 只给 `package.json#bin` 点名那条文件 755,其余一律 644(`npm pack` 会保留,而 `git` 里的 x 位不进 tarball —— 所以**本机永远复现不出来**)。0.1.6 的已知缺陷:应急 `chmod +x <包目录>/{scripts/seed-profile.sh,bin/opencli-isolated}`,正规解是升到 0.1.7(启动器与 `selfcheck` 已改成不吃 x 位) |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dsh-workbench/core",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "个人工作台:Agent 工作台外壳(左栏 + 常驻对话 + 自研右侧数据面板)。",
5
5
  "type": "module",
6
6
  "icon": "./icon.svg",
@@ -78,7 +78,7 @@
78
78
  "access": "public"
79
79
  },
80
80
  "dependencies": {
81
- "@dsh-workbench/shared": "0.1.8"
81
+ "@dsh-workbench/shared": "0.1.9"
82
82
  },
83
83
  "scripts": {
84
84
  "build": "node scripts/build.mjs && node scripts/build-types.mjs",