| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139 |
- const assert = require('assert/strict');
- const fs = require('fs');
- const os = require('os');
- const path = require('path');
- const {
- createDocumentKnowledgeService,
- createTodoKnowledgeService,
- unwrapOfficialResponse,
- } = require('../mcp/src/dashboard/official-office-knowledge-service');
- function rpc(payload) {
- return {
- status: 'ok',
- data: {
- response: {
- jsonrpc: '2.0',
- id: 1,
- result: { isError: false, content: [{ type: 'text', text: JSON.stringify(payload) }] },
- },
- },
- };
- }
- async function main() {
- const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'qiwei-office-knowledge-'));
- const readyStatus = async () => ({ installed: true, valid: true, authorized: true, ready: true, installedVersion: '0.1.9' });
- const available = async () => ({ available: true, reason: 'available', message: '官方能力可用' });
- let docPolls = 0;
- const docCalls = [];
- const docOfficialCall = async request => {
- docCalls.push(request);
- if (request.method === 'create_doc') return rpc({ errcode: 0, docid: 'doc-live-1', url: 'https://doc.weixin.qq.com/doc/demo' });
- if (request.method === 'edit_doc_content') return rpc({ errcode: 0 });
- if (request.method === 'get_doc_content') {
- docPolls += 1;
- if (docPolls % 2 === 1) return rpc({ errcode: 0, task_id: 'task-1', task_done: false });
- return rpc({ errcode: 0, task_id: 'task-1', task_done: true, docid: 'doc-live-1', url: 'https://doc.weixin.qq.com/doc/demo', doc_name: '客户演示方案', content: '# 客户演示方案\n\n王刚负责在 7 月 20 日前整理演示清单。' });
- }
- throw new Error(`unexpected doc method ${request.method}`);
- };
- const analyzer = async () => ({
- status: 'completed', summary: '文档明确了客户演示准备任务。', keyPoints: ['准备客户演示'], decisions: [],
- actionItems: [{ title: '整理演示清单', owner: '王刚', dueDate: '2026-07-20', evidence: '文档原文明确说明', confidence: 0.98 }],
- risks: [], knowledgeTags: ['客户演示'], analysisBasis: '仅基于企微文档原文。', requiresReview: true, analyzedAt: new Date().toISOString(), error: null,
- });
- try {
- const docs = createDocumentKnowledgeService({ storeDir: path.join(tempRoot, 'docs'), officialStatus: readyStatus, officialCall: docOfficialCall, capability: available, analyzer, wait: async () => {} });
- const created = await docs.createDocument({ title: '客户演示方案', content: '# 客户演示方案\n\n正文' });
- assert.equal(created.status, 'ok');
- assert.equal(created.summary.live, true);
- assert.equal(created.data.document.sourceKind, 'official-cli-live');
- assert.match(created.data.document.markdown, /王刚负责/);
- assert.ok(fs.existsSync(created.data.document.files.json));
- assert.ok(fs.existsSync(created.data.document.files.markdown));
- assert.deepEqual(docCalls.slice(0, 2).map(item => item.method), ['create_doc', 'edit_doc_content']);
- assert.ok(docCalls.filter(item => item.method === 'get_doc_content').length >= 2);
- const analyzed = await docs.analyze('doc-live-1');
- assert.equal(analyzed.status, 'ok');
- assert.equal(analyzed.data.document.analysis.actionItems[0].owner, '王刚');
- assert.match(fs.readFileSync(analyzed.data.document.files.markdown, 'utf8'), /整理演示清单/);
- const docHub = await docs.hub();
- assert.equal(docHub.summary.docReady, true);
- assert.equal(docHub.summary.documentCount, 1);
- const permissionDocs = createDocumentKnowledgeService({
- storeDir: path.join(tempRoot, 'permission-docs'), officialStatus: readyStatus, capability: available, wait: async () => {},
- officialCall: async request => {
- if (request.method === 'create_doc') return rpc({ errcode: 0, docid: 'doc-permission-1', url: 'https://doc.weixin.qq.com/doc/permission' });
- if (request.method === 'edit_doc_content') return rpc({ errcode: 0 });
- return rpc({ errcode: 851008, errmsg: 'partial no authorization' });
- },
- });
- const permissionCreated = await permissionDocs.createDocument({ title: '待读权限文档', content: '# 已成功写入' });
- assert.equal(permissionCreated.status, 'ok');
- assert.equal(permissionCreated.summary.readbackPending, true);
- assert.equal(permissionCreated.data.document.readbackStatus, 'pending-permission');
- assert.equal(permissionCreated.data.document.sourceKind, 'official-cli-live-created');
- const todoCalls = [];
- let todoListEmpty = false;
- const todoOfficialCall = async request => {
- todoCalls.push(request);
- if (request.method === 'search_todo_userid') return rpc({ errcode: 0, user_list: [{ userid: 'wanggang', name: '王刚', alias: '刚sir' }] });
- if (request.method === 'get_todo_list') return rpc({ errcode: 0, todo_list: todoListEmpty ? [] : [
- { todo_id: 'todo-live-1', content: '整理客户资料', todo_status: 1, end_time: '2026-07-20 18:00:00', follower_list: { followers: [{ follower_id: 'wanggang' }] } },
- { todo_id: 'todo-live-2', content: '确认演示时间', todo_status: 0, follower_list: { followers: [{ follower_id: 'wanggang' }] } },
- ] });
- if (request.method === 'get_todo_detail') return rpc({ errcode: 0, data_list: [
- { todo_id: 'todo-live-3', content: '制作客户演示截图', todo_status: 1, end_time: '2026-07-21 18:00:00', follower_list: { followers: [{ follower_id: 'wanggang' }] } },
- ] });
- if (request.method === 'create_todo') return rpc({ errcode: 0, todo_id: 'todo-live-3' });
- if (request.method === 'update_todo') return rpc({ errcode: 0 });
- throw new Error(`unexpected todo method ${request.method}`);
- };
- const todos = createTodoKnowledgeService({ storeDir: path.join(tempRoot, 'todos'), officialStatus: readyStatus, officialCall: todoOfficialCall, capability: available });
- const users = await todos.searchUsers({ keyword: '王刚' });
- assert.equal(users.data.users[0].id, 'wanggang');
- const synced = await todos.sync({ followerId: 'wanggang' });
- assert.equal(synced.status, 'ok');
- assert.equal(synced.summary.syncedCount, 2);
- const todoCreated = await todos.create({ content: '制作客户演示截图', followerIds: ['wanggang'], endTime: '2026-07-21T18:00', remindType: 3 });
- assert.equal(todoCreated.status, 'ok');
- assert.equal(todoCreated.data.todo.id, 'todo-live-3');
- const refreshed = await todos.refreshDetails({ todoIds: ['todo-live-3'] });
- assert.equal(refreshed.summary.refreshedCount, 1);
- todoListEmpty = true;
- const preserved = await todos.sync({ followerId: 'wanggang' });
- assert.equal(preserved.summary.preservedCount, 3);
- const completed = await todos.complete('todo-live-3');
- assert.equal(completed.status, 'ok');
- assert.equal(todos.readIndex().todos.find(item => item.id === 'todo-live-3').status, 0);
- assert.ok(fs.existsSync(path.join(tempRoot, 'todos', 'todos.md')));
- const unwrapped = unwrapOfficialResponse(rpc({ errcode: 0, value: 'real' }));
- assert.equal(unwrapped.value, 'real');
- let blockedCalls = 0;
- const blockedDocs = createDocumentKnowledgeService({
- storeDir: path.join(tempRoot, 'blocked'), officialStatus: readyStatus,
- officialCall: async () => { blockedCalls += 1; throw new Error('blocked capability must not call live API'); },
- capability: async () => ({ available: false, reason: 'enterprise-policy', message: '文档能力未开放' }),
- });
- const blocked = await blockedDocs.importDocument({ docid: 'x' });
- assert.equal(blocked.status, 'error');
- assert.equal(blockedCalls, 0);
- process.stdout.write(`${JSON.stringify({ status: 'ok', officialEnvelopeUnwrapped: true, documentCreateReadAnalyze: true, documentReadPermissionFallback: true, todoSearchSyncCreateComplete: true, blockedPathMakesNoLiveCall: true }, null, 2)}\n`);
- } finally {
- fs.rmSync(tempRoot, { recursive: true, force: true });
- }
- }
- main().catch(error => {
- process.stderr.write(`${error.stack || error.message}\n`);
- process.exitCode = 1;
- });
|