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 = '';