From cbbf427a9331148ea1039846838928c03679aaea Mon Sep 17 00:00:00 2001 From: Jaakko Vanhala Date: Sun, 5 Apr 2026 09:51:01 +0300 Subject: [PATCH] =?UTF-8?q?Tab-completion=20kpn-terminaaliin:=20ennustava?= =?UTF-8?q?=20komennonsy=C3=B6tt=C3=B6=20sana=20kerrallaan?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TAB täydentää kontekstin mukaan: - tyhjä → "kpn " - "kpn " → "kpn help", "kpn run", "kpn pipeline" jne. - "kpn run " → agentit ja mallit (coder, manager, qwen-coder...) - "kpn run coder " → esimerkkiprompteja ("hello world in python") - "kpn pi" → "kpn pipeline " - osittainen sana → yhteinen etuliite tai ainoa vaihtoehto Tukee myös kpn pipeline -esimerkkiprompteja. Co-Authored-By: Claude Opus 4.6 (1M context) --- network-poc/static/index.html | 72 ++++++++++++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/network-poc/static/index.html b/network-poc/static/index.html index 69ceef1..213023a 100644 --- a/network-poc/static/index.html +++ b/network-poc/static/index.html @@ -1915,8 +1915,78 @@ termLog(` kpn: tuntematon alikomento "${sub}". Kokeile: kpn help`, '#f85149'); } + // Tab-completion: ennustava komennonsyöttö sana kerrallaan + const kpnCommands = { + 'kpn': ['help', 'run', 'pipeline', 'load', 'status', 'models', 'hello', 'clear'], + 'kpn run': ['coder', 'manager', 'tester', 'qa', 'data', 'observer', 'qwen-coder', 'smollm-135m', 'qwen-05b', 'phi3-mini'], + 'kpn pipeline': ['"'], + }; + // Esimerkkipromptit malleittain + const kpnExamples = { + 'kpn run coder': ['"hello world in python"', '"fibonacci in rust"', '"quicksort in javascript"'], + 'kpn run manager': ['"suunnittele REST API"', '"priorisoi tiimin tehtävät"'], + 'kpn run tester': ['"testaa login-toiminto"'], + 'kpn pipeline': ['"rakenna todo-sovellus"', '"tee laskin pythonilla"'], + }; + + function tabComplete(input) { + const val = input.value; + const words = val.trimEnd().split(/\s+/); + + // Etsitään sopiva täydennystaso + // "kpn" → "kpn " alikomennot, "kpn run" → mallit, "kpn run coder" → prompti + for (let depth = words.length; depth >= 1; depth--) { + const prefix = words.slice(0, depth).join(' '); + const partial = words[depth] || ''; + + // Tarkistetaan esimerkkipromptit ensin + if (kpnExamples[prefix] && !partial) { + const example = kpnExamples[prefix][Math.floor(Math.random() * kpnExamples[prefix].length)]; + input.value = prefix + ' ' + example; + return true; + } + + // Komentojen täydennys + const candidates = kpnCommands[prefix]; + if (candidates) { + const matches = partial + ? candidates.filter(c => c.startsWith(partial)) + : candidates; + if (matches.length === 1) { + words[depth] = matches[0]; + input.value = words.slice(0, depth + 1).join(' ') + ' '; + return true; + } else if (matches.length > 1 && !partial) { + input.value = prefix + ' ' + matches[0]; + return true; + } else if (matches.length > 1) { + // Yhteinen etuliite + let common = matches[0]; + for (const m of matches) { + while (!m.startsWith(common)) common = common.slice(0, -1); + } + if (common.length > partial.length) { + words[depth] = common; + input.value = words.slice(0, depth + 1).join(' '); + return true; + } + } + } + } + + // Tyhjä input → "kpn " + if (!val.trim()) { + input.value = 'kpn '; + return true; + } + return false; + } + termInput?.addEventListener('keydown', (e) => { - if (e.key === 'Enter') { + if (e.key === 'Tab') { + e.preventDefault(); + tabComplete(termInput); + } else if (e.key === 'Enter') { const cmd = termInput.value.trim(); if (cmd) termExec(cmd); termInput.value = '';