v2.2.1: Auto-install build tools (aapt2/ecj/d8/apksigner), dev tools banner with one-tap install
This commit is contained in:
173
www/js/app.js
173
www/js/app.js
@@ -549,6 +549,10 @@
|
||||
return;
|
||||
}
|
||||
|
||||
if ((state.currentMode === 'coding' || state.currentMode === 'agentic') && !termState.devToolsInstalled) {
|
||||
checkDevEnvironment();
|
||||
}
|
||||
|
||||
if (!state.activeConversationId) {
|
||||
newConversation();
|
||||
}
|
||||
@@ -1901,33 +1905,159 @@
|
||||
}
|
||||
|
||||
async function ensureBuildTools() {
|
||||
var check = await shellExec('command -v aapt2 && command -v ecj && (command -v d8 || command -v dx)', termState.homeDir, false);
|
||||
if (check.exitCode === 0) return true;
|
||||
|
||||
termPrint('[*] Installing build tools...', 'info');
|
||||
showStatusToast('Installing build tools (first time)...', 'info');
|
||||
|
||||
var installResult = await shellExec(
|
||||
'apt update -y 2>&1 && apt install -y aapt2 ecj dx apksigner 2>&1 || pkg install -y aapt2 ecj dx apksigner 2>&1',
|
||||
termState.homeDir, false
|
||||
);
|
||||
|
||||
if (installResult.output) {
|
||||
termPrint(installResult.output.replace(/\n$/, ''), '');
|
||||
}
|
||||
|
||||
var recheck = await shellExec('command -v aapt2 && command -v ecj', termState.homeDir, false);
|
||||
if (recheck.exitCode === 0) {
|
||||
termPrint('[OK] Build tools installed', 'success');
|
||||
showStatusToast('Build tools installed!', 'success');
|
||||
var check = await shellExec('command -v aapt2 >/dev/null 2>&1 && command -v ecj >/dev/null 2>&1 && (command -v d8 >/dev/null 2>&1 || command -v dx >/dev/null 2>&1)', termState.homeDir, false);
|
||||
if (check.exitCode === 0) {
|
||||
termState.devToolsInstalled = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
termPrint('[!] Failed to install build tools automatically', 'err');
|
||||
termPrint('Please run manually: pkg install aapt2 ecj dx apksigner', 'warning');
|
||||
if (Shell) {
|
||||
var env = await Shell.getEnv();
|
||||
termState.homeDir = env.HOME;
|
||||
termState.toolsDir = env.TOOLS;
|
||||
termState.projectsDir = env.PROJECTS;
|
||||
termState.cwd = env.CWD || env.HOME;
|
||||
}
|
||||
|
||||
var prefix = termState.homeDir ? termState.homeDir.replace('/home', '') + '/usr' : '';
|
||||
var pkgBin = prefix + '/bin/pkg';
|
||||
var aptBin = prefix + '/bin/apt';
|
||||
|
||||
var pkgExists = await shellExec('test -x "' + pkgBin + '"', termState.homeDir, false);
|
||||
var aptExists = await shellExec('test -x "' + aptBin + '"', termState.homeDir, false);
|
||||
|
||||
if (pkgExists.exitCode !== 0 && aptExists.exitCode !== 0) {
|
||||
termPrint('[!] No package manager found. Install Termux bootstrap first.', 'err');
|
||||
termState.devToolsInstalled = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
termPrint('[*] Installing build tools (aapt2, ecj, dx, apksigner)...', 'info');
|
||||
termPrint('[*] This may take a few minutes on first run...', 'info');
|
||||
showStatusToast('Installing build tools...', 'info');
|
||||
|
||||
var installCmd;
|
||||
if (pkgExists.exitCode === 0) {
|
||||
installCmd = pkgBin + ' update -y 2>&1 && ' + pkgBin + ' install -y aapt2 ecj dx apksigner 2>&1';
|
||||
} else {
|
||||
installCmd = aptBin + ' update -y 2>&1 && ' + aptBin + ' install -y aapt2 ecj dx apksigner 2>&1';
|
||||
}
|
||||
|
||||
var installResult = await shellExec(installCmd, termState.homeDir, false);
|
||||
if (installResult.output) {
|
||||
var out = installResult.output;
|
||||
if (out.length > 2000) out = out.substring(0, 1000) + '\n... truncated ...\n' + out.substring(out.length - 800);
|
||||
termPrint(out.replace(/\n$/, ''), '');
|
||||
}
|
||||
|
||||
var recheck = await shellExec('command -v aapt2 >/dev/null 2>&1 && command -v ecj >/dev/null 2>&1', termState.homeDir, false);
|
||||
if (recheck.exitCode === 0) {
|
||||
termPrint('[OK] Build tools installed successfully!', 'success');
|
||||
showStatusToast('Build tools installed!', 'success');
|
||||
termState.devToolsInstalled = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (pkgExists.exitCode === 0 && installResult.exitCode !== 0) {
|
||||
termPrint('[*] Retrying with apt directly...', 'info');
|
||||
var retryResult = await shellExec(aptBin + ' update 2>&1 && ' + aptBin + ' install -y aapt2 ecj dx apksigner 2>&1', termState.homeDir, false);
|
||||
if (retryResult.output) termPrint(retryResult.output.substring(0, 1500).replace(/\n$/, ''), '');
|
||||
|
||||
var recheck2 = await shellExec('command -v aapt2 >/dev/null 2>&1 && command -v ecj >/dev/null 2>&1', termState.homeDir, false);
|
||||
if (recheck2.exitCode === 0) {
|
||||
termPrint('[OK] Build tools installed!', 'success');
|
||||
showStatusToast('Build tools installed!', 'success');
|
||||
termState.devToolsInstalled = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
termPrint('[!] Auto-install failed. Open Terminal and run:', 'err');
|
||||
termPrint(' pkg update && pkg install aapt2 ecj dx apksigner', 'warning');
|
||||
termState.devToolsInstalled = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
async function checkDevEnvironment() {
|
||||
if (state.currentMode !== 'coding' && state.currentMode !== 'agentic') return;
|
||||
|
||||
if (!Bootstrap) return;
|
||||
try {
|
||||
var bsStatus = await Bootstrap.getStatus();
|
||||
if (!bsStatus.installed) {
|
||||
showDevToolsBanner('Termux not installed. Tap Dev Setup to install Linux environment + build tools.');
|
||||
return;
|
||||
}
|
||||
} catch(e) {}
|
||||
|
||||
if (termState.devToolsInstalled) return;
|
||||
|
||||
var check = await shellExec('command -v aapt2 >/dev/null 2>&1 && command -v ecj >/dev/null 2>&1', termState.homeDir, false);
|
||||
if (check.exitCode === 0) {
|
||||
termState.devToolsInstalled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
showDevToolsBanner('Build tools (aapt2, ecj, d8) not installed. Tap to auto-install.');
|
||||
}
|
||||
|
||||
function showDevToolsBanner(msg) {
|
||||
var existing = $('#dev-tools-banner');
|
||||
if (existing) existing.remove();
|
||||
|
||||
var container = $('#messages');
|
||||
if (!container) return;
|
||||
|
||||
var banner = document.createElement('div');
|
||||
banner.id = 'dev-tools-banner';
|
||||
banner.className = 'dev-tools-banner';
|
||||
banner.innerHTML = '<span class="dtb-icon">⚠</span> ' +
|
||||
'<span class="dtb-msg">' + msg + '</span>' +
|
||||
'<button class="dtb-install-btn">Install</button>' +
|
||||
'<button class="dtb-dismiss-btn">×</button>';
|
||||
|
||||
container.insertBefore(banner, container.firstChild);
|
||||
|
||||
banner.querySelector('.dtb-install-btn').addEventListener('click', async function() {
|
||||
var btn = this;
|
||||
btn.textContent = 'Installing...';
|
||||
btn.disabled = true;
|
||||
|
||||
var bsStatus;
|
||||
try { bsStatus = await Bootstrap.getStatus(); } catch(e) { bsStatus = { installed: false }; }
|
||||
|
||||
if (!bsStatus.installed) {
|
||||
try {
|
||||
await Bootstrap.install();
|
||||
if (Shell) {
|
||||
var env = await Shell.getEnv();
|
||||
termState.homeDir = env.HOME;
|
||||
termState.toolsDir = env.TOOLS;
|
||||
termState.projectsDir = env.PROJECTS;
|
||||
termState.cwd = env.CWD || env.HOME;
|
||||
}
|
||||
updateCwdDisplay();
|
||||
} catch(e) {
|
||||
btn.textContent = 'Bootstrap failed';
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var ok = await ensureBuildTools();
|
||||
if (ok) {
|
||||
banner.remove();
|
||||
showStatusToast('All tools installed!', 'success');
|
||||
} else {
|
||||
btn.textContent = 'Retry';
|
||||
btn.disabled = false;
|
||||
}
|
||||
});
|
||||
|
||||
banner.querySelector('.dtb-dismiss-btn').addEventListener('click', function() {
|
||||
banner.remove();
|
||||
});
|
||||
}
|
||||
|
||||
async function autoExecuteActions(actions, conv) {
|
||||
var hasFiles = actions.some(function(a) { return a.type === 'create_file'; });
|
||||
var hasBuild = actions.some(function(a) { return a.type === 'build_apk'; });
|
||||
@@ -2585,6 +2715,7 @@
|
||||
updateModeSelector();
|
||||
updateHeader();
|
||||
updateTerminalVisibility();
|
||||
checkDevEnvironment();
|
||||
saveState();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user