team-anya 0.2.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/README.md +38 -0
- package/apps/server/dist/broker/cc-broker.js +267 -0
- package/apps/server/dist/cli.js +296 -0
- package/apps/server/dist/config.js +78 -0
- package/apps/server/dist/daemon.js +51 -0
- package/apps/server/dist/franky/context-builder.js +161 -0
- package/apps/server/dist/franky/franky-mcp-server.js +110 -0
- package/apps/server/dist/franky/franky-orchestrator.js +629 -0
- package/apps/server/dist/franky/index.js +5 -0
- package/apps/server/dist/franky/topic-router.js +16 -0
- package/apps/server/dist/gateway/chat-sync.js +135 -0
- package/apps/server/dist/gateway/command-router.js +116 -0
- package/apps/server/dist/gateway/commands/cancel.js +32 -0
- package/apps/server/dist/gateway/commands/help.js +16 -0
- package/apps/server/dist/gateway/commands/index.js +26 -0
- package/apps/server/dist/gateway/commands/restart.js +43 -0
- package/apps/server/dist/gateway/commands/status.js +34 -0
- package/apps/server/dist/gateway/commands/tasks.js +33 -0
- package/apps/server/dist/gateway/feishu-sender.js +508 -0
- package/apps/server/dist/gateway/feishu-ws.js +353 -0
- package/apps/server/dist/gateway/health-monitor.js +154 -0
- package/apps/server/dist/gateway/http.js +1064 -0
- package/apps/server/dist/gateway/media-downloader.js +182 -0
- package/apps/server/dist/gateway/message-events.js +10 -0
- package/apps/server/dist/gateway/message-intake.js +72 -0
- package/apps/server/dist/gateway/message-queue.js +118 -0
- package/apps/server/dist/gateway/session-reader.js +142 -0
- package/apps/server/dist/gateway/ws-push.js +115 -0
- package/apps/server/dist/loid/brain.js +121 -0
- package/apps/server/dist/loid/clarifier.js +162 -0
- package/apps/server/dist/loid/context-builder.js +462 -0
- package/apps/server/dist/loid/mcp-server.js +119 -0
- package/apps/server/dist/loid/memory-settler.js +189 -0
- package/apps/server/dist/loid/opportunity-manager.js +148 -0
- package/apps/server/dist/loid/profile-updater.js +179 -0
- package/apps/server/dist/loid/project-registry.js +192 -0
- package/apps/server/dist/loid/reporter.js +148 -0
- package/apps/server/dist/loid/schemas.js +117 -0
- package/apps/server/dist/loid/self-calibrator.js +314 -0
- package/apps/server/dist/loid/session-manager.js +472 -0
- package/apps/server/dist/loid/session.js +276 -0
- package/apps/server/dist/main.js +528 -0
- package/apps/server/dist/tracing/index.js +2 -0
- package/apps/server/dist/tracing/trace-context.js +92 -0
- package/apps/server/dist/types/message.js +2 -0
- package/apps/server/dist/yor/yor-mcp-server.js +107 -0
- package/apps/server/dist/yor/yor-orchestrator.js +248 -0
- package/apps/web/dist/assets/index-BiiEB0qZ.css +1 -0
- package/apps/web/dist/assets/index-Dnb9LGZd.js +798 -0
- package/apps/web/dist/index.html +13 -0
- package/package.json +42 -0
- package/packages/cc-client/dist/claude-code-backend.js +792 -0
- package/packages/cc-client/dist/index.js +2 -0
- package/packages/cc-client/package.json +11 -0
- package/packages/core/dist/constants.js +60 -0
- package/packages/core/dist/errors.js +35 -0
- package/packages/core/dist/index.js +9 -0
- package/packages/core/dist/office-init.js +190 -0
- package/packages/core/dist/repo-cache.js +70 -0
- package/packages/core/dist/scope/checker.js +114 -0
- package/packages/core/dist/scope/defaults.js +55 -0
- package/packages/core/dist/scope/index.js +3 -0
- package/packages/core/dist/state-machine.js +86 -0
- package/packages/core/dist/types/audit.js +12 -0
- package/packages/core/dist/types/backend.js +2 -0
- package/packages/core/dist/types/commitment.js +17 -0
- package/packages/core/dist/types/communication.js +18 -0
- package/packages/core/dist/types/index.js +9 -0
- package/packages/core/dist/types/opportunity.js +27 -0
- package/packages/core/dist/types/org.js +26 -0
- package/packages/core/dist/types/task.js +46 -0
- package/packages/core/dist/types/workspace.js +39 -0
- package/packages/core/dist/workspace-manager.js +314 -0
- package/packages/core/package.json +10 -0
- package/packages/db/dist/client.js +69 -0
- package/packages/db/dist/index.js +756 -0
- package/packages/db/dist/schema/audit-events.js +13 -0
- package/packages/db/dist/schema/cc-sessions.js +14 -0
- package/packages/db/dist/schema/chats.js +35 -0
- package/packages/db/dist/schema/commitments.js +18 -0
- package/packages/db/dist/schema/communication-events.js +14 -0
- package/packages/db/dist/schema/index.js +14 -0
- package/packages/db/dist/schema/message-log.js +20 -0
- package/packages/db/dist/schema/opportunities.js +23 -0
- package/packages/db/dist/schema/org.js +36 -0
- package/packages/db/dist/schema/projects.js +23 -0
- package/packages/db/dist/schema/tasks.js +51 -0
- package/packages/db/dist/schema/topics.js +22 -0
- package/packages/db/dist/schema/trace-spans.js +19 -0
- package/packages/db/dist/schema/workspaces.js +15 -0
- package/packages/db/package.json +12 -0
- package/packages/db/src/migrations/0000_baseline.sql +251 -0
- package/packages/db/src/migrations/0001_workspaces.sql +19 -0
- package/packages/db/src/migrations/0002_workspace_parent.sql +1 -0
- package/packages/db/src/migrations/0003_chat_context.sql +3 -0
- package/packages/db/src/migrations/meta/_journal.json +34 -0
- package/packages/mcp-tools/dist/index.js +41 -0
- package/packages/mcp-tools/dist/layer1/audit-append.js +38 -0
- package/packages/mcp-tools/dist/layer1/audit-query.js +51 -0
- package/packages/mcp-tools/dist/layer1/memory-brief.js +168 -0
- package/packages/mcp-tools/dist/layer1/memory-context.js +124 -0
- package/packages/mcp-tools/dist/layer1/memory-digest.js +126 -0
- package/packages/mcp-tools/dist/layer1/memory-forget.js +108 -0
- package/packages/mcp-tools/dist/layer1/memory-learn.js +63 -0
- package/packages/mcp-tools/dist/layer1/memory-recall.js +287 -0
- package/packages/mcp-tools/dist/layer1/memory-reflect.js +80 -0
- package/packages/mcp-tools/dist/layer1/memory-remember.js +119 -0
- package/packages/mcp-tools/dist/layer1/memory-search.js +263 -0
- package/packages/mcp-tools/dist/layer1/memory-write.js +21 -0
- package/packages/mcp-tools/dist/layer1/org-lookup.js +47 -0
- package/packages/mcp-tools/dist/layer1/project-get.js +28 -0
- package/packages/mcp-tools/dist/layer1/project-list.js +20 -0
- package/packages/mcp-tools/dist/layer1/report-daily.js +68 -0
- package/packages/mcp-tools/dist/layer1/task-get.js +29 -0
- package/packages/mcp-tools/dist/layer1/task-update.js +34 -0
- package/packages/mcp-tools/dist/layer2/franky/topic-checkpoint.js +43 -0
- package/packages/mcp-tools/dist/layer2/franky/topic-escalate.js +19 -0
- package/packages/mcp-tools/dist/layer2/loid/decision-log.js +15 -0
- package/packages/mcp-tools/dist/layer2/loid/decision-no-action.js +15 -0
- package/packages/mcp-tools/dist/layer2/loid/delivery-create-pr.js +30 -0
- package/packages/mcp-tools/dist/layer2/loid/delivery-share.js +12 -0
- package/packages/mcp-tools/dist/layer2/loid/delivery-submit.js +77 -0
- package/packages/mcp-tools/dist/layer2/loid/delivery-upload.js +18 -0
- package/packages/mcp-tools/dist/layer2/loid/project-remove.js +16 -0
- package/packages/mcp-tools/dist/layer2/loid/project-upsert.js +33 -0
- package/packages/mcp-tools/dist/layer2/loid/task-dispatch.js +206 -0
- package/packages/mcp-tools/dist/layer2/loid/task-escalate-to-topic.js +170 -0
- package/packages/mcp-tools/dist/layer2/loid/task-lookup.js +45 -0
- package/packages/mcp-tools/dist/layer2/loid/topic-close.js +22 -0
- package/packages/mcp-tools/dist/layer2/loid/topic-create.js +60 -0
- package/packages/mcp-tools/dist/layer2/loid/yor-approve.js +8 -0
- package/packages/mcp-tools/dist/layer2/loid/yor-kill.js +7 -0
- package/packages/mcp-tools/dist/layer2/loid/yor-rework.js +7 -0
- package/packages/mcp-tools/dist/layer2/loid/yor-spawn.js +28 -0
- package/packages/mcp-tools/dist/layer2/loid/yor-status.js +8 -0
- package/packages/mcp-tools/dist/layer2/yor/task-block.js +11 -0
- package/packages/mcp-tools/dist/layer2/yor/task-deliver.js +35 -0
- package/packages/mcp-tools/dist/layer2/yor/task-progress.js +21 -0
- package/packages/mcp-tools/dist/layer3/adapters/feishu-adapter.js +203 -0
- package/packages/mcp-tools/dist/layer3/adapters/types.js +28 -0
- package/packages/mcp-tools/dist/layer3/channel-receive.js +11 -0
- package/packages/mcp-tools/dist/layer3/channel-send.js +75 -0
- package/packages/mcp-tools/dist/layer3/file-upload.js +44 -0
- package/packages/mcp-tools/dist/registry.js +911 -0
- package/packages/mcp-tools/package.json +13 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { readFileSync, existsSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { startLoidMcpServer } from './mcp-server.js';
|
|
4
|
+
import { LoidSessionManager } from './session-manager.js';
|
|
5
|
+
// ── LoidBrain ──
|
|
6
|
+
export class LoidBrain {
|
|
7
|
+
config;
|
|
8
|
+
deps;
|
|
9
|
+
ready = false;
|
|
10
|
+
mcpUrl = null;
|
|
11
|
+
mcpClose;
|
|
12
|
+
protocols = {};
|
|
13
|
+
sessionManager = null;
|
|
14
|
+
constructor(config, deps) {
|
|
15
|
+
this.config = config;
|
|
16
|
+
this.deps = deps;
|
|
17
|
+
}
|
|
18
|
+
async init() {
|
|
19
|
+
// 1. 启动指挥型 MCP server
|
|
20
|
+
const mcp = await startLoidMcpServer(this.deps.mcpDeps);
|
|
21
|
+
this.mcpClose = mcp.close;
|
|
22
|
+
this.mcpUrl = mcp.url;
|
|
23
|
+
// 2. 预读协议文件到内存
|
|
24
|
+
this.loadProtocols();
|
|
25
|
+
// 3. 确保基础目录存在
|
|
26
|
+
if (!existsSync(this.config.loidBaseDir)) {
|
|
27
|
+
const { mkdir } = await import('node:fs/promises');
|
|
28
|
+
await mkdir(this.config.loidBaseDir, { recursive: true });
|
|
29
|
+
}
|
|
30
|
+
// 4. 初始化 SessionManager
|
|
31
|
+
const logDir = join(this.config.loidBaseDir, '..', '..', 'data', 'logs', 'cc-logs');
|
|
32
|
+
this.sessionManager = new LoidSessionManager({
|
|
33
|
+
broker: this.deps.broker,
|
|
34
|
+
backendConfigTemplate: {
|
|
35
|
+
type: 'claude-code',
|
|
36
|
+
binary: this.config.binary,
|
|
37
|
+
workingDir: '', // 占位,由 SessionManager 按 chatId 动态设置
|
|
38
|
+
dangerouslySkipPermissions: true,
|
|
39
|
+
maxTurns: this.config.maxTurnsPerSession ?? 50,
|
|
40
|
+
mcpServers: [{
|
|
41
|
+
name: 'loid-tools',
|
|
42
|
+
url: this.mcpUrl,
|
|
43
|
+
headers: { 'x-anya-internal': 'true' },
|
|
44
|
+
}],
|
|
45
|
+
},
|
|
46
|
+
loidBaseDir: this.config.loidBaseDir,
|
|
47
|
+
officePath: this.config.officePath,
|
|
48
|
+
templateDir: this.config.templateDir,
|
|
49
|
+
idleTimeoutMs: this.config.idleTimeoutMs,
|
|
50
|
+
maxTurnsPerSession: this.config.maxTurnsPerSession,
|
|
51
|
+
protocols: this.protocols,
|
|
52
|
+
logDir,
|
|
53
|
+
logger: this.config.logger,
|
|
54
|
+
}, {
|
|
55
|
+
db: this.deps.mcpDeps.db,
|
|
56
|
+
feishuSender: this.deps.feishuSender,
|
|
57
|
+
projectRegistry: this.deps.projectRegistry,
|
|
58
|
+
});
|
|
59
|
+
this.ready = true;
|
|
60
|
+
this.config.logger?.info('LoidBrain 已初始化 (Session 模式)');
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* 重启指定 chatId 的 Loid session(/restart 命令)
|
|
64
|
+
* 确保下次来消息走全新 session 而非 resume
|
|
65
|
+
*/
|
|
66
|
+
async restartChat(chatId) {
|
|
67
|
+
await this.sessionManager?.restartChat(chatId);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* 仅释放所有 Loid 会话(重启场景用),保留 MCP server 和 ready 状态
|
|
71
|
+
*/
|
|
72
|
+
async disposeSessions() {
|
|
73
|
+
await this.sessionManager?.dispose();
|
|
74
|
+
this.config.logger?.info('LoidBrain 会话已全部释放(MCP server 保留)');
|
|
75
|
+
}
|
|
76
|
+
async dispose() {
|
|
77
|
+
await this.sessionManager?.dispose();
|
|
78
|
+
await this.mcpClose?.();
|
|
79
|
+
this.ready = false;
|
|
80
|
+
this.config.logger?.info('LoidBrain 已关闭');
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* 入口 1: 处理新消息
|
|
84
|
+
* 委托给 SessionManager 管理长驻会话
|
|
85
|
+
*/
|
|
86
|
+
async handleNewMessage(ctx) {
|
|
87
|
+
this.ensureReady();
|
|
88
|
+
const chatId = ctx.message.chatId ?? ctx.message.sender ?? 'default';
|
|
89
|
+
const sender = ctx.message.sender ?? '未知';
|
|
90
|
+
this.config.logger?.info(`[anya:pipeline] [Loid] 收到消息 ${sender}@${chatId}: "${ctx.message.content.slice(0, 60)}"`);
|
|
91
|
+
await this.sessionManager.handleMessage(chatId, ctx);
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* 入口 2: 处理 Yor 交付
|
|
95
|
+
* 委托给 SessionManager 管理验收会话
|
|
96
|
+
*/
|
|
97
|
+
async handleDelivery(ctx) {
|
|
98
|
+
this.ensureReady();
|
|
99
|
+
this.config.logger?.info(`[anya:pipeline] [Loid] 开始验收 ${ctx.taskId} (exit=${ctx.exitCode})`);
|
|
100
|
+
await this.sessionManager.handleDelivery(ctx);
|
|
101
|
+
}
|
|
102
|
+
// ── 私有方法 ──
|
|
103
|
+
ensureReady() {
|
|
104
|
+
if (!this.ready) {
|
|
105
|
+
throw new Error('LoidBrain 尚未初始化,请先调用 init()');
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
loadProtocols() {
|
|
109
|
+
const protocolNames = ['review', 'report'];
|
|
110
|
+
for (const name of protocolNames) {
|
|
111
|
+
const filePath = join(this.config.protocolsDir, `${name}.md`);
|
|
112
|
+
if (existsSync(filePath)) {
|
|
113
|
+
this.protocols[name] = readFileSync(filePath, 'utf-8');
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
this.config.logger?.error?.(`协议文件不存在: ${filePath}`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=brain.js.map
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { getTask, updateTask, addClarification, getClarifications, answerClarification } from '@team-anya/db';
|
|
2
|
+
import { TaskStatus } from '@team-anya/core';
|
|
3
|
+
// ── 问题模板 ──
|
|
4
|
+
const QUESTION_TEMPLATES = {
|
|
5
|
+
objective: [
|
|
6
|
+
'这个任务的具体目标是什么?希望达到什么效果?',
|
|
7
|
+
],
|
|
8
|
+
acceptance_criteria: [
|
|
9
|
+
'这个任务的验收标准是什么?怎样算完成?',
|
|
10
|
+
],
|
|
11
|
+
context: [
|
|
12
|
+
'能否提供更多背景信息?比如触发场景、影响范围、相关日志等?',
|
|
13
|
+
],
|
|
14
|
+
scope: [
|
|
15
|
+
'这个任务涉及哪个项目/仓库?影响范围有多大?',
|
|
16
|
+
],
|
|
17
|
+
};
|
|
18
|
+
// 精确型 sender 只问关键项(objective 和 acceptance_criteria 优先)
|
|
19
|
+
const CRITICAL_FIELDS = ['objective', 'acceptance_criteria'];
|
|
20
|
+
// ── Clarifier ──
|
|
21
|
+
export class Clarifier {
|
|
22
|
+
db;
|
|
23
|
+
getProfileStyle;
|
|
24
|
+
constructor(deps) {
|
|
25
|
+
this.db = deps.db;
|
|
26
|
+
this.getProfileStyle = deps.getProfileStyle;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* 检查任务需求的完整性(四要素:objective, acceptance_criteria, context, scope)
|
|
30
|
+
*/
|
|
31
|
+
checkCompleteness(taskData) {
|
|
32
|
+
const missing = [];
|
|
33
|
+
if (!taskData.objective || taskData.objective.trim() === '') {
|
|
34
|
+
missing.push('objective');
|
|
35
|
+
}
|
|
36
|
+
if (!taskData.acceptance_criteria || taskData.acceptance_criteria.trim() === '') {
|
|
37
|
+
missing.push('acceptance_criteria');
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
// 检查 JSON 数组是否为空
|
|
41
|
+
try {
|
|
42
|
+
const parsed = JSON.parse(taskData.acceptance_criteria);
|
|
43
|
+
if (Array.isArray(parsed) && parsed.length === 0) {
|
|
44
|
+
missing.push('acceptance_criteria');
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
// 非 JSON 格式,视为有值
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
if (!taskData.context || taskData.context.trim() === '') {
|
|
52
|
+
missing.push('context');
|
|
53
|
+
}
|
|
54
|
+
if (!taskData.project_id || taskData.project_id.trim() === '') {
|
|
55
|
+
missing.push('scope');
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
isComplete: missing.length === 0,
|
|
59
|
+
missing,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* 根据缺失项生成澄清问题
|
|
64
|
+
* @param missing 缺失的要素名
|
|
65
|
+
* @param style sender 的沟通风格(verbose=全问, precise=只问关键项)
|
|
66
|
+
*/
|
|
67
|
+
generateQuestions(missing, style = 'verbose') {
|
|
68
|
+
if (missing.length === 0)
|
|
69
|
+
return [];
|
|
70
|
+
const fieldsToAsk = style === 'precise'
|
|
71
|
+
? missing.filter(m => CRITICAL_FIELDS.includes(m))
|
|
72
|
+
: missing;
|
|
73
|
+
// 精确型如果没有关键项缺失,仍至少问第一个缺失项
|
|
74
|
+
const effectiveFields = fieldsToAsk.length > 0 ? fieldsToAsk : [missing[0]];
|
|
75
|
+
const questions = [];
|
|
76
|
+
for (const field of effectiveFields) {
|
|
77
|
+
const templates = QUESTION_TEMPLATES[field];
|
|
78
|
+
if (templates) {
|
|
79
|
+
questions.push(...templates);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return questions;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* 对任务进行需求澄清
|
|
86
|
+
* - 完整 → 直接转为 READY
|
|
87
|
+
* - 不完整 → 转为 NEED_CLARIFICATION,生成问题并写入 DB
|
|
88
|
+
*/
|
|
89
|
+
async clarifyTask(taskId, senderId) {
|
|
90
|
+
const task = getTask(this.db, taskId);
|
|
91
|
+
if (!task) {
|
|
92
|
+
throw new Error(`任务不存在: ${taskId}`);
|
|
93
|
+
}
|
|
94
|
+
if (task.status !== TaskStatus.NEW) {
|
|
95
|
+
throw new Error(`任务状态为 ${task.status},只有 NEW 状态才能进行澄清`);
|
|
96
|
+
}
|
|
97
|
+
const check = this.checkCompleteness({
|
|
98
|
+
objective: task.objective,
|
|
99
|
+
acceptance_criteria: task.acceptance_criteria,
|
|
100
|
+
context: task.context,
|
|
101
|
+
project_id: task.project_id,
|
|
102
|
+
});
|
|
103
|
+
if (check.isComplete) {
|
|
104
|
+
// 直接转为 READY
|
|
105
|
+
updateTask(this.db, taskId, { status: TaskStatus.READY });
|
|
106
|
+
return {
|
|
107
|
+
needsClarification: false,
|
|
108
|
+
questions: [],
|
|
109
|
+
missing: [],
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
// 获取 sender 的沟通风格
|
|
113
|
+
let style = 'verbose';
|
|
114
|
+
if (senderId && this.getProfileStyle) {
|
|
115
|
+
try {
|
|
116
|
+
style = await this.getProfileStyle(senderId);
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
// 降级为 verbose
|
|
120
|
+
style = 'verbose';
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
const questions = this.generateQuestions(check.missing, style);
|
|
124
|
+
// 转为 NEED_CLARIFICATION
|
|
125
|
+
updateTask(this.db, taskId, { status: TaskStatus.NEED_CLARIFICATION });
|
|
126
|
+
// 将问题写入 clarifications 表
|
|
127
|
+
for (const question of questions) {
|
|
128
|
+
addClarification(this.db, {
|
|
129
|
+
task_id: taskId,
|
|
130
|
+
question,
|
|
131
|
+
asked_by: 'loid',
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
return {
|
|
135
|
+
needsClarification: true,
|
|
136
|
+
questions,
|
|
137
|
+
missing: check.missing,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* 处理澄清回答
|
|
142
|
+
* - 更新 clarification 记录
|
|
143
|
+
* - 如果所有问题都已回答,将任务转为 READY
|
|
144
|
+
*/
|
|
145
|
+
async handleAnswer(clarificationId, answer, answeredBy) {
|
|
146
|
+
const updated = answerClarification(this.db, clarificationId, answer, answeredBy);
|
|
147
|
+
if (!updated) {
|
|
148
|
+
throw new Error(`澄清记录不存在: ${clarificationId}`);
|
|
149
|
+
}
|
|
150
|
+
const taskId = updated.task_id;
|
|
151
|
+
// 检查是否所有问题都已回答
|
|
152
|
+
const allClarifications = getClarifications(this.db, taskId);
|
|
153
|
+
const allAnswered = allClarifications.every(c => c.answer !== null);
|
|
154
|
+
if (allAnswered) {
|
|
155
|
+
const task = getTask(this.db, taskId);
|
|
156
|
+
if (task && task.status === TaskStatus.NEED_CLARIFICATION) {
|
|
157
|
+
updateTask(this.db, taskId, { status: TaskStatus.READY });
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=clarifier.js.map
|