@unifan/pi-unifan-zh 1.0.35 → 1.0.36
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.
|
@@ -1,52 +1,104 @@
|
|
|
1
1
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { detectWorkflowState } from "./src/tools/workflow-state.js";
|
|
5
|
-
import { executeSessionCheckpoint } from "./src/tools/session-checkpoint.js";
|
|
2
|
+
import type { ArtifactType } from "./src/tools/artifact-helper.js";
|
|
3
|
+
import type { WorkLoopDriver } from "./src/driver/work-loop-driver.js";
|
|
6
4
|
import { filterBashOutput } from "./src/filters/bash-output-filter.js";
|
|
7
5
|
import { filterReadOutput } from "./src/filters/read-output-filter.js";
|
|
8
|
-
import { WorkLoopDriver } from "./src/driver/work-loop-driver.js";
|
|
9
6
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
let workDriverInstance: WorkLoopDriver | null = null;
|
|
8
|
+
async function getWorkDriver(): Promise<WorkLoopDriver> {
|
|
9
|
+
if (!workDriverInstance) {
|
|
10
|
+
const { WorkLoopDriver: DriverClass } = await import("./src/driver/work-loop-driver.js");
|
|
11
|
+
workDriverInstance = new DriverClass();
|
|
12
|
+
}
|
|
13
|
+
return workDriverInstance;
|
|
14
|
+
}
|
|
13
15
|
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
),
|
|
25
|
-
topic: Type.Optional(Type.String({ description: "Topic or feature name for the artifact" })),
|
|
26
|
-
date: Type.Optional(Type.String({ description: "Date prefix formatted as YYYY-MM-DD" })),
|
|
27
|
-
ensureDir: Type.Optional(Type.Boolean({ description: "Whether to create directory if missing" })),
|
|
28
|
-
});
|
|
16
|
+
const workflowStateParams = {
|
|
17
|
+
type: "object",
|
|
18
|
+
required: ["repoRoot"],
|
|
19
|
+
properties: {
|
|
20
|
+
repoRoot: {
|
|
21
|
+
type: "string",
|
|
22
|
+
description: "Repository root path to scan for workflow artifacts",
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
} as any;
|
|
29
26
|
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
27
|
+
const artifactHelperParams = {
|
|
28
|
+
type: "object",
|
|
29
|
+
required: ["repoRoot", "artifactType"],
|
|
30
|
+
properties: {
|
|
31
|
+
repoRoot: {
|
|
32
|
+
type: "string",
|
|
33
|
+
description: "Repository root where workflow artifacts are stored",
|
|
34
|
+
},
|
|
35
|
+
artifactType: {
|
|
36
|
+
anyOf: [
|
|
37
|
+
{ type: "string", const: "brainstorm" },
|
|
38
|
+
{ type: "string", const: "plan" },
|
|
39
|
+
{ type: "string", const: "solution" },
|
|
40
|
+
{ type: "string", const: "checkpoint" },
|
|
41
|
+
],
|
|
42
|
+
description: "Target artifact category",
|
|
43
|
+
},
|
|
44
|
+
topic: {
|
|
45
|
+
type: "string",
|
|
46
|
+
description: "Topic or feature name for the artifact",
|
|
47
|
+
},
|
|
48
|
+
date: {
|
|
49
|
+
type: "string",
|
|
50
|
+
description: "Date prefix formatted as YYYY-MM-DD",
|
|
51
|
+
},
|
|
52
|
+
ensureDir: {
|
|
53
|
+
type: "boolean",
|
|
54
|
+
description: "Whether to create directory if missing",
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
} as any;
|
|
58
|
+
|
|
59
|
+
const sessionCheckpointParams = {
|
|
60
|
+
type: "object",
|
|
61
|
+
required: ["operation", "repoRoot"],
|
|
62
|
+
properties: {
|
|
63
|
+
operation: {
|
|
64
|
+
anyOf: [
|
|
65
|
+
{ type: "string", const: "save" },
|
|
66
|
+
{ type: "string", const: "load" },
|
|
67
|
+
{ type: "string", const: "list" },
|
|
68
|
+
{ type: "string", const: "fail" },
|
|
69
|
+
{ type: "string", const: "retry" },
|
|
70
|
+
],
|
|
71
|
+
description: "Checkpoint action to execute",
|
|
72
|
+
},
|
|
73
|
+
repoRoot: {
|
|
74
|
+
type: "string",
|
|
75
|
+
description: "Repository root path",
|
|
76
|
+
},
|
|
77
|
+
planPath: {
|
|
78
|
+
type: "string",
|
|
79
|
+
description: "Path to the plan markdown artifact",
|
|
80
|
+
},
|
|
81
|
+
planSlug: {
|
|
82
|
+
type: "string",
|
|
83
|
+
description: "Slug identifier for the execution plan",
|
|
84
|
+
},
|
|
85
|
+
completedUnits: {
|
|
86
|
+
type: "array",
|
|
87
|
+
items: {
|
|
88
|
+
type: "string",
|
|
89
|
+
},
|
|
90
|
+
description: "List of completed unit names",
|
|
91
|
+
},
|
|
92
|
+
failedUnit: {
|
|
93
|
+
type: "string",
|
|
94
|
+
description: "Unit name that encountered a failure",
|
|
95
|
+
},
|
|
96
|
+
error: {
|
|
97
|
+
type: "string",
|
|
98
|
+
description: "Error description or failure details",
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
} as any;
|
|
50
102
|
|
|
51
103
|
export default function workflowExtension(pi: ExtensionAPI) {
|
|
52
104
|
// 1. Register workflow_state tool (Core engine for 00-next)
|
|
@@ -56,7 +108,8 @@ export default function workflowExtension(pi: ExtensionAPI) {
|
|
|
56
108
|
description:
|
|
57
109
|
"Scan repository artifacts (brainstorms, plans, checkpoints, solutions) and determine current stage and recommended next skill.",
|
|
58
110
|
parameters: workflowStateParams,
|
|
59
|
-
async execute(_toolCallId, params) {
|
|
111
|
+
async execute(_toolCallId, params: any) {
|
|
112
|
+
const { detectWorkflowState } = await import("./src/tools/workflow-state.js");
|
|
60
113
|
const result = await detectWorkflowState(params.repoRoot);
|
|
61
114
|
return {
|
|
62
115
|
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
@@ -72,7 +125,8 @@ export default function workflowExtension(pi: ExtensionAPI) {
|
|
|
72
125
|
description:
|
|
73
126
|
"Resolve and optionally create standard Compound Engineering artifact paths under docs/ or .context/.",
|
|
74
127
|
parameters: artifactHelperParams,
|
|
75
|
-
async execute(_toolCallId, params) {
|
|
128
|
+
async execute(_toolCallId, params: any) {
|
|
129
|
+
const { resolveArtifactPath } = await import("./src/tools/artifact-helper.js");
|
|
76
130
|
const result = await resolveArtifactPath({
|
|
77
131
|
repoRoot: params.repoRoot,
|
|
78
132
|
artifactType: params.artifactType as ArtifactType,
|
|
@@ -94,7 +148,8 @@ export default function workflowExtension(pi: ExtensionAPI) {
|
|
|
94
148
|
description:
|
|
95
149
|
"Manage plan execution checkpoints: save completed units, load breakpoints, record errors, and retry failed units.",
|
|
96
150
|
parameters: sessionCheckpointParams,
|
|
97
|
-
async execute(_toolCallId, params) {
|
|
151
|
+
async execute(_toolCallId, params: any) {
|
|
152
|
+
const { executeSessionCheckpoint } = await import("./src/tools/session-checkpoint.js");
|
|
98
153
|
const result = await executeSessionCheckpoint({
|
|
99
154
|
operation: params.operation,
|
|
100
155
|
repoRoot: params.repoRoot,
|
|
@@ -189,8 +244,10 @@ export default function workflowExtension(pi: ExtensionAPI) {
|
|
|
189
244
|
pi.registerCommand("workflow", {
|
|
190
245
|
description: "查看当前项目的复合工程流状态与下一步推荐技能",
|
|
191
246
|
async handler(_args, ctx) {
|
|
247
|
+
const { detectWorkflowState } = await import("./src/tools/workflow-state.js");
|
|
192
248
|
const repoRoot = ctx.cwd || process.cwd();
|
|
193
249
|
const state = await detectWorkflowState(repoRoot);
|
|
250
|
+
const workDriver = await getWorkDriver();
|
|
194
251
|
const workStatus = workDriver.getStatus();
|
|
195
252
|
|
|
196
253
|
const msg = [
|
|
@@ -218,8 +275,6 @@ export default function workflowExtension(pi: ExtensionAPI) {
|
|
|
218
275
|
});
|
|
219
276
|
|
|
220
277
|
// 7. 03-work 原生自主循环驱动引擎 (无须额外命令,直接在 03-work 中原生生效)
|
|
221
|
-
const workDriver = new WorkLoopDriver();
|
|
222
|
-
|
|
223
278
|
// 监听用户输入与技能启动:当调用 03-work 或请求恢复执行时,自动启动自主循环驱动
|
|
224
279
|
pi.on("before_agent_start", async (event, ctx) => {
|
|
225
280
|
const promptLower = event.prompt.toLowerCase();
|
|
@@ -233,7 +288,8 @@ export default function workflowExtension(pi: ExtensionAPI) {
|
|
|
233
288
|
promptLower.includes("resume") ||
|
|
234
289
|
promptLower.includes("干活")));
|
|
235
290
|
|
|
236
|
-
if (is03Work && !
|
|
291
|
+
if (is03Work && (!workDriverInstance || !workDriverInstance.getStatus().isActive)) {
|
|
292
|
+
const workDriver = await getWorkDriver();
|
|
237
293
|
workDriver.setRepoRoot(ctx.cwd || process.cwd());
|
|
238
294
|
const res = await workDriver.start();
|
|
239
295
|
if (res.success && res.status.isActive) {
|
|
@@ -250,10 +306,11 @@ export default function workflowExtension(pi: ExtensionAPI) {
|
|
|
250
306
|
pi.on("input", async (event, ctx) => {
|
|
251
307
|
const text = event.text.trim().toLowerCase();
|
|
252
308
|
if (
|
|
253
|
-
|
|
309
|
+
workDriverInstance &&
|
|
310
|
+
workDriverInstance.getStatus().isActive &&
|
|
254
311
|
(text === "暂停" || text === "停止" || text === "pause" || text === "stop")
|
|
255
312
|
) {
|
|
256
|
-
await
|
|
313
|
+
await workDriverInstance.pause("用户手动输入暂停");
|
|
257
314
|
ctx.ui?.setStatus?.("workflow", undefined);
|
|
258
315
|
ctx.ui?.notify?.(
|
|
259
316
|
"⏸️ 03-work 自主循环已暂停。随时输入“继续”或调用 /skill:03-work 即可恢复。",
|
|
@@ -266,10 +323,12 @@ export default function workflowExtension(pi: ExtensionAPI) {
|
|
|
266
323
|
|
|
267
324
|
// 核心事件循环:每个回合结束后,若仍有未完成单元,自动注入下一回合实现“不做完不停机”
|
|
268
325
|
pi.on("agent_settled", async (_event, ctx) => {
|
|
269
|
-
|
|
326
|
+
if (workDriverInstance && workDriverInstance.getStatus().isActive) {
|
|
327
|
+
await workDriverInstance.onAgentSettled(ctx, pi);
|
|
328
|
+
}
|
|
270
329
|
});
|
|
271
330
|
|
|
272
331
|
pi.on("session_shutdown", async () => {
|
|
273
|
-
|
|
332
|
+
workDriverInstance?.cancelTimer();
|
|
274
333
|
});
|
|
275
334
|
}
|