@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
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import type { DataError, DataRequest, DataResult } from '../contract/data.js';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* 一条 opencli 命令的执行器:同一形状的 `execFile('opencli', args)`,结果只留 stdout。
|
|
5
|
-
*/
|
|
6
|
-
export type OpencliRunner = (
|
|
7
|
-
args: readonly string[],
|
|
8
|
-
) => Promise<{ readonly stdout: string }>;
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* 读缝(`DataReader.read`)的形状;模块直接把自己的 `data.read` 传进来即可。
|
|
12
|
-
*/
|
|
13
|
-
export type OpencliRead = (
|
|
14
|
-
request: DataRequest,
|
|
15
|
-
) => Promise<DataResult<unknown>>;
|
|
16
|
-
|
|
17
|
-
export interface OpencliRunnerOptions {
|
|
18
|
-
readonly timeoutMs?: number;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const AUTH_REQUIRED_EXIT_CODE = 77;
|
|
22
|
-
|
|
23
|
-
function textOf(value: unknown): string {
|
|
24
|
-
return typeof value === 'string' ? value : '';
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function failedOf(args: readonly string[], error: DataError | undefined): Error {
|
|
28
|
-
const head = `Command failed: opencli ${args.join(' ')}`;
|
|
29
|
-
const auth = error?.pageCode === 'auth-required';
|
|
30
|
-
const helpUrl = textOf(error?.helpUrl);
|
|
31
|
-
const detail = textOf(error?.detail);
|
|
32
|
-
const hint = textOf(error?.hint);
|
|
33
|
-
const failed = new Error(
|
|
34
|
-
[
|
|
35
|
-
head,
|
|
36
|
-
...(auth
|
|
37
|
-
? ['code: AUTH_REQUIRED', `message: ${textOf(error?.message)}`]
|
|
38
|
-
: [textOf(error?.message) || 'opencli 这条命令没跑通']),
|
|
39
|
-
...(detail === '' ? [] : [detail]),
|
|
40
|
-
...(hint === '' ? [] : [hint]),
|
|
41
|
-
...(auth && helpUrl !== ''
|
|
42
|
-
? [`help: Please open Chrome or Chromium and log in to ${helpUrl}`]
|
|
43
|
-
: []),
|
|
44
|
-
].join('\n'),
|
|
45
|
-
);
|
|
46
|
-
if (auth) (failed as Error & { code?: number }).code = AUTH_REQUIRED_EXIT_CODE;
|
|
47
|
-
return failed;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* 把读缝包成一条 opencli 命令的执行器:给还按 `execFile('opencli', args)` 收结果的编排库用,
|
|
52
|
-
* 让它们跑在面板用的那份 opencli 上(同一套插件、同一份登录态)。
|
|
53
|
-
*
|
|
54
|
-
* 失败按 opencli 自己的约定还原:未登录是 `code: AUTH_REQUIRED` + 退出码 77,编排库的
|
|
55
|
-
* 「等登录再重试」才接得上;其它失败保留 `Command failed: opencli …` 那句外壳。
|
|
56
|
-
* @param read 模块手里的读缝(`data.read`)。
|
|
57
|
-
* @param options `timeoutMs` 透传给读缝;不传就用读缝自己的默认值。
|
|
58
|
-
* @returns 执行器;直接交给编排库的 `setOpencliRunner`。
|
|
59
|
-
*/
|
|
60
|
-
export function opencliRunnerOf(
|
|
61
|
-
read: OpencliRead,
|
|
62
|
-
options: OpencliRunnerOptions = {},
|
|
63
|
-
): OpencliRunner {
|
|
64
|
-
return async (args) => {
|
|
65
|
-
const result = await read({
|
|
66
|
-
kind: 'command',
|
|
67
|
-
adapter: 'opencli',
|
|
68
|
-
argv: [...args],
|
|
69
|
-
...(options.timeoutMs === undefined
|
|
70
|
-
? {}
|
|
71
|
-
: { timeoutMs: options.timeoutMs }),
|
|
72
|
-
});
|
|
73
|
-
if (result.ok) return { stdout: JSON.stringify(result.data) };
|
|
74
|
-
throw failedOf(args, result.error);
|
|
75
|
-
};
|
|
76
|
-
}
|
package/src/host/paths.test.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { delimiter } from 'node:path';
|
|
2
|
-
import { describe, expect, it } from 'vitest';
|
|
3
|
-
import { ensureLibsBinOnPath, libsBinDir, npmCacheDir } from './paths.js';
|
|
4
|
-
|
|
5
|
-
describe('隔离运行时的路径', () => {
|
|
6
|
-
it('共用依赖的 bin 目录就在 libs 下面', () => {
|
|
7
|
-
expect(libsBinDir().endsWith('/opencli/libs/node_modules/.bin')).toBe(true);
|
|
8
|
-
expect(npmCacheDir().endsWith('/opencli/npm-cache')).toBe(true);
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
it('★ 把 bin 目录前插一次;再插不会重复(PATH 不许越跑越长)', () => {
|
|
12
|
-
const env = { PATH: `/usr/bin${delimiter}/bin` };
|
|
13
|
-
const dir = libsBinDir();
|
|
14
|
-
|
|
15
|
-
expect(ensureLibsBinOnPath(env)).toBe(true);
|
|
16
|
-
expect(env.PATH).toBe(`${dir}${delimiter}/usr/bin${delimiter}/bin`);
|
|
17
|
-
expect(ensureLibsBinOnPath(env)).toBe(false);
|
|
18
|
-
expect(env.PATH.split(delimiter).filter((one) => one === dir)).toHaveLength(1);
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
it('PATH 是空的也能插', () => {
|
|
22
|
-
const env: NodeJS.ProcessEnv = {};
|
|
23
|
-
expect(ensureLibsBinOnPath(env)).toBe(true);
|
|
24
|
-
expect(env.PATH).toBe(libsBinDir());
|
|
25
|
-
});
|
|
26
|
-
});
|
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
import type { SupplySource } from '../contract/needs.js';
|
|
2
|
-
import type { ProvisionProblem } from '../contract/plugin-source.js';
|
|
3
|
-
import { quoteShellArg } from './shell-text.js';
|
|
4
|
-
import { npmCacheDir, toolchainOpencliDir, vendorPeerLink, vendorPrefix } from './paths.js';
|
|
5
|
-
|
|
6
|
-
export type { ProvisionProblem } from '../contract/plugin-source.js';
|
|
7
|
-
|
|
8
|
-
export interface PluginSourceCommand {
|
|
9
|
-
readonly line: string;
|
|
10
|
-
readonly optional?: true;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export type ResolvedPluginSource =
|
|
14
|
-
| {
|
|
15
|
-
readonly ok: true;
|
|
16
|
-
readonly commands: readonly PluginSourceCommand[];
|
|
17
|
-
readonly line: string;
|
|
18
|
-
}
|
|
19
|
-
| {
|
|
20
|
-
readonly ok: false;
|
|
21
|
-
readonly problem: ProvisionProblem;
|
|
22
|
-
readonly env?: string;
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
export interface PluginSourceOptions {
|
|
26
|
-
readonly command?: string;
|
|
27
|
-
readonly plugin?: string;
|
|
28
|
-
readonly version?: string;
|
|
29
|
-
readonly mode?: 'install' | 'update';
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function mergeLines(commands: readonly PluginSourceCommand[]): string {
|
|
33
|
-
return commands.map((item) => (item.optional === true ? `(${item.line} || true)` : item.line)).join(' && ');
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function envValue(
|
|
37
|
-
env: Readonly<Record<string, string | undefined>>,
|
|
38
|
-
name: string,
|
|
39
|
-
): { readonly ok: true; readonly value: string } | { readonly ok: false } {
|
|
40
|
-
const value = env[name]?.trim();
|
|
41
|
-
return value === undefined || value === '' ? { ok: false } : { ok: true, value };
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export function npmRegistryOf(
|
|
45
|
-
source: { readonly registryEnv?: string; readonly registryDefault?: string },
|
|
46
|
-
env: Readonly<Record<string, string | undefined>>,
|
|
47
|
-
): { readonly ok: true; readonly value: string } | { readonly ok: false; readonly env: string } {
|
|
48
|
-
const name = source.registryEnv ?? '';
|
|
49
|
-
if (name !== '') {
|
|
50
|
-
const fromEnv = envValue(env, name);
|
|
51
|
-
if (fromEnv.ok) return fromEnv;
|
|
52
|
-
}
|
|
53
|
-
const fallback = source.registryDefault?.trim();
|
|
54
|
-
if (fallback === undefined || fallback === '') return { ok: false, env: name };
|
|
55
|
-
return { ok: true, value: fallback };
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
function installOne(command: string, spec: string): ResolvedPluginSource {
|
|
59
|
-
const line = `${quoteShellArg(command)} plugin install ${quoteShellArg(spec)}`;
|
|
60
|
-
return { ok: true, commands: [{ line }], line };
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
function pluginPackageOf(source: SupplySource, plugin: string): string {
|
|
64
|
-
if (source.kind === 'npm') {
|
|
65
|
-
const pkg = source.package?.trim() ?? '';
|
|
66
|
-
if (pkg !== '') return pkg;
|
|
67
|
-
return plugin.trim() === '' ? '' : `opencli-plugin-${plugin.trim()}`;
|
|
68
|
-
}
|
|
69
|
-
if (source.kind === 'git') return source.url.trim();
|
|
70
|
-
return '';
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
function npmSource(
|
|
74
|
-
source: SupplySource & { kind: 'npm' },
|
|
75
|
-
env: Readonly<Record<string, string | undefined>>,
|
|
76
|
-
options: PluginSourceOptions,
|
|
77
|
-
): ResolvedPluginSource {
|
|
78
|
-
const registry = npmRegistryOf(source, env);
|
|
79
|
-
if (!registry.ok) return { ok: false, problem: 'env-missing', env: registry.env };
|
|
80
|
-
|
|
81
|
-
const { command = 'opencli', plugin = '', version = 'latest', mode = 'install' } = options;
|
|
82
|
-
const name = pluginPackageOf(source, plugin);
|
|
83
|
-
if (name === '') return { ok: false, problem: 'malformed' };
|
|
84
|
-
|
|
85
|
-
const prefix = vendorPrefix();
|
|
86
|
-
const dirInPrefix = `${prefix}/node_modules/${name}`;
|
|
87
|
-
const peer = vendorPeerLink();
|
|
88
|
-
|
|
89
|
-
const commands: PluginSourceCommand[] = [
|
|
90
|
-
{
|
|
91
|
-
line: [
|
|
92
|
-
'npm i',
|
|
93
|
-
`--prefix ${quoteShellArg(prefix)}`,
|
|
94
|
-
quoteShellArg(`${name}@${version}`),
|
|
95
|
-
`--registry ${quoteShellArg(registry.value)}`,
|
|
96
|
-
`--cache ${quoteShellArg(npmCacheDir())}`,
|
|
97
|
-
].join(' '),
|
|
98
|
-
},
|
|
99
|
-
{
|
|
100
|
-
line: `rm -rf ${quoteShellArg(peer.dir)} && mkdir -p ${quoteShellArg(peer.parent)} && ln -s ${quoteShellArg(toolchainOpencliDir())} ${quoteShellArg(peer.dir)}`,
|
|
101
|
-
},
|
|
102
|
-
];
|
|
103
|
-
|
|
104
|
-
if (mode === 'install') {
|
|
105
|
-
if (plugin !== '') {
|
|
106
|
-
commands.push({
|
|
107
|
-
line: `${quoteShellArg(command)} plugin uninstall ${quoteShellArg(plugin)}`,
|
|
108
|
-
optional: true,
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
commands.push({
|
|
112
|
-
line: `NPM_CONFIG_REGISTRY=${quoteShellArg(registry.value)} ${quoteShellArg(command)} plugin install ${quoteShellArg(dirInPrefix)}`,
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
return { ok: true, commands, line: mergeLines(commands) };
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
export function resolvePluginSource(
|
|
120
|
-
source: SupplySource | undefined,
|
|
121
|
-
env: Readonly<Record<string, string | undefined>>,
|
|
122
|
-
options: PluginSourceOptions = {},
|
|
123
|
-
): ResolvedPluginSource {
|
|
124
|
-
if (source === undefined) return { ok: false, problem: 'not-declared' };
|
|
125
|
-
|
|
126
|
-
const command = options.command ?? 'opencli';
|
|
127
|
-
if (source.kind === 'git') {
|
|
128
|
-
const url = source.url.trim();
|
|
129
|
-
return url === '' ? { ok: false, problem: 'malformed' } : installOne(command, url);
|
|
130
|
-
}
|
|
131
|
-
if (source.kind === 'npm') return npmSource(source, env, options);
|
|
132
|
-
|
|
133
|
-
const value = source.env === undefined ? { ok: false as const } : envValue(env, source.env);
|
|
134
|
-
if (value.ok) return installOne(command, value.value);
|
|
135
|
-
if (source.path !== undefined && source.path.trim() !== '') return installOne(command, source.path.trim());
|
|
136
|
-
return { ok: false, problem: 'env-missing', env: source.env ?? '' };
|
|
137
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, mkdtempSync, realpathSync } from 'node:fs';
|
|
2
|
-
import { tmpdir } from 'node:os';
|
|
3
|
-
import { join } from 'node:path';
|
|
4
|
-
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
5
|
-
import { ensureLibsOpencliPeer } from './runtime-links.js';
|
|
6
|
-
|
|
7
|
-
afterEach(() => {
|
|
8
|
-
vi.unstubAllEnvs();
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
describe('ensureLibsOpencliPeer', () => {
|
|
12
|
-
it('★ 运行时那份 opencli 在 → 链到 libs,libs 里的命令才 import 得到它', () => {
|
|
13
|
-
const root = mkdtempSync(join(tmpdir(), 'wb-peer-'));
|
|
14
|
-
vi.stubEnv('DSH_WORKBENCH_HOME', root);
|
|
15
|
-
mkdirSync(join(root, 'opencli/toolchain/node_modules/@jackwener/opencli'), { recursive: true });
|
|
16
|
-
|
|
17
|
-
expect(ensureLibsOpencliPeer()).toBe(true);
|
|
18
|
-
const link = join(root, 'opencli/libs/node_modules/@jackwener/opencli');
|
|
19
|
-
expect(existsSync(link)).toBe(true);
|
|
20
|
-
expect(realpathSync(link)).toContain('toolchain/node_modules/@jackwener/opencli');
|
|
21
|
-
expect(ensureLibsOpencliPeer()).toBe(false);
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
it('运行时还没装 opencli → 不建空链接(等它装好再说)', () => {
|
|
25
|
-
const root = mkdtempSync(join(tmpdir(), 'wb-peer-'));
|
|
26
|
-
vi.stubEnv('DSH_WORKBENCH_HOME', root);
|
|
27
|
-
|
|
28
|
-
expect(ensureLibsOpencliPeer()).toBe(false);
|
|
29
|
-
expect(existsSync(join(root, 'opencli/libs/node_modules/@jackwener/opencli'))).toBe(false);
|
|
30
|
-
});
|
|
31
|
-
});
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, symlinkSync } from 'node:fs';
|
|
2
|
-
import { dirname } from 'node:path';
|
|
3
|
-
import { OPENCLI_NPM_PACKAGE, libsPrefix, toolchainOpencliDir } from './paths.js';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* 让共用依赖也能 import opencli:把隔离运行时里那份 opencli 链接到 libs 的 node_modules。
|
|
7
|
-
* 跑在 libs 里的命令(比如 opencli-workflow 带的 gitops)会按包名找 @jackwener/opencli,
|
|
8
|
-
* 找不到就起不来 —— 它不在 libs 的依赖里,是运行时提供的那一份。
|
|
9
|
-
* @returns 这次真的建了链接就 `true`;已经有了、或运行时那份还没装,就是 `false`。
|
|
10
|
-
*/
|
|
11
|
-
export function ensureLibsOpencliPeer(): boolean {
|
|
12
|
-
const link = `${libsPrefix()}/node_modules/${OPENCLI_NPM_PACKAGE}`;
|
|
13
|
-
if (existsSync(link)) return false;
|
|
14
|
-
const target = toolchainOpencliDir();
|
|
15
|
-
if (!existsSync(target)) return false;
|
|
16
|
-
try {
|
|
17
|
-
mkdirSync(dirname(link), { recursive: true });
|
|
18
|
-
symlinkSync(target, link);
|
|
19
|
-
return true;
|
|
20
|
-
} catch {
|
|
21
|
-
return false;
|
|
22
|
-
}
|
|
23
|
-
}
|