Files
SashaGoncharov19 51d085e865 Native iPhone port of Factorio 2.0.77
Run the original macOS ARM64 game code on iOS:
- tools/retarget.py: header-only Mach-O retargeting to an iOS dylib
- platform/native: UIKit host and macOS API shims (AppKit for SDL's
  Cocoa backend, CoreGraphics displays, CoreAudio device, Metal device
  properties, Wuffs PNG decoding, Steam and peripheral stubs)
- touch, overlay, iOS keyboard and hardware keyboard input
- tools/build_native.py: build, sign, install, data copy, launch
- docs: build guide, controls, architecture

Also includes the earlier static-translation research (ARM64 -> WASM ->
native) under docs/research, runtime/, tests/ and tools/.

No game files are included; the build reads them from a local install.
2026-10-23 15:27:58 +04:00

52 lines
2.8 KiB
JavaScript

// A temporary MCP client; does not modify any saved MCP client or REA configuration.
import { pathToFileURL } from 'node:url';
import { resolve, join } from 'node:path';
import { mkdir, writeFile } from 'node:fs/promises';
import { createInterface } from 'node:readline';
const [packageRoot, hopperLauncher] = process.argv.slice(2);
if (!packageRoot || !hopperLauncher) {
throw new Error('Usage: node tools/rea-session.mjs REA_PACKAGE_ROOT HOPPER_LAUNCHER (the vendor hopper helper)');
}
const dependencies = resolve(packageRoot, '..', '@modelcontextprotocol');
const { Client } = await import(pathToFileURL(join(dependencies, 'client/dist/index.mjs')));
const { StdioClientTransport } = await import(pathToFileURL(join(dependencies, 'client/dist/stdio.mjs')));
const transport = new StdioClientTransport({
command: join(packageRoot, '..', '.bin', 'rea'), args: ['--mcp'],
env: { ...process.env, HOPPER_LAUNCHER_PATH: hopperLauncher,
REA_HOPPER_STARTUP_TIMEOUT_MS: '600000' },
stderr: 'pipe',
});
// Consume diagnostics without printing inherited environment or bridge credentials.
transport.stderr?.on('data', () => {});
const client = new Client({ name: 'factorio-port-investigation', version: '0.1.0' });
const allowed = new Set(['open_binary', 'binary_session', 'list_documents',
'search_procedures', 'procedure_assembly', 'procedure_info', 'read_bytes',
'search_strings', 'read_function_instructions', 'procedure_callers', 'procedure_callees',
'procedure_pseudo_code', 'analyze_function', 'export_evidence_bundle', 'close_binary']);
await mkdir('evidence', { recursive: true });
await client.connect(transport);
console.log('REA MCP connected. Enter one JSON tool request per line; quit closes the target.');
const input = createInterface({ input: process.stdin, terminal: false });
let sequence = 0;
try {
for await (const line of input) {
if (line.trim() === 'quit') break;
try {
const request = JSON.parse(line);
if (!allowed.has(request.name)) throw new Error('Tool outside investigation allowlist');
console.log(`Calling ${request.name}`);
const result = await client.callTool(request, { timeout: 660000 });
const file = `evidence/${Date.now()}-${++sequence}-${request.name}.json`;
await writeFile(file, JSON.stringify(result, null, 2), { mode: 0o600 });
const data = result.structuredContent ?? result.content?.filter(x => x.type === 'text').map(x => {
try { return JSON.parse(x.text); } catch { return x.text; }
});
console.log(JSON.stringify({ file, isError: result.isError ?? false, data }).slice(0, 14000));
} catch (error) { console.log(JSON.stringify({ error: error.message })); }
}
} finally {
try { await client.callTool({ name: 'close_binary', arguments: {} }); }
finally { await client.close(); }
}