Extract memind_adm admin server, add local dev tooling, and remove image-generation.

Split platform admin and ops APIs into standalone admin-server.mjs with network guards; simplify billing to RMB token pricing, refactor user auth, and add rsync deploy plus local-test scripts and docs.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Your Name
2026-06-17 16:39:39 -07:00
parent ab0718938e
commit b0f5d6a51c
98 changed files with 5394 additions and 3010 deletions
+120
View File
@@ -0,0 +1,120 @@
#!/usr/bin/env node
/**
* Map local test domains -> 127.0.0.1 for dev (macOS hosts + per-domain resolver).
*
* Usage:
* sudo node scripts/setup-local-test-dns.mjs
* sudo node scripts/setup-local-test-dns.mjs --remove
*/
import fs from 'node:fs';
import path from 'node:path';
import { execSync } from 'node:child_process';
import { DNS_MARKER, DNS_PORT, LOCAL_IP, TEST_HOSTS } from './local-test-config.mjs';
const remove = process.argv.includes('--remove');
const hostsPath = '/etc/hosts';
const resolverDir = '/etc/resolver';
const resolverBody = `nameserver 127.0.0.1\nport ${DNS_PORT}\n# ${DNS_MARKER}\n`;
function flushDnsCache() {
try {
execSync('dscacheutil -flushcache', { stdio: 'ignore' });
execSync('killall -HUP mDNSResponder', { stdio: 'ignore' });
} catch {
// best effort
}
}
function hostLine(host) {
return `${LOCAL_IP} ${host} # ${DNS_MARKER}`;
}
function removeHostLines(lines, host) {
return lines.filter(
(line) =>
!line.includes(DNS_MARKER) &&
!new RegExp(`\\s${host.replace('.', '\\.')}(\\s|$)`).test(line),
);
}
function hostReady(lines, host) {
return lines.some(
(line) =>
(line.includes(DNS_MARKER) && line.includes(host)) ||
new RegExp(`\\s${host.replace('.', '\\.')}(\\s|$)`).test(line),
);
}
if (remove) {
if (process.getuid?.() !== 0) {
console.log('需要 root 权限,请执行:');
console.log(` sudo node ${process.argv[1]} --remove`);
process.exit(1);
}
let lines = fs.readFileSync(hostsPath, 'utf8').split('\n');
for (const host of TEST_HOSTS) {
lines = removeHostLines(lines, host);
try {
if (fs.existsSync(path.join(resolverDir, host))) fs.unlinkSync(path.join(resolverDir, host));
} catch {
// ignore
}
}
execSync(`tee ${hostsPath}`, {
input: `${lines.join('\n').replace(/\n?$/, '\n')}`,
stdio: ['pipe', 'inherit', 'inherit'],
});
flushDnsCache();
console.log(`已移除本地测试域名:${TEST_HOSTS.join(', ')}`);
process.exit(0);
}
const currentLines = fs.readFileSync(hostsPath, 'utf8').split('\n');
const allReady = TEST_HOSTS.every((host) => {
const resolverPath = path.join(resolverDir, host);
const resolverReady =
fs.existsSync(resolverPath) && fs.readFileSync(resolverPath, 'utf8').trim() === resolverBody.trim();
return hostReady(currentLines, host) && resolverReady;
});
if (allReady) {
console.log(`本地测试域名已配置:${TEST_HOSTS.join(', ')}`);
process.exit(0);
}
if (process.getuid?.() !== 0) {
console.log('需要 root 权限写入 /etc/hosts 和 /etc/resolver,请执行:');
console.log(` sudo pnpm setup:local-dns`);
process.exit(1);
}
let lines = currentLines;
for (const host of TEST_HOSTS) {
if (!hostReady(lines, host)) {
lines = lines.filter((line) => !line.includes(DNS_MARKER) || !line.includes(host));
lines.push(hostLine(host));
console.log(`已添加 hosts${hostLine(host)}`);
} else {
console.log(`${host} 已在 /etc/hosts 中指向 ${LOCAL_IP}`);
}
}
execSync(`tee ${hostsPath}`, {
input: `${lines.join('\n').replace(/\n?$/, '\n')}`,
stdio: ['pipe', 'inherit', 'inherit'],
});
fs.mkdirSync(resolverDir, { recursive: true });
for (const host of TEST_HOSTS) {
const resolverPath = path.join(resolverDir, host);
fs.writeFileSync(resolverPath, resolverBody, 'utf8');
console.log(`已添加 resolver${resolverPath} -> 127.0.0.1:${DNS_PORT}`);
}
flushDnsCache();
console.log('');
console.log('下一步:');
console.log(' sudo pnpm setup:local-tls # 生成本地 HTTPS 证书');
console.log(' pnpm dev # 启动全栈');
console.log(' sudo pnpm dev:local-proxy # HTTPS :443 统一入口');