import test from 'node:test'; import assert from 'node:assert/strict'; import crypto from 'node:crypto'; import fs from 'node:fs'; import os from 'node:os'; import path from 'node:path'; import { createWechatMpService as createProductionWechatMpService } from './wechat-mp.mjs'; import { prepareWechatHtmlDeliveryAtWorkspace } from './mindspace-wechat-html-delivery.mjs'; import { isWechatCursorChannelReply, prepareWechatCursorPageDelivery, } from './wechat-cursor-page-delivery.mjs'; import { PUBLISH_ROOT_DIR } from './user-publish.mjs'; function sha1(parts) { return crypto.createHash('sha1').update([...parts].sort().join('')).digest('hex'); } function signatureFor(token, timestamp, nonce) { return sha1([token, timestamp, nonce]); } function inboundXml({ fromUser = 'openid-test-1', content = '帮我做个测试页面' } = {}) { return [ '', '', ``, '1710000000', '', ``, 'msg-cursor-test-1', '', ].join(''); } function createWechatMpService(options) { const resolvePublishDir = async (userId) => options.userAuth?.resolveWorkingDir?.(userId) ?? `/tmp/${userId}`; const buildCanonicalUrl = (userId, relativePath) => { const base = String(options.config?.publicBaseUrl ?? 'https://example.com').replace(/\/+$/, ''); const normalized = String(relativePath).replace(/^\/+/, '').split('/').map(encodeURIComponent).join('/'); return `${base}/MindSpace/${encodeURIComponent(userId)}/${normalized}`; }; const htmlDeliveryAuthority = options.htmlDeliveryAuthority ?? { async prepareWechatHtmlDelivery(input) { const publishDir = await resolvePublishDir(input.userId); return prepareWechatHtmlDeliveryAtWorkspace({ reply: input.reply, intent: input.intent, publishDir, requestStartedAt: input.requestStartedAt, allowRecentArtifacts: input.allowRecentArtifacts, buildCanonicalUrl: (relativePath) => buildCanonicalUrl(input.userId, relativePath), }); }, async ensureWechatFreshPageThumbnails() { return { artifacts: [], images: [] }; }, }; return createProductionWechatMpService({ ...options, htmlDeliveryAuthority, }); } function createBoundWechatService(overrides = {}) { const apiCalls = []; const wechatCalls = []; const cursorCalls = []; const token = overrides.token ?? 'test-token'; const userId = overrides.userId ?? 'user-cursor-test'; const agentRunGateway = overrides.agentRunGateway ?? { async createRun(runUserId, payload) { cursorCalls.push(['createRun', runUserId, payload]); const touchNow = Date.now(); fs.utimesSync(htmlPath, touchNow / 1000, touchNow / 1000); return { id: 'run-cursor-1', status: 'queued' }; }, dispatchRun(runId) { cursorCalls.push(['dispatchRun', runId]); }, async getRunForUser(runUserId, runId) { cursorCalls.push(['getRunForUser', runUserId, runId]); return { id: runId, status: 'succeeded', error: null }; }, async listRunEventsForUser(runUserId, runId) { cursorCalls.push(['listRunEventsForUser', runUserId, runId]); return { events: [{ id: 'evt-1', eventType: 'tool_gateway_result', data: { executor: 'cursor', stdoutTail: '已生成 public/cursor-wechat-test-page.html', }, createdAt: Date.now(), }], }; }, }; const wechatCursorExecutorPolicyService = overrides.wechatCursorExecutorPolicyService ?? { async getEffectivePolicy() { return { enabled: false, userAllowed: false, userAllowlist: [], intentAllowlist: ['page.generate'], fallbackToDeepseek: true, }; }, }; const h5Root = fs.mkdtempSync(path.join(os.tmpdir(), 'wechat-cursor-h5-')); const publishDir = path.join(h5Root, PUBLISH_ROOT_DIR, userId); fs.mkdirSync(path.join(publishDir, 'public'), { recursive: true }); const htmlPath = path.join(publishDir, 'public', 'cursor-wechat-test-page.html'); fs.writeFileSync(htmlPath, 'Cursor Page
hi
'); const now = Date.now(); fs.utimesSync(htmlPath, now / 1000, now / 1000); const service = createWechatMpService({ h5Root, config: { enabled: true, appId: 'wx_local_test_only', appSecret: 'local-secret', token, publicBaseUrl: 'https://example.com', mediaPublicBaseUrl: 'https://example.com', bindPath: '/auth/wechat/authorize?intent=login', ackText: 'ack', unsupportedText: 'unsupported', unboundTextPrefix: '请先绑定', progressDelayMs: 0, requireFreshPageThumbnail: false, ...(overrides.config ?? {}), }, userAuth: { async findWechatUserByOpenid(_appId, openid) { return { userId, status: 'active', nickname: '测试用户', username: 'test-user', openid, }; }, async getWechatAgentRoute() { return { agentSessionId: 'session-cursor-1', isNewSession: false }; }, async clearWechatAgentRoute() {}, async canUseChat() { return { ok: true }; }, async resolveWorkingDir() { return publishDir; }, async getAgentSessionPolicy() { return { enableContextMemory: false, extensionOverrides: [], unrestricted: true }; }, async getUserPublishLayout() { return { displayName: '测试用户', username: 'test-user', slug: 'test-user', constraints: null }; }, async registerAgentSession() {}, async upsertWechatAgentRoute() {}, async billSessionUsage() {}, async recordWechatMpMessage() { return { inserted: true }; }, async finishWechatMpMessage() {}, async insertWechatMpMessageDetail() {}, ...(overrides.userAuth ?? {}), }, agentRunGateway, wechatCursorExecutorPolicyService, sessionApiFetch: async (sessionId, pathname, init = {}) => { apiCalls.push([pathname, init.method ?? 'GET']); if (pathname.endsWith('/events')) { return new Response( [ 'data: {"type":"Message","request_id":"req-fallback-1","message":{"id":"assistant-1","role":"assistant","metadata":{"userVisible":true},"content":[{"type":"text","text":"DeepSeek 回退页面已完成\\nhttps://example.com/MindSpace/user-cursor-test/public/fallback-page.html"}]}}\n\n', 'data: {"type":"Finish","request_id":"req-fallback-1","token_state":{"inputTokens":1,"outputTokens":2}}\n\n', ].join(''), { status: 200, headers: { 'Content-Type': 'text/event-stream' } }, ); } if (pathname.endsWith('/reply')) { return new Response('{}', { status: 200, headers: { 'Content-Type': 'application/json' } }); } if (pathname.includes('/agent/harness_remember') || pathname.includes('/agent/session/reconcile') || pathname.includes('/agent/harness_bootstrap')) { return new Response('{}', { status: 200, headers: { 'Content-Type': 'application/json' } }); } throw new Error(`unexpected api path: ${pathname} session=${sessionId}`); }, wechatFetch: async (url, init = {}) => { wechatCalls.push([String(url), init.method ?? 'GET', init]); if (String(url).includes('/cgi-bin/stable_token')) { return new Response(JSON.stringify({ access_token: 'local-access-token', expires_in: 7200 }), { status: 200, headers: { 'Content-Type': 'application/json' }, }); } if (String(url).includes('/cgi-bin/message/custom/send')) { return new Response(JSON.stringify({ errcode: 0, errmsg: 'ok' }), { status: 200, headers: { 'Content-Type': 'application/json' }, }); } throw new Error(`unexpected wechat url: ${url}`); }, linkExists: async (urlText) => String(urlText).includes('cursor-wechat-test-page.html') || String(urlText).includes('fallback-page.html'), ...(overrides.extra ?? {}), }); return { service, apiCalls, wechatCalls, cursorCalls, publishDir, token, }; } test('non-allowlisted wechat user keeps deepseek session reply path', async () => { const { service, apiCalls, cursorCalls, token } = createBoundWechatService(); const timestamp = '1710000000'; const nonce = 'nonce-no-cursor'; const result = await service.handleInboundMessage( inboundXml({ content: '帮我做一个简单测试页面' }), { timestamp, nonce, signature: signatureFor(token, timestamp, nonce) }, ); assert.equal(result.status, 200); await result.task; assert.equal(cursorCalls.some(([kind]) => kind === 'createRun'), false); assert.equal(apiCalls.some(([pathname]) => String(pathname).endsWith('/reply')), true); }); test('allowlisted wechat user uses cursor agent-run path without session reply', async () => { const { service, apiCalls, cursorCalls, wechatCalls, token } = createBoundWechatService({ wechatCursorExecutorPolicyService: { async getEffectivePolicy(_userId, user) { return { enabled: true, userAllowed: true, userAllowlist: [user?.userId ?? 'user-cursor-test'], intentAllowlist: ['page.generate'], fallbackToDeepseek: true, }; }, }, }); const timestamp = '1710000001'; const nonce = 'nonce-cursor'; const result = await service.handleInboundMessage( inboundXml({ content: '帮我做一个简单测试页面' }), { timestamp, nonce, signature: signatureFor(token, timestamp, nonce) }, ); assert.equal(result.status, 200); await result.task; assert.equal(cursorCalls.some(([kind]) => kind === 'createRun'), true); assert.equal(apiCalls.some(([pathname]) => String(pathname).endsWith('/reply')), false); const customSend = wechatCalls.find(([url]) => String(url).includes('/cgi-bin/message/custom/send')); assert.ok(customSend, 'expected wechat custom send'); const sendBody = JSON.parse(String(customSend[2]?.body ?? '{}')); const outboundText = String(sendBody?.text?.content ?? ''); assert.doesNotMatch(outboundText, /没有按服务号页面技能真正生成成功/); assert.match(outboundText, /cursor-wechat-test-page\.html/); }); test('allowlisted user falls back to deepseek when cursor run fails', async () => { const { service, apiCalls, cursorCalls, token } = createBoundWechatService({ agentRunGateway: { async createRun(runUserId, payload) { cursorCalls.push(['createRun', runUserId, payload]); return { id: 'run-fail-1', status: 'queued' }; }, dispatchRun(runId) { cursorCalls.push(['dispatchRun', runId]); }, async getRunForUser(runUserId, runId) { cursorCalls.push(['getRunForUser', runUserId, runId]); return { id: runId, status: 'failed', error: 'simulated cursor failure' }; }, async listRunEventsForUser() { return { events: [] }; }, }, wechatCursorExecutorPolicyService: { async getEffectivePolicy() { return { enabled: true, userAllowed: true, userAllowlist: ['user-cursor-test'], intentAllowlist: ['page.generate'], fallbackToDeepseek: true, }; }, }, }); const timestamp = '1710000002'; const nonce = 'nonce-fallback'; const result = await service.handleInboundMessage( inboundXml({ content: '帮我做一个简单测试页面' }), { timestamp, nonce, signature: signatureFor(token, timestamp, nonce) }, ); assert.equal(result.status, 200); await result.task; assert.equal(cursorCalls.some(([kind]) => kind === 'createRun'), true); assert.equal(apiCalls.some(([pathname]) => String(pathname).endsWith('/reply')), true); }); test('production-like openid in script default is not used when policy disabled', async () => { const prodLikeOpenid = 'ooil-0VFj68QK1tkHl39uL610et8'; const { service, cursorCalls, token } = createBoundWechatService({ userId: '1c99b83b-0454-474f-a5d2-129d34506a32', userAuth: { async findWechatUserByOpenid(_appId, openid) { assert.equal(openid, prodLikeOpenid); return { userId: '1c99b83b-0454-474f-a5d2-129d34506a32', status: 'active', nickname: 'John', username: 'john', }; }, }, }); const timestamp = '1710000003'; const nonce = 'nonce-prod-openid'; const result = await service.handleInboundMessage( inboundXml({ fromUser: prodLikeOpenid, content: '你好' }), { timestamp, nonce, signature: signatureFor(token, timestamp, nonce) }, ); assert.equal(result.status, 200); await result.task; assert.equal(cursorCalls.length, 0); });