@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,7 +1,7 @@
|
|
|
1
1
|
import { describe, expect, it, vi } from 'vitest';
|
|
2
2
|
|
|
3
3
|
let states: unknown[] = [];
|
|
4
|
-
vi.mock('
|
|
4
|
+
vi.mock('../../lib/react.js', () => ({
|
|
5
5
|
Fragment: Symbol.for('react.fragment'),
|
|
6
6
|
h: (type: unknown, props: unknown, ...children: unknown[]) => ({ type, props, children }),
|
|
7
7
|
useEffect: () => {},
|
|
@@ -10,21 +10,21 @@ vi.mock('../lib/react.js', () => ({
|
|
|
10
10
|
useState: (initial: unknown) => [states.length > 0 ? states.shift() : initial, () => {}],
|
|
11
11
|
}));
|
|
12
12
|
|
|
13
|
-
vi.mock('
|
|
13
|
+
vi.mock('../SelectField.css', () => ({ default: {} }));
|
|
14
14
|
|
|
15
15
|
import { Menu, TextShimmer } from '@deepseek-ai/dsh-client-ui-primitives';
|
|
16
|
-
import { Spinner } from '
|
|
16
|
+
import { Spinner } from '../Spinner.js';
|
|
17
17
|
import type { MenuEntry } from '@deepseek-ai/dsh-client-ui-primitives';
|
|
18
|
-
import { h } from '
|
|
19
|
-
import { Field } from '
|
|
20
|
-
import { TextField } from '
|
|
18
|
+
import { h } from '../../lib/react.js';
|
|
19
|
+
import { Field } from '../Field.js';
|
|
20
|
+
import { TextField } from '../TextField.js';
|
|
21
21
|
import {
|
|
22
22
|
SelectField,
|
|
23
23
|
defaultSelectFilter,
|
|
24
24
|
selectCursorValue,
|
|
25
25
|
selectEntries,
|
|
26
26
|
stepSelectCursor,
|
|
27
|
-
} from '
|
|
27
|
+
} from '../SelectField.js';
|
|
28
28
|
|
|
29
29
|
interface AnyElement {
|
|
30
30
|
readonly type: unknown;
|
|
@@ -54,10 +54,6 @@ function elementsOf(root: unknown): readonly AnyElement[] {
|
|
|
54
54
|
return collect(root);
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
function marked(nodes: readonly AnyElement[]): boolean {
|
|
58
|
-
return nodes.some((one) => one.props?.['data-wb-select-reveal'] === '');
|
|
59
|
-
}
|
|
60
|
-
|
|
61
57
|
function menuOf(root: unknown): AnyElement {
|
|
62
58
|
const menu = elementsOf(root).find((one) => one.type === Menu);
|
|
63
59
|
if (menu === undefined) throw new Error('没有渲染出 Menu');
|
|
@@ -276,32 +272,6 @@ describe('SelectField:工作区那套下拉的公共形状', () => {
|
|
|
276
272
|
expect(defaultSelectFilter(option, 'nope')).toBe(false);
|
|
277
273
|
});
|
|
278
274
|
|
|
279
|
-
it('★ revealId:只给那一行的图标裹上标记(开列表时靠它滚进可视区),别行一个字节不变', () => {
|
|
280
|
-
const items = selectEntries(
|
|
281
|
-
[
|
|
282
|
-
{ value: 'a', label: '甲', icon: <span>甲</span> },
|
|
283
|
-
{ value: 'b', label: '乙', icon: <span>乙</span> },
|
|
284
|
-
],
|
|
285
|
-
undefined,
|
|
286
|
-
'b',
|
|
287
|
-
);
|
|
288
|
-
const iconOf = (id: string): unknown =>
|
|
289
|
-
(items.find((one) => (one as { id?: string }).id === id) as { icon?: unknown } | undefined)?.icon;
|
|
290
|
-
|
|
291
|
-
expect(marked(elementsOf(iconOf('a')))).toBe(false);
|
|
292
|
-
expect(marked(elementsOf(iconOf('b')))).toBe(true);
|
|
293
|
-
});
|
|
294
|
-
|
|
295
|
-
it('★ revealId 撞上没有图标的行:退而标记它的文字(标记只落一处)', () => {
|
|
296
|
-
const items = selectEntries([{ value: 'a', label: '甲' }], undefined, 'a');
|
|
297
|
-
const row = items.find((one) => (one as { id?: string }).id === 'a') as
|
|
298
|
-
| { label?: unknown; icon?: unknown }
|
|
299
|
-
| undefined;
|
|
300
|
-
|
|
301
|
-
expect(row?.icon).toBeUndefined();
|
|
302
|
-
expect(marked(elementsOf(row?.label))).toBe(true);
|
|
303
|
-
});
|
|
304
|
-
|
|
305
275
|
it('条目构造:图标与禁用照传,分组标题只在换组时出现一次', () => {
|
|
306
276
|
const items = selectEntries(
|
|
307
277
|
[
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { describe, expect, it, vi } from 'vitest';
|
|
2
2
|
|
|
3
|
-
vi.mock('
|
|
4
|
-
const actual = await vi.importActual<typeof import('
|
|
3
|
+
vi.mock('../../lib/react.js', async () => {
|
|
4
|
+
const actual = await vi.importActual<typeof import('../../lib/react.js')>('../../lib/react.js');
|
|
5
5
|
return { ...actual, h: (type: unknown, props?: unknown, ...children: unknown[]) => ({ type, props: props ?? {}, children }) };
|
|
6
6
|
});
|
|
7
|
-
vi.mock('
|
|
7
|
+
vi.mock('../Spinner.css', () => ({ default: {} }));
|
|
8
8
|
|
|
9
9
|
import { StateDot } from '@deepseek-ai/dsh-client-ui-primitives';
|
|
10
|
-
import { Spinner } from '
|
|
10
|
+
import { Spinner } from '../Spinner.js';
|
|
11
11
|
|
|
12
12
|
describe('Spinner(loading 那颗)', () => {
|
|
13
13
|
it('画的是 dsh 的 ongoing 状态点(视觉只有这一处实现)', () => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
-
import { readText, writeText } from '
|
|
2
|
+
import { readText, writeText } from '../storage.js';
|
|
3
3
|
|
|
4
4
|
function fakeStorage(options: { throwOnWrite?: boolean } = {}) {
|
|
5
5
|
const data = new Map<string, string>();
|
package/src/config/constants.ts
CHANGED
|
@@ -31,7 +31,7 @@ export const DIY_RECORD_ACT_PATH = `${DIY_RECORD_PATH}/act`;
|
|
|
31
31
|
/** 面板运行态的路由前缀,挂在外壳 API 下:上报口用它,拒报回 report-refused。 */
|
|
32
32
|
export const PANEL_STATE_PREFIX = `${API_PREFIX}/${PANEL_STATE_PATH}`;
|
|
33
33
|
|
|
34
|
-
/**
|
|
34
|
+
/** 钉住的运行时版本:隔离运行时按它校验、取那一份。 */
|
|
35
35
|
export const OPENCLI_PIN = "1.8.8";
|
|
36
36
|
|
|
37
37
|
/** 缺陷看板套件的 dsh 服务名(`workbenchIssues`):套件照它登记自己那份服务。 */
|
|
@@ -55,13 +55,13 @@ export const DIY_RECORD_SERVICE = "workbenchDiyRecord";
|
|
|
55
55
|
/** 会话投影服务的 dsh 服务名(`sessionProjections`):宿主经 `stateOf(session, 'agentPreset')` 读那一档。 */
|
|
56
56
|
export const SESSION_PROJECTIONS_SERVICE = "sessionProjections";
|
|
57
57
|
|
|
58
|
-
/**
|
|
58
|
+
/** 面板清单一次取回的行数上限(条):外部模块拿它当分页参数。 */
|
|
59
59
|
export const PANEL_LIST_LIMIT = 50;
|
|
60
60
|
|
|
61
|
-
/**
|
|
61
|
+
/** 单次运行时调用的默认超时(毫秒);调用点没传 `timeoutMs` 时按它算。 */
|
|
62
62
|
export const OPENCLI_TIMEOUT_MS = 120_000;
|
|
63
63
|
|
|
64
|
-
/**
|
|
64
|
+
/** 同时最多几条运行时调用在跑(条):超出就排队。 */
|
|
65
65
|
export const OPENCLI_MAX_CONCURRENT = 4;
|
|
66
66
|
|
|
67
67
|
/** 启动预热站点那一跳的超时(毫秒);超时按未热对待,不挡面板。 */
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export interface RuntimeCapabilities {
|
|
2
|
+
readonly console: boolean;
|
|
3
|
+
readonly pluginMarket: boolean;
|
|
4
|
+
readonly browserBridge: boolean;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export interface RuntimeText {
|
|
8
|
+
readonly zh: string;
|
|
9
|
+
readonly en: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface RuntimeTerms {
|
|
13
|
+
readonly plugin: RuntimeText;
|
|
14
|
+
readonly pluginOf: RuntimeText;
|
|
15
|
+
readonly pluginThing: RuntimeText;
|
|
16
|
+
readonly pluginArea: RuntimeText;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface RuntimeBridgeFix {
|
|
20
|
+
readonly text: RuntimeText;
|
|
21
|
+
readonly link?: { readonly label: RuntimeText; readonly href: string };
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface RuntimeProfile {
|
|
25
|
+
readonly label: string;
|
|
26
|
+
readonly terms: RuntimeTerms;
|
|
27
|
+
readonly installHint: RuntimeText;
|
|
28
|
+
readonly diagnose: Readonly<Partial<Record<'exec' | 'login' | 'bridge', RuntimeText>>>;
|
|
29
|
+
readonly bridge?: Readonly<Partial<Record<string, RuntimeBridgeFix>>>;
|
|
30
|
+
}
|
package/src/contract/needs.ts
CHANGED
|
@@ -69,7 +69,7 @@ export interface BinNeed extends NeedCommon {
|
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
/**
|
|
72
|
-
*
|
|
72
|
+
* 某个运行时上要有一个扩展(运行时自己的插件就是这种),并且要提供这些命令。
|
|
73
73
|
*/
|
|
74
74
|
export interface ExtensionNeed extends NeedCommon {
|
|
75
75
|
readonly kind: 'extension';
|
|
@@ -82,8 +82,8 @@ export interface ExtensionNeed extends NeedCommon {
|
|
|
82
82
|
|
|
83
83
|
/**
|
|
84
84
|
* 要在隔离运行时里有一个共用依赖包。
|
|
85
|
-
* `runs`
|
|
86
|
-
* (库侧约定 `
|
|
85
|
+
* `runs` 写它自己会起哪个运行时的命令 —— 写了外壳就把那份执行器注入进去
|
|
86
|
+
* (库侧约定 `set<Runtime>Runner`);不写就按它自己在 PATH 上找。
|
|
87
87
|
*/
|
|
88
88
|
export interface LibNeed extends NeedCommon {
|
|
89
89
|
readonly kind: 'lib';
|
|
@@ -294,7 +294,7 @@ function perKindProblemsOf(
|
|
|
294
294
|
if (raw['docs'] !== undefined && text(raw['docs']) === '') errors.push(`${at}.docs 是空串`);
|
|
295
295
|
if (kind === 'lib') errors.push(...libRunsProblemsOf(raw['runs'], at));
|
|
296
296
|
if (kind === 'extension') {
|
|
297
|
-
if (text(raw['runtime']) === '') errors.push(`${at}.runtime 没写 ——
|
|
297
|
+
if (text(raw['runtime']) === '') errors.push(`${at}.runtime 没写 —— 扩展属于哪个运行时`);
|
|
298
298
|
if (text(raw['name']) === '') errors.push(`${at}.name 没写`);
|
|
299
299
|
if (raw['commands'] !== undefined) {
|
|
300
300
|
if (!Array.isArray(raw['commands'])) errors.push(`${at}.commands 要是数组`);
|
|
@@ -1 +1,25 @@
|
|
|
1
1
|
export type ProvisionProblem = 'not-declared' | 'env-missing' | 'malformed';
|
|
2
|
+
|
|
3
|
+
export interface PluginSourceCommand {
|
|
4
|
+
readonly line: string;
|
|
5
|
+
readonly optional?: true;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export type ResolvedPluginSource =
|
|
9
|
+
| {
|
|
10
|
+
readonly ok: true;
|
|
11
|
+
readonly commands: readonly PluginSourceCommand[];
|
|
12
|
+
readonly line: string;
|
|
13
|
+
}
|
|
14
|
+
| {
|
|
15
|
+
readonly ok: false;
|
|
16
|
+
readonly problem: ProvisionProblem;
|
|
17
|
+
readonly env?: string;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export interface PluginSourceOptions {
|
|
21
|
+
readonly command?: string;
|
|
22
|
+
readonly plugin?: string;
|
|
23
|
+
readonly version?: string;
|
|
24
|
+
readonly mode?: 'install' | 'update';
|
|
25
|
+
}
|
|
@@ -155,8 +155,14 @@ export interface BundleSupplyPayload {
|
|
|
155
155
|
readonly reason?: string;
|
|
156
156
|
}
|
|
157
157
|
|
|
158
|
+
export type PluginPackageKind = 'runtime-plugin';
|
|
159
|
+
|
|
160
|
+
export function isPluginPackageKind(kind: unknown): kind is PluginPackageKind {
|
|
161
|
+
return kind === 'runtime-plugin';
|
|
162
|
+
}
|
|
163
|
+
|
|
158
164
|
export interface BundleInstalledPlugin {
|
|
159
|
-
readonly kind:
|
|
165
|
+
readonly kind: PluginPackageKind;
|
|
160
166
|
readonly pkg: string;
|
|
161
167
|
readonly name?: string;
|
|
162
168
|
}
|
|
@@ -21,7 +21,7 @@ export interface HostCapabilities {
|
|
|
21
21
|
|
|
22
22
|
export interface ToolchainPlan {
|
|
23
23
|
readonly node: { readonly source: 'desktop-shim' | 'path' };
|
|
24
|
-
readonly npm: { readonly neededFor: '
|
|
24
|
+
readonly npm: { readonly neededFor: 'runtime-install' };
|
|
25
25
|
readonly pnpm: { readonly neededFor: 'workshop'; readonly expectedMajor: 10 };
|
|
26
26
|
}
|
|
27
27
|
|
package/src/contract/unit.ts
CHANGED
|
@@ -25,9 +25,9 @@ export interface UnitCard {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
|
-
*
|
|
28
|
+
* 合成工具背后那条运行时命令:插件名与命令名都是运行时那边的原名,`args` 是命令自己声明的参数名(按声明顺序)。
|
|
29
29
|
*/
|
|
30
|
-
export interface
|
|
30
|
+
export interface UnitToolRuntime {
|
|
31
31
|
readonly plugin: string;
|
|
32
32
|
readonly command: string;
|
|
33
33
|
readonly args: readonly string[];
|
|
@@ -35,12 +35,12 @@ export interface UnitToolOpencli {
|
|
|
35
35
|
|
|
36
36
|
/**
|
|
37
37
|
* 一条工具在清单里的样子:全名加会不会写;审批按 writes 认领。
|
|
38
|
-
* `
|
|
38
|
+
* `runtime` 只有「按已装插件合成」的单元写,手写模块的工具没有这一格。
|
|
39
39
|
*/
|
|
40
40
|
export interface UnitTool {
|
|
41
41
|
readonly name: string;
|
|
42
42
|
readonly writes: boolean;
|
|
43
|
-
readonly
|
|
43
|
+
readonly runtime?: UnitToolRuntime;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
/**
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import type { DataReader } from '
|
|
3
|
-
import type { ExtensionNeed } from '
|
|
4
|
-
import { extensionCallerOf } from '
|
|
2
|
+
import type { DataReader } from '../../contract/data.js';
|
|
3
|
+
import type { ExtensionNeed } from '../../contract/needs.js';
|
|
4
|
+
import { extensionCallerOf } from '../extension.js';
|
|
5
5
|
|
|
6
6
|
const NEED: ExtensionNeed = {
|
|
7
7
|
kind: 'extension',
|
|
@@ -32,7 +32,7 @@ describe('extensionCallerOf', () => {
|
|
|
32
32
|
await expect(caller.json(['issue-statuses'])).rejects.toMatchObject({
|
|
33
33
|
code: 'cli-unclassified',
|
|
34
34
|
message: expect.stringContaining('workbench_modules_update(id=coding-issues)'),
|
|
35
|
-
hint: expect.stringContaining('
|
|
35
|
+
hint: expect.stringContaining('coding issue-statuses --help'),
|
|
36
36
|
detail: "error: unknown command 'issue-statuses'",
|
|
37
37
|
});
|
|
38
38
|
});
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { describe, expect, it, vi } from 'vitest';
|
|
2
2
|
import type { LibNeed } from '../../contract/needs.js';
|
|
3
3
|
import type { LibReader } from '../../contract/lib.js';
|
|
4
|
-
import type {
|
|
4
|
+
import type { LibRunner } from '../../contract/runner.js';
|
|
5
5
|
import { withLibRunners } from '../lib-runners.js';
|
|
6
6
|
|
|
7
|
-
const runner:
|
|
7
|
+
const runner: LibRunner = async () => ({ stdout: '[]' });
|
|
8
8
|
|
|
9
9
|
function needOf(runs?: readonly string[]): LibNeed {
|
|
10
10
|
return {
|
|
@@ -28,6 +28,15 @@ function logger(): { readonly warn: ReturnType<typeof vi.fn<(message: string) =>
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
describe('withLibRunners', () => {
|
|
31
|
+
it('★ 换一个运行时名字(mcp)照样注入:外壳不认具体名字,只看清单的 runs', async () => {
|
|
32
|
+
const module = { setMcpRunner: vi.fn() };
|
|
33
|
+
const libs = withLibRunners(libsOf(module), { mcp: runner }, logger());
|
|
34
|
+
|
|
35
|
+
await libs.load(needOf(['mcp']), 'src/run.js');
|
|
36
|
+
|
|
37
|
+
expect(module.setMcpRunner).toHaveBeenCalledWith(runner);
|
|
38
|
+
});
|
|
39
|
+
|
|
31
40
|
it('没声明 runs → 原样返回,不注入、不记 warn', async () => {
|
|
32
41
|
const module = { setOpencliRunner: vi.fn() };
|
|
33
42
|
const warn = logger();
|
|
@@ -13,7 +13,7 @@ const HOME = '/h/workbench/opencli/home';
|
|
|
13
13
|
|
|
14
14
|
function entry(over: Partial<PluginLedgerEntry> = {}): PluginLedgerEntry {
|
|
15
15
|
return {
|
|
16
|
-
|
|
16
|
+
home: HOME,
|
|
17
17
|
package: 'opencli-plugin-inventory',
|
|
18
18
|
installedAt: '2026-10-14T00:00:00.000Z',
|
|
19
19
|
...over,
|
|
@@ -44,11 +44,11 @@ describe('台账条目的「放手」那一笔', () => {
|
|
|
44
44
|
});
|
|
45
45
|
|
|
46
46
|
it('另一个 home 的那一笔不受影响(隔离 wrapper 会换 home)', () => {
|
|
47
|
-
const other = entry({
|
|
47
|
+
const other = entry({ home: '/h/global/opencli/home' });
|
|
48
48
|
const released = withReleasedEntry([entry(), other], HOME, 'opencli-plugin-inventory', '2026-10-15T00:00:00.000Z');
|
|
49
49
|
|
|
50
|
-
expect(released.find((item) => item.
|
|
51
|
-
expect(heldEntriesOfHome(released, other.
|
|
50
|
+
expect(released.find((item) => item.home !== HOME)?.releasedAt).toBeUndefined();
|
|
51
|
+
expect(heldEntriesOfHome(released, other.home)).toHaveLength(1);
|
|
52
52
|
});
|
|
53
53
|
|
|
54
54
|
it('★ 按插件名找"用户持着的"那一份:插件名与包名两边都认(§3.4 那条映射)', () => {
|
|
@@ -67,8 +67,8 @@ describe('台账条目的「放手」那一笔', () => {
|
|
|
67
67
|
});
|
|
68
68
|
|
|
69
69
|
it('键还是「home + 包名」(同一份文件里两个 home 不互相撒谎)', () => {
|
|
70
|
-
expect(ledgerKeyOf({
|
|
71
|
-
ledgerKeyOf({
|
|
70
|
+
expect(ledgerKeyOf({ home: '/a', package: 'x' })).not.toBe(
|
|
71
|
+
ledgerKeyOf({ home: '/b', package: 'x' }),
|
|
72
72
|
);
|
|
73
73
|
});
|
|
74
74
|
});
|
|
@@ -92,3 +92,16 @@ describe('物理去留:由谁主张说话(动作与结果分层那条)', (
|
|
|
92
92
|
expect(pluginRetentionOf({ held: false, claimedBy: [], trustworthy: true })).toBe('remove');
|
|
93
93
|
});
|
|
94
94
|
});
|
|
95
|
+
|
|
96
|
+
describe('落盘字段改名后的老台账', () => {
|
|
97
|
+
it('★ 老文件里的 opencliHome 还认(改名不动数据)', () => {
|
|
98
|
+
const entries = parsePluginLedger({
|
|
99
|
+
entries: [
|
|
100
|
+
{ opencliHome: '/dsh/home-a', package: 'demo', installedAt: '2026-10-14T00:00:00.000Z' },
|
|
101
|
+
{ home: '/dsh/home-b', package: 'other', installedAt: '2026-10-14T00:00:00.000Z' },
|
|
102
|
+
],
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
expect(entries.map((entry) => entry.home)).toEqual(['/dsh/home-a', '/dsh/home-b']);
|
|
106
|
+
});
|
|
107
|
+
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import type { CallOverrides, RequestRecipe } from '
|
|
3
|
-
import { describeRecipe, scriptOf, scriptOfMany } from '
|
|
4
|
-
import { callsProblemOf, MAX_RECIPE_CALLS, recipeProblemOf } from '
|
|
2
|
+
import type { CallOverrides, RequestRecipe } from '../../contract/data.js';
|
|
3
|
+
import { describeRecipe, scriptOf, scriptOfMany } from '../recipe.js';
|
|
4
|
+
import { callsProblemOf, MAX_RECIPE_CALLS, recipeProblemOf } from '../recipe-rules.js';
|
|
5
5
|
|
|
6
6
|
const BASE: RequestRecipe = {
|
|
7
7
|
origin: 'https://x.example.com',
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { runtimeLayoutOf, runtimeRootOf } from '../paths.js';
|
|
3
|
+
|
|
4
|
+
describe('运行时根的算法(这里不认识任何具体运行时)', () => {
|
|
5
|
+
it('就是 workbench 根加一个 id,别处自己拼下面的布局', () => {
|
|
6
|
+
const layout = runtimeLayoutOf('demo-runtime');
|
|
7
|
+
|
|
8
|
+
expect(layout.root).toBe(runtimeRootOf('demo-runtime'));
|
|
9
|
+
expect(layout.root.endsWith('/workbench/demo-runtime')).toBe(true);
|
|
10
|
+
expect(layout.vendorPluginsDir).toBe(`${layout.root}/plugins-npm/node_modules`);
|
|
11
|
+
expect(layout.libsPrefix).toBe(`${layout.root}/libs`);
|
|
12
|
+
expect(layout.npmCacheDir).toBe(`${layout.root}/npm-cache`);
|
|
13
|
+
});
|
|
14
|
+
});
|
|
@@ -51,7 +51,7 @@ describe('供给索引:一个包只有一个来源', () => {
|
|
|
51
51
|
const index = buildSupplyIndex([
|
|
52
52
|
manifest('a', [extension('coding', [npm('opencli-plugin-coding')])]),
|
|
53
53
|
manifest('b', [extension('coding')]),
|
|
54
|
-
]);
|
|
54
|
+
], { packagePrefix: 'opencli-plugin-' });
|
|
55
55
|
|
|
56
56
|
expect(index.conflicts.map((item) => item.kind)).toEqual(['source-mismatch']);
|
|
57
57
|
expect(index.entryOf('extension', 'coding')?.conflicted).toBe(true);
|
|
@@ -152,7 +152,7 @@ describe('供给索引:一个包只有一个来源', () => {
|
|
|
152
152
|
});
|
|
153
153
|
|
|
154
154
|
it('没写 sources 的 extension 按约定落包名,进索引但不代装', () => {
|
|
155
|
-
const index = buildSupplyIndex([manifest('a', [extension('coding')])]);
|
|
155
|
+
const index = buildSupplyIndex([manifest('a', [extension('coding')])], { packagePrefix: 'opencli-plugin-' });
|
|
156
156
|
|
|
157
157
|
expect(index.entryOf('extension', 'coding')?.package).toBe('opencli-plugin-coding');
|
|
158
158
|
expect(index.sourcesOf('extension', 'coding')).toEqual([]);
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { supplyPortOf } from '../supply-port.js';
|
|
3
|
+
import { WORKBENCH_ADAPTERS } from '../adapters.js';
|
|
4
|
+
import { fakeAdapterSet } from '../../testing/fake-adapter-set.js';
|
|
5
|
+
|
|
6
|
+
function ctxOf(set: ReturnType<typeof fakeAdapterSet>): never {
|
|
7
|
+
return { get: (name: string) => (name === WORKBENCH_ADAPTERS ? set : undefined) } as never;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
describe('组合出给外壳的 supply 端口', () => {
|
|
11
|
+
it('给了 CLI 目录就透传(opencli 那类运行时)', () => {
|
|
12
|
+
const port = supplyPortOf(ctxOf(fakeAdapterSet()));
|
|
13
|
+
|
|
14
|
+
expect(port.cliCatalogPath?.()).toBe('/tmp/dsh-workbench-fake/catalog.json');
|
|
15
|
+
expect(port.vendorPluginsDir?.()).toContain('dsh-workbench-fake');
|
|
16
|
+
expect(port.runtimeInstallCommand?.()).toBeTruthy();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('★ 没给就整条不挂(纯 API 的运行时不用瞎编目录)', () => {
|
|
20
|
+
const set = fakeAdapterSet();
|
|
21
|
+
const modules = { ...set.modules } as Record<string, unknown>;
|
|
22
|
+
delete modules['cliCatalogPath'];
|
|
23
|
+
delete modules['vendorPluginsDir'];
|
|
24
|
+
delete modules['runtimeInstallCommand'];
|
|
25
|
+
const port = supplyPortOf(ctxOf({ ...set, modules } as never));
|
|
26
|
+
|
|
27
|
+
expect(port.cliCatalogPath).toBeUndefined();
|
|
28
|
+
expect(port.vendorPluginsDir).toBeUndefined();
|
|
29
|
+
expect(port.runtimeInstallCommand).toBeUndefined();
|
|
30
|
+
expect(port.isolatedRoot()).toBeTruthy();
|
|
31
|
+
});
|
|
32
|
+
});
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import type { DshHostContext } from '../api/dsh.js';
|
|
2
|
+
import type { AdapterSet } from './adapters.js';
|
|
3
|
+
import { validateAdapterSet } from './adapter-set.js';
|
|
4
|
+
|
|
5
|
+
const CAPABILITY_KEYS = ['console', 'pluginMarket', 'browserBridge'] as const;
|
|
6
|
+
const DATA_METHODS = ['read', 'request', 'requestMany', 'submit'] as const;
|
|
7
|
+
|
|
8
|
+
function isNonEmptyString(value: unknown): boolean {
|
|
9
|
+
return typeof value === 'string' && value.trim() !== '';
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const CLI_DIR_METHODS = [
|
|
13
|
+
['cliCatalogPath', 'cliCatalogPath'],
|
|
14
|
+
['vendorPluginsDir', 'vendorPluginsDir'],
|
|
15
|
+
] as const;
|
|
16
|
+
|
|
17
|
+
export function adapterContractGaps(set: AdapterSet, ctx: DshHostContext): readonly string[] {
|
|
18
|
+
const gaps: string[] = [];
|
|
19
|
+
const validated = validateAdapterSet(set, '契约');
|
|
20
|
+
if (!validated.ok) {
|
|
21
|
+
gaps.push(`成员不全:${validated.detail}`);
|
|
22
|
+
return gaps;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (!Number.isInteger(set.apiVersion) || set.apiVersion < 1) {
|
|
26
|
+
gaps.push(`apiVersion 不是正整数:${String(set.apiVersion)}`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const capabilities = set.runtime.capabilities(ctx);
|
|
30
|
+
for (const key of CAPABILITY_KEYS) {
|
|
31
|
+
if (typeof capabilities[key] !== 'boolean') gaps.push(`capabilities.${key} 不是布尔值`);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (typeof set.runtime.profile === 'function') {
|
|
35
|
+
const profile = set.runtime.profile(ctx);
|
|
36
|
+
if (!isNonEmptyString(profile?.label)) gaps.push('runtime.profile().label 不是非空字符串');
|
|
37
|
+
for (const key of ['plugin', 'pluginOf', 'pluginThing', 'pluginArea'] as const) {
|
|
38
|
+
const text = profile?.terms?.[key];
|
|
39
|
+
if (!isNonEmptyString(text?.zh) || !isNonEmptyString(text?.en)) {
|
|
40
|
+
gaps.push(`runtime.profile().terms.${key} 要给 zh / en 两份非空文案`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (!isNonEmptyString(profile?.installHint?.zh) || !isNonEmptyString(profile?.installHint?.en)) {
|
|
44
|
+
gaps.push('runtime.profile().installHint 要给 zh / en 两份非空文案');
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (typeof set.runtime.commandSurface === 'function') {
|
|
49
|
+
const surface = set.runtime.commandSurface(ctx);
|
|
50
|
+
if (surface !== undefined) {
|
|
51
|
+
if (!isNonEmptyString(surface.name)) gaps.push('runtime.commandSurface().name 不是非空字符串');
|
|
52
|
+
if (!isNonEmptyString(surface.pluginPrefix)) {
|
|
53
|
+
gaps.push('runtime.commandSurface().pluginPrefix 不是非空字符串');
|
|
54
|
+
}
|
|
55
|
+
if (typeof surface.invoke !== 'function') gaps.push('runtime.commandSurface().invoke 不是函数');
|
|
56
|
+
else if (!isNonEmptyString(surface.invoke('site', 'command'))) {
|
|
57
|
+
gaps.push('runtime.commandSurface().invoke(site, command) 拼不出非空命令行');
|
|
58
|
+
}
|
|
59
|
+
if (typeof surface.help !== 'function') gaps.push('runtime.commandSurface().help 不是函数');
|
|
60
|
+
else if (!isNonEmptyString(surface.help('site'))) {
|
|
61
|
+
gaps.push('runtime.commandSurface().help(site) 拼不出非空提示');
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const health = set.runtime.health(ctx);
|
|
67
|
+
const commands = set.runtime.commands(ctx);
|
|
68
|
+
for (const [name, status] of Object.entries(health)) {
|
|
69
|
+
if (!isNonEmptyString(status?.command)) gaps.push(`health['${name}'].command 不是非空字符串`);
|
|
70
|
+
if (!['env', 'isolated', 'path'].includes(status?.source)) gaps.push(`health['${name}'].source 不是已知来源`);
|
|
71
|
+
}
|
|
72
|
+
for (const name of Object.keys(commands)) {
|
|
73
|
+
if (health[name] === undefined) gaps.push(`commands 里的 ${name} 在 health 里没有对应条目`);
|
|
74
|
+
else if (!isNonEmptyString(commands[name])) gaps.push(`commands['${name}'] 不是非空字符串`);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
for (const method of DATA_METHODS) {
|
|
78
|
+
if (typeof set.data[method] !== 'function') gaps.push(`data.${method} 不是函数`);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (!isNonEmptyString(set.modules.isolatedRoot())) gaps.push('modules.isolatedRoot() 不是非空字符串');
|
|
82
|
+
if (set.modules.runtimeInstallCommand !== undefined && !isNonEmptyString(set.modules.runtimeInstallCommand())) {
|
|
83
|
+
gaps.push('modules.runtimeInstallCommand() 给了但不是非空字符串');
|
|
84
|
+
}
|
|
85
|
+
for (const [name, method] of CLI_DIR_METHODS) {
|
|
86
|
+
const given = set.modules[method];
|
|
87
|
+
if (given !== undefined && !isNonEmptyString(given())) gaps.push(`modules.${method}() 给了但不是非空字符串(${name})`);
|
|
88
|
+
}
|
|
89
|
+
if (typeof set.probe.probeUnits !== 'function') gaps.push('probe.probeUnits 不是函数');
|
|
90
|
+
if (typeof set.probe.registerPreflight !== 'function') gaps.push('probe.registerPreflight 不是函数');
|
|
91
|
+
|
|
92
|
+
return gaps;
|
|
93
|
+
}
|
package/src/host/adapter-set.ts
CHANGED
|
@@ -61,10 +61,9 @@ const CORE_METHODS = [
|
|
|
61
61
|
const FULL_MEMBERS = ['modules', 'runtime', 'plugins', 'actions'] as const;
|
|
62
62
|
|
|
63
63
|
const FULL_METHODS = [
|
|
64
|
+
['modules', 'isolatedRoot'],
|
|
64
65
|
['modules', 'isolatedHome'],
|
|
65
|
-
['modules', '
|
|
66
|
-
['modules', 'vendorPluginsDir'],
|
|
67
|
-
['modules', 'opencliInstallCommand'],
|
|
66
|
+
['modules', 'afterLibInstall'],
|
|
68
67
|
['modules', 'profileDirOf'],
|
|
69
68
|
['modules', 'profileModules'],
|
|
70
69
|
['modules', 'readInstalledModule'],
|
|
@@ -81,7 +80,10 @@ const FULL_METHODS = [
|
|
|
81
80
|
['modules', 'isNewerVersion'],
|
|
82
81
|
['modules', 'startSelfUpdate'],
|
|
83
82
|
['runtime', 'packageRoot'],
|
|
84
|
-
['runtime', '
|
|
83
|
+
['runtime', 'capabilities'],
|
|
84
|
+
['runtime', 'commands'],
|
|
85
|
+
['runtime', 'runners'],
|
|
86
|
+
['runtime', 'health'],
|
|
85
87
|
['runtime', 'seed'],
|
|
86
88
|
['runtime', 'warnUnwritableRoot'],
|
|
87
89
|
['plugins', 'declarationLookup'],
|
|
@@ -77,7 +77,7 @@ export interface SelfUpdateStart {
|
|
|
77
77
|
readonly forward: string;
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
export interface
|
|
80
|
+
export interface RuntimeStatus {
|
|
81
81
|
readonly command: string;
|
|
82
82
|
readonly source: 'env' | 'isolated' | 'path';
|
|
83
83
|
readonly isolated: string | null;
|