team-anya-cli 0.1.8 → 1.0.1
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 +1 -37
- package/package.json +6 -37
- package/anya/prompts/execution-guides/git-delivery.md +0 -38
- package/anya/prompts/execution-guides/testing-and-self-heal.md +0 -28
- package/anya/prompts/protocols/brief-assembly.md +0 -55
- package/anya/prompts/protocols/report.md +0 -175
- package/anya/prompts/protocols/review.md +0 -90
- package/anya/prompts/task-claude-md.template.md +0 -32
- package/apps/server/dist/broker/cc-broker.js +0 -261
- package/apps/server/dist/cli.js +0 -296
- package/apps/server/dist/config.js +0 -76
- package/apps/server/dist/daemon.js +0 -51
- package/apps/server/dist/franky/context-builder.js +0 -160
- package/apps/server/dist/franky/franky-mcp-server.js +0 -107
- package/apps/server/dist/franky/franky-orchestrator.js +0 -450
- package/apps/server/dist/franky/index.js +0 -5
- package/apps/server/dist/franky/topic-router.js +0 -16
- package/apps/server/dist/gateway/chat-sync.js +0 -135
- package/apps/server/dist/gateway/command-router.js +0 -114
- package/apps/server/dist/gateway/commands/cancel.js +0 -32
- package/apps/server/dist/gateway/commands/help.js +0 -16
- package/apps/server/dist/gateway/commands/index.js +0 -26
- package/apps/server/dist/gateway/commands/restart.js +0 -34
- package/apps/server/dist/gateway/commands/status.js +0 -34
- package/apps/server/dist/gateway/commands/tasks.js +0 -33
- package/apps/server/dist/gateway/feishu-sender.js +0 -410
- package/apps/server/dist/gateway/feishu-ws.js +0 -256
- package/apps/server/dist/gateway/http.js +0 -1019
- package/apps/server/dist/gateway/media-downloader.js +0 -149
- package/apps/server/dist/gateway/message-events.js +0 -10
- package/apps/server/dist/gateway/message-intake.js +0 -67
- package/apps/server/dist/gateway/message-queue.js +0 -118
- package/apps/server/dist/gateway/session-reader.js +0 -142
- package/apps/server/dist/gateway/ws-push.js +0 -115
- package/apps/server/dist/loid/brain.js +0 -105
- package/apps/server/dist/loid/clarifier.js +0 -162
- package/apps/server/dist/loid/context-builder.js +0 -413
- package/apps/server/dist/loid/mcp-server.js +0 -106
- package/apps/server/dist/loid/memory-settler.js +0 -189
- package/apps/server/dist/loid/opportunity-manager.js +0 -148
- package/apps/server/dist/loid/profile-updater.js +0 -179
- package/apps/server/dist/loid/reporter.js +0 -148
- package/apps/server/dist/loid/schemas.js +0 -117
- package/apps/server/dist/loid/self-calibrator.js +0 -314
- package/apps/server/dist/loid/session-manager.js +0 -301
- package/apps/server/dist/loid/session.js +0 -271
- package/apps/server/dist/loid/worktree-manager.js +0 -191
- package/apps/server/dist/main.js +0 -393
- package/apps/server/dist/tracing/index.js +0 -2
- package/apps/server/dist/tracing/trace-context.js +0 -92
- package/apps/server/dist/types/message.js +0 -2
- package/apps/server/dist/yor/yor-mcp-server.js +0 -104
- package/apps/server/dist/yor/yor-orchestrator.js +0 -233
- package/apps/web/dist/assets/index-BiiEB0qZ.css +0 -1
- package/apps/web/dist/assets/index-D1AK5ZEE.js +0 -798
- package/apps/web/dist/index.html +0 -13
- package/packages/cc-client/dist/claude-code-backend.js +0 -664
- package/packages/cc-client/dist/index.js +0 -2
- package/packages/cc-client/package.json +0 -11
- package/packages/core/dist/constants.js +0 -59
- package/packages/core/dist/errors.js +0 -35
- package/packages/core/dist/index.js +0 -7
- package/packages/core/dist/office-init.js +0 -101
- package/packages/core/dist/scope/checker.js +0 -114
- package/packages/core/dist/scope/defaults.js +0 -55
- package/packages/core/dist/scope/index.js +0 -3
- package/packages/core/dist/state-machine.js +0 -85
- package/packages/core/dist/types/audit.js +0 -12
- package/packages/core/dist/types/backend.js +0 -2
- package/packages/core/dist/types/commitment.js +0 -17
- package/packages/core/dist/types/communication.js +0 -18
- package/packages/core/dist/types/index.js +0 -8
- package/packages/core/dist/types/opportunity.js +0 -27
- package/packages/core/dist/types/org.js +0 -26
- package/packages/core/dist/types/task.js +0 -46
- package/packages/core/package.json +0 -10
- package/packages/db/dist/client.js +0 -69
- package/packages/db/dist/index.js +0 -691
- package/packages/db/dist/schema/audit-events.js +0 -13
- package/packages/db/dist/schema/cc-sessions.js +0 -14
- package/packages/db/dist/schema/chats.js +0 -33
- package/packages/db/dist/schema/commitments.js +0 -18
- package/packages/db/dist/schema/communication-events.js +0 -14
- package/packages/db/dist/schema/index.js +0 -13
- package/packages/db/dist/schema/message-log.js +0 -20
- package/packages/db/dist/schema/opportunities.js +0 -23
- package/packages/db/dist/schema/org.js +0 -36
- package/packages/db/dist/schema/projects.js +0 -23
- package/packages/db/dist/schema/tasks.js +0 -48
- package/packages/db/dist/schema/topics.js +0 -20
- package/packages/db/dist/schema/trace-spans.js +0 -19
- package/packages/db/package.json +0 -12
- package/packages/db/src/migrations/0000_baseline.sql +0 -251
- package/packages/db/src/migrations/meta/_journal.json +0 -13
- package/packages/mcp-tools/dist/index.js +0 -41
- package/packages/mcp-tools/dist/layer1/audit-append.js +0 -38
- package/packages/mcp-tools/dist/layer1/audit-query.js +0 -51
- package/packages/mcp-tools/dist/layer1/memory-brief.js +0 -168
- package/packages/mcp-tools/dist/layer1/memory-context.js +0 -124
- package/packages/mcp-tools/dist/layer1/memory-digest.js +0 -126
- package/packages/mcp-tools/dist/layer1/memory-forget.js +0 -108
- package/packages/mcp-tools/dist/layer1/memory-learn.js +0 -63
- package/packages/mcp-tools/dist/layer1/memory-recall.js +0 -287
- package/packages/mcp-tools/dist/layer1/memory-reflect.js +0 -80
- package/packages/mcp-tools/dist/layer1/memory-remember.js +0 -119
- package/packages/mcp-tools/dist/layer1/memory-search.js +0 -263
- package/packages/mcp-tools/dist/layer1/memory-write.js +0 -21
- package/packages/mcp-tools/dist/layer1/org-lookup.js +0 -47
- package/packages/mcp-tools/dist/layer1/project-get.js +0 -28
- package/packages/mcp-tools/dist/layer1/project-list.js +0 -20
- package/packages/mcp-tools/dist/layer1/report-daily.js +0 -68
- package/packages/mcp-tools/dist/layer1/task-get.js +0 -29
- package/packages/mcp-tools/dist/layer1/task-update.js +0 -34
- package/packages/mcp-tools/dist/layer2/franky/topic-checkpoint.js +0 -43
- package/packages/mcp-tools/dist/layer2/franky/topic-escalate.js +0 -19
- package/packages/mcp-tools/dist/layer2/loid/decision-log.js +0 -15
- package/packages/mcp-tools/dist/layer2/loid/decision-no-action.js +0 -15
- package/packages/mcp-tools/dist/layer2/loid/delivery-create-pr.js +0 -30
- package/packages/mcp-tools/dist/layer2/loid/delivery-share.js +0 -12
- package/packages/mcp-tools/dist/layer2/loid/delivery-submit.js +0 -77
- package/packages/mcp-tools/dist/layer2/loid/delivery-upload.js +0 -18
- package/packages/mcp-tools/dist/layer2/loid/project-remove.js +0 -16
- package/packages/mcp-tools/dist/layer2/loid/project-upsert.js +0 -33
- package/packages/mcp-tools/dist/layer2/loid/task-dispatch.js +0 -196
- package/packages/mcp-tools/dist/layer2/loid/task-lookup.js +0 -38
- package/packages/mcp-tools/dist/layer2/loid/topic-close.js +0 -22
- package/packages/mcp-tools/dist/layer2/loid/topic-create.js +0 -56
- package/packages/mcp-tools/dist/layer2/loid/yor-approve.js +0 -8
- package/packages/mcp-tools/dist/layer2/loid/yor-kill.js +0 -7
- package/packages/mcp-tools/dist/layer2/loid/yor-rework.js +0 -7
- package/packages/mcp-tools/dist/layer2/loid/yor-spawn.js +0 -15
- package/packages/mcp-tools/dist/layer2/loid/yor-status.js +0 -8
- package/packages/mcp-tools/dist/layer2/yor/task-block.js +0 -11
- package/packages/mcp-tools/dist/layer2/yor/task-deliver.js +0 -35
- package/packages/mcp-tools/dist/layer2/yor/task-progress.js +0 -21
- package/packages/mcp-tools/dist/layer3/adapters/feishu-adapter.js +0 -192
- package/packages/mcp-tools/dist/layer3/adapters/types.js +0 -28
- package/packages/mcp-tools/dist/layer3/channel-receive.js +0 -11
- package/packages/mcp-tools/dist/layer3/channel-send.js +0 -91
- package/packages/mcp-tools/dist/layer3/file-upload.js +0 -44
- package/packages/mcp-tools/dist/registry.js +0 -871
- package/packages/mcp-tools/package.json +0 -13
- package/workspace/.claude/settings.local.json +0 -9
- package/workspace/.mcp.json +0 -12
- package/workspace/CHARTER.md +0 -76
- package/workspace/CLAUDE.md +0 -58
- package/workspace/PROTOCOL.md +0 -160
- package/workspace/TOOLS.md +0 -470
- package/workspace/audit/.gitkeep +0 -0
- package/workspace/franky/CLAUDE.md +0 -37
- package/workspace/franky/PLAYBOOK.md +0 -215
- package/workspace/franky/PROFILE.md +0 -80
- package/workspace/loid/CLAUDE.md +0 -12
- package/workspace/loid/PLAYBOOK.md +0 -198
- package/workspace/loid/PROFILE.md +0 -78
- package/workspace/memory/commitments/.gitkeep +0 -0
- package/workspace/memory/execution/.gitkeep +0 -0
- package/workspace/memory/people/.gitkeep +0 -0
- package/workspace/memory/projects/.gitkeep +0 -0
- package/workspace/memory/self/.gitkeep +0 -0
- package/workspace/reference/identity/.gitkeep +0 -0
- package/workspace/reference/org/escalation.yaml +0 -24
- package/workspace/reference/org/ownership.yaml +0 -28
- package/workspace/reports/.gitkeep +0 -0
- package/workspace/yor/CLAUDE.md +0 -22
- package/workspace/yor/PLAYBOOK.md +0 -73
- package/workspace/yor/PROFILE.md +0 -52
- package/workspace/yor/SELF-HEAL.md +0 -39
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
import { execFile as execFileCb } from 'node:child_process';
|
|
2
|
-
import { promisify } from 'node:util';
|
|
3
|
-
import { updateTask, insertAuditEvent, getTask } from '@team-anya/db';
|
|
4
|
-
const execFile = promisify(execFileCb);
|
|
5
|
-
export async function deliverySubmit(deps, input) {
|
|
6
|
-
const { db, logger } = deps;
|
|
7
|
-
// 确定平台:通过任务的 project_id 查项目配置
|
|
8
|
-
const task = getTask(db, input.task_id);
|
|
9
|
-
let platform = 'local';
|
|
10
|
-
if (task?.project_id && deps.getProjectConfig) {
|
|
11
|
-
const config = await deps.getProjectConfig(task.project_id);
|
|
12
|
-
platform = config.platform;
|
|
13
|
-
}
|
|
14
|
-
logger?.info(`[anya:pipeline] [Loid] delivery.submit ${input.task_id} | platform=${platform} title="${input.title}"`);
|
|
15
|
-
switch (platform) {
|
|
16
|
-
case 'github': {
|
|
17
|
-
const args = ['pr', 'create', '--title', input.title, '--body', input.description];
|
|
18
|
-
if (input.base_branch) {
|
|
19
|
-
args.push('--base', input.base_branch);
|
|
20
|
-
}
|
|
21
|
-
const { stdout } = await execFile('gh', args, { cwd: input.working_dir });
|
|
22
|
-
const prUrl = stdout.trim();
|
|
23
|
-
updateTask(db, input.task_id, { pr_url: prUrl });
|
|
24
|
-
insertAuditEvent(db, {
|
|
25
|
-
event_type: 'pr_created',
|
|
26
|
-
actor: 'loid',
|
|
27
|
-
task_id: input.task_id,
|
|
28
|
-
summary: `GitHub PR 已创建: ${input.title}`,
|
|
29
|
-
detail: JSON.stringify({ pr_url: prUrl, base_branch: input.base_branch, platform }),
|
|
30
|
-
});
|
|
31
|
-
return { task_id: input.task_id, pr_url: prUrl, platform };
|
|
32
|
-
}
|
|
33
|
-
case 'gitlab': {
|
|
34
|
-
const args = [
|
|
35
|
-
'mr', 'create',
|
|
36
|
-
'--title', input.title,
|
|
37
|
-
'--description', input.description,
|
|
38
|
-
'--yes',
|
|
39
|
-
];
|
|
40
|
-
if (input.base_branch) {
|
|
41
|
-
args.push('--target-branch', input.base_branch);
|
|
42
|
-
}
|
|
43
|
-
const { stdout } = await execFile('glab', args, { cwd: input.working_dir });
|
|
44
|
-
// glab 输出格式:通常包含 MR URL
|
|
45
|
-
const mrUrl = stdout.trim().split('\n').pop() ?? stdout.trim();
|
|
46
|
-
updateTask(db, input.task_id, { pr_url: mrUrl });
|
|
47
|
-
insertAuditEvent(db, {
|
|
48
|
-
event_type: 'mr_created',
|
|
49
|
-
actor: 'loid',
|
|
50
|
-
task_id: input.task_id,
|
|
51
|
-
summary: `GitLab MR 已创建: ${input.title}`,
|
|
52
|
-
detail: JSON.stringify({ mr_url: mrUrl, base_branch: input.base_branch, platform }),
|
|
53
|
-
});
|
|
54
|
-
return { task_id: input.task_id, pr_url: mrUrl, platform };
|
|
55
|
-
}
|
|
56
|
-
case 'local': {
|
|
57
|
-
// 纯本地任务,记录最终 commit hash
|
|
58
|
-
let commitHash = 'unknown';
|
|
59
|
-
try {
|
|
60
|
-
const { stdout } = await execFile('git', ['-C', input.working_dir, 'log', '-1', '--format=%H']);
|
|
61
|
-
commitHash = stdout.trim();
|
|
62
|
-
}
|
|
63
|
-
catch {
|
|
64
|
-
// git 命令失败,忽略
|
|
65
|
-
}
|
|
66
|
-
insertAuditEvent(db, {
|
|
67
|
-
event_type: 'delivery_local',
|
|
68
|
-
actor: 'loid',
|
|
69
|
-
task_id: input.task_id,
|
|
70
|
-
summary: `本地交付完成: ${input.title}`,
|
|
71
|
-
detail: JSON.stringify({ commit_hash: commitHash, platform }),
|
|
72
|
-
});
|
|
73
|
-
return { task_id: input.task_id, commit_hash: commitHash, platform };
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
//# sourceMappingURL=delivery-submit.js.map
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { fileUpload } from '../../layer3/file-upload.js';
|
|
2
|
-
/**
|
|
3
|
-
* delivery.upload - 上传文件产物
|
|
4
|
-
*
|
|
5
|
-
* 委托给 file.upload 实现。target 参数暂不使用(预留给后续上传到指定位置的场景)。
|
|
6
|
-
*/
|
|
7
|
-
export async function deliveryUpload(deps, input) {
|
|
8
|
-
const result = await fileUpload(deps, {
|
|
9
|
-
file_path: input.file_path,
|
|
10
|
-
});
|
|
11
|
-
return {
|
|
12
|
-
status: 'uploaded',
|
|
13
|
-
url: result.url,
|
|
14
|
-
file_name: result.file_name,
|
|
15
|
-
file_size: result.file_size,
|
|
16
|
-
};
|
|
17
|
-
}
|
|
18
|
-
//# sourceMappingURL=delivery-upload.js.map
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { getProject, softDeleteProject, insertAuditEvent } from '@team-anya/db';
|
|
2
|
-
export async function projectRemove(db, _workspacePath, input) {
|
|
3
|
-
const existing = getProject(db, input.project_id);
|
|
4
|
-
if (!existing) {
|
|
5
|
-
return { removed: false, message: `Project ${input.project_id} not found` };
|
|
6
|
-
}
|
|
7
|
-
softDeleteProject(db, input.project_id);
|
|
8
|
-
insertAuditEvent(db, {
|
|
9
|
-
event_type: 'project_removed',
|
|
10
|
-
actor: 'loid',
|
|
11
|
-
summary: `Project ${input.project_id} soft-deleted: ${input.reason}`,
|
|
12
|
-
detail: JSON.stringify({ project_id: input.project_id, reason: input.reason }),
|
|
13
|
-
});
|
|
14
|
-
return { removed: true, message: `Project ${input.project_id} archived` };
|
|
15
|
-
}
|
|
16
|
-
//# sourceMappingURL=project-remove.js.map
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { getProject, upsertProject, syncProjectRepos, insertAuditEvent } from '@team-anya/db';
|
|
2
|
-
export async function projectUpsert(db, _workspacePath, input) {
|
|
3
|
-
const existing = getProject(db, input.project_id);
|
|
4
|
-
const action = existing ? 'updated' : 'created';
|
|
5
|
-
upsertProject(db, {
|
|
6
|
-
project_id: input.project_id,
|
|
7
|
-
name: input.name,
|
|
8
|
-
description: input.description ?? null,
|
|
9
|
-
platform: input.platform ?? 'github',
|
|
10
|
-
claude_md: input.claude_md ?? null,
|
|
11
|
-
});
|
|
12
|
-
const repos = input.repos ?? [];
|
|
13
|
-
if (repos.length > 0) {
|
|
14
|
-
syncProjectRepos(db, input.project_id, repos.map(r => ({
|
|
15
|
-
name: r.name,
|
|
16
|
-
git_url: r.git_url,
|
|
17
|
-
repo_path: r.repo_path,
|
|
18
|
-
default_branch: r.default_branch ?? 'main',
|
|
19
|
-
})));
|
|
20
|
-
}
|
|
21
|
-
insertAuditEvent(db, {
|
|
22
|
-
event_type: `project_${action}`,
|
|
23
|
-
actor: 'loid',
|
|
24
|
-
summary: `Project ${input.project_id} ${action}`,
|
|
25
|
-
detail: JSON.stringify({
|
|
26
|
-
project_id: input.project_id,
|
|
27
|
-
platform: input.platform ?? 'github',
|
|
28
|
-
repo_count: repos.length,
|
|
29
|
-
}),
|
|
30
|
-
});
|
|
31
|
-
return { project_id: input.project_id, action };
|
|
32
|
-
}
|
|
33
|
-
//# sourceMappingURL=project-upsert.js.map
|
|
@@ -1,196 +0,0 @@
|
|
|
1
|
-
import { writeFile, mkdir } from 'node:fs/promises';
|
|
2
|
-
import { execFile as execFileCb } from 'node:child_process';
|
|
3
|
-
import { join } from 'node:path';
|
|
4
|
-
import { promisify } from 'node:util';
|
|
5
|
-
import { createTask, updateTask, insertAuditEvent, getTodayMaxSequence, } from '@team-anya/db';
|
|
6
|
-
import { TaskStatus, generateTaskId, assertTransition } from '@team-anya/core';
|
|
7
|
-
const execFile = promisify(execFileCb);
|
|
8
|
-
/**
|
|
9
|
-
* 创建任务、写 brief、自动准备工作区
|
|
10
|
-
*
|
|
11
|
-
* 派工两步走:task.dispatch(MCP) → yor.spawn(MCP)
|
|
12
|
-
* dispatch 内部自动根据 project mode 准备隔离工作区(git worktree / mkdir)。
|
|
13
|
-
* 工作区准备失败时标记 BLOCKED 并返回 error,不抛异常。
|
|
14
|
-
*/
|
|
15
|
-
export async function taskDispatch(deps, input) {
|
|
16
|
-
const { db, workspacePath, logger } = deps;
|
|
17
|
-
const seq = getTodayMaxSequence(db) + 1;
|
|
18
|
-
const taskId = generateTaskId(seq);
|
|
19
|
-
// 1. 创建任务
|
|
20
|
-
createTask(db, {
|
|
21
|
-
task_id: taskId,
|
|
22
|
-
title: input.title,
|
|
23
|
-
status: TaskStatus.NEW,
|
|
24
|
-
source_type: 'feishu',
|
|
25
|
-
source_ref: input.source_message_id ?? null,
|
|
26
|
-
objective: input.objective,
|
|
27
|
-
acceptance_criteria: input.acceptance_criteria ? JSON.stringify(input.acceptance_criteria) : undefined,
|
|
28
|
-
context: input.context,
|
|
29
|
-
project_id: input.project_id,
|
|
30
|
-
created_by: input.created_by ?? null,
|
|
31
|
-
source_chat_id: input.source_chat_id ?? null,
|
|
32
|
-
});
|
|
33
|
-
// 2. 写 brief 到 workspace
|
|
34
|
-
const taskDir = join(workspacePath, 'yor', 'tasks', taskId);
|
|
35
|
-
await mkdir(taskDir, { recursive: true });
|
|
36
|
-
const briefPath = join(taskDir, 'brief.md');
|
|
37
|
-
await writeFile(briefPath, input.brief, 'utf-8');
|
|
38
|
-
// 3. 审计日志
|
|
39
|
-
insertAuditEvent(db, {
|
|
40
|
-
event_type: 'task_dispatched',
|
|
41
|
-
actor: 'loid',
|
|
42
|
-
task_id: taskId,
|
|
43
|
-
summary: `Loid 派工: ${input.title}`,
|
|
44
|
-
detail: JSON.stringify({ brief_length: input.brief.length, project: input.project_id }),
|
|
45
|
-
});
|
|
46
|
-
// 4. 获取项目配置
|
|
47
|
-
const project = deps.getProjectConfig
|
|
48
|
-
? await deps.getProjectConfig(input.project_id)
|
|
49
|
-
: undefined;
|
|
50
|
-
// 传了 project_id 但未在注册表中找到 → 直接 BLOCKED,不静默降级为 adhoc
|
|
51
|
-
if (input.project_id && project?.mode === 'adhoc') {
|
|
52
|
-
logger?.info(`[anya:pipeline] [Loid] 创建任务 ${taskId} "${input.title}" | project=${input.project_id} 未注册,BLOCKED`);
|
|
53
|
-
assertTransition(TaskStatus.NEW, TaskStatus.BLOCKED);
|
|
54
|
-
updateTask(db, taskId, { status: TaskStatus.BLOCKED });
|
|
55
|
-
insertAuditEvent(db, {
|
|
56
|
-
event_type: 'task_status_changed',
|
|
57
|
-
actor: 'loid',
|
|
58
|
-
task_id: taskId,
|
|
59
|
-
summary: `NEW → BLOCKED: 项目 "${input.project_id}" 未在注册表中找到,请先通过 project.upsert 注册`,
|
|
60
|
-
detail: JSON.stringify({ from: 'NEW', to: 'BLOCKED', reason: 'project_not_found', project_id: input.project_id }),
|
|
61
|
-
});
|
|
62
|
-
return {
|
|
63
|
-
task_id: taskId,
|
|
64
|
-
status: 'blocked',
|
|
65
|
-
brief_path: briefPath,
|
|
66
|
-
error: `项目 "${input.project_id}" 未在注册表中找到。请先调用 project.upsert 注册项目及其仓库配置,然后重新派工。`,
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
logger?.info(`[anya:pipeline] [Loid] 创建任务 ${taskId} "${input.title}"${input.project_id ? ` | project=${input.project_id} mode=${project?.mode}` : ''}`);
|
|
70
|
-
// 5. 自动准备工作区
|
|
71
|
-
const workspaceResult = await prepareWorkspace(taskId, taskDir, project, logger);
|
|
72
|
-
if (!workspaceResult.ok) {
|
|
73
|
-
// 工作区准备失败 → NEW → BLOCKED(经状态机校验)
|
|
74
|
-
assertTransition(TaskStatus.NEW, TaskStatus.BLOCKED);
|
|
75
|
-
updateTask(db, taskId, { status: TaskStatus.BLOCKED });
|
|
76
|
-
insertAuditEvent(db, {
|
|
77
|
-
event_type: 'task_status_changed',
|
|
78
|
-
actor: 'loid',
|
|
79
|
-
task_id: taskId,
|
|
80
|
-
summary: `NEW → BLOCKED: 工作区准备失败: ${workspaceResult.error}`,
|
|
81
|
-
detail: JSON.stringify({ from: 'NEW', to: 'BLOCKED', reason: workspaceResult.error }),
|
|
82
|
-
});
|
|
83
|
-
return { task_id: taskId, status: 'blocked', brief_path: briefPath, error: workspaceResult.error };
|
|
84
|
-
}
|
|
85
|
-
// 6. 工作区就绪 → NEW → READY,同时回写工作区信息
|
|
86
|
-
assertTransition(TaskStatus.NEW, TaskStatus.READY);
|
|
87
|
-
const branchName = project?.mode === 'project' ? `feat/anya-${taskId}` : undefined;
|
|
88
|
-
updateTask(db, taskId, {
|
|
89
|
-
status: TaskStatus.READY,
|
|
90
|
-
workspace_path: workspaceResult.workingDir,
|
|
91
|
-
assignee: 'yor',
|
|
92
|
-
...(branchName ? { branch: branchName } : {}),
|
|
93
|
-
});
|
|
94
|
-
insertAuditEvent(db, {
|
|
95
|
-
event_type: 'task_status_changed',
|
|
96
|
-
actor: 'loid',
|
|
97
|
-
task_id: taskId,
|
|
98
|
-
summary: 'NEW → READY: 工作区准备完成',
|
|
99
|
-
detail: JSON.stringify({ from: 'NEW', to: 'READY', workspace_path: workspaceResult.workingDir, branch: branchName }),
|
|
100
|
-
});
|
|
101
|
-
return { task_id: taskId, status: 'dispatched', brief_path: briefPath, working_dir: workspaceResult.workingDir };
|
|
102
|
-
}
|
|
103
|
-
async function prepareWorkspace(taskId, taskDir, project, logger) {
|
|
104
|
-
const mode = project?.mode ?? 'adhoc';
|
|
105
|
-
try {
|
|
106
|
-
switch (mode) {
|
|
107
|
-
case 'project': {
|
|
108
|
-
const repos = project.repos;
|
|
109
|
-
const workingDir = taskDir;
|
|
110
|
-
const createdWorktrees = [];
|
|
111
|
-
try {
|
|
112
|
-
for (const repo of repos) {
|
|
113
|
-
const defaultBranch = repo.default_branch ?? 'main';
|
|
114
|
-
const wtPath = join(workingDir, repo.name);
|
|
115
|
-
await execFile('git', ['-C', repo.repo_path, 'fetch', 'origin']);
|
|
116
|
-
await execFile('git', ['-C', repo.repo_path, 'worktree', 'add', wtPath, '-b', `feat/anya-${taskId}`, `origin/${defaultBranch}`]);
|
|
117
|
-
createdWorktrees.push({ repoPath: repo.repo_path, wtPath });
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
catch (err) {
|
|
121
|
-
// 回滚已创建的 worktree
|
|
122
|
-
for (const wt of createdWorktrees) {
|
|
123
|
-
try {
|
|
124
|
-
await execFile('git', ['-C', wt.repoPath, 'worktree', 'remove', wt.wtPath, '--force']);
|
|
125
|
-
}
|
|
126
|
-
catch {
|
|
127
|
-
// 回滚失败忽略
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
131
|
-
return { ok: false, error: `worktree 准备失败: ${msg}` };
|
|
132
|
-
}
|
|
133
|
-
// git init 为 CC 提供项目边界(防止全局搜索)
|
|
134
|
-
await execFile('git', ['init', workingDir]);
|
|
135
|
-
// .gitignore 忽略所有 worktree 子目录(它们各自有独立的 .git)
|
|
136
|
-
const ignoreContent = repos.map(r => `/${r.name}/`).join('\n') + '\n';
|
|
137
|
-
await writeFile(join(workingDir, '.gitignore'), ignoreContent, 'utf-8');
|
|
138
|
-
// 写入 CLAUDE.md 帮助 CC 理解工作区结构
|
|
139
|
-
const claudeMd = buildProjectClaudeMd(taskId, repos, project.claudeMd);
|
|
140
|
-
await writeFile(join(workingDir, 'CLAUDE.md'), claudeMd, 'utf-8');
|
|
141
|
-
// 提交到 git,否则 CC 不会加载 untracked 的 CLAUDE.md
|
|
142
|
-
await execFile('git', ['-C', workingDir, 'add', 'CLAUDE.md', '.gitignore']);
|
|
143
|
-
await execFile('git', ['-C', workingDir, 'commit', '-m', 'init: workspace config']);
|
|
144
|
-
logger?.info(`[anya:pipeline] [Loid] worktrees 已创建 (${repos.length} repos): ${workingDir}`);
|
|
145
|
-
return { ok: true, workingDir };
|
|
146
|
-
}
|
|
147
|
-
case 'adhoc':
|
|
148
|
-
default: {
|
|
149
|
-
const workingDir = taskDir;
|
|
150
|
-
await mkdir(join(workingDir, 'adhoc'), { recursive: true });
|
|
151
|
-
// 在任务级目录 git init,版本管理整个任务目录
|
|
152
|
-
await execFile('git', ['init', workingDir]);
|
|
153
|
-
await writeFile(join(workingDir, '.gitignore'), '*.tmp\nnode_modules/\n.DS_Store\n', 'utf-8');
|
|
154
|
-
await execFile('git', ['-C', workingDir, 'add', '.']);
|
|
155
|
-
await execFile('git', ['-C', workingDir, 'commit', '-m', `chore: init task ${taskId}`]);
|
|
156
|
-
logger?.info(`[anya:pipeline] [Loid] adhoc 目录已创建并 git init: ${workingDir}`);
|
|
157
|
-
return { ok: true, workingDir };
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
catch (err) {
|
|
162
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
163
|
-
return { ok: false, error: `工作区准备失败 (${mode}): ${msg}` };
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
// ── 工作区 CLAUDE.md 生成 ──
|
|
167
|
-
function buildProjectClaudeMd(taskId, repos, projectClaudeMd) {
|
|
168
|
-
const lines = [
|
|
169
|
-
`# 任务工作区 ${taskId}`,
|
|
170
|
-
'',
|
|
171
|
-
'本目录是任务工作区根目录。每个子目录是一个独立的 git worktree。',
|
|
172
|
-
'',
|
|
173
|
-
'## 仓库列表',
|
|
174
|
-
'',
|
|
175
|
-
'| 目录 | 分支 |',
|
|
176
|
-
'|------|------|',
|
|
177
|
-
];
|
|
178
|
-
for (const repo of repos) {
|
|
179
|
-
lines.push(`| \`${repo.name}/\` | \`feat/anya-${taskId}\` (基于 ${repo.default_branch}) |`);
|
|
180
|
-
}
|
|
181
|
-
lines.push('');
|
|
182
|
-
lines.push('## 重要');
|
|
183
|
-
lines.push('');
|
|
184
|
-
lines.push('- 每个子目录是独立的 git 仓库(worktree),搜索代码时请进入对应子目录');
|
|
185
|
-
lines.push('- git 操作(add/commit/push)必须在对应子目录内执行');
|
|
186
|
-
lines.push('- 不要在根目录执行 git commit');
|
|
187
|
-
lines.push('- 任务产物请读取 `brief.md` 了解详情');
|
|
188
|
-
if (projectClaudeMd) {
|
|
189
|
-
lines.push('');
|
|
190
|
-
lines.push('## 项目技术栈');
|
|
191
|
-
lines.push('');
|
|
192
|
-
lines.push(projectClaudeMd);
|
|
193
|
-
}
|
|
194
|
-
return lines.join('\n') + '\n';
|
|
195
|
-
}
|
|
196
|
-
//# sourceMappingURL=task-dispatch.js.map
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { getTask, getTasksByStatus } from '@team-anya/db';
|
|
2
|
-
import { TaskStatus } from '@team-anya/core';
|
|
3
|
-
/**
|
|
4
|
-
* 查询任务状态和历史
|
|
5
|
-
*
|
|
6
|
-
* 可按 task_id 或 status 过滤。不传参数时返回所有活跃任务。
|
|
7
|
-
*/
|
|
8
|
-
export async function taskLookup(db, input) {
|
|
9
|
-
let tasks;
|
|
10
|
-
if (input.task_id) {
|
|
11
|
-
const task = getTask(db, input.task_id);
|
|
12
|
-
tasks = task ? [task] : [];
|
|
13
|
-
}
|
|
14
|
-
else if (input.status) {
|
|
15
|
-
tasks = getTasksByStatus(db, input.status);
|
|
16
|
-
}
|
|
17
|
-
else {
|
|
18
|
-
// 默认返回活跃任务
|
|
19
|
-
tasks = [
|
|
20
|
-
...getTasksByStatus(db, TaskStatus.IN_PROGRESS),
|
|
21
|
-
...getTasksByStatus(db, TaskStatus.READY),
|
|
22
|
-
...getTasksByStatus(db, TaskStatus.NEED_CLARIFICATION),
|
|
23
|
-
...getTasksByStatus(db, TaskStatus.DELIVERING),
|
|
24
|
-
...getTasksByStatus(db, TaskStatus.BLOCKED),
|
|
25
|
-
];
|
|
26
|
-
}
|
|
27
|
-
return {
|
|
28
|
-
tasks: tasks.map(t => ({
|
|
29
|
-
task_id: t.task_id,
|
|
30
|
-
title: t.title,
|
|
31
|
-
status: t.status,
|
|
32
|
-
assignee: t.assignee,
|
|
33
|
-
created_at: t.created_at,
|
|
34
|
-
pr_url: t.pr_url ?? null,
|
|
35
|
-
})),
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
//# sourceMappingURL=task-lookup.js.map
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { getTopic, updateTopicStatus, insertAuditEvent, } from '@team-anya/db';
|
|
2
|
-
export async function topicClose(db, input, actor = 'loid') {
|
|
3
|
-
const topic = getTopic(db, input.topic_id);
|
|
4
|
-
if (!topic) {
|
|
5
|
-
return { closed: false, topic_id: input.topic_id, error: `专项 ${input.topic_id} 不存在` };
|
|
6
|
-
}
|
|
7
|
-
if (topic.status === 'closed') {
|
|
8
|
-
return { closed: false, topic_id: input.topic_id, error: `专项已处于 closed 状态` };
|
|
9
|
-
}
|
|
10
|
-
updateTopicStatus(db, input.topic_id, 'closed');
|
|
11
|
-
insertAuditEvent(db, {
|
|
12
|
-
event_type: 'topic_closed',
|
|
13
|
-
actor,
|
|
14
|
-
summary: `关闭专项「${topic.title}」(${input.topic_id})`,
|
|
15
|
-
detail: JSON.stringify({
|
|
16
|
-
topic_id: input.topic_id,
|
|
17
|
-
close_summary: input.summary,
|
|
18
|
-
}),
|
|
19
|
-
});
|
|
20
|
-
return { closed: true, topic_id: input.topic_id };
|
|
21
|
-
}
|
|
22
|
-
//# sourceMappingURL=topic-close.js.map
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import { generateTopicId, upsertTopic, getTopic, getProject, insertAuditEvent, } from '@team-anya/db';
|
|
2
|
-
export async function topicCreate(db, input, threadCreator) {
|
|
3
|
-
const topicId = generateTopicId(db);
|
|
4
|
-
let threadId = input.thread_id ?? null;
|
|
5
|
-
let rootMessageId = null;
|
|
6
|
-
// 自动创建话题:先发标题消息,再回复开启话题线程
|
|
7
|
-
if (!threadId && input.chat_id && threadCreator) {
|
|
8
|
-
// 1. 发送专项标题消息(作为话题根消息)
|
|
9
|
-
let projectLabel = '';
|
|
10
|
-
if (input.project_id) {
|
|
11
|
-
const project = getProject(db, input.project_id);
|
|
12
|
-
projectLabel = project ? `・${project.name}` : `・${input.project_id}`;
|
|
13
|
-
}
|
|
14
|
-
const headerText = `「专项${projectLabel}」${input.title}`;
|
|
15
|
-
rootMessageId = await threadCreator.sendText({
|
|
16
|
-
receiveIdType: 'chat_id',
|
|
17
|
-
receiveId: input.chat_id,
|
|
18
|
-
text: headerText,
|
|
19
|
-
});
|
|
20
|
-
// 2. 回复标题消息,开启话题线程
|
|
21
|
-
const result = await threadCreator.sendReplyInThread({
|
|
22
|
-
text: `📌 专项已开启,后续讨论请在此话题内进行。`,
|
|
23
|
-
replyToMessageId: rootMessageId,
|
|
24
|
-
});
|
|
25
|
-
threadId = result.threadId;
|
|
26
|
-
}
|
|
27
|
-
upsertTopic(db, {
|
|
28
|
-
id: topicId,
|
|
29
|
-
title: input.title,
|
|
30
|
-
description: input.description ?? null,
|
|
31
|
-
status: 'active',
|
|
32
|
-
project_id: input.project_id ?? null,
|
|
33
|
-
thread_id: threadId,
|
|
34
|
-
root_message_id: rootMessageId,
|
|
35
|
-
chat_id: input.chat_id ?? null,
|
|
36
|
-
created_by: input.created_by ?? null,
|
|
37
|
-
});
|
|
38
|
-
insertAuditEvent(db, {
|
|
39
|
-
event_type: 'topic_created',
|
|
40
|
-
actor: 'loid',
|
|
41
|
-
summary: `创建专项「${input.title}」(${topicId})`,
|
|
42
|
-
detail: JSON.stringify({
|
|
43
|
-
topic_id: topicId,
|
|
44
|
-
project_id: input.project_id,
|
|
45
|
-
thread_id: threadId,
|
|
46
|
-
}),
|
|
47
|
-
});
|
|
48
|
-
const topic = getTopic(db, topicId);
|
|
49
|
-
return {
|
|
50
|
-
topic_id: topic.id,
|
|
51
|
-
title: topic.title,
|
|
52
|
-
status: topic.status,
|
|
53
|
-
thread_id: topic.thread_id,
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
//# sourceMappingURL=topic-create.js.map
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
export function yorApprove(deps, input) {
|
|
2
|
-
const { yorOrchestrator, logger } = deps;
|
|
3
|
-
logger?.info(`[anya:pipeline] [Loid] yor.approve task=${input.task_id}`);
|
|
4
|
-
const message = input.message ?? '审核通过,任务完成。你可以做最后的清理工作。';
|
|
5
|
-
yorOrchestrator.approveAndShutdown(input.task_id, message);
|
|
6
|
-
return { task_id: input.task_id, approved: true };
|
|
7
|
-
}
|
|
8
|
-
//# sourceMappingURL=yor-approve.js.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
export async function yorKill(deps, input) {
|
|
2
|
-
const { yorOrchestrator, logger } = deps;
|
|
3
|
-
logger?.info(`[anya:pipeline] [Loid] yor.kill task=${input.task_id}`);
|
|
4
|
-
const result = await yorOrchestrator.kill(input.task_id);
|
|
5
|
-
return { task_id: input.task_id, killed: result.success };
|
|
6
|
-
}
|
|
7
|
-
//# sourceMappingURL=yor-kill.js.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
export function yorRework(deps, input) {
|
|
2
|
-
const { yorOrchestrator, logger } = deps;
|
|
3
|
-
logger?.info(`[anya:pipeline] [Loid] yor.rework task=${input.task_id}`);
|
|
4
|
-
yorOrchestrator.sendRework(input.task_id, input.feedback);
|
|
5
|
-
return { task_id: input.task_id, sent: true };
|
|
6
|
-
}
|
|
7
|
-
//# sourceMappingURL=yor-rework.js.map
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
export async function yorSpawn(deps, input) {
|
|
2
|
-
const { yorOrchestrator, logger } = deps;
|
|
3
|
-
logger?.info(`[anya:pipeline] [Loid] yor.spawn ${input.task_id} | dir=${input.working_dir}`);
|
|
4
|
-
const result = await yorOrchestrator.spawnAndExecute({
|
|
5
|
-
taskId: input.task_id,
|
|
6
|
-
workingDir: input.working_dir,
|
|
7
|
-
briefPath: input.brief_path,
|
|
8
|
-
env: input.env,
|
|
9
|
-
});
|
|
10
|
-
return {
|
|
11
|
-
instance_id: result.instanceId,
|
|
12
|
-
task_id: input.task_id,
|
|
13
|
-
};
|
|
14
|
-
}
|
|
15
|
-
//# sourceMappingURL=yor-spawn.js.map
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 报告阻塞
|
|
3
|
-
*
|
|
4
|
-
* Yor 遇到无法解决的问题时调用。
|
|
5
|
-
* 增加 category 字段与 PROTOCOL.md 对齐。
|
|
6
|
-
*/
|
|
7
|
-
export async function taskBlock(collector, input) {
|
|
8
|
-
collector.onBlockerReport(input);
|
|
9
|
-
return { received: true, type: 'blocker' };
|
|
10
|
-
}
|
|
11
|
-
//# sourceMappingURL=task-block.js.map
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { execFile as execFileCb } from 'node:child_process';
|
|
2
|
-
import { promisify } from 'node:util';
|
|
3
|
-
const execFile = promisify(execFileCb);
|
|
4
|
-
/**
|
|
5
|
-
* 提交交付成果
|
|
6
|
-
*
|
|
7
|
-
* Yor 完成任务后调用,报告变更文件、测试结果、PR 链接。
|
|
8
|
-
* 结果通过 collector 回调传给 dispatcher。
|
|
9
|
-
*
|
|
10
|
-
* 交付前检查 git 状态:如果有未提交变更,拒绝交付。
|
|
11
|
-
*/
|
|
12
|
-
export async function taskDeliver(collector, input, workingDir) {
|
|
13
|
-
// 检查 git 状态
|
|
14
|
-
if (workingDir) {
|
|
15
|
-
try {
|
|
16
|
-
// 检查是否是 git 仓库
|
|
17
|
-
await execFile('git', ['-C', workingDir, 'rev-parse', '--git-dir']);
|
|
18
|
-
// 检查是否有未提交变更
|
|
19
|
-
const { stdout } = await execFile('git', ['-C', workingDir, 'status', '--porcelain']);
|
|
20
|
-
if (stdout.trim().length > 0) {
|
|
21
|
-
return {
|
|
22
|
-
received: false,
|
|
23
|
-
type: 'delivery_rejected',
|
|
24
|
-
reason: `❌ 交付被拒绝:工作目录有未提交的变更。\n请先执行 git add + git commit,然后重新调用 task.deliver。\n未提交文件:\n${stdout.trim()}`,
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
catch {
|
|
29
|
-
// 不是 git 仓库或 git 命令失败,跳过检查(warn 级别)
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
collector.onDeliverySubmit(input);
|
|
33
|
-
return { received: true, type: 'delivery' };
|
|
34
|
-
}
|
|
35
|
-
//# sourceMappingURL=task-deliver.js.map
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { insertAuditEvent } from '@team-anya/db';
|
|
2
|
-
/**
|
|
3
|
-
* 中间进度汇报
|
|
4
|
-
*
|
|
5
|
-
* 长任务中 Yor 向 Loid 汇报里程碑,不改变任务状态。
|
|
6
|
-
* 写 audit event(yor_progress),Loid 可通过 audit.query 查看。
|
|
7
|
-
*/
|
|
8
|
-
export async function taskProgress(db, taskId, input) {
|
|
9
|
-
insertAuditEvent(db, {
|
|
10
|
-
event_type: 'yor_progress',
|
|
11
|
-
actor: 'yor',
|
|
12
|
-
task_id: taskId,
|
|
13
|
-
summary: input.milestone,
|
|
14
|
-
detail: JSON.stringify({
|
|
15
|
-
detail: input.detail,
|
|
16
|
-
next_step: input.next_step,
|
|
17
|
-
}),
|
|
18
|
-
});
|
|
19
|
-
return { received: true };
|
|
20
|
-
}
|
|
21
|
-
//# sourceMappingURL=task-progress.js.map
|