summaryrefslogtreecommitdiff
path: root/Components
diff options
context:
space:
mode:
authorMinteck <contact@minteck.org>2022-11-28 17:31:34 +0100
committerMinteck <contact@minteck.org>2022-11-28 17:31:34 +0100
commit7923aa8942b55884320ef2428417e3ee4b121613 (patch)
tree7993632f2898b1998f25b11ce40a8d2eb3d44730 /Components
downloadmistyos-og-7923aa8942b55884320ef2428417e3ee4b121613.tar.gz
mistyos-og-7923aa8942b55884320ef2428417e3ee4b121613.tar.bz2
mistyos-og-7923aa8942b55884320ef2428417e3ee4b121613.zip
Initial commitHEADmane
Diffstat (limited to 'Components')
-rw-r--r--Components/ChangeDir/index.js27
-rw-r--r--Components/ChangeDir/metadata.yml33
-rw-r--r--Components/Clear/index.js3
-rw-r--r--Components/Clear/metadata.yml20
-rw-r--r--Components/CoreDaemon/index.js352
-rw-r--r--Components/CoreDaemon/metadata.yml55
-rw-r--r--Components/CurrentDir/index.js3
-rw-r--r--Components/CurrentDir/metadata.yml20
-rw-r--r--Components/DisplayFile/hex.js44
-rw-r--r--Components/DisplayFile/index.js43
-rw-r--r--Components/DisplayFile/metadata.yml46
-rw-r--r--Components/Documentation/index.js129
-rw-r--r--Components/Documentation/metadata.yml30
-rw-r--r--Components/InternalShell/index.js14
-rw-r--r--Components/InternalShell/metadata.yml17
-rw-r--r--Components/ListDirectory/index.js85
-rw-r--r--Components/ListDirectory/metadata.yml40
-rw-r--r--Components/Restart/index.js11
-rw-r--r--Components/Restart/metadata.yml26
-rw-r--r--Components/ShowMisty/index.js30
-rw-r--r--Components/ShowMisty/metadata.yml22
-rw-r--r--Components/Shutdown/index.js11
-rw-r--r--Components/Shutdown/metadata.yml27
23 files changed, 1088 insertions, 0 deletions
diff --git a/Components/ChangeDir/index.js b/Components/ChangeDir/index.js
new file mode 100644
index 0000000..db9d82e
--- /dev/null
+++ b/Components/ChangeDir/index.js
@@ -0,0 +1,27 @@
+const fs = require('fs');
+const path = require('path');
+const chalk = require(__dirname + '/../../MistyCore/node_modules/chalk');
+
+module.exports = (arguments) => {
+ if (arguments._finals.length > 0) {
+ let newDirectory = path.resolve(arguments._finals[0]);
+
+ if (fs.existsSync(newDirectory)) {
+ try {
+ fs.accessSync(newDirectory, fs.constants.R_OK);
+
+ if (!fs.lstatSync(newDirectory).isDirectory()) {
+ console.log(chalk.bgYellow.white("<!>") + " " + chalk.yellow("Not a directory: ") + arguments['_finals'][0]);
+ } else {
+ process.chdir(newDirectory);
+ }
+ } catch (e) {
+ console.log(chalk.bgYellow.white("<!>") + " " + chalk.yellow("Permission denied: ") + arguments['_finals'][0]);
+ }
+ } else {
+ console.log(chalk.bgYellow.white("<!>") + " " + chalk.yellow("No such file or directory: ") + arguments['_finals'][0]);
+ }
+ } else {
+ console.log(chalk.bgYellow.white("<!>") + " " + chalk.yellow("Missing operand"));
+ }
+} \ No newline at end of file
diff --git a/Components/ChangeDir/metadata.yml b/Components/ChangeDir/metadata.yml
new file mode 100644
index 0000000..3818d75
--- /dev/null
+++ b/Components/ChangeDir/metadata.yml
@@ -0,0 +1,33 @@
+description: Changes the directory commands work from
+internal: true
+
+aliases:
+ - cd
+ - chdir
+ - chwd
+
+manual:
+ summary: |
+ This command changes the current working directory (CWD) for a specified directory.
+
+ parameters: []
+
+ final:
+ name: Dir
+ description: The directory to change to
+ required: true
+ multiple: false
+ command: false
+ path: true
+ daemon: false
+
+ examples:
+ - command: ChangeDir /
+ description: Changes directory to go to the system's root directory
+
+ - command: ChangeDir ..
+ description: Changes directory to go to the parent directory
+
+ compatibility:
+ mistyos: '>=1.0.0'
+ kernel: '>=5.10.0' \ No newline at end of file
diff --git a/Components/Clear/index.js b/Components/Clear/index.js
new file mode 100644
index 0000000..68c98ce
--- /dev/null
+++ b/Components/Clear/index.js
@@ -0,0 +1,3 @@
+module.exports = () => {
+ console.clear();
+} \ No newline at end of file
diff --git a/Components/Clear/metadata.yml b/Components/Clear/metadata.yml
new file mode 100644
index 0000000..fa28b6b
--- /dev/null
+++ b/Components/Clear/metadata.yml
@@ -0,0 +1,20 @@
+description: Clears the current screen
+internal: true
+
+aliases:
+ - cls
+ - clearscreen
+
+manual:
+ summary: |
+ This command clears the current screen.
+
+ parameters: []
+
+ final: null
+
+ examples: []
+
+ compatibility:
+ mistyos: '>=1.0.0'
+ kernel: '>=5.10.0' \ No newline at end of file
diff --git a/Components/CoreDaemon/index.js b/Components/CoreDaemon/index.js
new file mode 100644
index 0000000..5e830b8
--- /dev/null
+++ b/Components/CoreDaemon/index.js
@@ -0,0 +1,352 @@
+let arguments = JSON.parse(process.argv[2]);
+const chalk = require(__dirname + '/../../MistyCore/node_modules/chalk');
+const YAML = require(__dirname + '/../../MistyCore/node_modules/yaml');
+const si = require(__dirname + '/../../MistyCore/node_modules/systeminformation');
+const fs = require('fs');
+const net = require("net");
+let systemRoot = "/System/Library";
+
+function size(bytes) {
+ if (bytes > 1024) {
+ if (bytes > 1024**2) {
+ if (bytes > 1024**3) {
+ if (bytes > 1024**4) {
+ return (bytes / 1024**4).toFixed(2) + "T";
+ } else {
+ return (bytes / 1024**3).toFixed(2) + "G";
+ }
+ } else {
+ return (bytes / 1024**2).toFixed(2) + "M";
+ }
+ } else {
+ return (bytes / 1024).toFixed(2) + "K";
+ }
+ } else {
+ return bytes + "B";
+ }
+}
+
+function waitForState(daemon, status) {
+ return new Promise((resolve) => {
+ let i = 0;
+ let me = setInterval(() => {
+ if (status === "running") {
+ if (fs.readFileSync(systemRoot + "/../Volumes/VM/LaunchDaemons/" + daemon).toString().trim() !== "-1" && fs.readFileSync(systemRoot + "/../Volumes/VM/LaunchDaemons/" + daemon).toString().trim() !== "-3" && fs.readFileSync(systemRoot + "/../Volumes/VM/LaunchDaemons/" + daemon).toString().trim() !== "-2") {
+ clearInterval(me);
+
+ if (fs.readFileSync(systemRoot + "/../Volumes/VM/LaunchDaemons/" + daemon).toString().trim() !== "0") {
+ console.log(daemon + " is now running with PID " + fs.readFileSync(systemRoot + "/../Volumes/VM/LaunchDaemons/" + daemon).toString().trim());
+ } else if (fs.readFileSync(systemRoot + "/../Volumes/VM/LaunchDaemons/" + daemon).toString().trim() !== "-2") {
+ console.log(daemon + " has failed\nRun 'CoreDaemon -Status " + daemon + "' for details; 'CoreDaemon -ForceStop " + daemon + "' to force stop.");
+ process.exit(2);
+ } else {
+ console.log(daemon + " has now started");
+ }
+
+ resolve();
+ }
+ } else if (status === "stopped") {
+ if (fs.readFileSync(systemRoot + "/../Volumes/VM/LaunchDaemons/" + daemon).toString().trim() === "-1") {
+ clearInterval(me);
+ console.log(daemon + " is now stopped");
+ resolve();
+ }
+ if (fs.readFileSync(systemRoot + "/../Volumes/VM/LaunchDaemons/" + daemon).toString().trim() === "-2") {
+ clearInterval(me);
+ console.log(daemon + " has failed\nRun 'CoreDaemon -Status " + daemon + "' for details; 'CoreDaemon -ForceStop " + daemon + "' to force stop.");
+ process.exit(2);
+ resolve();
+ }
+ } else {
+ clearInterval(me);
+ resolve();
+ }
+
+ if (i >= 100) {
+ console.log("Timed out waiting for " + daemon + " after 10 seconds. Has the launch daemon failed?\nRun 'CoreDaemon -Status " + daemon + "' for details; 'CoreDaemon -ForceStop " + daemon + "' to force stop.");
+ process.exit(2);
+ }
+
+ i++;
+ }, 100);
+ });
+}
+
+(async () => {
+ let processes = (await si.processes()).list;
+
+ if (arguments['start'] && !arguments['stop'] && !arguments['restart'] && !arguments['status'] && !arguments['forcestop']) {
+ if (arguments['_finals'].length > 0) {
+ if (!fs.existsSync(systemRoot + "/../Volumes/VM/LaunchDaemons/" + arguments['_finals'][0])) {
+ console.log(chalk.bgYellow.white("<!>") + " " + chalk.yellow("No such launch daemon: ") + arguments['_finals'][0]);
+ return;
+ }
+
+ let state; switch (fs.readFileSync(systemRoot + "/../Volumes/VM/LaunchDaemons/" + arguments['_finals'][0]).toString()) { case "0": state = "running"; break; case "-1": state = "stopped"; break; case "-2": state = "failed"; break; default: state = "running"; break }
+
+ if (state === "running") {
+ console.log(chalk.bgYellow.white("<!>") + " " + chalk.yellow("The launch daemon is not stopped or failed"));
+ return;
+ }
+
+ const socket = net.createConnection(systemRoot + "/../Volumes/VM/MistyCore-Socket", () => {
+ console.log("Waiting for " + arguments['_finals'][0] + " to have started...");
+ socket.write(JSON.stringify({
+ action: "SERVICE",
+ payload: {
+ option: "start",
+ service: arguments['_finals'][0] + ".yml"
+ }
+ }));
+ waitForState(arguments['_finals'][0], "running");
+ });
+ } else {
+ console.log(chalk.bgYellow.white("<!>") + " " + chalk.yellow("Missing operand"));
+ }
+ } else if (arguments['stop'] && !arguments['start'] && !arguments['restart'] && !arguments['status'] && !arguments['forcestop']) {
+ if (arguments['_finals'].length > 0) {
+ if (!fs.existsSync(systemRoot + "/../Volumes/VM/LaunchDaemons/" + arguments['_finals'][0])) {
+ console.log(chalk.bgYellow.white("<!>") + " " + chalk.yellow("No such launch daemon: ") + arguments['_finals'][0]);
+ return;
+ }
+
+ let state; switch (fs.readFileSync(systemRoot + "/../Volumes/VM/LaunchDaemons/" + arguments['_finals'][0]).toString()) { case "0": state = "running"; break; case "-1": state = "stopped"; break; case "-2": state = "failed"; break; default: state = "running"; break }
+
+ if (state !== "running") {
+ console.log(chalk.bgYellow.white("<!>") + " " + chalk.yellow("The launch daemon is not running"));
+ return;
+ }
+
+ const socket = net.createConnection(systemRoot + "/../Volumes/VM/MistyCore-Socket", async () => {
+ console.log("Waiting for " + arguments['_finals'][0] + " to have stopped...");
+ socket.write(JSON.stringify({
+ action: "SERVICE",
+ payload: {
+ option: "stop",
+ service: arguments['_finals'][0] + ".yml"
+ }
+ }));
+ await waitForState(arguments['_finals'][0], "stopped");
+ });
+ } else {
+ console.log(chalk.bgYellow.white("<!>") + " " + chalk.yellow("Missing operand"));
+ }
+ } else if (arguments['forcestop'] && !arguments['start'] && !arguments['restart'] && !arguments['status'] && !arguments['stop']) {
+ if (arguments['_finals'].length > 0) {
+ if (!fs.existsSync(systemRoot + "/../Volumes/VM/LaunchDaemons/" + arguments['_finals'][0])) {
+ console.log(chalk.bgYellow.white("<!>") + " " + chalk.yellow("No such launch daemon: ") + arguments['_finals'][0]);
+ return;
+ }
+
+ let state; switch (fs.readFileSync(systemRoot + "/../Volumes/VM/LaunchDaemons/" + arguments['_finals'][0]).toString()) { case "0": state = "running"; break; case "-1": state = "stopped"; break; case "-2": state = "failed"; break; default: state = "running"; break }
+
+ if (state !== "running") {
+ console.log(chalk.bgYellow.white("<!>") + " " + chalk.yellow("The launch daemon is not running"));
+ return;
+ }
+
+ const socket = net.createConnection(systemRoot + "/../Volumes/VM/MistyCore-Socket", async () => {
+ console.log("Waiting for " + arguments['_finals'][0] + " to have force-stopped...");
+ socket.write(JSON.stringify({
+ action: "SERVICE",
+ payload: {
+ option: "forcestop",
+ service: arguments['_finals'][0] + ".yml"
+ }
+ }));
+ await waitForState(arguments['_finals'][0], "stopped");
+ });
+ } else {
+ console.log(chalk.bgYellow.white("<!>") + " " + chalk.yellow("Missing operand"));
+ }
+ } else if (arguments['restart'] && !arguments['stop'] && !arguments['start'] && !arguments['status'] && !arguments['forcestop']) {
+ if (arguments['_finals'].length > 0) {
+ if (!fs.existsSync(systemRoot + "/../Volumes/VM/LaunchDaemons/" + arguments['_finals'][0])) {
+ console.log(chalk.bgYellow.white("<!>") + " " + chalk.yellow("No such launch daemon: ") + arguments['_finals'][0]);
+ return;
+ }
+
+ let state; switch (fs.readFileSync(systemRoot + "/../Volumes/VM/LaunchDaemons/" + arguments['_finals'][0]).toString()) { case "0": state = "running"; break; case "-1": state = "stopped"; break; case "-2": state = "failed"; break; default: state = "running"; break }
+
+ if (state !== "running") {
+ console.log(chalk.bgYellow.white("<!>") + " " + chalk.yellow("The launch daemon is not running"));
+ return;
+ }
+
+ const socket = net.createConnection(systemRoot + "/../Volumes/VM/MistyCore-Socket", async () => {
+ console.log("Waiting for " + arguments['_finals'][0] + " to have restarted...");
+ socket.write(JSON.stringify({
+ action: "SERVICE",
+ payload: {
+ option: "restart",
+ service: arguments['_finals'][0] + ".yml"
+ }
+ }));
+ await waitForState(arguments['_finals'][0], "running");
+ });
+ } else {
+ console.log(chalk.bgYellow.white("<!>") + " " + chalk.yellow("Missing operand"));
+ }
+ } else if (arguments['status'] && !arguments['stop'] && !arguments['restart'] && !arguments['start'] && !arguments['forcestop']) {
+ if (arguments['_finals'].length > 0) {
+ if (!fs.existsSync(systemRoot + "/../Volumes/VM/LaunchDaemons/" + arguments['_finals'][0])) {
+ console.log(chalk.bgYellow.white("<!>") + " " + chalk.yellow("No such launch daemon: ") + arguments['_finals'][0]);
+ return;
+ }
+
+ let state; switch (fs.readFileSync(systemRoot + "/../Volumes/VM/LaunchDaemons/" + arguments['_finals'][0]).toString()) { case "0": state = "running"; break; case "-1": state = "stopped"; break; case "-3": state = "starting"; break; case "-2": state = "failed"; break; default: state = "running"; break }
+
+ let name = arguments['_finals'][0], displayName = arguments['_finals'][0];
+ let service = YAML.parse(fs.readFileSync(systemRoot + "/LaunchDaemons/" + name + ".yml").toString());
+
+ let memoryUsage;
+ let pid;
+ let parent = "-";
+
+ switch (fs.readFileSync(systemRoot + "/../Volumes/VM/LaunchDaemons/" + arguments['_finals'][0]).toString()) {
+ case "0":
+ case "-1":
+ case "-2":
+ case "-3":
+ memoryUsage = "-";
+ pid = "-";
+ break;
+
+ default:
+ let _processInfo = processes.filter(i => i.pid === parseInt(fs.readFileSync(systemRoot + "/../Volumes/VM/LaunchDaemons/" + arguments['_finals'][0]).toString()));
+
+ if (_processInfo.length > 0) {
+ pid = fs.readFileSync(systemRoot + "/../Volumes/VM/LaunchDaemons/" + arguments['_finals'][0]).toString() + " (" + _processInfo[0].name + ")";
+
+ let _parentInfo = processes.filter(i => i.pid === _processInfo[0].parentPid);
+ if (_parentInfo.length > 0) {
+ parent = _processInfo[0].parentPid + " (" + _parentInfo[0].name + ")";
+ } else {
+ parent = _processInfo[0].parentPid;
+ }
+
+ memoryUsage = size(_processInfo[0].memVsz);
+ } else {
+ pid = fs.readFileSync(systemRoot + "/../Volumes/VM/LaunchDaemons/" + arguments['_finals'][0]).toString();
+ memoryUsage = "-";
+ }
+
+ break;
+ }
+
+ let statusColor;
+
+ switch (state) {
+ case "running":
+ statusColor = chalk.green("running");
+ break;
+
+ case "starting":
+ statusColor = chalk.yellow("starting");
+ break;
+
+ case "failed":
+ statusColor = chalk.cyan("failed");
+ break;
+
+ case "stopped":
+ statusColor = chalk.red("stopped");
+ break;
+
+ default:
+ statusColor = chalk.gray("unknown");
+ break;
+ }
+
+ let reachDate = "-";
+
+ if (fs.existsSync(systemRoot + "/../Volumes/VM/LaunchDaemonsTimes/" + arguments['_finals'][0])) {
+ reachDate = new Date(parseInt(fs.readFileSync(systemRoot + "/../Volumes/VM/LaunchDaemonsTimes/" + arguments['_finals'][0]).toString())).toString();
+ }
+
+ let autoStart;
+ if (service.metadata.target === false) {
+ autoStart = chalk.gray("manual");
+ } else {
+ if (!isNaN(parseInt(service.metadata.target)) && parseInt(service.metadata.target) > -1 && parseInt(service.metadata.target) < 10) {
+ autoStart = "on target " + parseInt(service.metadata.target);
+ } else {
+ autoStart = chalk.red("invalid");
+ }
+ }
+
+ console.log(name + " - " + (service.metadata.description ?? "<no description>"));
+ console.log(chalk.cyan(" Loaded from:") + " " + systemRoot + "/LaunchDaemons/" + name + ".yml");
+ console.log(chalk.cyan(" Auto-start:") + " " + autoStart);
+ console.log(chalk.cyan(" Status:") + " " + statusColor);
+ console.log(chalk.cyan(" Reached:") + " " + reachDate);
+ console.log(chalk.cyan(" Main PID:") + " " + pid);
+ console.log(chalk.cyan(" Initiator:") + " " + parent);
+ console.log(chalk.cyan(" Memory:") + " " + memoryUsage);
+
+ if (service.commands.stop || service.commands.restart) {
+ console.log(chalk.cyan(" Type:") + " MistyCore:RunOnce");
+ } else {
+ console.log(chalk.cyan(" Type:") + " MistyCore:Daemon");
+ }
+
+ console.log("");
+
+ switch (state) {
+ case "running":
+ console.log("Run 'Logger -Unit " + name + "' to view logs; 'CoreDaemon -Stop " + name + "' to stop.");
+ break;
+
+ case "starting":
+ console.log("Run 'Logger -Unit " + name + "' to view logs; 'CoreDaemon -ForceStop " + name + "' to abort.");
+ break;
+
+ case "failed":
+ console.log("Run 'Logger -Unit " + name + "' to view logs; 'CoreDaemon -Start " + name + "' to start.");
+ break;
+
+ case "stopped":
+ console.log("Run 'Logger -Unit " + name + "' to view logs; 'CoreDaemon -Start " + name + "' to start.");
+ break;
+
+ default:
+ console.log("Run 'Logger -Unit " + name + "' to view logs");
+ break;
+ }
+ } else {
+ for (let name of fs.readdirSync(systemRoot + "/LaunchDaemons")) {
+ let daemon = name.substring(0, name.length - 4);
+
+ if (fs.existsSync(systemRoot + "/../Volumes/VM/LaunchDaemons/" + daemon)) {
+ let state; switch (fs.readFileSync(systemRoot + "/../Volumes/VM/LaunchDaemons/" + daemon).toString()) { case "0": state = "running"; break; case "-1": state = "stopped"; break; case "-3": state = "starting"; break; case "-2": state = "failed"; break; default: state = "running"; break }
+
+ switch (state) {
+ case "running":
+ console.log(" [ " + chalk.green("+") + " ] " + daemon);
+ break;
+
+ case "starting":
+ console.log(" [ " + chalk.yellow("W") + " ] " + daemon);
+ break;
+
+ case "failed":
+ console.log(" [ " + chalk.cyan("x") + " ] " + daemon);
+ break;
+
+ case "stopped":
+ console.log(" [ " + chalk.red("-") + " ] " + daemon);
+ break;
+
+ default:
+ console.log(" [ " + chalk.gray("?") + " ] " + daemon);
+ break;
+ }
+ } else {
+ console.log(" [ " + chalk.gray("?") + " ] " + daemon);
+ }
+ }
+ }
+ } else {
+ console.log(chalk.bgYellow.white("<!>") + " " + chalk.yellow("Only exactly one operation can be done at a time"));
+ }
+})(); \ No newline at end of file
diff --git a/Components/CoreDaemon/metadata.yml b/Components/CoreDaemon/metadata.yml
new file mode 100644
index 0000000..7cea718
--- /dev/null
+++ b/Components/CoreDaemon/metadata.yml
@@ -0,0 +1,55 @@
+description: Manages launch daemons running on the system
+internal: false
+
+aliases:
+ - service
+ - systemctl
+ - rc-service
+
+manual:
+ summary: |
+ This command starts, stops, gets the status and restarts launch daemons on the system.
+
+ parameters:
+ - name: Start
+ description: Start a launch daemon
+ required: false
+
+ - name: Stop
+ description: Stop a launch daemon
+ required: false
+
+ - name: ForceStop
+ description: Force-stop a launch daemon, having it exit immediately without finishing properly
+ required: false
+
+ - name: Restart
+ description: Restart a launch daemon
+ required: false
+
+ - name: Status
+ description: Show the status of a launch daemon
+ required: false
+
+ final:
+ name: LaunchDaemon
+ description: The launch daemon to manage
+ required: false
+ multiple: false
+ command: false
+ path: false
+ daemon: true
+
+ examples:
+ - command: CoreDaemon -Restart Something
+ description: Restarts the launch daemon named Something
+
+ - command: CoreDaemon -ForceStop HangingThing
+ description: Forces the launch daemon named HangingThing to stop
+
+ - command: CoreDaemon -Status
+ description: Shows the status of all launch daemons on the system
+
+ compatibility:
+ mistyos: '>=1.2.0'
+ kernel: '>=5.10.0' \ No newline at end of file
diff --git a/Components/CurrentDir/index.js b/Components/CurrentDir/index.js
new file mode 100644
index 0000000..9d954fc
--- /dev/null
+++ b/Components/CurrentDir/index.js
@@ -0,0 +1,3 @@
+module.exports = () => {
+ console.log(process.cwd());
+} \ No newline at end of file
diff --git a/Components/CurrentDir/metadata.yml b/Components/CurrentDir/metadata.yml
new file mode 100644
index 0000000..a8f5a32
--- /dev/null
+++ b/Components/CurrentDir/metadata.yml
@@ -0,0 +1,20 @@
+description: Returns the name of the current working directory
+internal: true
+
+aliases:
+ - pwd
+ - cwd
+
+manual:
+ summary: |
+ This command returns the current working directory (CWD) commands run from.
+
+ parameters: []
+
+ final: null
+
+ examples: []
+
+ compatibility:
+ mistyos: '>=1.0.0'
+ kernel: '>=5.10.0' \ No newline at end of file
diff --git a/Components/DisplayFile/hex.js b/Components/DisplayFile/hex.js
new file mode 100644
index 0000000..f062608
--- /dev/null
+++ b/Components/DisplayFile/hex.js
@@ -0,0 +1,44 @@
+const chalk = require(__dirname + '/../../MistyCore/node_modules/chalk');
+
+function hexEight(dec) {
+ let hex = Math.round(dec).toString(16);
+ let zero = "00000000";
+ return zero.substring(0, 8 - hex.length) + hex;
+}
+
+function fixLength(string, length) {
+ let end = " ".repeat(length);
+ if (string.length > length) return string.substring(0, length);
+
+ return string + end.substring(0, length - string.length);
+}
+
+module.exports = (buffer, color) => {
+ let ret = "";
+ let lines = buffer.toString("hex").match(/.{1,32}/g).map(i => i.match(/.{1,2}/g).join(" "));
+
+ let byte = 0;
+ for (let line of lines) {
+ if (color) {
+ ret += chalk.gray(hexEight(byte)) + " " + fixLength(line, 47).split(" ").map((i, _) => {
+ if ((_ + 1) % 2 === 1) {
+ return chalk.red(i);
+ } else {
+ return chalk.magenta(i);
+ }
+ }).join(" ") + " " + chalk.blue(Buffer.from(line.replaceAll(" ", ""), "hex").toString().replace(/[\x00-\x1F]/gm, chalk.gray("."))) + "\n";
+ } else {
+ ret += hexEight(byte) + " " + fixLength(line, 47) + " " + Buffer.from(line.replaceAll(" ", ""), "hex").toString().replace(/[\x00-\x1F]/gm, ".") + "\n";
+ }
+
+ byte += line.replaceAll(" ", "").length / 2;
+ }
+
+ if (color) {
+ ret += chalk.gray(hexEight(byte));
+ } else {
+ ret += hexEight(byte);
+ }
+
+ return ret;
+} \ No newline at end of file
diff --git a/Components/DisplayFile/index.js b/Components/DisplayFile/index.js
new file mode 100644
index 0000000..c6b3f25
--- /dev/null
+++ b/Components/DisplayFile/index.js
@@ -0,0 +1,43 @@
+let arguments = JSON.parse(process.argv[2]);
+const chalk = require(__dirname + '/../../MistyCore/node_modules/chalk');
+const fs = require("fs");
+const child_process = require("child_process");
+
+if (arguments._finals.length > 0) {
+ for (let file of arguments._finals) {
+ if (fs.existsSync(file)) {
+ try {
+ fs.accessSync(file, fs.constants.R_OK);
+
+ if (arguments['hex']) {
+ fs.writeFileSync("/System/Volumes/VM/HexDump", require('./hex')(fs.readFileSync(file), !arguments['pagination']));
+ file = "/System/Volumes/VM/HexDump";
+ }
+
+ if (fs.lstatSync(file).isDirectory()) {
+ console.log(chalk.bgYellow.white("<!>") + " " + chalk.yellow("Is a directory: ") + file);
+ } else {
+ if (arguments['pagination']) {
+ console.clear();
+ child_process.execFileSync("/System/Binaries/busybox", [ "less", "-~", "-S", "--", file ], { stdio: "inherit" });
+ console.clear();
+ } else {
+ if (arguments['search']) {
+ console.log(chalk.white(fs.readFileSync(file).toString().replace(arguments['search'], chalk.bold.red(arguments['search']))));
+ } else {
+ console.log(chalk.white(fs.readFileSync(file).toString()));
+ }
+ }
+ }
+
+ if (fs.existsSync("/System/Volumes/VM/HexDump")) fs.unlinkSync("/System/Volumes/VM/HexDump");
+ } catch (e) {
+ console.log(chalk.bgYellow.white("<!>") + " " + chalk.yellow("Permission denied: ") + file);
+ }
+ } else {
+ console.log(chalk.bgYellow.white("<!>") + " " + chalk.yellow("No such file or directory: ") + file);
+ }
+ }
+} else {
+ console.log(chalk.bgYellow.white("<!>") + " " + chalk.yellow("Missing operand"));
+} \ No newline at end of file
diff --git a/Components/DisplayFile/metadata.yml b/Components/DisplayFile/metadata.yml
new file mode 100644
index 0000000..e05d233
--- /dev/null
+++ b/Components/DisplayFile/metadata.yml
@@ -0,0 +1,46 @@
+description: Displays one or multiple file(s) in the terminal
+internal: false
+
+aliases:
+ - cat
+ - type
+ - more
+ - less
+
+manual:
+ summary: |
+ This command displays one or multiple file(s) in the terminal.
+
+ parameters:
+ - name: Pagination
+ description: Enable pagination (scrolling)
+ required: false
+
+ - name: Hex
+ description: Display an hexadecimal dump of the file instead of the contents of the file itself
+ required: false
+
+ - name: Search
+ value: Query
+ description: Search for text in the file(s); does not work with -Pagination
+ required: false
+
+ final:
+ name: File
+ description: The file(s) to display
+ required: true
+ multiple: true
+ command: false
+ path: true
+ daemon: false
+
+ examples:
+ - command: DisplayFile /User/Document.txt
+ description: Display the "Document.txt" file
+
+ - command: DisplayFile -Pagination /User/Essay.txt
+ description: Display the "Essay.txt" file with pagination
+
+ compatibility:
+ mistyos: '>=1.0.0'
+ kernel: '>=5.10.0' \ No newline at end of file
diff --git a/Components/Documentation/index.js b/Components/Documentation/index.js
new file mode 100644
index 0000000..1b0e132
--- /dev/null
+++ b/Components/Documentation/index.js
@@ -0,0 +1,129 @@
+const fs = require('fs');
+const path = require('path');
+const chalk = require(__dirname + '/../../MistyCore/node_modules/chalk');
+const child_process = require("child_process");
+const semver = require(__dirname + '/../../MistyCore/node_modules/semver');
+
+function prettyVersion(version) {
+ return version.replace(/^\*$/gm, "<all versions>").replace(/^>=(| *)(\d+\.\d+\.\d+)$/gm, "$2 and later").replace(/^=(| *)(\d+\.\d+\.\d+)$/gm, "$2").replace(/^(\d+\.\d+\.\d+)(| +)-(| +)(\d+\.\d+\.\d+)$/gm, "$1 to $4");
+}
+
+module.exports = (arguments) => {
+ if (arguments['_finals'].length === 0) {
+ console.log(chalk.bgYellow.white("<!>") + " " + chalk.yellow("Missing operand"));
+ return;
+ }
+
+ let input = arguments['_finals'][0];
+ let command = null;
+
+ let commands = global.commands;
+ let commandsMetadata = global.commandsMetadata;
+
+ for (let cmd of commands) {
+ if (cmd.toLowerCase() === input.toLowerCase()) {
+ command = cmd;
+ break;
+ }
+
+ let metadata = commandsMetadata[commands.indexOf(cmd)];
+ if (metadata['aliases'].map(i => i.toLowerCase()).includes(input.toLowerCase())) {
+ command = cmd;
+ break;
+ }
+ }
+
+ let metadata = commandsMetadata[commands.indexOf(command)];
+ if (!command) {
+ console.log(chalk.bgRed.white("<!>") + " " + chalk.red("Command not found: ") + input);
+ } else {
+ let out = chalk.reset("") + "\n";
+ let pack = "*";
+
+ out += chalk.red(" ╔" + "═".repeat(command.length + 2) + "╗\n ║ " + command + " ║\n " + "╚" + "═".repeat(command.length + 2) + "╝") + "\n\n";
+
+ out += chalk.magenta(" Name\n ----") + "\n";
+ out += chalk.whiteBright(" " + command + " - " + metadata.description) + "\n\n";
+
+ out += chalk.magenta(" Synopsis\n --------") + "\n";
+ out += chalk.whiteBright(" " + chalk.green(command));
+
+ for (let param of metadata['manual']['parameters']) {
+ out += " ";
+
+ if (!param.required) out += "[";
+ if (param.value) {
+ out += chalk.cyan("-" + param.name) + chalk.magenta(chalk.bgGray("=") + param.value);
+ } else {
+ out += chalk.magenta("-" + param.name);
+ }
+ if (!param.required) out += "]";
+ }
+
+ if (metadata['manual']['final']) {
+ out += " ";
+
+ if (!metadata['manual']['final'].required) out += "[";
+
+ if (metadata['manual']['final']['command']) {
+ out += chalk.yellow(metadata['manual']['final'].name);
+ } else {
+ out += metadata['manual']['final'].name;
+ }
+
+ if (metadata['manual']['final'].multiple) out += " ...";
+ if (!metadata['manual']['final'].required) out += "]";
+ }
+
+ out += "\n";
+
+ for (let alias of metadata.aliases) {
+ out += chalk.whiteBright(" " + chalk.green(alias) + chalk.gray(" (-> " + command + ")") + "\n");
+ }
+
+ if (metadata['manual']['summary'] || metadata['manual']['parameters'].length > 0) {
+ out += chalk.magenta("\n Description\n -----------") + "\n";
+ if (metadata['manual']['summary']) {
+ out += " " + metadata['manual']['summary'].trim();
+ for (let param of metadata['manual']['parameters']) {
+ out += "\n\n ";
+
+ if (param.value) {
+ out += chalk.cyan("-" + param.name) + chalk.magenta(chalk.bgGray("=") + param.value);
+ } else {
+ out += chalk.magenta("-" + param.name);
+ }
+
+ out += "\n " + param.description ?? "<no description>";
+ }
+
+ if (metadata['manual']['final']) {
+ out += "\n\n ";
+
+ if (metadata['manual']['final']['command']) {
+ out += chalk.yellow(metadata['manual']['final'].name);
+ } else {
+ out += metadata['manual']['final'].name;
+ }
+
+ if (metadata['manual']['final'].multiple) out += " ...";
+ out += "\n " + metadata['manual']['final'].description ?? "<no description>";
+ }
+ }
+ }
+
+ if (metadata['manual']['examples']) {
+ out += chalk.magenta("\n\n Examples\n --------") + "\n";
+
+ for (let example of metadata['manual']['examples']) {
+ out += " " + example.description + "\n " + chalk.blue("> ") + example.command + "\n";
+ }
+ }
+
+ out += chalk.magenta("\n\n Compatibility\n -------------") + "\n";
+ out += " MistyOS: " + prettyVersion(metadata['manual']['compatibility']['mistyos']) + "\n";
+ out += " Kernel: " + prettyVersion(metadata['manual']['compatibility']['kernel']);
+
+ console.log("\n" + out.trim() + "\n");
+ }
+} \ No newline at end of file
diff --git a/Components/Documentation/metadata.yml b/Components/Documentation/metadata.yml
new file mode 100644
index 0000000..799f509
--- /dev/null
+++ b/Components/Documentation/metadata.yml
@@ -0,0 +1,30 @@
+description: Shows documentation about a command
+internal: true
+
+aliases:
+ - man
+ - help
+ - docs
+
+manual:
+ summary: |
+ This command shows documentation about another command, including how to use it.
+
+ parameters: []
+
+ final:
+ name: Command
+ description: The command to get help for
+ required: true
+ multiple: false
+ command: true
+ path: false
+ daemon: false
+
+ examples:
+ - command: Documentation ChangeDir
+ description: Shows documentation for the ChangeDir command
+
+ compatibility:
+ mistyos: '>=1.0.0'
+ kernel: '>=5.10.0' \ No newline at end of file
diff --git a/Components/InternalShell/index.js b/Components/InternalShell/index.js
new file mode 100644
index 0000000..682da6e
--- /dev/null
+++ b/Components/InternalShell/index.js
@@ -0,0 +1,14 @@
+const child_process = require("child_process");
+global.log = require('../../MistyCore/log');
+
+module.exports = (arguments) => {
+ let args = [];
+
+ if (arguments['_finals'].length > 0) {
+ args = [ "-c", arguments['_finals'].join(" ") ];
+ }
+
+ log("Shell-InternalShell", "Starting internal shell");
+ child_process.execFileSync("/System/Binaries/sh", args, { stdio: "inherit" });
+ log("Shell-InternalShell", "Stopped internal shell");
+} \ No newline at end of file
diff --git a/Components/InternalShell/metadata.yml b/Components/InternalShell/metadata.yml
new file mode 100644
index 0000000..d196032
--- /dev/null
+++ b/Components/InternalShell/metadata.yml
@@ -0,0 +1,17 @@
+description: Internal shell
+internal: true
+
+aliases: []
+
+manual:
+ summary: ""
+
+ parameters: []
+
+ final: null
+
+ examples: []
+
+ compatibility:
+ mistyos: '>=1.0.0'
+ kernel: '>=5.10.0'
diff --git a/Components/ListDirectory/index.js b/Components/ListDirectory/index.js
new file mode 100644
index 0000000..a7fa45b
--- /dev/null
+++ b/Components/ListDirectory/index.js
@@ -0,0 +1,85 @@
+let arguments = JSON.parse(process.argv[2]);
+const chalk = require(__dirname + '/../../MistyCore/node_modules/chalk');
+const fs = require("fs");
+const path = require('path');
+
+let list = [];
+
+function processList(list, dir, arguments) {
+ if (!Object.keys(arguments).includes("all") && dir === "/") {
+ list = list.filter(i => i !== "dev" && i !== "etc" && i !== "bin" && i !== "lib" && i !== "lib64" && i !== "lost+found" && i !== "proc" && i !== "run" && i !== "sys" && i !== "MistyOSPrivate");
+ } else if (!Object.keys(arguments).includes("All") &&dir === "/User") {
+ list = list.filter(i => i !== "Library");
+ }
+
+ if (Object.keys(arguments).includes("all")) list.unshift(".", "..");
+ if (Object.keys(arguments).includes("search")) list = list.filter(i => i.includes(arguments["search"]));
+
+ if (!Object.keys(arguments).includes("all")) list = list.filter(i => !i.startsWith("."));
+ return list.map((i) => {
+ if (fs.existsSync(dir + "/" + i)) {
+ try {
+ fs.accessSync(dir + "/" + i, fs.constants.R_OK);
+
+ if (fs.lstatSync(dir + "/" + i).isDirectory()) {
+ return i + chalk.gray("/");
+ } else if (fs.lstatSync(dir + "/" + i).isSymbolicLink()) {
+ return i + chalk.gray(">");
+ } else {
+ return i;
+ }
+ } catch (e) {
+ return i + chalk.gray("?");
+ }
+ } else {
+ return i + chalk.gray("x");
+ }
+ });
+}
+
+if (arguments._finals.length > 0) {
+ if (arguments._finals.length === 1) {
+ if (fs.existsSync(arguments._finals[0])) {
+ try {
+ fs.accessSync(arguments._finals[0], fs.constants.R_OK);
+
+ if (!fs.lstatSync(arguments._finals[0]).isDirectory()) {
+ console.log(chalk.bgYellow.white("<!>") + " " + chalk.yellow("Not a directory: ") + arguments._finals[0]);
+ } else {
+ list = require('fs').readdirSync(arguments._finals[0]);
+ list = processList(list, path.resolve(arguments['_finals'][0]), arguments);
+ console.log(list.join(chalk.gray(", ")));
+ }
+ } catch (e) {
+ console.log(chalk.bgYellow.white("<!>") + " " + chalk.yellow("Permission denied: ") + arguments._finals[0]);
+ }
+ } else {
+ console.log(chalk.bgYellow.white("<!>") + " " + chalk.yellow("No such file or directory: ") + arguments._finals[0]);
+ }
+ } else {
+ for (let final of arguments._finals) {
+ console.log(final + ":");
+ if (fs.existsSync(final)) {
+ try {
+ fs.accessSync(final, fs.constants.R_OK);
+
+ if (!fs.lstatSync(final).isDirectory()) {
+ console.log(" " + chalk.bgYellow.white("<!>") + " " + chalk.yellow("Not a directory: ") + final);
+ } else {
+ list = require('fs').readdirSync(final);
+ list = processList(list, path.resolve(final), arguments);
+ console.log(" " + list.join(chalk.gray(", ")));
+ }
+ } catch (e) {
+ console.log(" " + chalk.bgYellow.white("<!>") + " " + chalk.yellow("Permission denied: ") + final);
+ }
+ } else {
+ console.log(" " + chalk.bgYellow.white("<!>") + " " + chalk.yellow("No such file or directory: ") + final);
+ }
+ }
+ }
+} else {
+ list = require('fs').readdirSync(".");
+ list = processList(list, path.resolve("."), arguments);
+ console.log(list.join(chalk.gray(", ")));
+} \ No newline at end of file
diff --git a/Components/ListDirectory/metadata.yml b/Components/ListDirectory/metadata.yml
new file mode 100644
index 0000000..431c999
--- /dev/null
+++ b/Components/ListDirectory/metadata.yml
@@ -0,0 +1,40 @@
+description: Lists files in the current or a select directory
+internal: false
+
+aliases:
+ - ls
+ - dir
+
+manual:
+ summary: |
+ This command lists all files that exist in the specific directory, or the current working directory if not specified.
+
+ parameters:
+ - name: All
+ description: Show hidden files (starting with . or system files)
+ required: false
+
+ - name: Search
+ value: Query
+ description: Search for a specific file containing the query
+ required: false
+
+ final:
+ name: Dir
+ description: The directory or directories to list files of
+ required: false
+ multiple: true
+ command: false
+ path: true
+ daemon: false
+
+ examples:
+ - command: ListDirectory -All
+ description: List all the files in the current directory, including hidden files
+
+ - command: ListDirectory /
+ description: List all the files in the root directory
+
+ compatibility:
+ mistyos: '>=1.0.0'
+ kernel: '>=5.10.0' \ No newline at end of file
diff --git a/Components/Restart/index.js b/Components/Restart/index.js
new file mode 100644
index 0000000..3846afe
--- /dev/null
+++ b/Components/Restart/index.js
@@ -0,0 +1,11 @@
+let net = require('net');
+let systemRoot = "/System/Library";
+const socket = net.createConnection(systemRoot + "/../Volumes/VM/MistyCore-Socket", () => {
+ socket.write(JSON.stringify({
+ action: "SERVICE",
+ payload: {
+ option: "restart",
+ service: "MistyOS.yml"
+ }
+ }));
+}); \ No newline at end of file
diff --git a/Components/Restart/metadata.yml b/Components/Restart/metadata.yml
new file mode 100644
index 0000000..165b987
--- /dev/null
+++ b/Components/Restart/metadata.yml
@@ -0,0 +1,26 @@
+description: Restarts the system properly
+internal: false
+
+aliases:
+ - reboot
+ - boot
+ - reset
+
+manual:
+ summary: |
+ This command restarts the system by passing a reboot command through MistyCore, causing the system to restart properly.
+
+ parameters: []
+
+ final: null
+
+ examples:
+ - command: Restart
+ description: Restarts the system normally
+
+ - command: CoreDaemon -Restart MistyOS
+ description: Restarts the system by using MistyCore's frontend directly
+
+ compatibility:
+ mistyos: '>=1.2.0'
+ kernel: '>=5.10.0' \ No newline at end of file
diff --git a/Components/ShowMisty/index.js b/Components/ShowMisty/index.js
new file mode 100644
index 0000000..2078a46
--- /dev/null
+++ b/Components/ShowMisty/index.js
@@ -0,0 +1,30 @@
+const chalk = require(__dirname + '/../../MistyCore/node_modules/chalk');
+const fs = require("fs");
+
+module.exports = () => {
+ process.stdout.write("\n ");
+ process.stdout.write(chalk.blue("██"));
+ process.stdout.write(chalk.yellow("██"));
+ process.stdout.write(" \n ");
+ process.stdout.write(chalk.yellow("██"));
+ process.stdout.write(chalk.cyan("██"));
+ process.stdout.write(" \n ");
+ process.stdout.write(chalk.yellow("██"));
+ process.stdout.write(" ");
+ process.stdout.write(chalk.blue("██"));
+ process.stdout.write(chalk.cyan("██"));
+ process.stdout.write(chalk.cyan("██"));
+ process.stdout.write(" \n ");
+ process.stdout.write(chalk.blue("██"));
+ process.stdout.write(" ");
+ process.stdout.write(chalk.cyan("██"));
+ process.stdout.write(chalk.cyan("██"));
+ process.stdout.write(chalk.cyan("██"));
+ process.stdout.write(" \n ");
+ process.stdout.write(chalk.yellow("██"));
+ process.stdout.write(" ");
+ process.stdout.write(chalk.cyan("██"));
+ process.stdout.write(" ");
+ process.stdout.write(chalk.cyan("██"));
+ process.stdout.write(" \n\n");
+} \ No newline at end of file
diff --git a/Components/ShowMisty/metadata.yml b/Components/ShowMisty/metadata.yml
new file mode 100644
index 0000000..e4d4266
--- /dev/null
+++ b/Components/ShowMisty/metadata.yml
@@ -0,0 +1,22 @@
+description: Shows a Misty ASCII art
+internal: true
+
+aliases:
+ - misty
+ - brightdawn
+ - mistybrightdawn
+ - mlp
+
+manual:
+ summary: |
+ This command shows a Misty ASCII art on the console. Yes, that's literally it.
+
+ parameters: []
+
+ final: null
+
+ examples: []
+
+ compatibility:
+ mistyos: '>=1.0.0'
+ kernel: '>=5.10.0' \ No newline at end of file
diff --git a/Components/Shutdown/index.js b/Components/Shutdown/index.js
new file mode 100644
index 0000000..cd26bd1
--- /dev/null
+++ b/Components/Shutdown/index.js
@@ -0,0 +1,11 @@
+let net = require('net');
+let systemRoot = "/System/Library";
+const socket = net.createConnection(systemRoot + "/../Volumes/VM/MistyCore-Socket", () => {
+ socket.write(JSON.stringify({
+ action: "SERVICE",
+ payload: {
+ option: "stop",
+ service: "MistyOS.yml"
+ }
+ }));
+}); \ No newline at end of file
diff --git a/Components/Shutdown/metadata.yml b/Components/Shutdown/metadata.yml
new file mode 100644
index 0000000..b335adb
--- /dev/null
+++ b/Components/Shutdown/metadata.yml
@@ -0,0 +1,27 @@
+description: Shuts down the system properly
+internal: false
+
+aliases:
+ - poweroff
+ - off
+ - turnoff
+ - halt
+
+manual:
+ summary: |
+ This command shuts down the system by passing a shutdown command through MistyCore, causing the system to power off properly.
+
+ parameters: []
+
+ final: null
+
+ examples:
+ - command: Shutdown
+ description: Shuts down the system normally
+
+ - command: CoreDaemon -Stop MistyOS
+ description: Shuts down the system by using MistyCore's frontend directly
+
+ compatibility:
+ mistyos: '>=1.2.0'
+ kernel: '>=5.10.0' \ No newline at end of file