aboutsummaryrefslogtreecommitdiff
path: root/modules/core/terminal.js
diff options
context:
space:
mode:
authorAgando <roduccomm@gmail.com>2026-06-01 06:00:39 +0200
committerAgando <roduccomm@gmail.com>2026-06-01 06:00:39 +0200
commit6aed9c9e0252b0c8f681a358e5a8707271454137 (patch)
tree332a29a515c87c2295355cf81f18b818cfbaa846 /modules/core/terminal.js
parent7cc82d2d32e44ab1c5b7d042d5522d036d9aa0be (diff)
auto: 2026-06-01_06:00 changes
Diffstat (limited to 'modules/core/terminal.js')
-rw-r--r--modules/core/terminal.js58
1 files changed, 44 insertions, 14 deletions
diff --git a/modules/core/terminal.js b/modules/core/terminal.js
index d53ab70..5008842 100644
--- a/modules/core/terminal.js
+++ b/modules/core/terminal.js
@@ -54,13 +54,12 @@
let curr = new Uint16Array(n + 1);
for (let j = 0; j <= n; j++) prev[j] = j;
for (let i = 1; i <= m; i++) {
- let next = new Uint16Array(n + 1);
- next[0] = i;
+ curr[0] = i;
for (let j = 1; j <= n; j++) {
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
- next[j] = Math.min(prev[j] + 1, curr[j - 1] + 1, prev[j - 1] + cost);
+ curr[j] = Math.min(prev[j] + 1, curr[j - 1] + 1, prev[j - 1] + cost);
}
- [prev, curr] = [curr, next];
+ [prev, curr] = [curr, prev];
}
return prev[n];
}
@@ -98,8 +97,11 @@
if (['help','security','security-level'].includes(cmd)) {
return this._dispatch(cmd, args);
}
- // Unknown command handling
+ // Unknown command handling — skip at level 0 (permissive)
if (unknown && !this.whitelist.has(cmd)) {
+ if (this.level === 0) {
+ return this._dispatch(cmd, args);
+ }
this.blockedCount++;
const sug = this.suggest(cmd);
if (sug) {
@@ -107,7 +109,7 @@
} else {
this.terminal.print(`Security: Unknown command "${cmd}" — blocked. Use 'security-level 0' to disable.`, 'warning');
}
- // At levels 0-1: suggest/fix but still route to AI (terminal is also a chat interface)
+ // At level 1: suggest/fix but still route to AI (terminal is also a chat interface)
// At level 2+: block entirely (paranoid)
if (this.level >= 2) {
this.terminal.print(`Security: Unknown command "${cmd}" blocked (level ${this.level}).`, 'error');
@@ -272,6 +274,9 @@
this.selectedSuggestion = (this.selectedSuggestion + 1) % this.suggestions.length;
this.updateAutocompleteDisplay();
}
+ } else if (e.ctrlKey && (e.key === 'k' || e.key === 'K')) {
+ e.preventDefault();
+ this.toggleCmdCards();
} else if (e.key === 'Escape') {
if (this._aiBusy) {
this.executeCommand('ai-stop');
@@ -984,7 +989,7 @@
catch (e) { console.warn(`[SafeRegister] Skipped ${label}: ${e.message}`); }
}
async _loadExtModules(filterKeys) {
- const autoLoadKeys = filterKeys || ['calc', 'voice', 'cron', 'theme', 'wpm', 'mindmap', 'webdav', 'skill-pack-core', 'editor', 'diff', 'alias', 'finder', 'filemgr', 'cryptogzip', 'shell', 'tutorial'];
+ const autoLoadKeys = filterKeys || ['calc', 'voice', 'cron', 'theme', 'wpm', 'mindmap', 'webdav', 'skill-pack-core', 'editor', 'diff', 'alias', 'finder', 'filemgr', 'cryptogzip', 'shell', 'tutorial', 'busybox'];
const cacheVer = localStorage.getItem('webx11_cache_ver') || '2026-05-27-14';
try {
const res = await fetch('packages.json?v=' + cacheVer);
@@ -1098,7 +1103,7 @@
}
// Enhanced: check fuzzy suggestions before showing "not found"
const suggestion = this.security.suggest(cmd);
- if (suggestion && suggestion.dist <= 2) {
+ if (suggestion && suggestion.dist <= 2 && suggestion.dist > 0) {
this.print(`Command not found: ${cmd}`, 'error');
this.print(`Did you mean: ${suggestion.cmd}? (yes) (no)`, 'info');
// Render clickable yes/no
@@ -1111,7 +1116,7 @@
const noSpan = document.createElement('span');
noSpan.textContent = ' [no] ';
noSpan.style.cssText = 'color:var(--error-color);cursor:pointer;text-decoration:underline';
- noSpan.onclick = () => { /* do nothing — user declined */ };
+ noSpan.onclick = () => { this.print('Dismissed.', 'text-muted'); };
const line = out.lastElementChild;
if (line) { line.appendChild(yesSpan); line.appendChild(noSpan); }
}
@@ -1450,8 +1455,7 @@
const endpoint = document.getElementById('ollama-endpoint').value.trim();
this.ollamaManager.setEndpoint(endpoint);
const success = await this.ollamaManager.connect();
- this.updateOllamaStatus();
- if (success) { this.renderOllamaModels(); }
+ if (success) { this.renderOllamaModels(); this._populateValidatorModels(); this.updateOllamaStatus(); }
}
setOllamaModel() {
const select = document.getElementById('ollama-current-model');
@@ -1589,6 +1593,8 @@
valSlider.style.borderColor = enabled ? 'var(--info-color)' : 'var(--border-color)';
}
}
+ // Auto-populate validator model dropdown from connected models
+ this._populateValidatorModels();
// Initialize stream toggle from stored state
const strCb = document.getElementById('ollama-stream-toggle');
const strLabel = document.getElementById('ollama-stream-label');
@@ -1617,12 +1623,27 @@
if (storedModel) {
valSelect.innerHTML = '<option value="' + storedModel + '">' + storedModel + '</option><option value="">Disable (use main AI model)</option>';
valSelect.disabled = false;
- } else {
- valSelect.innerHTML = '<option value="">Connect to load models</option>';
- valSelect.disabled = true;
}
}
}
+ _populateValidatorModels() {
+ const select = document.getElementById('validator-model-select');
+ if (!select || !this.ollamaManager) return;
+ const models = this.ollamaManager.getModels();
+ if (!models || models.length === 0) {
+ select.innerHTML = '<option value="">Connect to load models</option>';
+ select.disabled = true;
+ return;
+ }
+ const stored = this.ollamaManager.validatorModel || '';
+ let html = '<option value="">Disable (use main AI model)</option>';
+ models.forEach(function(m) {
+ const sel = m.name === stored ? ' selected' : '';
+ html += '<option value="' + m.name + '"' + sel + '>' + m.name + '</option>';
+ });
+ select.innerHTML = html;
+ select.disabled = false;
+ }
openStartupModules() {
document.getElementById('startup-modules').style.display = 'flex';
this.renderStartupModules();
@@ -1811,6 +1832,15 @@
// Also mark tutorial as skipped so it doesn't reappear
if (this.tutorialModule) this.tutorialModule.skipTutorial();
}
+ toggleCmdCards() {
+ const panel = document.getElementById('cmd-cards');
+ if (!panel) return;
+ panel.classList.toggle('visible');
+ // If opening, focus the input field
+ if (panel.classList.contains('visible')) {
+ setTimeout(() => this.inputField.focus(), 50);
+ }
+ }
log(level, source, message) {
const d = new Date();
const ts = d.toISOString().split('T')[1].split('.')[0];