team-anya-cli 0.1.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/anya/prompts/execution-guides/git-delivery.md +38 -0
- package/anya/prompts/execution-guides/testing-and-self-heal.md +28 -0
- package/anya/prompts/protocols/brief-assembly.md +55 -0
- package/anya/prompts/protocols/report.md +175 -0
- package/anya/prompts/protocols/review.md +90 -0
- package/anya/prompts/task-claude-md.template.md +32 -0
- package/apps/server/dist/broker/cc-broker.js +257 -0
- package/apps/server/dist/cli.js +296 -0
- package/apps/server/dist/config.js +76 -0
- package/apps/server/dist/daemon.js +51 -0
- package/apps/server/dist/gateway/chat-sync.js +135 -0
- package/apps/server/dist/gateway/command-router.js +114 -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 +34 -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 +346 -0
- package/apps/server/dist/gateway/feishu-ws.js +254 -0
- package/apps/server/dist/gateway/http.js +994 -0
- package/apps/server/dist/gateway/media-downloader.js +149 -0
- package/apps/server/dist/gateway/message-events.js +10 -0
- package/apps/server/dist/gateway/message-intake.js +50 -0
- package/apps/server/dist/gateway/message-queue.js +104 -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 +104 -0
- package/apps/server/dist/loid/clarifier.js +162 -0
- package/apps/server/dist/loid/context-builder.js +413 -0
- package/apps/server/dist/loid/mcp-server.js +104 -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/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 +217 -0
- package/apps/server/dist/loid/session.js +271 -0
- package/apps/server/dist/loid/worktree-manager.js +191 -0
- package/apps/server/dist/main.js +337 -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 +104 -0
- package/apps/server/dist/yor/yor-orchestrator.js +233 -0
- package/apps/web/dist/assets/index-CHIT0Dya.css +1 -0
- package/apps/web/dist/assets/index-CJzAjoVH.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 +664 -0
- package/packages/cc-client/dist/index.js +2 -0
- package/packages/cc-client/package.json +11 -0
- package/packages/core/dist/constants.js +59 -0
- package/packages/core/dist/errors.js +35 -0
- package/packages/core/dist/index.js +7 -0
- package/packages/core/dist/office-init.js +97 -0
- package/packages/core/dist/scope/checker.js +114 -0
- package/packages/core/dist/scope/defaults.js +40 -0
- package/packages/core/dist/scope/index.js +3 -0
- package/packages/core/dist/state-machine.js +85 -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 +8 -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/package.json +10 -0
- package/packages/db/dist/client.js +69 -0
- package/packages/db/dist/index.js +603 -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 +33 -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 +12 -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 +46 -0
- package/packages/db/dist/schema/trace-spans.js +19 -0
- package/packages/db/package.json +12 -0
- package/packages/db/src/migrations/0000_simple_magneto.sql +148 -0
- package/packages/db/src/migrations/0001_nifty_morph.sql +42 -0
- package/packages/db/src/migrations/0002_common_joshua_kane.sql +20 -0
- package/packages/db/src/migrations/0003_add_cc_sessions.sql +13 -0
- package/packages/db/src/migrations/0004_jittery_triathlon.sql +1 -0
- package/packages/db/src/migrations/meta/0000_snapshot.json +987 -0
- package/packages/db/src/migrations/meta/0001_snapshot.json +1280 -0
- package/packages/db/src/migrations/meta/0002_snapshot.json +1417 -0
- package/packages/db/src/migrations/meta/0004_snapshot.json +1505 -0
- package/packages/db/src/migrations/meta/_journal.json +41 -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/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 +177 -0
- package/packages/mcp-tools/dist/layer2/loid/task-lookup.js +38 -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 +15 -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 +191 -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 +90 -0
- package/packages/mcp-tools/dist/layer3/file-upload.js +44 -0
- package/packages/mcp-tools/dist/registry.js +779 -0
- package/packages/mcp-tools/package.json +13 -0
- package/workspace/.claude/settings.local.json +9 -0
- package/workspace/.mcp.json +12 -0
- package/workspace/CHARTER.md +73 -0
- package/workspace/CLAUDE.md +49 -0
- package/workspace/PROTOCOL.md +126 -0
- package/workspace/TOOLS.md +464 -0
- package/workspace/audit/.gitkeep +0 -0
- package/workspace/loid/CLAUDE.md +12 -0
- package/workspace/loid/PLAYBOOK.md +198 -0
- package/workspace/loid/PROFILE.md +78 -0
- 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 +24 -0
- package/workspace/reference/org/ownership.yaml +28 -0
- package/workspace/reports/.gitkeep +0 -0
- package/workspace/yor/CLAUDE.md +22 -0
- package/workspace/yor/PLAYBOOK.md +73 -0
- package/workspace/yor/PROFILE.md +52 -0
- package/workspace/yor/SELF-HEAL.md +39 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { resolve, dirname } from 'node:path';
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
3
|
+
import { readFileSync, existsSync, mkdirSync } from 'node:fs';
|
|
4
|
+
import Database from 'better-sqlite3';
|
|
5
|
+
import { drizzle } from 'drizzle-orm/better-sqlite3';
|
|
6
|
+
import { migrate } from 'drizzle-orm/better-sqlite3/migrator';
|
|
7
|
+
import * as schema from './schema/index.js';
|
|
8
|
+
/**
|
|
9
|
+
* 获取 migrations 目录的绝对路径
|
|
10
|
+
*
|
|
11
|
+
* 兼容两种运行方式:
|
|
12
|
+
* - 源码运行(vitest/tsx):import.meta.url → src/client.ts → src/migrations/
|
|
13
|
+
* - 编译后运行(node dist/):import.meta.url → dist/client.js → 回溯到 src/migrations/
|
|
14
|
+
*/
|
|
15
|
+
function getMigrationsPath() {
|
|
16
|
+
const currentDir = dirname(fileURLToPath(import.meta.url));
|
|
17
|
+
// 优先尝试同级 migrations 目录(源码模式)
|
|
18
|
+
const sameLevelPath = resolve(currentDir, 'migrations');
|
|
19
|
+
if (existsSync(resolve(sameLevelPath, 'meta', '_journal.json'))) {
|
|
20
|
+
return sameLevelPath;
|
|
21
|
+
}
|
|
22
|
+
// 回溯到 src/migrations(编译后 dist/ 模式)
|
|
23
|
+
const srcPath = resolve(currentDir, '..', 'src', 'migrations');
|
|
24
|
+
if (existsSync(resolve(srcPath, 'meta', '_journal.json'))) {
|
|
25
|
+
return srcPath;
|
|
26
|
+
}
|
|
27
|
+
throw new Error(`找不到 migrations 目录,已尝试:\n - ${sameLevelPath}\n - ${srcPath}`);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* 创建数据库连接并自动运行 migration
|
|
31
|
+
*/
|
|
32
|
+
export function createDB(dbPath) {
|
|
33
|
+
// 确保数据库文件所在目录存在
|
|
34
|
+
mkdirSync(dirname(dbPath), { recursive: true });
|
|
35
|
+
const sqlite = new Database(dbPath);
|
|
36
|
+
// 启用 WAL 模式(支持并发读)
|
|
37
|
+
sqlite.pragma('journal_mode = WAL');
|
|
38
|
+
sqlite.pragma('foreign_keys = ON');
|
|
39
|
+
const db = drizzle(sqlite, { schema });
|
|
40
|
+
// 自动运行 migration(幂等,已执行过的不会重复执行)
|
|
41
|
+
migrate(db, { migrationsFolder: getMigrationsPath() });
|
|
42
|
+
return db;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* 创建内存数据库(测试用,直接从 migration SQL 建表)
|
|
46
|
+
*/
|
|
47
|
+
export function createTestDB() {
|
|
48
|
+
const sqlite = new Database(':memory:');
|
|
49
|
+
sqlite.pragma('foreign_keys = ON');
|
|
50
|
+
const db = drizzle(sqlite, { schema });
|
|
51
|
+
// 读取 migration SQL 直接执行(内存库不走 migration 元数据表)
|
|
52
|
+
const migrationsPath = getMigrationsPath();
|
|
53
|
+
const journalPath = resolve(migrationsPath, 'meta', '_journal.json');
|
|
54
|
+
const journal = JSON.parse(readFileSync(journalPath, 'utf-8'));
|
|
55
|
+
for (const entry of journal.entries) {
|
|
56
|
+
const sqlPath = resolve(migrationsPath, `${entry.tag}.sql`);
|
|
57
|
+
const sqlContent = readFileSync(sqlPath, 'utf-8');
|
|
58
|
+
// drizzle migration SQL 用 --> statement-breakpoint 分隔语句
|
|
59
|
+
const statements = sqlContent
|
|
60
|
+
.split('--> statement-breakpoint')
|
|
61
|
+
.map(s => s.trim())
|
|
62
|
+
.filter(Boolean);
|
|
63
|
+
for (const stmt of statements) {
|
|
64
|
+
sqlite.exec(stmt);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return db;
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1,603 @@
|
|
|
1
|
+
import { eq, desc, gte, like, and, sql, count, isNull, isNotNull } from 'drizzle-orm';
|
|
2
|
+
import { tasks, taskClarifications, commitments, opportunities, auditEvents, orgMembers, orgOwnership, orgEscalationRules, communicationEvents, messageLog, traceSpans, chats, chatMembers, projects, projectRepos, ccSessions } from './schema/index.js';
|
|
3
|
+
export { createDB, createTestDB } from './client.js';
|
|
4
|
+
export * from './schema/index.js';
|
|
5
|
+
// ── Task CRUD ──
|
|
6
|
+
export function createTask(db, data) {
|
|
7
|
+
return db.insert(tasks).values(data).returning().get();
|
|
8
|
+
}
|
|
9
|
+
export function getTask(db, taskId) {
|
|
10
|
+
return db.select().from(tasks).where(eq(tasks.task_id, taskId)).get();
|
|
11
|
+
}
|
|
12
|
+
export function updateTask(db, taskId, data) {
|
|
13
|
+
return db.update(tasks)
|
|
14
|
+
.set({ ...data, updated_at: new Date().toISOString() })
|
|
15
|
+
.where(eq(tasks.task_id, taskId))
|
|
16
|
+
.returning()
|
|
17
|
+
.get();
|
|
18
|
+
}
|
|
19
|
+
export function getTasksByStatus(db, status) {
|
|
20
|
+
return db.select().from(tasks).where(eq(tasks.status, status)).orderBy(desc(tasks.created_at)).all();
|
|
21
|
+
}
|
|
22
|
+
export function getTasksByProject(db, projectId) {
|
|
23
|
+
return db.select().from(tasks).where(eq(tasks.project_id, projectId)).orderBy(desc(tasks.created_at)).all();
|
|
24
|
+
}
|
|
25
|
+
export function getAllTasks(db) {
|
|
26
|
+
return db.select().from(tasks).orderBy(desc(tasks.created_at)).all();
|
|
27
|
+
}
|
|
28
|
+
export function getTasksByAssignee(db, assignee) {
|
|
29
|
+
return db.select().from(tasks).where(eq(tasks.assignee, assignee)).orderBy(desc(tasks.created_at)).all();
|
|
30
|
+
}
|
|
31
|
+
export function getTasksByChatId(db, chatId) {
|
|
32
|
+
return db.select().from(tasks).where(eq(tasks.source_chat_id, chatId)).orderBy(desc(tasks.created_at)).all();
|
|
33
|
+
}
|
|
34
|
+
// ── Clarification CRUD ──
|
|
35
|
+
export function addClarification(db, data) {
|
|
36
|
+
return db.insert(taskClarifications).values(data).returning().get();
|
|
37
|
+
}
|
|
38
|
+
export function getClarifications(db, taskId) {
|
|
39
|
+
return db.select().from(taskClarifications)
|
|
40
|
+
.where(eq(taskClarifications.task_id, taskId)).all();
|
|
41
|
+
}
|
|
42
|
+
export function answerClarification(db, id, answer, answeredBy) {
|
|
43
|
+
return db.update(taskClarifications)
|
|
44
|
+
.set({
|
|
45
|
+
answer,
|
|
46
|
+
answered_by: answeredBy,
|
|
47
|
+
answered_at: new Date().toISOString(),
|
|
48
|
+
})
|
|
49
|
+
.where(eq(taskClarifications.id, id))
|
|
50
|
+
.returning()
|
|
51
|
+
.get();
|
|
52
|
+
}
|
|
53
|
+
// ── Commitment CRUD ──
|
|
54
|
+
export function createCommitment(db, data) {
|
|
55
|
+
return db.insert(commitments).values(data).returning().get();
|
|
56
|
+
}
|
|
57
|
+
export function getCommitment(db, id) {
|
|
58
|
+
return db.select().from(commitments).where(eq(commitments.id, id)).get();
|
|
59
|
+
}
|
|
60
|
+
export function getCommitmentByTask(db, taskId) {
|
|
61
|
+
return db.select().from(commitments).where(eq(commitments.task_id, taskId)).get();
|
|
62
|
+
}
|
|
63
|
+
export function getCommitmentsByTaskId(db, taskId) {
|
|
64
|
+
return db.select().from(commitments).where(eq(commitments.task_id, taskId)).all();
|
|
65
|
+
}
|
|
66
|
+
export function getActiveCommitments(db) {
|
|
67
|
+
return db.select().from(commitments).where(eq(commitments.status, 'active')).all();
|
|
68
|
+
}
|
|
69
|
+
export function getCommitmentsByStatus(db, status) {
|
|
70
|
+
return db.select().from(commitments).where(eq(commitments.status, status)).all();
|
|
71
|
+
}
|
|
72
|
+
export function getAllCommitments(db) {
|
|
73
|
+
return db.select().from(commitments).all();
|
|
74
|
+
}
|
|
75
|
+
export function updateCommitment(db, id, data) {
|
|
76
|
+
return db.update(commitments)
|
|
77
|
+
.set(data)
|
|
78
|
+
.where(eq(commitments.id, id))
|
|
79
|
+
.returning()
|
|
80
|
+
.get();
|
|
81
|
+
}
|
|
82
|
+
// ── Audit Events ──
|
|
83
|
+
export function insertAuditEvent(db, data) {
|
|
84
|
+
return db.insert(auditEvents).values(data).returning().get();
|
|
85
|
+
}
|
|
86
|
+
export function getAuditEventsByTask(db, taskId) {
|
|
87
|
+
return db.select().from(auditEvents).where(eq(auditEvents.task_id, taskId)).all();
|
|
88
|
+
}
|
|
89
|
+
export function getAuditEventsByType(db, eventType) {
|
|
90
|
+
return db.select().from(auditEvents).where(eq(auditEvents.event_type, eventType)).all();
|
|
91
|
+
}
|
|
92
|
+
export function getAuditEventsByDate(db, date) {
|
|
93
|
+
return db.select().from(auditEvents).where(like(auditEvents.created_at, `${date}%`)).all();
|
|
94
|
+
}
|
|
95
|
+
// ── Opportunity ──
|
|
96
|
+
export function createOpportunity(db, data) {
|
|
97
|
+
return db.insert(opportunities).values(data).returning().get();
|
|
98
|
+
}
|
|
99
|
+
export function getOpenOpportunities(db) {
|
|
100
|
+
return db.select().from(opportunities)
|
|
101
|
+
.where(eq(opportunities.status, 'detected'))
|
|
102
|
+
.all();
|
|
103
|
+
}
|
|
104
|
+
export function getOpportunity(db, id) {
|
|
105
|
+
return db.select().from(opportunities).where(eq(opportunities.id, id)).get();
|
|
106
|
+
}
|
|
107
|
+
export function getAllOpportunities(db) {
|
|
108
|
+
return db.select().from(opportunities).all();
|
|
109
|
+
}
|
|
110
|
+
export function getOpportunitiesByStatus(db, status) {
|
|
111
|
+
return db.select().from(opportunities).where(eq(opportunities.status, status)).all();
|
|
112
|
+
}
|
|
113
|
+
export function updateOpportunity(db, id, data) {
|
|
114
|
+
return db.update(opportunities)
|
|
115
|
+
.set(data)
|
|
116
|
+
.where(eq(opportunities.id, id))
|
|
117
|
+
.returning()
|
|
118
|
+
.get();
|
|
119
|
+
}
|
|
120
|
+
// ── Org ──
|
|
121
|
+
export function getOrgMember(db, memberId) {
|
|
122
|
+
return db.select().from(orgMembers).where(eq(orgMembers.member_id, memberId)).get();
|
|
123
|
+
}
|
|
124
|
+
export function upsertOrgMember(db, data) {
|
|
125
|
+
const setFields = {
|
|
126
|
+
name: data.name,
|
|
127
|
+
updated_at: sql `(datetime('now'))`,
|
|
128
|
+
};
|
|
129
|
+
if (data.platform !== undefined)
|
|
130
|
+
setFields.platform = data.platform;
|
|
131
|
+
if (data.union_id !== undefined)
|
|
132
|
+
setFields.union_id = data.union_id;
|
|
133
|
+
if (data.user_id !== undefined)
|
|
134
|
+
setFields.user_id = data.user_id;
|
|
135
|
+
if (data.en_name !== undefined)
|
|
136
|
+
setFields.en_name = data.en_name;
|
|
137
|
+
if (data.email !== undefined)
|
|
138
|
+
setFields.email = data.email;
|
|
139
|
+
if (data.employee_no !== undefined)
|
|
140
|
+
setFields.employee_no = data.employee_no;
|
|
141
|
+
if (data.avatar_url !== undefined)
|
|
142
|
+
setFields.avatar_url = data.avatar_url;
|
|
143
|
+
if (data.metadata !== undefined)
|
|
144
|
+
setFields.metadata = data.metadata;
|
|
145
|
+
if (data.last_synced_at !== undefined)
|
|
146
|
+
setFields.last_synced_at = data.last_synced_at;
|
|
147
|
+
return db.insert(orgMembers)
|
|
148
|
+
.values({
|
|
149
|
+
member_id: data.member_id,
|
|
150
|
+
name: data.name,
|
|
151
|
+
platform: data.platform,
|
|
152
|
+
union_id: data.union_id,
|
|
153
|
+
user_id: data.user_id,
|
|
154
|
+
en_name: data.en_name,
|
|
155
|
+
email: data.email,
|
|
156
|
+
employee_no: data.employee_no,
|
|
157
|
+
avatar_url: data.avatar_url,
|
|
158
|
+
metadata: data.metadata,
|
|
159
|
+
last_synced_at: data.last_synced_at,
|
|
160
|
+
})
|
|
161
|
+
.onConflictDoUpdate({
|
|
162
|
+
target: orgMembers.member_id,
|
|
163
|
+
set: setFields,
|
|
164
|
+
})
|
|
165
|
+
.returning()
|
|
166
|
+
.get();
|
|
167
|
+
}
|
|
168
|
+
export function getOwnershipByTarget(db, target) {
|
|
169
|
+
return db.select().from(orgOwnership).where(eq(orgOwnership.target, target)).all();
|
|
170
|
+
}
|
|
171
|
+
export function getEscalationRules(db, scope = 'global') {
|
|
172
|
+
return db.select().from(orgEscalationRules)
|
|
173
|
+
.where(eq(orgEscalationRules.scope, scope))
|
|
174
|
+
.all();
|
|
175
|
+
}
|
|
176
|
+
// ── 统计 ──
|
|
177
|
+
export function getTaskCountByStatus(db) {
|
|
178
|
+
const all = db.select().from(tasks).all();
|
|
179
|
+
const counts = {};
|
|
180
|
+
for (const task of all) {
|
|
181
|
+
counts[task.status] = (counts[task.status] || 0) + 1;
|
|
182
|
+
}
|
|
183
|
+
return counts;
|
|
184
|
+
}
|
|
185
|
+
// ── CommunicationEvent ──
|
|
186
|
+
export function insertCommunicationEvent(db, data) {
|
|
187
|
+
return db.insert(communicationEvents).values(data).returning().get();
|
|
188
|
+
}
|
|
189
|
+
export function getRecentCommunicationEvents(db, limit = 50, since) {
|
|
190
|
+
if (since) {
|
|
191
|
+
return db.select().from(communicationEvents)
|
|
192
|
+
.where(gte(communicationEvents.created_at, since))
|
|
193
|
+
.orderBy(desc(communicationEvents.created_at))
|
|
194
|
+
.limit(limit)
|
|
195
|
+
.all();
|
|
196
|
+
}
|
|
197
|
+
return db.select().from(communicationEvents)
|
|
198
|
+
.orderBy(desc(communicationEvents.created_at))
|
|
199
|
+
.limit(limit)
|
|
200
|
+
.all();
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* 获取今日新建任务的最大序号(用于生成 task_id)
|
|
204
|
+
*/
|
|
205
|
+
export function getTodayMaxSequence(db) {
|
|
206
|
+
const today = new Date().toISOString().slice(0, 10).replace(/-/g, '');
|
|
207
|
+
const all = db.select().from(tasks).all();
|
|
208
|
+
let max = 0;
|
|
209
|
+
for (const task of all) {
|
|
210
|
+
if (task.task_id.startsWith(`ANYA-${today}-`)) {
|
|
211
|
+
const seq = parseInt(task.task_id.split('-')[2], 10);
|
|
212
|
+
if (seq > max)
|
|
213
|
+
max = seq;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
return max;
|
|
217
|
+
}
|
|
218
|
+
// ── MessageLog CRUD ──
|
|
219
|
+
export function insertMessageLog(db, data) {
|
|
220
|
+
return db.insert(messageLog).values(data).returning().get();
|
|
221
|
+
}
|
|
222
|
+
export function getRecentMessages(db, opts = {}) {
|
|
223
|
+
const { limit = 50, offset = 0, direction, since, message_type, sender, receiver, chat_id, chat_type, sort: sortOrder } = opts;
|
|
224
|
+
const conditions = [];
|
|
225
|
+
if (direction)
|
|
226
|
+
conditions.push(eq(messageLog.direction, direction));
|
|
227
|
+
if (since)
|
|
228
|
+
conditions.push(gte(messageLog.created_at, since));
|
|
229
|
+
if (message_type)
|
|
230
|
+
conditions.push(eq(messageLog.message_type, message_type));
|
|
231
|
+
if (sender)
|
|
232
|
+
conditions.push(eq(messageLog.sender, sender));
|
|
233
|
+
if (receiver)
|
|
234
|
+
conditions.push(eq(messageLog.receiver, receiver));
|
|
235
|
+
if (chat_id)
|
|
236
|
+
conditions.push(eq(messageLog.chat_id, chat_id));
|
|
237
|
+
if (chat_type)
|
|
238
|
+
conditions.push(eq(messageLog.chat_type, chat_type));
|
|
239
|
+
const query = conditions.length > 0
|
|
240
|
+
? db.select().from(messageLog).where(and(...conditions))
|
|
241
|
+
: db.select().from(messageLog);
|
|
242
|
+
const orderBy = sortOrder === 'asc' ? messageLog.created_at : desc(messageLog.created_at);
|
|
243
|
+
return query
|
|
244
|
+
.orderBy(orderBy)
|
|
245
|
+
.limit(limit)
|
|
246
|
+
.offset(offset)
|
|
247
|
+
.all();
|
|
248
|
+
}
|
|
249
|
+
export function getMessageStats(db) {
|
|
250
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
251
|
+
const todayMessages = db.select().from(messageLog)
|
|
252
|
+
.where(gte(messageLog.created_at, today))
|
|
253
|
+
.all();
|
|
254
|
+
let inbound = 0;
|
|
255
|
+
let outbound = 0;
|
|
256
|
+
for (const msg of todayMessages) {
|
|
257
|
+
if (msg.direction === 'inbound')
|
|
258
|
+
inbound++;
|
|
259
|
+
else if (msg.direction === 'outbound')
|
|
260
|
+
outbound++;
|
|
261
|
+
}
|
|
262
|
+
return { today: today, inbound, outbound, total: inbound + outbound };
|
|
263
|
+
}
|
|
264
|
+
// ── Trace Spans CRUD ──
|
|
265
|
+
export function insertTraceSpan(db, data) {
|
|
266
|
+
return db.insert(traceSpans).values(data).returning().get();
|
|
267
|
+
}
|
|
268
|
+
export function updateTraceSpan(db, spanId, data) {
|
|
269
|
+
return db.update(traceSpans)
|
|
270
|
+
.set(data)
|
|
271
|
+
.where(eq(traceSpans.span_id, spanId))
|
|
272
|
+
.returning()
|
|
273
|
+
.get();
|
|
274
|
+
}
|
|
275
|
+
export function getTraceSpans(db, traceId) {
|
|
276
|
+
return db.select().from(traceSpans)
|
|
277
|
+
.where(eq(traceSpans.trace_id, traceId))
|
|
278
|
+
.orderBy(traceSpans.started_at)
|
|
279
|
+
.all();
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* 查询 trace 列表(按根 span 聚合)
|
|
283
|
+
*/
|
|
284
|
+
export function listTraces(db, opts = {}) {
|
|
285
|
+
const limit = opts.limit ?? 50;
|
|
286
|
+
const offset = opts.offset ?? 0;
|
|
287
|
+
// 用子查询按 trace_id 聚合,取每个 trace 的根 span 信息
|
|
288
|
+
const conditions = [];
|
|
289
|
+
if (opts.operation) {
|
|
290
|
+
conditions.push(like(traceSpans.operation, `%${opts.operation}%`));
|
|
291
|
+
}
|
|
292
|
+
if (opts.status) {
|
|
293
|
+
conditions.push(eq(traceSpans.status, opts.status));
|
|
294
|
+
}
|
|
295
|
+
const whereClause = conditions.length > 0 ? and(...conditions) : undefined;
|
|
296
|
+
// 查总数(按 trace_id 去重)
|
|
297
|
+
const countResult = db
|
|
298
|
+
.select({ count: sql `count(distinct ${traceSpans.trace_id})` })
|
|
299
|
+
.from(traceSpans)
|
|
300
|
+
.where(whereClause)
|
|
301
|
+
.get();
|
|
302
|
+
const total = countResult?.count ?? 0;
|
|
303
|
+
// 查列表:每个 trace_id 取聚合信息
|
|
304
|
+
const rows = db.all(sql `
|
|
305
|
+
SELECT
|
|
306
|
+
${traceSpans.trace_id} as trace_id,
|
|
307
|
+
min(${traceSpans.started_at}) as started_at,
|
|
308
|
+
max(${traceSpans.ended_at}) as ended_at,
|
|
309
|
+
count(*) as span_count,
|
|
310
|
+
group_concat(distinct ${traceSpans.operation}) as operations,
|
|
311
|
+
CASE
|
|
312
|
+
WHEN sum(CASE WHEN ${traceSpans.status} = 'error' THEN 1 ELSE 0 END) > 0 THEN 'error'
|
|
313
|
+
WHEN sum(CASE WHEN ${traceSpans.status} = 'in_progress' THEN 1 ELSE 0 END) > 0 THEN 'in_progress'
|
|
314
|
+
ELSE 'success'
|
|
315
|
+
END as status,
|
|
316
|
+
CASE
|
|
317
|
+
WHEN max(${traceSpans.ended_at}) IS NOT NULL
|
|
318
|
+
THEN (julianday(max(${traceSpans.ended_at})) - julianday(min(${traceSpans.started_at}))) * 86400000
|
|
319
|
+
ELSE NULL
|
|
320
|
+
END as total_duration_ms
|
|
321
|
+
FROM ${traceSpans}
|
|
322
|
+
${whereClause ? sql `WHERE ${whereClause}` : sql ``}
|
|
323
|
+
GROUP BY ${traceSpans.trace_id}
|
|
324
|
+
ORDER BY min(${traceSpans.started_at}) DESC
|
|
325
|
+
LIMIT ${limit}
|
|
326
|
+
OFFSET ${offset}
|
|
327
|
+
`);
|
|
328
|
+
return { data: rows, total };
|
|
329
|
+
}
|
|
330
|
+
export function getMessageLogById(db, id) {
|
|
331
|
+
return db.select().from(messageLog).where(eq(messageLog.id, id)).get();
|
|
332
|
+
}
|
|
333
|
+
export function getMessageLogBySourceRef(db, sourceRef) {
|
|
334
|
+
return db.select().from(messageLog).where(eq(messageLog.source_ref, sourceRef)).get();
|
|
335
|
+
}
|
|
336
|
+
// ── Chats CRUD ──
|
|
337
|
+
export function upsertChat(db, data) {
|
|
338
|
+
return db.insert(chats)
|
|
339
|
+
.values(data)
|
|
340
|
+
.onConflictDoUpdate({
|
|
341
|
+
target: chats.chat_id,
|
|
342
|
+
set: {
|
|
343
|
+
name: data.name,
|
|
344
|
+
description: data.description,
|
|
345
|
+
avatar: data.avatar,
|
|
346
|
+
owner_id: data.owner_id,
|
|
347
|
+
chat_mode: data.chat_mode,
|
|
348
|
+
chat_type: data.chat_type,
|
|
349
|
+
chat_tag: data.chat_tag,
|
|
350
|
+
chat_status: data.chat_status,
|
|
351
|
+
external: data.external,
|
|
352
|
+
tenant_key: data.tenant_key,
|
|
353
|
+
user_count: data.user_count,
|
|
354
|
+
bot_count: data.bot_count,
|
|
355
|
+
metadata: data.metadata,
|
|
356
|
+
last_synced_at: data.last_synced_at,
|
|
357
|
+
updated_at: sql `(datetime('now'))`,
|
|
358
|
+
},
|
|
359
|
+
})
|
|
360
|
+
.returning()
|
|
361
|
+
.get();
|
|
362
|
+
}
|
|
363
|
+
export function getChat(db, chatId) {
|
|
364
|
+
return db.select().from(chats).where(eq(chats.chat_id, chatId)).get();
|
|
365
|
+
}
|
|
366
|
+
export function getAllChats(db, opts) {
|
|
367
|
+
const conditions = [];
|
|
368
|
+
if (opts?.platform)
|
|
369
|
+
conditions.push(eq(chats.platform, opts.platform));
|
|
370
|
+
if (opts?.chat_type)
|
|
371
|
+
conditions.push(eq(chats.chat_type, opts.chat_type));
|
|
372
|
+
if (opts?.name)
|
|
373
|
+
conditions.push(like(chats.name, `%${opts.name}%`));
|
|
374
|
+
const whereClause = conditions.length > 0 ? and(...conditions) : undefined;
|
|
375
|
+
return db.select().from(chats).where(whereClause).orderBy(desc(chats.updated_at)).all();
|
|
376
|
+
}
|
|
377
|
+
export function getChatStats(db) {
|
|
378
|
+
const all = db.select().from(chats).all();
|
|
379
|
+
const byType = {};
|
|
380
|
+
for (const chat of all) {
|
|
381
|
+
const t = chat.chat_type ?? 'unknown';
|
|
382
|
+
byType[t] = (byType[t] || 0) + 1;
|
|
383
|
+
}
|
|
384
|
+
return { total: all.length, byType };
|
|
385
|
+
}
|
|
386
|
+
// ── Chat Members CRUD ──
|
|
387
|
+
export function upsertChatMember(db, data) {
|
|
388
|
+
// 先查是否存在
|
|
389
|
+
const existing = db.select().from(chatMembers)
|
|
390
|
+
.where(and(eq(chatMembers.chat_id, data.chat_id), eq(chatMembers.member_id, data.member_id)))
|
|
391
|
+
.get();
|
|
392
|
+
if (existing) {
|
|
393
|
+
return db.update(chatMembers)
|
|
394
|
+
.set({ role: data.role ?? existing.role, synced_at: sql `(datetime('now'))` })
|
|
395
|
+
.where(eq(chatMembers.id, existing.id))
|
|
396
|
+
.returning()
|
|
397
|
+
.get();
|
|
398
|
+
}
|
|
399
|
+
return db.insert(chatMembers)
|
|
400
|
+
.values({ chat_id: data.chat_id, member_id: data.member_id, role: data.role ?? 'member' })
|
|
401
|
+
.returning()
|
|
402
|
+
.get();
|
|
403
|
+
}
|
|
404
|
+
export function getChatMembers(db, chatId) {
|
|
405
|
+
return db.select({
|
|
406
|
+
id: chatMembers.id,
|
|
407
|
+
chat_id: chatMembers.chat_id,
|
|
408
|
+
member_id: chatMembers.member_id,
|
|
409
|
+
role: chatMembers.role,
|
|
410
|
+
synced_at: chatMembers.synced_at,
|
|
411
|
+
name: orgMembers.name,
|
|
412
|
+
en_name: orgMembers.en_name,
|
|
413
|
+
email: orgMembers.email,
|
|
414
|
+
employee_no: orgMembers.employee_no,
|
|
415
|
+
avatar_url: orgMembers.avatar_url,
|
|
416
|
+
member_role: orgMembers.role,
|
|
417
|
+
team: orgMembers.team,
|
|
418
|
+
})
|
|
419
|
+
.from(chatMembers)
|
|
420
|
+
.innerJoin(orgMembers, eq(chatMembers.member_id, orgMembers.member_id))
|
|
421
|
+
.where(eq(chatMembers.chat_id, chatId))
|
|
422
|
+
.all();
|
|
423
|
+
}
|
|
424
|
+
export function getMemberChats(db, memberId) {
|
|
425
|
+
return db.select({
|
|
426
|
+
chat_id: chats.chat_id,
|
|
427
|
+
name: chats.name,
|
|
428
|
+
chat_type: chats.chat_type,
|
|
429
|
+
chat_tag: chats.chat_tag,
|
|
430
|
+
user_count: chats.user_count,
|
|
431
|
+
role: chatMembers.role,
|
|
432
|
+
})
|
|
433
|
+
.from(chatMembers)
|
|
434
|
+
.innerJoin(chats, eq(chatMembers.chat_id, chats.chat_id))
|
|
435
|
+
.where(eq(chatMembers.member_id, memberId))
|
|
436
|
+
.all();
|
|
437
|
+
}
|
|
438
|
+
export function removeChatMembers(db, chatId) {
|
|
439
|
+
return db.delete(chatMembers).where(eq(chatMembers.chat_id, chatId)).run();
|
|
440
|
+
}
|
|
441
|
+
export function getAllOrgMembers(db) {
|
|
442
|
+
return db.select().from(orgMembers).all();
|
|
443
|
+
}
|
|
444
|
+
// ── Projects CRUD ──
|
|
445
|
+
export function upsertProject(db, data) {
|
|
446
|
+
return db.insert(projects)
|
|
447
|
+
.values(data)
|
|
448
|
+
.onConflictDoUpdate({
|
|
449
|
+
target: projects.project_id,
|
|
450
|
+
set: {
|
|
451
|
+
name: data.name,
|
|
452
|
+
description: data.description,
|
|
453
|
+
platform: data.platform,
|
|
454
|
+
claude_md: data.claude_md,
|
|
455
|
+
updated_at: sql `(datetime('now'))`,
|
|
456
|
+
},
|
|
457
|
+
})
|
|
458
|
+
.returning()
|
|
459
|
+
.get();
|
|
460
|
+
}
|
|
461
|
+
export function getProject(db, projectId, includeDeleted = false) {
|
|
462
|
+
const conditions = [eq(projects.project_id, projectId)];
|
|
463
|
+
if (!includeDeleted) {
|
|
464
|
+
conditions.push(isNull(projects.deleted_at));
|
|
465
|
+
}
|
|
466
|
+
return db.select().from(projects).where(and(...conditions)).get();
|
|
467
|
+
}
|
|
468
|
+
export function getAllProjects(db, includeDeleted = false) {
|
|
469
|
+
const where = includeDeleted ? undefined : isNull(projects.deleted_at);
|
|
470
|
+
return db.select().from(projects).where(where).orderBy(desc(projects.updated_at)).all();
|
|
471
|
+
}
|
|
472
|
+
export function softDeleteProject(db, projectId) {
|
|
473
|
+
return db.update(projects)
|
|
474
|
+
.set({ deleted_at: new Date().toISOString() })
|
|
475
|
+
.where(eq(projects.project_id, projectId))
|
|
476
|
+
.run();
|
|
477
|
+
}
|
|
478
|
+
// ── Project Repos CRUD ──
|
|
479
|
+
export function upsertProjectRepo(db, data) {
|
|
480
|
+
return db.insert(projectRepos).values(data).returning().get();
|
|
481
|
+
}
|
|
482
|
+
export function getProjectRepos(db, projectId) {
|
|
483
|
+
return db.select().from(projectRepos)
|
|
484
|
+
.where(eq(projectRepos.project_id, projectId))
|
|
485
|
+
.all();
|
|
486
|
+
}
|
|
487
|
+
export function removeProjectRepos(db, projectId) {
|
|
488
|
+
return db.delete(projectRepos).where(eq(projectRepos.project_id, projectId)).run();
|
|
489
|
+
}
|
|
490
|
+
export function syncProjectRepos(db, projectId, repos) {
|
|
491
|
+
removeProjectRepos(db, projectId);
|
|
492
|
+
return repos.map(r => upsertProjectRepo(db, {
|
|
493
|
+
project_id: projectId,
|
|
494
|
+
name: r.name,
|
|
495
|
+
git_url: r.git_url ?? null,
|
|
496
|
+
repo_path: r.repo_path ?? null,
|
|
497
|
+
default_branch: r.default_branch ?? 'main',
|
|
498
|
+
}));
|
|
499
|
+
}
|
|
500
|
+
export function getProjectWithRepos(db, projectId) {
|
|
501
|
+
const project = getProject(db, projectId);
|
|
502
|
+
if (!project)
|
|
503
|
+
return null;
|
|
504
|
+
const repos = getProjectRepos(db, projectId);
|
|
505
|
+
return { ...project, repos };
|
|
506
|
+
}
|
|
507
|
+
// ── CC Sessions CRUD ──
|
|
508
|
+
export function insertCCSession(db, data) {
|
|
509
|
+
return db.insert(ccSessions).values(data).returning().get();
|
|
510
|
+
}
|
|
511
|
+
export function getCCSessionsByTask(db, taskId) {
|
|
512
|
+
return db.select().from(ccSessions)
|
|
513
|
+
.where(eq(ccSessions.task_id, taskId))
|
|
514
|
+
.orderBy(desc(ccSessions.started_at))
|
|
515
|
+
.all();
|
|
516
|
+
}
|
|
517
|
+
export function getCCSessionBySessionId(db, sessionId) {
|
|
518
|
+
return db.select().from(ccSessions)
|
|
519
|
+
.where(eq(ccSessions.session_id, sessionId))
|
|
520
|
+
.get();
|
|
521
|
+
}
|
|
522
|
+
export function updateCCSessionEnded(db, sessionId) {
|
|
523
|
+
return db.update(ccSessions)
|
|
524
|
+
.set({ ended_at: new Date().toISOString() })
|
|
525
|
+
.where(eq(ccSessions.session_id, sessionId))
|
|
526
|
+
.returning()
|
|
527
|
+
.get();
|
|
528
|
+
}
|
|
529
|
+
export function getAllCCSessions(db, filters = {}) {
|
|
530
|
+
const conditions = [];
|
|
531
|
+
if (filters.role)
|
|
532
|
+
conditions.push(eq(ccSessions.role, filters.role));
|
|
533
|
+
if (filters.taskId)
|
|
534
|
+
conditions.push(eq(ccSessions.task_id, filters.taskId));
|
|
535
|
+
if (filters.chatId)
|
|
536
|
+
conditions.push(eq(ccSessions.chat_id, filters.chatId));
|
|
537
|
+
if (filters.active === true)
|
|
538
|
+
conditions.push(isNull(ccSessions.ended_at));
|
|
539
|
+
if (filters.active === false)
|
|
540
|
+
conditions.push(isNotNull(ccSessions.ended_at));
|
|
541
|
+
const where = conditions.length > 0 ? and(...conditions) : undefined;
|
|
542
|
+
const total = db.select({ count: count() }).from(ccSessions)
|
|
543
|
+
.where(where).get()?.count ?? 0;
|
|
544
|
+
const data = db.select().from(ccSessions)
|
|
545
|
+
.where(where)
|
|
546
|
+
.orderBy(desc(ccSessions.started_at))
|
|
547
|
+
.limit(filters.limit ?? 50)
|
|
548
|
+
.offset(filters.offset ?? 0)
|
|
549
|
+
.all();
|
|
550
|
+
return { data, total };
|
|
551
|
+
}
|
|
552
|
+
export function getCCSessionsByChat(db, chatId) {
|
|
553
|
+
return db.select().from(ccSessions)
|
|
554
|
+
.where(eq(ccSessions.chat_id, chatId))
|
|
555
|
+
.orderBy(desc(ccSessions.started_at))
|
|
556
|
+
.all();
|
|
557
|
+
}
|
|
558
|
+
export function getAllProjectsWithStats(db, includeDeleted = false) {
|
|
559
|
+
const where = includeDeleted ? undefined : isNull(projects.deleted_at);
|
|
560
|
+
const allProjects = db.select().from(projects).where(where).orderBy(desc(projects.updated_at)).all();
|
|
561
|
+
const allTasks = db.select({
|
|
562
|
+
project_id: tasks.project_id,
|
|
563
|
+
status: tasks.status,
|
|
564
|
+
updated_at: tasks.updated_at,
|
|
565
|
+
}).from(tasks).all();
|
|
566
|
+
// 每个项目的仓库数量
|
|
567
|
+
const allRepos = db.select({
|
|
568
|
+
project_id: projectRepos.project_id,
|
|
569
|
+
}).from(projectRepos).all();
|
|
570
|
+
const repoCountByProject = {};
|
|
571
|
+
for (const r of allRepos) {
|
|
572
|
+
repoCountByProject[r.project_id] = (repoCountByProject[r.project_id] || 0) + 1;
|
|
573
|
+
}
|
|
574
|
+
const tasksByProject = {};
|
|
575
|
+
for (const t of allTasks) {
|
|
576
|
+
if (!t.project_id)
|
|
577
|
+
continue;
|
|
578
|
+
if (!tasksByProject[t.project_id]) {
|
|
579
|
+
tasksByProject[t.project_id] = { total: 0, done: 0, in_progress: 0, blocked: 0, last_activity: null };
|
|
580
|
+
}
|
|
581
|
+
const stats = tasksByProject[t.project_id];
|
|
582
|
+
stats.total++;
|
|
583
|
+
if (t.status === 'DONE')
|
|
584
|
+
stats.done++;
|
|
585
|
+
else if (t.status === 'IN_PROGRESS')
|
|
586
|
+
stats.in_progress++;
|
|
587
|
+
else if (t.status === 'BLOCKED')
|
|
588
|
+
stats.blocked++;
|
|
589
|
+
if (!stats.last_activity || t.updated_at > stats.last_activity) {
|
|
590
|
+
stats.last_activity = t.updated_at;
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
return allProjects.map(p => ({
|
|
594
|
+
...p,
|
|
595
|
+
repo_count: repoCountByProject[p.project_id] ?? 0,
|
|
596
|
+
task_count: tasksByProject[p.project_id]?.total ?? 0,
|
|
597
|
+
done_count: tasksByProject[p.project_id]?.done ?? 0,
|
|
598
|
+
in_progress_count: tasksByProject[p.project_id]?.in_progress ?? 0,
|
|
599
|
+
blocked_count: tasksByProject[p.project_id]?.blocked ?? 0,
|
|
600
|
+
last_activity_at: tasksByProject[p.project_id]?.last_activity ?? p.updated_at,
|
|
601
|
+
}));
|
|
602
|
+
}
|
|
603
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core';
|
|
2
|
+
import { sql } from 'drizzle-orm';
|
|
3
|
+
export const auditEvents = sqliteTable('audit_events', {
|
|
4
|
+
id: integer('id').primaryKey({ autoIncrement: true }),
|
|
5
|
+
event_type: text('event_type').notNull(),
|
|
6
|
+
actor: text('actor').notNull(),
|
|
7
|
+
task_id: text('task_id'),
|
|
8
|
+
summary: text('summary').notNull(),
|
|
9
|
+
detail: text('detail'), // JSON 字符串
|
|
10
|
+
file_ref: text('file_ref'),
|
|
11
|
+
created_at: text('created_at').notNull().default(sql `(datetime('now'))`),
|
|
12
|
+
});
|
|
13
|
+
//# sourceMappingURL=audit-events.js.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core';
|
|
2
|
+
import { sql } from 'drizzle-orm';
|
|
3
|
+
export const ccSessions = sqliteTable('cc_sessions', {
|
|
4
|
+
id: integer('id').primaryKey({ autoIncrement: true }),
|
|
5
|
+
session_id: text('session_id').notNull(),
|
|
6
|
+
role: text('role').notNull(), // 'loid' | 'yor'
|
|
7
|
+
instance_id: text('instance_id'),
|
|
8
|
+
task_id: text('task_id'),
|
|
9
|
+
chat_id: text('chat_id'),
|
|
10
|
+
project_path: text('project_path'),
|
|
11
|
+
started_at: text('started_at').notNull().default(sql `(datetime('now'))`),
|
|
12
|
+
ended_at: text('ended_at'),
|
|
13
|
+
});
|
|
14
|
+
//# sourceMappingURL=cc-sessions.js.map
|