team-anya-cli 0.1.4 → 0.1.6
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/apps/server/dist/broker/cc-broker.js +5 -1
- package/apps/server/dist/franky/context-builder.js +160 -0
- package/apps/server/dist/franky/franky-mcp-server.js +107 -0
- package/apps/server/dist/franky/franky-orchestrator.js +450 -0
- package/apps/server/dist/franky/index.js +5 -0
- package/apps/server/dist/franky/topic-router.js +16 -0
- package/apps/server/dist/gateway/feishu-sender.js +66 -2
- package/apps/server/dist/gateway/feishu-ws.js +5 -4
- package/apps/server/dist/gateway/message-intake.js +21 -4
- package/apps/server/dist/loid/brain.js +1 -0
- package/apps/server/dist/loid/mcp-server.js +1 -0
- package/apps/server/dist/loid/session-manager.js +95 -11
- package/apps/server/dist/main.js +58 -3
- package/apps/web/dist/assets/index-BiiEB0qZ.css +1 -0
- package/apps/web/dist/assets/{index-CJzAjoVH.js → index-D1AK5ZEE.js} +189 -189
- package/apps/web/dist/index.html +2 -2
- package/package.json +1 -1
- package/packages/core/dist/office-init.js +4 -0
- package/packages/core/dist/scope/defaults.js +15 -0
- package/packages/core/dist/scope/index.js +1 -1
- package/packages/db/dist/index.js +95 -7
- package/packages/db/dist/schema/cc-sessions.js +1 -1
- package/packages/db/dist/schema/index.js +1 -0
- package/packages/db/dist/schema/tasks.js +2 -0
- package/packages/db/dist/schema/topics.js +20 -0
- package/packages/db/src/migrations/0005_lethal_golden_guardian.sql +5 -0
- package/packages/db/src/migrations/0006_add_topics.sql +21 -0
- package/packages/db/src/migrations/0007_add_topic_root_message_id.sql +1 -0
- package/packages/db/src/migrations/meta/0005_snapshot.json +1513 -0
- package/packages/db/src/migrations/meta/0006_snapshot.json +1513 -0
- package/packages/db/src/migrations/meta/_journal.json +21 -0
- package/packages/mcp-tools/dist/layer2/franky/topic-checkpoint.js +43 -0
- package/packages/mcp-tools/dist/layer2/franky/topic-escalate.js +19 -0
- package/packages/mcp-tools/dist/layer2/loid/topic-close.js +22 -0
- package/packages/mcp-tools/dist/layer2/loid/topic-create.js +56 -0
- package/packages/mcp-tools/dist/layer3/adapters/feishu-adapter.js +1 -0
- package/packages/mcp-tools/dist/layer3/channel-send.js +1 -0
- package/packages/mcp-tools/dist/registry.js +105 -17
- package/workspace/CHARTER.md +7 -4
- package/workspace/CLAUDE.md +18 -9
- package/workspace/PROTOCOL.md +35 -1
- package/workspace/TOOLS.md +6 -0
- package/workspace/franky/CLAUDE.md +37 -0
- package/workspace/franky/PLAYBOOK.md +215 -0
- package/workspace/franky/PROFILE.md +80 -0
- package/apps/web/dist/assets/index-CHIT0Dya.css +0 -1
package/apps/web/dist/index.html
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<title>Anya Gateway Dashboard</title>
|
|
7
|
-
<script type="module" crossorigin src="/assets/index-
|
|
8
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
7
|
+
<script type="module" crossorigin src="/assets/index-D1AK5ZEE.js"></script>
|
|
8
|
+
<link rel="stylesheet" crossorigin href="/assets/index-BiiEB0qZ.css">
|
|
9
9
|
</head>
|
|
10
10
|
<body>
|
|
11
11
|
<div id="root"></div>
|
package/package.json
CHANGED
|
@@ -13,6 +13,9 @@ const ALWAYS_OVERWRITE_FILES = [
|
|
|
13
13
|
'yor/PROFILE.md',
|
|
14
14
|
'yor/PLAYBOOK.md',
|
|
15
15
|
'yor/SELF-HEAL.md',
|
|
16
|
+
'franky/CLAUDE.md',
|
|
17
|
+
'franky/PROFILE.md',
|
|
18
|
+
'franky/PLAYBOOK.md',
|
|
16
19
|
];
|
|
17
20
|
/** 仅当目标不存在时才复制的文件(配置/数据,运行时可能被修改) */
|
|
18
21
|
const COPY_IF_MISSING_FILES = [
|
|
@@ -34,6 +37,7 @@ const REQUIRED_DIRS = [
|
|
|
34
37
|
'reports',
|
|
35
38
|
'yor',
|
|
36
39
|
'loid',
|
|
40
|
+
'franky',
|
|
37
41
|
'.claude',
|
|
38
42
|
];
|
|
39
43
|
async function exists(path) {
|
|
@@ -37,4 +37,19 @@ export const DEFAULT_FORBIDDEN_PATHS = [
|
|
|
37
37
|
'**/.git/objects/**',
|
|
38
38
|
'**/.git/refs/**',
|
|
39
39
|
];
|
|
40
|
+
/**
|
|
41
|
+
* Franky 专项模式的默认 scope
|
|
42
|
+
* 比 Yor 更宽松:允许 git push 到 feature 分支,允许创建 PR
|
|
43
|
+
* 但仍禁止 push main/master 和 force push
|
|
44
|
+
*/
|
|
45
|
+
export const FRANKY_DEFAULT_SCOPE = {
|
|
46
|
+
allowedPaths: ['**'],
|
|
47
|
+
forbiddenPaths: DEFAULT_FORBIDDEN_PATHS,
|
|
48
|
+
allowedCommands: ['**'],
|
|
49
|
+
forbiddenCommands: [
|
|
50
|
+
'git push\\s+--force',
|
|
51
|
+
'git push\\b.*--force',
|
|
52
|
+
'git push\\b.*\\b(main|master)\\b',
|
|
53
|
+
],
|
|
54
|
+
};
|
|
40
55
|
//# sourceMappingURL=defaults.js.map
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { ScopeChecker, DEFAULT_SCOPE } from './checker.js';
|
|
2
|
-
export { DEFAULT_FORBIDDEN_COMMANDS, DEFAULT_FORBIDDEN_PATHS } from './defaults.js';
|
|
2
|
+
export { DEFAULT_FORBIDDEN_COMMANDS, DEFAULT_FORBIDDEN_PATHS, FRANKY_DEFAULT_SCOPE } from './defaults.js';
|
|
3
3
|
//# sourceMappingURL=index.js.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
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';
|
|
2
|
+
import { tasks, taskClarifications, commitments, opportunities, auditEvents, orgMembers, orgOwnership, orgEscalationRules, communicationEvents, messageLog, traceSpans, chats, chatMembers, projects, projectRepos, ccSessions, topics } from './schema/index.js';
|
|
3
3
|
export { createDB, createTestDB } from './client.js';
|
|
4
4
|
export * from './schema/index.js';
|
|
5
5
|
// ── Task CRUD ──
|
|
@@ -236,11 +236,32 @@ export function getRecentMessages(db, opts = {}) {
|
|
|
236
236
|
conditions.push(eq(messageLog.chat_id, chat_id));
|
|
237
237
|
if (chat_type)
|
|
238
238
|
conditions.push(eq(messageLog.chat_type, chat_type));
|
|
239
|
-
const
|
|
240
|
-
? db.select().from(messageLog).where(and(...conditions))
|
|
241
|
-
: db.select().from(messageLog);
|
|
239
|
+
const whereClause = conditions.length > 0 ? and(...conditions) : undefined;
|
|
242
240
|
const orderBy = sortOrder === 'asc' ? messageLog.created_at : desc(messageLog.created_at);
|
|
243
|
-
return
|
|
241
|
+
return db
|
|
242
|
+
.select({
|
|
243
|
+
id: messageLog.id,
|
|
244
|
+
direction: messageLog.direction,
|
|
245
|
+
source_type: messageLog.source_type,
|
|
246
|
+
source_ref: messageLog.source_ref,
|
|
247
|
+
sender: messageLog.sender,
|
|
248
|
+
sender_name: sql `(SELECT name FROM org_members WHERE member_id = ${messageLog.sender})`,
|
|
249
|
+
receiver: messageLog.receiver,
|
|
250
|
+
receiver_name: sql `(SELECT name FROM org_members WHERE member_id = ${messageLog.receiver})`,
|
|
251
|
+
chat_id: messageLog.chat_id,
|
|
252
|
+
chat_type: messageLog.chat_type,
|
|
253
|
+
content: messageLog.content,
|
|
254
|
+
message_type: messageLog.message_type,
|
|
255
|
+
intent_level: messageLog.intent_level,
|
|
256
|
+
related_task_id: messageLog.related_task_id,
|
|
257
|
+
metadata: messageLog.metadata,
|
|
258
|
+
trace_id: messageLog.trace_id,
|
|
259
|
+
created_at: messageLog.created_at,
|
|
260
|
+
chat_name: chats.name,
|
|
261
|
+
})
|
|
262
|
+
.from(messageLog)
|
|
263
|
+
.leftJoin(chats, eq(messageLog.chat_id, chats.chat_id))
|
|
264
|
+
.where(whereClause)
|
|
244
265
|
.orderBy(orderBy)
|
|
245
266
|
.limit(limit)
|
|
246
267
|
.offset(offset)
|
|
@@ -425,7 +446,7 @@ export function getMemberChats(db, memberId) {
|
|
|
425
446
|
return db.select({
|
|
426
447
|
chat_id: chats.chat_id,
|
|
427
448
|
name: chats.name,
|
|
428
|
-
|
|
449
|
+
chat_mode: chats.chat_mode,
|
|
429
450
|
chat_tag: chats.chat_tag,
|
|
430
451
|
user_count: chats.user_count,
|
|
431
452
|
role: chatMembers.role,
|
|
@@ -506,7 +527,7 @@ export function getProjectWithRepos(db, projectId) {
|
|
|
506
527
|
}
|
|
507
528
|
// ── CC Sessions CRUD ──
|
|
508
529
|
export function insertCCSession(db, data) {
|
|
509
|
-
return db.insert(ccSessions).values(data).returning().get();
|
|
530
|
+
return db.insert(ccSessions).values(data).onConflictDoNothing({ target: ccSessions.session_id }).returning().get();
|
|
510
531
|
}
|
|
511
532
|
export function getCCSessionsByTask(db, taskId) {
|
|
512
533
|
return db.select().from(ccSessions)
|
|
@@ -600,4 +621,71 @@ export function getAllProjectsWithStats(db, includeDeleted = false) {
|
|
|
600
621
|
last_activity_at: tasksByProject[p.project_id]?.last_activity ?? p.updated_at,
|
|
601
622
|
}));
|
|
602
623
|
}
|
|
624
|
+
export function upsertTopic(db, input) {
|
|
625
|
+
const now = new Date().toISOString().replace(/\.\d{3}Z$/, 'Z');
|
|
626
|
+
return db.insert(topics).values({
|
|
627
|
+
id: input.id,
|
|
628
|
+
project_id: input.project_id ?? null,
|
|
629
|
+
title: input.title,
|
|
630
|
+
description: input.description ?? null,
|
|
631
|
+
status: input.status,
|
|
632
|
+
thread_id: input.thread_id ?? null,
|
|
633
|
+
root_message_id: input.root_message_id ?? null,
|
|
634
|
+
chat_id: input.chat_id ?? null,
|
|
635
|
+
workspace_path: input.workspace_path ?? null,
|
|
636
|
+
branch_name: input.branch_name ?? null,
|
|
637
|
+
created_by: input.created_by ?? null,
|
|
638
|
+
created_at: now,
|
|
639
|
+
updated_at: now,
|
|
640
|
+
}).onConflictDoUpdate({
|
|
641
|
+
target: topics.id,
|
|
642
|
+
set: {
|
|
643
|
+
title: input.title,
|
|
644
|
+
description: input.description ?? null,
|
|
645
|
+
status: input.status,
|
|
646
|
+
thread_id: input.thread_id ?? null,
|
|
647
|
+
root_message_id: input.root_message_id ?? null,
|
|
648
|
+
chat_id: input.chat_id ?? null,
|
|
649
|
+
workspace_path: input.workspace_path ?? null,
|
|
650
|
+
branch_name: input.branch_name ?? null,
|
|
651
|
+
updated_at: now,
|
|
652
|
+
},
|
|
653
|
+
}).run();
|
|
654
|
+
}
|
|
655
|
+
export function getTopic(db, id) {
|
|
656
|
+
return db.select().from(topics).where(eq(topics.id, id)).get();
|
|
657
|
+
}
|
|
658
|
+
export function getTopicByThreadId(db, threadId) {
|
|
659
|
+
return db.select().from(topics)
|
|
660
|
+
.where(and(eq(topics.thread_id, threadId), eq(topics.status, 'active')))
|
|
661
|
+
.get();
|
|
662
|
+
}
|
|
663
|
+
export function updateTopicStatus(db, id, status) {
|
|
664
|
+
const now = new Date().toISOString().replace(/\.\d{3}Z$/, 'Z');
|
|
665
|
+
return db.update(topics).set({
|
|
666
|
+
status,
|
|
667
|
+
updated_at: now,
|
|
668
|
+
...(status === 'closed' ? { closed_at: now } : {}),
|
|
669
|
+
}).where(eq(topics.id, id)).run();
|
|
670
|
+
}
|
|
671
|
+
export function getActiveTopics(db) {
|
|
672
|
+
return db.select().from(topics).where(eq(topics.status, 'active')).all();
|
|
673
|
+
}
|
|
674
|
+
export function getTodayMaxTopicSequence(db) {
|
|
675
|
+
const today = new Date().toISOString().slice(0, 10).replace(/-/g, '');
|
|
676
|
+
const prefix = `TOPIC-${today}-`;
|
|
677
|
+
const rows = db.select().from(topics).where(like(topics.id, `${prefix}%`)).all();
|
|
678
|
+
let max = 0;
|
|
679
|
+
for (const topic of rows) {
|
|
680
|
+
const seq = parseInt(topic.id.split('-')[2], 10);
|
|
681
|
+
if (seq > max)
|
|
682
|
+
max = seq;
|
|
683
|
+
}
|
|
684
|
+
return max;
|
|
685
|
+
}
|
|
686
|
+
export function generateTopicId(db) {
|
|
687
|
+
const today = new Date().toISOString().slice(0, 10).replace(/-/g, '');
|
|
688
|
+
const max = getTodayMaxTopicSequence(db);
|
|
689
|
+
return `TOPIC-${today}-${String(max + 1).padStart(3, '0')}`;
|
|
690
|
+
}
|
|
603
691
|
//# sourceMappingURL=index.js.map
|
|
@@ -2,7 +2,7 @@ import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core';
|
|
|
2
2
|
import { sql } from 'drizzle-orm';
|
|
3
3
|
export const ccSessions = sqliteTable('cc_sessions', {
|
|
4
4
|
id: integer('id').primaryKey({ autoIncrement: true }),
|
|
5
|
-
session_id: text('session_id').notNull(),
|
|
5
|
+
session_id: text('session_id').notNull().unique(),
|
|
6
6
|
role: text('role').notNull(), // 'loid' | 'yor'
|
|
7
7
|
instance_id: text('instance_id'),
|
|
8
8
|
task_id: text('task_id'),
|
|
@@ -29,6 +29,8 @@ export const tasks = sqliteTable('tasks', {
|
|
|
29
29
|
cc_session_id: text('cc_session_id'),
|
|
30
30
|
// 文件路径
|
|
31
31
|
workspace_path: text('workspace_path'),
|
|
32
|
+
// 专项关联(可选,用于回溯关联)
|
|
33
|
+
topic_id: text('topic_id'),
|
|
32
34
|
// 时间戳
|
|
33
35
|
created_at: text('created_at').notNull().default(sql `(strftime('%Y-%m-%dT%H:%M:%SZ', 'now'))`),
|
|
34
36
|
updated_at: text('updated_at').notNull().default(sql `(strftime('%Y-%m-%dT%H:%M:%SZ', 'now'))`),
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { sqliteTable, text } from 'drizzle-orm/sqlite-core';
|
|
2
|
+
import { sql } from 'drizzle-orm';
|
|
3
|
+
import { projects } from './projects.js';
|
|
4
|
+
export const topics = sqliteTable('topics', {
|
|
5
|
+
id: text('id').primaryKey(),
|
|
6
|
+
project_id: text('project_id').references(() => projects.project_id),
|
|
7
|
+
title: text('title').notNull(),
|
|
8
|
+
description: text('description'),
|
|
9
|
+
status: text('status').notNull().default('active'),
|
|
10
|
+
thread_id: text('thread_id'),
|
|
11
|
+
root_message_id: text('root_message_id'),
|
|
12
|
+
chat_id: text('chat_id'),
|
|
13
|
+
workspace_path: text('workspace_path'),
|
|
14
|
+
branch_name: text('branch_name'),
|
|
15
|
+
created_by: text('created_by'),
|
|
16
|
+
created_at: text('created_at').notNull().default(sql `(strftime('%Y-%m-%dT%H:%M:%SZ', 'now'))`),
|
|
17
|
+
updated_at: text('updated_at').notNull().default(sql `(strftime('%Y-%m-%dT%H:%M:%SZ', 'now'))`),
|
|
18
|
+
closed_at: text('closed_at'),
|
|
19
|
+
});
|
|
20
|
+
//# sourceMappingURL=topics.js.map
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
-- 先删除重复的 cc_sessions 记录(保留每个 session_id 中 id 最小的那条)
|
|
2
|
+
DELETE FROM `cc_sessions` WHERE `id` NOT IN (
|
|
3
|
+
SELECT MIN(`id`) FROM `cc_sessions` GROUP BY `session_id`
|
|
4
|
+
);--> statement-breakpoint
|
|
5
|
+
CREATE UNIQUE INDEX `cc_sessions_session_id_unique` ON `cc_sessions` (`session_id`);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
CREATE TABLE `topics` (
|
|
2
|
+
`id` text PRIMARY KEY NOT NULL,
|
|
3
|
+
`project_id` text REFERENCES `projects`(`project_id`),
|
|
4
|
+
`title` text NOT NULL,
|
|
5
|
+
`description` text,
|
|
6
|
+
`status` text NOT NULL DEFAULT 'active',
|
|
7
|
+
`thread_id` text,
|
|
8
|
+
`chat_id` text,
|
|
9
|
+
`workspace_path` text,
|
|
10
|
+
`branch_name` text,
|
|
11
|
+
`created_by` text,
|
|
12
|
+
`created_at` text NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')),
|
|
13
|
+
`updated_at` text NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')),
|
|
14
|
+
`closed_at` text
|
|
15
|
+
);
|
|
16
|
+
--> statement-breakpoint
|
|
17
|
+
CREATE INDEX `idx_topics_thread_id` ON `topics` (`thread_id`);
|
|
18
|
+
--> statement-breakpoint
|
|
19
|
+
CREATE INDEX `idx_topics_status` ON `topics` (`status`);
|
|
20
|
+
--> statement-breakpoint
|
|
21
|
+
ALTER TABLE `tasks` ADD COLUMN `topic_id` text REFERENCES `topics`(`id`);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ALTER TABLE `topics` ADD `root_message_id` text;
|