Add MindSpace page live edit, chat skills, and H5 deploy tooling.
Introduce page edit sessions with draft preview and patch API, chat skill picker, user memory profile, h5ApiBase resolution, voice WAV transport, and scripts for 105/g2 deployment and Plaza local dev. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,115 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Minimal DNS server for plaza.tkmind.cn -> 127.0.0.1
|
||||
* Works with /etc/resolver/plaza.tkmind.cn (macOS per-domain DNS override).
|
||||
*
|
||||
* Usage:
|
||||
* node scripts/plaza-local-dns-server.mjs
|
||||
*/
|
||||
import dgram from 'node:dgram';
|
||||
|
||||
const host = process.env.PLAZA_LOCAL_HOST ?? 'plaza.tkmind.cn';
|
||||
const ip = (process.env.PLAZA_LOCAL_IP ?? '127.0.0.1').split('.').map(Number);
|
||||
const port = Number(process.env.PLAZA_LOCAL_DNS_PORT ?? 5533);
|
||||
const bind = process.env.PLAZA_LOCAL_DNS_BIND ?? '127.0.0.1';
|
||||
|
||||
function encodeName(name) {
|
||||
const parts = name.split('.').filter(Boolean);
|
||||
return Buffer.concat([
|
||||
...parts.map((part) => Buffer.concat([Buffer.from([part.length]), Buffer.from(part, 'ascii')])),
|
||||
Buffer.from([0]),
|
||||
]);
|
||||
}
|
||||
|
||||
const hostEncoded = encodeName(host);
|
||||
|
||||
function readQuestionName(msg, offset) {
|
||||
const labels = [];
|
||||
let pos = offset;
|
||||
while (pos < msg.length) {
|
||||
const len = msg[pos];
|
||||
if (len === 0) {
|
||||
pos += 1;
|
||||
break;
|
||||
}
|
||||
labels.push(msg.subarray(pos + 1, pos + 1 + len).toString('ascii'));
|
||||
pos += 1 + len;
|
||||
}
|
||||
return { name: labels.join('.'), next: pos };
|
||||
}
|
||||
|
||||
function questionMatches(name) {
|
||||
return name === host || name === `${host}.`;
|
||||
}
|
||||
|
||||
const server = dgram.createSocket('udp4');
|
||||
|
||||
server.on('message', (msg, rinfo) => {
|
||||
if (msg.length < 12) return;
|
||||
|
||||
const qdCount = msg.readUInt16BE(4);
|
||||
if (qdCount !== 1) return;
|
||||
|
||||
const question = readQuestionName(msg, 12);
|
||||
const qtype = msg.readUInt16BE(question.next);
|
||||
const qclass = msg.readUInt16BE(question.next + 2);
|
||||
const questionEnd = question.next + 4;
|
||||
|
||||
if (!questionMatches(question.name) || (qtype !== 1 && qtype !== 28) || qclass !== 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
const questionSection = msg.subarray(12, questionEnd);
|
||||
const ttl = Buffer.from([0x00, 0x00, 0x00, 0x3c]); // 60s
|
||||
|
||||
let answer;
|
||||
if (qtype === 1) {
|
||||
answer = Buffer.concat([
|
||||
Buffer.from([0xc0, 0x0c]), // pointer to question name
|
||||
Buffer.from([0x00, 0x01, 0x00, 0x01]), // A, IN
|
||||
ttl,
|
||||
Buffer.from([0x00, 0x04]),
|
||||
Buffer.from(ip),
|
||||
]);
|
||||
} else {
|
||||
// AAAA for ::ffff:127.0.0.1 so browsers don't prefer Tailscale fake-ip v6
|
||||
answer = Buffer.concat([
|
||||
Buffer.from([0xc0, 0x0c]),
|
||||
Buffer.from([0x00, 0x1c, 0x00, 0x01]), // AAAA, IN
|
||||
ttl,
|
||||
Buffer.from([0x00, 0x10]),
|
||||
Buffer.from([
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, ip[0], ip[1], ip[2], ip[3],
|
||||
]),
|
||||
]);
|
||||
}
|
||||
|
||||
const header = Buffer.alloc(12);
|
||||
header.writeUInt16BE(msg.readUInt16BE(0), 0); // ID
|
||||
header.writeUInt16BE(0x8180, 2); // QR=1, AA=1, RD supported
|
||||
header.writeUInt16BE(1, 4); // QDCOUNT
|
||||
header.writeUInt16BE(1, 6); // ANCOUNT
|
||||
header.writeUInt16BE(0, 8);
|
||||
header.writeUInt16BE(0, 10);
|
||||
|
||||
const response = Buffer.concat([header, questionSection, answer]);
|
||||
server.send(response, rinfo.port, rinfo.address);
|
||||
});
|
||||
|
||||
server.on('error', (err) => {
|
||||
if (err.code === 'EADDRINUSE') {
|
||||
console.error(`Plaza DNS 端口 ${port} 已被占用`);
|
||||
process.exit(1);
|
||||
}
|
||||
throw err;
|
||||
});
|
||||
|
||||
server.bind(port, bind, () => {
|
||||
console.log(`Plaza DNS ${host} -> ${ip.join('.')} @ ${bind}:${port}`);
|
||||
});
|
||||
|
||||
for (const signal of ['SIGINT', 'SIGTERM']) {
|
||||
process.on(signal, () => {
|
||||
server.close(() => process.exit(0));
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user