/
s.homyakov
/
dev2harness
Обзор
Документация
Войти
/
s.homyakov
/
dev2harness
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
main
src/terminalEngine.js
295 строк
10 KB
Sergey Homyakov
Harden user state and sandbox flows
27 май 2026, 09:28
27 май 2026, 09:28
1813063
Код
Авторство
О чём код?
const HOME = "workspace"; function cloneState(state) { return { cwd: state.cwd, dirs: new Set(state.dirs), files: new Map(state.files), history: [...state.history] }; } function cleanPath(path) { const parts = []; for (const part of path.split("/")) { if (!part || part === ".") continue; if (part === "..") parts.pop(); else parts.push(part); } return parts.join("/") || "."; } function resolvePath(cwd, target = ".") { if (!target || target === ".") return cwd; if (target === "~") return HOME; if (target.startsWith("~/")) return cleanPath(HOME + target.slice(1)); if (target.startsWith("/")) return cleanPath(target); return cleanPath(`${cwd}/${target}`); } function parentOf(path) { if (path === ".") return "."; const parts = path.split("/").filter(Boolean); parts.pop(); return parts.join("/") || "."; } function nameOf(path) { return path.split("/").filter(Boolean).at(-1) || "."; } function splitArgs(raw) { const matches = raw.match(/"[^"]*"|'[^']*'|\S+/g) || []; return matches.map((part) => part.replace(/^["']|["']$/g, "")); } function listDir(state, dir) { const children = []; for (const path of state.dirs) { if (path !== dir && parentOf(path) === dir) children.push(`${nameOf(path)}/`); } for (const path of state.files.keys()) { if (parentOf(path) === dir) children.push(nameOf(path)); } return children.sort().join(" ") || "(empty)"; } function blocked(raw) { return /(^|\s)(sudo|chmod|chown|ssh|scp|curl|wget|kill|pkill|dd|mkfs|python)(\s|$)/.test( raw ); } export function createTerminalState() { return { cwd: HOME, dirs: new Set(["/", "/home", HOME, `${HOME}/projects`, `${HOME}/notes`]), files: new Map([ [`${HOME}/readme.txt`, "Welcome to OpenCode Harness\nStart small and verify often."], [`${HOME}/draft.txt`, "rough outline"], [`${HOME}/app.log`, "info server started\nwarning cache is cold\nerror missing route"], [`${HOME}/api.json`, "{\"status\":\"ok\",\"lesson\":\"terminal\"}"], [`${HOME}/error.log`, "TypeError at server.js:12 - handler is not a function"], [`${HOME}/task.md`, "Goal: build a tiny feature\nConstraints: keep it testable\nDone: demo works"] ]), history: [] }; } export function terminalSnapshot(state) { return { cwd: state.cwd, dirs: [...state.dirs], files: [...state.files.entries()] }; } export function runCommand(current, rawInput) { const raw = rawInput.trim(); const state = cloneState(current); if (!raw) return { state, output: "", ok: false }; if (blocked(raw)) { state.history.push({ command: raw, output: "Blocked in the learning sandbox." }); return { state, output: "Blocked in the learning sandbox.", ok: false }; } const args = splitArgs(raw); const command = args[0]; let output = ""; let ok = true; try { if (command === "pwd") { output = state.cwd; } else if (command === "ls") { const dir = resolvePath(state.cwd, args[1] || "."); output = state.dirs.has(dir) ? listDir(state, dir) : `ls: ${args[1]}: No such directory`; ok = state.dirs.has(dir); } else if (command === "cd") { const dir = resolvePath(state.cwd, args[1] || HOME); if (state.dirs.has(dir)) { state.cwd = dir; output = ""; } else { output = `cd: no such directory: ${args[1] || ""}`; ok = false; } } else if (command === "mkdir") { const dir = resolvePath(state.cwd, args[1]); if (!args[1]) { output = "mkdir: missing folder name"; ok = false; } else if (!state.dirs.has(parentOf(dir))) { output = "mkdir: parent folder does not exist"; ok = false; } else { state.dirs.add(dir); output = ""; } } else if (command === "touch") { const file = resolvePath(state.cwd, args[1]); if (!args[1]) { output = "touch: missing file name"; ok = false; } else { state.files.set(file, state.files.get(file) || ""); output = ""; } } else if (command === "cat") { const file = resolvePath(state.cwd, args[1]); if (state.files.has(file)) output = state.files.get(file); else { output = `cat: ${args[1]}: No such file`; ok = false; } } else if (command === "echo") { const redirectIndex = args.findIndex((arg) => arg === ">" || arg === ">>"); if (redirectIndex > -1) { const text = args.slice(1, redirectIndex).join(" "); const file = resolvePath(state.cwd, args[redirectIndex + 1]); const previous = args[redirectIndex] === ">>" ? state.files.get(file) || "" : ""; state.files.set(file, previous ? `${previous}\n${text}` : text); output = ""; } else { output = args.slice(1).join(" "); } } else if (command === "grep") { const term = args[1]; const file = resolvePath(state.cwd, args[2]); if (!term || !args[2]) { output = "grep: usage grep text file"; ok = false; } else if (!state.files.has(file)) { output = `grep: ${args[2]}: No such file`; ok = false; } else { output = state.files .get(file) .split("\n") .filter((line) => line.toLowerCase().includes(term.toLowerCase())) .join("\n") || "(no matches)"; } } else if (command === "rg") { const term = args[1]; const targets = args.slice(2).map((arg) => resolvePath(state.cwd, arg)); const files = targets.length ? targets.filter((target) => state.files.has(target)) : [...state.files.keys()]; if (!term) { output = "rg: usage rg text [file]"; ok = false; } else if (targets.length && files.length === 0) { output = `rg: ${args[2]}: No such file`; ok = false; } else { const pattern = term.replace(/^["']|["']$/g, ""); output = files .flatMap((file) => state.files .get(file) .split("\n") .filter((line) => line.toLowerCase().includes(pattern.toLowerCase())) .map((line) => (files.length > 1 ? `${file}: ${line}` : line)) ) .join("\n") || "(no matches)"; } } else if (command === "cp") { const source = resolvePath(state.cwd, args[1]); const target = resolvePath(state.cwd, args[2]); if (state.files.has(source) && args[2]) { state.files.set(target, state.files.get(source)); output = ""; } else { output = "cp: source file not found"; ok = false; } } else if (command === "mv") { const source = resolvePath(state.cwd, args[1]); const target = resolvePath(state.cwd, args[2]); if (state.files.has(source) && args[2]) { state.files.set(target, state.files.get(source)); state.files.delete(source); output = ""; } else { output = "mv: source file not found"; ok = false; } } else if (command === "rm") { const flags = args.filter((arg) => arg.startsWith("-")); const recursive = flags.some((flag) => flag.includes("r")); const targetArg = args.find((arg, index) => index > 0 && !arg.startsWith("-")); const target = resolvePath(state.cwd, targetArg); if (state.files.has(target)) { state.files.delete(target); output = ""; } else if (state.dirs.has(target) && recursive) { for (const path of [...state.files.keys()]) { if (path.startsWith(`${target}/`)) state.files.delete(path); } for (const path of [...state.dirs]) { if (path === target || path.startsWith(`${target}/`)) state.dirs.delete(path); } output = ""; } else { output = "rm: target not found or folder needs -r"; ok = false; } } else if (command === "wc") { const file = resolvePath(state.cwd, args.at(-1)); if (state.files.has(file)) { const text = state.files.get(file); output = `${text.split("\n").length} ${text.split(/\s+/).filter(Boolean).length} ${text.length} ${args.at(-1)}`; } else { output = "wc: file not found"; ok = false; } } else if (command === "git") { const sub = args[1]; if (sub === "status") output = "On branch main\nChanges not staged for commit:\n modified: lesson-notes.md"; else if (sub === "add") output = ""; else if (sub === "commit") output = "[main 42abcde] checkpoint"; else if (sub === "diff" && args.includes("--check")) output = ""; else if (sub === "diff" && args.includes("--stat")) output = " lesson-notes.md | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)"; else if (sub === "diff") output = "- old note\n+ clearer note"; else if (sub === "rev-parse") output = "main"; else if (sub === "log") output = "42abcde checkpoint\n31bca98 initial course shell"; else if (sub === "branch") output = args[2] ? "" : "* main"; else if (sub === "checkout") output = ""; else { output = `git: unsupported practice command ${sub || ""}`; ok = false; } } else if (command === "npm") { const sub = args.slice(1).join(" "); if (sub === "init -y") { state.files.set(`${state.cwd}/package.json`, "{\"scripts\":{\"dev\":\"vite\"}}"); output = "Wrote package.json"; } else if (sub === "run dev") output = "Local dev server ready at http://localhost:5173"; else if (sub === "test") output = "3 checks passed"; else if (sub === "run lint") output = "lint passed"; else { output = `npm: unsupported practice command ${sub}`; ok = false; } } else if (command === "node") { if (args[1] === "server.js") output = "Server listening at http://localhost:3000"; else if (args[1] === "-e") output = "JSON parsed successfully"; else { output = "node: file not found in sandbox"; ok = false; } } else { output = `${command}: command not found in this lesson sandbox`; ok = false; } } catch (error) { output = error.message; ok = false; } state.history.push({ command: raw, output }); return { state, output, ok }; }