v2.2.1: Auto-install build tools (aapt2/ecj/d8/apksigner), dev tools banner with one-tap install

This commit is contained in:
admin
2026-05-19 19:47:33 +04:00
Unverified
parent 538505e38b
commit 9880baac5b
6 changed files with 217 additions and 25 deletions

View File

@@ -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">&#9888;</span> ' +
'<span class="dtb-msg">' + msg + '</span>' +
'<button class="dtb-install-btn">Install</button>' +
'<button class="dtb-dismiss-btn">&times;</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();
});
});