superun-ai-cli 0.1.10 → 0.1.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +128 -2
- package/dist/api/agent-command-api.js +11 -1
- package/dist/api/agent-command-api.js.map +1 -1
- package/dist/api/agent-query-api.d.ts +6 -0
- package/dist/api/agent-query-api.js +18 -0
- package/dist/api/agent-query-api.js.map +1 -1
- package/dist/commands/chat/index.js +4 -0
- package/dist/commands/chat/index.js.map +1 -1
- package/dist/commands/chat/message.d.ts +1 -1
- package/dist/commands/chat/message.js +64 -5
- package/dist/commands/chat/message.js.map +1 -1
- package/dist/commands/chat/review.d.ts +4 -0
- package/dist/commands/chat/review.js +7 -0
- package/dist/commands/chat/review.js.map +1 -0
- package/dist/commands/chat/send.js +4 -1
- package/dist/commands/chat/send.js.map +1 -1
- package/dist/commands/chat/style.js +1 -1
- package/dist/commands/chat/test.d.ts +4 -0
- package/dist/commands/chat/test.js +7 -0
- package/dist/commands/chat/test.js.map +1 -0
- package/dist/commands/chat/wait.js +8 -1
- package/dist/commands/chat/wait.js.map +1 -1
- package/dist/commands/system/update.d.ts +1 -1
- package/dist/commands/system/update.js +1 -1
- package/dist/commands/system/update.js.map +1 -1
- package/dist/contracts/cli-output.d.ts +23 -1
- package/dist/conversation/auto-test-tasks.d.ts +14 -0
- package/dist/conversation/auto-test-tasks.js +120 -0
- package/dist/conversation/auto-test-tasks.js.map +1 -0
- package/dist/conversation/auto-test.d.ts +14 -0
- package/dist/conversation/auto-test.js +25 -0
- package/dist/conversation/auto-test.js.map +1 -0
- package/dist/conversation/check-context.d.ts +20 -0
- package/dist/conversation/check-context.js +67 -0
- package/dist/conversation/check-context.js.map +1 -0
- package/dist/conversation/check-question-context.d.ts +4 -0
- package/dist/conversation/check-question-context.js +57 -0
- package/dist/conversation/check-question-context.js.map +1 -0
- package/dist/conversation/code-review.d.ts +14 -0
- package/dist/conversation/code-review.js +26 -0
- package/dist/conversation/code-review.js.map +1 -0
- package/dist/conversation/next-actions.d.ts +3 -1
- package/dist/conversation/next-actions.js +167 -10
- package/dist/conversation/next-actions.js.map +1 -1
- package/dist/conversation/round-selector.d.ts +2 -0
- package/dist/conversation/round-selector.js +9 -2
- package/dist/conversation/round-selector.js.map +1 -1
- package/dist/conversation/session-waiter.js +6 -4
- package/dist/conversation/session-waiter.js.map +1 -1
- package/dist/conversation/task-progress-reader.d.ts +9 -2
- package/dist/conversation/task-progress-reader.js +54 -3
- package/dist/conversation/task-progress-reader.js.map +1 -1
- package/dist/interactions/handlers/reply-universal-ask.js +25 -1
- package/dist/interactions/handlers/reply-universal-ask.js.map +1 -1
- package/dist/output/task-reminder.d.ts +12 -0
- package/dist/output/task-reminder.js +35 -0
- package/dist/output/task-reminder.js.map +1 -0
- package/dist/output/writer.d.ts +6 -1
- package/dist/output/writer.js +42 -1
- package/dist/output/writer.js.map +1 -1
- package/dist/runner.js +21 -1
- package/dist/runner.js.map +1 -1
- package/dist/runtime.d.ts +4 -0
- package/dist/runtime.js +219 -33
- package/dist/runtime.js.map +1 -1
- package/dist/update/version-gate.js +43 -56
- package/dist/update/version-gate.js.map +1 -1
- package/package.json +1 -1
- package/dist/update/update-lock.d.ts +0 -1
- package/dist/update/update-lock.js +0 -57
- package/dist/update/update-lock.js.map +0 -1
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/** 任务进行中的通用定时提醒,由顶层输出管理生命周期。@author xiuyu.yi */
|
|
2
|
+
import { randomUUID } from 'node:crypto';
|
|
3
|
+
export class TaskReminder {
|
|
4
|
+
emit;
|
|
5
|
+
timer;
|
|
6
|
+
constructor(emit) {
|
|
7
|
+
this.emit = emit;
|
|
8
|
+
}
|
|
9
|
+
start() {
|
|
10
|
+
if (this.timer)
|
|
11
|
+
return;
|
|
12
|
+
const taskId = randomUUID();
|
|
13
|
+
let sequence = 0;
|
|
14
|
+
this.timer = setInterval(() => {
|
|
15
|
+
try {
|
|
16
|
+
this.emit({
|
|
17
|
+
id: `${taskId}:${++sequence}`,
|
|
18
|
+
message: '任务还在进行中,可以去 superun.ai 查看详情。',
|
|
19
|
+
url: 'https://superun.ai',
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
// 提醒输出失败只停止提醒,不中断业务执行。
|
|
24
|
+
this.stop();
|
|
25
|
+
}
|
|
26
|
+
}, 5 * 60 * 1000);
|
|
27
|
+
this.timer.unref();
|
|
28
|
+
}
|
|
29
|
+
stop() {
|
|
30
|
+
if (this.timer)
|
|
31
|
+
clearInterval(this.timer);
|
|
32
|
+
this.timer = undefined;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=task-reminder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task-reminder.js","sourceRoot":"","sources":["../../src/output/task-reminder.ts"],"names":[],"mappings":"AAAA,gDAAgD;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAQzC,MAAM,OAAO,YAAY;IAGM;IAFrB,KAAK,CAAkC;IAE/C,YAA6B,IAA4C;QAA5C,SAAI,GAAJ,IAAI,CAAwC;IAAG,CAAC;IAE7E,KAAK;QACH,IAAI,IAAI,CAAC,KAAK;YAAE,OAAO;QACvB,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;QAC5B,IAAI,QAAQ,GAAG,CAAC,CAAC;QACjB,IAAI,CAAC,KAAK,GAAG,WAAW,CACtB,GAAG,EAAE;YACH,IAAI,CAAC;gBACH,IAAI,CAAC,IAAI,CAAC;oBACR,EAAE,EAAE,GAAG,MAAM,IAAI,EAAE,QAAQ,EAAE;oBAC7B,OAAO,EAAE,8BAA8B;oBACvC,GAAG,EAAE,oBAAoB;iBAC1B,CAAC,CAAC;YACL,CAAC;YAAC,MAAM,CAAC;gBACP,uBAAuB;gBACvB,IAAI,CAAC,IAAI,EAAE,CAAC;YACd,CAAC;QACH,CAAC,EACD,CAAC,GAAG,EAAE,GAAG,IAAI,CACd,CAAC;QACF,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;IAED,IAAI;QACF,IAAI,IAAI,CAAC,KAAK;YAAE,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC1C,IAAI,CAAC,KAAK,GAAG,SAAS,CAAC;IACzB,CAAC;CACF"}
|
package/dist/output/writer.d.ts
CHANGED
|
@@ -4,12 +4,17 @@ export declare class OutputWriter {
|
|
|
4
4
|
private readonly stderr;
|
|
5
5
|
private written;
|
|
6
6
|
private readonly secrets;
|
|
7
|
+
private readonly shownMessages;
|
|
8
|
+
private disposed;
|
|
9
|
+
private readonly taskReminder;
|
|
7
10
|
constructor(stdout?: (text: string) => void, stderr?: (text: string) => void);
|
|
8
11
|
registerSecret(secret: string): void;
|
|
9
12
|
redact(text: string): string;
|
|
10
13
|
log(text: string): void;
|
|
14
|
+
dispose(): void;
|
|
15
|
+
startTaskReminder(): void;
|
|
11
16
|
/** stderr 输出过程事件,stdout 仍只输出一次最终结果。 */
|
|
12
|
-
progress(data: Pick<CreationResult, 'sessionId' | 'messageId' | 'taskProgress'>): void;
|
|
17
|
+
progress(data: Pick<CreationResult, 'sessionId' | 'messageId' | 'taskProgress'> & Partial<Pick<CreationResult, 'autoTest' | 'codeReview' | 'messages'>>): void;
|
|
13
18
|
write(data: unknown): void;
|
|
14
19
|
fail(error: unknown): number;
|
|
15
20
|
private emit;
|
package/dist/output/writer.js
CHANGED
|
@@ -1,12 +1,23 @@
|
|
|
1
1
|
/** stdout 单结果输出,敏感值统一脱敏。@author xiuyu.yi */
|
|
2
2
|
import { SCHEMA_VERSION } from '../config/constants.js';
|
|
3
3
|
import { CliError, EXIT_CODES } from './exit-codes.js';
|
|
4
|
+
import { TaskReminder } from './task-reminder.js';
|
|
4
5
|
const SENSITIVE_KEY = /^(?:pat|token|access[-_]?token|private[-_]?token|gatewayToken|authorization|password|secret|secrets|secretValues|apiKey|api_key|rowKey|authToken)$/i;
|
|
5
6
|
export class OutputWriter {
|
|
6
7
|
stdout;
|
|
7
8
|
stderr;
|
|
8
9
|
written = false;
|
|
9
10
|
secrets = new Set();
|
|
11
|
+
shownMessages = new Map();
|
|
12
|
+
disposed = false;
|
|
13
|
+
taskReminder = new TaskReminder((data) => {
|
|
14
|
+
this.stderr(`${this.serialize({
|
|
15
|
+
schemaVersion: SCHEMA_VERSION,
|
|
16
|
+
event: 'task_reminder',
|
|
17
|
+
data,
|
|
18
|
+
instruction: '立即原样展示 data.message,将 superun.ai 链接到 data.url。同一 data.id 不重复展示;不同 ID 是每隔 5 分钟的再次提醒,文案相同也要展示。继续等待当前任务,不结束等待、不重新提交任务。',
|
|
19
|
+
})}\n`);
|
|
20
|
+
});
|
|
10
21
|
constructor(stdout = (text) => process.stdout.write(text), stderr = (text) => process.stderr.write(text)) {
|
|
11
22
|
this.stdout = stdout;
|
|
12
23
|
this.stderr = stderr;
|
|
@@ -24,8 +35,35 @@ export class OutputWriter {
|
|
|
24
35
|
log(text) {
|
|
25
36
|
this.stderr(`${this.redact(text)}\n`);
|
|
26
37
|
}
|
|
38
|
+
dispose() {
|
|
39
|
+
this.disposed = true;
|
|
40
|
+
this.taskReminder.stop();
|
|
41
|
+
}
|
|
42
|
+
startTaskReminder() {
|
|
43
|
+
if (!this.written && !this.disposed)
|
|
44
|
+
this.taskReminder.start();
|
|
45
|
+
}
|
|
27
46
|
/** stderr 输出过程事件,stdout 仍只输出一次最终结果。 */
|
|
28
47
|
progress(data) {
|
|
48
|
+
const checkName = data.codeReview ? '代码审查' : data.autoTest ? '自动测试' : undefined;
|
|
49
|
+
if (checkName) {
|
|
50
|
+
const messages = data.messages?.filter((message) => {
|
|
51
|
+
if (message.role !== 'assistant' || !message.text.trim())
|
|
52
|
+
return false;
|
|
53
|
+
const key = `${data.sessionId}:${message.id}`;
|
|
54
|
+
if (this.shownMessages.get(key) === message.text)
|
|
55
|
+
return false;
|
|
56
|
+
this.shownMessages.set(key, message.text);
|
|
57
|
+
return true;
|
|
58
|
+
}) ?? [];
|
|
59
|
+
if (messages.length)
|
|
60
|
+
this.stderr(`${this.serialize({
|
|
61
|
+
schemaVersion: SCHEMA_VERSION,
|
|
62
|
+
event: 'conversation_message',
|
|
63
|
+
data: { sessionId: data.sessionId, messageId: data.messageId, messages },
|
|
64
|
+
instruction: `及时展示这些${checkName}或修复的实际对话消息,保留发现的问题与修复前告知;同一消息 id 更新正文,不重复追加。该事件只是过程,继续等待当前命令,不表示${checkName}或修复已全部完成,不展示继续创作或上线运营菜单。`,
|
|
65
|
+
})}\n`);
|
|
66
|
+
}
|
|
29
67
|
if (!data.taskProgress)
|
|
30
68
|
return;
|
|
31
69
|
this.stderr(`${this.serialize({
|
|
@@ -36,7 +74,9 @@ export class OutputWriter {
|
|
|
36
74
|
messageId: data.messageId,
|
|
37
75
|
taskProgress: data.taskProgress,
|
|
38
76
|
},
|
|
39
|
-
instruction:
|
|
77
|
+
instruction: checkName
|
|
78
|
+
? `展示 data.taskProgress.markdown 中实际任务进度,不把功能步骤数当作${checkName}的问题数或通过数。及时展示 conversation_message 中发现的问题和修复说明。继续等待当前命令的最终结果,不重复提交任务、不展示操作菜单。`
|
|
79
|
+
: '每次查询都展示 data.taskProgress.markdown 中当前开发中的功能及步骤,即使 changed 为 false 也展示;不要从历史消息补回已完成的功能或旧步骤。支持原位更新时按卡片 id 更新,否则每次展示当前快照。不追加执行详情或工具次数。这是过程更新,继续等待当前命令的最终结果,不代表整个任务结束,不重复提交任务。',
|
|
40
80
|
})}\n`);
|
|
41
81
|
}
|
|
42
82
|
write(data) {
|
|
@@ -60,6 +100,7 @@ export class OutputWriter {
|
|
|
60
100
|
emit(value) {
|
|
61
101
|
if (this.written)
|
|
62
102
|
return;
|
|
103
|
+
this.dispose();
|
|
63
104
|
this.written = true;
|
|
64
105
|
this.stdout(`${this.serialize(value)}\n`);
|
|
65
106
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"writer.js","sourceRoot":"","sources":["../../src/output/writer.ts"],"names":[],"mappings":"AAAA,4CAA4C;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAExD,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"writer.js","sourceRoot":"","sources":["../../src/output/writer.ts"],"names":[],"mappings":"AAAA,4CAA4C;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAExD,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,MAAM,aAAa,GACjB,qJAAqJ,CAAC;AAExJ,MAAM,OAAO,YAAY;IAkBJ;IACA;IAlBX,OAAO,GAAG,KAAK,CAAC;IACP,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAC5B,aAAa,GAAG,IAAI,GAAG,EAAkB,CAAC;IACnD,QAAQ,GAAG,KAAK,CAAC;IACR,YAAY,GAAG,IAAI,YAAY,CAAC,CAAC,IAAI,EAAE,EAAE;QACxD,IAAI,CAAC,MAAM,CACT,GAAG,IAAI,CAAC,SAAS,CAAC;YAChB,aAAa,EAAE,cAAc;YAC7B,KAAK,EAAE,eAAe;YACtB,IAAI;YACJ,WAAW,EACT,qHAAqH;SACxH,CAAC,IAAI,CACP,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,YACmB,SAAiC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,EACrE,SAAiC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC;QADrE,WAAM,GAAN,MAAM,CAA+D;QACrE,WAAM,GAAN,MAAM,CAA+D;IACrF,CAAC;IAEJ,cAAc,CAAC,MAAc;QAC3B,IAAI,MAAM;YAAE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACvC,CAAC;IAED,MAAM,CAAC,IAAY;QACjB,IAAI,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,yBAAyB,EAAE,OAAO,CAAC,CAAC;QAC5D,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,OAAO;YAAE,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC3E,OAAO,IAAI,CAAC;IACd,CAAC;IAED,GAAG,CAAC,IAAY;QACd,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IAED,OAAO;QACL,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;IAC3B,CAAC;IAED,iBAAiB;QACf,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,QAAQ;YAAE,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC;IACjE,CAAC;IAED,uCAAuC;IACvC,QAAQ,CACN,IACuE;QAEvE,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;QAChF,IAAI,SAAS,EAAE,CAAC;YACd,MAAM,QAAQ,GACZ,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE;gBAChC,IAAI,OAAO,CAAC,IAAI,KAAK,WAAW,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE;oBAAE,OAAO,KAAK,CAAC;gBACvE,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,SAAS,IAAI,OAAO,CAAC,EAAE,EAAE,CAAC;gBAC9C,IAAI,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,OAAO,CAAC,IAAI;oBAAE,OAAO,KAAK,CAAC;gBAC/D,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;gBAC1C,OAAO,IAAI,CAAC;YACd,CAAC,CAAC,IAAI,EAAE,CAAC;YACX,IAAI,QAAQ,CAAC,MAAM;gBACjB,IAAI,CAAC,MAAM,CACT,GAAG,IAAI,CAAC,SAAS,CAAC;oBAChB,aAAa,EAAE,cAAc;oBAC7B,KAAK,EAAE,sBAAsB;oBAC7B,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,QAAQ,EAAE;oBACxE,WAAW,EAAE,SAAS,SAAS,mEAAmE,SAAS,0BAA0B;iBACtI,CAAC,IAAI,CACP,CAAC;QACN,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,YAAY;YAAE,OAAO;QAC/B,IAAI,CAAC,MAAM,CACT,GAAG,IAAI,CAAC,SAAS,CAAC;YAChB,aAAa,EAAE,cAAc;YAC7B,KAAK,EAAE,eAAe;YACtB,IAAI,EAAE;gBACJ,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,YAAY,EAAE,IAAI,CAAC,YAAY;aAChC;YACD,WAAW,EAAE,SAAS;gBACpB,CAAC,CAAC,kDAAkD,SAAS,+EAA+E;gBAC5I,CAAC,CAAC,6KAA6K;SAClL,CAAC,IAAI,CACP,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,IAAa;QACjB,IAAI,CAAC,IAAI,CAAC,EAAE,aAAa,EAAE,cAAc,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAC/D,CAAC;IAED,IAAI,CAAC,KAAc;QACjB,MAAM,OAAO,GACX,KAAK,YAAY,QAAQ;YACvB,CAAC,CAAC,KAAK;YACP,CAAC,CAAC,IAAI,QAAQ,CAAC,gBAAgB,EAAE,mBAAmB,CAAC,CAAC;QAC1D,IAAI,CAAC,IAAI,CAAC;YACR,aAAa,EAAE,cAAc;YAC7B,EAAE,EAAE,KAAK;YACT,KAAK,EAAE;gBACL,GAAG,OAAO,CAAC,OAAO;gBAClB,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,OAAO,EAAE,OAAO,CAAC,OAAO;aACzB;SACF,CAAC,CAAC;QACH,OAAO,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC,CAAC;IAEO,IAAI,CAAC,KAAc;QACzB,IAAI,IAAI,CAAC,OAAO;YAAE,OAAO;QACzB,IAAI,CAAC,OAAO,EAAE,CAAC;QACf,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC5C,CAAC;IAEO,SAAS,CAAC,KAAc;QAC9B,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC,GAAG,EAAE,IAAa,EAAE,EAAE,CAC9D,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAC1F,CAAC;QACF,OAAO,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IACjC,CAAC;CACF"}
|
package/dist/runner.js
CHANGED
|
@@ -14,7 +14,11 @@ class Reexecuted extends Error {
|
|
|
14
14
|
}
|
|
15
15
|
export async function runCli(argv, options = {}) {
|
|
16
16
|
const output = options.output ?? new OutputWriter(), controller = new AbortController();
|
|
17
|
-
|
|
17
|
+
let afterInput;
|
|
18
|
+
const interrupt = () => {
|
|
19
|
+
output.dispose();
|
|
20
|
+
controller.abort();
|
|
21
|
+
};
|
|
18
22
|
process.once('SIGINT', interrupt);
|
|
19
23
|
process.once('SIGTERM', interrupt);
|
|
20
24
|
const checkVersion = options.checkVersion ?? versionGate;
|
|
@@ -33,6 +37,19 @@ export async function runCli(argv, options = {}) {
|
|
|
33
37
|
},
|
|
34
38
|
update: () => versionGate(argv, output, true),
|
|
35
39
|
});
|
|
40
|
+
// 认证完成后,仅为持续等待的业务命令启用旁路提醒;不改动各命令的执行逻辑。
|
|
41
|
+
program.hook('preAction', (_root, command) => {
|
|
42
|
+
const commandOptions = command.opts();
|
|
43
|
+
if (!(commandOptions.wait === true || (command.name() === 'wait' && command.parent?.name() === 'chat')))
|
|
44
|
+
return;
|
|
45
|
+
// 等待用户从标准输入提供需求或回答时不计时,也不额外读取输入流。
|
|
46
|
+
if (commandOptions.input === '-' && !process.stdin.readableEnded) {
|
|
47
|
+
afterInput = () => output.startTaskReminder();
|
|
48
|
+
process.stdin.once('end', afterInput);
|
|
49
|
+
}
|
|
50
|
+
else
|
|
51
|
+
output.startTaskReminder();
|
|
52
|
+
});
|
|
36
53
|
await program.parseAsync(argv, { from: 'user' });
|
|
37
54
|
return 0;
|
|
38
55
|
}
|
|
@@ -47,6 +64,9 @@ export async function runCli(argv, options = {}) {
|
|
|
47
64
|
return output.fail(error);
|
|
48
65
|
}
|
|
49
66
|
finally {
|
|
67
|
+
output.dispose();
|
|
68
|
+
if (afterInput)
|
|
69
|
+
process.stdin.off('end', afterInput);
|
|
50
70
|
process.off('SIGINT', interrupt);
|
|
51
71
|
process.off('SIGTERM', interrupt);
|
|
52
72
|
}
|
package/dist/runner.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner.js","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"AAAA,qCAAqC;AACrC,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAGvD,MAAM,UAAW,SAAQ,KAAK;IACP;IAArB,YAAqB,QAAgB;QACnC,KAAK,CAAC,YAAY,CAAC,CAAC;QADD,aAAQ,GAAR,QAAQ,CAAQ;IAErC,CAAC;CACF;AAOD,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,IAAmB,EAAE,UAAyB,EAAE;IAC3E,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,IAAI,YAAY,EAAE,EACjD,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACrC,MAAM,SAAS,GAAG,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"runner.js","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"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"}
|
package/dist/runtime.d.ts
CHANGED
|
@@ -17,6 +17,7 @@ import type { GuidanceResult } from './conversation/next-actions.js';
|
|
|
17
17
|
import { SessionWaiter } from './conversation/session-waiter.js';
|
|
18
18
|
import type { WaitOptions } from './conversation/session-waiter.js';
|
|
19
19
|
import { TaskProgressReader } from './conversation/task-progress-reader.js';
|
|
20
|
+
import { AutoTestTasks } from './conversation/auto-test-tasks.js';
|
|
20
21
|
export declare class CreationRuntime {
|
|
21
22
|
readonly client: ApiClient;
|
|
22
23
|
readonly output: OutputWriter;
|
|
@@ -30,11 +31,13 @@ export declare class CreationRuntime {
|
|
|
30
31
|
readonly previewVersions: PreviewVersionApi;
|
|
31
32
|
readonly waiter: SessionWaiter;
|
|
32
33
|
readonly taskProgress: TaskProgressReader;
|
|
34
|
+
readonly autoTestTasks: AutoTestTasks;
|
|
33
35
|
private demoSnapshotSync?;
|
|
34
36
|
constructor(client: ApiClient, output: OutputWriter);
|
|
35
37
|
load(sessionId: string): Promise<SessionView>;
|
|
36
38
|
choices(sessionId: string, anchor?: string, view?: SessionView): Promise<Array<Choice>>;
|
|
37
39
|
inspect(view: SessionView, styleTarget?: StyleWaitTarget): Promise<CreationResult>;
|
|
40
|
+
resolveChecks(view: SessionView): Promise<Pick<CreationResult, 'autoTest' | 'codeReview'>>;
|
|
38
41
|
state(sessionId: string): Promise<CreationResult>;
|
|
39
42
|
withGuidance<T extends GuidanceResult>(result: T): T & {
|
|
40
43
|
nextActions: import("./contracts/cli-output.js").NextAction[];
|
|
@@ -45,6 +48,7 @@ export declare class CreationRuntime {
|
|
|
45
48
|
} | undefined;
|
|
46
49
|
};
|
|
47
50
|
wait(sessionId: string, options: WaitOptions): Promise<CreationResult>;
|
|
51
|
+
private approveStylePlan;
|
|
48
52
|
accepted(response: JsonObject, sessionId: string | undefined, wait: boolean, options: WaitOptions): Promise<CreationResult>;
|
|
49
53
|
generateStyles(sessionId: string, content: string, count: number, preReplyMessageId?: string): Promise<JsonObject>;
|
|
50
54
|
selectStyle(sessionId: string, choiceId: string): Promise<JsonObject>;
|
package/dist/runtime.js
CHANGED
|
@@ -14,14 +14,21 @@ import { toolId as sourceToolId, toolData } from './interactions/context.js';
|
|
|
14
14
|
import { integrationKey } from './interactions/handlers/reply-plugin.js';
|
|
15
15
|
import { isStyleSelected, projectChoices, styleBranchAnchor, styleChoiceLabel, styleWaitTarget, } from './interactions/parsers/style-selection.js';
|
|
16
16
|
import { resolveState } from './conversation/state-resolver.js';
|
|
17
|
-
import { buildNextActions, hasCompletedCreationResult } from './conversation/next-actions.js';
|
|
17
|
+
import { buildNextActions, hasCompletedCreationResult, pendingStylePlanApproval, } from './conversation/next-actions.js';
|
|
18
18
|
import { demoGenerationStatus, findModifiedDemoPreview, isInitialDemoRound, projectDemoPreview, } from './conversation/demo-preview.js';
|
|
19
|
-
import { currentRound, roundMessage } from './conversation/round-selector.js';
|
|
19
|
+
import { currentRound, roundMessage, roundContainingMessage } from './conversation/round-selector.js';
|
|
20
20
|
import { SessionWaiter } from './conversation/session-waiter.js';
|
|
21
21
|
import { CliError } from './output/exit-codes.js';
|
|
22
22
|
import { dispatchReply } from './interactions/handlers/index.js';
|
|
23
23
|
import { TaskProgressReader } from './conversation/task-progress-reader.js';
|
|
24
24
|
import { submittedTaskProgress, taskProgressSnapshot } from './conversation/task-progress.js';
|
|
25
|
+
import { autoTestContext, AUTO_TEST_SPEC } from './conversation/auto-test.js';
|
|
26
|
+
import { projectText } from './conversation/text-projector.js';
|
|
27
|
+
import { applySnapshot } from './conversation/session-waiter.js';
|
|
28
|
+
import { AutoTestTasks } from './conversation/auto-test-tasks.js';
|
|
29
|
+
import { codeReviewContext, CODE_REVIEW_SPEC } from './conversation/code-review.js';
|
|
30
|
+
import { readCheckQuestionContext } from './conversation/check-question-context.js';
|
|
31
|
+
import { checkContextFromExtra, reportReference } from './conversation/check-context.js';
|
|
25
32
|
// 仅独立演示版本等待快照同步,研发主线直接使用稳定预览地址。
|
|
26
33
|
const DEMO_SNAPSHOT_SYNC_MS = 15_000;
|
|
27
34
|
export class CreationRuntime {
|
|
@@ -37,6 +44,7 @@ export class CreationRuntime {
|
|
|
37
44
|
previewVersions;
|
|
38
45
|
waiter;
|
|
39
46
|
taskProgress;
|
|
47
|
+
autoTestTasks;
|
|
40
48
|
demoSnapshotSync;
|
|
41
49
|
constructor(client, output) {
|
|
42
50
|
this.client = client;
|
|
@@ -50,6 +58,7 @@ export class CreationRuntime {
|
|
|
50
58
|
this.publish = new PublishApi(client);
|
|
51
59
|
this.previewVersions = new PreviewVersionApi(client);
|
|
52
60
|
this.taskProgress = new TaskProgressReader(client);
|
|
61
|
+
this.autoTestTasks = new AutoTestTasks(client);
|
|
53
62
|
this.waiter = new SessionWaiter({
|
|
54
63
|
conversation: this.conversation,
|
|
55
64
|
command: this.command,
|
|
@@ -83,13 +92,22 @@ export class CreationRuntime {
|
|
|
83
92
|
return projectChoices(await this.query.parallel(sessionId, preReplyMessageId), preReplyMessageId, this.client.config.endpoint);
|
|
84
93
|
}
|
|
85
94
|
async inspect(view, styleTarget) {
|
|
95
|
+
const { autoTest, codeReview } = await this.resolveChecks(view);
|
|
96
|
+
const check = codeReview ?? autoTest;
|
|
86
97
|
const anchor = styleTarget?.preReplyMessageId ?? styleBranchAnchor(view);
|
|
87
98
|
const choices = anchor ? await this.choices(view.session.sessionId, anchor, view) : [];
|
|
88
99
|
view = {
|
|
89
100
|
...view,
|
|
90
101
|
activeSubagentWork: await this.taskProgress.hasPendingSubagentWork(view.session.sessionId),
|
|
91
102
|
};
|
|
92
|
-
const
|
|
103
|
+
const pendingReports = codeReview
|
|
104
|
+
? await this.taskProgress.pendingReviewReports(view, codeReview.previousSourceMessageId)
|
|
105
|
+
: autoTest
|
|
106
|
+
? await this.autoTestTasks.pending(view)
|
|
107
|
+
: [];
|
|
108
|
+
if (pendingReports.length)
|
|
109
|
+
view.activeSubagentWork = true;
|
|
110
|
+
const bindings = collectInteractions(view, !styleTarget && isStyleSelected(view, choices)).filter((binding) => !check || binding.interaction.kind !== 'SELECT_FEATURES');
|
|
93
111
|
const processingIds = new Set();
|
|
94
112
|
for (const binding of bindings) {
|
|
95
113
|
if (binding.interaction.kind !== 'PLUGIN_ACTION')
|
|
@@ -102,38 +120,78 @@ export class CreationRuntime {
|
|
|
102
120
|
processingIds.add(binding.interaction.interactionId);
|
|
103
121
|
}
|
|
104
122
|
const visibleBindings = bindings.filter((binding) => !processingIds.has(binding.interaction.interactionId));
|
|
105
|
-
const taskProgress = await this.taskProgress.read(view, choices, visibleBindings.map((binding) => binding.interaction));
|
|
123
|
+
const taskProgress = await this.taskProgress.read(view, choices, visibleBindings.map((binding) => binding.interaction), { autoTest: !!autoTest, codeReview: !!codeReview });
|
|
106
124
|
let result;
|
|
107
125
|
try {
|
|
108
126
|
result = resolveState({ ...view, automaticWork: processingIds.size > 0 }, visibleBindings, choices, styleTarget);
|
|
109
127
|
}
|
|
110
128
|
catch (error) {
|
|
111
|
-
if (error instanceof CliError)
|
|
129
|
+
if (check && error instanceof CliError && error.code === 'BUSINESS_ERROR') {
|
|
130
|
+
result = {
|
|
131
|
+
state: 'FAILED',
|
|
132
|
+
sessionId: view.session.sessionId,
|
|
133
|
+
messageId: roundMessage(view, currentRound(view))?.messageId,
|
|
134
|
+
replyMessageId: currentRound(view)?.anchorUserMessageId,
|
|
135
|
+
messages: check.reportMessages,
|
|
136
|
+
progress: [],
|
|
137
|
+
interactions: [],
|
|
138
|
+
};
|
|
139
|
+
check.error = text(error.details.errorType) ?? error.message;
|
|
140
|
+
}
|
|
141
|
+
else if (error instanceof CliError)
|
|
112
142
|
throw new CliError(error.code, error.message, { ...error.details, taskProgress });
|
|
113
|
-
|
|
143
|
+
else
|
|
144
|
+
throw error;
|
|
145
|
+
}
|
|
146
|
+
result.taskProgress = pendingReports.length
|
|
147
|
+
? taskProgressSnapshot(view.session.sessionId, [...new Map([...taskProgress.tasks, ...pendingReports].map((task) => [task.id, task])).values()], taskProgress.warnings)
|
|
148
|
+
: taskProgress;
|
|
149
|
+
result.cursor = { ...result.cursor, progressRevision: result.taskProgress.revision };
|
|
150
|
+
if (check) {
|
|
151
|
+
// 审查和测试独立于开发阶段和功能推荐,不能落到普通研发完成菜单。
|
|
152
|
+
const questionContext = await readCheckQuestionContext(this.client, view, result.interactions);
|
|
153
|
+
if (questionContext.length) {
|
|
154
|
+
result.messages = [
|
|
155
|
+
...new Map([...result.messages, ...questionContext].map((message) => [message.id, message])).values(),
|
|
156
|
+
];
|
|
157
|
+
check.reportMessages = [
|
|
158
|
+
...new Map([...check.reportMessages, ...questionContext].map((message) => [message.id, message])).values(),
|
|
159
|
+
];
|
|
160
|
+
}
|
|
161
|
+
if (autoTest)
|
|
162
|
+
result.autoTest = autoTest;
|
|
163
|
+
if (codeReview)
|
|
164
|
+
result.codeReview = codeReview;
|
|
165
|
+
return result;
|
|
114
166
|
}
|
|
115
|
-
result.taskProgress = taskProgress;
|
|
116
|
-
result.cursor = { ...result.cursor, progressRevision: taskProgress.revision };
|
|
117
167
|
const roundExtra = roundMessage(view, currentRound(view))?.roundExtra ?? {};
|
|
118
168
|
const planningChoiceId = text(roundExtra.cliPlanAfterStyle);
|
|
169
|
+
const started = enabled(roundExtra.startDevelopment);
|
|
170
|
+
const planApproved = enabled(roundExtra.architecturePlanApproved);
|
|
119
171
|
if (planningChoiceId &&
|
|
120
172
|
!styleTarget &&
|
|
121
173
|
isStyleSelected(view, choices) &&
|
|
122
|
-
isInitialDemoRound(view) &&
|
|
123
|
-
!enabled(roundExtra.startDevelopment)) {
|
|
174
|
+
((isInitialDemoRound(view) && !started) || (started && !planApproved))) {
|
|
124
175
|
result.stylePlanning = { choiceId: planningChoiceId };
|
|
125
|
-
//
|
|
126
|
-
if (
|
|
176
|
+
// 演示和规划都静默衔接,真正需要补充信息的问题仍按原文展示。
|
|
177
|
+
if (['RUNNING', 'QUEUED', 'COMPLETED', 'NEEDS_INPUT'].includes(result.state) &&
|
|
178
|
+
(!result.interactions.length || pendingStylePlanApproval(result))) {
|
|
127
179
|
const choice = choices.find((item) => item.choiceId === planningChoiceId);
|
|
128
180
|
result.messages = [
|
|
129
181
|
{
|
|
130
182
|
id: `${result.replyMessageId}:style-planning`,
|
|
131
183
|
role: 'assistant',
|
|
132
184
|
text: choice
|
|
133
|
-
? `已采用${styleChoiceLabel(choice)}
|
|
134
|
-
: '
|
|
185
|
+
? `已采用${styleChoiceLabel(choice)},正在整理开发功能清单。`
|
|
186
|
+
: '风格已选定,正在整理开发功能清单。',
|
|
135
187
|
},
|
|
136
188
|
];
|
|
189
|
+
if (result.taskProgress) {
|
|
190
|
+
const roundId = currentRound(view)?.roundId;
|
|
191
|
+
result.taskProgress = taskProgressSnapshot(view.session.sessionId, result.taskProgress.tasks.map((task) => task.kind === 'message' && task.roundId === roundId
|
|
192
|
+
? { ...task, title: '整理开发功能清单', status: 'running', detail: undefined }
|
|
193
|
+
: task), result.taskProgress.warnings);
|
|
194
|
+
}
|
|
137
195
|
}
|
|
138
196
|
}
|
|
139
197
|
if (result.state === 'COMPLETED' && isStyleSelected(view, choices) && isInitialDemoRound(view)) {
|
|
@@ -146,8 +204,6 @@ export class CreationRuntime {
|
|
|
146
204
|
return { ...result, state: 'RUNNING' };
|
|
147
205
|
result.demo = demo;
|
|
148
206
|
}
|
|
149
|
-
const started = enabled(roundExtra.startDevelopment);
|
|
150
|
-
const planApproved = enabled(roundExtra.architecturePlanApproved);
|
|
151
207
|
const modifiedDemo = result.state === 'COMPLETED' &&
|
|
152
208
|
!started &&
|
|
153
209
|
!isInitialDemoRound(view) &&
|
|
@@ -183,7 +239,7 @@ export class CreationRuntime {
|
|
|
183
239
|
? 'COMPLETED'
|
|
184
240
|
: 'DEVELOPING',
|
|
185
241
|
};
|
|
186
|
-
if (result.development.stage === 'PLAN_REVIEW')
|
|
242
|
+
if (result.development.stage === 'PLAN_REVIEW' && !result.stylePlanning)
|
|
187
243
|
result.attachments = (await this.query.attachments(view.session.sessionId, ['README.md'])).filter((attachment) => attachment.name === 'README.md');
|
|
188
244
|
const current = currentRound(view);
|
|
189
245
|
const onlyFeatureSelection = result.interactions.every((item) => item.kind === 'SELECT_FEATURES');
|
|
@@ -201,17 +257,103 @@ export class CreationRuntime {
|
|
|
201
257
|
}
|
|
202
258
|
return result;
|
|
203
259
|
}
|
|
260
|
+
async resolveChecks(view) {
|
|
261
|
+
const current = currentRound(view);
|
|
262
|
+
if (!current)
|
|
263
|
+
return {};
|
|
264
|
+
let sourceId = current.anchorUserMessageId;
|
|
265
|
+
let sourceRound = current;
|
|
266
|
+
const visited = new Set();
|
|
267
|
+
// 审查回投后可能再委派修复;逐层沿真实关联回溯,不能取最近的历史审查轮。
|
|
268
|
+
for (let depth = 0; depth < 8; depth++) {
|
|
269
|
+
if (visited.has(sourceId))
|
|
270
|
+
break;
|
|
271
|
+
visited.add(sourceId);
|
|
272
|
+
// 隐藏或并入其他轮的用户消息仍有持久化来源;单消息快照不保证返回渲染轮。
|
|
273
|
+
const source = sourceRound
|
|
274
|
+
? undefined
|
|
275
|
+
: await this.query.messageReferenceSource(view.session.sessionId, sourceId);
|
|
276
|
+
const contexts = source
|
|
277
|
+
? {
|
|
278
|
+
autoTest: checkContextFromExtra(source.roundExtra, AUTO_TEST_SPEC, sourceId),
|
|
279
|
+
codeReview: checkContextFromExtra(source.roundExtra, CODE_REVIEW_SPEC, sourceId),
|
|
280
|
+
}
|
|
281
|
+
: {
|
|
282
|
+
autoTest: autoTestContext(view, sourceId),
|
|
283
|
+
codeReview: codeReviewContext(view, sourceId),
|
|
284
|
+
};
|
|
285
|
+
if (contexts.autoTest && contexts.codeReview)
|
|
286
|
+
throw new CliError('PROTOCOL_ERROR', '当前结果同时关联审查与测试,无法确认来源');
|
|
287
|
+
const check = contexts.codeReview ?? contexts.autoTest;
|
|
288
|
+
if (check) {
|
|
289
|
+
if (check.previousSourceMessageId) {
|
|
290
|
+
const readPrevious = (source) => {
|
|
291
|
+
const round = roundContainingMessage(source, check.previousSourceMessageId);
|
|
292
|
+
return round
|
|
293
|
+
? projectText([round]).messages.filter((item) => item.role === 'assistant')
|
|
294
|
+
: undefined;
|
|
295
|
+
};
|
|
296
|
+
let previous = readPrevious(view);
|
|
297
|
+
if (!previous) {
|
|
298
|
+
const snapshot = await this.conversation.snapshot(view.session.sessionId, check.previousSourceMessageId);
|
|
299
|
+
if (snapshot.pipeline)
|
|
300
|
+
previous = readPrevious(applySnapshot(view, snapshot.pipeline));
|
|
301
|
+
}
|
|
302
|
+
check.previousReportMessages = previous;
|
|
303
|
+
}
|
|
304
|
+
check.sourceMessageId = current.anchorUserMessageId;
|
|
305
|
+
check.reportMessages = projectText([current]).messages.filter((item) => item.role === 'assistant');
|
|
306
|
+
return contexts;
|
|
307
|
+
}
|
|
308
|
+
const reference = source ? reportReference(source) : undefined;
|
|
309
|
+
const childId = reference && 'childId' in reference
|
|
310
|
+
? reference.childId
|
|
311
|
+
: sourceRound?.meta?.subAgentReport
|
|
312
|
+
? text(sourceRound.meta.subAgentReportFrom)
|
|
313
|
+
: undefined;
|
|
314
|
+
const parentId = childId
|
|
315
|
+
? await this.taskProgress.parentReplyMessageId(view.session.sessionId, childId)
|
|
316
|
+
: reference && 'taskId' in reference
|
|
317
|
+
? await this.autoTestTasks.parentForTask(view.session.sessionId, reference.taskId)
|
|
318
|
+
: sourceRound
|
|
319
|
+
? await this.autoTestTasks.reportParent(view, sourceId)
|
|
320
|
+
: undefined;
|
|
321
|
+
if (!parentId) {
|
|
322
|
+
const businessType = source?.roundExtra.business_type ??
|
|
323
|
+
view.pipeline.messages.find((message) => message.messageId === sourceId)?.roundExtra?.business_type;
|
|
324
|
+
if (reference ||
|
|
325
|
+
sourceRound?.meta?.subAgentReport ||
|
|
326
|
+
businessType === 'background_task_report' ||
|
|
327
|
+
businessType === 'sub_agent_report')
|
|
328
|
+
throw new CliError('PROTOCOL_ERROR', '暂时无法读取后台回执的来源,请重新查询当前状态');
|
|
329
|
+
return {};
|
|
330
|
+
}
|
|
331
|
+
sourceId = parentId;
|
|
332
|
+
// 合并轮内可能有多次委派;此时按精确消息回溯,不能用宿主轮覆盖它的来源。
|
|
333
|
+
sourceRound = view.pipeline.render?.rounds.find((round) => round.anchorUserMessageId === parentId);
|
|
334
|
+
}
|
|
335
|
+
throw new CliError('PROTOCOL_ERROR', '后台回执的来源链存在循环或层数过多,无法确认当前结果');
|
|
336
|
+
}
|
|
204
337
|
async state(sessionId) {
|
|
205
338
|
return this.withGuidance(await this.inspect(await this.load(sessionId)));
|
|
206
339
|
}
|
|
207
340
|
withGuidance(result) {
|
|
208
|
-
|
|
209
|
-
|
|
341
|
+
// 对外仍表示正在整理清单;内部保留真实确认交互,由 wait 校验后继续。
|
|
342
|
+
const visible = pendingStylePlanApproval(result)
|
|
343
|
+
? {
|
|
344
|
+
...result,
|
|
345
|
+
state: 'RUNNING',
|
|
346
|
+
interactions: [],
|
|
347
|
+
development: result.development ? { ...result.development, stage: 'PLANNING' } : undefined,
|
|
348
|
+
}
|
|
210
349
|
: result;
|
|
350
|
+
const output = visible.taskProgress
|
|
351
|
+
? { ...visible, cursor: { ...visible.cursor, progressRevision: visible.taskProgress.revision } }
|
|
352
|
+
: visible;
|
|
211
353
|
const completed = {
|
|
212
354
|
...output,
|
|
213
|
-
...(hasCompletedCreationResult(
|
|
214
|
-
? { toolUsage: this.taskProgress.completionSummary(
|
|
355
|
+
...(hasCompletedCreationResult(visible)
|
|
356
|
+
? { toolUsage: this.taskProgress.completionSummary(visible.sessionId, visible.messageId) }
|
|
215
357
|
: {}),
|
|
216
358
|
};
|
|
217
359
|
return { ...completed, nextActions: buildNextActions(completed, this.client.config) };
|
|
@@ -221,17 +363,27 @@ export class CreationRuntime {
|
|
|
221
363
|
const remaining = () => deadline === undefined ? undefined : Math.max(0, (deadline - Date.now()) / 1000);
|
|
222
364
|
let pending = options;
|
|
223
365
|
let result = await this.waiter.wait(sessionId, { ...pending, timeout: remaining() });
|
|
224
|
-
while (result.stylePlanning && result.state === 'COMPLETED') {
|
|
366
|
+
while (result.stylePlanning && (result.state === 'COMPLETED' || pendingStylePlanApproval(result))) {
|
|
225
367
|
if (deadline !== undefined && Date.now() >= deadline)
|
|
226
|
-
return this.withGuidance({
|
|
368
|
+
return this.withGuidance({
|
|
369
|
+
...result,
|
|
370
|
+
state: pendingStylePlanApproval(result) ? result.state : 'RUNNING',
|
|
371
|
+
waitTimedOut: true,
|
|
372
|
+
});
|
|
227
373
|
const choiceId = result.stylePlanning.choiceId;
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
374
|
+
const approval = pendingStylePlanApproval(result);
|
|
375
|
+
let response;
|
|
376
|
+
if (approval)
|
|
377
|
+
response = await this.approveStylePlan(sessionId, choiceId, approval.interactionId);
|
|
378
|
+
else {
|
|
379
|
+
result = await this.viewDemo(sessionId, { timeout: remaining() }, choiceId);
|
|
380
|
+
if (!result.stylePlanning || result.state !== 'COMPLETED')
|
|
381
|
+
break;
|
|
382
|
+
if (deadline !== undefined && Date.now() >= deadline)
|
|
383
|
+
return this.withGuidance({ ...result, state: 'RUNNING', waitTimedOut: true });
|
|
384
|
+
// 查看演示与进入研发各自先核对当前轮,失败时保留真实错误,不重发写请求。
|
|
385
|
+
response = await this.startDevelopment(sessionId, choiceId);
|
|
386
|
+
}
|
|
235
387
|
pending = {
|
|
236
388
|
messageId: text(response.messageId),
|
|
237
389
|
requiredMessageId: text(response.messageId) ?? text(response.replyMessageId),
|
|
@@ -239,9 +391,22 @@ export class CreationRuntime {
|
|
|
239
391
|
};
|
|
240
392
|
result = await this.waiter.wait(sessionId, { ...pending, timeout: remaining() });
|
|
241
393
|
}
|
|
242
|
-
//
|
|
394
|
+
// 最终展示功能清单或实际业务问题,静默步骤的消息不带到下一阶段。
|
|
243
395
|
return this.withGuidance(result);
|
|
244
396
|
}
|
|
397
|
+
async approveStylePlan(sessionId, choiceId, interactionId) {
|
|
398
|
+
const latest = await this.inspect(await this.load(sessionId));
|
|
399
|
+
if (latest.stylePlanning?.choiceId !== choiceId ||
|
|
400
|
+
pendingStylePlanApproval(latest)?.interactionId !== interactionId)
|
|
401
|
+
throw new CliError('STALE_INTERACTION', '研发规划或当前问题已变化,请重新查询当前状态', { sessionId });
|
|
402
|
+
return this.command.chat({
|
|
403
|
+
sessionId,
|
|
404
|
+
content: '确认研发规划',
|
|
405
|
+
businessParams: { business_type: 'architecture_plan_approve' },
|
|
406
|
+
// 自动衔接只消费本次初始规划,不影响后续独立的规划调整与确认。
|
|
407
|
+
excludedInheritedRoundExtraKeys: ['cliPlanAfterStyle'],
|
|
408
|
+
});
|
|
409
|
+
}
|
|
245
410
|
async accepted(response, sessionId, wait, options) {
|
|
246
411
|
const id = text(response.sessionId) ?? sessionId;
|
|
247
412
|
if (!id)
|
|
@@ -258,7 +423,10 @@ export class CreationRuntime {
|
|
|
258
423
|
try {
|
|
259
424
|
// 接受回执也展示同一项目的其他活跃任务;仅查进度,不推进任务或读取功能清单。
|
|
260
425
|
const view = { ...(await this.conversation.recently(id)), extra: {} };
|
|
261
|
-
const snapshot = await this.taskProgress.read(view, await this.choices(id, undefined, view)
|
|
426
|
+
const snapshot = await this.taskProgress.read(view, await this.choices(id, undefined, view), [], {
|
|
427
|
+
autoTest: ['test', 'repair'].includes(String(response.autoTestPhase)),
|
|
428
|
+
codeReview: ['review', 'repair'].includes(String(response.codeReviewPhase)),
|
|
429
|
+
});
|
|
262
430
|
const responseIds = [text(response.messageId), text(response.replyMessageId)].filter(Boolean);
|
|
263
431
|
const round = view.pipeline.render?.rounds.find((item) => responseIds.includes(item.anchorUserMessageId) ||
|
|
264
432
|
[...item.userItems, ...item.agentItems].some((content) => responseIds.includes(content.source?.messageId)));
|
|
@@ -285,6 +453,24 @@ export class CreationRuntime {
|
|
|
285
453
|
? { stylePlanning: { choiceId: String(response.planningChoiceId) } }
|
|
286
454
|
: {}),
|
|
287
455
|
cursor: { branchAnchor: text(response.preReplyMessageId) },
|
|
456
|
+
...(['test', 'repair'].includes(String(response.autoTestPhase))
|
|
457
|
+
? {
|
|
458
|
+
autoTest: {
|
|
459
|
+
phase: response.autoTestPhase,
|
|
460
|
+
sourceMessageId: text(response.replyMessageId) ?? text(response.messageId) ?? '',
|
|
461
|
+
reportMessages: [],
|
|
462
|
+
},
|
|
463
|
+
}
|
|
464
|
+
: {}),
|
|
465
|
+
...(['review', 'repair'].includes(String(response.codeReviewPhase))
|
|
466
|
+
? {
|
|
467
|
+
codeReview: {
|
|
468
|
+
phase: response.codeReviewPhase,
|
|
469
|
+
sourceMessageId: text(response.replyMessageId) ?? text(response.messageId) ?? '',
|
|
470
|
+
reportMessages: [],
|
|
471
|
+
},
|
|
472
|
+
}
|
|
473
|
+
: {}),
|
|
288
474
|
});
|
|
289
475
|
}
|
|
290
476
|
async generateStyles(sessionId, content, count, preReplyMessageId) {
|
|
@@ -349,7 +535,7 @@ export class CreationRuntime {
|
|
|
349
535
|
retryable: false,
|
|
350
536
|
});
|
|
351
537
|
}
|
|
352
|
-
const planningNotice = `已采用${styleChoiceLabel(choice)}
|
|
538
|
+
const planningNotice = `已采用${styleChoiceLabel(choice)},正在整理开发功能清单。`;
|
|
353
539
|
this.output.log(planningNotice);
|
|
354
540
|
return { ...response, planningChoiceId: choice.choiceId, planningNotice };
|
|
355
541
|
}
|