Unless I am misunderstanding the source code I see, I feel like OCL is trying to add too much functionality, which might be incompatible with some operating systems. What EXACTLY is the stated purpose of this program? I tend to come from the unix-y school of multiple small utilities functioning independently, and I feel that you are adding too many features in one monolithic component. Here is what I feel would be most useful for me, each as a separate concern in some way.
(1) Parallel boot loader, that can be used to run a custom bios. Allows the user to select which OS they want to run.
(2) A standard compatibility library between operating systems.
In my opinion, these two should be separate, to the point of being essentially separate projects, so that if someone does not want OCL, they can just use the bootloader, and if someone does not want to use the boot-loader, they can still run an OCL operating system without any problems. I propose that bios.lua look into "/rom/boot/" and "/boot/" which will contain replacement bios files for each possible OS, and run the selected one. Other features can be added, but I really don't think it should be forcing the programmers to conform to the OCL specifications if they don't want to for whatever reason. If you don't, people might be forced to run your system in a compatibility layer just to run their system properly which would be a silly state of affairs.
As for OCL itself, it makes a lot of assumptions about the nature of your OS which might not hold true. For me, this is particularly relevant, because the way I am designing my OS breaks a lot of those assumptions.
(1) What if an operating system does not load it's programs and such from the hard drive, but rather from some other source, like HTTP or rednet? In other words, I might want to, as part of booting my OS, load my shell/programs/libraries from a specific remote location, and then use loadstring to parse them directly into functions, so the system is at no point stored on the local computer? For example, on a multiplayer server, you might be worried your turtles could be captured by "the enemy", and so you run the OS in such a way that if the turtle is captured, there is no way to recover your code. I don't see how I can sensibly implement OCL.hasCustomShell() on such a system. Maybe this is not really the concern of OCL.
(2) The ID and read/write functions are cool.
(3) I don't understand getRoot(). What is the use case for this? All the use cases that I can think of are covered by the other directory-getting functions.
(4) The other path getting functions are neat, and a good idea, but they share the same problem as #1. I really don't see a fix for this that does not increase complexity by a significant amount; I guess the only way to create a "remote" filesystem would probably be to modify "fs" significantly and allow special paths that link to virtual files.
(5) I really like the abstraction on the idea of "apps". It is clean, simple, and allows programs to be written for many systems at once. I feel like this can and should be the core of this library. Here is how I would recommend expanding this: make it possible to query the system for what apps can be run, and then run apps directly. Thus, someone wants to write a multi-OS custom shell, they can easily see what apps are visible, and run one, irrelevent of how the system is assembled. Or, if you wish to deploy a system as multiple separate apps, you can call one from the other, without having to deal with any of the implementation details.
(6) Centralized logging system is an awesome, amazing idea. Not sure what the purpose of getLogFile is though… what if the OS does not actually write the logged information to a file, but just keeps it in memory? Or sends it to be stored on another computer somewhere? What multi-OS program needs to be able to read a log file? If you have user-based file permissions, it is very possible that it wont be able to open the file anyway.
(7) Unless I missed it, there is no removeFromStack(). Thus, if you addToStack, you will be permanently one off. Am I wrong? Also, I don't see the point of this exactly. If the OS wishes to track what programs you have run, it can override the various methods of calling a program to do so. What is the use case for this exactly?
(8) I have no idea how exit program possibly works.
(9) OCL.run() does not allow arguments to be passed into the called program. This is a major, major flaw, in my opinion.
This kind of API really is a very cool boon to authors of operating systems and software. However, I feel that the focus is too scattered, and forces certain ideas of what an OS should and shouldn't do which prevents it from reaching it's full potential. The problem I feel is that there is a disconnect between the natural lua way of viewing a program as a function, and the way this program view it, as a file. In lua, there is no real difference between a program file and a function, save the fact that one is stored on the disk. You load em up into a function, pass in parameters, and get return results: this is how it SHOULD be, how I structure my code, how I structure my OS. My "run" functions can take a path or a function: both work the same.
One other thing: what kind of functionality are you assuming is availible to the program? Are you assuming that all the standard libraries exist unchanged? Because I certainly have done my fair share of tinkering with libraries. What if "fs" is modified or removed? The program will silently fail. This should at the very least be made explicit, but here is another proposal: turn this into a more generic "dependancy manager". The interface would let you view what programs and libraries are availible, at what versions. You could load the libraries you need (if they are not loaded) via a standard interface, or run installed apps.
Then, separately, you would define a number of "library interfaces". These could include a read-write interface, a logging interface, a "standard filesystem locations" interface, etc. An OS can implement whichever ones in wants to, and the user can require whichever libraries and programs they want to, and the system would determine if the program can or cannot run in the given environment. The program would look like this:
requireLib("OCL.term", 1.0)
requireLib("OCL.log", 1.0)
requireLib("OCL.paths", 1.0)
requireLib("someNetworkingSystem", 0.32)
requireApp("programCore") -- these could have versions too in theory
requireApp("someDatabase")
OCL.log("Program started")
OCL.term.nPrint("This program is going to call another")
local result = runApp("programCore")
someNetworkingSystem.send(result)
runApp("database","store",result)
-- etc
requireLib would make sure the library exists at the correct version. It might load the library from a file if needed or whatever else the OS writer decides. If it cannot load a correct version of the library into the current global namespace for whatever reason, it will throw an error. Thus, the program writer will be assured that all the correct functionality exists, and the user will be informed with a helpful error message infoming them exactly what is missing from their system.
PS: Could you please license it? Linking or distributing non-licensed copyrighted code is illegal, so it would be helpful if you tossed in some kind of disclaimer or whatever allowing usage. I am a big fan of WTFPL, but whatever you prefer.