@dsh-workbench/shared 1.0.0-beta.0 → 1.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/dist/components/FormNodes.js +5 -1
  2. package/dist/components/FormRows.css +1 -0
  3. package/dist/components/FormRows.d.ts +4 -2
  4. package/dist/components/FormRows.js +5 -4
  5. package/dist/config/constants.d.ts +0 -2
  6. package/dist/config/constants.js +0 -5
  7. package/dist/contract/command.d.ts +22 -0
  8. package/dist/contract/command.js +1 -0
  9. package/dist/contract/data.d.ts +2 -1
  10. package/dist/contract/extension.d.ts +14 -0
  11. package/dist/contract/extension.js +1 -0
  12. package/dist/contract/git.d.ts +38 -0
  13. package/dist/contract/git.js +1 -0
  14. package/dist/contract/lib.d.ts +4 -0
  15. package/dist/contract/lib.js +1 -0
  16. package/dist/host/adapter-set.js +1 -0
  17. package/dist/host/adapters.d.ts +6 -0
  18. package/dist/host/extension.d.ts +7 -0
  19. package/dist/host/extension.js +39 -0
  20. package/dist/host/git.d.ts +2 -33
  21. package/dist/host/http.js +1 -1
  22. package/dist/host/market-index.js +3 -44
  23. package/dist/host/port-types.d.ts +1 -0
  24. package/dist/host/release-packages.generated.d.ts +1 -0
  25. package/dist/host/release-packages.generated.js +10 -0
  26. package/dist/host/tool-kit.d.ts +0 -6
  27. package/dist/host/tool-kit.js +0 -22
  28. package/dist/host/unit-face.d.ts +7 -0
  29. package/dist/host/version-range.js +7 -67
  30. package/dist/host/version.d.ts +3 -2
  31. package/dist/host/version.js +17 -19
  32. package/dist/host.d.ts +6 -0
  33. package/dist/host.js +6 -0
  34. package/dist/i18n/en.js +1 -0
  35. package/dist/i18n/index.d.ts +2 -1
  36. package/dist/i18n/zh.d.ts +1 -0
  37. package/dist/i18n/zh.js +1 -0
  38. package/dist/index.d.ts +4 -0
  39. package/dist/index.js +4 -0
  40. package/dist/lib/version.d.ts +4 -0
  41. package/dist/lib/version.js +21 -0
  42. package/package.json +6 -4
  43. package/src/components/Form.test.tsx +6 -0
  44. package/src/components/FormNodes.tsx +6 -1
  45. package/src/components/FormRows.css +1 -0
  46. package/src/components/FormRows.test.tsx +30 -0
  47. package/src/components/FormRows.tsx +9 -5
  48. package/src/config/constants.ts +0 -6
  49. package/src/contract/command.ts +25 -0
  50. package/src/contract/data.ts +2 -1
  51. package/src/contract/extension.ts +20 -0
  52. package/src/contract/git.ts +20 -0
  53. package/src/contract/lib.ts +5 -0
  54. package/src/host/adapter-set.ts +1 -0
  55. package/src/host/adapters.ts +6 -0
  56. package/src/host/extension.test.ts +55 -0
  57. package/src/host/extension.ts +57 -0
  58. package/src/host/git.ts +6 -14
  59. package/src/host/http.ts +1 -1
  60. package/src/host/market-index.ts +3 -33
  61. package/src/host/port-types.ts +1 -0
  62. package/src/host/release-packages.generated.ts +10 -0
  63. package/src/host/tool-kit.ts +0 -35
  64. package/src/host/unit-face.ts +7 -0
  65. package/src/host/version-range.ts +6 -64
  66. package/src/host/version.ts +18 -18
  67. package/src/host.ts +6 -0
  68. package/src/i18n/en.ts +1 -0
  69. package/src/i18n/zh.ts +1 -0
  70. package/src/index.ts +4 -0
@@ -0,0 +1,55 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import type { DataReader } from '../contract/data.js';
3
+ import type { ExtensionNeed } from '../contract/needs.js';
4
+ import { extensionCallerOf } from './extension.js';
5
+
6
+ const NEED: ExtensionNeed = {
7
+ kind: 'extension',
8
+ runtime: 'opencli',
9
+ name: 'coding',
10
+ purpose: '测试',
11
+ };
12
+
13
+ function failingData(): DataReader {
14
+ return {
15
+ read: async () => ({
16
+ ok: false,
17
+ error: {
18
+ code: 'command',
19
+ message: 'opencli 这条命令没跑通(退出码 1)',
20
+ detail: "error: unknown command 'issue-statuses'",
21
+ pageCode: 'cli-unclassified',
22
+ },
23
+ }),
24
+ } as unknown as DataReader;
25
+ }
26
+
27
+ describe('extensionCallerOf', () => {
28
+ it('cli-unclassified 补“升级插件”的 message 与 hint,id 用调用方给的 suiteId', async () => {
29
+ const caller = extensionCallerOf(failingData(), NEED, {
30
+ suiteId: 'coding-issues',
31
+ });
32
+ await expect(caller.json(['issue-statuses'])).rejects.toMatchObject({
33
+ code: 'cli-unclassified',
34
+ message: expect.stringContaining('workbench_modules_update(id=coding-issues)'),
35
+ hint: expect.stringContaining('opencli coding issue-statuses --help'),
36
+ detail: "error: unknown command 'issue-statuses'",
37
+ });
38
+ });
39
+
40
+ it('别的码不补“插件版本旧”', async () => {
41
+ const caller = extensionCallerOf(failingData(), NEED, {
42
+ suiteId: 'coding-issues',
43
+ });
44
+ const data = {
45
+ read: async () => ({
46
+ ok: false,
47
+ error: { code: 'auth', message: '需要登录', pageCode: 'auth-required' },
48
+ }),
49
+ } as unknown as DataReader;
50
+ await expect(
51
+ extensionCallerOf(data, NEED, { suiteId: 'x' }).json(['issue-statuses']),
52
+ ).rejects.toMatchObject({ code: 'auth-required', message: '需要登录' });
53
+ expect(caller).toBeDefined();
54
+ });
55
+ });
@@ -0,0 +1,57 @@
1
+ import type { DataReader } from '../contract/data.js';
2
+ import type { ExtensionCaller, ExtensionCallOptions, ExtensionValue } from '../contract/extension.js';
3
+ import type { ExtensionNeed } from '../contract/needs.js';
4
+ import { WorkbenchDataError } from './data-error.js';
5
+
6
+ function cliCodeOf(code: string): string {
7
+ if (code === 'auth') return 'auth-required';
8
+ if (code === 'timeout') return 'cli-timeout';
9
+ if (code === 'parse') return 'cli-bad-output';
10
+ return 'cli-exec-failed';
11
+ }
12
+
13
+ export interface ExtensionCallerOptions {
14
+ readonly suiteId?: string | undefined;
15
+ }
16
+
17
+ export function extensionCallerOf(
18
+ data: DataReader,
19
+ need: ExtensionNeed,
20
+ callerOptions: ExtensionCallerOptions = {},
21
+ ): ExtensionCaller {
22
+ return {
23
+ async json(
24
+ args: readonly string[],
25
+ options: ExtensionCallOptions = {},
26
+ ): Promise<ExtensionValue> {
27
+ const result = await data.read({
28
+ kind: 'command',
29
+ adapter: need.runtime,
30
+ argv: [need.name, ...args],
31
+ ...(options.timeoutMs === undefined ? {} : { timeoutMs: options.timeoutMs }),
32
+ });
33
+ if (result.ok) return { value: result.data, at: Date.now() };
34
+ const code = result.error.pageCode ?? cliCodeOf(result.error.code);
35
+ const command = [need.name, ...args].join(' ');
36
+ const advice =
37
+ code === 'cli-unclassified'
38
+ ? `这条命令(${command})在这份 ${need.name} 插件里可能不存在(插件版本旧就会缺):用 workbench_modules_update(id=${callerOptions.suiteId ?? need.name})升级,或在面板的模块状态里点更新,再重试。终端确认:opencli ${need.name} ${args[0] ?? ''} --help`
39
+ : undefined;
40
+ const hint =
41
+ advice === undefined
42
+ ? result.error.hint
43
+ : result.error.hint === undefined
44
+ ? advice
45
+ : `${advice}\n${result.error.hint}`;
46
+ throw new WorkbenchDataError(
47
+ code,
48
+ advice === undefined ? result.error.message : `${result.error.message}。${advice}`,
49
+ {
50
+ ...(result.error.detail === undefined ? {} : { detail: result.error.detail }),
51
+ ...(hint === undefined ? {} : { hint }),
52
+ ...(result.error.helpUrl === undefined ? {} : { helpUrl: result.error.helpUrl }),
53
+ },
54
+ );
55
+ },
56
+ };
57
+ }
package/src/host/git.ts CHANGED
@@ -2,25 +2,17 @@ import type { DshShell } from '../api/dsh.js';
2
2
  import { quoteShellArg, tailLines } from '../host/shell-text.js';
3
3
  import { runShell } from '../host/shell.js';
4
4
 
5
- export type OriginRead =
6
- | { readonly kind: 'ok'; readonly remote: string }
7
- | { readonly kind: 'no-origin'; readonly detail?: string }
8
- | { readonly kind: 'unknown'; readonly reason: string; readonly detail?: string };
5
+ export type {
6
+ BranchRead,
7
+ HeadRead,
8
+ OriginRead,
9
+ } from '../contract/git.js';
10
+ import type { BranchRead, HeadRead, OriginRead } from '../contract/git.js';
9
11
 
10
12
  export type OriginReader = (path: string) => Promise<OriginRead>;
11
13
 
12
- export type BranchRead =
13
- | { readonly kind: 'ok'; readonly branch: string }
14
- | { readonly kind: 'no-branch'; readonly detail?: string | undefined }
15
- | { readonly kind: 'unknown'; readonly reason: string; readonly detail?: string | undefined };
16
-
17
14
  export type BranchReader = (path: string) => Promise<BranchRead>;
18
15
 
19
- export type HeadRead =
20
- | { readonly kind: 'ok'; readonly commit: string }
21
- | { readonly kind: 'no-head'; readonly detail?: string }
22
- | { readonly kind: 'unknown'; readonly reason: string; readonly detail?: string };
23
-
24
16
  export type HeadReader = (path: string) => Promise<HeadRead>;
25
17
 
26
18
  export function createHeadReader(options: {
package/src/host/http.ts CHANGED
@@ -90,7 +90,7 @@ export function registerApi(ctx: DshHostContext, routes: RouteTable): () => void
90
90
  try {
91
91
  sendJson(res, 200, await handler(search));
92
92
  } catch (error) {
93
- if (error instanceof WorkbenchDataError) {
93
+ if (isDataError(error)) {
94
94
  sendJson(res, 200, { ok: false, error: toErrorPayload(error) });
95
95
  return;
96
96
  }
@@ -13,6 +13,7 @@ import type {
13
13
  } from '../contract/protocol/market-index.js';
14
14
  import { MARKET_INDEX_FORMAT } from '../contract/protocol/market-index.js';
15
15
  import { marketText } from '../lib/market-index.js';
16
+ import { compareVersions, isValidVersion } from './version.js';
16
17
 
17
18
  export { marketBranchOk, marketInstallTarget, marketText } from '../lib/market-index.js';
18
19
 
@@ -39,7 +40,6 @@ export const MARKET_INDEX_README_LINES: readonly string[] = [
39
40
  '',
40
41
  ];
41
42
 
42
- const SEMVER = /^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+([0-9A-Za-z.-]+))?$/;
43
43
  const NPM_NAME = /^(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*$/;
44
44
  const GIT_COMMIT = /^[0-9a-f]{40}$/;
45
45
  const MAX_ICON_CHARS = 32 * 1024;
@@ -73,37 +73,7 @@ function problem(kind: MarketIndexProblem['kind'], detail: string, at?: string):
73
73
  }
74
74
 
75
75
  export function compareSemver(left: string, right: string): number | undefined {
76
- const a = SEMVER.exec(left);
77
- const b = SEMVER.exec(right);
78
- if (a === null || b === null) return undefined;
79
- for (let index = 1; index <= 3; index += 1) {
80
- const diff = Number(a[index]) - Number(b[index]);
81
- if (diff !== 0) return diff > 0 ? 1 : -1;
82
- }
83
- const preA = a[4];
84
- const preB = b[4];
85
- if (preA === undefined && preB === undefined) return 0;
86
- if (preA === undefined) return 1;
87
- if (preB === undefined) return -1;
88
- const leftParts = preA.split('.');
89
- const rightParts = preB.split('.');
90
- for (let index = 0; index < Math.max(leftParts.length, rightParts.length); index += 1) {
91
- const one = leftParts[index];
92
- const other = rightParts[index];
93
- if (one === undefined) return -1;
94
- if (other === undefined) return 1;
95
- const oneNumber = /^\d+$/.test(one);
96
- const otherNumber = /^\d+$/.test(other);
97
- if (oneNumber && otherNumber) {
98
- const diff = Number(one) - Number(other);
99
- if (diff !== 0) return diff > 0 ? 1 : -1;
100
- continue;
101
- }
102
- if (oneNumber) return -1;
103
- if (otherNumber) return 1;
104
- if (one !== other) return one > other ? 1 : -1;
105
- }
106
- return 0;
76
+ return compareVersions(left, right);
107
77
  }
108
78
 
109
79
  function sourceOf(raw: unknown, at: string): MarketIndexSource | MarketIndexProblem {
@@ -138,7 +108,7 @@ function versionOf(raw: unknown, at: string): MarketIndexVersion | MarketIndexPr
138
108
  const record = asRecord(raw);
139
109
  if (record === undefined) return problem('version', '版本必须是一个对象', at);
140
110
  const version = asText(record['version']);
141
- if (!SEMVER.test(version)) return problem('version', `版本号不是合法 SemVer:${JSON.stringify(version)}`, at);
111
+ if (!isValidVersion(version)) return problem('version', `版本号不是合法 SemVer:${JSON.stringify(version)}`, at);
142
112
  const source = sourceOf(record['source'], `${at}.source`);
143
113
  if ('kind' in source) return source;
144
114
  const timestamp = record['publishTimestamp'];
@@ -61,6 +61,7 @@ export interface SupplyLatestOptions {
61
61
 
62
62
  export interface SupplyMissingPartsOptions {
63
63
  readonly shell: DshShell;
64
+ readonly name: string;
64
65
  readonly registry: string;
65
66
  readonly version: string;
66
67
  readonly force?: boolean;
@@ -0,0 +1,10 @@
1
+ export const RELEASE_PACKAGES = [
2
+ '@dsh-workbench/adapter-probe',
3
+ '@dsh-workbench/adapter-profile',
4
+ '@dsh-workbench/adapter-runtime',
5
+ '@dsh-workbench/adapter-supply',
6
+ '@dsh-workbench/adapters-default',
7
+ '@dsh-workbench/core',
8
+ '@dsh-workbench/module-tools',
9
+ '@dsh-workbench/shared',
10
+ ] as const;
@@ -1,5 +1,4 @@
1
1
  import type { DshToolRunContext } from '../api/dsh.js';
2
- import { WorkbenchDataError } from './data-error.js';
3
2
 
4
3
  export function sessionWorkspace(exec: DshToolRunContext | undefined): string | null {
5
4
  const cwd = exec?.agent?.session?.header?.cwd;
@@ -25,37 +24,3 @@ export const TEXT_OUTPUT = { schema: { type: 'object', properties: {}, additiona
25
24
  export function jsonText(value: unknown): string {
26
25
  return JSON.stringify(value);
27
26
  }
28
-
29
- const UNCLASSIFIED = 'cli-unclassified';
30
-
31
- export interface CommandHintNames {
32
- readonly plugin: string;
33
- readonly suiteId: string;
34
- }
35
-
36
- export type CommandHint = <T>(command: string, run: () => Promise<T>) => Promise<T>;
37
-
38
- export function commandHintFor(names: CommandHintNames): CommandHint {
39
- return async (command, run) => {
40
- try {
41
- return await run();
42
- } catch (error) {
43
- if (!(error instanceof WorkbenchDataError) || error.code !== UNCLASSIFIED) throw error;
44
-
45
- const advice =
46
- `这条命令(${command})在这份 ${names.plugin} 插件里可能不存在(插件版本旧就会缺):` +
47
- `用 workbench_modules_update(id=${names.suiteId})升级插件,或在面板的模块状态里点更新,再重试。`;
48
-
49
- throw new WorkbenchDataError(error.code, `${error.message}。${advice}`, {
50
- ...(error.detail === undefined ? {} : { detail: error.detail }),
51
- hint:
52
- `升级:workbench_modules_update(id=${names.suiteId})。` +
53
- `终端确认:opencli ${names.plugin} ${command} --help${
54
- error.hint === undefined ? '' : `\n${error.hint}`
55
- }`,
56
- ...(error.helpUrl === undefined ? {} : { helpUrl: error.helpUrl }),
57
- ...(error.project === undefined ? {} : { project: error.project }),
58
- });
59
- }
60
- };
61
- }
@@ -8,6 +8,9 @@ import type { ApprovalCall, ApprovalFacts, ApprovalPolicy } from '../host/tool-a
8
8
  import type { ValueHandoff } from '../host/value-handoff.js';
9
9
  import type { WorkspaceStore } from '../host/workspace-store.js';
10
10
  import type { DataReader } from '../contract/data.js';
11
+ import type { LibReader } from '../contract/lib.js';
12
+ import type { GitReader } from '../contract/git.js';
13
+ import type { CommandReader } from '../contract/command.js';
11
14
 
12
15
  export interface ToolScopeContext {
13
16
  readonly workspace: string | null;
@@ -22,6 +25,10 @@ export interface UnitMountDeps {
22
25
  readonly ownedUnits: () => readonly string[];
23
26
  readonly installable?: (() => readonly string[]) | undefined;
24
27
  readonly data: DataReader;
28
+ readonly env?: Readonly<Record<string, string | undefined>> | undefined;
29
+ readonly libs?: LibReader | undefined;
30
+ readonly git?: GitReader | undefined;
31
+ readonly commands?: CommandReader | undefined;
25
32
  readonly store: WorkspaceStore;
26
33
  readonly values?: ValueHandoff | undefined;
27
34
  readonly probe?: (
@@ -1,71 +1,13 @@
1
- import { compareVersions } from './version.js';
1
+ import semver from 'semver';
2
2
 
3
3
  export type VersionVerdict = 'satisfied' | 'unsatisfied' | 'malformed';
4
4
 
5
- function readable(version: string): boolean {
6
- return compareVersions(version, '0.0.0') !== undefined;
7
- }
8
-
9
- function segmentsOf(version: string): number[] | undefined {
10
- if (!readable(version)) return undefined;
11
- return version.split('.').map((part) => Number.parseInt(part, 10));
12
- }
13
-
14
- function caretUpper(base: readonly number[]): string {
15
- const [major = 0, minor = 0, patch = 0] = base;
16
- if (major > 0) return `${major + 1}.0.0`;
17
- return minor > 0 ? `0.${minor + 1}.0` : `0.0.${patch + 1}`;
18
- }
19
-
20
- function tildeUpper(base: readonly number[]): string {
21
- const [major = 0, minor = 0] = base;
22
- return `${major}.${minor + 1}.0`;
23
- }
24
-
25
- function comparator(token: string, version: string): boolean | undefined {
26
- const match = /^(>=|<=|>|<|=|\^|~)?\s*(.+)$/.exec(token.trim());
27
- if (match === null) return undefined;
28
- const [, operator = '', raw = ''] = match;
29
- const base = segmentsOf(raw.trim());
30
- if (base === undefined) return undefined;
31
- const at = (other: string): number | undefined => compareVersions(version, other);
32
- switch (operator) {
33
- case '^':
34
- return (at(raw) ?? -1) >= 0 && (at(caretUpper(base)) ?? 1) < 0;
35
- case '~':
36
- return (at(raw) ?? -1) >= 0 && (at(tildeUpper(base)) ?? 1) < 0;
37
- default:
38
- break;
39
- }
40
- const compared = at(raw.trim());
41
- if (compared === undefined) return undefined;
42
- switch (operator) {
43
- case '>=':
44
- return compared >= 0;
45
- case '<=':
46
- return compared <= 0;
47
- case '>':
48
- return compared > 0;
49
- case '<':
50
- return compared < 0;
51
- case '=':
52
- case '':
53
- return compared === 0;
54
- default:
55
- return undefined;
56
- }
57
- }
58
-
59
5
  export function checkVersionRange(contract: string | undefined, version: string): VersionVerdict {
60
6
  const spec = contract?.trim() ?? '';
61
7
  if (spec === '') return 'satisfied';
62
- if (!readable(version)) return 'malformed';
63
- const tokens = spec.split(/\s+/).filter((token) => token !== '');
64
- if (tokens.length === 0) return 'satisfied';
65
- for (const token of tokens) {
66
- const verdict = comparator(token, version);
67
- if (verdict === undefined) return 'malformed';
68
- if (!verdict) return 'unsatisfied';
69
- }
70
- return 'satisfied';
8
+ const range = semver.validRange(spec);
9
+ if (range === null) return 'malformed';
10
+ const parsed = semver.coerce(version);
11
+ if (parsed === null) return 'malformed';
12
+ return semver.satisfies(parsed, range) ? 'satisfied' : 'unsatisfied';
71
13
  }
@@ -1,4 +1,22 @@
1
1
  import { readFileSync } from 'node:fs';
2
+ import semver from 'semver';
3
+
4
+ export function compareVersions(left: string, right: string): number | undefined {
5
+ const a = semver.valid(left.trim());
6
+ const b = semver.valid(right.trim());
7
+ if (a === null || b === null) return undefined;
8
+ return semver.compare(a, b);
9
+ }
10
+
11
+ export function isValidVersion(value: string): boolean {
12
+ return semver.valid(value.trim()) !== null;
13
+ }
14
+
15
+ export function isNewerVersion(latest: string, installed: string): boolean {
16
+ if (latest === installed) return false;
17
+ const compared = compareVersions(latest, installed);
18
+ return compared === undefined ? true : compared > 0;
19
+ }
2
20
 
3
21
  export function runningVersionOf(moduleUrl: string): string | undefined {
4
22
  try {
@@ -10,21 +28,3 @@ export function runningVersionOf(moduleUrl: string): string | undefined {
10
28
  return undefined;
11
29
  }
12
30
  }
13
-
14
- export function compareVersions(a: string, b: string): number | undefined {
15
- const na = a.split('.').map((part) => Number.parseInt(part, 10));
16
- const nb = b.split('.').map((part) => Number.parseInt(part, 10));
17
- if (na.some(Number.isNaN) || nb.some(Number.isNaN)) return undefined;
18
- for (let index = 0; index < Math.max(na.length, nb.length); index += 1) {
19
- const left = na[index] ?? 0;
20
- const right = nb[index] ?? 0;
21
- if (left !== right) return left > right ? 1 : -1;
22
- }
23
- return 0;
24
- }
25
-
26
- export function isNewerVersion(latest: string, installed: string): boolean {
27
- if (latest === installed) return false;
28
- const compared = compareVersions(latest, installed);
29
- return compared === undefined ? true : compared > 0;
30
- }
package/src/host.ts CHANGED
@@ -3,6 +3,10 @@ export * from './api/context-ref.js';
3
3
  export * from './contract/unit.js';
4
4
  export * from './contract/needs.js';
5
5
  export * from './contract/data.js';
6
+ export * from './contract/extension.js';
7
+ export * from './contract/lib.js';
8
+ export * from './contract/git.js';
9
+ export * from './contract/command.js';
6
10
  export * from './contract/unit-board.js';
7
11
  export * from './contract/workbench-contract.js';
8
12
  export * from './contract/blocker.js';
@@ -41,6 +45,7 @@ export * from './host/provision.js';
41
45
  export * from './host/channel-plugin.js';
42
46
  export * from './host/recipe.js';
43
47
  export * from './host/recipe-rules.js';
48
+ export * from './host/release-packages.generated.js';
44
49
  export * from './contract/unit-capability.js';
45
50
  export * from './contract/plugin-source.js';
46
51
  export * from './contract/cli.js';
@@ -63,6 +68,7 @@ export * from './host/patch.js';
63
68
  export * from './host/adapters.js';
64
69
  export * from './host/adapter-set.js';
65
70
  export * from './host/needs.js';
71
+ export * from './host/extension.js';
66
72
  export * from './host/port-types.js';
67
73
  export * from './host/version-range.js';
68
74
  export * from './host/market-index.js';
package/src/i18n/en.ts CHANGED
@@ -277,6 +277,7 @@ export const en: Record<keyof WorkbenchMessages, string> = {
277
277
  'panels.discover.loading': 'Reading the index',
278
278
  'panels.discover.lead': 'Browse modules from an index source; install and go.',
279
279
  'panels.discover.addSource': 'Add',
280
+ 'panels.discover.addingSource': 'Adding…',
280
281
  'panels.discover.addFirstSource': 'Add index source',
281
282
  'panels.discover.removeSource': 'Remove',
282
283
  'panels.discover.removeSourceNamed': 'Remove {url}',
package/src/i18n/zh.ts CHANGED
@@ -274,6 +274,7 @@ export const zh = {
274
274
  'panels.discover.loading': '正在读取索引',
275
275
  'panels.discover.lead': '从索引源浏览模块;装上就能用。',
276
276
  'panels.discover.addSource': '添加',
277
+ 'panels.discover.addingSource': '正在添加…',
277
278
  'panels.discover.addFirstSource': '添加索引源',
278
279
  'panels.discover.removeSource': '移除',
279
280
  'panels.discover.removeSourceNamed': '移除 {url}',
package/src/index.ts CHANGED
@@ -37,6 +37,10 @@ export * from './config/constants.js';
37
37
  export * from './config/storage.js';
38
38
  export * from './contract/blocker.js';
39
39
  export * from './contract/data.js';
40
+ export * from './contract/extension.js';
41
+ export * from './contract/lib.js';
42
+ export * from './contract/git.js';
43
+ export * from './contract/command.js';
40
44
  export * from './contract/facts.js';
41
45
  export * from './contract/long-task.js';
42
46
  export * from './contract/protocol/bundle-install.js';