diff --git a/kernel.lua b/kernel.lua index 05d4449..19cc023 100644 --- a/kernel.lua +++ b/kernel.lua @@ -1,55 +1,86 @@ +local BASE_URL = "https://git.astrocore.space/root/nova-corp/raw/branch/main/" +-- Download to , replacing any existing file. +local function download(url, destFile) + if fs.exists(destFile) then + shell.execute("rm", destFile) + end + shell.execute("wget", url, destFile) + sleep(1) +end local function addDriver(fileName) - local extension = ".lua" - local fullFile = fileName .. extension - shell.execute("rm", fullFile) - local baseRoute = "https://git.astrocore.space/root/nova-corp/raw/branch/main/" - shell.execute("wget", baseRoute .. fullFile) - sleep(2) + local fullFile = fileName .. ".lua" + download(BASE_URL .. fullFile, fullFile) return require(fileName) end local function addFolderDriver(folder, fileName) - local extension = ".lua" - local fullFile = fileName .. extension - shell.execute("rm", fullFile) - local baseRoute = "https://git.astrocore.space/root/nova-corp/raw/branch/main/" - shell.execute("wget", baseRoute .. folder .. "/" .. fullFile) - sleep(2) + local fullFile = fileName .. ".lua" + download(BASE_URL .. folder .. "/" .. fullFile, fullFile) return require(fileName) end local function addProgram(fileName) - local extension = ".lua" - local fullFile = fileName .. extension - shell.execute("rm", fullFile) - local baseRoute = "https://git.astrocore.space/root/nova-corp/raw/branch/main/" - shell.execute("wget", baseRoute .. "programs" .. "/" .. fullFile) - sleep(2) + local fullFile = fileName .. ".lua" + download(BASE_URL .. "programs/" .. fullFile, fullFile) return require(fileName) end local function addSound(fileName) - local extension = ".dfpwm" - local fullFile = fileName .. extension - shell.execute("rm", fullFile) - local baseRoute = "https://git.astrocore.space/root/nova-corp/raw/branch/main/" - shell.execute("wget", baseRoute .. "sounds" .. "/" .. fullFile) - sleep(2) - return + local fullFile = fileName .. ".dfpwm" + download(BASE_URL .. "sounds/" .. fullFile, fullFile) end local function addServerHandler(fileName) - local extension = ".lua" - local fullFile = fileName .. extension - shell.execute("rm", fullFile) - local baseRoute = "https://git.astrocore.space/root/nova-corp/raw/branch/main/" - shell.execute("wget", baseRoute .. "server" .. "/" .. fullFile) - sleep(2) + local fullFile = fileName .. ".lua" + download(BASE_URL .. "server/" .. fullFile, fullFile) return require(fileName) end +-- installInit downloads programs/init.lua and writes it as startup.lua +-- so that on next boot the user is prompted for which program to install. +local function installInit() + download(BASE_URL .. "programs/init.lua", "startup.lua") + print("init installed as startup.lua. Reboot to choose a program.") +end + +-- addStartup("roulette") downloads programs/roulette.lua AND writes a +-- startup.lua that re-pulls the kernel + program on every boot and runs it. +local function addStartup(programName) + -- Pull the program once now so it's runnable immediately. + addProgram(programName) + + local startupSrc = ([[-- Auto-generated by kernel.addStartup("%s") +local BASE_URL = "%s" + +local function fetch(path, dest) + if fs.exists(dest) then shell.execute("rm", dest) end + shell.execute("wget", BASE_URL .. path, dest) + sleep(1) +end + +-- Refresh kernel and program on every boot so updates flow through. +fetch("kernel.lua", "kernel.lua") +local kernel = require("kernel") +local program = kernel.addProgram("%s") + +if program and program.start then program.start() end +if program and program.main then + program.main() +else + print("Program '%s' has no main() function.") +end +]]):format(programName, BASE_URL, programName, programName) + + if fs.exists("startup.lua") then shell.execute("rm", "startup.lua") end + local f = fs.open("startup.lua", "w") + f.write(startupSrc) + f.close() + + print("Startup installed for '" .. programName .. "'. Reboot to launch.") +end + addDriver("task-manager") addDriver("monitor-driver") @@ -57,5 +88,37 @@ addDriver("disk-driver") addDriver("speaker-driver") addSound("notification") +-- Always (re)install init as startup.lua when the kernel is freshly fetched. +-- The init program will overwrite startup.lua with the chosen program's +-- launcher the first time the user picks one. +-- +-- Gate: only run when executed directly from the shell (e.g. right after +-- `wget kernel.lua` then `kernel`). When required from a startup script +-- (`require("kernel")`) we skip this so we don't clobber the program's +-- startup.lua on every boot. +if not _G.__KERNEL_LOADED then + _G.__KERNEL_LOADED = true + if shell and shell.getRunningProgram and shell.getRunningProgram() == "kernel.lua" then + installInit() + end +end -return { addDriver = addDriver, addFolderDriver = addFolderDriver, addProgram = addProgram, addSound = addSound, addServerHandler = addServerHandler } \ No newline at end of file + +local kernel = { + addDriver = addDriver, + addFolderDriver = addFolderDriver, + addProgram = addProgram, + addSound = addSound, + addServerHandler = addServerHandler, + addStartup = addStartup, + installInit = installInit, +} + +-- Expose helpers as globals so they can be called directly from the shell: +-- > addStartup("roulette") +_G.addStartup = addStartup +_G.addProgram = addProgram +_G.addDriver = addDriver +_G.kernel = kernel + +return kernel diff --git a/programs/init.lua b/programs/init.lua new file mode 100644 index 0000000..f75c687 --- /dev/null +++ b/programs/init.lua @@ -0,0 +1,97 @@ +-- init: bootstrap launcher. +-- +-- Installed as startup.lua by the kernel. On boot it asks which program +-- to fetch, downloads it via the kernel, rewrites startup.lua so that +-- subsequent boots launch THAT program directly, then runs it. + +local BASE_URL = "https://git.astrocore.space/root/nova-corp/raw/branch/main/" + +local function fetch(path, dest) + if fs.exists(dest) then shell.execute("rm", dest) end + shell.execute("wget", BASE_URL .. path, dest) + sleep(1) +end + +local function ensureKernel() + if not fs.exists("kernel.lua") then + fetch("kernel.lua", "kernel.lua") + end + return require("kernel") +end + +local function writeProgramStartup(programName) + local src = ([[-- Auto-generated startup for "%s" +local BASE_URL = "%s" + +local function fetch(path, dest) + if fs.exists(dest) then shell.execute("rm", dest) end + shell.execute("wget", BASE_URL .. path, dest) + sleep(1) +end + +-- Always refresh kernel + program so code updates flow through. +fetch("kernel.lua", "kernel.lua") +local kernel = require("kernel") +local program = kernel.addProgram("%s") + +if type(program) ~= "table" then + print("Program '%s' did not return a module table.") + return +end + +if program.start then program.start() end +if program.main then + program.main() +else + print("Program '%s' has no main() function.") +end +]]):format(programName, BASE_URL, programName, programName, programName) + + if fs.exists("startup.lua") then shell.execute("rm", "startup.lua") end + local f = fs.open("startup.lua", "w") + f.write(src) + f.close() +end + +local function prompt() + term.clear() + term.setCursorPos(1, 1) + print("=== NovaCorp init ===") + print("Enter program name to install (from /programs):") + write("> ") + local name = read() + if not name or name == "" then + print("No program entered. Staying on init.") + return nil + end + return name +end + +local function main() + local name = prompt() + if not name then return end + + local kernel = ensureKernel() + + print("Fetching program '" .. name .. "'...") + local ok, programOrErr = pcall(kernel.addProgram, name) + if not ok then + print("Failed to download program: " .. tostring(programOrErr)) + print("Leaving init in place. Reboot to try again.") + return + end + + print("Replacing startup.lua...") + writeProgramStartup(name) + + print("Done. Launching '" .. name .. "' now.") + sleep(1) + + local program = programOrErr + if type(program) == "table" then + if program.start then pcall(program.start) end + if program.main then pcall(program.main) end + end +end + +main()