@dsh-workbench/shared 1.0.0-beta.0 → 1.0.0
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/components/FormNodes.js +5 -1
- package/dist/components/FormRows.css +1 -0
- package/dist/components/FormRows.d.ts +4 -2
- package/dist/components/FormRows.js +5 -4
- package/dist/config/constants.d.ts +0 -2
- package/dist/config/constants.js +0 -5
- package/dist/contract/command.d.ts +22 -0
- package/dist/contract/command.js +1 -0
- package/dist/contract/data.d.ts +2 -1
- package/dist/contract/extension.d.ts +14 -0
- package/dist/contract/extension.js +1 -0
- package/dist/contract/git.d.ts +38 -0
- package/dist/contract/git.js +1 -0
- package/dist/contract/lib.d.ts +4 -0
- package/dist/contract/lib.js +1 -0
- package/dist/contract/protocol/config-sync.d.ts +1 -21
- package/dist/contract/protocol/market-index.d.ts +1 -0
- package/dist/contract/protocol/profile-create.d.ts +0 -3
- package/dist/host/adapter-set.js +1 -0
- package/dist/host/adapters.d.ts +6 -0
- package/dist/host/extension.d.ts +7 -0
- package/dist/host/extension.js +39 -0
- package/dist/host/git.d.ts +2 -52
- package/dist/host/git.js +1 -64
- package/dist/host/http.js +1 -1
- package/dist/host/market-index.js +3 -44
- package/dist/host/port-types.d.ts +1 -0
- package/dist/host/release-packages.generated.d.ts +1 -0
- package/dist/host/release-packages.generated.js +10 -0
- package/dist/host/tool-kit.d.ts +0 -6
- package/dist/host/tool-kit.js +0 -22
- package/dist/host/unit-face.d.ts +7 -0
- package/dist/host/version-range.js +7 -67
- package/dist/host/version.d.ts +3 -2
- package/dist/host/version.js +17 -19
- package/dist/host.d.ts +6 -0
- package/dist/host.js +6 -0
- package/dist/i18n/en.js +3 -1
- package/dist/i18n/index.d.ts +9 -21
- package/dist/i18n/settings.d.ts +5 -19
- package/dist/i18n/settings.js +7 -35
- package/dist/i18n/zh.d.ts +8 -20
- package/dist/i18n/zh.js +3 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/dist/lib/version.d.ts +4 -0
- package/dist/lib/version.js +21 -0
- package/dist/testing/git.d.ts +3 -0
- package/dist/testing/git.js +36 -0
- package/package.json +6 -4
- package/src/components/Form.test.tsx +6 -0
- package/src/components/FormNodes.tsx +6 -1
- package/src/components/FormRows.css +1 -0
- package/src/components/FormRows.test.tsx +30 -0
- package/src/components/FormRows.tsx +9 -5
- package/src/config/constants.ts +0 -6
- package/src/contract/command.ts +25 -0
- package/src/contract/data.ts +2 -1
- package/src/contract/extension.ts +20 -0
- package/src/contract/git.ts +20 -0
- package/src/contract/lib.ts +5 -0
- package/src/contract/protocol/config-sync.ts +1 -24
- package/src/contract/protocol/market-index.ts +1 -0
- package/src/contract/protocol/profile-create.ts +0 -3
- package/src/host/adapter-set.ts +1 -0
- package/src/host/adapters.ts +6 -0
- package/src/host/extension.test.ts +55 -0
- package/src/host/extension.ts +57 -0
- package/src/host/git.ts +6 -92
- package/src/host/http.ts +1 -1
- package/src/host/market-index.ts +3 -33
- package/src/host/port-types.ts +1 -0
- package/src/host/release-packages.generated.ts +10 -0
- package/src/host/tool-kit.ts +0 -35
- package/src/host/unit-face.ts +7 -0
- package/src/host/version-range.ts +6 -64
- package/src/host/version.ts +18 -18
- package/src/host.ts +6 -0
- package/src/i18n/en.ts +3 -1
- package/src/i18n/settings.ts +7 -35
- package/src/i18n/zh.ts +3 -1
- package/src/index.ts +4 -0
|
@@ -144,14 +144,18 @@ export function formRowsOf(args) {
|
|
|
144
144
|
return args.fields.map((field) => h(FormRow, {
|
|
145
145
|
key: field.key,
|
|
146
146
|
label: field.label,
|
|
147
|
+
htmlFor: controlIdOf(field.key),
|
|
147
148
|
hint: field.hint,
|
|
148
149
|
problem: args.showProblem ? args.problems[field.key] : undefined,
|
|
149
150
|
layout: field.layout,
|
|
150
151
|
}, controlOf(field, args.problems, args.showProblem, args.busy)));
|
|
151
152
|
}
|
|
153
|
+
function controlIdOf(key) {
|
|
154
|
+
return `wb-form-${key}`;
|
|
155
|
+
}
|
|
152
156
|
function controlOf(field, problems, showProblem, busy) {
|
|
153
157
|
return field.control({
|
|
154
|
-
id:
|
|
158
|
+
id: controlIdOf(field.key),
|
|
155
159
|
name: field.key,
|
|
156
160
|
invalid: showProblem && Boolean(problems[field.key]),
|
|
157
161
|
disabled: busy || field.disabled === true,
|
|
@@ -17,6 +17,7 @@ export declare function FormRows({ children }: FormRowsProps): JSX.Element;
|
|
|
17
17
|
*/
|
|
18
18
|
export interface FormRowProps {
|
|
19
19
|
readonly label: ReactNode;
|
|
20
|
+
readonly htmlFor?: string | undefined;
|
|
20
21
|
readonly hint?: ReactNode | undefined;
|
|
21
22
|
readonly problem?: ReactNode | undefined;
|
|
22
23
|
readonly layout?: 'inline' | 'stacked' | undefined;
|
|
@@ -25,10 +26,11 @@ export interface FormRowProps {
|
|
|
25
26
|
/**
|
|
26
27
|
* 表单一行:左边标签、右边控件,提示与错误占控件下面那一格。
|
|
27
28
|
* @param props.label - 这一行的标签;进了这一行,控件自己就别再给 `label`,否则会多一个标签。
|
|
29
|
+
* @param props.htmlFor - 标签挂到哪个控件(同一个 `id`);不给就只是排布,点标签不聚焦 —— `Form` 会自己接好。
|
|
28
30
|
* @param props.hint - 控件下的说明;给了 `problem` 就不画它 —— 同一格不叠两段话。
|
|
29
31
|
* @param props.problem - 校验失败那句话;给了就顶掉 `hint` 并给整行加上出错标记。
|
|
30
32
|
* @param props.layout - `stacked` 才是标签在上、控件在下(默认 `inline`:标签在左)。
|
|
31
33
|
* @param props.children - 控件本体。
|
|
32
|
-
* @returns 一个 `<label
|
|
34
|
+
* @returns 一个 `<div>`:里面的 `<label>` 只包标签文字,不包控件、提示与整行的空白。
|
|
33
35
|
*/
|
|
34
|
-
export declare function FormRow({ label, hint, problem, layout, children }: FormRowProps): JSX.Element;
|
|
36
|
+
export declare function FormRow({ label, htmlFor, hint, problem, layout, children }: FormRowProps): JSX.Element;
|
|
@@ -11,15 +11,16 @@ export function FormRows({ children }) {
|
|
|
11
11
|
/**
|
|
12
12
|
* 表单一行:左边标签、右边控件,提示与错误占控件下面那一格。
|
|
13
13
|
* @param props.label - 这一行的标签;进了这一行,控件自己就别再给 `label`,否则会多一个标签。
|
|
14
|
+
* @param props.htmlFor - 标签挂到哪个控件(同一个 `id`);不给就只是排布,点标签不聚焦 —— `Form` 会自己接好。
|
|
14
15
|
* @param props.hint - 控件下的说明;给了 `problem` 就不画它 —— 同一格不叠两段话。
|
|
15
16
|
* @param props.problem - 校验失败那句话;给了就顶掉 `hint` 并给整行加上出错标记。
|
|
16
17
|
* @param props.layout - `stacked` 才是标签在上、控件在下(默认 `inline`:标签在左)。
|
|
17
18
|
* @param props.children - 控件本体。
|
|
18
|
-
* @returns 一个 `<label
|
|
19
|
+
* @returns 一个 `<div>`:里面的 `<label>` 只包标签文字,不包控件、提示与整行的空白。
|
|
19
20
|
*/
|
|
20
|
-
export function FormRow({ label, hint, problem, layout = 'inline', children }) {
|
|
21
|
-
return (h("
|
|
22
|
-
h("
|
|
21
|
+
export function FormRow({ label, htmlFor, hint, problem, layout = 'inline', children }) {
|
|
22
|
+
return (h("div", { className: "wb-formRow", "data-layout": layout, "data-wb-problem": problem === undefined ? undefined : '' },
|
|
23
|
+
h("label", { className: "wb-formLabel", htmlFor: htmlFor }, label),
|
|
23
24
|
h("span", { className: "wb-formControl" }, children),
|
|
24
25
|
problem === undefined ? (hint === undefined ? null : (h("span", { className: "wb-formHint" }, hint))) : (h("span", { className: "wb-formProblem" }, problem))));
|
|
25
26
|
}
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
/** 外壳插件的包名:浏览器模块表与宿主按它注册、认领这枚插件。 */
|
|
2
2
|
export declare const PLUGIN_ID = "@dsh-workbench/core";
|
|
3
|
-
/** 与外壳同批发布的兄弟包名:`release.ts` 用它判一版三包是否都已在源上。 */
|
|
4
|
-
export declare const RELEASE_SIBLINGS: readonly ["@dsh-workbench/shared", "@dsh-workbench/module-tools"];
|
|
5
3
|
/** 外壳宿主 HTTP API 的根前缀;prefs / actions / provision 等路由都挂在它下面。 */
|
|
6
4
|
export declare const API_PREFIX = "/workbench/api";
|
|
7
5
|
/** 模块偏好读写的路由前缀,挂在外壳 API 下:走写通道,拒写回 write-refused。 */
|
package/dist/config/constants.js
CHANGED
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
/** 外壳插件的包名:浏览器模块表与宿主按它注册、认领这枚插件。 */
|
|
2
2
|
export const PLUGIN_ID = "@dsh-workbench/core";
|
|
3
|
-
/** 与外壳同批发布的兄弟包名:`release.ts` 用它判一版三包是否都已在源上。 */
|
|
4
|
-
export const RELEASE_SIBLINGS = [
|
|
5
|
-
"@dsh-workbench/shared",
|
|
6
|
-
"@dsh-workbench/module-tools",
|
|
7
|
-
];
|
|
8
3
|
/** 外壳宿主 HTTP API 的根前缀;prefs / actions / provision 等路由都挂在它下面。 */
|
|
9
4
|
export const API_PREFIX = "/workbench/api";
|
|
10
5
|
/** 模块偏好读写的路由前缀,挂在外壳 API 下:走写通道,拒写回 write-refused。 */
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface CommandFile {
|
|
2
|
+
readonly content: string;
|
|
3
|
+
readonly suffix?: string | undefined;
|
|
4
|
+
}
|
|
5
|
+
export interface CommandRequest {
|
|
6
|
+
readonly argv: readonly string[];
|
|
7
|
+
readonly timeoutMs?: number | undefined;
|
|
8
|
+
readonly cwd?: string | undefined;
|
|
9
|
+
readonly files?: readonly CommandFile[] | undefined;
|
|
10
|
+
readonly appendFileArgs?: string | undefined;
|
|
11
|
+
}
|
|
12
|
+
export interface CommandResult {
|
|
13
|
+
readonly stdout: string;
|
|
14
|
+
readonly stderr: string;
|
|
15
|
+
readonly exitCode: number;
|
|
16
|
+
readonly timedOut: boolean;
|
|
17
|
+
readonly filePaths: readonly string[];
|
|
18
|
+
readonly error?: string | undefined;
|
|
19
|
+
}
|
|
20
|
+
export interface CommandReader {
|
|
21
|
+
run(request: CommandRequest): Promise<CommandResult>;
|
|
22
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/contract/data.d.ts
CHANGED
|
@@ -16,7 +16,8 @@ export interface BrowserDataRequest extends DataRequestBase {
|
|
|
16
16
|
}
|
|
17
17
|
export interface CommandDataRequest extends DataRequestBase {
|
|
18
18
|
readonly kind: 'command';
|
|
19
|
-
readonly
|
|
19
|
+
readonly adapter: string;
|
|
20
|
+
readonly argv: readonly string[];
|
|
20
21
|
}
|
|
21
22
|
export type DataRequest = HttpDataRequest | BrowserDataRequest | CommandDataRequest;
|
|
22
23
|
export type DataErrorCode = 'invalid-request' | 'http' | 'auth' | 'timeout' | 'parse' | 'command' | 'browser';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export type ExtensionSession = 'persistent' | 'ephemeral' | 'none';
|
|
2
|
+
export interface ExtensionCallOptions {
|
|
3
|
+
readonly key?: string;
|
|
4
|
+
readonly workdir?: string;
|
|
5
|
+
readonly session?: ExtensionSession;
|
|
6
|
+
readonly timeoutMs?: number;
|
|
7
|
+
}
|
|
8
|
+
export interface ExtensionValue<T = unknown> {
|
|
9
|
+
readonly value: T;
|
|
10
|
+
readonly at: number;
|
|
11
|
+
}
|
|
12
|
+
export interface ExtensionCaller {
|
|
13
|
+
json(args: readonly string[], options?: ExtensionCallOptions): Promise<ExtensionValue>;
|
|
14
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export type OriginRead = {
|
|
2
|
+
readonly kind: 'ok';
|
|
3
|
+
readonly remote: string;
|
|
4
|
+
} | {
|
|
5
|
+
readonly kind: 'no-origin';
|
|
6
|
+
readonly detail?: string;
|
|
7
|
+
} | {
|
|
8
|
+
readonly kind: 'unknown';
|
|
9
|
+
readonly reason: string;
|
|
10
|
+
readonly detail?: string;
|
|
11
|
+
};
|
|
12
|
+
export type BranchRead = {
|
|
13
|
+
readonly kind: 'ok';
|
|
14
|
+
readonly branch: string;
|
|
15
|
+
} | {
|
|
16
|
+
readonly kind: 'no-branch';
|
|
17
|
+
readonly detail?: string | undefined;
|
|
18
|
+
} | {
|
|
19
|
+
readonly kind: 'unknown';
|
|
20
|
+
readonly reason: string;
|
|
21
|
+
readonly detail?: string | undefined;
|
|
22
|
+
};
|
|
23
|
+
export type HeadRead = {
|
|
24
|
+
readonly kind: 'ok';
|
|
25
|
+
readonly commit: string;
|
|
26
|
+
} | {
|
|
27
|
+
readonly kind: 'no-head';
|
|
28
|
+
readonly detail?: string;
|
|
29
|
+
} | {
|
|
30
|
+
readonly kind: 'unknown';
|
|
31
|
+
readonly reason: string;
|
|
32
|
+
readonly detail?: string;
|
|
33
|
+
};
|
|
34
|
+
export interface GitReader {
|
|
35
|
+
origin(path: string): Promise<OriginRead>;
|
|
36
|
+
branch(path: string): Promise<BranchRead>;
|
|
37
|
+
head(path: string): Promise<HeadRead>;
|
|
38
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,30 +1,13 @@
|
|
|
1
1
|
export declare const CONFIG_SYNC_ROUTE = "config-sync";
|
|
2
2
|
export declare const CONFIG_SYNC_RESOURCE = "configSync";
|
|
3
|
-
export type ConfigSyncState = 'new' | 'differs'
|
|
4
|
-
export type ConfigSyncAssetState = 'missing' | 'differs' | 'same' | 'external';
|
|
5
|
-
export interface ConfigSyncAssetFile {
|
|
6
|
-
readonly path: string;
|
|
7
|
-
readonly state: ConfigSyncAssetState;
|
|
8
|
-
readonly bytes: number | null;
|
|
9
|
-
}
|
|
10
|
-
export interface ConfigSyncAsset {
|
|
11
|
-
readonly key: string;
|
|
12
|
-
readonly path: string;
|
|
13
|
-
readonly kind: 'file' | 'dir';
|
|
14
|
-
readonly state: ConfigSyncAssetState;
|
|
15
|
-
readonly files: readonly ConfigSyncAssetFile[];
|
|
16
|
-
readonly bytes: number;
|
|
17
|
-
readonly reason?: string;
|
|
18
|
-
}
|
|
3
|
+
export type ConfigSyncState = 'new' | 'differs';
|
|
19
4
|
export interface ConfigSyncRow {
|
|
20
5
|
readonly key: string;
|
|
21
6
|
readonly id: string;
|
|
22
|
-
readonly insert: boolean;
|
|
23
7
|
readonly state: ConfigSyncState;
|
|
24
8
|
readonly body: string;
|
|
25
9
|
readonly ownBody: string | null;
|
|
26
10
|
readonly missing: readonly string[];
|
|
27
|
-
readonly assets: readonly ConfigSyncAsset[];
|
|
28
11
|
}
|
|
29
12
|
export interface ConfigSyncProfile {
|
|
30
13
|
readonly name: string;
|
|
@@ -43,13 +26,10 @@ export interface ConfigSyncSnapshot {
|
|
|
43
26
|
export interface ConfigSyncApplied {
|
|
44
27
|
readonly written: readonly string[];
|
|
45
28
|
readonly skipped: readonly string[];
|
|
46
|
-
readonly files: readonly string[];
|
|
47
29
|
readonly verified: boolean;
|
|
48
30
|
}
|
|
49
31
|
export interface ConfigSyncRequest {
|
|
50
32
|
readonly source: string;
|
|
51
33
|
readonly keys: readonly string[];
|
|
52
34
|
readonly overwrite: readonly string[];
|
|
53
|
-
readonly assets?: readonly string[];
|
|
54
|
-
readonly overwriteAssets?: readonly string[];
|
|
55
35
|
}
|
|
@@ -161,6 +161,7 @@ export interface PublishChangelog {
|
|
|
161
161
|
export interface PublishPreview {
|
|
162
162
|
readonly name: string;
|
|
163
163
|
readonly version: string;
|
|
164
|
+
readonly author?: string;
|
|
164
165
|
readonly registry?: string;
|
|
165
166
|
readonly market?: MarketPublishDestination;
|
|
166
167
|
readonly changelog?: PublishChangelog;
|
|
@@ -11,9 +11,6 @@ export interface ProfileCreateSnapshot {
|
|
|
11
11
|
}
|
|
12
12
|
export interface ProfileCreateCopy {
|
|
13
13
|
readonly settings: boolean;
|
|
14
|
-
readonly plugins: boolean;
|
|
15
|
-
readonly projects: boolean;
|
|
16
|
-
readonly sessions: boolean;
|
|
17
14
|
}
|
|
18
15
|
export interface ProfileCreateRequest {
|
|
19
16
|
readonly profile: string;
|
package/dist/host/adapter-set.js
CHANGED
|
@@ -220,6 +220,7 @@ export function withDefaultAdapterSet(defaults, loaded) {
|
|
|
220
220
|
id: set.id ?? defaults.id,
|
|
221
221
|
version: set.version ?? defaults.version,
|
|
222
222
|
data: set.data ?? defaults.data,
|
|
223
|
+
libs: set.libs ?? defaults.libs,
|
|
223
224
|
supply: set.supply ?? defaults.supply,
|
|
224
225
|
modules: set.modules ?? defaults.modules,
|
|
225
226
|
profile: set.profile ?? defaults.profile,
|
package/dist/host/adapters.d.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import type { DshHostContext } from '../api/dsh.js';
|
|
2
2
|
import type { DataReader } from '../contract/data.js';
|
|
3
|
+
import type { LibReader } from '../contract/lib.js';
|
|
4
|
+
import type { GitReader } from '../contract/git.js';
|
|
5
|
+
import type { CommandReader } from '../contract/command.js';
|
|
3
6
|
import type { EnvSupplyPort, HostActions, ModulePort, PluginSurface, ProbePort, ProfilePort, RuntimePort } from './port-types.js';
|
|
4
7
|
export declare const WORKBENCH_ADAPTERS = "workbenchAdapters";
|
|
5
8
|
export declare const ADAPTER_SET_API_VERSION = 1;
|
|
@@ -9,6 +12,9 @@ export interface AdapterSet {
|
|
|
9
12
|
readonly id: string;
|
|
10
13
|
readonly version: string;
|
|
11
14
|
readonly data: DataReader;
|
|
15
|
+
readonly libs?: LibReader | undefined;
|
|
16
|
+
readonly git?: GitReader | undefined;
|
|
17
|
+
readonly commands?: CommandReader | undefined;
|
|
12
18
|
readonly supply: EnvSupplyPort;
|
|
13
19
|
readonly modules: ModulePort;
|
|
14
20
|
readonly profile: ProfilePort;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { DataReader } from '../contract/data.js';
|
|
2
|
+
import type { ExtensionCaller } from '../contract/extension.js';
|
|
3
|
+
import type { ExtensionNeed } from '../contract/needs.js';
|
|
4
|
+
export interface ExtensionCallerOptions {
|
|
5
|
+
readonly suiteId?: string | undefined;
|
|
6
|
+
}
|
|
7
|
+
export declare function extensionCallerOf(data: DataReader, need: ExtensionNeed, callerOptions?: ExtensionCallerOptions): ExtensionCaller;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { WorkbenchDataError } from './data-error.js';
|
|
2
|
+
function cliCodeOf(code) {
|
|
3
|
+
if (code === 'auth')
|
|
4
|
+
return 'auth-required';
|
|
5
|
+
if (code === 'timeout')
|
|
6
|
+
return 'cli-timeout';
|
|
7
|
+
if (code === 'parse')
|
|
8
|
+
return 'cli-bad-output';
|
|
9
|
+
return 'cli-exec-failed';
|
|
10
|
+
}
|
|
11
|
+
export function extensionCallerOf(data, need, callerOptions = {}) {
|
|
12
|
+
return {
|
|
13
|
+
async json(args, options = {}) {
|
|
14
|
+
const result = await data.read({
|
|
15
|
+
kind: 'command',
|
|
16
|
+
adapter: need.runtime,
|
|
17
|
+
argv: [need.name, ...args],
|
|
18
|
+
...(options.timeoutMs === undefined ? {} : { timeoutMs: options.timeoutMs }),
|
|
19
|
+
});
|
|
20
|
+
if (result.ok)
|
|
21
|
+
return { value: result.data, at: Date.now() };
|
|
22
|
+
const code = result.error.pageCode ?? cliCodeOf(result.error.code);
|
|
23
|
+
const command = [need.name, ...args].join(' ');
|
|
24
|
+
const advice = code === 'cli-unclassified'
|
|
25
|
+
? `这条命令(${command})在这份 ${need.name} 插件里可能不存在(插件版本旧就会缺):用 workbench_modules_update(id=${callerOptions.suiteId ?? need.name})升级,或在面板的模块状态里点更新,再重试。终端确认:opencli ${need.name} ${args[0] ?? ''} --help`
|
|
26
|
+
: undefined;
|
|
27
|
+
const hint = advice === undefined
|
|
28
|
+
? result.error.hint
|
|
29
|
+
: result.error.hint === undefined
|
|
30
|
+
? advice
|
|
31
|
+
: `${advice}\n${result.error.hint}`;
|
|
32
|
+
throw new WorkbenchDataError(code, advice === undefined ? result.error.message : `${result.error.message}。${advice}`, {
|
|
33
|
+
...(result.error.detail === undefined ? {} : { detail: result.error.detail }),
|
|
34
|
+
...(hint === undefined ? {} : { hint }),
|
|
35
|
+
...(result.error.helpUrl === undefined ? {} : { helpUrl: result.error.helpUrl }),
|
|
36
|
+
});
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
}
|
package/dist/host/git.d.ts
CHANGED
|
@@ -1,55 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
readonly kind: 'ok';
|
|
4
|
-
readonly remote: string;
|
|
5
|
-
} | {
|
|
6
|
-
readonly kind: 'no-origin';
|
|
7
|
-
readonly detail?: string;
|
|
8
|
-
} | {
|
|
9
|
-
readonly kind: 'unknown';
|
|
10
|
-
readonly reason: string;
|
|
11
|
-
readonly detail?: string;
|
|
12
|
-
};
|
|
1
|
+
export type { BranchRead, HeadRead, OriginRead, } from '../contract/git.js';
|
|
2
|
+
import type { BranchRead, HeadRead, OriginRead } from '../contract/git.js';
|
|
13
3
|
export type OriginReader = (path: string) => Promise<OriginRead>;
|
|
14
|
-
export type BranchRead = {
|
|
15
|
-
readonly kind: 'ok';
|
|
16
|
-
readonly branch: string;
|
|
17
|
-
} | {
|
|
18
|
-
readonly kind: 'no-branch';
|
|
19
|
-
readonly detail?: string | undefined;
|
|
20
|
-
} | {
|
|
21
|
-
readonly kind: 'unknown';
|
|
22
|
-
readonly reason: string;
|
|
23
|
-
readonly detail?: string | undefined;
|
|
24
|
-
};
|
|
25
4
|
export type BranchReader = (path: string) => Promise<BranchRead>;
|
|
26
|
-
export type HeadRead = {
|
|
27
|
-
readonly kind: 'ok';
|
|
28
|
-
readonly commit: string;
|
|
29
|
-
} | {
|
|
30
|
-
readonly kind: 'no-head';
|
|
31
|
-
readonly detail?: string;
|
|
32
|
-
} | {
|
|
33
|
-
readonly kind: 'unknown';
|
|
34
|
-
readonly reason: string;
|
|
35
|
-
readonly detail?: string;
|
|
36
|
-
};
|
|
37
5
|
export type HeadReader = (path: string) => Promise<HeadRead>;
|
|
38
|
-
export declare function createHeadReader(options: {
|
|
39
|
-
shell: DshShell;
|
|
40
|
-
logger?: {
|
|
41
|
-
warn?(message: string): void;
|
|
42
|
-
} | undefined;
|
|
43
|
-
}): HeadReader;
|
|
44
|
-
export declare function createBranchReader(options: {
|
|
45
|
-
shell: DshShell;
|
|
46
|
-
logger?: {
|
|
47
|
-
warn?(message: string): void;
|
|
48
|
-
} | undefined;
|
|
49
|
-
}): BranchReader;
|
|
50
|
-
export declare function createOriginReader(options: {
|
|
51
|
-
shell: DshShell;
|
|
52
|
-
logger?: {
|
|
53
|
-
warn?(message: string): void;
|
|
54
|
-
} | undefined;
|
|
55
|
-
}): OriginReader;
|
package/dist/host/git.js
CHANGED
|
@@ -1,64 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import { runShell } from '../host/shell.js';
|
|
3
|
-
export function createHeadReader(options) {
|
|
4
|
-
const { shell, logger } = options;
|
|
5
|
-
return async function readHead(path) {
|
|
6
|
-
const key = String(path ?? '').trim();
|
|
7
|
-
if (!key)
|
|
8
|
-
return { kind: 'unknown', reason: 'no-path' };
|
|
9
|
-
let result;
|
|
10
|
-
try {
|
|
11
|
-
result = await runShell(shell, `git -C ${quoteShellArg(key)} rev-parse HEAD`);
|
|
12
|
-
}
|
|
13
|
-
catch (error) {
|
|
14
|
-
logger?.warn?.(`[dsh-workbench] git rev-parse 执行失败:${String(error)}`);
|
|
15
|
-
return { kind: 'unknown', reason: 'exec-failed', detail: String(error) };
|
|
16
|
-
}
|
|
17
|
-
if (result.exitCode !== 0) {
|
|
18
|
-
return { kind: 'no-head', detail: tailLines(result.stderr, 3) };
|
|
19
|
-
}
|
|
20
|
-
return { kind: 'ok', commit: result.stdout.trim() };
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
export function createBranchReader(options) {
|
|
24
|
-
const { shell, logger } = options;
|
|
25
|
-
return async function readBranch(path) {
|
|
26
|
-
const key = String(path ?? '').trim();
|
|
27
|
-
if (!key)
|
|
28
|
-
return { kind: 'unknown', reason: 'no-path' };
|
|
29
|
-
let result;
|
|
30
|
-
try {
|
|
31
|
-
result = await runShell(shell, `git -C ${quoteShellArg(key)} rev-parse --abbrev-ref HEAD`);
|
|
32
|
-
}
|
|
33
|
-
catch (error) {
|
|
34
|
-
logger?.warn?.(`[dsh-workbench] git rev-parse --abbrev-ref 执行失败:${String(error)}`);
|
|
35
|
-
return { kind: 'unknown', reason: 'exec-failed', detail: String(error) };
|
|
36
|
-
}
|
|
37
|
-
const name = result.stdout.trim();
|
|
38
|
-
if (result.exitCode !== 0)
|
|
39
|
-
return { kind: 'no-branch', detail: tailLines(result.stderr, 3) };
|
|
40
|
-
if (name === '' || name === 'HEAD')
|
|
41
|
-
return { kind: 'no-branch', detail: name };
|
|
42
|
-
return { kind: 'ok', branch: name };
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
export function createOriginReader(options) {
|
|
46
|
-
const { shell, logger } = options;
|
|
47
|
-
return async function readOrigin(path) {
|
|
48
|
-
const key = String(path ?? '').trim();
|
|
49
|
-
if (!key)
|
|
50
|
-
return { kind: 'unknown', reason: 'no-path' };
|
|
51
|
-
let result;
|
|
52
|
-
try {
|
|
53
|
-
result = await runShell(shell, `git -C ${quoteShellArg(key)} remote get-url origin`);
|
|
54
|
-
}
|
|
55
|
-
catch (error) {
|
|
56
|
-
logger?.warn?.(`[dsh-workbench] git remote 执行失败:${String(error)}`);
|
|
57
|
-
return { kind: 'unknown', reason: 'exec-failed', detail: String(error) };
|
|
58
|
-
}
|
|
59
|
-
if (result.exitCode !== 0) {
|
|
60
|
-
return { kind: 'no-origin', detail: tailLines(result.stderr, 3) };
|
|
61
|
-
}
|
|
62
|
-
return { kind: 'ok', remote: result.stdout.trim() };
|
|
63
|
-
};
|
|
64
|
-
}
|
|
1
|
+
export {};
|
package/dist/host/http.js
CHANGED
|
@@ -70,7 +70,7 @@ export function registerApi(ctx, routes) {
|
|
|
70
70
|
sendJson(res, 200, await handler(search));
|
|
71
71
|
}
|
|
72
72
|
catch (error) {
|
|
73
|
-
if (error
|
|
73
|
+
if (isDataError(error)) {
|
|
74
74
|
sendJson(res, 200, { ok: false, error: toErrorPayload(error) });
|
|
75
75
|
return;
|
|
76
76
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
2
|
import { MARKET_INDEX_FORMAT } from '../contract/protocol/market-index.js';
|
|
3
3
|
import { marketText } from '../lib/market-index.js';
|
|
4
|
+
import { compareVersions, isValidVersion } from './version.js';
|
|
4
5
|
export { marketBranchOk, marketInstallTarget, marketText } from '../lib/market-index.js';
|
|
5
6
|
export const MARKET_INDEX_SEED = '{\n "format": 1,\n "plugins": []\n}\n';
|
|
6
7
|
export const MARKET_INDEX_README_LINES = [
|
|
@@ -23,7 +24,6 @@ export const MARKET_INDEX_README_LINES = [
|
|
|
23
24
|
'在工作台的「模块市场 → 发现」里添加本仓库地址,即可浏览与安装。',
|
|
24
25
|
'',
|
|
25
26
|
];
|
|
26
|
-
const SEMVER = /^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+([0-9A-Za-z.-]+))?$/;
|
|
27
27
|
const NPM_NAME = /^(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*$/;
|
|
28
28
|
const GIT_COMMIT = /^[0-9a-f]{40}$/;
|
|
29
29
|
const MAX_ICON_CHARS = 32 * 1024;
|
|
@@ -52,48 +52,7 @@ function problem(kind, detail, at) {
|
|
|
52
52
|
return { kind, detail, ...(at === undefined ? {} : { at }) };
|
|
53
53
|
}
|
|
54
54
|
export function compareSemver(left, right) {
|
|
55
|
-
|
|
56
|
-
const b = SEMVER.exec(right);
|
|
57
|
-
if (a === null || b === null)
|
|
58
|
-
return undefined;
|
|
59
|
-
for (let index = 1; index <= 3; index += 1) {
|
|
60
|
-
const diff = Number(a[index]) - Number(b[index]);
|
|
61
|
-
if (diff !== 0)
|
|
62
|
-
return diff > 0 ? 1 : -1;
|
|
63
|
-
}
|
|
64
|
-
const preA = a[4];
|
|
65
|
-
const preB = b[4];
|
|
66
|
-
if (preA === undefined && preB === undefined)
|
|
67
|
-
return 0;
|
|
68
|
-
if (preA === undefined)
|
|
69
|
-
return 1;
|
|
70
|
-
if (preB === undefined)
|
|
71
|
-
return -1;
|
|
72
|
-
const leftParts = preA.split('.');
|
|
73
|
-
const rightParts = preB.split('.');
|
|
74
|
-
for (let index = 0; index < Math.max(leftParts.length, rightParts.length); index += 1) {
|
|
75
|
-
const one = leftParts[index];
|
|
76
|
-
const other = rightParts[index];
|
|
77
|
-
if (one === undefined)
|
|
78
|
-
return -1;
|
|
79
|
-
if (other === undefined)
|
|
80
|
-
return 1;
|
|
81
|
-
const oneNumber = /^\d+$/.test(one);
|
|
82
|
-
const otherNumber = /^\d+$/.test(other);
|
|
83
|
-
if (oneNumber && otherNumber) {
|
|
84
|
-
const diff = Number(one) - Number(other);
|
|
85
|
-
if (diff !== 0)
|
|
86
|
-
return diff > 0 ? 1 : -1;
|
|
87
|
-
continue;
|
|
88
|
-
}
|
|
89
|
-
if (oneNumber)
|
|
90
|
-
return -1;
|
|
91
|
-
if (otherNumber)
|
|
92
|
-
return 1;
|
|
93
|
-
if (one !== other)
|
|
94
|
-
return one > other ? 1 : -1;
|
|
95
|
-
}
|
|
96
|
-
return 0;
|
|
55
|
+
return compareVersions(left, right);
|
|
97
56
|
}
|
|
98
57
|
function sourceOf(raw, at) {
|
|
99
58
|
const record = asRecord(raw);
|
|
@@ -129,7 +88,7 @@ function versionOf(raw, at) {
|
|
|
129
88
|
if (record === undefined)
|
|
130
89
|
return problem('version', '版本必须是一个对象', at);
|
|
131
90
|
const version = asText(record['version']);
|
|
132
|
-
if (!
|
|
91
|
+
if (!isValidVersion(version))
|
|
133
92
|
return problem('version', `版本号不是合法 SemVer:${JSON.stringify(version)}`, at);
|
|
134
93
|
const source = sourceOf(record['source'], `${at}.source`);
|
|
135
94
|
if ('kind' in source)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const RELEASE_PACKAGES: readonly ["@dsh-workbench/adapter-probe", "@dsh-workbench/adapter-profile", "@dsh-workbench/adapter-runtime", "@dsh-workbench/adapter-supply", "@dsh-workbench/adapters-default", "@dsh-workbench/core", "@dsh-workbench/module-tools", "@dsh-workbench/shared"];
|
|
@@ -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
|
+
];
|
package/dist/host/tool-kit.d.ts
CHANGED
|
@@ -12,9 +12,3 @@ export declare const TEXT_OUTPUT: {
|
|
|
12
12
|
render: typeof textRender;
|
|
13
13
|
};
|
|
14
14
|
export declare function jsonText(value: unknown): string;
|
|
15
|
-
export interface CommandHintNames {
|
|
16
|
-
readonly plugin: string;
|
|
17
|
-
readonly suiteId: string;
|
|
18
|
-
}
|
|
19
|
-
export type CommandHint = <T>(command: string, run: () => Promise<T>) => Promise<T>;
|
|
20
|
-
export declare function commandHintFor(names: CommandHintNames): CommandHint;
|
package/dist/host/tool-kit.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { WorkbenchDataError } from './data-error.js';
|
|
2
1
|
export function sessionWorkspace(exec) {
|
|
3
2
|
const cwd = exec?.agent?.session?.header?.cwd;
|
|
4
3
|
return typeof cwd === 'string' && cwd.trim() !== '' ? cwd.trim() : null;
|
|
@@ -18,24 +17,3 @@ export const TEXT_OUTPUT = { schema: { type: 'object', properties: {}, additiona
|
|
|
18
17
|
export function jsonText(value) {
|
|
19
18
|
return JSON.stringify(value);
|
|
20
19
|
}
|
|
21
|
-
const UNCLASSIFIED = 'cli-unclassified';
|
|
22
|
-
export function commandHintFor(names) {
|
|
23
|
-
return async (command, run) => {
|
|
24
|
-
try {
|
|
25
|
-
return await run();
|
|
26
|
-
}
|
|
27
|
-
catch (error) {
|
|
28
|
-
if (!(error instanceof WorkbenchDataError) || error.code !== UNCLASSIFIED)
|
|
29
|
-
throw error;
|
|
30
|
-
const advice = `这条命令(${command})在这份 ${names.plugin} 插件里可能不存在(插件版本旧就会缺):` +
|
|
31
|
-
`用 workbench_modules_update(id=${names.suiteId})升级插件,或在面板的模块状态里点更新,再重试。`;
|
|
32
|
-
throw new WorkbenchDataError(error.code, `${error.message}。${advice}`, {
|
|
33
|
-
...(error.detail === undefined ? {} : { detail: error.detail }),
|
|
34
|
-
hint: `升级:workbench_modules_update(id=${names.suiteId})。` +
|
|
35
|
-
`终端确认:opencli ${names.plugin} ${command} --help${error.hint === undefined ? '' : `\n${error.hint}`}`,
|
|
36
|
-
...(error.helpUrl === undefined ? {} : { helpUrl: error.helpUrl }),
|
|
37
|
-
...(error.project === undefined ? {} : { project: error.project }),
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
};
|
|
41
|
-
}
|
package/dist/host/unit-face.d.ts
CHANGED
|
@@ -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
|
export interface ToolScopeContext {
|
|
12
15
|
readonly workspace: string | null;
|
|
13
16
|
readonly preset: string | null;
|
|
@@ -23,6 +26,10 @@ export interface UnitMountDeps {
|
|
|
23
26
|
readonly ownedUnits: () => readonly string[];
|
|
24
27
|
readonly installable?: (() => readonly string[]) | undefined;
|
|
25
28
|
readonly data: DataReader;
|
|
29
|
+
readonly env?: Readonly<Record<string, string | undefined>> | undefined;
|
|
30
|
+
readonly libs?: LibReader | undefined;
|
|
31
|
+
readonly git?: GitReader | undefined;
|
|
32
|
+
readonly commands?: CommandReader | undefined;
|
|
26
33
|
readonly store: WorkspaceStore;
|
|
27
34
|
readonly values?: ValueHandoff | undefined;
|
|
28
35
|
readonly probe?: (unit: string, options?: {
|