@xiaoso/dsh-workflow-lite 0.0.0-stage → 0.1.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/LICENSE +24 -0
- package/README.en.md +84 -0
- package/README.md +83 -2
- package/THIRD_PARTY_NOTICES.md +762 -0
- package/assets/icon-full.webp +0 -0
- package/assets/icon.webp +0 -0
- package/assets/wordmark.png +0 -0
- package/cordis.patch.yml +3 -0
- package/lib/client.js +127442 -0
- package/lib/index.mjs +9613 -0
- package/lib/types/client/app/addStep.d.ts +25 -0
- package/lib/types/client/app/desktop.d.ts +52 -0
- package/lib/types/client/app/host.d.ts +29 -0
- package/lib/types/client/app/sessions.d.ts +117 -0
- package/lib/types/client/app/theme.d.ts +27 -0
- package/lib/types/client/app/usePluginConfig.d.ts +59 -0
- package/lib/types/client/app/useRunFile.d.ts +24 -0
- package/lib/types/client/app/useRunGraph.d.ts +51 -0
- package/lib/types/client/app/useRunHistory.d.ts +21 -0
- package/lib/types/client/app/useRuns.d.ts +84 -0
- package/lib/types/client/app/useVersions.d.ts +50 -0
- package/lib/types/client/app/useWorkflow.d.ts +67 -0
- package/lib/types/client/app/viewport.d.ts +14 -0
- package/lib/types/client/i18n.d.ts +930 -0
- package/lib/types/client/index.d.ts +18 -0
- package/lib/types/client/model/connect.d.ts +44 -0
- package/lib/types/client/model/editor.d.ts +252 -0
- package/lib/types/client/model/fileKind.d.ts +15 -0
- package/lib/types/client/model/hostPath.d.ts +15 -0
- package/lib/types/client/model/htmlPreview.d.ts +24 -0
- package/lib/types/client/model/hubRuns.d.ts +45 -0
- package/lib/types/client/model/layout.d.ts +83 -0
- package/lib/types/client/model/library.d.ts +109 -0
- package/lib/types/client/model/nudge.d.ts +43 -0
- package/lib/types/client/model/pathSample.d.ts +26 -0
- package/lib/types/client/model/route.d.ts +121 -0
- package/lib/types/client/model/runDraft.d.ts +68 -0
- package/lib/types/client/model/runGraph.d.ts +15 -0
- package/lib/types/client/model/runHistory.d.ts +40 -0
- package/lib/types/client/model/themes.d.ts +87 -0
- package/lib/types/client/model/time.d.ts +7 -0
- package/lib/types/client/rpc.d.ts +42 -0
- package/lib/types/client/ui/AppearancePicker.d.ts +23 -0
- package/lib/types/client/ui/Canvas.d.ts +76 -0
- package/lib/types/client/ui/Confirm.d.ts +42 -0
- package/lib/types/client/ui/DocViewer.d.ts +67 -0
- package/lib/types/client/ui/Dock.d.ts +13 -0
- package/lib/types/client/ui/FileTag.d.ts +9 -0
- package/lib/types/client/ui/FileViewer.d.ts +30 -0
- package/lib/types/client/ui/FlowStreaks.d.ts +40 -0
- package/lib/types/client/ui/Handoff.d.ts +30 -0
- package/lib/types/client/ui/HostPicker.d.ts +31 -0
- package/lib/types/client/ui/HubDialog.d.ts +38 -0
- package/lib/types/client/ui/HubRunRow.d.ts +22 -0
- package/lib/types/client/ui/HubRuns.d.ts +19 -0
- package/lib/types/client/ui/HubSettings.d.ts +20 -0
- package/lib/types/client/ui/HubStorage.d.ts +18 -0
- package/lib/types/client/ui/HubWorkflowList.d.ts +21 -0
- package/lib/types/client/ui/HubWorkflowRow.d.ts +33 -0
- package/lib/types/client/ui/HubWorkflows.d.ts +26 -0
- package/lib/types/client/ui/HubWorkspacePicker.d.ts +16 -0
- package/lib/types/client/ui/Icon.d.ts +83 -0
- package/lib/types/client/ui/InputPanel.d.ts +37 -0
- package/lib/types/client/ui/InputsDialog.d.ts +22 -0
- package/lib/types/client/ui/Inspector.d.ts +51 -0
- package/lib/types/client/ui/Issues.d.ts +15 -0
- package/lib/types/client/ui/Launch.d.ts +30 -0
- package/lib/types/client/ui/Library.d.ts +23 -0
- package/lib/types/client/ui/LinkRow.d.ts +31 -0
- package/lib/types/client/ui/Markdown.d.ts +21 -0
- package/lib/types/client/ui/NodeHeads.d.ts +47 -0
- package/lib/types/client/ui/NoteDrawer.d.ts +21 -0
- package/lib/types/client/ui/OpenWith.d.ts +21 -0
- package/lib/types/client/ui/Outputs.d.ts +61 -0
- package/lib/types/client/ui/PanelHead.d.ts +21 -0
- package/lib/types/client/ui/PlanDialog.d.ts +18 -0
- package/lib/types/client/ui/PreviewCard.d.ts +38 -0
- package/lib/types/client/ui/QuickAdd.d.ts +30 -0
- package/lib/types/client/ui/ResourceItemDialog.d.ts +33 -0
- package/lib/types/client/ui/ResourceItems.d.ts +30 -0
- package/lib/types/client/ui/ResourcePanel.d.ts +26 -0
- package/lib/types/client/ui/Resources.d.ts +43 -0
- package/lib/types/client/ui/RunDraftBar.d.ts +35 -0
- package/lib/types/client/ui/RunEdge.d.ts +29 -0
- package/lib/types/client/ui/RunFiles.d.ts +24 -0
- package/lib/types/client/ui/RunInput.d.ts +26 -0
- package/lib/types/client/ui/RunItemDialog.d.ts +43 -0
- package/lib/types/client/ui/RunModeSwitch.d.ts +14 -0
- package/lib/types/client/ui/RunNav.d.ts +22 -0
- package/lib/types/client/ui/RunNodeState.d.ts +42 -0
- package/lib/types/client/ui/RunOverview.d.ts +27 -0
- package/lib/types/client/ui/RunPosition.d.ts +24 -0
- package/lib/types/client/ui/RunResource.d.ts +40 -0
- package/lib/types/client/ui/RunStatusMenu.d.ts +28 -0
- package/lib/types/client/ui/RunStep.d.ts +45 -0
- package/lib/types/client/ui/RunTopBar.d.ts +42 -0
- package/lib/types/client/ui/RunView.d.ts +43 -0
- package/lib/types/client/ui/SettingsDialog.d.ts +25 -0
- package/lib/types/client/ui/SettingsFields.d.ts +37 -0
- package/lib/types/client/ui/SkillPicker.d.ts +25 -0
- package/lib/types/client/ui/SkillPreview.d.ts +27 -0
- package/lib/types/client/ui/StepMark.d.ts +16 -0
- package/lib/types/client/ui/StepPanel.d.ts +26 -0
- package/lib/types/client/ui/ThemePicker.d.ts +13 -0
- package/lib/types/client/ui/TipLayer.d.ts +17 -0
- package/lib/types/client/ui/TopBar.d.ts +32 -0
- package/lib/types/client/ui/VersionList.d.ts +19 -0
- package/lib/types/client/ui/VersionRow.d.ts +19 -0
- package/lib/types/client/ui/VersionsDialog.d.ts +18 -0
- package/lib/types/client/ui/WorkflowRow.d.ts +32 -0
- package/lib/types/client/ui/WorkflowSwitcher.d.ts +20 -0
- package/lib/types/client/ui/WorkflowView.d.ts +27 -0
- package/lib/types/client/ui/lines.d.ts +13 -0
- package/lib/types/client/ui/primitives.d.ts +119 -0
- package/lib/types/client/ui/resourceUi.d.ts +49 -0
- package/lib/types/client/ui/stepIcons.d.ts +10 -0
- package/lib/types/host/authoringSkill.d.ts +17 -0
- package/lib/types/host/config.d.ts +54 -0
- package/lib/types/host/hostFs.d.ts +69 -0
- package/lib/types/host/plan.d.ts +68 -0
- package/lib/types/host/pluginConfig.d.ts +57 -0
- package/lib/types/host/rpc.d.ts +45 -0
- package/lib/types/host/runs/files.d.ts +37 -0
- package/lib/types/host/runs/notice.d.ts +21 -0
- package/lib/types/host/runs/service.d.ts +258 -0
- package/lib/types/host/runs/skill.d.ts +16 -0
- package/lib/types/host/runs/storage.d.ts +16 -0
- package/lib/types/host/runs/store.d.ts +56 -0
- package/lib/types/host/skillView.d.ts +22 -0
- package/lib/types/host/store/atomic.d.ts +34 -0
- package/lib/types/host/store/materialize.d.ts +19 -0
- package/lib/types/host/store/merge.d.ts +25 -0
- package/lib/types/host/store/paths.d.ts +86 -0
- package/lib/types/host/store/repository.d.ts +217 -0
- package/lib/types/host/store/versions.d.ts +38 -0
- package/lib/types/host/tool/tool.d.ts +432 -0
- package/lib/types/index.d.ts +35 -0
- package/lib/types/shared/appearance.d.ts +49 -0
- package/lib/types/shared/compile.d.ts +71 -0
- package/lib/types/shared/graph.d.ts +54 -0
- package/lib/types/shared/graphDiff.d.ts +29 -0
- package/lib/types/shared/inputs.d.ts +46 -0
- package/lib/types/shared/limits.d.ts +77 -0
- package/lib/types/shared/model.d.ts +122 -0
- package/lib/types/shared/naming.d.ts +59 -0
- package/lib/types/shared/outputPaths.d.ts +49 -0
- package/lib/types/shared/resources.d.ts +98 -0
- package/lib/types/shared/runCursor.d.ts +54 -0
- package/lib/types/shared/runState.d.ts +221 -0
- package/lib/types/shared/runSync.d.ts +24 -0
- package/lib/types/shared/types.d.ts +488 -0
- package/lib/types/shared/validate.d.ts +54 -0
- package/lib/types/shared/wire.d.ts +600 -0
- package/locale/en.json +6 -0
- package/locale/zh.json +6 -0
- package/package.json +144 -4
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dsh-workflow-lite — 唯一的模型可见工具 `workflow_lite`。
|
|
3
|
+
*
|
|
4
|
+
* **一个工具 + 一个 action 枚举**:枚举本身就是能力清单,模型看枚举就知道这张图能干什么,
|
|
5
|
+
* 不必先记住一长串工具名再挑;也避开 DSH 内置的 `workflow` 工具(跑 JS 编排脚本)。
|
|
6
|
+
*
|
|
7
|
+
* 返回通道只有三条:
|
|
8
|
+
* - **被规则拒绝** → 一律 `{ error: { code, message, detail? } }`(`code ∈ {not_found, invalid_args,
|
|
9
|
+
* blocked, conflict, io_error}`)——它是**返回**而不是抛,好让模型读到结构化失败。
|
|
10
|
+
* - **`problems` 只在 `compile` 里出现**,装编译级错误。
|
|
11
|
+
* - **`warnings` 装警告与提示**,每条带 `level`,任何 action 都能带。
|
|
12
|
+
*
|
|
13
|
+
* 定位一律用 `id`;`label` 只用于显示。
|
|
14
|
+
* @module @xiaoso/dsh-workflow-lite/host/tool/tool
|
|
15
|
+
*/
|
|
16
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
17
|
+
import type { JsonValue } from '@deepseek-ai/dsh-util-values';
|
|
18
|
+
import type { ExecutionMode, ReusePolicy } from '../../shared/types.ts';
|
|
19
|
+
import { type Action } from '../../shared/types.ts';
|
|
20
|
+
import type { RunService } from '../runs/service.ts';
|
|
21
|
+
import { type Repository } from '../store/repository.ts';
|
|
22
|
+
/** 工具需要的三个活依赖(`dataDir` / `maxResultBytes` 是活配置,所以取函数而不是值)。 */
|
|
23
|
+
export interface ToolDeps {
|
|
24
|
+
repository: Repository;
|
|
25
|
+
dataDir: () => string;
|
|
26
|
+
maxResultBytes: () => number;
|
|
27
|
+
/** 工作流实例(运行状态);不给就当没有这块能力(`runs` / `resume` 报错,编译不建实例)。 */
|
|
28
|
+
runs?: RunService;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* 注册那唯一的工具。
|
|
32
|
+
* @param ctx - 插件上下文(`tools` 已就绪)。
|
|
33
|
+
* @param deps - 仓储与两个活配置。
|
|
34
|
+
* @returns 注销器。
|
|
35
|
+
*/
|
|
36
|
+
/** 工具的参数面(与下方注册处的 `parameters` 同构;抽成具名接口好让单测直接构造)。 */
|
|
37
|
+
export interface WorkflowLiteArgs {
|
|
38
|
+
action: Action;
|
|
39
|
+
workflow?: string;
|
|
40
|
+
node?: string;
|
|
41
|
+
content?: string;
|
|
42
|
+
label?: string;
|
|
43
|
+
output?: string;
|
|
44
|
+
outputs?: {
|
|
45
|
+
path: string;
|
|
46
|
+
rule?: string;
|
|
47
|
+
}[];
|
|
48
|
+
description?: string;
|
|
49
|
+
no_output?: boolean;
|
|
50
|
+
from_template?: string;
|
|
51
|
+
to?: string;
|
|
52
|
+
source?: string;
|
|
53
|
+
target?: string;
|
|
54
|
+
when?: string;
|
|
55
|
+
goal?: string;
|
|
56
|
+
full?: boolean;
|
|
57
|
+
output_root?: string;
|
|
58
|
+
mode?: ExecutionMode;
|
|
59
|
+
reuse?: ReusePolicy;
|
|
60
|
+
set_goal?: boolean;
|
|
61
|
+
handoff?: 'result' | 'none';
|
|
62
|
+
handoff_note?: string;
|
|
63
|
+
update?: boolean;
|
|
64
|
+
run_state?: boolean;
|
|
65
|
+
instance?: string;
|
|
66
|
+
all?: boolean;
|
|
67
|
+
status?: string;
|
|
68
|
+
note?: string;
|
|
69
|
+
nodes?: NodePatchArgs[];
|
|
70
|
+
log?: string;
|
|
71
|
+
input?: InputArgs;
|
|
72
|
+
answers?: AnswerArgs[];
|
|
73
|
+
resource?: ResourceArgs;
|
|
74
|
+
}
|
|
75
|
+
/** write_resource 的 resource(与参数声明同构)。 */
|
|
76
|
+
export interface ResourceArgs {
|
|
77
|
+
label?: string;
|
|
78
|
+
description?: string;
|
|
79
|
+
items?: {
|
|
80
|
+
kind: string;
|
|
81
|
+
value: string;
|
|
82
|
+
note?: string;
|
|
83
|
+
}[];
|
|
84
|
+
}
|
|
85
|
+
/** write_node 的 input(与参数声明同构)。 */
|
|
86
|
+
export interface InputArgs {
|
|
87
|
+
question?: string;
|
|
88
|
+
kind?: string;
|
|
89
|
+
options?: string[];
|
|
90
|
+
default?: string;
|
|
91
|
+
defaults?: string[];
|
|
92
|
+
placeholder?: string;
|
|
93
|
+
hint?: string;
|
|
94
|
+
required?: boolean;
|
|
95
|
+
}
|
|
96
|
+
/** compile 的 answers 里的一项。 */
|
|
97
|
+
export interface AnswerArgs {
|
|
98
|
+
id: string;
|
|
99
|
+
value?: string;
|
|
100
|
+
values?: string[];
|
|
101
|
+
}
|
|
102
|
+
/** `state` 动作里一个步骤的改动(与参数声明同构)。 */
|
|
103
|
+
export interface NodePatchArgs {
|
|
104
|
+
id: string;
|
|
105
|
+
status?: string;
|
|
106
|
+
summary?: string;
|
|
107
|
+
outputs?: string[];
|
|
108
|
+
verdict?: string;
|
|
109
|
+
error?: string;
|
|
110
|
+
by?: string;
|
|
111
|
+
}
|
|
112
|
+
/** `execute` 真正用到的那一小块执行上下文(完整 `ToolRunContext` 结构上兼容它)。 */
|
|
113
|
+
export interface ToolExecView {
|
|
114
|
+
agent?: {
|
|
115
|
+
session?: {
|
|
116
|
+
header?: {
|
|
117
|
+
id?: string;
|
|
118
|
+
cwd?: string;
|
|
119
|
+
origin?: string;
|
|
120
|
+
parentSession?: string;
|
|
121
|
+
};
|
|
122
|
+
};
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* 工具的处理体。**抽出来是为了可单测**:单测直接调它,不必造一个 Cordis Context。
|
|
127
|
+
* @param deps - 仓储与两个活配置。
|
|
128
|
+
* @returns 处理一个调用并回规范 JSON 值(失败也是返回值,不抛)。
|
|
129
|
+
*/
|
|
130
|
+
export declare function createWorkflowLiteHandler(deps: ToolDeps): (args: WorkflowLiteArgs, exec?: ToolExecView) => Promise<JsonValue>;
|
|
131
|
+
/** 工具的参数声明(隐式开放对象根;`required` 内联写)。导出供测试直接编译成 JSON Schema 校验。 */
|
|
132
|
+
export declare const PARAMETERS: {
|
|
133
|
+
readonly action: {
|
|
134
|
+
readonly type: "string";
|
|
135
|
+
readonly enum: readonly ["list", "read", "compile", "create", "write_node", "set_label", "delete_node", "connect", "disconnect", "rename_workflow", "delete_workflow", "save_as_template", "configure", "write_resource", "runs", "resume", "state"];
|
|
136
|
+
readonly required: true;
|
|
137
|
+
readonly description: "要做的动作。";
|
|
138
|
+
};
|
|
139
|
+
readonly workflow: {
|
|
140
|
+
readonly type: "string";
|
|
141
|
+
readonly description: "图名(不带 .json)。除 list 外都需要。";
|
|
142
|
+
};
|
|
143
|
+
readonly node: {
|
|
144
|
+
readonly type: "string";
|
|
145
|
+
readonly description: "节点 id(read / write_node / set_label / delete_node / save_as_template)。";
|
|
146
|
+
};
|
|
147
|
+
readonly content: {
|
|
148
|
+
readonly type: "string";
|
|
149
|
+
readonly description: "write_node:节点提示词正文(允许空串,但空正文是编译级)。";
|
|
150
|
+
};
|
|
151
|
+
readonly label: {
|
|
152
|
+
readonly type: "string";
|
|
153
|
+
readonly description: "write_node / set_label:显示名。不要求唯一;空串 = 清除(回落显示 id)。";
|
|
154
|
+
};
|
|
155
|
+
readonly output: {
|
|
156
|
+
readonly type: "string";
|
|
157
|
+
readonly description: "write_node:产出契约(相对工作区根的路径)。";
|
|
158
|
+
};
|
|
159
|
+
readonly outputs: {
|
|
160
|
+
readonly type: "array";
|
|
161
|
+
readonly description: "write_node:一个或多个产出,每个可带生成规则(规则进派发计划的交付契约)。给了它就整份替换 output。";
|
|
162
|
+
readonly items: {
|
|
163
|
+
readonly type: "object";
|
|
164
|
+
readonly additionalProperties: false;
|
|
165
|
+
readonly properties: {
|
|
166
|
+
readonly path: {
|
|
167
|
+
readonly type: "string";
|
|
168
|
+
readonly required: true;
|
|
169
|
+
readonly description: "相对工作区根的产出路径。";
|
|
170
|
+
};
|
|
171
|
+
readonly rule: {
|
|
172
|
+
readonly type: "string";
|
|
173
|
+
readonly description: "这份产出该怎么写:结构、必须包含什么、长度上限(进资源说明)。";
|
|
174
|
+
};
|
|
175
|
+
};
|
|
176
|
+
};
|
|
177
|
+
};
|
|
178
|
+
readonly description: {
|
|
179
|
+
readonly type: "string";
|
|
180
|
+
readonly description: "write_node:一句话说明这一步做什么(给人看,不进计划);空串 = 清除。";
|
|
181
|
+
};
|
|
182
|
+
readonly no_output: {
|
|
183
|
+
readonly type: "boolean";
|
|
184
|
+
readonly description: "write_node:true ⇒ 显式声明本节点不产出文件(写 output: false)。";
|
|
185
|
+
};
|
|
186
|
+
readonly from_template: {
|
|
187
|
+
readonly type: "string";
|
|
188
|
+
readonly description: "write_node:从 templates/nodes/<名>.json 取 data 本体(不复制它的 id 与 position)。";
|
|
189
|
+
};
|
|
190
|
+
readonly to: {
|
|
191
|
+
readonly type: "string";
|
|
192
|
+
readonly description: "rename_workflow:新图名 / save_as_template:节点模板名(缺省 = 步骤 id)。";
|
|
193
|
+
};
|
|
194
|
+
readonly source: {
|
|
195
|
+
readonly type: "string";
|
|
196
|
+
readonly description: "connect / disconnect:源节点 id。";
|
|
197
|
+
};
|
|
198
|
+
readonly target: {
|
|
199
|
+
readonly type: "string";
|
|
200
|
+
readonly description: "connect / disconnect:目标节点 id。";
|
|
201
|
+
};
|
|
202
|
+
readonly when: {
|
|
203
|
+
readonly type: "string";
|
|
204
|
+
readonly description: "connect / disconnect:条件(缺省 = 无条件边)。短判定词(pass / fail)走 VERDICT 约定;也可以写一句自然语言条件,由执行者判断。";
|
|
205
|
+
};
|
|
206
|
+
readonly handoff: {
|
|
207
|
+
readonly type: "string";
|
|
208
|
+
readonly enum: readonly ["result", "none"];
|
|
209
|
+
readonly description: "connect(步骤 → 步骤):result(缺省)把上游这一次的执行结果交给下游 / none 只管先后。边已存在时只改交接。";
|
|
210
|
+
};
|
|
211
|
+
readonly handoff_note: {
|
|
212
|
+
readonly type: "string";
|
|
213
|
+
readonly description: "connect(步骤 → 步骤):交接说明——下游拿到执行结果之后怎么用(进派发计划);空串 = 清除。";
|
|
214
|
+
};
|
|
215
|
+
readonly update: {
|
|
216
|
+
readonly type: "boolean";
|
|
217
|
+
readonly description: "connect(步骤 → 资源):true = 在原文件上更新(先读再改,如修完在问题清单里打钩);false = 整份写出。缺省:资源还没人写就是整份写出,已经有人写就是更新。";
|
|
218
|
+
};
|
|
219
|
+
readonly resource: {
|
|
220
|
+
readonly type: "object";
|
|
221
|
+
readonly description: "write_resource:资源的内容(给了 node 就是修改那个资源,给了的字段才改;没给 node 就是新建)。";
|
|
222
|
+
readonly additionalProperties: false;
|
|
223
|
+
readonly properties: {
|
|
224
|
+
readonly label: {
|
|
225
|
+
readonly type: "string";
|
|
226
|
+
readonly description: "名字(计划里称呼它);空串 = 清除。";
|
|
227
|
+
};
|
|
228
|
+
readonly description: {
|
|
229
|
+
readonly type: "string";
|
|
230
|
+
readonly description: "一句话描述(给人看,不进计划);空串 = 清除。";
|
|
231
|
+
};
|
|
232
|
+
readonly items: {
|
|
233
|
+
readonly type: "array";
|
|
234
|
+
readonly description: "全部内容(整份替换),按顺序。";
|
|
235
|
+
readonly items: {
|
|
236
|
+
readonly type: "object";
|
|
237
|
+
readonly additionalProperties: false;
|
|
238
|
+
readonly properties: {
|
|
239
|
+
readonly kind: {
|
|
240
|
+
readonly type: "string";
|
|
241
|
+
readonly enum: readonly ["file", "folder", "url", "skill", "text"];
|
|
242
|
+
readonly required: true;
|
|
243
|
+
readonly description: "file 文件 / folder 文件夹(value 是路径:绝对路径原样用;相对路径有步骤写它时在产出根目录下,只被读时相对工作区)/ url 网址 / skill(value 是 skill 名)/ text 自定义(value 是用户自己写的一段提示词,原样交给读它的步骤)。";
|
|
244
|
+
};
|
|
245
|
+
readonly value: {
|
|
246
|
+
readonly type: "string";
|
|
247
|
+
readonly required: true;
|
|
248
|
+
readonly description: "路径 / 网址 / skill 名 / 正文。";
|
|
249
|
+
};
|
|
250
|
+
readonly note: {
|
|
251
|
+
readonly type: "string";
|
|
252
|
+
readonly description: "这一项怎么用。写入的文件写成规格:结构、长度上限;更新的再写明哪些部分就地改写、记录表每次加一行的格式。text 不用。";
|
|
253
|
+
};
|
|
254
|
+
};
|
|
255
|
+
};
|
|
256
|
+
};
|
|
257
|
+
};
|
|
258
|
+
};
|
|
259
|
+
readonly goal: {
|
|
260
|
+
readonly type: "string";
|
|
261
|
+
readonly description: "compile:本次目标(用户说了要做成什么时写,进计划的「本次执行」段)。";
|
|
262
|
+
};
|
|
263
|
+
readonly full: {
|
|
264
|
+
readonly type: "boolean";
|
|
265
|
+
readonly description: "compile:true = 整卷预览(内联正文,不建实例、不写文件);建图后自检用它。";
|
|
266
|
+
};
|
|
267
|
+
readonly output_root: {
|
|
268
|
+
readonly type: "string";
|
|
269
|
+
readonly description: "configure:产出根目录(相对工作区或绝对路径),编译时拼在每个产出文件前面;{instance} 换成实例 id。空串 = 清除(默认 .workflow-lite/runs/{instance}/out),. = 工作区根目录。";
|
|
270
|
+
};
|
|
271
|
+
readonly run_state: {
|
|
272
|
+
readonly type: "boolean";
|
|
273
|
+
readonly description: "configure:记录运行状态。打开后每个工作流实例都带一份运行状态,执行时按计划末尾「运行状态」段用 state 记进度。";
|
|
274
|
+
};
|
|
275
|
+
readonly instance: {
|
|
276
|
+
readonly type: "string";
|
|
277
|
+
readonly description: "resume / state:实例 id(缺省 = 本会话当前的实例;用户从画布上执行时会给出)。";
|
|
278
|
+
};
|
|
279
|
+
readonly status: {
|
|
280
|
+
readonly type: "string";
|
|
281
|
+
readonly enum: readonly ["pending", "running", "waiting", "done", "failed", "cancelled"];
|
|
282
|
+
readonly description: "state:整体状态。";
|
|
283
|
+
};
|
|
284
|
+
readonly note: {
|
|
285
|
+
readonly type: "string";
|
|
286
|
+
readonly description: "state:整体的一句说明(waiting 写等什么、failed / cancelled 写原因);空串 = 清掉。";
|
|
287
|
+
};
|
|
288
|
+
readonly nodes: {
|
|
289
|
+
readonly type: "array";
|
|
290
|
+
readonly description: "state:要改的步骤,每项一个。改 status 时插件自动补轮次、开始 / 结束时间和流水;done 带 summary、outputs,有条件出边的带 verdict(取它出边的条件值);failed 带 error。";
|
|
291
|
+
readonly items: {
|
|
292
|
+
readonly type: "object";
|
|
293
|
+
readonly additionalProperties: false;
|
|
294
|
+
readonly properties: {
|
|
295
|
+
readonly id: {
|
|
296
|
+
readonly type: "string";
|
|
297
|
+
readonly required: true;
|
|
298
|
+
readonly description: "步骤 id(大小写与图一致)。";
|
|
299
|
+
};
|
|
300
|
+
readonly status: {
|
|
301
|
+
readonly type: "string";
|
|
302
|
+
readonly enum: readonly ["pending", "running", "waiting", "done", "failed", "skipped"];
|
|
303
|
+
readonly description: "步骤状态。";
|
|
304
|
+
};
|
|
305
|
+
readonly summary: {
|
|
306
|
+
readonly type: "string";
|
|
307
|
+
readonly description: "一两句结论(200 字以内);空串 = 清掉。";
|
|
308
|
+
};
|
|
309
|
+
readonly outputs: {
|
|
310
|
+
readonly type: "array";
|
|
311
|
+
readonly items: {
|
|
312
|
+
readonly type: "string";
|
|
313
|
+
};
|
|
314
|
+
readonly description: "这一轮实际写出的文件路径(照计划里给的路径写)。";
|
|
315
|
+
};
|
|
316
|
+
readonly verdict: {
|
|
317
|
+
readonly type: "string";
|
|
318
|
+
readonly description: "判定:它出边的条件值之一(如 pass / fail)。";
|
|
319
|
+
};
|
|
320
|
+
readonly error: {
|
|
321
|
+
readonly type: "string";
|
|
322
|
+
readonly description: "失败原因。";
|
|
323
|
+
};
|
|
324
|
+
readonly by: {
|
|
325
|
+
readonly type: "string";
|
|
326
|
+
readonly description: "谁做的:self / subagent / 队员名。";
|
|
327
|
+
};
|
|
328
|
+
};
|
|
329
|
+
};
|
|
330
|
+
};
|
|
331
|
+
readonly log: {
|
|
332
|
+
readonly type: "string";
|
|
333
|
+
readonly description: "state:往流水追加一条说明。";
|
|
334
|
+
};
|
|
335
|
+
readonly input: {
|
|
336
|
+
readonly type: "object";
|
|
337
|
+
readonly description: "write_node:给了它就是新建或修改一个输入节点(执行前问用户的问题;问题与回答进计划,占位与说明只给填写的人看)。";
|
|
338
|
+
readonly additionalProperties: false;
|
|
339
|
+
readonly properties: {
|
|
340
|
+
readonly question: {
|
|
341
|
+
readonly type: "string";
|
|
342
|
+
readonly description: "问题(一行);新建时必填。";
|
|
343
|
+
};
|
|
344
|
+
readonly kind: {
|
|
345
|
+
readonly type: "string";
|
|
346
|
+
readonly enum: readonly ["text", "textarea", "choice", "multi"];
|
|
347
|
+
readonly description: "text 一句话(缺省)/ textarea 多行 / choice 单选 / multi 多选。";
|
|
348
|
+
};
|
|
349
|
+
readonly options: {
|
|
350
|
+
readonly type: "array";
|
|
351
|
+
readonly items: {
|
|
352
|
+
readonly type: "string";
|
|
353
|
+
};
|
|
354
|
+
readonly description: "选项(choice / multi)。";
|
|
355
|
+
};
|
|
356
|
+
readonly default: {
|
|
357
|
+
readonly type: "string";
|
|
358
|
+
readonly description: "默认值(文字题的预填文字、单选的一个选项)。";
|
|
359
|
+
};
|
|
360
|
+
readonly defaults: {
|
|
361
|
+
readonly type: "array";
|
|
362
|
+
readonly items: {
|
|
363
|
+
readonly type: "string";
|
|
364
|
+
};
|
|
365
|
+
readonly description: "多选的默认选项。";
|
|
366
|
+
};
|
|
367
|
+
readonly placeholder: {
|
|
368
|
+
readonly type: "string";
|
|
369
|
+
readonly description: "输入框里的灰字;空串 = 清除。";
|
|
370
|
+
};
|
|
371
|
+
readonly hint: {
|
|
372
|
+
readonly type: "string";
|
|
373
|
+
readonly description: "填写时显示的说明;空串 = 清除。";
|
|
374
|
+
};
|
|
375
|
+
readonly required: {
|
|
376
|
+
readonly type: "boolean";
|
|
377
|
+
readonly description: "必填。";
|
|
378
|
+
};
|
|
379
|
+
};
|
|
380
|
+
};
|
|
381
|
+
readonly answers: {
|
|
382
|
+
readonly type: "array";
|
|
383
|
+
readonly description: "compile:用户对输入节点的回答,每项一个;没给的用默认值。用户在画布上点「执行」时已经填过,不用再给。";
|
|
384
|
+
readonly items: {
|
|
385
|
+
readonly type: "object";
|
|
386
|
+
readonly additionalProperties: false;
|
|
387
|
+
readonly properties: {
|
|
388
|
+
readonly id: {
|
|
389
|
+
readonly type: "string";
|
|
390
|
+
readonly required: true;
|
|
391
|
+
readonly description: "输入节点 id。";
|
|
392
|
+
};
|
|
393
|
+
readonly value: {
|
|
394
|
+
readonly type: "string";
|
|
395
|
+
readonly description: "文字题、单选的回答。";
|
|
396
|
+
};
|
|
397
|
+
readonly values: {
|
|
398
|
+
readonly type: "array";
|
|
399
|
+
readonly items: {
|
|
400
|
+
readonly type: "string";
|
|
401
|
+
};
|
|
402
|
+
readonly description: "多选选中的项。";
|
|
403
|
+
};
|
|
404
|
+
};
|
|
405
|
+
};
|
|
406
|
+
};
|
|
407
|
+
readonly all: {
|
|
408
|
+
readonly type: "boolean";
|
|
409
|
+
readonly description: "runs:true = 列所有会话的实例(缺省只列本会话的)。";
|
|
410
|
+
};
|
|
411
|
+
readonly mode: {
|
|
412
|
+
readonly type: "string";
|
|
413
|
+
readonly enum: readonly ["auto", "serial", "subagent", "team"];
|
|
414
|
+
readonly description: "configure:执行方式。auto 由主 agent 决定 / serial 本人串行 / subagent 主 agent 派子代理 / team 主 agent 当 Agent Team 的 Lead。";
|
|
415
|
+
};
|
|
416
|
+
readonly reuse: {
|
|
417
|
+
readonly type: "string";
|
|
418
|
+
readonly enum: readonly ["auto", "reuse", "fresh"];
|
|
419
|
+
readonly description: "configure:复用执行者——同一个步骤再次执行(循环下一轮、重试、中断后继续)交给谁。auto 由主 agent 决定 / reuse 交回上次做它的子代理或队员,带着之前的上下文 / fresh 每次新派,上下文干净。serial 时不起作用。";
|
|
420
|
+
};
|
|
421
|
+
readonly set_goal: {
|
|
422
|
+
readonly type: "boolean";
|
|
423
|
+
readonly description: "configure:设定目标(缺省开)。开着时计划让主 agent 开始前用 create_goal 把这次执行设成会话目标,做完标记完成;长流程不会做一半就停。";
|
|
424
|
+
};
|
|
425
|
+
};
|
|
426
|
+
/**
|
|
427
|
+
* 注册那唯一的工具。
|
|
428
|
+
* @param ctx - 插件上下文(`tools` 已就绪)。
|
|
429
|
+
* @param deps - 仓储与两个活配置。
|
|
430
|
+
* @returns 注销器。
|
|
431
|
+
*/
|
|
432
|
+
export declare function registerWorkflowLiteTool(ctx: Context, deps: ToolDeps): () => void;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dsh-workflow-lite — host 半。
|
|
3
|
+
*
|
|
4
|
+
* 三件事:把**文件仓储**(单文件 JSON、原子写、写前哈希 + 字段级合并)接到活配置上;
|
|
5
|
+
* 注册**唯一的模型可见工具** `workflow_lite`(14 个 action,没有档位开关);把**画布 RPC**
|
|
6
|
+
* 挂到共享 Connection 的 `/api` 通道上(只在有 web 的 profile 里挂,缺它不影响工具可用)。
|
|
7
|
+
*
|
|
8
|
+
* 这个插件**不执行任何节点**:它只管理文件、渲染画布、把图编译成一份派发计划,
|
|
9
|
+
* 拿到计划的模型自己决定怎么执行。插件不调度,就没有并发/超时/重试/锁/心跳/恢复。
|
|
10
|
+
* 每次执行都是一个工作流实例:图的快照 + 工作区里的实例目录(任务描述、默认产出)。开了「记录运行状态」
|
|
11
|
+
* 的图还带一份状态:主 agent 经工具的 `state` 动作记进度,用户在画布上看、改,改动通知回模型。
|
|
12
|
+
*
|
|
13
|
+
* @module @xiaoso/dsh-workflow-lite
|
|
14
|
+
*/
|
|
15
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
16
|
+
import { CONFIG_KEYS, Config, type WorkflowLiteSettings } from './host/config.ts';
|
|
17
|
+
/** Host 插件名(也是 profile patch 那行的 id)。 */
|
|
18
|
+
export declare const name = "workflow-lite";
|
|
19
|
+
/** 插件的配置声明——Cordis 从入口模块的命名空间上读它。 */
|
|
20
|
+
export { Config };
|
|
21
|
+
/**
|
|
22
|
+
* 硬依赖只有 `tools`(工具注册是插件的存在理由)。
|
|
23
|
+
*
|
|
24
|
+
* `connection` **刻意不在这里**:画布 RPC 走 `ctx.inject(['connection'])` 的子上下文注册,
|
|
25
|
+
* 这样在没有 web 服务的 profile 里,插件照样只带工具起来,而不是整个 fiber 停在 pending。
|
|
26
|
+
*/
|
|
27
|
+
export declare const inject: string[];
|
|
28
|
+
/**
|
|
29
|
+
* Host 插件体。
|
|
30
|
+
* @param ctx - host 插件上下文。
|
|
31
|
+
* @param config - 解析后的活配置(`Volatile` 引用,写入时就地更新)。
|
|
32
|
+
*/
|
|
33
|
+
export declare function apply(ctx: Context, config: WorkflowLiteSettings): Promise<void>;
|
|
34
|
+
/** 六个配置键(文档与测试用)。`dataDir` 改动需要重启——仓储在装配时定住数据根。 */
|
|
35
|
+
export { CONFIG_KEYS };
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dsh-workflow-lite — 步骤卡的图标与颜色:图标库、色板,以及新步骤怎么挑一个不重样的。
|
|
3
|
+
*
|
|
4
|
+
* 图标与颜色只是认路的记号,**不进计划**。存在步骤的 `data.icon` / `data.color` 里;没存的老步骤
|
|
5
|
+
* 按 id 猜(`review`、`review-2` 都是审查的样子,猜不中就是通用的样子)。
|
|
6
|
+
*
|
|
7
|
+
* 这里只有名字(host 与 client 都要用:校验、新建步骤时挑一个);图标的笔画在 `client/ui/stepIcons.ts`。
|
|
8
|
+
* 纯函数,不碰磁盘、不 import DSH 包。
|
|
9
|
+
*
|
|
10
|
+
* @module @xiaoso/dsh-workflow-lite/shared/appearance
|
|
11
|
+
*/
|
|
12
|
+
import type { NodeData, WorkflowNode } from './types.ts';
|
|
13
|
+
/**
|
|
14
|
+
* 图标库。顺序就是新步骤挑图标的顺序:先挑通用的那些,内置步骤的六个放在最后
|
|
15
|
+
* (它们代表固定的意思,空白步骤别一上来就撞上)。
|
|
16
|
+
*/
|
|
17
|
+
export declare const STEP_ICONS: readonly ["idea", "target", "terminal", "bug", "test", "database", "chart", "globe", "chat", "mail", "rocket", "gear", "layers", "book", "checklist", "clipboard", "brush", "image", "translate", "branch", "package", "cloud", "lock", "flag", "sparkle", "scan", "plan", "implement", "review", "fix", "report", "blank"];
|
|
18
|
+
export type StepIcon = (typeof STEP_ICONS)[number];
|
|
19
|
+
/** 色板。顺序就是新步骤挑颜色的顺序;中性的石板灰放最后。 */
|
|
20
|
+
export declare const STEP_COLORS: readonly ["blue", "green", "amber", "coral", "teal", "pink", "olive", "violet", "slate"];
|
|
21
|
+
export type StepColor = (typeof STEP_COLORS)[number];
|
|
22
|
+
export interface Appearance {
|
|
23
|
+
icon: StepIcon;
|
|
24
|
+
color: StepColor;
|
|
25
|
+
}
|
|
26
|
+
export declare function isStepIcon(value: unknown): value is StepIcon;
|
|
27
|
+
export declare function isStepColor(value: unknown): value is StepColor;
|
|
28
|
+
/** 按 id 猜样子:`review`、`review-2` 都算审查;猜不中是通用的样子。 */
|
|
29
|
+
export declare function guessAppearance(id: string): Appearance;
|
|
30
|
+
/** 一个步骤卡的样子:存了就用存的,没存(或存的不认识)就按 id 猜。 */
|
|
31
|
+
export declare function appearanceOf(id: string, data: Pick<NodeData, 'icon' | 'color'>): Appearance;
|
|
32
|
+
/**
|
|
33
|
+
* 给新步骤挑样子:给了的(来自模板 / 内置步骤)照用,缺的那一半挑图里用得最少的——
|
|
34
|
+
* 尽量不和已有的步骤重样。
|
|
35
|
+
*/
|
|
36
|
+
export declare function pickAppearance(nodes: readonly WorkflowNode[], preferred?: Pick<NodeData, 'icon' | 'color'>,
|
|
37
|
+
/** 新步骤的 id:是内置步骤的名字(`review`、`review-2`)就照内置步骤的样子。 */
|
|
38
|
+
id?: string): Appearance;
|
|
39
|
+
/**
|
|
40
|
+
* 给新的「我的步骤」挑样子:避开内置步骤和已有的我的步骤用过的——步骤库里一眼扫过去尽量不重样。
|
|
41
|
+
* 没存样子的老模板在库里显示的是书签,不算占用。
|
|
42
|
+
*/
|
|
43
|
+
export declare function pickTemplateAppearance(templates: readonly {
|
|
44
|
+
name: string;
|
|
45
|
+
icon?: string;
|
|
46
|
+
color?: string;
|
|
47
|
+
}[]): Appearance;
|
|
48
|
+
/** 内置步骤的样子(步骤库、示例流程用)。 */
|
|
49
|
+
export declare function presetAppearance(id: string): Appearance;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dsh-workflow-lite — 派发计划编译器(产品核心)。
|
|
3
|
+
*
|
|
4
|
+
* **纯函数**:不碰磁盘、不看时钟、不用随机数——同一份 `PlanFacts` + 同一份 `GraphAnalysis`
|
|
5
|
+
* + 同一份可选入参 ⇒ **逐字节相同**的输出。物化载荷是 I/O,不在这里。
|
|
6
|
+
*
|
|
7
|
+
* 只有一份段结构,两个视图共用:
|
|
8
|
+
* - **派发版** {@link buildPlan}:② 段的「任务描述路径」给出绝对路径,**正文一个字都不进计划**。
|
|
9
|
+
* - **整卷版** {@link buildFullText}:同一份段结构,把路径引用换成**逐节点内联正文**。
|
|
10
|
+
*
|
|
11
|
+
* 派发版里路径指向的那些文件由 {@link buildTaskTexts} 给出正文:提示词原文,末尾附上这一步读写的资源。
|
|
12
|
+
*
|
|
13
|
+
* 段序**稳定在前、易变在后**:①②③④⑥ 只依赖图 JSON 与路径映射,⑤ 每次都变。
|
|
14
|
+
*
|
|
15
|
+
* 全篇的序一律是 `id` 的**码位序**({@link byId}):清单表行序、批次内序、前置列、补注序。
|
|
16
|
+
* 计划里的节点引用:② 段清单表**首列**写 `label(id)`({@link displayName}),
|
|
17
|
+
* 其余位置一律写 `id`——`id` 唯一,且与载荷文件名一致。
|
|
18
|
+
*
|
|
19
|
+
* @module @xiaoso/dsh-workflow-lite/shared/compile
|
|
20
|
+
*/
|
|
21
|
+
import { type GraphAnalysis } from './graph.ts';
|
|
22
|
+
import type { PlanFacts, PlanId, PlanResult, ValidationProblem, WorkflowDocument } from './types.ts';
|
|
23
|
+
/**
|
|
24
|
+
* 「运行状态」段(工作流开了「记录运行状态」时才有):用 `state` 动作记进度、谁记、什么时候记、
|
|
25
|
+
* 怎么接着跑。字段全表与例子在 skill `workflow-run-state`,这里只放执行时离不开的规矩。
|
|
26
|
+
*/
|
|
27
|
+
export declare function runStateLines(section: RunStateSection): string[];
|
|
28
|
+
/**
|
|
29
|
+
* {@link buildPlan} / {@link buildFullText} 的**可选**入参(必填签名不变)。
|
|
30
|
+
*
|
|
31
|
+
* ⑥ 段「图的注意事项」逐字取自校验结论(`shared/validate.ts`),所以警告与提示必须由调用方带进来;
|
|
32
|
+
* 这里收**该图的全部** `ValidationProblem`——`warning` / `hint` 进 ⑥ 段,
|
|
33
|
+
* `compile` 级与内部判定合并后决定"是否拒绝出计划"(`plan` 为空串)。
|
|
34
|
+
*/
|
|
35
|
+
export interface PlanOptions {
|
|
36
|
+
/** 该图本次校验出的全部问题。 */
|
|
37
|
+
problems?: readonly ValidationProblem[];
|
|
38
|
+
/** 这次执行要记运行状态:计划末尾追加「运行状态」段(见 {@link runStateLines})。 */
|
|
39
|
+
runState?: RunStateSection;
|
|
40
|
+
}
|
|
41
|
+
/** 「运行状态」段要的东西(host 建好实例后给;预览时实例 id 是 `{instance}`)。 */
|
|
42
|
+
export interface RunStateSection {
|
|
43
|
+
/** 实例 id:模型调用 `state` / `resume` 时带上它。 */
|
|
44
|
+
instance: string;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* 派发版:图 + 入参 → 派发计划文本。**纯函数,不碰磁盘。**
|
|
48
|
+
*
|
|
49
|
+
* 有**编译级**问题时返回 `plan: ''`(绝不返回一份残缺计划),`problems` 里是:
|
|
50
|
+
* 内部判定的 `no_nodes` / `prompt_empty`,加上 `options.problems` 里编译级的那些。
|
|
51
|
+
*/
|
|
52
|
+
export declare function buildPlan(facts: PlanFacts, analysis: GraphAnalysis, options?: PlanOptions): PlanResult;
|
|
53
|
+
/**
|
|
54
|
+
* 整卷版:**同一份段结构**,但把"路径引用"换成"内联正文"(给人和存档)。
|
|
55
|
+
*
|
|
56
|
+
* ② 段清单表不再有「任务描述路径」列(路径是本机私有的、带不走),
|
|
57
|
+
* 段尾追加 `### 节点正文`,逐节点内联 `data.prompt` 原文。
|
|
58
|
+
* 有编译级问题时返回空串(与派发版的失败姿态一致——不替它编内容、也不给空正文放行)。
|
|
59
|
+
*/
|
|
60
|
+
export declare function buildFullText(facts: PlanFacts, analysis: GraphAnalysis, options?: PlanOptions): string;
|
|
61
|
+
/**
|
|
62
|
+
* 各步骤的任务描述(`id` → 正文):提示词原文,末尾附上这一步读写的资源(路径已拼好、说明原样)、
|
|
63
|
+
* 写文件的规矩和判定行要求。执行者只读这一份就知道写哪、怎么写,不靠编排者转述——
|
|
64
|
+
* 转述几轮之后,同一份文件每轮的写法都不一样。没什么可附的步骤就是提示词原文。
|
|
65
|
+
*/
|
|
66
|
+
export declare function buildTaskTexts(facts: PlanFacts, analysis: GraphAnalysis): Map<string, string>;
|
|
67
|
+
/**
|
|
68
|
+
* 内容寻址:`planId` = **图内容哈希**前 8 位(canonical writer 的字节 ⇒ 同内容必得同 `planId`
|
|
69
|
+
* ⇒ 同目录幂等覆盖;异内容换目录,先前发出的计划不会被打穿)。
|
|
70
|
+
*/
|
|
71
|
+
export declare function planIdOf(document: WorkflowDocument): PlanId;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dsh-workflow-lite — 图的语义分析:环、回边、执行批次、出边形态。
|
|
3
|
+
*
|
|
4
|
+
* 允许成环之后,编译器最要紧的四件事都在这里一次算清:
|
|
5
|
+
* - **环 = 强连通分量**(SCC)。一个 SCC 就是一个循环体。
|
|
6
|
+
* - **回边**=在 SCC 内做一次 DFS,**指向当前 DFS 栈上祖先**的那条边(自环也算)。
|
|
7
|
+
* 起点取该 SCC 的**入口节点**——被环外入边指向的那个;没有环外入边时按语义挑最像起点的
|
|
8
|
+
* (第一轮就跑得起来、是被条件线跳回来的),并列再取 `id` 最小者(见 `loopStart`)。
|
|
9
|
+
* 一个 SCC **至少**有一条回边;简单环恰好一条,多环交叠的 SCC 可以有多条。
|
|
10
|
+
* - **回边不计入汇合与批次推导**(它不是"要等它",而是"再触发一次")。前向边照常计入前置。
|
|
11
|
+
* - **执行批次**=在"去掉回边之后的 DAG"上做最长路径分层。
|
|
12
|
+
*
|
|
13
|
+
* 全篇的序一律是 **`id` 的码位序**(不是 `localeCompare`,也不是文件里的数组序)。
|
|
14
|
+
*
|
|
15
|
+
* 纯函数,不碰磁盘、不 import DSH 包。
|
|
16
|
+
* @module @xiaoso/dsh-workflow-lite/shared/graph
|
|
17
|
+
*/
|
|
18
|
+
import type { CycleGroup, EdgeShape, ExecutionBatch, WorkflowDocument, WorkflowEdge } from './types.ts';
|
|
19
|
+
/** 按**码位序**比较两个字符串(`localeCompare` 会随 locale 变,不能用)。 */
|
|
20
|
+
export declare function compareByCodepoint(a: string, b: string): number;
|
|
21
|
+
/** 排序助手:按 `id` 码位序升序。 */
|
|
22
|
+
export declare function byId(a: string, b: string): number;
|
|
23
|
+
export interface GraphAnalysis {
|
|
24
|
+
/** 全部**步骤** id,按 `id` 码位序(文件节点不在其中)。 */
|
|
25
|
+
nodeIds: string[];
|
|
26
|
+
/** 边 id → 边。 */
|
|
27
|
+
edgesById: Map<string, WorkflowEdge>;
|
|
28
|
+
/** 节点 id → 出边形态。 */
|
|
29
|
+
shapes: Map<string, EdgeShape>;
|
|
30
|
+
/** 回边 id 集合。 */
|
|
31
|
+
backEdges: Set<string>;
|
|
32
|
+
/** 循环体(SCC)列表,按入口 id 码位序。 */
|
|
33
|
+
cycles: CycleGroup[];
|
|
34
|
+
/** 执行批次,按批次序。 */
|
|
35
|
+
batches: ExecutionBatch[];
|
|
36
|
+
/** 节点 id → 前置 id(**含回边**),按 `id` 码位序。 */
|
|
37
|
+
predecessors: Map<string, string[]>;
|
|
38
|
+
/** 节点 id → 后继 id,按 `id` 码位序。 */
|
|
39
|
+
successors: Map<string, string[]>;
|
|
40
|
+
/** 图内是否有边指向不存在的节点(悬空 edge ⇒ 保存级)。 */
|
|
41
|
+
danglingEdges: WorkflowEdge[];
|
|
42
|
+
}
|
|
43
|
+
/** 判形态:单条 = 顺序;全无条件 = 并行扇出;全有条件 = 状态分支;混用 = 歧义。 */
|
|
44
|
+
export declare function classifyShape(outgoing: readonly WorkflowEdge[]): EdgeShape;
|
|
45
|
+
/** 一条边的条件值;缺省与空串都当"无条件"。 */
|
|
46
|
+
export declare function edgeWhen(edge: WorkflowEdge): string | undefined;
|
|
47
|
+
/**
|
|
48
|
+
* 分析整张图。对**悬空 edge**(端点不存在)不抛错——它由校验层判保存级,
|
|
49
|
+
* 这里把这类边收进 `danglingEdges` 并从拓扑计算里排除,好让上层能同时报出
|
|
50
|
+
* "图坏了"与"坏在哪",而不是在分析阶段就崩掉。
|
|
51
|
+
*/
|
|
52
|
+
export declare function analyzeGraph(document: WorkflowDocument): GraphAnalysis;
|
|
53
|
+
/** 一个循环体是否**没有出口**(环上没有任何指向环外的条件边)——警告级。 */
|
|
54
|
+
export declare function cycleHasNoExit(cycle: CycleGroup): boolean;
|