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.
Files changed (145) hide show
  1. package/README.md +38 -0
  2. package/apps/server/dist/broker/cc-broker.js +267 -0
  3. package/apps/server/dist/cli.js +296 -0
  4. package/apps/server/dist/config.js +78 -0
  5. package/apps/server/dist/daemon.js +51 -0
  6. package/apps/server/dist/franky/context-builder.js +161 -0
  7. package/apps/server/dist/franky/franky-mcp-server.js +110 -0
  8. package/apps/server/dist/franky/franky-orchestrator.js +629 -0
  9. package/apps/server/dist/franky/index.js +5 -0
  10. package/apps/server/dist/franky/topic-router.js +16 -0
  11. package/apps/server/dist/gateway/chat-sync.js +135 -0
  12. package/apps/server/dist/gateway/command-router.js +116 -0
  13. package/apps/server/dist/gateway/commands/cancel.js +32 -0
  14. package/apps/server/dist/gateway/commands/help.js +16 -0
  15. package/apps/server/dist/gateway/commands/index.js +26 -0
  16. package/apps/server/dist/gateway/commands/restart.js +43 -0
  17. package/apps/server/dist/gateway/commands/status.js +34 -0
  18. package/apps/server/dist/gateway/commands/tasks.js +33 -0
  19. package/apps/server/dist/gateway/feishu-sender.js +508 -0
  20. package/apps/server/dist/gateway/feishu-ws.js +353 -0
  21. package/apps/server/dist/gateway/health-monitor.js +154 -0
  22. package/apps/server/dist/gateway/http.js +1064 -0
  23. package/apps/server/dist/gateway/media-downloader.js +182 -0
  24. package/apps/server/dist/gateway/message-events.js +10 -0
  25. package/apps/server/dist/gateway/message-intake.js +72 -0
  26. package/apps/server/dist/gateway/message-queue.js +118 -0
  27. package/apps/server/dist/gateway/session-reader.js +142 -0
  28. package/apps/server/dist/gateway/ws-push.js +115 -0
  29. package/apps/server/dist/loid/brain.js +121 -0
  30. package/apps/server/dist/loid/clarifier.js +162 -0
  31. package/apps/server/dist/loid/context-builder.js +462 -0
  32. package/apps/server/dist/loid/mcp-server.js +119 -0
  33. package/apps/server/dist/loid/memory-settler.js +189 -0
  34. package/apps/server/dist/loid/opportunity-manager.js +148 -0
  35. package/apps/server/dist/loid/profile-updater.js +179 -0
  36. package/apps/server/dist/loid/project-registry.js +192 -0
  37. package/apps/server/dist/loid/reporter.js +148 -0
  38. package/apps/server/dist/loid/schemas.js +117 -0
  39. package/apps/server/dist/loid/self-calibrator.js +314 -0
  40. package/apps/server/dist/loid/session-manager.js +472 -0
  41. package/apps/server/dist/loid/session.js +276 -0
  42. package/apps/server/dist/main.js +528 -0
  43. package/apps/server/dist/tracing/index.js +2 -0
  44. package/apps/server/dist/tracing/trace-context.js +92 -0
  45. package/apps/server/dist/types/message.js +2 -0
  46. package/apps/server/dist/yor/yor-mcp-server.js +107 -0
  47. package/apps/server/dist/yor/yor-orchestrator.js +248 -0
  48. package/apps/web/dist/assets/index-BiiEB0qZ.css +1 -0
  49. package/apps/web/dist/assets/index-Dnb9LGZd.js +798 -0
  50. package/apps/web/dist/index.html +13 -0
  51. package/package.json +42 -0
  52. package/packages/cc-client/dist/claude-code-backend.js +792 -0
  53. package/packages/cc-client/dist/index.js +2 -0
  54. package/packages/cc-client/package.json +11 -0
  55. package/packages/core/dist/constants.js +60 -0
  56. package/packages/core/dist/errors.js +35 -0
  57. package/packages/core/dist/index.js +9 -0
  58. package/packages/core/dist/office-init.js +190 -0
  59. package/packages/core/dist/repo-cache.js +70 -0
  60. package/packages/core/dist/scope/checker.js +114 -0
  61. package/packages/core/dist/scope/defaults.js +55 -0
  62. package/packages/core/dist/scope/index.js +3 -0
  63. package/packages/core/dist/state-machine.js +86 -0
  64. package/packages/core/dist/types/audit.js +12 -0
  65. package/packages/core/dist/types/backend.js +2 -0
  66. package/packages/core/dist/types/commitment.js +17 -0
  67. package/packages/core/dist/types/communication.js +18 -0
  68. package/packages/core/dist/types/index.js +9 -0
  69. package/packages/core/dist/types/opportunity.js +27 -0
  70. package/packages/core/dist/types/org.js +26 -0
  71. package/packages/core/dist/types/task.js +46 -0
  72. package/packages/core/dist/types/workspace.js +39 -0
  73. package/packages/core/dist/workspace-manager.js +314 -0
  74. package/packages/core/package.json +10 -0
  75. package/packages/db/dist/client.js +69 -0
  76. package/packages/db/dist/index.js +756 -0
  77. package/packages/db/dist/schema/audit-events.js +13 -0
  78. package/packages/db/dist/schema/cc-sessions.js +14 -0
  79. package/packages/db/dist/schema/chats.js +35 -0
  80. package/packages/db/dist/schema/commitments.js +18 -0
  81. package/packages/db/dist/schema/communication-events.js +14 -0
  82. package/packages/db/dist/schema/index.js +14 -0
  83. package/packages/db/dist/schema/message-log.js +20 -0
  84. package/packages/db/dist/schema/opportunities.js +23 -0
  85. package/packages/db/dist/schema/org.js +36 -0
  86. package/packages/db/dist/schema/projects.js +23 -0
  87. package/packages/db/dist/schema/tasks.js +51 -0
  88. package/packages/db/dist/schema/topics.js +22 -0
  89. package/packages/db/dist/schema/trace-spans.js +19 -0
  90. package/packages/db/dist/schema/workspaces.js +15 -0
  91. package/packages/db/package.json +12 -0
  92. package/packages/db/src/migrations/0000_baseline.sql +251 -0
  93. package/packages/db/src/migrations/0001_workspaces.sql +19 -0
  94. package/packages/db/src/migrations/0002_workspace_parent.sql +1 -0
  95. package/packages/db/src/migrations/0003_chat_context.sql +3 -0
  96. package/packages/db/src/migrations/meta/_journal.json +34 -0
  97. package/packages/mcp-tools/dist/index.js +41 -0
  98. package/packages/mcp-tools/dist/layer1/audit-append.js +38 -0
  99. package/packages/mcp-tools/dist/layer1/audit-query.js +51 -0
  100. package/packages/mcp-tools/dist/layer1/memory-brief.js +168 -0
  101. package/packages/mcp-tools/dist/layer1/memory-context.js +124 -0
  102. package/packages/mcp-tools/dist/layer1/memory-digest.js +126 -0
  103. package/packages/mcp-tools/dist/layer1/memory-forget.js +108 -0
  104. package/packages/mcp-tools/dist/layer1/memory-learn.js +63 -0
  105. package/packages/mcp-tools/dist/layer1/memory-recall.js +287 -0
  106. package/packages/mcp-tools/dist/layer1/memory-reflect.js +80 -0
  107. package/packages/mcp-tools/dist/layer1/memory-remember.js +119 -0
  108. package/packages/mcp-tools/dist/layer1/memory-search.js +263 -0
  109. package/packages/mcp-tools/dist/layer1/memory-write.js +21 -0
  110. package/packages/mcp-tools/dist/layer1/org-lookup.js +47 -0
  111. package/packages/mcp-tools/dist/layer1/project-get.js +28 -0
  112. package/packages/mcp-tools/dist/layer1/project-list.js +20 -0
  113. package/packages/mcp-tools/dist/layer1/report-daily.js +68 -0
  114. package/packages/mcp-tools/dist/layer1/task-get.js +29 -0
  115. package/packages/mcp-tools/dist/layer1/task-update.js +34 -0
  116. package/packages/mcp-tools/dist/layer2/franky/topic-checkpoint.js +43 -0
  117. package/packages/mcp-tools/dist/layer2/franky/topic-escalate.js +19 -0
  118. package/packages/mcp-tools/dist/layer2/loid/decision-log.js +15 -0
  119. package/packages/mcp-tools/dist/layer2/loid/decision-no-action.js +15 -0
  120. package/packages/mcp-tools/dist/layer2/loid/delivery-create-pr.js +30 -0
  121. package/packages/mcp-tools/dist/layer2/loid/delivery-share.js +12 -0
  122. package/packages/mcp-tools/dist/layer2/loid/delivery-submit.js +77 -0
  123. package/packages/mcp-tools/dist/layer2/loid/delivery-upload.js +18 -0
  124. package/packages/mcp-tools/dist/layer2/loid/project-remove.js +16 -0
  125. package/packages/mcp-tools/dist/layer2/loid/project-upsert.js +33 -0
  126. package/packages/mcp-tools/dist/layer2/loid/task-dispatch.js +206 -0
  127. package/packages/mcp-tools/dist/layer2/loid/task-escalate-to-topic.js +170 -0
  128. package/packages/mcp-tools/dist/layer2/loid/task-lookup.js +45 -0
  129. package/packages/mcp-tools/dist/layer2/loid/topic-close.js +22 -0
  130. package/packages/mcp-tools/dist/layer2/loid/topic-create.js +60 -0
  131. package/packages/mcp-tools/dist/layer2/loid/yor-approve.js +8 -0
  132. package/packages/mcp-tools/dist/layer2/loid/yor-kill.js +7 -0
  133. package/packages/mcp-tools/dist/layer2/loid/yor-rework.js +7 -0
  134. package/packages/mcp-tools/dist/layer2/loid/yor-spawn.js +28 -0
  135. package/packages/mcp-tools/dist/layer2/loid/yor-status.js +8 -0
  136. package/packages/mcp-tools/dist/layer2/yor/task-block.js +11 -0
  137. package/packages/mcp-tools/dist/layer2/yor/task-deliver.js +35 -0
  138. package/packages/mcp-tools/dist/layer2/yor/task-progress.js +21 -0
  139. package/packages/mcp-tools/dist/layer3/adapters/feishu-adapter.js +203 -0
  140. package/packages/mcp-tools/dist/layer3/adapters/types.js +28 -0
  141. package/packages/mcp-tools/dist/layer3/channel-receive.js +11 -0
  142. package/packages/mcp-tools/dist/layer3/channel-send.js +75 -0
  143. package/packages/mcp-tools/dist/layer3/file-upload.js +44 -0
  144. package/packages/mcp-tools/dist/registry.js +911 -0
  145. 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