Makelore 2.0 initial clean snapshot

This commit is contained in:
inman
2026-07-29 17:22:35 +08:00
commit b8ca3f8eea
694 changed files with 139782 additions and 0 deletions

View File

@@ -0,0 +1,202 @@
#!/usr/bin/env node
import { spawn } from 'node:child_process';
import { existsSync } from 'node:fs';
import { mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import { dirname, join, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
import { createServer } from 'node:net';
const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..');
const enabled = process.env.NIANCODE_OPENCODE_REAL_SMOKE === '1'
|| process.env.OPENCODE_REAL_SMOKE === '1';
function skip(reason) {
console.log(`[opencode-real-smoke] skipped: ${reason}`);
process.exit(0);
}
if (!enabled) {
skip('set NIANCODE_OPENCODE_REAL_SMOKE=1 to launch a real opencode runtime');
}
function resolveOpencodeBin() {
const explicit = process.env.NIANCODE_OPENCODE_BIN || process.env.OPENCODE_BIN;
if (explicit) return explicit;
const binName = process.platform === 'win32' ? 'opencode.cmd' : 'opencode';
const localBin = join(repoRoot, 'node_modules', '.bin', binName);
if (existsSync(localBin)) return localBin;
return binName;
}
async function resolveConfigContent() {
if (process.env.OPENCODE_CONFIG_CONTENT) return process.env.OPENCODE_CONFIG_CONTENT;
if (process.env.OPENCODE_REAL_SMOKE_CONFIG) return process.env.OPENCODE_REAL_SMOKE_CONFIG;
if (process.env.OPENCODE_REAL_SMOKE_CONFIG_FILE) {
return await readFile(resolve(process.env.OPENCODE_REAL_SMOKE_CONFIG_FILE), 'utf8');
}
return null;
}
async function getFreePort() {
return await new Promise((resolvePort, reject) => {
const server = createServer();
server.once('error', reject);
server.listen(0, '127.0.0.1', () => {
const address = server.address();
const port = typeof address === 'object' && address ? address.port : null;
server.close(() => {
if (typeof port === 'number') {
resolvePort(port);
return;
}
reject(new Error('Unable to reserve a local smoke-test port'));
});
});
});
}
function waitForListening(proc, timeoutMs) {
return awaitableProcessOutput(proc, timeoutMs, (text) => {
const match = text.match(/opencode server listening\s+on\s+(https?:\/\/[^\s]+)/);
return match?.[1] ?? null;
});
}
function awaitableProcessOutput(proc, timeoutMs, resolveFromText) {
return new Promise((resolveUrl, reject) => {
let settled = false;
let stderr = '';
const finish = (callback) => {
if (settled) return;
settled = true;
clearTimeout(timer);
callback();
};
const timer = setTimeout(() => {
finish(() => reject(new Error(`Timed out waiting for opencode server after ${timeoutMs}ms${stderr ? `\n${stderr}` : ''}`)));
}, timeoutMs);
proc.stdout?.on('data', (chunk) => {
const text = chunk.toString();
process.stdout.write(text);
const result = resolveFromText(text);
if (result) finish(() => resolveUrl(result));
});
proc.stderr?.on('data', (chunk) => {
const text = chunk.toString();
stderr += text;
process.stderr.write(text);
});
proc.on('error', (error) => finish(() => reject(error)));
proc.on('exit', (code) => {
finish(() => reject(new Error(`opencode exited before it became ready: ${code ?? 'unknown'}${stderr ? `\n${stderr}` : ''}`)));
});
});
}
function sessionIdOf(session) {
if (!session || typeof session !== 'object') return null;
const value = session.id ?? session.sessionID ?? session.sessionId;
return typeof value === 'string' && value.trim() ? value : null;
}
async function requestJson(url, init = {}) {
const response = await fetch(url, {
...init,
headers: {
'Content-Type': 'application/json',
...(init.headers ?? {}),
},
});
if (!response.ok) {
const body = await response.text().catch(() => '');
throw new Error(`opencode request failed ${response.status} ${response.statusText}${body ? `\n${body}` : ''}`);
}
if (response.status === 204) return null;
return await response.json();
}
async function createProjectDir() {
if (process.env.OPENCODE_REAL_SMOKE_PROJECT) {
return {
path: resolve(process.env.OPENCODE_REAL_SMOKE_PROJECT),
cleanup: async () => {},
};
}
const path = await mkdtemp(join(tmpdir(), 'niancode-opencode-smoke-'));
await writeFile(join(path, 'README.md'), '# Makelore opencode real-runtime smoke\n');
return {
path,
cleanup: async () => {
await rm(path, { recursive: true, force: true });
},
};
}
const configContent = await resolveConfigContent();
if (!configContent && process.env.OPENCODE_REAL_SMOKE_ALLOW_LOCAL_CONFIG !== '1') {
skip('provide OPENCODE_CONFIG_CONTENT, OPENCODE_REAL_SMOKE_CONFIG, or OPENCODE_REAL_SMOKE_CONFIG_FILE');
}
JSON.parse(configContent ?? '{}');
const binPath = resolveOpencodeBin();
const port = Number(process.env.OPENCODE_REAL_SMOKE_PORT) || await getFreePort();
const startupTimeoutMs = Number(process.env.OPENCODE_REAL_SMOKE_STARTUP_TIMEOUT_MS) || 20_000;
const apiTimeoutMs = Number(process.env.OPENCODE_REAL_SMOKE_API_TIMEOUT_MS) || 60_000;
const project = await createProjectDir();
const proc = spawn(binPath, ['serve', '--hostname=127.0.0.1', `--port=${port}`], {
env: {
...process.env,
...(configContent ? { OPENCODE_CONFIG_CONTENT: configContent } : {}),
},
stdio: ['ignore', 'pipe', 'pipe'],
windowsHide: true,
shell: process.platform === 'win32' && /\.cmd$/i.test(binPath),
});
try {
const baseUrl = await waitForListening(proc, startupTimeoutMs);
const directoryQuery = `directory=${encodeURIComponent(project.path)}`;
const scopedHeaders = { 'x-opencode-directory': encodeURIComponent(project.path) };
const sessions = await requestJson(`${baseUrl}/session?${directoryQuery}`, {
signal: AbortSignal.timeout(apiTimeoutMs),
headers: scopedHeaders,
});
if (!Array.isArray(sessions)) {
throw new Error('Expected /session to return an array');
}
const session = await requestJson(`${baseUrl}/session?${directoryQuery}`, {
method: 'POST',
body: JSON.stringify({}),
signal: AbortSignal.timeout(apiTimeoutMs),
headers: scopedHeaders,
});
const sessionId = sessionIdOf(session);
if (!sessionId) {
throw new Error('Created opencode session did not include an id');
}
if (process.env.OPENCODE_REAL_SMOKE_PROMPT) {
await requestJson(`${baseUrl}/session/${encodeURIComponent(sessionId)}/message?${directoryQuery}`, {
method: 'POST',
body: JSON.stringify({
parts: [
{ type: 'text', text: process.env.OPENCODE_REAL_SMOKE_PROMPT },
],
}),
signal: AbortSignal.timeout(apiTimeoutMs),
headers: scopedHeaders,
});
}
console.log(`[opencode-real-smoke] ok: started ${baseUrl}, listed ${sessions.length} session(s), created ${sessionId}`);
} finally {
proc.kill();
await project.cleanup();
}