同步 enhance/bridge/smoke/retire 模块、vendor 3.3.34、增强面板与 PRD 文档, Hub 接入 hub-routes-prd,含安装/经验/模块说明与 co-integration 运维脚本。 Co-authored-by: Cursor <cursoragent@cursor.com>
209 lines
7.6 KiB
JavaScript
209 lines
7.6 KiB
JavaScript
'use strict';
|
||
|
||
const enhance = require('./enhance');
|
||
const bridge = require('./bridge');
|
||
const modeLib = require('./mode');
|
||
const templatesLib = require('./templates');
|
||
const smokeLib = require('./smoke');
|
||
const retireLib = require('./retire');
|
||
|
||
const HUB_URL = `http://127.0.0.1:${process.env.PCHAT_HTTP_PORT || '13458'}`;
|
||
|
||
function defaultWorkspace(sessions) {
|
||
if (process.env.PCHAT_WORKSPACE) return process.env.PCHAT_WORKSPACE;
|
||
for (const s of sessions.values()) {
|
||
if (s.workspace && s.workspace !== 'none') return s.workspace;
|
||
}
|
||
return '/Users/karuo/Documents/个人';
|
||
}
|
||
|
||
async function handlePrdRoutes(ctx) {
|
||
const { u, req, res, sessions, pendingWaits, saveSessions, nowMs, json, readBody } = ctx;
|
||
const WORKSPACE = defaultWorkspace(sessions);
|
||
|
||
if (u.pathname === '/api/prd/progress' && req.method === 'GET') {
|
||
json(res, 200, enhance.getPrdProgress());
|
||
return true;
|
||
}
|
||
|
||
if (u.pathname === '/api/mode/check' && req.method === 'GET') {
|
||
const report = modeLib.detectRulesConflict(WORKSPACE);
|
||
if (templatesLib.templatesReady(WORKSPACE)) enhance.markPrdItem('phase2-templates', true);
|
||
json(res, 200, { ok: true, workspace: WORKSPACE, ...report });
|
||
return true;
|
||
}
|
||
|
||
if (u.pathname === '/api/mode/retire-cochat-rule' && req.method === 'POST') {
|
||
const fs = require('fs');
|
||
const path = require('path');
|
||
const rulesDir = path.join(WORKSPACE, '.cursor', 'rules');
|
||
const retiredDir = path.join(rulesDir, '_retired');
|
||
const src = path.join(rulesDir, 'co-chat.mdc');
|
||
let moved = false;
|
||
try {
|
||
if (fs.existsSync(src)) {
|
||
fs.mkdirSync(retiredDir, { recursive: true });
|
||
const dest = path.join(retiredDir, 'co-chat.mdc');
|
||
fs.renameSync(src, dest);
|
||
moved = true;
|
||
}
|
||
} catch (e) {
|
||
json(res, 500, { ok: false, error: String(e.message || e) });
|
||
return true;
|
||
}
|
||
const report = modeLib.detectRulesConflict(WORKSPACE);
|
||
json(res, 200, { ok: true, moved, conflict: report.conflict, message: report.message });
|
||
return true;
|
||
}
|
||
|
||
if (u.pathname === '/api/templates' && req.method === 'GET') {
|
||
const data = templatesLib.getTemplates(WORKSPACE);
|
||
if (templatesLib.templatesReady(WORKSPACE)) enhance.markPrdItem('phase2-templates', true);
|
||
json(res, 200, data);
|
||
return true;
|
||
}
|
||
|
||
if (u.pathname === '/api/retire/check' && req.method === 'GET') {
|
||
const state = enhance.getStatus();
|
||
const report = retireLib.checkRetirePreconditions(state);
|
||
if (report.script) enhance.markPrdItem('phase3-retire', true);
|
||
json(res, 200, report);
|
||
return true;
|
||
}
|
||
|
||
if (u.pathname === '/api/smoke/run' && req.method === 'POST') {
|
||
const result = await smokeLib.runSmoke(HUB_URL);
|
||
if (result.ok) enhance.markPrdItem('phase3-smoke', true);
|
||
json(res, 200, result);
|
||
return true;
|
||
}
|
||
|
||
if (u.pathname === '/api/bridge/sync' && req.method === 'POST') {
|
||
const body = JSON.parse(await readBody(req) || '{}');
|
||
const result = bridge.syncToSession({ token: body.token, content: body.content, source: body.source }, sessions, pendingWaits, nowMs, saveSessions);
|
||
if (result.ok) {
|
||
enhance.markPrdItem('phase2-bridge', true);
|
||
const s = sessions.get(body.token);
|
||
if (s) enhance.markPrdItem('mode-a-wait', pendingWaits.has(body.token) || (s.messages || []).length > 0);
|
||
}
|
||
json(res, result.ok ? 200 : 400, result);
|
||
return true;
|
||
}
|
||
|
||
if (u.pathname === '/api/session/mode' && req.method === 'POST') {
|
||
const body = JSON.parse(await readBody(req) || '{}');
|
||
const s = sessions.get(body.token);
|
||
if (!s) { json(res, 404, { ok: false, error: 'unknown token' }); return true; }
|
||
if (!modeLib.setSessionMode(s, body.mode)) { json(res, 400, { ok: false, error: 'invalid mode' }); return true; }
|
||
saveSessions();
|
||
json(res, 200, { ok: true, mode: body.mode, badge: modeLib.sessionBadge(s) });
|
||
return true;
|
||
}
|
||
|
||
if (u.pathname === '/api/enhance/status' && req.method === 'GET') {
|
||
const state = enhance.getStatus();
|
||
enhance.markPrdItem('phase1-hub-progress', true);
|
||
enhance.markPrdItem('phase1-wizard-ui', true);
|
||
json(res, 200, { ok: true, state });
|
||
return true;
|
||
}
|
||
|
||
if (u.pathname === '/api/enhance/diagnose' && req.method === 'GET') {
|
||
const report = enhance.diagnose();
|
||
enhance.markPrdItem('phase1-w2-w8', enhance.w8GatesPass(report.state));
|
||
if (enhance.modeBGatesPass(report.state)) enhance.markPrdItem('mode-b-opus', true);
|
||
json(res, 200, { ok: true, report });
|
||
return true;
|
||
}
|
||
|
||
if (u.pathname === '/api/enhance/apply' && req.method === 'POST') {
|
||
const result = await enhance.applyEnhance();
|
||
enhance.markPrdItem('phase1-enhance-api', true);
|
||
enhance.markPrdItem('phase1-patch-bridge', !!result.ok);
|
||
json(res, 200, result);
|
||
return true;
|
||
}
|
||
|
||
if (u.pathname === '/api/enhance/repair' && req.method === 'POST') {
|
||
const result = await enhance.repairEnhance();
|
||
json(res, 200, result);
|
||
return true;
|
||
}
|
||
|
||
if (u.pathname === '/api/enhance/toggle' && req.method === 'POST') {
|
||
const body = JSON.parse(await readBody(req) || '{}');
|
||
const result = enhance.setEnhanceEnabled(!!body.enabled);
|
||
json(res, result.ok ? 200 : 400, result);
|
||
return true;
|
||
}
|
||
|
||
if (u.pathname === '/api/enhance/settings' && req.method === 'POST') {
|
||
const body = JSON.parse(await readBody(req) || '{}');
|
||
const state = enhance.updateNoQuotaSettings(body);
|
||
json(res, 200, { ok: true, state });
|
||
return true;
|
||
}
|
||
|
||
if (u.pathname === '/api/enhance/fix-perm' && req.method === 'POST') {
|
||
const result = enhance.runPermFixOsascript();
|
||
const state = enhance.loadState();
|
||
enhance.syncGatesToState(state);
|
||
enhance.saveState(state);
|
||
if (enhance.w8GatesPass(state)) enhance.markPrdItem('phase1-w2-w8', true);
|
||
json(res, 200, { ok: state.permOk, result, state });
|
||
return true;
|
||
}
|
||
|
||
if (u.pathname === '/api/enhance/fix-prefs' && req.method === 'POST') {
|
||
const result = enhance.fixCursorPrefs();
|
||
const state = enhance.loadState();
|
||
enhance.syncGatesToState(state);
|
||
enhance.saveState(state);
|
||
json(res, 200, { ok: result.cursorPrefOk, prefs: result, state });
|
||
return true;
|
||
}
|
||
|
||
if (u.pathname === '/api/enhance/open-w2-terminal' && req.method === 'POST') {
|
||
const { spawn } = require('child_process');
|
||
const cmd = 'sudo bash ~/.cursor/cochat_fix_write_permission.sh';
|
||
spawn('osascript', ['-e', `tell application "Terminal" to do script "${cmd}"`], { detached: true, stdio: 'ignore' }).unref();
|
||
json(res, 200, { ok: true, message: '已在 Terminal 打开 W2 命令,输入密码后 Cmd+Q 重启 Cursor' });
|
||
return true;
|
||
}
|
||
|
||
if (u.pathname === '/api/enhance/opus-probe' && req.method === 'GET') {
|
||
const state = enhance.getStatus();
|
||
const markers = enhance.verifyPatchMarkers();
|
||
const ready = enhance.modeBGatesPass(state);
|
||
if (ready) enhance.markPrdItem('mode-b-opus', true);
|
||
json(res, 200, {
|
||
ok: ready,
|
||
gates: {
|
||
permOk: state.permOk,
|
||
patchOk: state.patchOk,
|
||
patchNativeOk: !!state.patchNativeOk,
|
||
cursorPrefOk: state.cursorPrefOk,
|
||
},
|
||
markers: markers.details,
|
||
message: ready
|
||
? (state.patchOk ? '三门禁全绿(workbench 补丁)' : 'pchat 原生模式就绪,Opus 探测可用')
|
||
: '请先 W2 + W6,并开启增强包',
|
||
});
|
||
return true;
|
||
}
|
||
|
||
if (u.pathname === '/enhance' && req.method === 'GET') {
|
||
const fs = require('fs');
|
||
const path = require('path');
|
||
const p = path.join(__dirname, '..', 'panel-enhance.html');
|
||
if (!fs.existsSync(p)) return false;
|
||
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
||
res.end(fs.readFileSync(p, 'utf8'));
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
module.exports = { handlePrdRoutes, defaultWorkspace };
|