'use strict'; const assert = require('assert/strict'); const fs = require('fs'); const os = require('os'); const path = require('path'); const { spawnSync } = require('child_process'); const { resolveWorkspaceRoot, workspaceIdentity } = require('../mcp/src/core/runtime-context'); const { buildStartupSummary, startupAssistantMessage } = require('../mcp/src/core/startup-summary'); const ROOT = path.resolve(__dirname, '..'); function testRuntimeContext(tempRoot) { const installedPackage = path.join(tempRoot, '.claude', 'plugins', 'qiwei-assistant'); fs.mkdirSync(installedPackage, { recursive: true }); assert.equal(resolveWorkspaceRoot({ packageRoot: installedPackage, cwd: installedPackage }), tempRoot); assert.equal(resolveWorkspaceRoot({ packageRoot: ROOT, workspaceRoot: tempRoot }), tempRoot); assert.match(workspaceIdentity(tempRoot), /^[0-9a-f]{12}$/); } function testStartupSummary() { const offline = buildStartupSummary( { summary: { authConfigured: true, subscribed: true } }, { data: { account: { configured: true, online: false }, listener: { running: false }, config: { allowedSenderCount: 1 } } }, ); assert.equal(offline.ready, false); assert.equal(offline.nextAction, '在工作台点击“恢复登录”'); assert.match(startupAssistantMessage(offline), /企微账号待处理/); const ready = buildStartupSummary( { summary: { authConfigured: true, subscribed: true } }, { data: { account: { configured: true, online: true }, listener: { running: true }, config: { allowedSenderCount: 1 } } }, ); assert.equal(ready.ready, true); assert.match(ready.nextAction, /可以进入智能会话/); } function testWorkspaceInstall(tempRoot) { const target = path.join(tempRoot, 'customer-project'); fs.mkdirSync(target, { recursive: true }); fs.writeFileSync(path.join(target, '.gitignore'), '# Customer rules\ncustomer-cache/\n', 'utf8'); const result = spawnSync(process.execPath, [path.join(ROOT, 'install.js'), 'workspace', target, '--skip-install'], { cwd: ROOT, encoding: 'utf8', windowsHide: true, }); assert.equal(result.status, 0, result.stderr || result.stdout); const mcp = JSON.parse(fs.readFileSync(path.join(target, '.mcp.json'), 'utf8')); const config = mcp.mcpServers?.['qiwei-assistant']; assert.equal(config.cwd, target); assert.equal(config.env?.QIWEI_WORKSPACE_ROOT, target); assert.equal(config.env?.QIWEI_OUTPUTS_DIR, path.join(target, 'outputs')); assert.equal(config.env?.CLAUDE_CODE_WORKDIR, target); assert(fs.existsSync(path.join(target, '.claude', 'plugins', 'qiwei-assistant', 'scripts', 'preview-dashboard.js'))); assert(!fs.existsSync(path.join(target, '.claude', 'plugins', 'qiwei-assistant', '.env.local'))); const gitignorePath = path.join(target, '.gitignore'); const firstGitignore = fs.readFileSync(gitignorePath, 'utf8'); assert.match(firstGitignore, /# Customer rules\ncustomer-cache\//); assert.match(firstGitignore, /# >>> qiwei-assistant managed ignores >>>/); assert.match(firstGitignore, /\*\*\/\.env\.local/); assert.match(firstGitignore, /outputs\/messages\/\*\.db/); const repeated = spawnSync(process.execPath, [path.join(ROOT, 'install.js'), 'workspace', target, '--skip-install'], { cwd: ROOT, encoding: 'utf8', windowsHide: true, }); assert.equal(repeated.status, 0, repeated.stderr || repeated.stdout); const secondGitignore = fs.readFileSync(gitignorePath, 'utf8'); assert.equal((secondGitignore.match(/# >>> qiwei-assistant managed ignores >>>/g) || []).length, 1); assert.match(secondGitignore, /# Customer rules\ncustomer-cache\//); } function testRuntimeProcessSeparation() { const previewSource = fs.readFileSync(path.join(ROOT, 'scripts', 'preview-dashboard.js'), 'utf8'); const dashboardSource = fs.readFileSync(path.join(ROOT, 'scripts', 'start-dashboard.js'), 'utf8'); const serverSource = fs.readFileSync(path.join(ROOT, 'mcp', 'src', 'server.js'), 'utf8'); assert.doesNotMatch(previewSource, /\.startRuntime\s*\(/); assert.match(previewSource, /ensureRelayDaemon\s*\(/); assert.match(dashboardSource, /ensureRelayDaemon\s*\(/); assert.match(serverSource, /ensureRelayDaemon\s*\(/); } function testAgentWorkbenchOfflineStartup() { const appSource = fs.readFileSync(path.join(ROOT, 'mcp', 'src', 'dashboard', 'app.js'), 'utf8'); const renderAgentSource = appSource.slice( appSource.indexOf('function renderAgentPage()'), appSource.indexOf('// ==================== Login ===================='), ); assert.match(renderAgentSource, /startAgentPageRuntime\(page\);/); assert.doesNotMatch(renderAgentSource, /if \(!state\.bootstrapping\)\s+startAgentPageRuntime\(page\)/); assert.match(appSource, /api\('GET', '\/api\/status\?fast=true', undefined, 2500\)/); assert.match(appSource, /api\('GET', '\/api\/agent\/status', undefined, 2500\)/); } function main() { const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'qiwei-preview-smoke-')); try { testRuntimeContext(tempRoot); testStartupSummary(); testWorkspaceInstall(tempRoot); testRuntimeProcessSeparation(); testAgentWorkbenchOfflineStartup(); } finally { fs.rmSync(tempRoot, { recursive: true, force: true }); } process.stdout.write(`${JSON.stringify({ status: 'ok', checks: 5 }, null, 2)}\n`); } try { main(); } catch (error) { process.stderr.write(`${error.message}\n`); process.exit(1); }