diff --git a/app/hello/hello.js b/app/hello/hello.js
new file mode 100644
index 0000000..295624c
--- /dev/null
+++ b/app/hello/hello.js
@@ -0,0 +1,35 @@
+/*
+
+ Hello message
+
+*/
+
+const message = `Приветствуем в PoshlostiOS!!!!
+
+Стандартные komandi:
+* cd
- перемещение по папкам
+* hello - эт кодмана
+* ls [dir] - посмотреть список файлов
+* meow - чтото пробормотать
+* posh [command] - типа херня которая команды обрабатывает
+* vget - скачать файлы из интернетов
+* clear - стереть терминал
+* rm - удалить файл
+* mv - переместить файл
+* bump - создать файл
+* cp - скопировать файл
+* mkdir - создать папку
+* reset - УНИЧТОЖИТЬ СИСТЕМУ, и установить заново :3
+* cat - показать содержимое файла
+* ppm [package] - пакетный менеджер
+
+Планируется:
+* сделать hex цвета
+* прога Worldwide Objective Manuals (WOMan) которая пишет туторы по пакетам, написанию прог и описание стандартных прог
+* прога чтото наподобе nano или vi
+`
+
+async function main(args) {
+ writeStdout(message)
+ return 0
+}
\ No newline at end of file
diff --git a/app/hello/package.json b/app/hello/package.json
new file mode 100644
index 0000000..40fa5af
--- /dev/null
+++ b/app/hello/package.json
@@ -0,0 +1,8 @@
+{
+ "name": "hello",
+ "version": "0.1.2",
+ "description": "Hello Message",
+ "author": "MeexReay",
+ "apps": [ "hello.js" ],
+ "configs": []
+}
\ No newline at end of file
diff --git a/app/neofetch/neofetch.js b/app/neofetch/neofetch.js
new file mode 100644
index 0000000..f0f8e8a
--- /dev/null
+++ b/app/neofetch/neofetch.js
@@ -0,0 +1,82 @@
+/*
+
+ neofetch - neofetch
+
+*/
+
+function getDurationString(start_time) {
+ const now = new Date();
+ const diffMs = now - start_time;
+
+ const seconds = Math.floor(diffMs / 1000);
+ const minutes = Math.floor(seconds / 60);
+ const hours = Math.floor(minutes / 60);
+ const days = Math.floor(hours / 24);
+
+ const remainingHours = hours % 24;
+ const remainingMinutes = minutes % 60;
+
+ let result = [];
+
+ if (days > 0) result.push(`${days}d`);
+ if (remainingHours > 0) result.push(`${remainingHours}h`);
+ result.push(`${remainingMinutes}m`);
+
+ return result.join(" ");
+}
+
+// Function to get CPU, GPU, and memory information
+function getSystemInfo() {
+ const cpuInfo = navigator.hardwareConcurrency;
+
+ const memoryInfo = navigator.deviceMemory;
+ const totalJSHeap = performance.memory.totalJSHeapSize / (1024 * 1024);
+
+ const canvas = document.createElement('canvas');
+ const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
+ let gpuInfo = null;
+
+ if (gl) {
+ const debugInfo = gl.getExtension('WEBGL_debug_renderer_info');
+ if (debugInfo) {
+ gpuInfo = {
+ vendor: gl.getParameter(debugInfo.UNMASKED_VENDOR_WEBGL),
+ renderer: gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL)
+ };
+ }
+ }
+
+ return [
+ cpuInfo + " cores",
+ memoryInfo ? memoryInfo * 1024 + ' MB' : 'Not supported',
+ totalJSHeap.toFixed(2) + ' MB',
+ gpuInfo ? `${gpuInfo.renderer}` : 'GPU Info not available'
+ ]
+}
+
+async function main(args) {
+ let [cpu, max_mem, now_mem, gpu] = getSystemInfo()
+
+ writeStdout(`
+ █████ user@poshlosti
+ ███░░░█ █ ------------------
+ █░░█░░░██ OS: PoshlostiOS
+ █░█░░████ Uptime: ${getDurationString(start_date)}
+ █░███░░░░█ Packages: ${(await listPackages()).length} (ppm)
+ ██░░░░░░░█ Shell: posh ${(await getInstalledPackage("posh")).version}
+ █ █░░░░░░░██ Resolution: ${window.innerWidth}x${window.innerHeight}
+ █░░░░░░░░█ Memory: ${now_mem} / ${max_mem}
+ █░░░░░░░░█ CPU: ${cpu}
+ █░░░░░░░░░█ GPU: ${gpu}
+ ██░░░░░░░░███████
+ █░░████████▓▓▓█
+ █████████▓▓▓▓▓▓▓▓▓██
+ █▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓█
+ █▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓██
+ ██▓▓▓▓▓▓▓▓▓▓▓▓▓█
+ █▓▓▓▓▓▓▓▓▓█████
+ ██████████
+`)
+
+ return 0
+}
\ No newline at end of file
diff --git a/app/neofetch/package.json b/app/neofetch/package.json
new file mode 100644
index 0000000..2caa673
--- /dev/null
+++ b/app/neofetch/package.json
@@ -0,0 +1,8 @@
+{
+ "name": "neofetch",
+ "version": "0.1.1",
+ "description": "neofetch damn",
+ "author": "MeexReay",
+ "apps": [ "neofetch.js" ],
+ "configs": []
+}
\ No newline at end of file
diff --git a/app/posh/cd.js b/app/posh/cd.js
new file mode 100644
index 0000000..a7a2c40
--- /dev/null
+++ b/app/posh/cd.js
@@ -0,0 +1,9 @@
+async function main(args) {
+ if (!hasFile(args[1])) {
+ writeStdout(`нет такой папки бро\n`)
+ return 1
+ }
+ cwd = simplifyPath(args[1])
+ writeStdout(`бро переместил тебя в ${args[1]} без б ваще обращайся\n`)
+ return 0
+}
\ No newline at end of file
diff --git a/app/posh/clear.js b/app/posh/clear.js
new file mode 100644
index 0000000..aa0488b
--- /dev/null
+++ b/app/posh/clear.js
@@ -0,0 +1,4 @@
+async function main(args) {
+ clearTerminal()
+ return 0
+}
\ No newline at end of file
diff --git a/app/posh/meow.js b/app/posh/meow.js
new file mode 100644
index 0000000..4408e86
--- /dev/null
+++ b/app/posh/meow.js
@@ -0,0 +1,4 @@
+async function main(args) {
+ writeStdout(args.slice(1).join(" ")+"\n")
+ return 0
+}
\ No newline at end of file
diff --git a/app/posh/package.json b/app/posh/package.json
new file mode 100644
index 0000000..b4ad6d0
--- /dev/null
+++ b/app/posh/package.json
@@ -0,0 +1,8 @@
+{
+ "name": "posh",
+ "version": "0.1.1",
+ "description": "Poshlosti Shell",
+ "author": "MeexReay",
+ "apps": [ "posh.js", "meow.js", "cd.js", "clear.js" ],
+ "configs": [ "posh.json" ]
+}
\ No newline at end of file
diff --git a/app/posh/posh.js b/app/posh/posh.js
new file mode 100644
index 0000000..b0f63a0
--- /dev/null
+++ b/app/posh/posh.js
@@ -0,0 +1,93 @@
+/*
+
+ PoSh - Poshlosti Shell
+
+*/
+
+async function processCommand(command, args) {
+ let executable = command
+ if (!executable.startsWith("/")) {
+ if (executable.includes("/")) {
+ executable = cwd + "/" + executable
+ } else {
+ executable = "/app/" + executable
+ }
+ }
+ if (!hasFile(executable) && hasFile(executable+".js")) {
+ executable = executable + ".js"
+ }
+ executable = simplifyPath(executable)
+
+ if (hasFile(executable)) {
+ try {
+ let code = await executeCommand([executable].concat(args)).promise
+ if (code != 0) {
+ await writeStdout("\nСтатус код: "+code+"\n")
+ }
+ } catch (e) {
+ console.log(e)
+ await writeStdout("Не запустилася\n")
+ }
+ } else {
+ await writeStdout("Твоя команда "+executable+" не найдена :3\n")
+ }
+}
+
+async function main(args) {
+ if (args.length > 1) {
+ await processCommand(args[1], args.slice(2))
+ }
+
+ let history = [""]
+ let history_index = 0
+
+ let config = JSON.parse(readFile("/config/posh.json"))
+ let prompt = config["prompt"]
+ let startup = config["startup"]
+
+ for (let command of startup) {
+ let args = command.split(" ")
+ await processCommand(args[0], args.slice(1))
+ }
+
+ while (true) {
+ await writeStdout(prompt.replace("{cwd}", cwd))
+
+ let command = await readLine((key, ctrl, alt, shift, content, pos) => {
+ console.log(history, content, pos, key)
+
+ if (key == "ArrowDown") {
+ history_index = Math.max(0, history_index - 1)
+ return [history[history_index], history[history_index].length]
+ }
+
+ if (key == "ArrowUp") {
+ history_index = Math.min(history.length-1, history_index + 1)
+ return [history[history_index], history[history_index].length]
+ }
+
+ return [content, pos]
+ })
+
+ if (command.length > 0) {
+ history.splice(1, 0, command);
+ history_index = 0
+
+ let args = command.split(" ")
+ command = args[0]
+ args = args.slice(1)
+
+ if (command == "exit") {
+ if (args.length == 0) {
+ return 0
+ } else {
+ return parseInt(args[0])
+ }
+ } else {
+ await processCommand(command, args)
+ }
+ }
+ }
+
+ return 0
+}
\ No newline at end of file
diff --git a/app/posh/posh.json b/app/posh/posh.json
new file mode 100644
index 0000000..f9ddf57
--- /dev/null
+++ b/app/posh/posh.json
@@ -0,0 +1,7 @@
+{
+ "prompt": "[posh {cwd}]$ ",
+ "startup": [
+ "hello",
+ "meow"
+ ]
+}
\ No newline at end of file
diff --git a/app/ppm/package.json b/app/ppm/package.json
new file mode 100644
index 0000000..da80131
--- /dev/null
+++ b/app/ppm/package.json
@@ -0,0 +1,8 @@
+{
+ "name": "ppm",
+ "version": "0.1.3",
+ "description": "Poshliy Package Manager",
+ "author": "MeexReay",
+ "apps": [ "ppm.js" ],
+ "configs": [ "ppm.json" ]
+}
\ No newline at end of file
diff --git a/app/ppm/ppm.js b/app/ppm/ppm.js
new file mode 100644
index 0000000..3250ac7
--- /dev/null
+++ b/app/ppm/ppm.js
@@ -0,0 +1,124 @@
+/*
+
+ PPM - Poshliy Package Manager
+
+*/
+
+async function main(args) {
+ if (args.length == 3 && "iurs".includes(args[1])) {
+ let package = args[2]
+
+ if (args[1] == "i") {
+ let config = JSON.parse(readFile("/config/ppm.json"))
+
+ for (const repo of config["repositories"]) {
+ // await writeStdout(`Фетчим ${package} на репозитории ${repo}\n`)
+
+ let status = await installPackage(repo+"/"+package)
+
+ if (status == 0) {
+ let pkg = await getInstalledPackage(package)
+ await writeStdout(`Пакет ${pkg['name']}-${pkg['version']} установлен\n`)
+ return 0
+ } else if (status == 1) {
+ await writeStdout("Пакет не установлен тк он уже установлен чувааак\n")
+ return 1
+ }
+ }
+ } else if (args[1] == "u") {
+ let config = JSON.parse(readFile("/config/ppm.json"))
+
+ for (const repo of config["repositories"]) {
+ let status = await updatePackage(package, repo+"/"+package)
+
+ if (status == 0) {
+ let pkg = await getInstalledPackage(package)
+ await writeStdout(`Пакет ${pkg['name']}-${pkg['version']} обновлен\n`)
+ return 0
+ } else if (status == 1) {
+ await writeStdout("Пакет не найден ты его установи сначала чел\n")
+ return 1
+ }
+ }
+
+ await writeStdout("обнова не прошла успешна\n")
+ return 1
+ } else if (args[1] == "r") {
+ if (await removePackage(package)) {
+ await writeStdout(`Пакет ${package} удален\n`)
+ } else {
+ await writeStdout("Биспокойся произошла ошибко\n")
+ return 1
+ }
+ } else if (args[1] == "s") {
+ let pkg = await getInstalledPackage(package)
+ for (const [key, value] of Object.entries(pkg)) {
+ await writeStdout(key.charAt(0).toUpperCase()+key.slice(1)+": "+value+"\n")
+ }
+ }
+ } else if (args.length == 2 && args[1] == "l") {
+ await writeStdout("ваши покеты:\n")
+ for (const package of (await listPackages())) {
+ await writeStdout("- "+package["name"]+"-"+package["version"]+"\n")
+ }
+ } else if (args.length == 2 && args[1] == "a") {
+ let config = JSON.parse(readFile("/config/ppm.json"))
+
+ for (const package of (await listPackages())) {
+ for (const repo of config["repositories"]) {
+ // await writeStdout(`Фетчим ${package["name"]} на репозитории ${repo}\n`)
+
+ let fetched = await fetchPackage(repo+"/"+package["name"])
+ if (fetched != null) {
+ if (fetched["version"] == package["version"]) {
+ await writeStdout(`Пакет ${package['name']}-${package['version']} уже на последней версии\n`)
+ break
+ }
+
+ let status = await updatePackage(package["name"], repo+"/"+package["name"])
+
+ if (status == 0) {
+ let pkg = await getInstalledPackage(package["name"])
+ await writeStdout(`Пакет ${pkg['name']}-${pkg['version']} обновлен\n`)
+ break
+ } else if (status == 1) {
+ break
+ }
+ }
+ }
+ }
+
+ await writeStdout("Обнова прошла успешна\n")
+ return 0
+ } else if (args.length == 2 && args[1] == "A") {
+ let config = JSON.parse(readFile("/config/ppm.json"))
+
+ for (const package of (await listPackages())) {
+ for (const repo of config["repositories"]) {
+ let status = await updatePackage(package["name"], repo+"/"+package["name"])
+
+ if (status == 0) {
+ let pkg = await getInstalledPackage(package["name"])
+ await writeStdout(`Пакет ${pkg['name']}-${pkg['version']} обновлен\n`)
+ break
+ } else{
+ console.log(status, repo, package)
+ }
+ }
+ }
+
+ await writeStdout("Обнова прошла успешна\n")
+ return 0
+ } else {
+ await writeStdout("Использование:\n")
+ await writeStdout(" ppm i <пакет> - установить пакет\n")
+ await writeStdout(" ppm u <пакет> - обновить пакет\n")
+ await writeStdout(" ppm r <пакет> - удалить пакет\n")
+ await writeStdout(" ppm s <пакет> - показать инфу о пакете\n")
+ await writeStdout(" ppm l - показать инфу о пакете\n")
+ await writeStdout(" ppm a - обновить все пакеты\n")
+ await writeStdout(" ppm A - обновить все пакеты принудительно\n")
+ }
+
+ return 0
+}
\ No newline at end of file
diff --git a/app/ppm/ppm.json b/app/ppm/ppm.json
new file mode 100644
index 0000000..578a53f
--- /dev/null
+++ b/app/ppm/ppm.json
@@ -0,0 +1,5 @@
+{
+ "repositories": [
+ "https://poshlostios.meex.lol/app"
+ ]
+}
\ No newline at end of file
diff --git a/app/putils/bump.js b/app/putils/bump.js
new file mode 100644
index 0000000..536a7bc
--- /dev/null
+++ b/app/putils/bump.js
@@ -0,0 +1,5 @@
+async function main(args) {
+ writeFile(args[1], "")
+ writeStdout(`все твой файл создан ${args[1]} такой же ты хотел жа\n`)
+ return 0
+}
\ No newline at end of file
diff --git a/app/putils/cat.js b/app/putils/cat.js
new file mode 100644
index 0000000..68cd488
--- /dev/null
+++ b/app/putils/cat.js
@@ -0,0 +1,8 @@
+async function main(args) {
+ if (!hasFile(args[1])) {
+ writeStdout(`нет такой faila бро\n`)
+ return 1
+ }
+ writeStdout(readFile(args[1])+"\n")
+ return 0
+}
\ No newline at end of file
diff --git a/app/putils/cp.js b/app/putils/cp.js
new file mode 100644
index 0000000..8db38f9
--- /dev/null
+++ b/app/putils/cp.js
@@ -0,0 +1,55 @@
+async function main(args=["","",""]) {
+ let source = simplifyPath(args[1])
+ let target = simplifyPath(args[2])
+
+ if (!hasFile(args[1])) {
+ writeStdout(`нет такой херни чо мне ты даешь долбан X нету :x: :regional_symbol_x: :cross:\n`)
+ return 1
+ }
+
+ if (isFolder(source)) {
+ if (!hasFile(target) || isFolder(target)) {
+ let create_dirs = hasFile(target) ? [] : [target]
+ let write_files = []
+
+ let recursive = (folder) => {
+ for (const file of listFiles(folder)) {
+ let path = folder+"/"+file
+ if (isFolder(path)) {
+ create_dirs.push(path)
+ recursive(path)
+ } else {
+ write_files.push(path)
+ }
+ }
+ }
+
+ recursive(source)
+
+ for (const dir of create_dirs) {
+ createFolder(target + dir.slice(source.length))
+ }
+
+ for (const file of write_files) {
+ let path = target + file.slice(source.length)
+ writeFile(path, readFile(file))
+ }
+ } else {
+ writeStdout("ой сукаа я вахуе\n")
+ return 1
+ }
+ } else {
+ if (isFolder(target)) {
+ target = target+"/"+source.split("/").reverse()[0]
+ }
+
+ let content = readFile(source)
+ writeFile(target, content)
+ }
+
+ removeFile(source)
+
+ writeStdout(`все скопировано бро ${source} в ${target} скопировано спомощье команды CP (ЦП)\n`)
+
+ return 0
+}
\ No newline at end of file
diff --git a/app/putils/ls.js b/app/putils/ls.js
new file mode 100644
index 0000000..9a975a0
--- /dev/null
+++ b/app/putils/ls.js
@@ -0,0 +1,12 @@
+async function main(args) {
+ if (args.length < 2) {
+ writeStdout(listFiles(".").map(o => {
+ return (isFolder(o) ? "DIR " : "FILE") + " " + simplifyPath(o)
+ }).join("\n")+"\n")
+ } else {
+ writeStdout(listFiles(args[1]).map(o => {
+ return (isFolder(args[1]+"/"+o) ? "DIR " : "FILE") + " " + simplifyPath(args[1]+"/"+o)
+ }).join("\n")+"\n")
+ }
+ return 0
+}
\ No newline at end of file
diff --git a/app/putils/mkdir.js b/app/putils/mkdir.js
new file mode 100644
index 0000000..00fcb3f
--- /dev/null
+++ b/app/putils/mkdir.js
@@ -0,0 +1,5 @@
+async function main(args) {
+ createFolder(args[1])
+ writeStdout(`папка создана ${args[1]}\n`)
+ return 0
+}
\ No newline at end of file
diff --git a/app/putils/mv.js b/app/putils/mv.js
new file mode 100644
index 0000000..6f46048
--- /dev/null
+++ b/app/putils/mv.js
@@ -0,0 +1,55 @@
+async function main(args=["","",""]) {
+ let source = simplifyPath(args[1])
+ let target = simplifyPath(args[2])
+
+ if (!hasFile(args[1])) {
+ writeStdout(`бро я б помог сделал что ты хочешь но сука нет такого файла бай бай\n`)
+ return 1
+ }
+
+ if (isFolder(source)) {
+ if (!hasFile(target) || isFolder(target)) {
+ let create_dirs = hasFile(target) ? [] : [target]
+ let write_files = []
+
+ let recursive = (folder) => {
+ for (const file of listFiles(folder)) {
+ let path = folder+"/"+file
+ if (isFolder(path)) {
+ create_dirs.push(path)
+ recursive(path)
+ } else {
+ write_files.push(path)
+ }
+ }
+ }
+
+ recursive(source)
+
+ for (const dir of create_dirs) {
+ createFolder(target + dir.slice(source.length))
+ }
+
+ for (const file of write_files) {
+ let path = target + file.slice(source.length)
+ writeFile(path, readFile(file))
+ }
+ } else {
+ writeStdout("как по твоему я должен блять переместить папку в файл ты ебнутый сука\n")
+ return 1
+ }
+ } else {
+ if (isFolder(target)) {
+ target = target+"/"+source.split("/").reverse()[0]
+ }
+
+ let content = readFile(source)
+ writeFile(target, content)
+ }
+
+ removeFile(source)
+
+ writeStdout(`все перемещено чо надо то есть ${source} в ${target} ну изи получается\n`)
+
+ return 0
+}
\ No newline at end of file
diff --git a/app/putils/package.json b/app/putils/package.json
new file mode 100644
index 0000000..1cba82d
--- /dev/null
+++ b/app/putils/package.json
@@ -0,0 +1,8 @@
+{
+ "name": "putils",
+ "version": "0.1.0",
+ "description": "Poshliye Utiliti",
+ "author": "MeexReay",
+ "apps": [ "bump.js", "cat.js", "cp.js", "ls.js", "mkdir.js", "mv.js", "rm.js" ],
+ "configs": []
+}
\ No newline at end of file
diff --git a/app/putils/rm.js b/app/putils/rm.js
new file mode 100644
index 0000000..a3b31b1
--- /dev/null
+++ b/app/putils/rm.js
@@ -0,0 +1,9 @@
+async function main(args) {
+ if (!hasFile(args[1])) {
+ writeStdout(`я вахуе ну ты же знаешь что такого файла нет нахуй ты это делаешь\n`)
+ return 1
+ }
+ removeFile(args[1])
+ writeStdout(`ну все твой файл ${args[1]} удален ДОВОЛЕН ЧТО ТЫ СДЕЛАЛ?\n`)
+ return 0
+}
\ No newline at end of file
diff --git a/app/reset/package.json b/app/reset/package.json
new file mode 100644
index 0000000..ce69b49
--- /dev/null
+++ b/app/reset/package.json
@@ -0,0 +1,8 @@
+{
+ "name": "reset",
+ "version": "0.1.0",
+ "description": "Resets system to a newborn",
+ "author": "MeexReay",
+ "apps": [ "reset.js" ],
+ "configs": []
+}
\ No newline at end of file
diff --git a/app/reset/reset.js b/app/reset/reset.js
new file mode 100644
index 0000000..a02f7e4
--- /dev/null
+++ b/app/reset/reset.js
@@ -0,0 +1,18 @@
+async function main(args) {
+ await writeStdout("Ты уверен, что хочешь стереть систему, и установить снова?? (y/n) > ")
+ let confirm = (await readLine()).toLowerCase() == "y"
+ if (confirm) {
+ await new Promise(r => setTimeout(r, 100));
+ await writeStdout("Прощай...")
+ await new Promise(r => setTimeout(r, 2000));
+ await resetSystem()
+ document.location.reload()
+ for (const c of Array.from("\nвелосипе")) {
+ await writeStdout(c)
+ await new Promise(r => setTimeout(r, 30));
+ }
+ await new Promise(r => setTimeout(r, 999999));
+ }
+
+ return 0
+}
\ No newline at end of file
diff --git a/app/vget/package.json b/app/vget/package.json
new file mode 100644
index 0000000..0f2e0fe
--- /dev/null
+++ b/app/vget/package.json
@@ -0,0 +1,8 @@
+{
+ "name": "vget",
+ "version": "0.1.0",
+ "description": "Vulgar get",
+ "author": "MeexReay",
+ "apps": [ "vget.js" ],
+ "configs": []
+}
\ No newline at end of file
diff --git a/app/vget/vget.js b/app/vget/vget.js
new file mode 100644
index 0000000..334bad5
--- /dev/null
+++ b/app/vget/vget.js
@@ -0,0 +1,17 @@
+/*
+
+ VGet - Vulgar Get
+
+*/
+
+async function main(args) {
+ if (args.length != 3) {
+ writeStdout("vget \n")
+ return 1
+ }
+
+ writeFile(args[2], await (await fetch(args[0])).text())
+ writeStdout("Файл "+args[1]+" вставлен внутрь пути "+args[2]+"\n")
+
+ return 0
+}
\ No newline at end of file
diff --git a/font/terminus.ttf b/font/terminus.ttf
new file mode 100644
index 0000000..d125e63
Binary files /dev/null and b/font/terminus.ttf differ
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..42d854b
--- /dev/null
+++ b/index.html
@@ -0,0 +1,77 @@
+
+
+
+
+
+ PoshlostiOS
+
+
+
+
+
+
+
+
+
+
+ _
+
+
+
+
+
+
+
diff --git a/sys/fs.js b/sys/fs.js
new file mode 100644
index 0000000..c549aeb
--- /dev/null
+++ b/sys/fs.js
@@ -0,0 +1,223 @@
+var fs_mapping = {}
+
+function saveMapping() {
+ localStorage.setItem("fs_mapping", JSON.stringify(fs_mapping))
+}
+
+function loadMapping() {
+ if (localStorage.getItem("fs_mapping") == null) {
+ fs_mapping = {}
+ } else {
+ fs_mapping = JSON.parse(localStorage.getItem("fs_mapping"))
+ }
+}
+
+loadMapping()
+
+function getMappingCode(path) {
+ let parts = (path.startsWith("/") ? path.slice(1) : path).split("/")
+ let now = fs_mapping
+
+ let index = 0
+ for (const part of parts) {
+ if (Object.keys(now).includes(part)) {
+ if (index == parts.length-1) {
+ return "file_"+now[part]
+ } else {
+ now = now[part]
+ }
+ } else {
+ return null
+ }
+ index++
+ }
+ return null
+}
+
+function createMappingCode(path) {
+ if (path.length === 0) return null
+
+ let code = 0, i, chr
+
+ for (i = 0; i < path.length; i++) {
+ chr = path.charCodeAt(i)
+ code = ((code << 5) - code) + chr
+ code |= 0
+ }
+
+ let parts = (path.startsWith("/") ? path.slice(1) : path).split("/")
+ let now = fs_mapping
+
+ let index = 0
+ for (const part of parts) {
+ if (index == parts.length-1) {
+ now[part] = code
+ } else if (Object.keys(now).includes(part)) {
+ now = now[part]
+ } else {
+ return null
+ }
+ index++
+ }
+ saveMapping()
+
+ return "file_"+code
+}
+
+function createMappingFolder(path) {
+ let parts = (path.startsWith("/") ? path.slice(1) : path).split("/")
+ let now = fs_mapping
+
+ let index = 0
+ for (const part of parts) {
+ if (index == parts.length-1) {
+ now[part] = {}
+ } else if (Object.keys(now).includes(part)) {
+ now = now[part]
+ } else {
+ return null
+ }
+ index++
+ }
+ saveMapping()
+ return null
+}
+
+function listMappingFolder(path) {
+ if (path == "/") return Object.keys(fs_mapping)
+ let parts = (path.startsWith("/") ? path.slice(1) : path).split("/")
+ let now = fs_mapping
+
+ let index = 0
+ for (const part of parts) {
+ if (Object.keys(now).includes(part)) {
+ if (index == parts.length-1) {
+ return Object.keys(now[part])
+ } else {
+ now = now[part]
+ }
+ } else {
+ return null
+ }
+ index++
+ }
+ return null
+}
+
+function isMappingFolder(path) {
+ let parts = (path.startsWith("/") ? path.slice(1) : path).split("/")
+ let now = fs_mapping
+
+ let index = 0
+ for (const part of parts) {
+ if (Object.keys(now).includes(part)) {
+ if (index == parts.length-1) {
+ return typeof now[part] === "object"
+ } else {
+ now = now[part]
+ }
+ } else {
+ return null
+ }
+ index++
+ }
+ return null
+}
+
+function removeMappingEntry(path) {
+ let parts = (path.startsWith("/") ? path.slice(1) : path).split("/")
+ let now = fs_mapping
+
+ let index = 0
+ for (const part of parts) {
+ if (Object.keys(now).includes(part)) {
+ if (index == parts.length-1) {
+ delete now[part]
+
+ saveMapping()
+ } else {
+ now = now[part]
+ }
+ } else {
+ return null
+ }
+ index++
+ }
+ return null
+}
+
+function readFile(path) {
+ path = simplifyPath(path)
+ return localStorage.getItem(getMappingCode(path))
+}
+
+function writeFile(path, content) {
+ path = simplifyPath(path)
+ let code = getMappingCode(path)
+ if (code == null) code = createMappingCode(path)
+ localStorage.setItem(code, content)
+}
+
+function hasFile(path) {
+ path = simplifyPath(path)
+ return getMappingCode(path) != null
+}
+
+function listFiles(path) {
+ path = simplifyPath(path)
+ return listMappingFolder(path)
+}
+
+function createFolder(path) {
+ createMappingFolder(simplifyPath(path))
+}
+
+function removeFile(path) {
+ path = simplifyPath(path)
+ if (!isFolder(path)) {
+ localStorage.removeItem(getMappingCode(path))
+ }
+ removeMappingEntry(path)
+}
+
+function isFolder(path) {
+ path = simplifyPath(path)
+ return isMappingFolder(path)
+}
+
+function simplifyPath(path) {
+ if (!path.startsWith("/")) path = cwd+"/" + path;
+
+ const segments = path.split('/');
+ const stack = [];
+
+ for (let segment of segments) {
+ if (segment === '' || segment === '.') {
+ continue;
+ } else if (segment === '..') {
+ if (stack.length > 0) {
+ stack.pop();
+ }
+ } else {
+ stack.push(segment);
+ }
+ }
+
+ const simplifiedPath = '/' + stack.join('/');
+ return simplifiedPath;
+}
+
+function clearFileSystem() {
+ let callback = (x) => {
+ for (const o of Object.values(x)) {
+ if (typeof o === "object") {
+ callback(o)
+ } else {
+ localStorage.removeItem("file_"+o)
+ }
+ }
+ }
+ callback(fs_mapping)
+ fs_mapping = {}
+ saveMapping()
+}
\ No newline at end of file
diff --git a/sys/ppm.js b/sys/ppm.js
new file mode 100644
index 0000000..5453d2a
--- /dev/null
+++ b/sys/ppm.js
@@ -0,0 +1,128 @@
+async function fetchPackage(url) {
+ try {
+ return await fetchJson(url+"/package.json")
+ } catch (error) {
+ return null
+ }
+}
+
+async function getInstalledPackage(name) {
+ if (!hasFile("/etc/ppm/"+name)) {
+ return null
+ }
+
+ return JSON.parse(readFile("/etc/ppm/"+name))
+}
+
+async function listPackages() {
+ let packages = []
+ for (const name of listFiles("/etc/ppm")) {
+ packages.push(JSON.parse(readFile("/etc/ppm/"+name)))
+ }
+ return packages
+}
+
+async function fetchJson(url) {
+ for (let i = 0; i < 10; i++) {
+ try {
+ return await fetch(url).then(o => o.json())
+ } catch (error) {
+ continue
+ }
+ }
+ return null
+}
+
+async function fetchText(url) {
+ for (let i = 0; i < 10; i++) {
+ try {
+ return await fetch(url).then(o => o.text())
+ } catch (error) {
+ continue
+ }
+ }
+ return null
+}
+
+async function installPackage(url) {
+ let package
+ try {
+ package = await fetch(url+"/package.json").then(o => o.json())
+ } catch (error) {
+ return 2
+ }
+
+ if (!hasFile("/etc/ppm")) {
+ createFolder("/etc/ppm")
+ }
+
+ if (hasFile("/etc/ppm/"+package["name"])) {
+ return 1
+ }
+
+ if ("apps" in package) {
+ for (const app of package.apps) {
+ writeFile("/app/"+app, await fetchText(url+"/"+app))
+ }
+ }
+
+ if ("configs" in package) {
+ for (const config of package.configs) {
+ writeFile("/config/"+config, await fetchText(url+"/"+config))
+ }
+ }
+
+ writeFile("/etc/ppm/"+package["name"], JSON.stringify(package))
+
+ return 0
+}
+
+async function removePackage(name) {
+ let package = await getInstalledPackage(name)
+
+ if (package == null) return false
+
+ if ("apps" in package) {
+ for (const app of package.apps) {
+ removeFile("/app/"+app)
+ }
+ }
+
+ if ("configs" in package) {
+ for (const config of package.configs) {
+ removeFile("/config/"+config)
+ }
+ }
+
+ removeFile("/etc/ppm/"+name)
+
+ return true
+}
+
+async function updatePackage(name, url) {
+ let package = await getInstalledPackage(name)
+
+ if (package == null) return 1
+
+ if ("apps" in package) {
+ for (const app of package.apps) {
+ removeFile("/app/"+app)
+ }
+ }
+
+ try {
+ package = await fetch(url+"/package.json").then(o => o.json())
+ } catch (error) {
+ return 2
+ }
+
+ if ("apps" in package) {
+ for (const app of package.apps) {
+ writeFile("/app/"+app, await fetchText(url+"/"+app))
+ }
+ }
+
+ writeFile("/etc/ppm/"+name, JSON.stringify(package))
+
+ return 0
+}
\ No newline at end of file
diff --git a/sys/system.js b/sys/system.js
new file mode 100644
index 0000000..8370012
--- /dev/null
+++ b/sys/system.js
@@ -0,0 +1,190 @@
+var cwd = "/home"
+
+var stdout = ""
+var stdin = ""
+
+var disable_stdin = true
+var silent_stdin = false
+
+var processes = []
+
+const RENDER_STDIN = 1
+const SILENT_STDIN = 2
+const DISABLE_STDIN = 3
+const ENABLE_STDIN = 4
+
+async function readLine(on_key=(key, ctrl, alt, shift, content, pos) => [content, pos]) {
+ setStdinFlag(ENABLE_STDIN)
+
+ let start_cursor_pos = getCursor()
+
+ let pos = 0
+ let content = ""
+ while (true) {
+ let event = await pollStdinEvent()
+
+ if (event.type == "key") {
+ if (event.key == "Backspace") {
+ if (content.length >= 1) {
+ content = content.substring(0, content.length-1)
+ trimTerminal(1)
+ }
+ } else if (event.key == "ArrowLeft") {
+ let cursor = getCursor()
+ if (cursor[0] > start_cursor_pos[0]) {
+ setCursor(cursor[0]-1, cursor[1])
+ pos -= 1
+ }
+ } else if (event.key == "ArrowRight") {
+ let cursor = getCursor()
+ if (cursor[0] < start_cursor_pos[0] + content.length) {
+ setCursor(cursor[0]+1, cursor[1])
+ pos += 1
+ }
+ } else {
+ let res = on_key(key, is_ctrl, is_alt, is_shift, content, pos)
+ terminal_text = terminal_text.slice(0, terminal_text.length - content.length) + res[0]
+ updateTerminal()
+ setCursor(start_cursor_pos[0] + res[1], start_cursor_pos[1])
+ content = res[0]
+ pos = res[1]
+ }
+
+ continue
+ } else if (event.type == "char") {
+ if (event.char == "\n") break
+
+ content = content.slice(0, pos) + event.char + content.slice(pos)
+ pos += 1
+ }
+ }
+
+ setStdinFlag(DISABLE_STDIN)
+
+ return content
+}
+
+async function pollStdinEvent() {
+ let char = await readStdin()
+
+ if (char == "\r") {
+ let key = ""
+ char = await readStdin()
+ while (char != "\r") {
+ key += char
+ char = await readStdin()
+ }
+
+ let is_ctrl = key.charAt(0) == "1"
+ let is_alt = key.charAt(1) == "1"
+ let is_shift = key.charAt(2) == "1"
+ key = key.slice(3)
+
+ return {
+ "type": "key",
+ "ctrl": is_ctrl,
+ "alt": is_alt,
+ "shift": is_shift,
+ "key": key
+ }
+ }
+
+ return {
+ "type": "char",
+ "char": char
+ }
+}
+
+async function readStdin() {
+ while (stdin.length == 0) {
+ await new Promise(resolve => setTimeout(resolve, 10))
+ }
+ let was_stdin = stdin.charAt(0)
+ stdin = stdin.slice(1)
+ return was_stdin
+}
+
+async function writeStdout(content) {
+ stdout += content
+ writeTerminal(content)
+}
+
+function setStdinFlag(flag) {
+ if (flag == 1) {
+ silent_stdin = true
+ } else if (flag == 2) {
+ silent_stdin = false
+ } else if (flag == 3) {
+ disable_stdin = true
+ } else if (flag == 4) {
+ disable_stdin = false
+ }
+}
+
+function executeCommand(args, read=readStdin, write=writeStdout) {
+ let id = new Date().getMilliseconds().toString()+(Math.random()*100)
+ let func_content = readFile(args[0])
+ if (func_content == null || !func_content.includes("function main")) return
+ let func = new Function("args", "readStdin", "writeStdout", func_content+"\n\nreturn main(args)")
+ let process = {
+ "id": id,
+ "name": args.join(" "),
+ "promise": new Promise((resolve, reject) => {
+ setTimeout(() => {
+ try {
+ resolve(func(args, read, write))
+ } catch (e) {
+ console.log(e)
+ reject(e)
+ }
+ }, 0)
+ }).then(o => {
+ processes = processes.filter(x => x.id != id)
+ return o
+ })
+ }
+ processes.push(process)
+ return process
+}
+
+function loadApp(name) {
+ fetch("app/"+name+".js")
+ .then(o => o.text())
+ .then(o => {
+ writeFile("/app/"+name+".js", o)
+ })
+}
+
+function loadAppAndExecute(name) {
+ fetch("app/"+name+".js")
+ .then(o => o.text())
+ .then(o => {
+ writeFile("/app/"+name+".js", o)
+ })
+}
+
+async function resetSystem() {
+ clearFileSystem()
+
+ createFolder("/")
+ createFolder("/home")
+ createFolder("/app")
+ createFolder("/config")
+ createFolder("/temp")
+ createFolder("/etc")
+
+ await installPackage("app/hello")
+ await installPackage("app/posh")
+ await installPackage("app/ppm")
+ await installPackage("app/putils")
+ await installPackage("app/reset")
+ await installPackage("app/vget")
+}
+
+if (Object.keys(fs_mapping).length == 0) {
+ resetSystem()
+}
+
+executeCommand(["/app/posh.js"])
+
+var start_date = new Date()
\ No newline at end of file
diff --git a/sys/terminal.js b/sys/terminal.js
new file mode 100644
index 0000000..cd30c88
--- /dev/null
+++ b/sys/terminal.js
@@ -0,0 +1,116 @@
+const CHAR_SIZE = [10, 22]
+const CURSOR_OFFSET = [10, 10]
+
+var terminal = document.getElementById("terminal")
+var terminal_text = ""
+var last_stdin_length = 0
+
+function writeTerminalAtCursor(content) {
+ let cursor_index = getCursorIndex()
+ terminal_text = terminal_text.slice(0, cursor_index) + content + terminal_text.slice(cursor_index)
+ setCursor(cursor_pos[0]+1, cursor_pos[1])
+ last_stdin_length += 1
+ updateTerminalWOCursor()
+}
+
+function writeTerminal(content) {
+ terminal_text += content
+ last_stdin_length = 0
+ updateTerminal()
+}
+
+function replaceTerminal(content) {
+ terminal_text = content
+ updateTerminal()
+}
+
+function trimTerminal(length) {
+ terminal_text = terminal_text.substring(0, terminal_text.length-length)
+ updateTerminal()
+}
+
+function clearTerminal() {
+ terminal_text = ""
+ updateTerminal()
+}
+
+function updateTerminalWOCursor() {
+ terminal.innerText = terminal_text
+}
+
+function updateTerminal() {
+ setCursor(
+ terminal_text.split("\n").reverse()[0].length,
+ terminal_text.split("\n").length-1
+ )
+ updateTerminalWOCursor()
+}
+
+var cursor = document.getElementById("cursor")
+var cursor_pos = [0, 0]
+
+function getCursorIndex() {
+ let lines = terminal_text.split("\n")
+ let index = 0
+ for (let y = 0; y < lines.length; y++) {
+ const line = lines[y];
+ const length = line.length
+
+ if (y == cursor_pos[1]) {
+ return index + cursor_pos[0]
+ }
+
+ index += length + 1
+ }
+ return 0
+}
+
+function getCursor() {
+ return cursor_pos
+}
+
+function setCursor(x, y) {
+ cursor_pos = [x, y]
+ updateCursor()
+}
+
+function updateCursor() {
+ cursor.style["top"] = cursor_pos[1] * CHAR_SIZE[1] + CURSOR_OFFSET[1] + "px"
+ cursor.style["left"] = cursor_pos[0] * CHAR_SIZE[0] + CURSOR_OFFSET[0] + "px"
+ cursor.scrollIntoView({behavior: "smooth", inline: "end"})
+}
+
+document.onkeydown = (e) => {
+ let key = e.key;
+ if (!disable_stdin) {
+ if (key == "Enter") {
+ stdin += "\n"
+ if (!silent_stdin) {
+ writeTerminal("\n")
+ }
+ } else if (key.length == 1) {
+ if (e.ctrlKey && key == "v") return
+ stdin += key
+ if (!silent_stdin) {
+ writeTerminalAtCursor(key)
+ }
+ } else {
+ stdin += "\r"+(e.ctrlKey ? "1" : "0")+(e.altKey ? "1" : "0")+(e.shiftKey ? "1" : "0")+e.key+"\r"
+ }
+ }
+}
+
+var clipboard_collect = document.getElementById("clipboard-collect")
+
+setInterval(() => {
+ clipboard_collect.focus()
+});
+
+clipboard_collect.onpaste = (e) => {
+ let paste = (e.clipboardData || window.clipboardData).getData("text");
+
+ if (paste != null) {
+ stdin += paste.replace("\r", "")
+ writeTerminal(paste)
+ }
+}
\ No newline at end of file