@dsh-workbench/core 0.1.15 → 0.1.17
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/README.md +19 -0
- package/bin/dsh-workbench +5 -1
- package/client.js +660 -128
- package/cordis.patch.yml +22 -0
- package/dist/client/client.body.js +660 -128
- package/dist/client/index.js +660 -128
- package/dist/host/index.js +1733 -324
- package/dist/types/app/client.d.ts +124 -9
- package/dist/types/app/layouts/market/add-module-text.d.ts +2 -0
- package/dist/types/app/layouts/market/use-add-module.d.ts +4 -3
- package/dist/types/app/layouts/market/use-module-versions.d.ts +2 -0
- package/dist/types/app/layouts/rightbar/MarketView.d.ts +3 -1
- package/dist/types/app/layouts/rightbar/__tests__/market-rows-plugins.test.d.ts +1 -0
- package/dist/types/app/layouts/rightbar/market-mock.d.ts +9 -0
- package/dist/types/app/layouts/rightbar/market-plugin-rows.d.ts +8 -0
- package/dist/types/app/layouts/rightbar/market-rows.d.ts +14 -3
- package/dist/types/app/layouts/rightbar/registry.d.ts +0 -1
- package/dist/types/app/units/__tests__/manifests.test.d.ts +1 -0
- package/dist/types/app/units/fixture-unit-mock.d.ts +3 -3
- package/dist/types/app/units/host.d.ts +2 -2
- package/dist/types/app/units/manifests.d.ts +5 -0
- package/dist/types/app/units/registry.d.ts +10 -2
- package/dist/types/modules/panels/__tests__/market-env.test.d.ts +1 -0
- package/dist/types/modules/panels/__tests__/market-plugin.test.d.ts +1 -0
- package/dist/types/modules/panels/__tests__/market-route.test.d.ts +1 -0
- package/dist/types/modules/panels/__tests__/plugin-actions.test.d.ts +1 -0
- package/dist/types/modules/panels/__tests__/plugin-ledger.test.d.ts +1 -0
- package/dist/types/modules/panels/__tests__/plugin-section.test.d.ts +1 -0
- package/dist/types/modules/panels/__tests__/scope.test.d.ts +1 -0
- package/dist/types/modules/panels/__tests__/service-release.test.d.ts +1 -0
- package/dist/types/modules/panels/index.d.ts +2 -2
- package/dist/types/modules/panels/model/config.d.ts +27 -9
- package/dist/types/modules/panels/model/market-dispatch.d.ts +9 -0
- package/dist/types/modules/panels/model/market-env.d.ts +20 -0
- package/dist/types/modules/panels/model/market-route.d.ts +26 -0
- package/dist/types/modules/panels/model/market-types.d.ts +71 -0
- package/dist/types/modules/panels/model/market.d.ts +7 -66
- package/dist/types/modules/panels/model/plugin-actions.d.ts +50 -0
- package/dist/types/modules/panels/model/plugin-ledger.d.ts +22 -0
- package/dist/types/modules/panels/model/plugin-name.d.ts +8 -0
- package/dist/types/modules/panels/model/plugin-name.test.d.ts +1 -0
- package/dist/types/modules/panels/model/plugin-section.d.ts +13 -0
- package/dist/types/modules/panels/model/service.d.ts +8 -6
- package/dist/types/shared/api/bundle-install.d.ts +8 -1
- package/dist/types/shared/api/host/__tests__/registry-declaration.test.d.ts +1 -0
- package/dist/types/shared/api/host/__tests__/unit-roster-facts.test.d.ts +1 -0
- package/dist/types/shared/api/host/bundle-routes.d.ts +1 -0
- package/dist/types/shared/api/host/installed-module.d.ts +7 -0
- package/dist/types/shared/api/host/mount-units.d.ts +5 -3
- package/dist/types/shared/api/host/package-content.d.ts +6 -0
- package/dist/types/shared/api/host/package-content.test.d.ts +1 -0
- package/dist/types/shared/api/host/package-kind.d.ts +21 -0
- package/dist/types/shared/api/host/package-kind.test.d.ts +1 -0
- package/dist/types/shared/api/host/package-route.d.ts +23 -0
- package/dist/types/shared/api/host/package-route.test.d.ts +1 -0
- package/dist/types/shared/api/host/registry-declaration.d.ts +23 -0
- package/dist/types/shared/api/host/runtime-seed.d.ts +40 -0
- package/dist/types/shared/api/host/runtime-seed.test.d.ts +1 -0
- package/dist/types/shared/api/host/unit-registry.d.ts +33 -4
- package/dist/types/shared/api/host/unit-roster-facts.d.ts +5 -0
- package/dist/types/shared/api/installed-plugins.d.ts +12 -0
- package/dist/types/shared/api/unit-manifests.d.ts +5 -0
- package/dist/types/shared/api/unit-manifests.test.d.ts +1 -0
- package/dist/types/shared/hooks/bundle-queries.d.ts +2 -0
- package/dist/types/shared/hooks/use-facts.d.ts +1 -0
- package/docs/HANDOFF.md +82 -44
- package/docs/OPERATIONS.md +22 -1
- package/package.json +5 -4
- package/scripts/seed-workshop.sh +216 -0
- package/skills/workbench-module-diy/BUILD.md +5 -5
- package/skills/workbench-module-diy/DESIGN.md +7 -1
- package/skills/workbench-module-diy/REVIEW.md +3 -2
- package/skills/workbench-module-diy/TOOLING.md +2 -2
- package/skills/workbench-module-diy/TOOLS.md +9 -2
|
@@ -8,7 +8,7 @@ export interface BundleRegistries {
|
|
|
8
8
|
readonly fallbackRegistries: readonly BundleRegistry[];
|
|
9
9
|
readonly resolved: string | null;
|
|
10
10
|
}
|
|
11
|
-
export type BundleInspectProblem = 'invalid-spec' | 'already-installed' | 'not-found' | 'not-a-package' | 'not-a-bundle' | 'network' | 'unknown';
|
|
11
|
+
export type BundleInspectProblem = 'invalid-spec' | 'already-installed' | 'not-found' | 'not-a-package' | 'not-a-bundle' | 'not-a-workbench-module' | 'not-a-module-or-plugin' | 'network' | 'unknown';
|
|
12
12
|
export type BundleSpecKind = 'registry' | 'path' | 'git' | 'tarball';
|
|
13
13
|
export interface BundleInspectionAccepted {
|
|
14
14
|
readonly status: 'accepted';
|
|
@@ -74,10 +74,16 @@ export interface BundleSupplyPayload {
|
|
|
74
74
|
readonly state: BundleSupplyState;
|
|
75
75
|
readonly reason?: string;
|
|
76
76
|
}
|
|
77
|
+
export interface BundleInstalledPlugin {
|
|
78
|
+
readonly kind: 'opencli-plugin';
|
|
79
|
+
readonly pkg: string;
|
|
80
|
+
readonly name?: string;
|
|
81
|
+
}
|
|
77
82
|
export interface BundleInstallPayload {
|
|
78
83
|
readonly change: BundleChange;
|
|
79
84
|
readonly module: BundleModulePayload;
|
|
80
85
|
readonly supply: BundleSupplyPayload;
|
|
86
|
+
readonly plugin?: BundleInstalledPlugin;
|
|
81
87
|
}
|
|
82
88
|
export interface BundleRemovePayload {
|
|
83
89
|
readonly change: BundleChange;
|
|
@@ -92,6 +98,7 @@ export interface ModuleVersion {
|
|
|
92
98
|
readonly installed: string;
|
|
93
99
|
readonly latest?: string;
|
|
94
100
|
readonly local?: boolean;
|
|
101
|
+
readonly refused?: readonly string[];
|
|
95
102
|
}
|
|
96
103
|
export interface ModuleVersionsPayload {
|
|
97
104
|
readonly modules: readonly ModuleVersion[];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { DshHostContext, DshShell } from '@dsh-workbench/shared';
|
|
2
2
|
import { type RouteHandler } from '@dsh-workbench/shared/host';
|
|
3
3
|
export declare function bundleRegistriesHandler(ctx: DshHostContext): RouteHandler;
|
|
4
|
+
export declare function resetRefusalLog(): void;
|
|
4
5
|
export declare function moduleVersionsHandler(ctx: DshHostContext, shell: DshShell | undefined): RouteHandler;
|
|
5
6
|
export declare function bundleInspectHandler(ctx: DshHostContext): RouteHandler;
|
|
@@ -22,5 +22,12 @@ export interface ProfileModule {
|
|
|
22
22
|
readonly registry?: string;
|
|
23
23
|
readonly local?: boolean;
|
|
24
24
|
}
|
|
25
|
+
export declare function profileManifestOf(profileDir: string | null): Readonly<Record<string, unknown>> | undefined;
|
|
25
26
|
export declare function profileModules(profileDir: string | null): readonly ProfileModule[];
|
|
27
|
+
export declare function moduleDeclarationOf(profileDir: string | null, pkg: string): unknown;
|
|
28
|
+
export interface DeclarationGap {
|
|
29
|
+
readonly pkg: string;
|
|
30
|
+
readonly problems: readonly string[];
|
|
31
|
+
}
|
|
32
|
+
export declare function declarationGaps(profileDir: string | null): readonly DeclarationGap[] | undefined;
|
|
26
33
|
export declare function readInstalledModule(profileDir: string | null, pkg: string): InstalledModule;
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import type { DshHostContext } from '@dsh-workbench/shared';
|
|
2
2
|
import type { UnitManifest } from '@dsh-workbench/shared/host';
|
|
3
3
|
import { type RouteTable } from '@dsh-workbench/shared/host';
|
|
4
|
-
import type { ContextRenderer,
|
|
4
|
+
import type { ContextRenderer, UnitMountDeps, UnitMountResult, UnitCall } from '@dsh-workbench/shared/host';
|
|
5
|
+
import type { HostUnit } from './unit-registry';
|
|
5
6
|
import { type UnitReadiness } from './unit-readiness';
|
|
6
7
|
export interface UnitFailure {
|
|
7
8
|
readonly id: string;
|
|
8
9
|
readonly reason: string;
|
|
9
10
|
}
|
|
10
11
|
export interface MountedUnit {
|
|
11
|
-
readonly
|
|
12
|
+
readonly host: HostUnit;
|
|
12
13
|
readonly result: UnitMountResult;
|
|
13
14
|
readonly readiness: UnitReadiness;
|
|
14
15
|
}
|
|
@@ -40,13 +41,14 @@ interface NamedEntry {
|
|
|
40
41
|
handle(payload: unknown): unknown;
|
|
41
42
|
}
|
|
42
43
|
export declare function failureReasonOf(error: unknown): string;
|
|
43
|
-
export declare function mountUnits(
|
|
44
|
+
export declare function mountUnits(units: readonly HostUnit[], deps: {
|
|
44
45
|
ctx: DshHostContext;
|
|
45
46
|
logger?: {
|
|
46
47
|
info?(m: string): void;
|
|
47
48
|
warn?(m: string): void;
|
|
48
49
|
} | undefined;
|
|
49
50
|
manifests: () => readonly UnitManifest[];
|
|
51
|
+
ownedUnits?: () => readonly string[];
|
|
50
52
|
opencliCommand?: string;
|
|
51
53
|
probe?: UnitMountDeps['probe'];
|
|
52
54
|
store?: UnitMountDeps['store'];
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { DshShell } from '@dsh-workbench/shared';
|
|
2
|
+
export declare function withPackageDir<T>(options: {
|
|
3
|
+
readonly shell?: DshShell | undefined;
|
|
4
|
+
readonly spec: string;
|
|
5
|
+
readonly registry?: string | undefined;
|
|
6
|
+
}, visit: (dir: string) => T): Promise<T | undefined>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export type PackageKind = 'opencli-plugin' | 'dsh-bundle' | 'both' | 'neither';
|
|
2
|
+
export interface PackageVerdict {
|
|
3
|
+
readonly kind: PackageKind;
|
|
4
|
+
readonly pkg?: string;
|
|
5
|
+
readonly pluginName?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface NpmRef {
|
|
8
|
+
readonly name: string;
|
|
9
|
+
readonly version?: string;
|
|
10
|
+
}
|
|
11
|
+
export declare const OPENCLI_MANIFEST_FILE = "opencli-plugin.json";
|
|
12
|
+
export declare function splitNpmSpec(spec: string): NpmRef | undefined;
|
|
13
|
+
export declare function isCommandFile(name: string): boolean;
|
|
14
|
+
export declare function pluginManifestOf(dir: string): Readonly<Record<string, unknown>> | undefined;
|
|
15
|
+
export declare function hasCommandFile(dir: string): boolean;
|
|
16
|
+
export declare function pluginAt(dir: string): {
|
|
17
|
+
readonly name?: string;
|
|
18
|
+
} | undefined;
|
|
19
|
+
export declare function dshMarkersOf(raw: unknown): boolean;
|
|
20
|
+
export declare function verdictOf(dir: string): PackageVerdict | undefined;
|
|
21
|
+
export declare function refusalReason(): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { DshShell } from '@dsh-workbench/shared';
|
|
2
|
+
import { type ResolvedPluginSource } from '@dsh-workbench/shared/host';
|
|
3
|
+
export type PackageRouteKind = 'opencli-plugin' | 'dsh-bundle' | 'neither';
|
|
4
|
+
export interface PackageRoute {
|
|
5
|
+
readonly kind: PackageRouteKind;
|
|
6
|
+
readonly pkg?: string;
|
|
7
|
+
readonly pluginName?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare const LOCAL_PLUGIN_ENV = "DSH_WB_OPENCLI_PLUGIN_PATH";
|
|
10
|
+
export declare const PLUGIN_REGISTRY_ENV = "DSH_WB_OPENCLI_PLUGIN_REGISTRY";
|
|
11
|
+
export declare function packageRouteOf(options: {
|
|
12
|
+
readonly spec: string;
|
|
13
|
+
readonly shell?: DshShell | undefined;
|
|
14
|
+
readonly registry?: string | undefined;
|
|
15
|
+
readonly force?: boolean;
|
|
16
|
+
}): Promise<PackageRoute | undefined>;
|
|
17
|
+
export declare function resetPackageRouteCache(): void;
|
|
18
|
+
export declare function pluginInstallPlan(options: {
|
|
19
|
+
readonly spec: string;
|
|
20
|
+
readonly command: string;
|
|
21
|
+
readonly registry?: string | undefined;
|
|
22
|
+
readonly pluginName?: string | undefined;
|
|
23
|
+
}): ResolvedPluginSource;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { DshShell } from '@dsh-workbench/shared';
|
|
2
|
+
export declare function localDirOf(spec: string): string | undefined;
|
|
3
|
+
export declare function packageManifestOf(dir: string): Readonly<Record<string, unknown>> | undefined;
|
|
4
|
+
export declare function dshRecordOf(dir: string): unknown | undefined;
|
|
5
|
+
export declare function packageNameOf(dir: string): string | undefined;
|
|
6
|
+
export declare function pathDeclarationOf(spec: string): unknown | undefined;
|
|
7
|
+
export interface RegistryDshLookup {
|
|
8
|
+
readonly readable: boolean;
|
|
9
|
+
readonly raw: unknown;
|
|
10
|
+
}
|
|
11
|
+
export declare function registryDshOf(options: {
|
|
12
|
+
shell: DshShell;
|
|
13
|
+
name: string;
|
|
14
|
+
registry?: string | undefined;
|
|
15
|
+
force?: boolean;
|
|
16
|
+
}): Promise<RegistryDshLookup>;
|
|
17
|
+
export declare function registryDeclarationOf(options: {
|
|
18
|
+
shell: DshShell;
|
|
19
|
+
name: string;
|
|
20
|
+
registry: string;
|
|
21
|
+
force?: boolean;
|
|
22
|
+
}): Promise<unknown | undefined>;
|
|
23
|
+
export declare function declarationRefusalOf(name: string, raw: unknown): readonly string[];
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import type { DshHostContext } from '@dsh-workbench/shared';
|
|
3
|
+
export declare const WORKSHOP_SKILLS_DIR = "workbench-module-diy";
|
|
4
|
+
export type SeedLog = (message: string) => void;
|
|
5
|
+
export interface RuntimeSeedPaths {
|
|
6
|
+
readonly root: string;
|
|
7
|
+
readonly entryDir: string;
|
|
8
|
+
readonly opencliRoot: string;
|
|
9
|
+
readonly opencliBinDir: string;
|
|
10
|
+
readonly opencliBin: string;
|
|
11
|
+
readonly opencliHome: string;
|
|
12
|
+
readonly workshop: string;
|
|
13
|
+
readonly workshopPackages: string;
|
|
14
|
+
readonly workshopManifest: string;
|
|
15
|
+
readonly skillsLink: string;
|
|
16
|
+
}
|
|
17
|
+
export interface RuntimeSeedOptions {
|
|
18
|
+
readonly root: string;
|
|
19
|
+
readonly home: string;
|
|
20
|
+
readonly packageRoot: string;
|
|
21
|
+
readonly log?: SeedLog;
|
|
22
|
+
}
|
|
23
|
+
export declare function runtimeSeedPaths(root: string): RuntimeSeedPaths;
|
|
24
|
+
export declare function runtimeSeedRootOf(ctx: DshHostContext): string | null;
|
|
25
|
+
export declare function packageRootOf(moduleUrl: string): string;
|
|
26
|
+
export declare function isInstalledCopy(packageRoot: string): boolean;
|
|
27
|
+
export declare function opencliWrapperScript(packageRoot: string, home: string): string;
|
|
28
|
+
export interface SeedCommand {
|
|
29
|
+
readonly file: string;
|
|
30
|
+
readonly args: readonly string[];
|
|
31
|
+
readonly env: Readonly<Record<string, string>>;
|
|
32
|
+
readonly log: string;
|
|
33
|
+
}
|
|
34
|
+
export declare function workshopSeedPlan(packageRoot: string, home: string, root: string): {
|
|
35
|
+
readonly entry: SeedCommand;
|
|
36
|
+
readonly full: SeedCommand;
|
|
37
|
+
};
|
|
38
|
+
export declare function runDetached(command: SeedCommand, onError: SeedLog, spawnImpl?: typeof spawn): void;
|
|
39
|
+
export declare function prependPath(entryDir: string, env?: NodeJS.ProcessEnv): boolean;
|
|
40
|
+
export declare function seedRuntimeFiles(options: RuntimeSeedOptions): readonly string[];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,9 +1,38 @@
|
|
|
1
1
|
import type { UnitManifest } from '@dsh-workbench/shared';
|
|
2
|
-
import type {
|
|
2
|
+
import type { UnitModuleFace, UnitOwnedFace } from '@dsh-workbench/shared/host';
|
|
3
|
+
export interface UnitRefusal {
|
|
4
|
+
readonly unit: string;
|
|
5
|
+
readonly pkg?: string;
|
|
6
|
+
readonly reasons: readonly string[];
|
|
7
|
+
}
|
|
8
|
+
export type UnitSource = {
|
|
9
|
+
readonly kind: 'package';
|
|
10
|
+
readonly pkg: string;
|
|
11
|
+
} | {
|
|
12
|
+
readonly kind: 'owned';
|
|
13
|
+
};
|
|
14
|
+
export interface HostUnit {
|
|
15
|
+
readonly unit: string;
|
|
16
|
+
readonly manifest: UnitManifest;
|
|
17
|
+
readonly face: UnitModuleFace;
|
|
18
|
+
readonly source: UnitSource;
|
|
19
|
+
}
|
|
20
|
+
export interface UnitDeclarationSource {
|
|
21
|
+
readonly pkg: string;
|
|
22
|
+
readonly declaration: unknown;
|
|
23
|
+
}
|
|
3
24
|
export interface UnitRegistry {
|
|
4
|
-
register(face:
|
|
5
|
-
|
|
25
|
+
register(face: UnitModuleFace): () => void;
|
|
26
|
+
registerOwned(face: UnitOwnedFace): () => void;
|
|
27
|
+
all(): readonly HostUnit[];
|
|
28
|
+
owned(): readonly string[];
|
|
29
|
+
refusals(): readonly UnitRefusal[];
|
|
6
30
|
manifests(): readonly UnitManifest[];
|
|
7
31
|
subscribe(listener: () => void): () => void;
|
|
8
32
|
}
|
|
9
|
-
export declare function createUnitRegistry(
|
|
33
|
+
export declare function createUnitRegistry(options: {
|
|
34
|
+
declarationOf: (unit: string) => UnitDeclarationSource | undefined;
|
|
35
|
+
logger?: {
|
|
36
|
+
warn?(message: string): void;
|
|
37
|
+
} | undefined;
|
|
38
|
+
}): UnitRegistry;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare const INSTALLED_PLUGINS_ROUTE = "panels/plugins";
|
|
2
|
+
export interface InstalledPlugin {
|
|
3
|
+
readonly pkg: string;
|
|
4
|
+
readonly name?: string;
|
|
5
|
+
readonly installed?: string;
|
|
6
|
+
readonly latest?: string;
|
|
7
|
+
readonly local?: boolean;
|
|
8
|
+
readonly broken?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export interface InstalledPluginsPayload {
|
|
11
|
+
readonly plugins: readonly InstalledPlugin[];
|
|
12
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { ApiResponse } from '@dsh-workbench/shared';
|
|
2
2
|
import { type BundleInspectionPayload, type BundleRegistriesPayload, type ModuleVersionsPayload } from '../api/bundle-install';
|
|
3
|
+
import { type InstalledPluginsPayload } from '../api/installed-plugins';
|
|
3
4
|
export declare function readBundleRegistries(): Promise<ApiResponse<BundleRegistriesPayload>>;
|
|
4
5
|
export declare function readBundleInspection(spec: string, registry?: string): Promise<ApiResponse<BundleInspectionPayload>>;
|
|
5
6
|
export declare function readModuleVersions(force?: boolean): Promise<ApiResponse<ModuleVersionsPayload>>;
|
|
7
|
+
export declare function readInstalledPlugins(force?: boolean): Promise<ApiResponse<InstalledPluginsPayload>>;
|
package/docs/HANDOFF.md
CHANGED
|
@@ -1,37 +1,55 @@
|
|
|
1
1
|
# 把工作台给别人用
|
|
2
2
|
|
|
3
|
-
工作台是一个 **dsh
|
|
4
|
-
`
|
|
5
|
-
|
|
3
|
+
工作台是一个 **dsh 插件包**,现在发在**公网 npm** 上:`@dsh-workbench/core`
|
|
4
|
+
(实测 `npm view @dsh-workbench/core version` 出号,`npm pack` 的产物里
|
|
5
|
+
`dsh.bundle.patch` / `cordis.patch.yml` / `client.js` / `dist/host/index.js` 都在)。
|
|
6
|
+
所以**对方不需要配任何私有源**就能装。
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
两种给法,先挑一种:
|
|
9
|
+
|
|
10
|
+
| 给法 | 对方要做的事 | 换来的 |
|
|
11
|
+
| --- | --- | --- |
|
|
12
|
+
| **A. 装进他自己的 `dsh web`**(最短) | Plugins → Add plugin → `@dsh-workbench/core` → Enable now → **刷新页面** | 就在那份 web 里换成工作台;**同一个 profile、同一份会话**、同一个端口 |
|
|
13
|
+
| **B. 独立实例**(要数据分家就选它) | `npx --yes @dsh-workbench/core@latest setup` → `npx @dsh-workbench/core` | 另一个 profile、另一个端口(:3081),他自己那份 `dsh web` **一行不改** |
|
|
14
|
+
|
|
15
|
+
一条路径一句话:**A = 点一下装(单 profile);B = `setup` 然后起(双 profile)**。
|
|
16
|
+
取舍与代价见 [`docs/adr/0037`](../../../docs/adr/0037-workbench-installs-into-any-profile.md)。
|
|
8
17
|
|
|
9
18
|
## 一、对方机器上要有的
|
|
10
19
|
|
|
11
20
|
| # | 东西 | 为什么 | 怎么有 |
|
|
12
21
|
| --- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------- |
|
|
13
22
|
| 1 | `dsh` | 本体。本仓库在 `0.1.7-rc.2` 上验过 | `npm i -g @deepseek-ai/dsh`(公网 npm 上有) |
|
|
14
|
-
| 2 | `node` + **`pnpm`** | dsh 的 `plugin`
|
|
15
|
-
| 3 | 跑过一次 `dsh web` | `setup` 拿 `~/.dsh/profiles/web`
|
|
16
|
-
| 4 |
|
|
17
|
-
| 5 | Coding 账号 + opencli 登录态 | 面板的数据来自 opencli 的 coding 插件 |
|
|
23
|
+
| 2 | `node` + **`pnpm`** | dsh 的 `plugin` 子命令(以及 web 的 Plugins 页)都是**转发给 pnpm** 的;没有 pnpm 会直接报 `dsh: pnpm was not found` | 各自装 |
|
|
24
|
+
| 3 | 跑过一次 `dsh web` | 走 A 需要它给出那个 profile;走 B 时 `setup` 拿 `~/.dsh/profiles/web` 当模板。没有它会**明确报错**,不会静默建出半个 profile | `dsh web` |
|
|
25
|
+
| 4 | 一个能解析这个包的源 | 包在**公网 npm** 上,默认源即可。只有将来改发内网源时,才要 `npm config set @<scope>:registry …` + `npm login`(带 scope 的包只去 `.npmrc` 里给这个 scope 指的源找) | `npm view @dsh-workbench/core version` 出号即可 |
|
|
26
|
+
| 5 | Coding 账号 + opencli 登录态 | 面板的数据来自 opencli 的 coding 插件 | 见第五节 |
|
|
18
27
|
|
|
19
|
-
##
|
|
28
|
+
## 二、A:装进他自己的 `dsh web`(插件页,一条龙)
|
|
20
29
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
30
|
+
在 `dsh web`(:3080)里:
|
|
31
|
+
|
|
32
|
+
1. 侧栏 **Plugins → Add plugin**,填 `@dsh-workbench/core`;
|
|
33
|
+
2. **Install → Enable now**;
|
|
34
|
+
3. **刷新一次页面**(客户端 bundle 是页面加载时装进去的)。
|
|
35
|
+
|
|
36
|
+
装完左栏就是工作台、右侧多出面板列。缺的那几件(隔离 opencli 的入口、`dsh-wb-module`、
|
|
37
|
+
DIY 工坊骨架、可写根)由**外壳自己**补齐 —— 不用跑 `setup`,也不用起第二个实例。
|
|
38
|
+
|
|
39
|
+
差别(先跟对方说清):**会话 / 存储不分家**(接着用他原来那份)、**没有独立端口与进程**、
|
|
40
|
+
**改外壳源码不热重载**、DIY 工坊依赖是首次启动在后台装的。
|
|
25
41
|
|
|
26
|
-
|
|
42
|
+
## 三、B:两步装(独立 profile,占 :3081)
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
# ① 建 profile + 把工作台装进去,然后起(占 :3081,dsh web 继续用 :3080)
|
|
27
46
|
npx --yes @dsh-workbench/core@latest setup
|
|
28
47
|
npx @dsh-workbench/core
|
|
29
48
|
```
|
|
30
49
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
不设这一行,症状是 `404 Not Found - GET https://registry.npmjs.org/@pagoda%2fdsh-workbench`。
|
|
50
|
+
> 若团队后来把包改发到内网源,这两条命令之前要各加一次:
|
|
51
|
+
> `npm config set @<scope>:registry "$NPM_REGISTRY"` 与 `npm login --registry=$NPM_REGISTRY`。
|
|
52
|
+
> 不设的话症状是 `404 Not Found - GET https://registry.npmjs.org/@<scope>%2F…`。
|
|
35
53
|
|
|
36
54
|
> ⚠️ **0.1.6 的已知缺陷**:`setup` 可能死在
|
|
37
55
|
> `…/@dsh-workbench/core/scripts/seed-profile.sh: Permission denied`(发出去的包里随包脚本丢了
|
|
@@ -76,7 +94,7 @@ Settings → 插件里把 `@dsh-workbench/core` 关掉后,工作台会**退化
|
|
|
76
94
|
要重新同步得重跑 `setup`。有意共享的只有两样:**API 凭据**(`~/.dsh/.credentials.yaml`,
|
|
77
95
|
一机一把 key)和 `$DSH_HOME/cordis.patch.yml`(机器公共层,对所有 profile 实时生效)。
|
|
78
96
|
|
|
79
|
-
##
|
|
97
|
+
## 四、不想用 npx?仓库副本也可以
|
|
80
98
|
|
|
81
99
|
`bin/dsh-workbench` 认得出自己是不是仓库副本(看有没有 `.git`):
|
|
82
100
|
|
|
@@ -88,7 +106,7 @@ git clone <仓库> && cd dsh-workbench && pnpm install
|
|
|
88
106
|
|
|
89
107
|
两种身份装出来的东西**同一个包名**,所以对方以后换成正装也不会打架。
|
|
90
108
|
|
|
91
|
-
##
|
|
109
|
+
## 五、数据通路(面板要有数据)
|
|
92
110
|
|
|
93
111
|
1. **opencli 隔离运行时**。第一次打开工作台,启动体检会**自己装**它(`@jackwener/opencli`,
|
|
94
112
|
公网包),落在 `$DSH_HOME/workbench/opencli/toolchain/`,**与对方本机的 `opencli` 完全隔离**
|
|
@@ -142,35 +160,52 @@ git clone <仓库> && cd dsh-workbench && pnpm install
|
|
|
142
160
|
装的时候 `bin/opencli-isolated` 会把 `~/.npmrc` 指回去,就为了拿到源的 token;
|
|
143
161
|
npm 缓存则一律落在那台机器自己的隔离运行时里(**不碰** `~/.npm`)。
|
|
144
162
|
|
|
145
|
-
##
|
|
163
|
+
## 六、不用管的
|
|
146
164
|
|
|
147
165
|
- **`dsh web` 一行不改**:`./scripts/verify.sh` 是外部证据 —— 比对 web 的 profile 哈希、
|
|
148
166
|
两个 profile 的组合树差异、数据是否分家,而不是自证。
|
|
149
167
|
- 会话 / 存储 / 附件各自独立;工作台是**另一个端口、另一个进程**,可与 `dsh web` 同开。
|
|
150
168
|
- 改工作台设置只落在 `profiles/workbench/cordis.patch.yml`。
|
|
151
169
|
|
|
152
|
-
##
|
|
170
|
+
## 七、发版(发起人)
|
|
153
171
|
|
|
154
172
|
```bash
|
|
155
173
|
cd <仓库根>
|
|
156
|
-
pnpm release:dry #
|
|
157
|
-
pnpm release
|
|
174
|
+
pnpm release:dry # 彩排:门禁 → 选版本号 → 构建 → publish --dry-run;不上传,结束回滚版本号
|
|
175
|
+
pnpm release # 真发:上面那一串 + 逐包上传 + git 收尾(提交 / tag / 推送)
|
|
158
176
|
```
|
|
159
177
|
|
|
160
|
-
|
|
178
|
+
不用先 `npm version`:版本号由脚本选(交互,或 `--target 0.2.0`),同步到根与所有包的
|
|
179
|
+
manifest;彩排结束、以及「零上传」的失败,都会自动回滚。
|
|
180
|
+
|
|
181
|
+
**门禁整次发布只跑一遍**(preflight 那次 `pnpm run check`;`--resume` 也跑)。发布走
|
|
182
|
+
`pnpm -r publish --ignore-scripts`:各包的 `prepublishOnly` / `prepack` 是留给**手敲**
|
|
183
|
+
`pnpm publish` 的人兜底的(外壳那份 = 整仓门禁);不关掉它们,pnpm 会在**彩排与真发各再跑
|
|
184
|
+
一遍**整门禁 —— 一次发布就是 3 遍门禁 + 3 遍 vitest + 每个包多两轮构建(实测 pnpm 10.32.1:
|
|
185
|
+
`--dry-run` 一样触发)。来历见
|
|
186
|
+
[`.scratch/dsh-ui-alignment/spec.md`](../../../.scratch/dsh-ui-alignment/spec.md) §18.45。
|
|
187
|
+
|
|
188
|
+
脚本把这几件事变成**硬失败**(都在任何上传之前):
|
|
189
|
+
|
|
190
|
+
- **工作区不干净** → 默认拒(发布会把它们 `git add -A` 一起提交),`--allow-dirty` 才放行;
|
|
191
|
+
- **目标版本必须高于当前版本**;目标版本若在源上**已完整存在**,直接拒(要补发用 `--resume`);
|
|
192
|
+
- **npm 没登录** → 就地拉起 `npm login`;
|
|
193
|
+
- **彩排不过**(`publish --dry-run` 打不出包)→ 零上传退出。
|
|
194
|
+
|
|
195
|
+
只能自己盯、脚本不查的两条:
|
|
161
196
|
|
|
162
197
|
- **`dist/` 在 `.gitignore` 里**:npm 打包的兜底就是 `.gitignore`,不在 `files` 里显式列出
|
|
163
|
-
就会漏掉构建产物 —— 症状不是报错,而是"别人装上后宿主侧起不来"
|
|
164
|
-
|
|
165
|
-
- `private: true` 没摘;
|
|
198
|
+
就会漏掉构建产物 —— 症状不是报错,而是"别人装上后宿主侧起不来"(外壳与 `module-hello` 的
|
|
199
|
+
`files` 都显式列了 `dist` / `client.js`,但发布脚本不核这件事);
|
|
166
200
|
- **随包脚本的可执行位**:`pnpm publish` 只给 `package.json#bin` 点名的那**一个**文件 755,
|
|
167
201
|
其余在 tarball 里一律 644(`npm pack` 会保留,而 git 里的 x 位不进 tarball)——
|
|
168
202
|
所以随包脚本一律不吃 x 位:启动器里 `bash` 呼 `seed-profile.sh`、opencli 那条稳定路径写成
|
|
169
|
-
|
|
203
|
+
自己拥有的转发脚本。这条由外壳 `selfcheck` 的判据钉着(门禁里跑)。
|
|
204
|
+
这类错**本机复现不出来**,只在别人机器上炸
|
|
170
205
|
(0.1.6 就是这么坏在 `seed-profile.sh: Permission denied` 上的,见
|
|
171
206
|
[`.scratch/dsh-ui-alignment/spec.md`](../../../.scratch/dsh-ui-alignment/spec.md) §18.41)。
|
|
172
207
|
|
|
173
|
-
##
|
|
208
|
+
## 八、版本与兼容(实话)
|
|
174
209
|
|
|
175
210
|
`package.json` 的 `peerDependencies` 里**没有** `@deepseek-ai/dsh`,这是有意的:
|
|
176
211
|
dsh 目前是 `0.1.7-rc.2`(预发布),声明范围会让版本不一致的人**装不上**;不声明则是
|
|
@@ -195,29 +230,31 @@ dsh 会用这条做**安装预检**(`evaluatePluginCompatibility`),不满
|
|
|
195
230
|
## 发布(一个脚本,一条命令)
|
|
196
231
|
|
|
197
232
|
```bash
|
|
198
|
-
pnpm release # 门禁 →
|
|
199
|
-
pnpm release:dry #
|
|
233
|
+
pnpm release # 门禁 → 选版本号 → 构建 → 彩排 → 逐包上传 → git 收尾
|
|
234
|
+
pnpm release:dry # 同上,但 publish 只 dry-run:零上传,结束回滚版本号
|
|
200
235
|
```
|
|
201
236
|
|
|
202
|
-
`scripts/release.mjs`
|
|
203
|
-
谁要发、发到哪、要发什么,全部从各包自述清单读,不写死名单:
|
|
237
|
+
`scripts/release.mjs` 是**唯一**的发布入口。发什么、发到哪、谁先谁后,都从各包自述清单读:
|
|
204
238
|
|
|
205
|
-
- **发不发** =
|
|
206
|
-
|
|
207
|
-
-
|
|
208
|
-
|
|
239
|
+
- **发不发** = `packages/*` 一级目录里,非 `private` 且自述了 `publishConfig`(`access` 或 `registry`);
|
|
240
|
+
私有模块必须显式写发布目标这条,由门禁的 `contracts` 判据守着(不许默认落到公网);
|
|
241
|
+
- **发到哪** = 包自己的 `publishConfig.registry`(pnpm 在 recursive publish 里逐包取它),没写的
|
|
242
|
+
落到脚本顶部的 `REGISTRY`(npmjs);本仓现在这 4 个包都发公网,命令一律带 `--access public`。
|
|
243
|
+
注意 `inspectTarget` **只查 npmjs** —— "这个版本发出去没有"对发内网源的包看不准;
|
|
244
|
+
- **什么顺序** = pnpm 自己拓扑排序(`shared` → `core` → 用到它们的模块);
|
|
245
|
+
- **发什么** = pnpm 按各包 `files` / `.gitignore` 打包;**打包清单没人替你核**(见上一章
|
|
246
|
+
「只能自己盯」)。要看清单用 `dsh-wb-module publish`:它只 dry-run、打印清单,不发布。
|
|
209
247
|
|
|
210
|
-
|
|
211
|
-
发布用 `pnpm publish`(不是 `npm publish`):只有 pnpm 会把 `workspace:*` 改写成真实版本,
|
|
248
|
+
发布必须走 `pnpm publish`(不是 `npm publish`):只有 pnpm 会把 `workspace:*` 改写成真实版本,
|
|
212
249
|
`npm pack` / `npm publish` 不会 —— 直接发别人装不上。
|
|
213
250
|
|
|
214
|
-
###
|
|
251
|
+
### 版本同步规则(约定 —— 门禁只守其中一条)
|
|
215
252
|
|
|
216
253
|
| 关系 | 规则 |
|
|
217
254
|
| --- | --- |
|
|
218
|
-
| 模块 ↔ 外壳 | 模块 `peerDependencies['@dsh-workbench/core'] = ^0.1.0`。**`^0.x` 锁次版本**:外壳升到 `0.2.0` 时 `^0.1.0`
|
|
255
|
+
| 模块 ↔ 外壳 | 模块 `peerDependencies['@dsh-workbench/core'] = ^0.1.0`。**`^0.x` 锁次版本**:外壳升到 `0.2.0` 时 `^0.1.0` 不再满足 —— 要把每个模块的范围一起改(或一起升)。门禁只守"peer 依赖存在"(`contracts` 判据),**范围合不合体没人替你算**,靠自觉 |
|
|
219
256
|
| `shared` ↔ 外壳/模块 | 依赖写的是 `workspace:*`,发布时会被改写成**当时那个版本号** → `shared` 必须先发;`shared` 升版后,用到它的包要重新发一次才会带上新范围 |
|
|
220
|
-
| `module-tools` ↔ `init` 模板 | 模板里 `@dsh-workbench/core` / `module-tools` 的范围要跟着本仓版本走,否则 `init`
|
|
257
|
+
| `module-tools` ↔ `init` 模板 | 模板里 `@dsh-workbench/core` / `module-tools` 的范围要跟着本仓版本走,否则 `init` 生成的是过期范围 —— **现在没有任何判据检查它**(上一版 release 脚本查过,换成现在这份之后这条没了),升外壳次版本时记得一起改 |
|
|
221
258
|
|
|
222
259
|
### 中断了怎么续跑(发布是可中断的)
|
|
223
260
|
|
|
@@ -228,7 +265,8 @@ pnpm release:resume # 从现场恢复;**已在源上的包自动跳过**
|
|
|
228
265
|
```
|
|
229
266
|
|
|
230
267
|
- **不带 `--resume` 重跑会被拒**:目标版本必须高于当前版本;源上若已有同名同版本,脚本会说"先提版本号"。这正是为续跑设计的语义(不是 bug)。
|
|
268
|
+
- **`--resume` 照样跑一遍门禁**:断了之后很可能改过包,而门禁整次发布只有 preflight 那一处。真要跳过用 `--skip-gate`(发布不会再补跑一遍)。
|
|
231
269
|
- `pnpm release:dry` 是**彩排**:改版本号 → 构建 → `publish --dry-run` → **回滚本地版本号**,不上传。
|
|
232
270
|
- 发布**成功之后**才做 git 收尾:`git add -A` → `commit -m "chore: 发布版本 v<ver>"` → `tag v<ver>` → `push` → `push origin v<ver>`。git 收尾失败时包已经发出去了,脚本会把该手打的命令打出来,并提示可以 `pnpm release:resume`。
|
|
233
|
-
- 常用旗标:`--target <ver>` 跳出版本选择 · `-y/--yes` 跳过确认 · `--allow-dirty` · `--skip-gate
|
|
271
|
+
- 常用旗标:`--target <ver>` 跳出版本选择 · `-y/--yes` 跳过确认 · `--allow-dirty` · `--skip-gate` / `--skip-rehearsal`(都不推荐) · `--skip-build`(用磁盘上现有产物 —— `prepack` 已关,不再兜底重建)。
|
|
234
272
|
- 依赖:`enquirer`(交互选择版本)与 `semver`(版本比较)是根上的 devDependencies。
|
package/docs/OPERATIONS.md
CHANGED
|
@@ -28,7 +28,28 @@
|
|
|
28
28
|
前提:`dsh` 和 `pnpm` 在 PATH 上(`dsh plugin` 是转发给 pnpm 的),
|
|
29
29
|
且 `~/.dsh/profiles/web` 已存在(跑过一次 `dsh web` 即可)。
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
**给别人用**(两条路:插件页装进他自己的 web / 独立实例 `setup`;包在公网 npm 上)见 [`HANDOFF.md`](HANDOFF.md)。
|
|
32
|
+
|
|
33
|
+
### 变体:装进**当前** profile(在 `dsh web` 里装,不起第二个实例)
|
|
34
|
+
|
|
35
|
+
`dsh web` 侧栏 **Plugins → Add plugin** → 填 `@dsh-workbench/core`(公网 npm 上有,默认源即可)
|
|
36
|
+
→ **Install → Enable now** → **刷新页面**。装的就是 `dsh web` 自己那个 profile。
|
|
37
|
+
|
|
38
|
+
**完成判据**:刷新后左栏是工作台的、右侧出现面板列;`$DSH_HOME/workbench/opencli/bin/opencli`
|
|
39
|
+
存在且指向本包 `bin/opencli-isolated`;`$DSH_HOME/workbench/bin/dsh-wb-module` 可执行
|
|
40
|
+
(这三条不再依赖启动器 —— 宿主自举写的)。
|
|
41
|
+
|
|
42
|
+
这条路上没有启动器,缺的几件由**宿主自举**补齐(建目录、写隔离 opencli 入口、前插 `PATH`、
|
|
43
|
+
后台建 DIY 工坊骨架),可写根由 bundle 层那一行 `sandbox-policy` 放行 —— 见
|
|
44
|
+
[ADR-0037](../../../docs/adr/0037-workbench-installs-into-any-profile.md)。
|
|
45
|
+
|
|
46
|
+
自举是**静默**的:它写了什么只在宿主日志里,后台脚本(工坊骨架 / 依赖)的输出在
|
|
47
|
+
`$DSH_HOME/workbench/seed.log`。DIY 那个工坊“怎么都没建起来”时先看这两个地方。
|
|
48
|
+
|
|
49
|
+
差别:**会话 / 存储不隔离**(接着用你原来那份)、**没有独立端口与进程**、
|
|
50
|
+
**改外壳源码不热重载**、DIY 工坊依赖是首次启动在后台装的(几百 MB,失败只落日志)。
|
|
51
|
+
|
|
52
|
+
撤销:Plugins 页卸载 `@dsh-workbench/core`(配置与数据不清);`~/.dsh/workbench/**` 想清就手删。
|
|
32
53
|
|
|
33
54
|
## 日常
|
|
34
55
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dsh-workbench/core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.17",
|
|
4
4
|
"description": "个人工作台:Agent 工作台外壳(左栏 + 常驻对话 + 自研右侧数据面板)。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"icon": "./icon.svg",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"bin": {
|
|
23
23
|
"dsh-workbench": "./bin/dsh-workbench"
|
|
24
24
|
},
|
|
25
|
-
"//files": "npm 的兜底是 .gitignore —— 而 dist/ 在 .gitignore 里,不显式列出就会**漏掉宿主入口**(exports['.'] 指向它)。发出去之前用 npm pack --dry-run 数一遍 dist/ 有几条。skills/ 是 DIY 模式挂给 agent 的指引(经 skill-filesystem 的 customSkillDirs 挂载),漏了不报错、只是 DIY 的 agent 什么都不知道 —— selfcheck 有一条判据盯着它。",
|
|
25
|
+
"//files": "npm 的兜底是 .gitignore —— 而 dist/ 在 .gitignore 里,不显式列出就会**漏掉宿主入口**(exports['.'] 指向它)。发出去之前用 npm pack --dry-run 数一遍 dist/ 有几条。skills/ 是 DIY 模式挂给 agent 的指引(经 skill-filesystem 的 customSkillDirs 挂载),漏了不报错、只是 DIY 的 agent 什么都不知道 —— selfcheck 有一条判据盯着它。scripts/ 下是**随包出货的脚本**:启动器与宿主自举都要跑它们(seed-profile.sh / seed-workshop.sh),漏一个的症状是「仓库里怎么都对、装出去那台静默什么也没做」。",
|
|
26
26
|
"files": [
|
|
27
27
|
"dist",
|
|
28
28
|
"client.js",
|
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
"skills",
|
|
34
34
|
"preset",
|
|
35
35
|
"scripts/seed-profile.sh",
|
|
36
|
+
"scripts/seed-workshop.sh",
|
|
36
37
|
"README.md",
|
|
37
38
|
"docs/HANDOFF.md",
|
|
38
39
|
"docs/OPERATIONS.md"
|
|
@@ -81,12 +82,12 @@
|
|
|
81
82
|
"vite": "^8.3.1",
|
|
82
83
|
"vitest": "^5.0.2"
|
|
83
84
|
},
|
|
84
|
-
"//publishConfig": "
|
|
85
|
+
"//publishConfig": "只影响**发布这个包**,不影响别人解析依赖。现在发**公网 npm**(scripts/release.mjs 走 registry.npmjs.org),所以这里只有 access;哪天真要改发内网源,地址写在这一段的 registry 里(release.mjs 会优先读它)。",
|
|
85
86
|
"publishConfig": {
|
|
86
87
|
"access": "public"
|
|
87
88
|
},
|
|
88
89
|
"dependencies": {
|
|
89
|
-
"@dsh-workbench/shared": "0.1.
|
|
90
|
+
"@dsh-workbench/shared": "0.1.17"
|
|
90
91
|
},
|
|
91
92
|
"scripts": {
|
|
92
93
|
"build": "node scripts/build.mjs && node scripts/build-types.mjs",
|