mirror of
https://github.com/siteboon/claudecodeui.git
synced 2026-06-20 07:52:00 +08:00
feat: add CloudCLI computer use semantics, desktop helper packaging, and permission onboarding
This commit is contained in:
133
scripts/build-computer-semantics.mjs
Normal file
133
scripts/build-computer-semantics.mjs
Normal file
@@ -0,0 +1,133 @@
|
||||
#!/usr/bin/env node
|
||||
import { spawn } from 'node:child_process';
|
||||
import fs from 'node:fs/promises';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const rootDir = path.resolve(__dirname, '..');
|
||||
const platform = process.env.CLOUDCLI_SEMANTICS_PLATFORM || process.platform;
|
||||
const arch = process.env.CLOUDCLI_SEMANTICS_ARCH || process.arch;
|
||||
const platformArch = `${platform}-${arch}`;
|
||||
const semanticsRoot = path.join(rootDir, 'server', 'modules', 'computer-use', 'semantics');
|
||||
const outDir = path.join(semanticsRoot, 'bin', platformArch);
|
||||
const requireBuild = process.env.CLOUDCLI_SEMANTICS_BUILD_REQUIRED === '1';
|
||||
|
||||
function run(command, args, options = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const child = spawn(command, args, {
|
||||
stdio: 'inherit',
|
||||
shell: process.platform === 'win32',
|
||||
...options,
|
||||
});
|
||||
child.once('error', reject);
|
||||
child.once('exit', (code) => {
|
||||
if (code === 0) resolve();
|
||||
else reject(new Error(`${command} ${args.join(' ')} exited with code ${code}`));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function commandExists(command) {
|
||||
return new Promise((resolve) => {
|
||||
const child = spawn(command, ['--version'], {
|
||||
stdio: 'ignore',
|
||||
shell: process.platform === 'win32',
|
||||
});
|
||||
child.once('error', () => resolve(false));
|
||||
child.once('exit', (code) => resolve(code === 0));
|
||||
});
|
||||
}
|
||||
|
||||
async function pathExists(filePath) {
|
||||
try {
|
||||
await fs.access(filePath);
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function isUpToDate(output, inputs) {
|
||||
if (!(await pathExists(output))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const outputStat = await fs.stat(output);
|
||||
for (const input of inputs) {
|
||||
const inputStat = await fs.stat(input);
|
||||
if (inputStat.mtimeMs > outputStat.mtimeMs) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
async function ensureCommand(command, helpText) {
|
||||
if (await commandExists(command)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const message = `${command} was not found. ${helpText}`;
|
||||
if (requireBuild) {
|
||||
throw new Error(message);
|
||||
}
|
||||
console.log(`Skipping semantic helper build: ${message}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (platform === 'darwin') {
|
||||
const source = path.join(semanticsRoot, 'helpers', 'macos', 'CloudCLISemantics.swift');
|
||||
const output = path.join(outDir, 'CloudCLISemantics');
|
||||
|
||||
if (!(await ensureCommand('swiftc', 'Install Xcode Command Line Tools to compile the macOS helper.'))) {
|
||||
process.exit(0);
|
||||
}
|
||||
if (await isUpToDate(output, [source])) {
|
||||
console.log(`Semantic helper is up to date: ${path.relative(rootDir, output)}`);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
await fs.mkdir(outDir, { recursive: true });
|
||||
await run('swiftc', [
|
||||
source,
|
||||
'-o',
|
||||
output,
|
||||
'-framework',
|
||||
'AppKit',
|
||||
'-framework',
|
||||
'ApplicationServices',
|
||||
]);
|
||||
await fs.chmod(output, 0o755);
|
||||
console.log(`Built ${path.relative(rootDir, output)}`);
|
||||
} else if (platform === 'win32') {
|
||||
const project = path.join(semanticsRoot, 'helpers', 'windows', 'CloudCLISemantics.csproj');
|
||||
const source = path.join(semanticsRoot, 'helpers', 'windows', 'Program.cs');
|
||||
const output = path.join(outDir, 'CloudCLISemantics.exe');
|
||||
|
||||
if (!(await ensureCommand('dotnet', '.NET SDK is required to compile the Windows helper.'))) {
|
||||
process.exit(0);
|
||||
}
|
||||
if (await isUpToDate(output, [project, source])) {
|
||||
console.log(`Semantic helper is up to date: ${path.relative(rootDir, output)}`);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
await fs.mkdir(outDir, { recursive: true });
|
||||
await run('dotnet', [
|
||||
'publish',
|
||||
project,
|
||||
'-c',
|
||||
'Release',
|
||||
'-r',
|
||||
arch === 'arm64' ? 'win-arm64' : 'win-x64',
|
||||
'--self-contained',
|
||||
'false',
|
||||
'-p:PublishSingleFile=true',
|
||||
'-o',
|
||||
outDir,
|
||||
]);
|
||||
console.log(`Built ${path.relative(rootDir, output)}`);
|
||||
} else {
|
||||
console.log(`Semantic helper build is not supported for ${platform}-${arch}.`);
|
||||
}
|
||||
Reference in New Issue
Block a user