@mickorz/opencode-agentic-workflow 0.4.0 → 0.5.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.
Files changed (127) hide show
  1. package/README.md +306 -5
  2. package/dist/cli/config.d.ts +121 -0
  3. package/dist/cli/config.js +331 -0
  4. package/dist/cli/config.js.map +1 -0
  5. package/dist/cli/doctor.d.ts +5 -0
  6. package/dist/cli/doctor.js +141 -0
  7. package/dist/cli/doctor.js.map +1 -0
  8. package/dist/cli/index.d.ts +18 -0
  9. package/dist/cli/index.js +120 -0
  10. package/dist/cli/index.js.map +1 -0
  11. package/dist/cli/install.d.ts +19 -0
  12. package/dist/cli/install.js +135 -0
  13. package/dist/cli/install.js.map +1 -0
  14. package/dist/cli/uninstall.d.ts +16 -0
  15. package/dist/cli/uninstall.js +110 -0
  16. package/dist/cli/uninstall.js.map +1 -0
  17. package/dist/cli/update.d.ts +15 -0
  18. package/dist/cli/update.js +86 -0
  19. package/dist/cli/update.js.map +1 -0
  20. package/dist/core/index.d.ts +39 -0
  21. package/dist/core/index.js +38 -0
  22. package/dist/core/index.js.map +1 -0
  23. package/dist/observability/events.d.ts +43 -0
  24. package/dist/observability/events.js.map +1 -1
  25. package/dist/plugin/checkpoint-override.d.ts +7 -9
  26. package/dist/plugin/checkpoint-override.js +8 -14
  27. package/dist/plugin/checkpoint-override.js.map +1 -1
  28. package/dist/plugin/define-workflow.d.ts +33 -0
  29. package/dist/plugin/define-workflow.js +103 -0
  30. package/dist/plugin/define-workflow.js.map +1 -0
  31. package/dist/plugin/index.js +406 -26
  32. package/dist/plugin/index.js.map +1 -1
  33. package/dist/plugin/opencode-v2-executor.js +58 -46
  34. package/dist/plugin/opencode-v2-executor.js.map +1 -1
  35. package/dist/plugin/progress-board.d.ts +64 -0
  36. package/dist/plugin/progress-board.js +150 -0
  37. package/dist/plugin/progress-board.js.map +1 -0
  38. package/dist/plugin/progress-rpc.d.ts +390 -0
  39. package/dist/plugin/progress-rpc.js +318 -0
  40. package/dist/plugin/progress-rpc.js.map +1 -0
  41. package/dist/plugin/progress-view.d.ts +82 -0
  42. package/dist/plugin/progress-view.js +244 -0
  43. package/dist/plugin/progress-view.js.map +1 -0
  44. package/dist/plugin/run-sessions.d.ts +28 -0
  45. package/dist/plugin/run-sessions.js +46 -0
  46. package/dist/plugin/run-sessions.js.map +1 -0
  47. package/dist/plugin/tool-args.d.ts +15 -0
  48. package/dist/plugin/tool-args.js +28 -0
  49. package/dist/plugin/tool-args.js.map +1 -0
  50. package/dist/plugin/tui.d.ts +11 -4
  51. package/dist/plugin/tui.js +149 -5
  52. package/dist/plugin/tui.js.map +1 -1
  53. package/dist/plugin/workflow-control.d.ts +16 -0
  54. package/dist/plugin/workflow-control.js +85 -0
  55. package/dist/plugin/workflow-control.js.map +1 -0
  56. package/dist/plugin/workflow-schedule.d.ts +24 -0
  57. package/dist/plugin/workflow-schedule.js +97 -0
  58. package/dist/plugin/workflow-schedule.js.map +1 -0
  59. package/dist/quality/checkpoint.d.ts +5 -2
  60. package/dist/quality/checkpoint.js +11 -6
  61. package/dist/quality/checkpoint.js.map +1 -1
  62. package/dist/quality/verify.d.ts +21 -2
  63. package/dist/quality/verify.js +36 -14
  64. package/dist/quality/verify.js.map +1 -1
  65. package/dist/registry/definition.d.ts +12 -0
  66. package/dist/registry/definition.js.map +1 -1
  67. package/dist/registry/registry.d.ts +4 -0
  68. package/dist/registry/registry.js +20 -1
  69. package/dist/registry/registry.js.map +1 -1
  70. package/dist/registry/run-control.d.ts +27 -0
  71. package/dist/registry/run-control.js +51 -0
  72. package/dist/registry/run-control.js.map +1 -0
  73. package/dist/registry/runner.d.ts +29 -6
  74. package/dist/registry/runner.js +153 -35
  75. package/dist/registry/runner.js.map +1 -1
  76. package/dist/runtime/errors.d.ts +26 -0
  77. package/dist/runtime/errors.js +30 -0
  78. package/dist/runtime/errors.js.map +1 -1
  79. package/dist/runtime/executor.d.ts +22 -0
  80. package/dist/runtime/executor.js.map +1 -1
  81. package/dist/runtime/run-context.d.ts +44 -0
  82. package/dist/runtime/run-context.js +32 -0
  83. package/dist/runtime/run-context.js.map +1 -0
  84. package/dist/scheduler/cron.d.ts +29 -0
  85. package/dist/scheduler/cron.js +171 -0
  86. package/dist/scheduler/cron.js.map +1 -0
  87. package/dist/scheduler/service.d.ts +78 -0
  88. package/dist/scheduler/service.js +210 -0
  89. package/dist/scheduler/service.js.map +1 -0
  90. package/dist/scheduler/store.d.ts +26 -0
  91. package/dist/scheduler/store.js +94 -0
  92. package/dist/scheduler/store.js.map +1 -0
  93. package/dist/scheduler/types.d.ts +53 -0
  94. package/dist/scheduler/types.js +12 -0
  95. package/dist/scheduler/types.js.map +1 -0
  96. package/dist/state/journal.d.ts +23 -0
  97. package/dist/state/journal.js +2 -0
  98. package/dist/state/journal.js.map +1 -1
  99. package/dist/state/recorder.d.ts +67 -0
  100. package/dist/state/recorder.js +148 -2
  101. package/dist/state/recorder.js.map +1 -1
  102. package/dist/workflow/agent.d.ts +42 -1
  103. package/dist/workflow/agent.js +116 -6
  104. package/dist/workflow/agent.js.map +1 -1
  105. package/dist/workflow/judge-panel.d.ts +37 -0
  106. package/dist/workflow/judge-panel.js +66 -0
  107. package/dist/workflow/judge-panel.js.map +1 -0
  108. package/dist/workflow/pipeline.d.ts +21 -0
  109. package/dist/workflow/pipeline.js +71 -0
  110. package/dist/workflow/pipeline.js.map +1 -0
  111. package/dist/workflow/race.d.ts +16 -0
  112. package/dist/workflow/race.js +46 -0
  113. package/dist/workflow/race.js.map +1 -0
  114. package/dist/workflow/sequence.js +6 -0
  115. package/dist/workflow/sequence.js.map +1 -1
  116. package/dist/workflows/loader.d.ts +124 -0
  117. package/dist/workflows/loader.js +500 -0
  118. package/dist/workflows/loader.js.map +1 -0
  119. package/dist/workspace/ambient.d.ts +6 -4
  120. package/dist/workspace/ambient.js +10 -4
  121. package/dist/workspace/ambient.js.map +1 -1
  122. package/package.json +16 -6
  123. package/skills/workflow-authoring/SKILL.md +111 -0
  124. package/skills/workflow-optimize/SKILL.md +70 -0
  125. package/dist/workflows/index.d.ts +0 -19
  126. package/dist/workflows/index.js +0 -40
  127. package/dist/workflows/index.js.map +0 -1
@@ -0,0 +1,318 @@
1
+ /**
2
+ * Workflow Progress RPC 契约(P2-8,server 与 TUI 双形态共享)
3
+ *
4
+ * 流向:
5
+ * server RunJournal 状态转换 -> emitEvent("run.progress") -> ProgressBoard
6
+ * --events.emit--> rpc.agentic-workflow-progress.progress { run 快照 }
7
+ * TUI 面板:
8
+ * <--call-- rpc "snapshot" -> { runs: [...] }(面板打开时初始同步)
9
+ * --事件--> 实时更新(全量快照,无需增量对账)
10
+ *
11
+ * 快照小而可序列化(不含步骤 output——详情看 journal 文件)。
12
+ */
13
+ import { Rpc } from "@opencode/plugin/rpc";
14
+ /** run 快照 JSON Schema(event 载荷与 snapshot 方法输出条目共用) */
15
+ const runSnapshotSchema = {
16
+ type: "object",
17
+ properties: {
18
+ runId: { type: "string" },
19
+ workflow: {
20
+ type: "object",
21
+ properties: {
22
+ id: { type: "string" },
23
+ version: { type: "string" },
24
+ },
25
+ required: ["id", "version"],
26
+ additionalProperties: false,
27
+ },
28
+ status: { type: "string" },
29
+ startedAt: { type: "number" },
30
+ completedAt: { type: "number" },
31
+ failure: { type: "string" },
32
+ parentRunId: { type: "string" },
33
+ depth: { type: "number" },
34
+ steps: {
35
+ type: "array",
36
+ items: {
37
+ type: "object",
38
+ properties: {
39
+ index: { type: "number" },
40
+ name: { type: "string" },
41
+ status: { type: "string" },
42
+ startedAt: { type: "number" },
43
+ completedAt: { type: "number" },
44
+ },
45
+ required: ["index", "status"],
46
+ },
47
+ },
48
+ },
49
+ required: ["runId", "workflow", "status", "startedAt", "steps"],
50
+ };
51
+ /** run 详情 JSON Schema(detail 方法输出;步骤载荷为预览化字符串) */
52
+ const runDetailSchema = {
53
+ type: "object",
54
+ properties: {
55
+ runId: { type: "string" },
56
+ workflow: {
57
+ type: "object",
58
+ properties: {
59
+ id: { type: "string" },
60
+ version: { type: "string" },
61
+ },
62
+ required: ["id", "version"],
63
+ additionalProperties: false,
64
+ },
65
+ status: { type: "string" },
66
+ startedAt: { type: "number" },
67
+ completedAt: { type: "number" },
68
+ failure: { type: "string" },
69
+ parentRunId: { type: "string" },
70
+ depth: { type: "number" },
71
+ args: { type: "string" },
72
+ steps: {
73
+ type: "array",
74
+ items: {
75
+ type: "object",
76
+ properties: {
77
+ index: { type: "number" },
78
+ name: { type: "string" },
79
+ status: { type: "string" },
80
+ startedAt: { type: "number" },
81
+ completedAt: { type: "number" },
82
+ input: { type: "string" },
83
+ output: { type: "string" },
84
+ error: { type: "string" },
85
+ usage: {
86
+ type: "object",
87
+ properties: {
88
+ input: { type: "number" },
89
+ output: { type: "number" },
90
+ reasoning: { type: "number" },
91
+ },
92
+ required: ["input", "output", "reasoning"],
93
+ additionalProperties: false,
94
+ },
95
+ model: { type: "string" },
96
+ sessionIDs: { type: "array", items: { type: "string" } },
97
+ },
98
+ required: ["index", "status"],
99
+ },
100
+ },
101
+ },
102
+ required: ["runId", "workflow", "status", "startedAt", "steps"],
103
+ };
104
+ export const ProgressRpc = Rpc.define({
105
+ id: "agentic-workflow-progress",
106
+ methods: {
107
+ /** TUI -> server:拉取当前 board(面板打开时初始同步) */
108
+ snapshot: {
109
+ input: {
110
+ type: "object",
111
+ properties: {},
112
+ additionalProperties: false,
113
+ },
114
+ output: {
115
+ type: "object",
116
+ properties: {
117
+ runs: { type: "array", items: runSnapshotSchema },
118
+ },
119
+ required: ["runs"],
120
+ additionalProperties: false,
121
+ },
122
+ },
123
+ /** TUI -> server:单个 run 的节点详情(journal 单读,载荷为预览) */
124
+ detail: {
125
+ input: {
126
+ type: "object",
127
+ properties: {
128
+ runId: { type: "string" },
129
+ },
130
+ required: ["runId"],
131
+ additionalProperties: false,
132
+ },
133
+ output: {
134
+ type: "object",
135
+ properties: {
136
+ run: { oneOf: [runDetailSchema, { type: "null" }] },
137
+ },
138
+ required: ["run"],
139
+ additionalProperties: false,
140
+ },
141
+ },
142
+ /**
143
+ * TUI -> server:Open Session 回放——按 runId + 步骤名取该步骤子会话的
144
+ * 完整对话(文本预览)。index 选多会话步骤(pipeline)的第几个,缺省最后。
145
+ */
146
+ session: {
147
+ input: {
148
+ type: "object",
149
+ properties: {
150
+ runId: { type: "string" },
151
+ step: { type: "string" },
152
+ index: { type: "number" },
153
+ },
154
+ required: ["runId", "step"],
155
+ additionalProperties: false,
156
+ },
157
+ output: {
158
+ type: "object",
159
+ properties: {
160
+ session: {
161
+ oneOf: [
162
+ {
163
+ type: "object",
164
+ properties: {
165
+ sessionID: { type: "string" },
166
+ step: { type: "string" },
167
+ messages: {
168
+ type: "array",
169
+ items: {
170
+ type: "object",
171
+ properties: {
172
+ type: { type: "string" },
173
+ text: { type: "string" },
174
+ },
175
+ required: ["type", "text"],
176
+ additionalProperties: false,
177
+ },
178
+ },
179
+ },
180
+ required: ["sessionID", "messages"],
181
+ additionalProperties: false,
182
+ },
183
+ { type: "null" },
184
+ ],
185
+ },
186
+ },
187
+ required: ["session"],
188
+ additionalProperties: false,
189
+ },
190
+ },
191
+ },
192
+ events: {
193
+ /** server -> TUI:run 全量快照 */
194
+ progress: { schema: runSnapshotSchema },
195
+ },
196
+ });
197
+ /** TUI 订阅用事件名(字面量类型;与 ProgressRpc.id 的一致性由单测保证) */
198
+ export const PROGRESS_EVENT = "rpc.agentic-workflow-progress.progress";
199
+ /** 收窄事件/方法载荷为快照(事件 data 为 unknown 形状);不合法返回 undefined */
200
+ export function parseRunSnapshot(data) {
201
+ if (typeof data !== "object" || data === null)
202
+ return undefined;
203
+ const record = data;
204
+ if (typeof record.runId !== "string")
205
+ return undefined;
206
+ if (typeof record.status !== "string")
207
+ return undefined;
208
+ if (typeof record.startedAt !== "number")
209
+ return undefined;
210
+ if (!Array.isArray(record.steps))
211
+ return undefined;
212
+ const workflow = record.workflow;
213
+ if (typeof workflow !== "object" ||
214
+ workflow === null ||
215
+ typeof workflow.id !== "string" ||
216
+ typeof workflow.version !== "string") {
217
+ return undefined;
218
+ }
219
+ for (const step of record.steps) {
220
+ if (typeof step !== "object" || step === null)
221
+ return undefined;
222
+ const s = step;
223
+ if (typeof s.index !== "number" || typeof s.status !== "string")
224
+ return undefined;
225
+ }
226
+ return data;
227
+ }
228
+ /** 收窄 snapshot 方法输出为快照数组;不合法整体丢弃(面板回退到空态) */
229
+ export function parseRunSnapshotList(data) {
230
+ if (typeof data !== "object" || data === null)
231
+ return [];
232
+ const runs = data.runs;
233
+ if (!Array.isArray(runs))
234
+ return [];
235
+ const parsed = runs.map(parseRunSnapshot).filter((s) => s !== undefined);
236
+ return parsed.filter((s) => s !== undefined);
237
+ }
238
+ /** 收窄 detail 方法入参为 runId;不合法(缺/非串)返回 undefined */
239
+ export function parseRunDetailRequest(data) {
240
+ if (typeof data !== "object" || data === null)
241
+ return undefined;
242
+ const runId = data.runId;
243
+ return typeof runId === "string" ? runId : undefined;
244
+ }
245
+ /** 收窄 detail 方法输出为详情;null(run 不存在/无 journal)或不合法返回 undefined */
246
+ export function parseRunDetail(data) {
247
+ if (typeof data !== "object" || data === null)
248
+ return undefined;
249
+ const record = data;
250
+ if (record.run === null)
251
+ return undefined;
252
+ const run = record.run;
253
+ if (typeof run !== "object" || run === null)
254
+ return undefined;
255
+ const detail = run;
256
+ if (typeof detail.runId !== "string")
257
+ return undefined;
258
+ if (typeof detail.status !== "string")
259
+ return undefined;
260
+ if (typeof detail.startedAt !== "number")
261
+ return undefined;
262
+ if (!Array.isArray(detail.steps))
263
+ return undefined;
264
+ const workflow = detail.workflow;
265
+ if (typeof workflow !== "object" ||
266
+ workflow === null ||
267
+ typeof workflow.id !== "string" ||
268
+ typeof workflow.version !== "string") {
269
+ return undefined;
270
+ }
271
+ for (const step of detail.steps) {
272
+ if (typeof step !== "object" || step === null)
273
+ return undefined;
274
+ const s = step;
275
+ if (typeof s.index !== "number" || typeof s.status !== "string")
276
+ return undefined;
277
+ }
278
+ return run;
279
+ }
280
+ /** 收窄 session 方法入参;不合法返回 undefined */
281
+ export function parseSessionReplayRequest(data) {
282
+ if (typeof data !== "object" || data === null)
283
+ return undefined;
284
+ const req = data;
285
+ if (typeof req.runId !== "string" || typeof req.step !== "string")
286
+ return undefined;
287
+ return {
288
+ runId: req.runId,
289
+ step: req.step,
290
+ ...(typeof req.index === "number" ? { index: req.index } : {}),
291
+ };
292
+ }
293
+ /** 收窄 session 方法输出;不合法返回 undefined */
294
+ export function parseSessionReplay(data) {
295
+ if (typeof data !== "object" || data === null)
296
+ return undefined;
297
+ const out = data;
298
+ if (typeof out.session !== "object" || out.session === null)
299
+ return undefined;
300
+ const session = out.session;
301
+ if (typeof session.sessionID !== "string" || !Array.isArray(session.messages))
302
+ return undefined;
303
+ const messages = [];
304
+ for (const message of session.messages) {
305
+ if (typeof message !== "object" || message === null)
306
+ return undefined;
307
+ const m = message;
308
+ if (typeof m.type !== "string" || typeof m.text !== "string")
309
+ return undefined;
310
+ messages.push({ type: m.type, text: m.text });
311
+ }
312
+ return {
313
+ sessionID: session.sessionID,
314
+ ...(typeof session.step === "string" ? { step: session.step } : {}),
315
+ messages,
316
+ };
317
+ }
318
+ //# sourceMappingURL=progress-rpc.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"progress-rpc.js","sourceRoot":"","sources":["../../src/plugin/progress-rpc.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,82 @@
1
+ /**
2
+ * 进度面板视图模型(P2-8)
3
+ *
4
+ * 纯函数层:RunProgressSnapshot -> 展示行。无 solid 依赖——
5
+ * TUI 组件消费,单测直接断言(渲染逻辑的最小不可测面只剩 JSX 摆放)。
6
+ */
7
+ import type { RunProgressSnapshot } from "../observability/events.js";
8
+ import type { RunDetail } from "../state/recorder.js";
9
+ export declare function runGlyph(status: string): string;
10
+ export declare function stepGlyph(status: string): string;
11
+ /** 毫秒 -> 人读时长(0s / 12.3s / 1m02s / 1h03m) */
12
+ export declare function formatDuration(ms: number): string;
13
+ export interface StepViewModel {
14
+ label: string;
15
+ glyph: string;
16
+ status: string;
17
+ duration?: string;
18
+ }
19
+ export interface RunViewModel {
20
+ title: string;
21
+ glyph: string;
22
+ status: string;
23
+ /** 完成用 completedAt-startedAt;进行中用 now-startedAt(随事件刷新) */
24
+ duration: string;
25
+ failure?: string;
26
+ steps: StepViewModel[];
27
+ }
28
+ /** 单 run -> 视图模型(now 注入,测试可冻结时间) */
29
+ export declare function toRunViewModel(run: RunProgressSnapshot, now?: number): RunViewModel;
30
+ export interface PanelLinesOptions {
31
+ /** 行宽上限(截断加 …);默认不截断 */
32
+ maxWidth?: number;
33
+ /** 展开全步骤树的 run 数(最新的在前);默认 1(最新 run 展开) */
34
+ expandedRuns?: number;
35
+ }
36
+ /**
37
+ * 整板 -> 展示行(最新顶层 run 展开步骤树,其余收为一行摘要;
38
+ * subflow 子 run 按 parentRunId 缩进挂在父 run 下,深度再加两格)。
39
+ * 面板组件逐行渲染;单测直接断言行内容。
40
+ */
41
+ export declare function renderPanelLines(runs: readonly RunProgressSnapshot[], now?: number, options?: PanelLinesOptions): string[];
42
+ /** TUI 侧详情缓存条目(runId + 预渲染行;key 仅供去重,不参与渲染) */
43
+ export interface DetailSection {
44
+ runId: string;
45
+ lines: string[];
46
+ }
47
+ /** 详情区行:缓存的详情属于板上最新 run 时输出(头行分隔),否则空 */
48
+ export declare function renderDetailSection(runs: readonly RunProgressSnapshot[], detail: DetailSection | undefined): string[];
49
+ /** TUI 侧会话回放缓存条目(runId@step 去重键 + 预渲染行) */
50
+ export interface SessionSection {
51
+ runId: string;
52
+ step: string;
53
+ lines: string[];
54
+ }
55
+ /** 会话回放区行:缓存属于板上最新 run 时输出(头行分隔),否则空 */
56
+ export declare function renderSessionSection(runs: readonly RunProgressSnapshot[], session: SessionSection | undefined): string[];
57
+ /**
58
+ * 回放载荷 -> 预渲染行:步骤头(步骤名 + 会话 ID)+ 逐消息折行块,
59
+ * 总行数预算 maxLines(超出尾缀 …)。纯函数,单测覆盖。
60
+ */
61
+ export declare function renderSessionLines(replay: {
62
+ sessionID: string;
63
+ step?: string;
64
+ messages: ReadonlyArray<{
65
+ type: string;
66
+ text: string;
67
+ }>;
68
+ }, maxWidth?: number, maxLines?: number): string[];
69
+ /** token 数 -> 紧凑人读(123 / 1.2k / 15.3k) */
70
+ export declare function formatTokens(n: number): string;
71
+ export interface DetailLinesOptions {
72
+ /** 行宽上限(截断加 …);默认不截断 */
73
+ maxWidth?: number;
74
+ /** 每段预览最多折行数(默认 3) */
75
+ maxPreviewLines?: number;
76
+ }
77
+ /**
78
+ * run 详情 -> 展示行(P2-8b 节点详情):头行(workflow@version · 状态 · 时长)、
79
+ * runId/lineage、args 预览、逐步骤(状态 + 时长 + 输出/错误预览折行)。
80
+ * 纯函数,TUI 组件逐行渲染;单测直接断言行内容。
81
+ */
82
+ export declare function renderDetailLines(detail: RunDetail, now?: number, options?: DetailLinesOptions): string[];
@@ -0,0 +1,244 @@
1
+ /**
2
+ * 进度面板视图模型(P2-8)
3
+ *
4
+ * 纯函数层:RunProgressSnapshot -> 展示行。无 solid 依赖——
5
+ * TUI 组件消费,单测直接断言(渲染逻辑的最小不可测面只剩 JSX 摆放)。
6
+ */
7
+ const RUN_GLYPHS = {
8
+ running: "▶",
9
+ completed: "✓",
10
+ failed: "✗",
11
+ aborted: "⏹",
12
+ };
13
+ const STEP_GLYPHS = {
14
+ pending: "·",
15
+ running: "▶",
16
+ completed: "✓",
17
+ failed: "✗",
18
+ skipped: "–",
19
+ };
20
+ export function runGlyph(status) {
21
+ return RUN_GLYPHS[status] ?? "?";
22
+ }
23
+ export function stepGlyph(status) {
24
+ return STEP_GLYPHS[status] ?? "?";
25
+ }
26
+ /** 毫秒 -> 人读时长(0s / 12.3s / 1m02s / 1h03m) */
27
+ export function formatDuration(ms) {
28
+ if (!Number.isFinite(ms) || ms <= 0)
29
+ return "0s";
30
+ if (ms < 60_000)
31
+ return `${(ms / 1000).toFixed(1)}s`;
32
+ const totalSeconds = Math.floor(ms / 1000);
33
+ const minutes = Math.floor(totalSeconds / 60);
34
+ const seconds = totalSeconds % 60;
35
+ if (minutes < 60)
36
+ return `${minutes}m${String(seconds).padStart(2, "0")}s`;
37
+ const hours = Math.floor(minutes / 60);
38
+ return `${hours}h${String(minutes % 60).padStart(2, "0")}m`;
39
+ }
40
+ /** 单 run -> 视图模型(now 注入,测试可冻结时间) */
41
+ export function toRunViewModel(run, now = Date.now()) {
42
+ const end = run.completedAt ?? now;
43
+ const steps = run.steps.map((step) => {
44
+ const startedAt = step.startedAt;
45
+ const finishedAt = step.completedAt;
46
+ return {
47
+ label: step.name ?? `step ${step.index}`,
48
+ glyph: stepGlyph(step.status),
49
+ status: step.status,
50
+ ...(startedAt !== undefined
51
+ ? { duration: formatDuration((finishedAt ?? end) - startedAt) }
52
+ : {}),
53
+ };
54
+ });
55
+ return {
56
+ title: `${run.workflow.id}@${run.workflow.version}`,
57
+ glyph: runGlyph(run.status),
58
+ status: run.status,
59
+ duration: formatDuration(Math.max(0, end - run.startedAt)),
60
+ ...(run.failure !== undefined ? { failure: run.failure } : {}),
61
+ steps,
62
+ };
63
+ }
64
+ function truncate(line, maxWidth) {
65
+ if (maxWidth === undefined || line.length <= maxWidth)
66
+ return line;
67
+ return `${line.slice(0, Math.max(1, maxWidth - 1))}…`;
68
+ }
69
+ /**
70
+ * 整板 -> 展示行(最新顶层 run 展开步骤树,其余收为一行摘要;
71
+ * subflow 子 run 按 parentRunId 缩进挂在父 run 下,深度再加两格)。
72
+ * 面板组件逐行渲染;单测直接断言行内容。
73
+ */
74
+ export function renderPanelLines(runs, now = Date.now(), options) {
75
+ if (runs.length === 0) {
76
+ return ["Agentic Workflow", "(no runs yet — start one with workflow_start)"];
77
+ }
78
+ // P2-9 lineage:父子分组(父不在板上的孤儿按顶层渲染)
79
+ const byId = new Set(runs.map((r) => r.runId));
80
+ const childrenOf = new Map();
81
+ const topLevels = [];
82
+ for (const run of runs) {
83
+ if (run.parentRunId !== undefined && byId.has(run.parentRunId)) {
84
+ const list = childrenOf.get(run.parentRunId) ?? [];
85
+ list.push(run);
86
+ childrenOf.set(run.parentRunId, list);
87
+ }
88
+ else {
89
+ topLevels.push(run);
90
+ }
91
+ }
92
+ const expanded = options?.expandedRuns ?? 1;
93
+ const lines = ["Agentic Workflow"];
94
+ /** 递归渲染一棵 run 树:本体 + 其 subflow 子孙(缩进随深度) */
95
+ const emitRun = (run, topLevelIndex) => {
96
+ const vm = toRunViewModel(run, now);
97
+ const isTop = run.parentRunId === undefined;
98
+ if (isTop) {
99
+ lines.push(truncate(`${vm.glyph} ${vm.title} ${vm.duration}`, options?.maxWidth));
100
+ if (topLevelIndex < expanded) {
101
+ for (const step of vm.steps) {
102
+ const duration = step.duration ? ` ${step.duration}` : "";
103
+ lines.push(truncate(` ${step.glyph} ${step.label}${duration}`, options?.maxWidth));
104
+ }
105
+ if (vm.failure) {
106
+ lines.push(truncate(` ↳ ${vm.failure}`, options?.maxWidth));
107
+ }
108
+ }
109
+ }
110
+ else {
111
+ const indent = " ".repeat(Math.min(run.depth ?? 1, 3));
112
+ const lineage = run.status === "running" ? " ⇢ subflow" : " · subflow";
113
+ lines.push(truncate(`${indent}↳ ${vm.glyph} ${vm.title} ${vm.duration}${lineage}`, options?.maxWidth));
114
+ if (vm.failure) {
115
+ lines.push(truncate(`${indent} ↳ ${vm.failure}`, options?.maxWidth));
116
+ }
117
+ }
118
+ for (const child of childrenOf.get(run.runId) ?? []) {
119
+ emitRun(child, topLevelIndex);
120
+ }
121
+ };
122
+ topLevels.forEach((run, i) => emitRun(run, i));
123
+ return lines;
124
+ }
125
+ /** 详情区行:缓存的详情属于板上最新 run 时输出(头行分隔),否则空 */
126
+ export function renderDetailSection(runs, detail) {
127
+ const newest = runs[0];
128
+ if (!newest || !detail || detail.runId !== newest.runId || detail.lines.length === 0) {
129
+ return [];
130
+ }
131
+ return ["── detail", ...detail.lines];
132
+ }
133
+ /** 会话回放区行:缓存属于板上最新 run 时输出(头行分隔),否则空 */
134
+ export function renderSessionSection(runs, session) {
135
+ const newest = runs[0];
136
+ if (!newest || !session || session.runId !== newest.runId || session.lines.length === 0) {
137
+ return [];
138
+ }
139
+ return ["── session", ...session.lines];
140
+ }
141
+ /** 消息类型的行前缀(与面板既有图标语言一致:❯ 提问 / · 回答 / ↳ 其他) */
142
+ function sessionMessagePrefix(type) {
143
+ if (type === "user")
144
+ return "❯ ";
145
+ if (type === "assistant")
146
+ return "· ";
147
+ return "↳ ";
148
+ }
149
+ /**
150
+ * 回放载荷 -> 预渲染行:步骤头(步骤名 + 会话 ID)+ 逐消息折行块,
151
+ * 总行数预算 maxLines(超出尾缀 …)。纯函数,单测覆盖。
152
+ */
153
+ export function renderSessionLines(replay, maxWidth, maxLines = 24) {
154
+ const header = `${replay.step !== undefined ? `${replay.step} · ` : ""}${replay.sessionID}`;
155
+ const lines = [header];
156
+ for (const message of replay.messages) {
157
+ if (lines.length >= maxLines)
158
+ break;
159
+ const prefix = sessionMessagePrefix(message.type);
160
+ const wrapped = wrapPreview(message.text, maxWidth, 3);
161
+ for (let i = 0; i < wrapped.length && lines.length < maxLines; i++) {
162
+ lines.push(i === 0 ? `${prefix}${wrapped[i]}` : ` ${wrapped[i]}`);
163
+ }
164
+ }
165
+ if (lines.length >= maxLines)
166
+ lines.push("…");
167
+ return lines;
168
+ }
169
+ /** 单段预览 -> 折行块(宽度不定时按单行原样;超出行数截断加 …) */
170
+ function wrapPreview(text, maxWidth, maxLines) {
171
+ if (maxWidth === undefined || maxWidth < 8)
172
+ return [text];
173
+ const chunks = [];
174
+ for (let i = 0; i < text.length && chunks.length < maxLines; i += maxWidth) {
175
+ chunks.push(text.slice(i, i + maxWidth));
176
+ }
177
+ if (text.length > maxLines * maxWidth) {
178
+ const last = chunks[chunks.length - 1] ?? "";
179
+ chunks[chunks.length - 1] = `${last.slice(0, Math.max(1, maxWidth - 1))}…`;
180
+ }
181
+ return chunks;
182
+ }
183
+ /** token 数 -> 紧凑人读(123 / 1.2k / 15.3k) */
184
+ export function formatTokens(n) {
185
+ if (!Number.isFinite(n) || n < 1000)
186
+ return String(Math.max(0, Math.round(n)));
187
+ return `${(n / 1000).toFixed(1)}k`;
188
+ }
189
+ /**
190
+ * run 详情 -> 展示行(P2-8b 节点详情):头行(workflow@version · 状态 · 时长)、
191
+ * runId/lineage、args 预览、逐步骤(状态 + 时长 + 输出/错误预览折行)。
192
+ * 纯函数,TUI 组件逐行渲染;单测直接断言行内容。
193
+ */
194
+ export function renderDetailLines(detail, now = Date.now(), options) {
195
+ const maxWidth = options?.maxWidth;
196
+ const maxPreview = options?.maxPreviewLines ?? 3;
197
+ const duration = detail.completedAt !== undefined
198
+ ? formatDuration(Math.max(0, detail.completedAt - detail.startedAt))
199
+ : formatDuration(Math.max(0, now - detail.startedAt));
200
+ const lines = [
201
+ truncate(`${runGlyph(detail.status)} ${detail.workflow.id}@${detail.workflow.version} · ${detail.status} · ${duration}`, maxWidth),
202
+ ];
203
+ const meta = [detail.runId];
204
+ if (detail.parentRunId !== undefined) {
205
+ meta.push(`parent ${detail.parentRunId}`, `depth ${detail.depth ?? "?"}`);
206
+ }
207
+ lines.push(truncate(` ${meta.join(" · ")}`, maxWidth));
208
+ if (detail.args !== undefined && detail.args !== "") {
209
+ lines.push(truncate(` args ${detail.args}`, maxWidth));
210
+ }
211
+ for (const step of detail.steps) {
212
+ const stepDuration = step.startedAt !== undefined
213
+ ? ` ${formatDuration(Math.max(0, (step.completedAt ?? now) - step.startedAt))}`
214
+ : "";
215
+ // P2-8b 元数据后缀:模型 + token 合计(input+output+reasoning;reasoning
216
+ // 已含于 output 时宿主报 0,不会重复计)
217
+ const meta = [];
218
+ if (step.usage !== undefined) {
219
+ const total = step.usage.input + step.usage.output + step.usage.reasoning;
220
+ meta.push(`${formatTokens(total)} tok`);
221
+ }
222
+ if (step.model !== undefined)
223
+ meta.push(step.model);
224
+ const metaSuffix = meta.length > 0 ? ` · ${meta.join(" · ")}` : "";
225
+ lines.push(truncate(` ${stepGlyph(step.status)} ${step.name ?? `step ${step.index}`}${stepDuration}${metaSuffix}`, maxWidth));
226
+ // 预览折行宽度扣除缩进,保证整行不超 maxWidth(宽度不定时不折)
227
+ const previewWidth = maxWidth === undefined ? undefined : Math.max(8, maxWidth - 4);
228
+ if (step.error !== undefined && step.error !== "") {
229
+ for (const line of wrapPreview(`✗ ${step.error}`, previewWidth, maxPreview)) {
230
+ lines.push(` ${line}`);
231
+ }
232
+ }
233
+ else if (step.output !== undefined && step.output !== "") {
234
+ for (const line of wrapPreview(`→ ${step.output}`, previewWidth, maxPreview)) {
235
+ lines.push(` ${line}`);
236
+ }
237
+ }
238
+ }
239
+ if (detail.failure !== undefined && detail.failure !== "") {
240
+ lines.push(truncate(` ↳ ${detail.failure}`, maxWidth));
241
+ }
242
+ return lines;
243
+ }
244
+ //# sourceMappingURL=progress-view.js.map