@dsh-workbench/shared 1.1.8 → 1.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.
- package/dist/api/blocker-table.d.ts +1 -0
- package/dist/api/blocker-table.js +1 -1
- package/dist/components/SelectField.css +0 -6
- package/dist/components/SelectField.d.ts +2 -3
- package/dist/components/SelectField.js +9 -30
- package/dist/components/SelectFieldNodes.d.ts +3 -1
- package/dist/components/SelectFieldNodes.js +2 -1
- package/dist/components/SelectFieldWheel.d.ts +9 -0
- package/dist/components/SelectFieldWheel.js +35 -0
- package/dist/config/constants.d.ts +4 -4
- package/dist/config/constants.js +4 -4
- package/dist/contract/capabilities.d.ts +29 -0
- package/dist/contract/capabilities.js +1 -0
- package/dist/contract/needs.d.ts +3 -3
- package/dist/contract/needs.js +1 -1
- package/dist/contract/plugin-source.d.ts +19 -0
- package/dist/contract/protocol/bundle-install.d.ts +3 -1
- package/dist/contract/protocol/bundle-install.js +3 -0
- package/dist/contract/protocol/platform.d.ts +1 -1
- package/dist/contract/runner.d.ts +6 -0
- package/dist/contract/runner.js +1 -0
- package/dist/contract/unit.d.ts +4 -4
- package/dist/host/adapter-contract.d.ts +3 -0
- package/dist/host/adapter-contract.js +93 -0
- package/dist/host/adapter-set.js +6 -4
- package/dist/host/adapter-types.d.ts +1 -1
- package/dist/host/bundle-manager.d.ts +3 -0
- package/dist/host/bundle-manager.js +181 -0
- package/dist/host/cli.js +3 -1
- package/dist/host/config-sync.d.ts +48 -0
- package/dist/host/config-sync.js +342 -0
- package/dist/host/dsh-plugins.d.ts +5 -0
- package/dist/host/dsh-plugins.js +51 -0
- package/dist/host/extension.js +1 -1
- package/dist/host/flow/check.d.ts +9 -0
- package/dist/host/flow/check.js +179 -0
- package/dist/host/flow/expr.d.ts +30 -0
- package/dist/host/flow/expr.js +99 -0
- package/dist/host/flow/kit.d.ts +14 -0
- package/dist/host/flow/kit.js +13 -0
- package/dist/host/flow/run.d.ts +13 -0
- package/dist/host/flow/run.js +287 -0
- package/dist/host/flow/types.d.ts +188 -0
- package/dist/host/flow/types.js +1 -0
- package/dist/host/host-actions.d.ts +2 -0
- package/dist/host/host-actions.js +5 -0
- package/dist/host/host-kit.d.ts +19 -0
- package/dist/host/host-kit.js +14 -0
- package/dist/host/http.d.ts +2 -6
- package/dist/host/http.js +2 -2
- package/dist/host/installed-module.d.ts +23 -0
- package/dist/host/installed-module.js +264 -0
- package/dist/host/lib-install.d.ts +7 -9
- package/dist/host/lib-install.js +9 -12
- package/dist/host/lib-runners.d.ts +3 -5
- package/dist/host/lib-runners.js +2 -2
- package/dist/host/local-declaration.d.ts +7 -0
- package/dist/host/local-declaration.js +33 -0
- package/dist/host/module-root.d.ts +1 -0
- package/dist/host/module-root.js +5 -0
- package/dist/host/npm-registry.d.ts +10 -0
- package/dist/host/npm-registry.js +16 -0
- package/dist/host/opencli-runner.d.ts +2 -1
- package/dist/host/package-content.d.ts +7 -0
- package/dist/host/package-content.js +69 -0
- package/dist/host/package-kind.d.ts +13 -0
- package/dist/host/package-kind.js +51 -0
- package/dist/host/package-route.d.ts +31 -0
- package/dist/host/package-route.js +57 -0
- package/dist/host/paths.d.ts +11 -19
- package/dist/host/paths.js +16 -43
- package/dist/host/platform.js +1 -1
- package/dist/host/plugin-ledger.d.ts +8 -8
- package/dist/host/plugin-ledger.js +23 -16
- package/dist/host/plugin.d.ts +1 -2
- package/dist/host/plugin.js +4 -5
- package/dist/host/port-types.d.ts +42 -9
- package/dist/host/preflight.d.ts +3 -2
- package/dist/host/profile-create.d.ts +18 -0
- package/dist/host/profile-create.js +118 -0
- package/dist/host/profile-registries.d.ts +10 -0
- package/dist/host/profile-registries.js +150 -0
- package/dist/host/registry-declaration.d.ts +21 -0
- package/dist/host/registry-declaration.js +33 -0
- package/dist/host/release-probe.d.ts +34 -0
- package/dist/host/release-probe.js +88 -0
- package/dist/host/runner.d.ts +26 -0
- package/dist/host/runner.js +50 -0
- package/dist/host/shell.d.ts +0 -2
- package/dist/host/shell.js +0 -7
- package/dist/host/spec.js +1 -1
- package/dist/host/supply-index.d.ts +1 -0
- package/dist/host/supply-index.js +8 -7
- package/dist/host/supply-port.js +13 -3
- package/dist/host/unit-face.d.ts +2 -1
- package/dist/host/version.js +11 -6
- package/dist/host.d.ts +24 -6
- package/dist/host.js +23 -6
- package/dist/i18n/en.js +16 -19
- package/dist/i18n/index.d.ts +17 -20
- package/dist/i18n/runtime-terms.d.ts +15 -0
- package/dist/i18n/runtime-terms.js +22 -0
- package/dist/i18n/zh.d.ts +16 -19
- package/dist/i18n/zh.js +16 -19
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/dist/testing/fake-adapter-set.d.ts +5 -0
- package/dist/testing/fake-adapter-set.js +150 -0
- package/dist/testing/needs.js +1 -1
- package/dist/testing.d.ts +1 -0
- package/dist/testing.js +1 -0
- package/package.json +1 -1
- package/src/api/__tests__/blocker-table.test.ts +25 -0
- package/src/api/{workbench-client.test.ts → __tests__/workbench-client.test.ts} +2 -2
- package/src/api/blocker-table.ts +6 -2
- package/src/components/SelectField.css +0 -6
- package/src/components/SelectField.tsx +7 -36
- package/src/components/SelectFieldNodes.tsx +4 -1
- package/src/components/{Card.test.tsx → __tests__/Card.test.tsx} +2 -2
- package/src/components/{CardAnchor.test.tsx → __tests__/CardAnchor.test.tsx} +3 -3
- package/src/components/{CardHead.test.tsx → __tests__/CardHead.test.tsx} +1 -1
- package/src/components/{ChoiceGroup.test.tsx → __tests__/ChoiceGroup.test.tsx} +2 -2
- package/src/components/{ConfirmBar.test.tsx → __tests__/ConfirmBar.test.tsx} +5 -5
- package/src/components/{Field.test.tsx → __tests__/Field.test.tsx} +1 -1
- package/src/components/{Form.test.tsx → __tests__/Form.test.tsx} +5 -5
- package/src/components/{FormActions.test.tsx → __tests__/FormActions.test.tsx} +3 -3
- package/src/components/{FormRows.test.tsx → __tests__/FormRows.test.tsx} +2 -2
- package/src/components/{FormTypes.test.ts → __tests__/FormTypes.test.ts} +1 -1
- package/src/components/{FormWiring.test.tsx → __tests__/FormWiring.test.tsx} +4 -4
- package/src/components/{Link.test.tsx → __tests__/Link.test.tsx} +1 -1
- package/src/components/{Rows.test.tsx → __tests__/Rows.test.tsx} +2 -2
- package/src/components/{SelectField.test.tsx → __tests__/SelectField.test.tsx} +7 -37
- package/src/components/{Spinner.test.tsx → __tests__/Spinner.test.tsx} +4 -4
- package/src/config/{constants.test.ts → __tests__/constants.test.ts} +1 -1
- package/src/config/{storage.test.ts → __tests__/storage.test.ts} +1 -1
- package/src/config/constants.ts +4 -4
- package/src/contract/capabilities.ts +30 -0
- package/src/contract/needs.ts +4 -4
- package/src/contract/plugin-source.ts +24 -0
- package/src/contract/protocol/bundle-install.ts +7 -1
- package/src/contract/protocol/platform.ts +1 -1
- package/src/contract/runner.ts +6 -0
- package/src/contract/unit.ts +4 -4
- package/src/host/{extension.test.ts → __tests__/extension.test.ts} +4 -4
- package/src/host/{install-failure.test.ts → __tests__/install-failure.test.ts} +1 -1
- package/src/host/{installed-sources.test.ts → __tests__/installed-sources.test.ts} +1 -1
- package/src/host/__tests__/lib-runners.test.ts +11 -2
- package/src/host/__tests__/plugin-ledger.test.ts +19 -6
- package/src/host/{recipe.test.ts → __tests__/recipe.test.ts} +3 -3
- package/src/host/__tests__/runtime-layout.test.ts +14 -0
- package/src/host/__tests__/supply-index.test.ts +2 -2
- package/src/host/__tests__/supply-port.test.ts +32 -0
- package/src/host/adapter-contract.ts +93 -0
- package/src/host/adapter-set.ts +6 -4
- package/src/host/adapter-types.ts +1 -1
- package/src/host/bundle-manager.ts +195 -0
- package/src/host/cli.ts +3 -1
- package/src/host/config-sync.ts +386 -0
- package/src/host/dsh-plugins.ts +60 -0
- package/src/host/extension.ts +1 -1
- package/src/host/flow/__tests__/advanced.test.ts +302 -0
- package/src/host/flow/__tests__/check.test.ts +169 -0
- package/src/host/flow/__tests__/run.test.ts +301 -0
- package/src/host/flow/check.ts +216 -0
- package/src/host/flow/expr.ts +94 -0
- package/src/host/flow/kit.ts +30 -0
- package/src/host/flow/run.ts +325 -0
- package/src/host/flow/types.ts +199 -0
- package/src/host/host-actions.ts +7 -0
- package/src/host/host-kit.ts +26 -0
- package/src/host/http.ts +6 -8
- package/src/host/installed-module.ts +272 -0
- package/src/host/lib-install.ts +14 -12
- package/src/host/lib-runners.ts +6 -8
- package/src/host/local-declaration.ts +37 -0
- package/src/host/module-root.ts +6 -0
- package/src/host/npm-registry.ts +21 -0
- package/src/host/package-content.ts +76 -0
- package/src/host/package-kind.ts +63 -0
- package/src/host/package-route.ts +93 -0
- package/src/host/paths.ts +27 -52
- package/src/host/platform.ts +1 -1
- package/src/host/plugin-ledger.ts +25 -18
- package/src/host/plugin.ts +4 -5
- package/src/host/port-types.ts +43 -9
- package/src/host/preflight.ts +3 -2
- package/src/host/profile-create.ts +133 -0
- package/src/host/profile-registries.ts +145 -0
- package/src/host/registry-declaration.ts +70 -0
- package/src/host/release-probe.ts +202 -0
- package/src/host/shell.ts +0 -9
- package/src/host/spec.ts +1 -1
- package/src/host/supply-index.ts +9 -7
- package/src/host/supply-port.ts +13 -3
- package/src/host/unit-face.ts +2 -1
- package/src/host/version.ts +12 -7
- package/src/host.ts +34 -6
- package/src/i18n/{index.test.ts → __tests__/index.test.ts} +3 -3
- package/src/i18n/{merge.test.ts → __tests__/merge.test.ts} +1 -1
- package/src/i18n/{zh.test.ts → __tests__/zh.test.ts} +2 -2
- package/src/i18n/en.ts +16 -20
- package/src/i18n/runtime-terms.ts +26 -0
- package/src/i18n/zh.ts +16 -20
- package/src/index.ts +4 -0
- package/src/lib/{board-fact.test.ts → __tests__/board-fact.test.ts} +1 -1
- package/src/lib/{busy.test.ts → __tests__/busy.test.ts} +1 -1
- package/src/lib/{form-problem.test.ts → __tests__/form-problem.test.ts} +1 -1
- package/src/lib/{git-address.test.ts → __tests__/git-address.test.ts} +1 -1
- package/src/lib/{react.test.ts → __tests__/react.test.ts} +1 -1
- package/src/lib/{text.test.ts → __tests__/text.test.ts} +1 -1
- package/src/lib/{ui.test.ts → __tests__/ui.test.ts} +1 -1
- package/src/testing/__tests__/fake-adapter-set.test.ts +28 -0
- package/src/testing/fake-adapter-set.ts +173 -0
- package/src/testing/needs.ts +1 -1
- package/src/testing.ts +1 -0
- package/src/host/__tests__/command-name.test.ts +0 -16
- package/src/host/__tests__/opencli-runner.test.ts +0 -120
- package/src/host/channel-plugin.ts +0 -55
- package/src/host/command-name.ts +0 -15
- package/src/host/opencli-runner.ts +0 -76
- package/src/host/paths.test.ts +0 -26
- package/src/host/plugin-source.ts +0 -137
- package/src/host/runtime-links.test.ts +0 -31
- package/src/host/runtime-links.ts +0 -23
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { localDirOf } from './spec.js';
|
|
4
|
+
export { localDirOf };
|
|
5
|
+
import { declarationProblemsOf } from '../contract/unit-declaration.js';
|
|
6
|
+
function asRecord(value) {
|
|
7
|
+
return typeof value === 'object' && value !== null ? value : undefined;
|
|
8
|
+
}
|
|
9
|
+
export function packageManifestOf(dir) {
|
|
10
|
+
try {
|
|
11
|
+
const parsed = JSON.parse(fs.readFileSync(path.join(dir, 'package.json'), 'utf8'));
|
|
12
|
+
return asRecord(parsed);
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return undefined;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export function dshRecordOf(dir) {
|
|
19
|
+
return packageManifestOf(dir)?.dsh;
|
|
20
|
+
}
|
|
21
|
+
export function packageNameOf(dir) {
|
|
22
|
+
const name = packageManifestOf(dir)?.name;
|
|
23
|
+
return typeof name === 'string' && name.trim() !== '' ? name.trim() : undefined;
|
|
24
|
+
}
|
|
25
|
+
export function pathDeclarationOf(spec) {
|
|
26
|
+
const dir = localDirOf(spec);
|
|
27
|
+
return dir === undefined ? undefined : asRecord(dshRecordOf(dir))?.workbench;
|
|
28
|
+
}
|
|
29
|
+
export function declarationRefusalOf(name, raw) {
|
|
30
|
+
if (raw === undefined)
|
|
31
|
+
return [];
|
|
32
|
+
return declarationProblemsOf(name, raw);
|
|
33
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function packageRootOf(moduleUrl: string): string;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare function npmRegistryOf(source: {
|
|
2
|
+
readonly registryEnv?: string;
|
|
3
|
+
readonly registryDefault?: string;
|
|
4
|
+
}, env: Readonly<Record<string, string | undefined>>): {
|
|
5
|
+
readonly ok: true;
|
|
6
|
+
readonly value: string;
|
|
7
|
+
} | {
|
|
8
|
+
readonly ok: false;
|
|
9
|
+
readonly env: string;
|
|
10
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
function envValue(env, name) {
|
|
2
|
+
const value = env[name]?.trim();
|
|
3
|
+
return value === undefined || value === '' ? { ok: false } : { ok: true, value };
|
|
4
|
+
}
|
|
5
|
+
export function npmRegistryOf(source, env) {
|
|
6
|
+
const name = source.registryEnv ?? '';
|
|
7
|
+
if (name !== '') {
|
|
8
|
+
const fromEnv = envValue(env, name);
|
|
9
|
+
if (fromEnv.ok)
|
|
10
|
+
return fromEnv;
|
|
11
|
+
}
|
|
12
|
+
const fallback = source.registryDefault?.trim();
|
|
13
|
+
if (fallback === undefined || fallback === '')
|
|
14
|
+
return { ok: false, env: name };
|
|
15
|
+
return { ok: true, value: fallback };
|
|
16
|
+
}
|
|
@@ -2,9 +2,10 @@ import type { DataRequest, DataResult } from '../contract/data.js';
|
|
|
2
2
|
/**
|
|
3
3
|
* 一条 opencli 命令的执行器:同一形状的 `execFile('opencli', args)`,结果只留 stdout。
|
|
4
4
|
*/
|
|
5
|
-
export type
|
|
5
|
+
export type LibRunner = (args: readonly string[]) => Promise<{
|
|
6
6
|
readonly stdout: string;
|
|
7
7
|
}>;
|
|
8
|
+
export type OpencliRunner = LibRunner;
|
|
8
9
|
/**
|
|
9
10
|
* 读缝(`DataReader.read`)的形状;模块直接把自己的 `data.read` 传进来即可。
|
|
10
11
|
*/
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { DshShell } from '../api/dsh.js';
|
|
2
|
+
export declare function withPackageDir<T>(options: {
|
|
3
|
+
readonly shell?: DshShell | undefined;
|
|
4
|
+
readonly spec: string;
|
|
5
|
+
readonly registry?: string | undefined;
|
|
6
|
+
readonly cacheDir?: string | undefined;
|
|
7
|
+
}, visit: (dir: string) => T): Promise<T | undefined>;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { INSTALL_TIMEOUT_MS } from '../config/constants.js';
|
|
5
|
+
import { parseJsonLoose } from '../lib/text.js';
|
|
6
|
+
import { quoteShellArg } from './shell-text.js';
|
|
7
|
+
import { runShell } from './shell.js';
|
|
8
|
+
import { splitNpmSpec } from './package-kind.js';
|
|
9
|
+
import { localDirOf } from './local-declaration.js';
|
|
10
|
+
function cacheFlag(cacheDir) {
|
|
11
|
+
return cacheDir === undefined ? '' : ` --cache ${quoteShellArg(cacheDir)}`;
|
|
12
|
+
}
|
|
13
|
+
function packedFileFrom(stdout, root) {
|
|
14
|
+
const parsed = parseJsonLoose(stdout);
|
|
15
|
+
if (Array.isArray(parsed)) {
|
|
16
|
+
const first = parsed[0];
|
|
17
|
+
const filename = typeof first === 'object' && first !== null ? first.filename : undefined;
|
|
18
|
+
if (typeof filename === 'string' && filename.trim() !== '') {
|
|
19
|
+
const at = path.join(root, path.basename(filename.trim()));
|
|
20
|
+
if (fs.existsSync(at))
|
|
21
|
+
return at;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
try {
|
|
25
|
+
const found = fs.readdirSync(root).filter((name) => name.endsWith('.tgz'));
|
|
26
|
+
return found.length === 1 ? path.join(root, found[0] ?? '') : undefined;
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export async function withPackageDir(options, visit) {
|
|
33
|
+
const local = localDirOf(options.spec);
|
|
34
|
+
if (local !== undefined)
|
|
35
|
+
return visit(local);
|
|
36
|
+
if (splitNpmSpec(options.spec) === undefined)
|
|
37
|
+
return undefined;
|
|
38
|
+
const shell = options.shell;
|
|
39
|
+
if (shell === undefined)
|
|
40
|
+
return undefined;
|
|
41
|
+
let root;
|
|
42
|
+
try {
|
|
43
|
+
root = fs.mkdtempSync(path.join(os.tmpdir(), 'wb-package-'));
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
48
|
+
try {
|
|
49
|
+
const at = options.registry === undefined ? '' : ` --registry ${quoteShellArg(options.registry)}`;
|
|
50
|
+
const packed = await runShell(shell, `npm pack ${quoteShellArg(options.spec)} --ignore-scripts --json --pack-destination ${quoteShellArg(root)}${cacheFlag(options.cacheDir)}${at}`, { timeoutMs: INSTALL_TIMEOUT_MS }).catch(() => undefined);
|
|
51
|
+
if (packed === undefined || packed.exitCode !== 0)
|
|
52
|
+
return undefined;
|
|
53
|
+
const file = packedFileFrom(packed.stdout, root);
|
|
54
|
+
if (file === undefined)
|
|
55
|
+
return undefined;
|
|
56
|
+
const unpacked = await runShell(shell, `tar -xzf ${quoteShellArg(file)} -C ${quoteShellArg(root)}`, {
|
|
57
|
+
timeoutMs: INSTALL_TIMEOUT_MS,
|
|
58
|
+
}).catch(() => undefined);
|
|
59
|
+
if (unpacked === undefined || unpacked.exitCode !== 0)
|
|
60
|
+
return undefined;
|
|
61
|
+
const dir = path.join(root, 'package');
|
|
62
|
+
if (!fs.existsSync(dir))
|
|
63
|
+
return undefined;
|
|
64
|
+
return visit(dir);
|
|
65
|
+
}
|
|
66
|
+
finally {
|
|
67
|
+
fs.rmSync(root, { recursive: true, force: true });
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export { splitNpmSpec } from './spec.js';
|
|
2
|
+
export type { NpmRef } from './spec.js';
|
|
3
|
+
export type PackageKind = 'runtime-plugin' | 'dsh-bundle' | 'both' | 'neither';
|
|
4
|
+
export interface PackageVerdict {
|
|
5
|
+
readonly kind: PackageKind;
|
|
6
|
+
readonly pkg?: string;
|
|
7
|
+
readonly pluginName?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function isCommandFile(name: string): boolean;
|
|
10
|
+
export declare function pluginManifestOf(dir: string, manifestFile: string): Readonly<Record<string, unknown>> | undefined;
|
|
11
|
+
export declare function hasCommandFile(dir: string): boolean;
|
|
12
|
+
export declare function dshMarkersOf(raw: unknown): boolean;
|
|
13
|
+
export declare function verdictOf(dir: string, manifestFile: string): PackageVerdict | undefined;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
export { splitNpmSpec } from './spec.js';
|
|
4
|
+
import { dshRecordOf, packageManifestOf, packageNameOf } from './local-declaration.js';
|
|
5
|
+
import { pluginAt } from './plugin.js';
|
|
6
|
+
function asRecord(value) {
|
|
7
|
+
return typeof value === 'object' && value !== null ? value : undefined;
|
|
8
|
+
}
|
|
9
|
+
export function isCommandFile(name) {
|
|
10
|
+
if (name.endsWith('.d.ts') || name.endsWith('.test.ts'))
|
|
11
|
+
return false;
|
|
12
|
+
if (name.endsWith('.d.js'))
|
|
13
|
+
return false;
|
|
14
|
+
return name.endsWith('.ts') || name.endsWith('.js');
|
|
15
|
+
}
|
|
16
|
+
export function pluginManifestOf(dir, manifestFile) {
|
|
17
|
+
try {
|
|
18
|
+
const parsed = JSON.parse(fs.readFileSync(path.join(dir, manifestFile), 'utf8'));
|
|
19
|
+
if (Array.isArray(parsed))
|
|
20
|
+
return undefined;
|
|
21
|
+
return asRecord(parsed);
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export function hasCommandFile(dir) {
|
|
28
|
+
try {
|
|
29
|
+
return fs.readdirSync(dir).some(isCommandFile);
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
export function dshMarkersOf(raw) {
|
|
36
|
+
const record = asRecord(raw);
|
|
37
|
+
return record !== undefined && ('bundle' in record || 'workbench' in record);
|
|
38
|
+
}
|
|
39
|
+
export function verdictOf(dir, manifestFile) {
|
|
40
|
+
const plugin = pluginAt(dir, manifestFile);
|
|
41
|
+
if (packageManifestOf(dir) === undefined && plugin === undefined)
|
|
42
|
+
return undefined;
|
|
43
|
+
const dsh = dshMarkersOf(dshRecordOf(dir));
|
|
44
|
+
const kind = plugin !== undefined && dsh ? 'both' : plugin !== undefined ? 'runtime-plugin' : dsh ? 'dsh-bundle' : 'neither';
|
|
45
|
+
const pkg = packageNameOf(dir);
|
|
46
|
+
return {
|
|
47
|
+
kind,
|
|
48
|
+
...(pkg === undefined ? {} : { pkg }),
|
|
49
|
+
...(plugin?.name === undefined ? {} : { pluginName: plugin.name }),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { DshShell } from '../api/dsh.js';
|
|
2
|
+
export type PackageRouteKind = 'runtime-plugin' | 'dsh-bundle' | 'neither';
|
|
3
|
+
export interface PackageRoute {
|
|
4
|
+
readonly kind: PackageRouteKind;
|
|
5
|
+
readonly pkg?: string;
|
|
6
|
+
readonly pluginName?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface PackageRouter {
|
|
9
|
+
packageRouteOf(options: RouteOptions): Promise<PackageRoute | undefined>;
|
|
10
|
+
reset(): void;
|
|
11
|
+
}
|
|
12
|
+
interface RouteOptions {
|
|
13
|
+
readonly spec: string;
|
|
14
|
+
readonly shell?: DshShell | undefined;
|
|
15
|
+
readonly registry?: string | undefined;
|
|
16
|
+
readonly force?: boolean;
|
|
17
|
+
}
|
|
18
|
+
export interface PackageRouterOptions {
|
|
19
|
+
readonly manifestFile: string;
|
|
20
|
+
readonly cacheDir?: string | undefined;
|
|
21
|
+
readonly dshLookup?: ((options: {
|
|
22
|
+
shell: DshShell;
|
|
23
|
+
name: string;
|
|
24
|
+
registry: string;
|
|
25
|
+
}) => Promise<{
|
|
26
|
+
readable: boolean;
|
|
27
|
+
raw: unknown;
|
|
28
|
+
}>) | undefined;
|
|
29
|
+
}
|
|
30
|
+
export declare function createPackageRouter(options: PackageRouterOptions): PackageRouter;
|
|
31
|
+
export {};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { VERSION_CHECK_TTL_MS } from '../config/constants.js';
|
|
2
|
+
import { dshMarkersOf, splitNpmSpec, verdictOf } from './package-kind.js';
|
|
3
|
+
import { withPackageDir } from './package-content.js';
|
|
4
|
+
import { localDirOf } from './local-declaration.js';
|
|
5
|
+
function routeOfVerdict(verdict, fallback) {
|
|
6
|
+
const pkg = verdict.pkg ?? fallback;
|
|
7
|
+
if (verdict.kind === 'neither')
|
|
8
|
+
return { kind: 'neither', ...(pkg === undefined ? {} : { pkg }) };
|
|
9
|
+
if (verdict.kind === 'dsh-bundle' || verdict.kind === 'both')
|
|
10
|
+
return { kind: 'dsh-bundle' };
|
|
11
|
+
return {
|
|
12
|
+
kind: 'runtime-plugin',
|
|
13
|
+
...(pkg === undefined ? {} : { pkg }),
|
|
14
|
+
...(verdict.pluginName === undefined ? {} : { pluginName: verdict.pluginName }),
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export function createPackageRouter(options) {
|
|
18
|
+
const cache = new Map();
|
|
19
|
+
return {
|
|
20
|
+
packageRouteOf: (routeOptions) => routeOf(cache, options, routeOptions),
|
|
21
|
+
reset: () => {
|
|
22
|
+
cache.clear();
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
async function routeOf(cache, options, routeOptions) {
|
|
27
|
+
const local = localDirOf(routeOptions.spec);
|
|
28
|
+
if (local !== undefined) {
|
|
29
|
+
const verdict = verdictOf(local, options.manifestFile);
|
|
30
|
+
return verdict === undefined ? undefined : routeOfVerdict(verdict, splitNpmSpec(routeOptions.spec)?.name);
|
|
31
|
+
}
|
|
32
|
+
const ref = splitNpmSpec(routeOptions.spec);
|
|
33
|
+
if (ref === undefined)
|
|
34
|
+
return undefined;
|
|
35
|
+
const shell = routeOptions.shell;
|
|
36
|
+
const registry = routeOptions.registry;
|
|
37
|
+
if (shell === undefined || registry === undefined)
|
|
38
|
+
return undefined;
|
|
39
|
+
const key = `${registry}|${routeOptions.spec}`;
|
|
40
|
+
const hit = cache.get(key);
|
|
41
|
+
if (routeOptions.force !== true && hit !== undefined && Date.now() - hit.at < VERSION_CHECK_TTL_MS) {
|
|
42
|
+
return hit.route ?? undefined;
|
|
43
|
+
}
|
|
44
|
+
const found = options.dshLookup === undefined
|
|
45
|
+
? { readable: false, raw: undefined }
|
|
46
|
+
: await options.dshLookup({ shell, name: routeOptions.spec, registry });
|
|
47
|
+
let route;
|
|
48
|
+
if (found.readable && dshMarkersOf(found.raw)) {
|
|
49
|
+
route = { kind: 'dsh-bundle' };
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
const verdict = await withPackageDir({ shell, spec: routeOptions.spec, registry, ...(options.cacheDir === undefined ? {} : { cacheDir: options.cacheDir }) }, (dir) => verdictOf(dir, options.manifestFile));
|
|
53
|
+
route = verdict === undefined ? undefined : routeOfVerdict(verdict, ref.name);
|
|
54
|
+
}
|
|
55
|
+
cache.set(key, { at: Date.now(), route: route ?? null });
|
|
56
|
+
return route;
|
|
57
|
+
}
|
package/dist/host/paths.d.ts
CHANGED
|
@@ -1,19 +1,11 @@
|
|
|
1
|
-
export
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
export declare function npmCacheDir(): string;
|
|
13
|
-
export declare function libsBinDir(): string;
|
|
14
|
-
/**
|
|
15
|
-
* 把隔离运行时的共用依赖 bin 目录放到 PATH 最前面(可执行文件都从这儿找)。
|
|
16
|
-
* @param env 改哪份环境(默认当前进程)。
|
|
17
|
-
* @returns 真的插进去了就 `true`;已经在里面就 `false`。
|
|
18
|
-
*/
|
|
19
|
-
export declare function ensureLibsBinOnPath(env?: NodeJS.ProcessEnv): boolean;
|
|
1
|
+
export interface RuntimeLayout {
|
|
2
|
+
readonly root: string;
|
|
3
|
+
readonly home: string;
|
|
4
|
+
readonly vendorPrefix: string;
|
|
5
|
+
readonly vendorPluginsDir: string;
|
|
6
|
+
readonly libsPrefix: string;
|
|
7
|
+
readonly libsBinDir: string;
|
|
8
|
+
readonly npmCacheDir: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function runtimeRootOf(id: string): string;
|
|
11
|
+
export declare function runtimeLayoutOf(id: string): RuntimeLayout;
|
package/dist/host/paths.js
CHANGED
|
@@ -1,45 +1,18 @@
|
|
|
1
|
-
import { delimiter } from 'node:path';
|
|
2
1
|
import { workbenchRoot } from './data-root.js';
|
|
3
|
-
export function
|
|
4
|
-
return `${workbenchRoot()}
|
|
5
|
-
}
|
|
6
|
-
export function
|
|
7
|
-
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
return
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export function toolchainOpencliDir() {
|
|
20
|
-
return `${isolatedRoot()}/toolchain/node_modules/${OPENCLI_NPM_PACKAGE}`;
|
|
21
|
-
}
|
|
22
|
-
export function vendorPeerLink() {
|
|
23
|
-
const base = `${vendorPrefix()}/node_modules`;
|
|
24
|
-
const [scope] = OPENCLI_NPM_PACKAGE.split('/');
|
|
25
|
-
return { dir: `${base}/${OPENCLI_NPM_PACKAGE}`, parent: `${base}/${scope}` };
|
|
26
|
-
}
|
|
27
|
-
export function npmCacheDir() {
|
|
28
|
-
return `${isolatedRoot()}/npm-cache`;
|
|
29
|
-
}
|
|
30
|
-
export function libsBinDir() {
|
|
31
|
-
return `${libsPrefix()}/node_modules/.bin`;
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* 把隔离运行时的共用依赖 bin 目录放到 PATH 最前面(可执行文件都从这儿找)。
|
|
35
|
-
* @param env 改哪份环境(默认当前进程)。
|
|
36
|
-
* @returns 真的插进去了就 `true`;已经在里面就 `false`。
|
|
37
|
-
*/
|
|
38
|
-
export function ensureLibsBinOnPath(env = process.env) {
|
|
39
|
-
const dir = libsBinDir();
|
|
40
|
-
const parts = (env.PATH ?? '').split(delimiter).filter((one) => one !== '');
|
|
41
|
-
if (parts.includes(dir))
|
|
42
|
-
return false;
|
|
43
|
-
env.PATH = [dir, ...parts].join(delimiter);
|
|
44
|
-
return true;
|
|
2
|
+
export function runtimeRootOf(id) {
|
|
3
|
+
return `${workbenchRoot()}/${id}`;
|
|
4
|
+
}
|
|
5
|
+
export function runtimeLayoutOf(id) {
|
|
6
|
+
const root = runtimeRootOf(id);
|
|
7
|
+
const vendorPrefix = `${root}/plugins-npm`;
|
|
8
|
+
const libsPrefix = `${root}/libs`;
|
|
9
|
+
return {
|
|
10
|
+
root,
|
|
11
|
+
home: `${root}/home`,
|
|
12
|
+
vendorPrefix,
|
|
13
|
+
vendorPluginsDir: `${vendorPrefix}/node_modules`,
|
|
14
|
+
libsPrefix,
|
|
15
|
+
libsBinDir: `${libsPrefix}/node_modules/.bin`,
|
|
16
|
+
npmCacheDir: `${root}/npm-cache`,
|
|
17
|
+
};
|
|
45
18
|
}
|
package/dist/host/platform.js
CHANGED
|
@@ -33,7 +33,7 @@ export function hostSurface(input = {}) {
|
|
|
33
33
|
restartHint: deployment === 'desktop' ? '退出并重开 Desktop' : '重启一次 dsh',
|
|
34
34
|
toolchain: {
|
|
35
35
|
node: { source: deployment === 'desktop' ? 'desktop-shim' : 'path' },
|
|
36
|
-
npm: { neededFor: '
|
|
36
|
+
npm: { neededFor: 'runtime-install' },
|
|
37
37
|
pnpm: { neededFor: 'workshop', expectedMajor: 10 },
|
|
38
38
|
},
|
|
39
39
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ModuleStore } from './workspace-store.js';
|
|
2
2
|
export declare const PLUGIN_LEDGER_FILE = "plugins.json";
|
|
3
3
|
export interface PluginLedgerEntry {
|
|
4
|
-
readonly
|
|
4
|
+
readonly home: string;
|
|
5
5
|
readonly package: string;
|
|
6
6
|
readonly name?: string;
|
|
7
7
|
readonly registry?: string;
|
|
@@ -10,23 +10,23 @@ export interface PluginLedgerEntry {
|
|
|
10
10
|
readonly releasedAt?: string;
|
|
11
11
|
}
|
|
12
12
|
export declare function ledgerKeyOf(entry: {
|
|
13
|
-
readonly
|
|
13
|
+
readonly home: string;
|
|
14
14
|
readonly package: string;
|
|
15
15
|
}): string;
|
|
16
16
|
export declare function parsePluginLedger(raw: unknown): PluginLedgerEntry[];
|
|
17
17
|
export declare function readPluginLedger(store: ModuleStore): PluginLedgerEntry[];
|
|
18
18
|
export declare function writePluginLedger(store: ModuleStore, entries: readonly PluginLedgerEntry[]): void;
|
|
19
|
-
export declare function pluginEntriesOfHome(entries: readonly PluginLedgerEntry[],
|
|
19
|
+
export declare function pluginEntriesOfHome(entries: readonly PluginLedgerEntry[], home: string): PluginLedgerEntry[];
|
|
20
20
|
export declare function isHeldEntry(entry: PluginLedgerEntry): boolean;
|
|
21
|
-
export declare function heldEntriesOfHome(entries: readonly PluginLedgerEntry[],
|
|
22
|
-
export declare function heldEntryOfPlugin(entries: readonly PluginLedgerEntry[],
|
|
23
|
-
export declare function withReleasedEntry(entries: readonly PluginLedgerEntry[],
|
|
21
|
+
export declare function heldEntriesOfHome(entries: readonly PluginLedgerEntry[], home: string): PluginLedgerEntry[];
|
|
22
|
+
export declare function heldEntryOfPlugin(entries: readonly PluginLedgerEntry[], home: string, plugin: string): PluginLedgerEntry | undefined;
|
|
23
|
+
export declare function withReleasedEntry(entries: readonly PluginLedgerEntry[], home: string, pkg: string, releasedAt: string): PluginLedgerEntry[];
|
|
24
24
|
export type PluginRetention = 'remove' | 'keep-held' | 'keep-claimed' | 'keep-unsure';
|
|
25
25
|
export declare function pluginRetentionOf(options: {
|
|
26
26
|
readonly held: boolean;
|
|
27
27
|
readonly claimedBy: readonly string[];
|
|
28
28
|
readonly trustworthy: boolean;
|
|
29
29
|
}): PluginRetention;
|
|
30
|
-
export declare function pluginEntryOf(entries: readonly PluginLedgerEntry[],
|
|
30
|
+
export declare function pluginEntryOf(entries: readonly PluginLedgerEntry[], home: string, pkg: string): PluginLedgerEntry | undefined;
|
|
31
31
|
export declare function withPluginEntry(entries: readonly PluginLedgerEntry[], entry: PluginLedgerEntry): PluginLedgerEntry[];
|
|
32
|
-
export declare function withoutPluginEntry(entries: readonly PluginLedgerEntry[],
|
|
32
|
+
export declare function withoutPluginEntry(entries: readonly PluginLedgerEntry[], home: string, pkg: string): PluginLedgerEntry[];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export const PLUGIN_LEDGER_FILE = 'plugins.json';
|
|
2
2
|
export function ledgerKeyOf(entry) {
|
|
3
|
-
return `${entry.
|
|
3
|
+
return `${entry.home}\u0000${entry.package}`;
|
|
4
4
|
}
|
|
5
5
|
function textOf(value) {
|
|
6
6
|
if (typeof value !== 'string')
|
|
@@ -8,20 +8,27 @@ function textOf(value) {
|
|
|
8
8
|
const trimmed = value.trim();
|
|
9
9
|
return trimmed === '' ? undefined : trimmed;
|
|
10
10
|
}
|
|
11
|
+
function legacyHomeOf(box) {
|
|
12
|
+
for (const [key, value] of Object.entries(box)) {
|
|
13
|
+
if (key !== 'home' && key.toLowerCase().endsWith('home'))
|
|
14
|
+
return value;
|
|
15
|
+
}
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
11
18
|
function entryOf(value) {
|
|
12
19
|
if (typeof value !== 'object' || value === null)
|
|
13
20
|
return undefined;
|
|
14
21
|
const box = value;
|
|
15
|
-
const
|
|
22
|
+
const home = textOf(box['home']) ?? textOf(legacyHomeOf(box));
|
|
16
23
|
const pkg = textOf(box['package']);
|
|
17
24
|
const installedAt = textOf(box['installedAt']);
|
|
18
|
-
if (
|
|
25
|
+
if (home === undefined || pkg === undefined || installedAt === undefined)
|
|
19
26
|
return undefined;
|
|
20
27
|
const name = textOf(box['name']);
|
|
21
28
|
const registry = textOf(box['registry']);
|
|
22
29
|
const releasedAt = textOf(box['releasedAt']);
|
|
23
30
|
return {
|
|
24
|
-
|
|
31
|
+
home,
|
|
25
32
|
package: pkg,
|
|
26
33
|
installedAt,
|
|
27
34
|
...(name === undefined ? {} : { name }),
|
|
@@ -57,23 +64,23 @@ export function writePluginLedger(store, entries) {
|
|
|
57
64
|
}
|
|
58
65
|
store.write(PLUGIN_LEDGER_FILE, { entries });
|
|
59
66
|
}
|
|
60
|
-
export function pluginEntriesOfHome(entries,
|
|
61
|
-
return entries.filter((entry) => entry.
|
|
67
|
+
export function pluginEntriesOfHome(entries, home) {
|
|
68
|
+
return entries.filter((entry) => entry.home === home);
|
|
62
69
|
}
|
|
63
70
|
export function isHeldEntry(entry) {
|
|
64
71
|
return entry.releasedAt === undefined;
|
|
65
72
|
}
|
|
66
|
-
export function heldEntriesOfHome(entries,
|
|
67
|
-
return pluginEntriesOfHome(entries,
|
|
73
|
+
export function heldEntriesOfHome(entries, home) {
|
|
74
|
+
return pluginEntriesOfHome(entries, home).filter(isHeldEntry);
|
|
68
75
|
}
|
|
69
|
-
export function heldEntryOfPlugin(entries,
|
|
76
|
+
export function heldEntryOfPlugin(entries, home, plugin) {
|
|
70
77
|
const key = plugin.trim();
|
|
71
78
|
if (key === '')
|
|
72
79
|
return undefined;
|
|
73
|
-
return heldEntriesOfHome(entries,
|
|
80
|
+
return heldEntriesOfHome(entries, home).find((entry) => entry.name === key || entry.package === key);
|
|
74
81
|
}
|
|
75
|
-
export function withReleasedEntry(entries,
|
|
76
|
-
const entry = pluginEntryOf(entries,
|
|
82
|
+
export function withReleasedEntry(entries, home, pkg, releasedAt) {
|
|
83
|
+
const entry = pluginEntryOf(entries, home, pkg);
|
|
77
84
|
if (entry === undefined || entry.releasedAt !== undefined)
|
|
78
85
|
return [...entries];
|
|
79
86
|
return withPluginEntry(entries, { ...entry, releasedAt });
|
|
@@ -85,15 +92,15 @@ export function pluginRetentionOf(options) {
|
|
|
85
92
|
return 'keep-unsure';
|
|
86
93
|
return options.claimedBy.length > 0 ? 'keep-claimed' : 'remove';
|
|
87
94
|
}
|
|
88
|
-
export function pluginEntryOf(entries,
|
|
89
|
-
const key = ledgerKeyOf({
|
|
95
|
+
export function pluginEntryOf(entries, home, pkg) {
|
|
96
|
+
const key = ledgerKeyOf({ home, package: pkg });
|
|
90
97
|
return entries.find((entry) => ledgerKeyOf(entry) === key);
|
|
91
98
|
}
|
|
92
99
|
export function withPluginEntry(entries, entry) {
|
|
93
100
|
const key = ledgerKeyOf(entry);
|
|
94
101
|
return [...entries.filter((item) => ledgerKeyOf(item) !== key), entry];
|
|
95
102
|
}
|
|
96
|
-
export function withoutPluginEntry(entries,
|
|
97
|
-
const key = ledgerKeyOf({
|
|
103
|
+
export function withoutPluginEntry(entries, home, pkg) {
|
|
104
|
+
const key = ledgerKeyOf({ home, package: pkg });
|
|
98
105
|
return entries.filter((entry) => ledgerKeyOf(entry) !== key);
|
|
99
106
|
}
|
package/dist/host/plugin.d.ts
CHANGED
package/dist/host/plugin.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { readFileSync, readdirSync } from 'node:fs';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
|
-
export const OPENCLI_MANIFEST_FILE = 'opencli-plugin.json';
|
|
4
3
|
function asRecord(value) {
|
|
5
4
|
return typeof value === 'object' && value !== null ? value : undefined;
|
|
6
5
|
}
|
|
@@ -11,9 +10,9 @@ function isCommandFile(name) {
|
|
|
11
10
|
return false;
|
|
12
11
|
return name.endsWith('.ts') || name.endsWith('.js');
|
|
13
12
|
}
|
|
14
|
-
function pluginManifestOf(dir) {
|
|
13
|
+
function pluginManifestOf(dir, manifestFile) {
|
|
15
14
|
try {
|
|
16
|
-
const parsed = JSON.parse(readFileSync(join(dir,
|
|
15
|
+
const parsed = JSON.parse(readFileSync(join(dir, manifestFile), 'utf8'));
|
|
17
16
|
if (Array.isArray(parsed))
|
|
18
17
|
return undefined;
|
|
19
18
|
return asRecord(parsed);
|
|
@@ -30,8 +29,8 @@ function hasCommandFile(dir) {
|
|
|
30
29
|
return false;
|
|
31
30
|
}
|
|
32
31
|
}
|
|
33
|
-
export function pluginAt(dir) {
|
|
34
|
-
const manifest = pluginManifestOf(dir);
|
|
32
|
+
export function pluginAt(dir, manifestFile) {
|
|
33
|
+
const manifest = pluginManifestOf(dir, manifestFile);
|
|
35
34
|
if (manifest === undefined || !hasCommandFile(dir))
|
|
36
35
|
return undefined;
|
|
37
36
|
const name = manifest.name;
|