v1.3.1: Auto-execute AI actions, Keep Screen On, status toasts

This commit is contained in:
admin
2026-05-19 17:12:07 +04:00
Unverified
parent 83fb658a1e
commit 88378b6342
8 changed files with 213 additions and 5 deletions

View File

@@ -28,7 +28,9 @@
streamingConvId: null,
streamingContent: '',
streamingResponseDiv: null,
terminalOpen: false
terminalOpen: false,
keepAwake: false,
autoDeploy: true
};
function $(sel) { return document.querySelector(sel); }
@@ -46,6 +48,8 @@
state.currentMode = localStorage.getItem(STORAGE_KEY + 'currentMode') || 'chat';
state.theme = localStorage.getItem(STORAGE_KEY + 'theme') || 'dark';
state.terminalOpen = localStorage.getItem(STORAGE_KEY + 'terminalOpen') === 'true';
state.keepAwake = localStorage.getItem(STORAGE_KEY + 'keepAwake') === 'true';
state.autoDeploy = localStorage.getItem(STORAGE_KEY + 'autoDeploy') !== 'false';
var convData = localStorage.getItem(STORAGE_KEY + 'conversations');
state.conversations = convData ? JSON.parse(convData) : [];
state.activeConversationId = localStorage.getItem(STORAGE_KEY + 'activeConv') || null;
@@ -64,6 +68,8 @@
localStorage.setItem(STORAGE_KEY + 'currentMode', state.currentMode);
localStorage.setItem(STORAGE_KEY + 'theme', state.theme);
localStorage.setItem(STORAGE_KEY + 'terminalOpen', state.terminalOpen.toString());
localStorage.setItem(STORAGE_KEY + 'keepAwake', state.keepAwake.toString());
localStorage.setItem(STORAGE_KEY + 'autoDeploy', state.autoDeploy.toString());
localStorage.setItem(STORAGE_KEY + 'conversations', JSON.stringify(state.conversations));
localStorage.setItem(STORAGE_KEY + 'activeConv', state.activeConversationId || '');
} catch(e) { console.error('Save state error:', e); }
@@ -458,6 +464,7 @@
state.streamingContent = '';
updateSendButton();
showThinking();
if (state.keepAwake) setWakeLock(true);
var requestBody = null;
var responseDiv = null;
@@ -517,6 +524,21 @@
updateSendButton();
saveState();
updateTerminalContent();
if (state.keepAwake) setWakeLock(false);
if (state.autoDeploy && (state.currentMode === 'coding' || state.currentMode === 'agentic')) {
var finalContent = state.streamingContent || '';
if (!finalContent && conv && conv.messages.length) {
var last = conv.messages[conv.messages.length - 1];
if (last && last.role === 'assistant') finalContent = last.content;
}
if (finalContent) {
var autoActions = parseAiActions(finalContent);
if (autoActions.length > 0) {
autoExecuteActions(autoActions, conv);
}
}
}
}
}
@@ -1014,6 +1036,7 @@
var Shell = null;
var Installer = null;
var Wake = null;
var termState = {
history: [],
historyIndex: -1,
@@ -1032,9 +1055,18 @@
try {
Shell = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Shell;
Installer = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Installer;
Wake = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Wake;
} catch(e) {}
if (!Shell) console.warn('Shell plugin not available');
if (!Installer) console.warn('Installer plugin not available');
if (!Wake) console.warn('Wake plugin not available');
}
async function setWakeLock(on) {
if (!Wake) return;
try {
if (on) { await Wake.acquire(); } else { await Wake.release(); }
} catch(e) { console.warn('WakeLock error:', e); }
}
async function shellExec(command, cwd, stream) {
@@ -1333,6 +1365,64 @@
termPrint('--- Deploy complete ---\n', 'info');
}
function showStatusToast(message, type) {
var existing = $('#status-toast');
if (existing) existing.remove();
var toast = document.createElement('div');
toast.id = 'status-toast';
toast.style.cssText = 'position:fixed;bottom:80px;left:50%;transform:translateX(-50%);z-index:1000;' +
'padding:10px 20px;border-radius:20px;font-size:13px;font-weight:600;max-width:90%;' +
'text-align:center;pointer-events:none;opacity:0;transition:opacity 0.3s;' +
'background:' + (type === 'success' ? 'var(--success)' : type === 'err' ? 'var(--danger)' : 'var(--accent)') +
';color:white;box-shadow:0 4px 12px rgba(0,0,0,0.3)';
toast.textContent = message;
document.body.appendChild(toast);
requestAnimationFrame(function() { toast.style.opacity = '1'; });
setTimeout(function() {
toast.style.opacity = '0';
setTimeout(function() { if (toast.parentElement) toast.remove(); }, 300);
}, 3000);
}
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'; });
var hasInstall = actions.some(function(a) { return a.type === 'install_apk'; });
var hasCommands = actions.some(function(a) { return a.type === 'run_command'; });
if (!hasFiles && !hasBuild && !hasInstall && !hasCommands) return;
var fileCount = actions.filter(function(a) { return a.type === 'create_file'; }).length;
if (fileCount > 0) {
showStatusToast('Auto-deploying ' + fileCount + ' file' + (fileCount > 1 ? 's' : '') + '...', 'info');
await deployActions(actions);
showStatusToast(fileCount + ' file' + (fileCount > 1 ? 's' : '') + ' deployed', 'success');
}
if (hasCommands) {
for (var i = 0; i < actions.length; i++) {
if (actions[i].type === 'run_command') {
showStatusToast('Running: ' + actions[i].command.substring(0, 40) + '...', 'info');
await termQueueCommand(actions[i].command);
}
}
}
if (hasBuild) {
showStatusToast('Building APK...', 'info');
await buildFromActions(actions);
}
if (hasInstall) {
for (var j = 0; j < actions.length; j++) {
if (actions[j].type === 'install_apk') {
showStatusToast('Installing APK...', 'info');
await installApk(actions[j].path);
}
}
}
}
async function buildFromActions(actions) {
showScreen('terminal');
termPrint('\n--- Building APK ---', 'info');
@@ -1720,6 +1810,8 @@
$('#tokens-value').textContent = state.maxTokens;
$('#settings-websearch').checked = state.webSearch;
$('#settings-streaming').checked = state.streaming;
$('#settings-autodeploy').checked = state.autoDeploy;
$('#settings-keepawake').checked = state.keepAwake;
}
function saveSettings() {
@@ -1864,6 +1956,14 @@
$('#settings-model').addEventListener('change', saveSettings);
$('#settings-websearch').addEventListener('change', saveSettings);
$('#settings-streaming').addEventListener('change', saveSettings);
$('#settings-autodeploy').addEventListener('change', function() {
state.autoDeploy = this.checked;
saveState();
});
$('#settings-keepawake').addEventListener('change', function() {
state.keepAwake = this.checked;
saveState();
});
$('#theme-toggle-header').addEventListener('click', toggleTheme);