@dsh-workbench/core 0.3.3 → 0.3.5
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/client.js +1749 -114
- package/cordis.patch.yml +32 -0
- package/dist/client/client.body.js +1749 -114
- package/dist/client/index.js +1749 -114
- package/dist/host/index.js +3101 -1156
- package/dist/types/app/client.d.ts +306 -60
- package/dist/types/app/layouts/approval-detail.d.ts +13 -0
- package/dist/types/app/layouts/sidebar/RecordFooterAction.d.ts +16 -0
- package/dist/types/app/layouts/sidebar/record-footer.d.ts +4 -0
- package/dist/types/modules/panels/client.d.ts +1 -0
- package/dist/types/modules/panels/model/diy-components.d.ts +3 -0
- package/dist/types/modules/panels/model/diy-components.test.d.ts +1 -0
- package/dist/types/modules/panels/model/diy-context.d.ts +4 -5
- package/dist/types/modules/panels/model/diy-observers.d.ts +2 -2
- package/dist/types/modules/panels/model/diy-page.d.ts +1 -1
- package/dist/types/modules/panels/model/diy-record-bar.test.d.ts +1 -0
- package/dist/types/modules/panels/model/diy-record-capture.d.ts +27 -0
- package/dist/types/modules/panels/model/diy-record-capture.test.d.ts +1 -0
- package/dist/types/modules/panels/model/diy-record-failure.test.d.ts +1 -0
- package/dist/types/modules/panels/model/diy-record-routes.d.ts +2 -0
- package/dist/types/modules/panels/model/diy-record-routes.test.d.ts +1 -0
- package/dist/types/modules/panels/model/diy-record-scripts.d.ts +6 -0
- package/dist/types/modules/panels/model/diy-record-text.d.ts +89 -0
- package/dist/types/modules/panels/model/diy-record-text.test.d.ts +1 -0
- package/dist/types/modules/panels/model/diy-record-tools.d.ts +2 -0
- package/dist/types/modules/panels/model/diy-record.d.ts +76 -0
- package/dist/types/modules/panels/model/diy-record.test.d.ts +1 -0
- package/dist/types/modules/panels/model/handoff.d.ts +1 -0
- package/dist/types/modules/panels/unit.d.ts +10 -5
- package/dist/types/shared/api/context-chips.d.ts +20 -0
- package/dist/types/shared/api/host/diy-acts.d.ts +4 -0
- package/dist/types/shared/api/host/diy-components.d.ts +65 -0
- package/dist/types/shared/api/host/diy-debug-act.d.ts +24 -7
- package/dist/types/shared/api/host/diy-record-act.d.ts +19 -0
- package/dist/types/shared/api/host/diy-workshop.d.ts +1 -3
- package/dist/types/shared/api/host/mount-units.d.ts +4 -0
- package/dist/types/shared/api/host/preset-scope.d.ts +16 -0
- package/dist/types/shared/api/host/tool-scope.d.ts +6 -2
- package/dist/types/shared/api/host/workshop-root.d.ts +7 -0
- package/dist/types/shared/components/BlockerState.d.ts +12 -0
- package/dist/types/shared/components/PanelFoot.d.ts +9 -0
- package/dist/types/shared/components/Tip.d.ts +8 -0
- package/dist/types/shared/hooks/bundle-queries.d.ts +12 -0
- package/dist/types/shared/hooks/fact-transports.d.ts +4 -0
- package/dist/types/shared/hooks/panel-state-report.d.ts +12 -0
- package/dist/types/shared/hooks/use-api-resource.d.ts +22 -0
- package/dist/types/shared/hooks/use-blocker-actions.d.ts +8 -0
- package/dist/types/shared/hooks/use-capabilities.d.ts +55 -0
- package/dist/types/shared/hooks/use-capability-gate.d.ts +16 -0
- package/dist/types/shared/hooks/use-card-summary.d.ts +7 -0
- package/dist/types/shared/hooks/use-diy-debug.d.ts +13 -0
- package/dist/types/shared/hooks/use-diy-record.d.ts +21 -0
- package/dist/types/shared/hooks/use-facts.d.ts +10 -0
- package/dist/types/shared/hooks/use-host-write.d.ts +12 -0
- package/dist/types/shared/hooks/use-long-task.d.ts +8 -0
- package/dist/types/shared/hooks/use-unit-board.d.ts +17 -0
- package/dist/types/shared/hooks/use-visible-busy.d.ts +17 -0
- package/package.json +2 -2
- package/scripts/seed-workshop.sh +42 -2
- package/skills/workbench-module-diy/BUILD.md +4 -3
- package/skills/workbench-module-diy/DATASOURCE.md +2 -2
- package/skills/workbench-module-diy/DESIGN.md +26 -1
- package/skills/workbench-module-diy/FAMILY.md +56 -0
- package/skills/workbench-module-diy/KIT.md +111 -96
- package/skills/workbench-module-diy/PANEL.md +24 -13
- package/skills/workbench-module-diy/REVIEW.md +9 -8
- package/skills/workbench-module-diy/SKILL.md +16 -6
- package/skills/workbench-module-diy/TOOLING.md +5 -2
- package/skills/workbench-module-diy/TOOLS.md +7 -41
- package/skills/workbench-module-diy/WIRING.md +14 -6
- package/skills/workbench-module-diy/WRITES.md +47 -6
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { DshPromptAssembly } from '@dsh-workbench/shared';
|
|
2
|
+
import type { ToolScopeContext } from '@dsh-workbench/shared/host';
|
|
2
3
|
export interface ScopedToolRegistry {
|
|
3
4
|
restrict(filter: {
|
|
4
5
|
readonly allow?: readonly string[];
|
|
@@ -11,13 +12,16 @@ export interface ToolScopeAgent {
|
|
|
11
12
|
get?<T = unknown>(name: string): T | undefined;
|
|
12
13
|
} | undefined;
|
|
13
14
|
readonly session?: {
|
|
15
|
+
readonly id?: string | undefined;
|
|
14
16
|
readonly header?: {
|
|
15
|
-
readonly cwd?: string;
|
|
17
|
+
readonly cwd?: string | undefined;
|
|
18
|
+
readonly agentPreset?: string | undefined;
|
|
16
19
|
} | undefined;
|
|
17
20
|
} | undefined;
|
|
18
21
|
}
|
|
19
22
|
export interface ToolScopeOptions {
|
|
20
|
-
deniedTools(
|
|
23
|
+
deniedTools(context: ToolScopeContext): readonly string[];
|
|
24
|
+
presetOf?: ((handle: ToolScopeAgent) => string | null) | undefined;
|
|
21
25
|
logger?: {
|
|
22
26
|
info?(message: string): void;
|
|
23
27
|
warn?(message: string): void;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { DshHostContext } from '@dsh-workbench/shared';
|
|
2
|
+
export interface WorkshopRoot {
|
|
3
|
+
readonly root: string;
|
|
4
|
+
readonly packagesDir: string;
|
|
5
|
+
readonly title: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function workshopRootOf(ctx: DshHostContext, workspace: string | null): Promise<WorkshopRoot | null>;
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import type { ModuleBlocker } from '@dsh-workbench/shared';
|
|
2
2
|
import type { Translate } from '@dsh-workbench/shared';
|
|
3
|
+
/**
|
|
4
|
+
* `<BlockerState>` 的 prop:一份 blocker 加几个回调。
|
|
5
|
+
*/
|
|
3
6
|
export interface BlockerStateProps {
|
|
4
7
|
readonly blocker: ModuleBlocker;
|
|
5
8
|
readonly t: Translate;
|
|
@@ -8,4 +11,13 @@ export interface BlockerStateProps {
|
|
|
8
11
|
readonly flush?: boolean;
|
|
9
12
|
readonly onOpenMarket?: () => void;
|
|
10
13
|
}
|
|
14
|
+
/**
|
|
15
|
+
* 卡片被挡住(或要给一句 notice)时渲染的那一块:按 `blocker.severity` 出块状或一行提示,动作接重试 / 跑修复 / 复制。
|
|
16
|
+
* @param props.blocker - 要显示的那份 blocker:`title` / `hint` / `detail` / `actions` / `severity`。
|
|
17
|
+
* @param props.t - 翻译函数,这一块出现的每句话都从它来。
|
|
18
|
+
* @param props.onRetry - `retry` 动作与修复成功后的重试回调。
|
|
19
|
+
* @param props.onOpenMarket - `open-market` 动作;没给就退回 `onRetry`。
|
|
20
|
+
* @param props.busy - 外层是不是在忙(默认 `false`);为真时动作一并禁用。
|
|
21
|
+
* @param props.flush - 是否贴着容器边(默认 `false`):去掉图标、收窄留白,给卡片内嵌用。
|
|
22
|
+
*/
|
|
11
23
|
export declare function BlockerState({ blocker, t, onRetry, busy, flush, onOpenMarket, }: BlockerStateProps): JSX.Element;
|
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
import type { ReactNode } from '@dsh-workbench/shared';
|
|
2
|
+
/**
|
|
3
|
+
* `<PanelFoot>` 的 prop:左边一句脚注,右边一格内容。
|
|
4
|
+
*/
|
|
2
5
|
export interface PanelFootProps {
|
|
3
6
|
readonly text?: string;
|
|
4
7
|
readonly size?: 'sm' | 'md';
|
|
5
8
|
readonly children?: ReactNode;
|
|
6
9
|
}
|
|
10
|
+
/**
|
|
11
|
+
* 面板底部那行脚注:左侧一句 `text`,右侧放 `children`,两样都不给就是一个空的页脚壳。
|
|
12
|
+
* @param props.text - 左侧那句说明文字;不传时左侧什么都不渲染。
|
|
13
|
+
* @param props.size - 文字档(默认 `'sm'`,11px 三级色;`'md'` 是 14px 二级色,给更宽的面板用)。
|
|
14
|
+
* @param props.children - 右侧那一格内容(一般是按钮或状态),可省略。
|
|
15
|
+
*/
|
|
7
16
|
export declare function PanelFoot({ text, size, children }: PanelFootProps): JSX.Element;
|
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
import { Tooltip } from '@deepseek-ai/dsh-client-ui-primitives';
|
|
2
2
|
type TooltipProps = Parameters<typeof Tooltip>[0];
|
|
3
|
+
/**
|
|
4
|
+
* dsh `Tooltip` 的外壳默认值版:说明统一按右栏习惯(`bottom` / `end` / `gap 6` / 挂 body)来,其余 prop 原样转给 `Tooltip`。
|
|
5
|
+
* @param props.side - 气泡出现在锚点哪一侧(默认 `'bottom'`)。
|
|
6
|
+
* @param props.align - 底 / 顶气泡贴锚点哪条边(默认 `'end'`)。
|
|
7
|
+
* @param props.gap - 锚点到气泡的间距(默认 `6`)。
|
|
8
|
+
* @param props.portal - 是否挂到 `document.body`,以逃出裁剪容器与层叠上下文(默认 `true`)。
|
|
9
|
+
* @param props.children - 单个锚点元素;`label` / `shortcutKeys` / `openOnClick` 等其余 prop 与 dsh 同形。
|
|
10
|
+
*/
|
|
3
11
|
export declare function Tip({ side, align, gap, portal, ...rest }: TooltipProps): JSX.Element;
|
|
4
12
|
export {};
|
|
@@ -1,7 +1,19 @@
|
|
|
1
1
|
import type { ApiResponse } from '@dsh-workbench/shared';
|
|
2
2
|
import { type BundleInspectionPayload, type BundleRegistriesPayload, type ModuleVersionsPayload } from '../api/bundle-install';
|
|
3
3
|
import { type InstalledPluginsPayload } from '../api/installed-plugins';
|
|
4
|
+
/**
|
|
5
|
+
* 读模块源注册表:装模块时能从哪些源取、当前解析到哪一个。
|
|
6
|
+
*/
|
|
4
7
|
export declare function readBundleRegistries(): Promise<ApiResponse<BundleRegistriesPayload>>;
|
|
8
|
+
/**
|
|
9
|
+
* 装之前先看清一个 spec 是什么(收了 / 拒了 / 是个插件);`registry` 省略或空就按默认源解析。
|
|
10
|
+
*/
|
|
5
11
|
export declare function readBundleInspection(spec: string, registry?: string): Promise<ApiResponse<BundleInspectionPayload>>;
|
|
12
|
+
/**
|
|
13
|
+
* 问模块有没有新版;`force: true` 绕过缓存重新问源(“更新”那条路用)。
|
|
14
|
+
*/
|
|
6
15
|
export declare function readModuleVersions(force?: boolean): Promise<ApiResponse<ModuleVersionsPayload>>;
|
|
16
|
+
/**
|
|
17
|
+
* 读已装的 opencli 插件台账;`force: true` 绕过缓存重新问一遍。
|
|
18
|
+
*/
|
|
7
19
|
export declare function readInstalledPlugins(force?: boolean): Promise<ApiResponse<InstalledPluginsPayload>>;
|
|
@@ -1,12 +1,24 @@
|
|
|
1
1
|
import type { PanelCardError, PanelCardPhase } from '@dsh-workbench/shared';
|
|
2
|
+
/**
|
|
3
|
+
* 从路由里切出单元 id(`cmdb/runs` → `cmdb`);切不出来(没有前缀)回 `null`。
|
|
4
|
+
*/
|
|
2
5
|
export declare function unitOfRoute(route: string): string | null;
|
|
6
|
+
/**
|
|
7
|
+
* 告诉上报这沓“现在的工作区是哪个”;换工作区会丢掉还没冲出去的待报读数。
|
|
8
|
+
*/
|
|
3
9
|
export declare function setPanelWorkspace(path: string | null): void;
|
|
10
|
+
/**
|
|
11
|
+
* 卡片读数落地时调它(`useApiResource` 已经接好):同一单元同一条路由只留最新一条,攒一拍再一起冲给宿主。
|
|
12
|
+
*/
|
|
4
13
|
export declare function reportPanelRead(input: {
|
|
5
14
|
readonly unit: string;
|
|
6
15
|
readonly route: string;
|
|
7
16
|
readonly phase: PanelCardPhase;
|
|
8
17
|
readonly error?: PanelCardError | undefined;
|
|
9
18
|
}): void;
|
|
19
|
+
/**
|
|
20
|
+
* 卡片崩了时调它:`unit` 与原因立刻报给宿主(不攒);还不知道工作区时不报。
|
|
21
|
+
*/
|
|
10
22
|
export declare function reportPanelCrash(input: {
|
|
11
23
|
readonly unit: string;
|
|
12
24
|
readonly reason: string;
|
|
@@ -1,16 +1,38 @@
|
|
|
1
1
|
import type { ApiError, ApiResponse, Query } from '@dsh-workbench/shared';
|
|
2
|
+
/**
|
|
3
|
+
* 一次读的状态:`idle` 没开读 · `loading` 在飞 · `ready` 有值 · `error` 失败;`value` 是 `ApiResponse<T>`、
|
|
4
|
+
* `at` 是拿到这个值的时间戳。**身份没变的重取(如点刷新)进 `loading` 时上一次的 `value` 与 `at` 会留着**
|
|
5
|
+
* —— 界面照旧有得画;身份变了、本来就没值、或读到 `error` 时才没有(那时两者都是 `undefined`)。
|
|
6
|
+
*/
|
|
2
7
|
export interface ResourceState<T> {
|
|
3
8
|
readonly phase: 'idle' | 'loading' | 'ready' | 'error';
|
|
4
9
|
readonly value?: T;
|
|
5
10
|
readonly error?: ApiError;
|
|
6
11
|
readonly at?: number;
|
|
7
12
|
}
|
|
13
|
+
/**
|
|
14
|
+
* 这次读的身份:`route` 加排好序的 `query`(排序是为了同一次读只有一个 key);给了 `override` 就用它。
|
|
15
|
+
*/
|
|
8
16
|
export declare function resourceIdentity(route: string, query: Query, override?: string | undefined): string;
|
|
17
|
+
/**
|
|
18
|
+
* 把身份与两个版本号拼成合流用的 key:同一个 key 的并发读共享同一条请求。
|
|
19
|
+
*/
|
|
9
20
|
export declare function readKeyOf(identity: string, refreshToken: number, factRev: number): string;
|
|
21
|
+
/**
|
|
22
|
+
* 非 hook 的取数本体(要自己管缓存时才直接调):同一个 `key` 只发一次,并发调用共享同一个 `task`;
|
|
23
|
+
* 用它就一定要 `release`(一般放 `finally`),最后一个 `release` 才 abort,否则那条请求永不取消。
|
|
24
|
+
*/
|
|
10
25
|
export declare function requestResource<T>(route: string, query: Query, key: string): {
|
|
11
26
|
task: Promise<ApiResponse<T>>;
|
|
12
27
|
release: () => void;
|
|
13
28
|
};
|
|
29
|
+
/**
|
|
30
|
+
* 卡片里所有的读都走它:按身份发一次 `apiGet`,同 key 合流、订阅事实通道(这条变了自动重取)、
|
|
31
|
+
* 并把读数上报面板(`workbench_diy_panel` 看的就是它);身份或版本号一变就换一条读,旧的当场取消。
|
|
32
|
+
* `options.enabled` 为 `false` 时不发请求、相位恒为 `idle`;`key` 覆盖身份、`fact` 换订阅哪条事实
|
|
33
|
+
* (默认 `factOfRoute(route)`)、`report: false` 不上报(夹具与后台探针用)。身份没变的重取会留住上一格
|
|
34
|
+
* 的 `value`,相位降到 `loading`。
|
|
35
|
+
*/
|
|
14
36
|
export declare function useApiResource<T>(route: string, query: Query, refreshToken: number, options?: {
|
|
15
37
|
enabled?: boolean;
|
|
16
38
|
key?: string;
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import type { BlockerAction } from '@dsh-workbench/shared';
|
|
2
|
+
/**
|
|
3
|
+
* blocker 那几个动作的句柄:`run(action)` 执行、`copied` 刚复制走的文本、`running` 正在跑的修复标签、`failure` 失败信息。
|
|
4
|
+
*/
|
|
2
5
|
export interface BlockerActions {
|
|
3
6
|
run(action: BlockerAction): void;
|
|
4
7
|
copied: string | null;
|
|
@@ -8,4 +11,9 @@ export interface BlockerActions {
|
|
|
8
11
|
detail?: string;
|
|
9
12
|
} | null;
|
|
10
13
|
}
|
|
14
|
+
/**
|
|
15
|
+
* `<BlockerState>` 用它把 blocker 的动作接到实处:`retry` 与修复成功后的重试走 `onRetry`、`run-fix` 走 provision
|
|
16
|
+
* 写通道、`copy` 写剪贴板、`open-url` 开新窗;`open-market` 没给 `onOpenMarket` 时退回 `onRetry`。
|
|
17
|
+
* 自己画 blocker 那一块才直接用。
|
|
18
|
+
*/
|
|
11
19
|
export declare function useBlockerActions(onRetry: () => void, onOpenMarket?: () => void): BlockerActions;
|
|
@@ -1,25 +1,80 @@
|
|
|
1
1
|
import type { CapabilityPayload } from '@dsh-workbench/shared';
|
|
2
|
+
/**
|
|
3
|
+
* 纯函数:`refreshToken` 与上一次不同,这一次就该强制重探。
|
|
4
|
+
*/
|
|
2
5
|
export declare function shouldForce(refreshToken: number, previousToken: number): boolean;
|
|
6
|
+
/**
|
|
7
|
+
* 整张能力表:单元 id → 那一格声明的能力(`design.json` 里那份)。
|
|
8
|
+
*/
|
|
3
9
|
export type CapabilityMap = Record<string, CapabilityPayload>;
|
|
10
|
+
/**
|
|
11
|
+
* 探针状态:`checkedAt` 上一次探完的时刻(没探过是 `null`)、`checking` 是不是正在探。
|
|
12
|
+
*/
|
|
4
13
|
export interface CapabilityProbeState {
|
|
5
14
|
readonly checkedAt: number | null;
|
|
6
15
|
readonly checking: boolean;
|
|
7
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* 让下一次强探静默(不点亮 `checking`)—— 装机预检那类不该惊动界面的探用。
|
|
19
|
+
*/
|
|
8
20
|
export declare function markNextProbeSilent(): void;
|
|
21
|
+
/**
|
|
22
|
+
* 探针状态的取值口,给 `useSyncExternalStore` 用;渲染里要状态请用 `useCapabilityProbe`。
|
|
23
|
+
*/
|
|
9
24
|
export declare function probeValue(): CapabilityProbeState;
|
|
25
|
+
/**
|
|
26
|
+
* 探针状态的订阅口,返回退订函数;渲染里要状态请用 `useCapabilityProbe`。
|
|
27
|
+
*/
|
|
10
28
|
export declare function subscribeProbe(listener: () => void): () => void;
|
|
29
|
+
/**
|
|
30
|
+
* 能力表那条事实的名字:写完之后 `useFactInvalidate(CAPABILITY_FACT)` 标它,读者自动重取。
|
|
31
|
+
*/
|
|
11
32
|
export declare const CAPABILITY_FACT = "capability";
|
|
33
|
+
/**
|
|
34
|
+
* 当前整张能力表的取值口(没探过是 `null`),给 `useSyncExternalStore` 用;渲染里请用 `useCapabilities`。
|
|
35
|
+
*/
|
|
12
36
|
export declare function capabilityValue(): CapabilityMap | null;
|
|
37
|
+
/**
|
|
38
|
+
* 能力表的订阅口,返回退订函数;渲染里请用 `useCapabilities`。
|
|
39
|
+
*/
|
|
13
40
|
export declare function subscribeCapabilities(listener: () => void): () => void;
|
|
41
|
+
/**
|
|
42
|
+
* 写入口:换整张表并通知订阅者(同值不通知);传 `null` 清探针状态,`rechecked: true` 时顺手记下 `checkedAt`。
|
|
43
|
+
*/
|
|
14
44
|
export declare function setCapabilities(next: CapabilityMap | null, rechecked?: boolean): void;
|
|
45
|
+
/**
|
|
46
|
+
* 一次强探开始:点亮“正在探”;已经在探就跳过。
|
|
47
|
+
*/
|
|
15
48
|
export declare function beginProbe(): void;
|
|
49
|
+
/**
|
|
50
|
+
* 一次强探收尾:熄灭“正在探”。
|
|
51
|
+
*/
|
|
16
52
|
export declare function endProbe(): void;
|
|
53
|
+
/**
|
|
54
|
+
* 把一次探测的结果发布出去:读到了就广播并回 `true`;没读到(`null`)时已有结论就留着回 `false`,
|
|
55
|
+
* 从来没有过结论才落一张空表回 `true`(“探不动”不等于“还没探”)。
|
|
56
|
+
*/
|
|
17
57
|
export declare function publishCapability(result: CapabilityMap | null, rechecked?: boolean): boolean;
|
|
58
|
+
/**
|
|
59
|
+
* 同一语义(同一个 `force`)的在飞探测搭车:并发调用共享同一个 promise;落地或失败就清掉,
|
|
60
|
+
* 下一次强探会真的再跑一遍;`force` 不同不搭车。
|
|
61
|
+
*/
|
|
18
62
|
export declare function shareCapabilityFetch(force: boolean, load: (force: boolean) => Promise<CapabilityMap | null>): Promise<CapabilityMap | null>;
|
|
63
|
+
/**
|
|
64
|
+
* 探一次能力表并发布:`force` 决定这是“重探”还是顺带读 —— 只有重探负责点亮 / 熄灭探针(`silent` 时连点亮都不做),
|
|
65
|
+
* 被更新的一次重探盖过的非强制结果会丢掉。
|
|
66
|
+
*/
|
|
19
67
|
export declare function runCapabilityRead(options: {
|
|
20
68
|
readonly force: boolean;
|
|
21
69
|
readonly silent?: boolean;
|
|
22
70
|
readonly load?: (force: boolean) => Promise<CapabilityMap | null>;
|
|
23
71
|
}): Promise<void>;
|
|
72
|
+
/**
|
|
73
|
+
* 渲染里要整张能力表时调用:所有读者共享同一份结论,没探过是 `null`。
|
|
74
|
+
* `refreshToken` 变化算一次强制重探,事实版本(`CAPABILITY_FACT`)与 `reloadToken` 变化各触发一次重读。
|
|
75
|
+
*/
|
|
24
76
|
export declare function useCapabilities(refreshToken: number, reloadToken?: number): CapabilityMap | null;
|
|
77
|
+
/**
|
|
78
|
+
* 渲染里要探针状态(`checking` / `checkedAt`)时调用,比如“最近检查”那一行。
|
|
79
|
+
*/
|
|
25
80
|
export declare function useCapabilityProbe(): CapabilityProbeState;
|
|
@@ -1,15 +1,27 @@
|
|
|
1
1
|
import type { CapabilityPayload } from '@dsh-workbench/shared';
|
|
2
2
|
import { type GateMode } from '@dsh-workbench/shared';
|
|
3
3
|
import { type CapabilityMap } from './use-capabilities';
|
|
4
|
+
/**
|
|
5
|
+
* 一格的能力门:`capability` 是这一格声明的能力(没读到是 `null`)、`gated` 放行没(为真 = 这一格能画)、
|
|
6
|
+
* `forceProbe()` 现在就去探一次。
|
|
7
|
+
*/
|
|
4
8
|
export interface CapabilityGate {
|
|
5
9
|
readonly capability: CapabilityPayload | null;
|
|
6
10
|
readonly gated: boolean;
|
|
7
11
|
forceProbe(): void;
|
|
8
12
|
}
|
|
13
|
+
/**
|
|
14
|
+
* 卡片里判断“这一格现在能不能画”时调用:`refreshToken` 变化触发一次重探。
|
|
15
|
+
* `options.mode` 换门的口径(默认 `'capability'`)、`options.fixture` 给夹具一份假能力;
|
|
16
|
+
* `gated` 按口径算 —— 读数还没到先放行(让它去读),读到明确不通过才拦;`forceProbe()` 是“现在就去探一次”。
|
|
17
|
+
*/
|
|
9
18
|
export declare function useCapabilityGate(unit: string, refreshToken: number, options?: {
|
|
10
19
|
readonly mode?: GateMode | undefined;
|
|
11
20
|
readonly fixture?: CapabilityPayload | undefined;
|
|
12
21
|
}): CapabilityGate;
|
|
22
|
+
/**
|
|
23
|
+
* 整张能力表的视图:表本体加探针的 `checkedAt` / `checking`,以及 `forceProbe()` 与 `reload()`。
|
|
24
|
+
*/
|
|
13
25
|
export interface CapabilityMapView {
|
|
14
26
|
readonly capabilities: CapabilityMap | null;
|
|
15
27
|
readonly checkedAt: number | null;
|
|
@@ -17,4 +29,8 @@ export interface CapabilityMapView {
|
|
|
17
29
|
forceProbe(): void;
|
|
18
30
|
reload(): void;
|
|
19
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* 设置页 / 体检那类“要全部单元的能力表”时调用:`reload()` 重取整张表、`forceProbe()` 立刻探一次、
|
|
34
|
+
* `checking` 是探针在跑;没探过时 `capabilities` 是 `null`。
|
|
35
|
+
*/
|
|
20
36
|
export declare function useCapabilityMap(refreshToken: number): CapabilityMapView;
|
|
@@ -1,7 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 卡片报给面板那一格的两个数:`refreshing` 还在不在忙、`at` 最近一次读到值的时间(没有是 `null`)。
|
|
3
|
+
*/
|
|
1
4
|
export interface CardSummary {
|
|
2
5
|
readonly refreshing: boolean;
|
|
3
6
|
readonly at: number | null;
|
|
4
7
|
}
|
|
8
|
+
/**
|
|
9
|
+
* 自己搭卡片、要把 `{ refreshing, at }` 在变化时交给调用点上报面板时调用;`onSummary` 要稳定引用
|
|
10
|
+
* (一般 `useCallback`),否则每次渲染都会上报一次。`useUnitBoard` 已经把这条接好。
|
|
11
|
+
*/
|
|
5
12
|
export declare function useCardSummary(onSummary: (summary: CardSummary) => void, summary: {
|
|
6
13
|
readonly refreshing: boolean;
|
|
7
14
|
readonly at: number | null | undefined;
|
|
@@ -1,8 +1,21 @@
|
|
|
1
1
|
import type { DebugState } from '@dsh-workbench/shared';
|
|
2
2
|
import type { HostWrite } from './use-host-write';
|
|
3
|
+
/**
|
|
4
|
+
* 调试约定的读路由(宿主侧那半同名)。
|
|
5
|
+
*/
|
|
3
6
|
export declare const DIY_DEBUG_ROUTE = "panels/diy-debug";
|
|
7
|
+
/**
|
|
8
|
+
* 调试约定那条事实的名字:写完调 `useFactInvalidate(DIY_DEBUG_FACT)`,读者自动重取。
|
|
9
|
+
*/
|
|
4
10
|
export declare const DIY_DEBUG_FACT = "diy-debug";
|
|
11
|
+
/**
|
|
12
|
+
* 要读“现在的调试约定是什么”时调用(左栏底部那枚状态);跟着事实变化自动重取,不上报面板;
|
|
13
|
+
* 还没读到或后端说没有约定时都是 `null`。
|
|
14
|
+
*/
|
|
5
15
|
export declare function useDiyDebugState(): DebugState | null;
|
|
16
|
+
/**
|
|
17
|
+
* 要发“开始 / 暂停 / 继续 / 结束调试”那几把动作时调用;写走 `diy-debug/act` 通道。
|
|
18
|
+
*/
|
|
6
19
|
export declare function useDiyDebugAct(): HostWrite<{
|
|
7
20
|
text?: string;
|
|
8
21
|
}>;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { RecordState } from '@dsh-workbench/shared';
|
|
2
|
+
import type { HostWrite } from './use-host-write';
|
|
3
|
+
/**
|
|
4
|
+
* 录制交接的读路由(宿主侧那半同名)。
|
|
5
|
+
*/
|
|
6
|
+
export declare const DIY_RECORD_ROUTE = "panels/diy-record";
|
|
7
|
+
/**
|
|
8
|
+
* 录制交接那条事实的名字:写完调 `useFactInvalidate(DIY_RECORD_FACT)`,读者自动重取。
|
|
9
|
+
*/
|
|
10
|
+
export declare const DIY_RECORD_FACT = "diy-record";
|
|
11
|
+
/**
|
|
12
|
+
* 要读“这一段录制交接进行到哪了”时调用(左栏底部那枚状态);跟着事实变化自动重取,不上报面板;
|
|
13
|
+
* 还没读到或后端说没有交接时都是 `null`。
|
|
14
|
+
*/
|
|
15
|
+
export declare function useDiyRecordState(): RecordState | null;
|
|
16
|
+
/**
|
|
17
|
+
* 要发录制交接那几把动作(准备 / 读回 / 收尾)时调用;写走 `diy-record/act` 通道。
|
|
18
|
+
*/
|
|
19
|
+
export declare function useDiyRecordAct(): HostWrite<{
|
|
20
|
+
text?: string;
|
|
21
|
+
}>;
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 渲染里要“这条事实的版本号”时调用:版本一变,喂给 `useApiResource` 的 key 就变、读自动重来。
|
|
3
|
+
* 卡片读数默认订的 `factOfRoute(route)` 已经接好,只有要订别的事实才显式传 `fact`。
|
|
4
|
+
*/
|
|
1
5
|
export declare function useFactRevision(fact: string): number;
|
|
6
|
+
/**
|
|
7
|
+
* 不在渲染里的地方(宿主事件、定时器里看到的旧值)要听事实变化时用它;返回值就是退订函数,用完记得退。
|
|
8
|
+
*/
|
|
2
9
|
export declare function subscribeFactRevision(fact: string, listener: () => void): () => void;
|
|
10
|
+
/**
|
|
11
|
+
* 写完之后把这条事实标脏时调用:不标,面板就停在旧值;不传 `fact` 是把所有事实一起标脏。
|
|
12
|
+
*/
|
|
3
13
|
export declare function useFactInvalidate(): (fact?: string) => void;
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import { type WriteChannel, type WriteOutcome } from '@dsh-workbench/shared';
|
|
2
|
+
/**
|
|
3
|
+
* 一个写通道的句柄:`busy` 在发、`failed` / `detail` 上一条人话失败(没有是 `null`)、
|
|
4
|
+
* `send(body, { silent })` 回 `WriteOutcome`、`fail(message, detail?)` 本地就知道不行时自己塞一条、`clear()` 清掉。
|
|
5
|
+
*/
|
|
2
6
|
export interface HostWrite<T> {
|
|
3
7
|
readonly busy: boolean;
|
|
4
8
|
readonly failed: string | null;
|
|
@@ -9,9 +13,17 @@ export interface HostWrite<T> {
|
|
|
9
13
|
fail(message: string, detail?: string): void;
|
|
10
14
|
clear(): void;
|
|
11
15
|
}
|
|
16
|
+
/**
|
|
17
|
+
* 写通道的配置:`channel` 用哪个前缀、`resource` 挂在它的哪一格(多数通道留空)、`networkText` 网络不通时那句人话。
|
|
18
|
+
*/
|
|
12
19
|
export interface HostWriteOptions {
|
|
13
20
|
readonly channel: WriteChannel;
|
|
14
21
|
readonly resource?: string | undefined;
|
|
15
22
|
readonly networkText: string;
|
|
16
23
|
}
|
|
24
|
+
/**
|
|
25
|
+
* 组件里要写(发 POST)时调用 —— 写只走这条,别在组件里自己 `fetch`。
|
|
26
|
+
* `send` 失败自动落到 `failed` + `detail`(界面直接显示,别自己拼);`silent: true` 是不打扰:不动 `busy` / `failed`,
|
|
27
|
+
* 结果只从返回值拿。返回的 `busy` 是这一路写有没有在飞。
|
|
28
|
+
*/
|
|
17
29
|
export declare function useHostWrite<T>(options: HostWriteOptions): HostWrite<T>;
|
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
import { type LongTaskStatus } from '@dsh-workbench/shared';
|
|
2
|
+
/**
|
|
3
|
+
* 这一单元的长任务清单:`runs` 是这次读交回的那一批(读数还没回来时是空数组)。
|
|
4
|
+
*/
|
|
2
5
|
export interface LongTaskFeed<T> {
|
|
3
6
|
readonly runs: readonly T[];
|
|
4
7
|
}
|
|
8
|
+
/**
|
|
9
|
+
* 卡片要轮询长任务那一行时调用:有在跑的(`running` / `needs-login`)按 `longTaskPollMs` 走快档、空闲走慢档;
|
|
10
|
+
* `workspace` 为 `null`、`mocked: true` 或 `enabled: false` 时不轮。换单元 / 换工作区就是换读数身份,
|
|
11
|
+
* 旧那批立刻清空、读数回来前 `runs` 是空数组。
|
|
12
|
+
*/
|
|
5
13
|
export declare function useLongTask<T extends {
|
|
6
14
|
readonly id: string;
|
|
7
15
|
readonly status: LongTaskStatus;
|
|
@@ -6,10 +6,19 @@ import type { ApiError } from '@dsh-workbench/shared';
|
|
|
6
6
|
import type { ResourceState } from './use-api-resource';
|
|
7
7
|
import type { CapabilityGate } from './use-capability-gate';
|
|
8
8
|
import { type CardSummary } from './use-card-summary';
|
|
9
|
+
/**
|
|
10
|
+
* 卡片读数的最小形状:`state` 是 `useApiResource` 那一格,加上 `refreshing` / `at`(来自 `CardSummary`)
|
|
11
|
+
* 与 `settling`(挂过最短可见时长的那截收尾)。
|
|
12
|
+
*/
|
|
9
13
|
export interface CardFeed extends CardSummary {
|
|
10
14
|
readonly state: ResourceState<unknown>;
|
|
11
15
|
readonly settling?: boolean | undefined;
|
|
12
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* 起步一张卡片要交的东西:这一格的 `unit`、能力门 `gate`、`refreshToken`、`onRefresh` / `onSummary` 两个回调、
|
|
19
|
+
* 自己的读数函数 `read(gated)`(收到的是“放行没”,为真才去读)、翻译 `t`(`enabled: false` 时整格不读);
|
|
20
|
+
* `platformBlocker(error, t)` 把平台错误翻成 blocker。
|
|
21
|
+
*/
|
|
13
22
|
export interface UnitBoardOptions<TFeed extends CardFeed> {
|
|
14
23
|
readonly unit: string;
|
|
15
24
|
readonly gate: CapabilityGate;
|
|
@@ -21,6 +30,10 @@ export interface UnitBoardOptions<TFeed extends CardFeed> {
|
|
|
21
30
|
readonly enabled?: boolean | undefined;
|
|
22
31
|
readonly platformBlocker?: ((error: ApiError, t: Translate) => ModuleBlocker | undefined) | undefined;
|
|
23
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* `useUnitBoard` 叠出来的整组:`feed`(含 `state`)、`capability`、`gated`(放行没)、`refresh`、`forceProbe`、`summary`,
|
|
35
|
+
* 外加拆好的那几个 blocker 字段。
|
|
36
|
+
*/
|
|
24
37
|
export interface UnitBoard<TFeed extends CardFeed> extends UnitBlockers {
|
|
25
38
|
readonly feed: TFeed;
|
|
26
39
|
readonly capability: CapabilityPayload | null;
|
|
@@ -29,4 +42,8 @@ export interface UnitBoard<TFeed extends CardFeed> extends UnitBlockers {
|
|
|
29
42
|
readonly forceProbe: () => void;
|
|
30
43
|
readonly summary: CardSummary;
|
|
31
44
|
}
|
|
45
|
+
/**
|
|
46
|
+
* 卡片起步就用它:把“gate 不放行就不读”、忙 / 安定(按 `MIN_BUSY_MS` 挂最短可见时长)、读数报错时
|
|
47
|
+
* 自动 `forceProbe`、`useCardSummary` 上报面板、blocker 拆分一次叠好。`read(gated)` 里自己调 `useApiResource`。
|
|
48
|
+
*/
|
|
32
49
|
export declare function useUnitBoard<TFeed extends CardFeed>(options: UnitBoardOptions<TFeed>): UnitBoard<TFeed>;
|
|
@@ -1,8 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 读数的相位:`idle` 还没开读 · `loading` 在飞 · `ready` 有值 · `error` 失败。
|
|
3
|
+
*/
|
|
1
4
|
export type HeldPhase = 'idle' | 'loading' | 'ready' | 'error';
|
|
5
|
+
/**
|
|
6
|
+
* “在忙,还是只是收尾”的投影:`settling` 为真时读数已经回来、界面还挂着。
|
|
7
|
+
*/
|
|
2
8
|
export interface BusyView {
|
|
3
9
|
readonly busy: boolean;
|
|
4
10
|
readonly settling: boolean;
|
|
5
11
|
}
|
|
12
|
+
/**
|
|
13
|
+
* 把“正在刷新”折进相位:`refreshing` 且已是 `ready` 记作 `loading`,让“旧值还显示、新的在路上”有名字。
|
|
14
|
+
*/
|
|
6
15
|
export declare function heldPhase(phase: HeldPhase, refreshing: boolean): HeldPhase;
|
|
16
|
+
/**
|
|
17
|
+
* 由 `active` 与 `useVisibleBusy` 挂出来的 `visible` 投影出 `{ busy, settling }`;纯函数,好测。
|
|
18
|
+
*/
|
|
7
19
|
export declare function busyView(active: boolean, visible: boolean): BusyView;
|
|
20
|
+
/**
|
|
21
|
+
* 需要“最少转一会儿”的忙态时调用:`active` 变真立刻 `busy`;变假时若这次没转满 `floorMs`,`busy` 先挂着,
|
|
22
|
+
* 这期间 `settling` 为真表示读数在回来的路上。`floorMs` 传共享包的 `MIN_BUSY_MS`,别自己编 ——
|
|
23
|
+
* 取数几毫秒就回来时不挂这一会儿,用户看到的是“闪一下”,比不转更难读。
|
|
24
|
+
*/
|
|
8
25
|
export declare function useVisibleBusy(active: boolean, floorMs: number): BusyView;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dsh-workbench/core",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.5",
|
|
4
4
|
"description": "个人工作台:Agent 工作台外壳(左栏 + 常驻对话 + 自研右侧数据面板)。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"icon": "./icon.svg",
|
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
"access": "public"
|
|
88
88
|
},
|
|
89
89
|
"dependencies": {
|
|
90
|
-
"@dsh-workbench/shared": "0.3.
|
|
90
|
+
"@dsh-workbench/shared": "0.3.5"
|
|
91
91
|
},
|
|
92
92
|
"scripts": {
|
|
93
93
|
"build": "node scripts/build.mjs && node scripts/build-types.mjs",
|
package/scripts/seed-workshop.sh
CHANGED
|
@@ -102,6 +102,24 @@ target_version() {
|
|
|
102
102
|
printf '%s\n' "$version"
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
+
# 外壳 manifest 里钉的那份 dsh UI 版本(模块模板默认带的那个 devDependency,见
|
|
106
|
+
# `.scratch/dsh-primitives-face/spec.md` §3.1)。源优先**基准**(正在跑的那份外壳),
|
|
107
|
+
# 没有才退回跑脚本这份副本 —— 与 link_workshop_skills 同一条口径。
|
|
108
|
+
# 读不到就留空:调用方按"不写这一项"处理(模块 `init` 那边有自己的兜底常量与一句人话)。
|
|
109
|
+
shell_primitives_version() {
|
|
110
|
+
local root="$SHELL_ROOT"
|
|
111
|
+
[ -n "$root" ] && [ -f "$root/package.json" ] || root="$REPO_DIR"
|
|
112
|
+
[ -f "$root/package.json" ] || return 0
|
|
113
|
+
node -e '
|
|
114
|
+
const fs = require("node:fs");
|
|
115
|
+
try {
|
|
116
|
+
const pinned = JSON.parse(fs.readFileSync(process.argv[1], "utf8"))
|
|
117
|
+
.devDependencies?.["@deepseek-ai/dsh-client-ui-primitives"];
|
|
118
|
+
process.stdout.write(typeof pinned === "string" ? pinned : "");
|
|
119
|
+
} catch {}
|
|
120
|
+
' "$root/package.json" 2>/dev/null || true
|
|
121
|
+
}
|
|
122
|
+
|
|
105
123
|
# 三个包的装法**只有一处真相**:仓库副本 link 进本仓,安装副本按目标版本装。
|
|
106
124
|
# skeleton 与 sync 都调它 —— 两份规则漂开的症状是"根清单是 link、overrides 是 ^",
|
|
107
125
|
# 于是同一个工坊里两代并存(正是要防的那件事),而且不报错。
|
|
@@ -124,6 +142,15 @@ compute_specs() {
|
|
|
124
142
|
TOOLS_SPEC="^$version"
|
|
125
143
|
SHARED_SPEC="^$version"
|
|
126
144
|
fi
|
|
145
|
+
# dsh 原语(模块模板默认带的那个):**精确版**,与模块自己那份 devDependency 对齐 ——
|
|
146
|
+
# 类型面要对齐对账过的那一版(`.scratch/dsh-primitives-face/spec.md` §3.1)。
|
|
147
|
+
# 空 = 读不到外壳 manifest,就**不写这一项**(模块 `init` 有自己的兜底常量)。
|
|
148
|
+
local primitives_version
|
|
149
|
+
primitives_version="$(shell_primitives_version)"
|
|
150
|
+
PRIMITIVES_SPEC=""
|
|
151
|
+
if [ -n "$primitives_version" ]; then
|
|
152
|
+
PRIMITIVES_SPEC="$primitives_version"
|
|
153
|
+
fi
|
|
127
154
|
}
|
|
128
155
|
|
|
129
156
|
# 日志**只有一处**去处:$DSH_HOME/workbench/seed.log(冻结接口)。
|
|
@@ -395,8 +422,8 @@ run_sync() {
|
|
|
395
422
|
log_line "→ ⚠️ 自愈失败:${reason}"
|
|
396
423
|
return 1
|
|
397
424
|
fi
|
|
398
|
-
node - "$DIY_DIR/package.json" "$CORE_SPEC" "$TOOLS_SPEC" "$SHARED_SPEC" <<'NODE'
|
|
399
|
-
const [file, core, tools, shared] = process.argv.slice(2);
|
|
425
|
+
node - "$DIY_DIR/package.json" "$CORE_SPEC" "$TOOLS_SPEC" "$SHARED_SPEC" "$PRIMITIVES_SPEC" <<'NODE'
|
|
426
|
+
const [file, core, tools, shared, primitives] = process.argv.slice(2);
|
|
400
427
|
const fs = require('node:fs');
|
|
401
428
|
const manifest = JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
402
429
|
const want = {
|
|
@@ -405,6 +432,11 @@ const want = {
|
|
|
405
432
|
'@dsh-workbench/shared': shared,
|
|
406
433
|
};
|
|
407
434
|
manifest.devDependencies = { ...(manifest.devDependencies ?? {}), ...want };
|
|
435
|
+
// dsh 原语(模块模板默认带的那个):只进 devDependencies,**不进 overrides** ——
|
|
436
|
+
// 它不是 @dsh-workbench 的包,覆盖它没有意义(那是"多个模块各装一份"的另一种病)。
|
|
437
|
+
if (primitives !== undefined && primitives !== '') {
|
|
438
|
+
manifest.devDependencies['@deepseek-ai/dsh-client-ui-primitives'] = primitives;
|
|
439
|
+
}
|
|
408
440
|
manifest.pnpm = {
|
|
409
441
|
...(manifest.pnpm ?? {}),
|
|
410
442
|
overrides: { ...(manifest.pnpm?.overrides ?? {}), ...want },
|
|
@@ -556,6 +588,13 @@ if [ -f "$DIY_DIR/package.json" ]; then
|
|
|
556
588
|
echo "→ DIY 工坊已存在,跳过建骨架(要重来就先删掉 ${DIY_DIR})"
|
|
557
589
|
else
|
|
558
590
|
echo "→ 建 DIY 工坊 $DIY_DIR"
|
|
591
|
+
# 原语那一行可能没有(读不到外壳 manifest 时不写):空行在 JSON 里无害。
|
|
592
|
+
# ⚠️ 这里是 `if` 不是 `[ … ] && …`:后者在 `set -e` 下,测试为假时整条语句返回 1,
|
|
593
|
+
# 脚本会**当场退出**(骨架只建到一半、自愈也不起了)—— 实测被 ④ 那一格抓到。
|
|
594
|
+
PRIMITIVES_LINE=""
|
|
595
|
+
if [ -n "$PRIMITIVES_SPEC" ]; then
|
|
596
|
+
PRIMITIVES_LINE=" \"@deepseek-ai/dsh-client-ui-primitives\": \"$PRIMITIVES_SPEC\","
|
|
597
|
+
fi
|
|
559
598
|
cat >"$DIY_DIR/package.json" <<EOF
|
|
560
599
|
{
|
|
561
600
|
"name": "dsh-workbench-diy",
|
|
@@ -567,6 +606,7 @@ else
|
|
|
567
606
|
"@dsh-workbench/core": "$CORE_SPEC",
|
|
568
607
|
"@dsh-workbench/module-tools": "$TOOLS_SPEC",
|
|
569
608
|
"@dsh-workbench/shared": "$SHARED_SPEC",
|
|
609
|
+
${PRIMITIVES_LINE}
|
|
570
610
|
"@types/node": "^24.19.0",
|
|
571
611
|
"@types/react": "^19.3.0",
|
|
572
612
|
"esbuild": "^0.28.2",
|
|
@@ -68,7 +68,7 @@ pnpm exec dsh-wb-module init <unit> --dir <工坊>/packages/module-<unit> --temp
|
|
|
68
68
|
|
|
69
69
|
| 文件 | 职责 |
|
|
70
70
|
|---|---|
|
|
71
|
-
| `package.json` | 自述清单:包名、`dsh.bundle.patch`、`dsh.client
|
|
71
|
+
| `package.json` | 自述清单:包名、`dsh.bundle.patch`、`dsh.client`(`external` 默认带 `@dsh-workbench/core/client` 与 dsh 原语那行)、`dsh.workbench.unit`、`dsh.workbenchFaces{host,client}`(工具链字段,门禁必填)、六个脚本、peer 依赖;原语那行由 `init` 盖精确版([KIT.md](KIT.md) §8) |
|
|
72
72
|
| `arch.config.mjs` | 模块自己的**架构方言**:**只有一行**工厂调用 `moduleArch()`(从 `@dsh-workbench/module-tools/arch` 来)。层序表 / 两个运行时 / 阈值只有那一份,随工具链同代 |
|
|
73
73
|
| `eslint.config.mjs` | 模块自己的**语法卫生方言**:**只有两行** —— `moduleLint({ rootDir: import.meta.dirname })`(从 `@dsh-workbench/module-tools/lint` 来;`rootDir` 把 tsconfig 根钉在这个模块上,多份配置并存时 typescript-eslint 才猜得出)。规则 / ignores 只有那一份,随工具链同代;要放行某条就从 `moduleLint({ rules, ignores })` 开口子,别改方言那些块(判据比整份 8 块,逐块点名),也别手写一份自己的(自己 import 方言再照抄整份则分不出来) |
|
|
74
74
|
| `cordis.patch.yml` | 把自己插进 profile 的那一行 |
|
|
@@ -104,6 +104,7 @@ dsh-wb-module build # 出 client.js 与 dist/host.js
|
|
|
104
104
|
dsh-wb-module check # 十三条判据,全跑
|
|
105
105
|
dsh-wb-module check --only cards # 单跑一条(contracts / protocol / bundles / source / arch / lint /
|
|
106
106
|
# primitives / kit / cards / standalone / markers / style / alias)
|
|
107
|
+
dsh-wb-module check --only primitives [--all|--json] # 查询口:dsh 原语里有什么
|
|
107
108
|
dsh-wb-module lint [--fix] # 跑模块自己那份 eslint 配置;--fix 写回
|
|
108
109
|
```
|
|
109
110
|
|
|
@@ -116,7 +117,7 @@ dsh-wb-module lint [--fix] # 跑模块自己那份 eslint 配置;--fi
|
|
|
116
117
|
|
|
117
118
|
```bash
|
|
118
119
|
pnpm build # 构建
|
|
119
|
-
pnpm typecheck # tsc --noEmit
|
|
120
|
+
pnpm typecheck # tsc --noEmit(init 后先 pnpm install)
|
|
120
121
|
pnpm test # vitest
|
|
121
122
|
pnpm selfcheck # 构建 + 把 client.js 当加载器跑一遍(`diy` 骨架里还多一条 `design check`)
|
|
122
123
|
pnpm check # dsh-wb-module check:十三条判据
|
|
@@ -134,7 +135,7 @@ pnpm lint # dsh-wb-module lint:语法卫生(`pnpm lint -- --fix` 写
|
|
|
134
135
|
`workbench_diy_status`(`unit=<单元 id>`)看它现在走到哪一步、`workbench_diy_install` 装上并上板、
|
|
135
136
|
`workbench_diy_show` 只上板 —— 见 §7。**上完板自己逐条走一遍(这就是验收那一拍)**:浏览器那 14 把
|
|
136
137
|
(`state` / `get html` / `find` / `click` / `hover` / `type` / `fill` / `keys` / `scroll` / `wait` / `eval` /
|
|
137
|
-
`screenshot` / `network` / `dialog`,argv 与结果原样转发,全表见 [
|
|
138
|
+
`screenshot` / `network` / `dialog`,argv 与结果原样转发,全表见 [FAMILY.md](FAMILY.md))打的是
|
|
138
139
|
**用户当前那一页**上工坊那块板里的那张卡 —— 用户那一页不会被换掉,但他得把工作台切到前台。
|
|
139
140
|
**看屏 / 动屏那一族(浏览器那 14 把 / `logs_*`)要先 `workbench_diy_debug_start`**(`unit=…`;
|
|
140
141
|
会请他点头一次)—— 没有这场约定它们一律当场拒;不看屏了先 `_pause`、收工 `_stop`。
|