| name | zeros-kernel-interaction |
| description | Guide for interacting with ZerOS kernel and system APIs. Use when working with ZerOS kernel modules, calling kernel APIs from programs, accessing system services, or understanding how programs communicate with the ZerOS kernel. |
ZerOS Kernel and System Interaction Guide
This skill provides guidance on how to interact with ZerOS kernel and system APIs, including kernel module development, program-to-kernel communication, and system service access.
Core Concepts
ZerOS Architecture
ZerOS is a browser-based virtual operating system kernel with:
- Kernel modules: Core system functionality (process management, memory, filesystem, etc.)
- POOL: Object pool for module data sharing and communication
- ProcessManager: Manages program lifecycle and kernel API calls
- Permission system: Controls access to kernel APIs
Module Communication
Kernel modules communicate through:
- POOL:
POOL.__GET__("KERNEL_GLOBAL_POOL", "ModuleName") to access modules
- Direct access: Modules registered globally via
window.ModuleName or globalThis.ModuleName
- Dependency management: Modules declared in
bootloader/starter.js
Program-to-Kernel API Calls
Method 1: Process-Bound API (Recommended)
Use initArgs.kernelAPI.call() for secure, process-bound API calls:
async __init__(pid, initArgs) {
this.pid = pid;
this.kernelAPI = initArgs.kernelAPI;
const content = await this.kernelAPI.call('Disk.read', ['D:/myfile.txt']);
await this.kernelAPI.call('Notification.create', [{
title: 'Success',
content: 'File read successfully'
}]);
}
Advantages:
- No PID parameter needed (bound to process)
- Prevents PID spoofing (CVS_ZEROS_009 mitigation)
- Recommended for sensitive or multi-instance programs
Method 2: Standard API Call
Use ProcessManager.callKernelAPI() for standard calls:
const result = await ProcessManager.callKernelAPI(this.pid, 'Disk.read', ['D:/myfile.txt']);
await ProcessManager.callKernelAPI(this.pid, 'Notification.create', [{
title: 'Info',
content: 'Operation completed',
type: 'info',
duration: 3000
}]);
API Format: 'ModuleName.methodName'
- Module name: e.g.,
Disk, GUIManager, LStorage
- Method name: e.g.,
read, write, registerWindow
Common Kernel APIs
File System Operations
API Namespace: FileSystem.*
const content = await this.kernelAPI.call('FileSystem.read', ['D:/path/to/file.txt']);
await this.kernelAPI.call('FileSystem.write', ['D:/path/to/file.txt', content]);
await this.kernelAPI.call('FileSystem.delete', ['D:/path/to/file.txt']);
await this.kernelAPI.call('FileSystem.create', ['D:/path/to/newfile.txt', 'file']);
await this.kernelAPI.call('FileSystem.create', ['D:/path/to/newdir', 'directory']);
const files = await this.kernelAPI.call('FileSystem.list', ['D:/path/to/dir']);
const info = await this.kernelAPI.call('FileSystem.exists', ['D:/path/to/file.txt']);
GUI Operations
API Namespace: GUI.*, Notification.*
const windowId = await this.kernelAPI.call('GUI.createWindow', [this.pid, windowElement, {
title: 'My Window',
icon: 'icon.svg',
resizable: true,
minimizable: true,
onClose: () => {
}
}]);
await this.kernelAPI.call('GUI.manageWindow', [windowId, 'minimize']);
await this.kernelAPI.call('GUI.manageWindow', [windowId, 'maximize']);
await this.kernelAPI.call('GUI.manageWindow', [windowId, 'close']);
await this.kernelAPI.call('Notification.create', [{
title: 'Title',
content: 'Message',
type: 'info',
duration: 5000
}]);
await this.kernelAPI.call('Notification.remove', [notificationId]);
Storage Operations
API Namespace: Storage.*
const value = await this.kernelAPI.call('Storage.read', ['key']);
await this.kernelAPI.call('Storage.write', ['key', value]);
Cache Operations
await this.kernelAPI.call('Cache.set', ['key', value, {
ttl: 3600000,
pid: this.pid
}]);
const value = await this.kernelAPI.call('Cache.get', ['key', defaultValue, {
pid: this.pid
}]);
await this.kernelAPI.call('Cache.delete', ['key', { pid: this.pid }]);
Network Operations
API Namespace: Network.*, Network.Port.*
const response = await this.kernelAPI.call('Network.request', [url, {
method: 'GET',
headers: {},
body: null
}]);
const response = await this.kernelAPI.call('Network.fetch', [url, options]);
await this.kernelAPI.call('Network.Port.register', [port, {
onMessage: (data) => { },
onConnect: () => { },
onDisconnect: () => { }
}]);
await this.kernelAPI.call('Network.Port.unregister', [port]);
const status = await this.kernelAPI.call('Network.Port.getStatus', [port]);
const ports = await this.kernelAPI.call('Network.Port.list', []);
await this.kernelAPI.call('Network.Port.send', [port, data]);
Memory Operations
const memoryInfo = await this.kernelAPI.call('MemoryManager.allocateMemory', [
heapSize,
shedSize
]);
await this.kernelAPI.call('MemoryManager.freeMemory', [this.pid]);
Desktop Management
API Namespace: Desktop.*
await this.kernelAPI.call('Desktop.addShortcut', [{
name: 'My App',
icon: 'icon.svg',
programName: 'myapp',
args: []
}]);
await this.kernelAPI.call('Desktop.removeShortcut', ['shortcutId']);
const icons = await this.kernelAPI.call('Desktop.getIcons', []);
const config = await this.kernelAPI.call('Desktop.getConfig', []);
await this.kernelAPI.call('Desktop.setArrangementMode', ['grid']);
await this.kernelAPI.call('Desktop.setIconSize', [48]);
await this.kernelAPI.call('Desktop.setAutoArrange', [true]);
await this.kernelAPI.call('Desktop.refresh', []);
Taskbar Operations
API Namespace: Taskbar.*
await this.kernelAPI.call('Taskbar.pinProgram', ['programName']);
await this.kernelAPI.call('Taskbar.unpinProgram', ['programName']);
const pinned = await this.kernelAPI.call('Taskbar.getPinnedPrograms', []);
const isPinned = await this.kernelAPI.call('Taskbar.isPinned', ['programName']);
const iconId = await this.kernelAPI.call('Taskbar.addIcon', [{
icon: 'icon.svg',
tooltip: 'My Tooltip',
onClick: () => { }
}]);
await this.kernelAPI.call('Taskbar.updateIcon', [iconId, {
icon: 'new-icon.svg',
tooltip: 'New Tooltip'
}]);
await this.kernelAPI.call('Taskbar.removeIcon', [iconId]);
Process Management
API Namespace: Process.*
await this.kernelAPI.call('Process.requestBackground', []);
await this.kernelAPI.call('Process.registerBackgroundTrayClick', [() => {
}]);
await this.kernelAPI.call('Process.registerBackgroundTrayContextMenu', [[
{ label: 'Show', action: () => { } },
{ label: 'Settings', action: () => { } }
]]);
await this.kernelAPI.call('Process.requestSelfTermination', []);
await this.kernelAPI.call('Process.manage', ['start', 'programName', initArgs]);
await this.kernelAPI.call('Process.manage', ['kill', pid]);
Drag and Drop
API Namespace: Drag.*
const sessionId = await this.kernelAPI.call('Drag.createSession', [element]);
await this.kernelAPI.call('Drag.enable', [sessionId]);
await this.kernelAPI.call('Drag.disable', [sessionId]);
await this.kernelAPI.call('Drag.registerDropZone', [element, {
onDrop: (data) => { }
}]);
await this.kernelAPI.call('Drag.createFileDrag', [element, filePath]);
await this.kernelAPI.call('Drag.createWindowDrag', [element, windowId]);
const drags = await this.kernelAPI.call('Drag.getProcessDrags', [this.pid]);
Geography (Location)
API Namespace: Geography.*
const position = await this.kernelAPI.call('Geography.getCurrentPosition', []);
const cached = await this.kernelAPI.call('Geography.getCachedLocation', []);
await this.kernelAPI.call('Geography.clearCache', []);
const supported = await this.kernelAPI.call('Geography.isSupported', []);
Cryptography
API Namespace: Crypt.*
const keyPair = await this.kernelAPI.call('Crypt.generateKeyPair', []);
await this.kernelAPI.call('Crypt.importKeyPair', [privateKey, publicKey]);
const info = await this.kernelAPI.call('Crypt.getKeyInfo', [keyId]);
const keys = await this.kernelAPI.call('Crypt.listKeys', []);
await this.kernelAPI.call('Crypt.deleteKey', [keyId]);
await this.kernelAPI.call('Crypt.setDefaultKey', [keyId]);
const encrypted = await this.kernelAPI.call('Crypt.encrypt', [data, keyId]);
const decrypted = await this.kernelAPI.call('Crypt.decrypt', [encrypted, keyId]);
const hash = await this.kernelAPI.call('Crypt.md5', [data]);
const randomInt = await this.kernelAPI.call('Crypt.randomInt', [min, max]);
const randomFloat = await this.kernelAPI.call('Crypt.randomFloat', []);
const randomBool = await this.kernelAPI.call('Crypt.randomBoolean', []);
const randomString = await this.kernelAPI.call('Crypt.randomString', [length]);
const randomChoice = await this.kernelAPI.call('Crypt.randomChoice', [array]);
const shuffled = await this.kernelAPI.call('Crypt.shuffle', [array]);
Speech Recognition
API Namespace: Speech.*
const supported = await this.kernelAPI.call('Speech.isSupported', []);
const sessionId = await this.kernelAPI.call('Speech.createSession', [{
language: 'zh-CN',
continuous: true,
interimResults: true,
onResult: (results) => { },
onError: (error) => { }
}]);
await this.kernelAPI.call('Speech.startRecognition', [sessionId]);
await this.kernelAPI.call('Speech.stopRecognition', [sessionId]);
await this.kernelAPI.call('Speech.stopSession', [sessionId]);
const status = await this.kernelAPI.call('Speech.getSessionStatus', [sessionId]);
const results = await this.kernelAPI.call('Speech.getSessionResults', [sessionId]);
Schedule Tasks
API Namespace: ScheduleTask.*
const taskId = await this.kernelAPI.call('ScheduleTask.create', [{
name: 'My Task',
type: 'program',
schedule: '0 0 * * *',
enabled: true,
config: { programName: 'myapp', args: [] }
}]);
const task = await this.kernelAPI.call('ScheduleTask.get', [taskId]);
const tasks = await this.kernelAPI.call('ScheduleTask.getAll', []);
await this.kernelAPI.call('ScheduleTask.update', [taskId, { enabled: false }]);
await this.kernelAPI.call('ScheduleTask.delete', [taskId]);
await this.kernelAPI.call('ScheduleTask.setEnabled', [taskId, true]);
Language Packs
API Namespace: Languages.*
await this.kernelAPI.call('Languages.loadPack', ['zh-CN', packData]);
await this.kernelAPI.call('Languages.setCurrent', ['zh-CN']);
const text = await this.kernelAPI.call('Languages.getText', ['CONSTANT_NAME']);
const packs = await this.kernelAPI.call('Languages.listPacks', []);
const locale = await this.kernelAPI.call('Languages.getCurrentLocale', []);
const locales = await this.kernelAPI.call('Languages.getLoadedLocales', []);
Server Management
API Namespace: Server.*
Important: Requires SERVER_SERVICE_MANAGE permission (DANGEROUS level, highest priority). Programs must NOT directly call ServerExpansion methods.
const services = await this.kernelAPI.call('Server.listServices', []);
const loaded = await this.kernelAPI.call('Server.loadAll', []);
const success = await this.kernelAPI.call('Server.start', ['serviceId']);
const success = await this.kernelAPI.call('Server.stop', ['serviceId']);
const status = await this.kernelAPI.call('Server.status', ['serviceId']);
const info = await this.kernelAPI.call('Server.info', ['serviceId']);
const isInited = await this.kernelAPI.call('Server.isInited', ['serviceId']);
const isStarted = await this.kernelAPI.call('Server.isStarted', ['serviceId']);
const configOptions = await this.kernelAPI.call('Server.listConfig', ['serviceId']);
await this.kernelAPI.call('Server.setConfig', ['serviceId', config]);
Theme Management
API Namespace: Theme.*
const theme = await this.kernelAPI.call('Theme.read', []);
await this.kernelAPI.call('Theme.write', [themeConfig]);
Exception Handling
API Namespace: Exception.*
await this.kernelAPI.call('Exception.report', [
'PROGRAM',
'Error message',
{ details: 'Additional info' },
this.pid
]);
Permission System
Permission Levels
- NORMAL: Automatically granted, no user confirmation, only logged
- SPECIAL: First-time user confirmation, decision saved for future use
- DANGEROUS: Requires admin approval, may prompt each time
Permission Declaration
Programs declare permissions in __info__():
static __info__() {
return {
name: 'MyProgram',
type: 'GUI',
permissions: [
PermissionManager.PERMISSION.KERNEL_DISK_READ,
PermissionManager.PERMISSION.KERNEL_DISK_WRITE,
PermissionManager.PERMISSION.SYSTEM_NOTIFICATION,
PermissionManager.PERMISSION.GUI_WINDOW_CREATE,
PermissionManager.PERMISSION.SERVER_SERVICE_MANAGE
]
};
}
Common Permissions
File System:
KERNEL_DISK_READ, KERNEL_DISK_WRITE, KERNEL_DISK_DELETE, KERNEL_DISK_CREATE, KERNEL_DISK_LIST
GUI:
GUI_WINDOW_CREATE, GUI_WINDOW_MANAGE
System:
SYSTEM_NOTIFICATION, SYSTEM_STORAGE_READ, SYSTEM_STORAGE_WRITE
SYSTEM_STORAGE_WRITE_USER_CONTROL (DANGEROUS, admin only)
SYSTEM_STORAGE_WRITE_PERMISSION_CONTROL (DANGEROUS, admin only)
Process:
PROCESS_MANAGE (DANGEROUS), PROCESS_BACKGROUND (NORMAL, self only)
Network:
Server:
SERVER_SERVICE_MANAGE (DANGEROUS, highest priority)
Other:
CRYPT_*, DRAG_*, GEOGRAPHY_LOCATION, SPEECH_RECOGNITION, CACHE_*, LANGUAGES_*, SCHEDULE_TASK_*
Permission Checking
Permissions are automatically checked when calling kernel APIs:
- NORMAL: Auto-granted, logged to audit trail
- SPECIAL: User dialog appears on first use, decision saved
- DANGEROUS: Admin approval required, may prompt each time
Important:
- Exploit program (PID 10000) bypasses all permission checks
- Permission decisions are cached for 5 seconds (TTL)
- Permission violations are logged to audit trail
Kernel Module Development
Module Structure
KernelLogger.info("MyDrive", "模块初始化");
class MyDrive {
static _initialized = false;
static init() {
if (MyDrive._initialized) return;
try {
MyDrive._initialized = true;
MyDrive._registerToPool();
KernelLogger.info("MyDrive", "模块初始化完成");
} catch (error) {
KernelLogger.error("MyDrive", "模块初始化失败", error);
}
}
static _registerToPool() {
if (typeof POOL !== 'undefined' && POOL && typeof POOL.__SET__ === 'function') {
POOL.__SET__("KERNEL_GLOBAL_POOL", "MyDrive", MyDrive);
}
}
static doSomething() {
if (!MyDrive._initialized) {
KernelLogger.warn("MyDrive", "模块未初始化");
return;
}
}
}
if (typeof KernelLogger !== 'undefined') {
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => MyDrive.init());
} else {
MyDrive.init();
}
}
if (typeof DependencyConfig !== 'undefined' && DependencyConfig && typeof DependencyConfig.publishSignal === 'function') {
DependencyConfig.publishSignal("../kernel/drive/myDrive.js");
}
Key Requirements
- Use KernelLogger: Never use
console.log, always use KernelLogger.info/warn/error/debug
- Register to POOL: Use
POOL.__SET__("KERNEL_GLOBAL_POOL", "ModuleName", ModuleClass)
- Declare dependencies: Add to
bootloader/starter.js MODULE_DEPENDENCIES
- Publish signal: Call
DependencyConfig.publishSignal() after initialization
- Check initialization: Always check
_initialized flag before operations
Accessing Other Modules
const LStorage = POOL.__GET__("KERNEL_GLOBAL_POOL", "LStorage");
if (LStorage) {
if (!LStorage._initialized) {
await LStorage.init();
}
const data = LStorage.getSystemStorage('key');
}
if (typeof ProcessManager !== 'undefined') {
ProcessManager.getProcessInfo(pid);
}
System Information
Get System Info
const version = SystemInformation.getSystemVersion();
const kernelVersion = SystemInformation.getKernelVersion();
const fsUrl = SystemInformation.getFSDirveUrl();
const origin = SystemInformation.getOrigin();
const env = SystemInformation.getHostEnvironment();
Process Management
Get Process Information
const processInfo = ProcessManager.getProcessInfo(this.pid);
const exists = ProcessManager.hasProcess(pid);
const processes = ProcessManager.listProcesses();
Self-Termination
await this.kernelAPI.call('Process.requestSelfTermination', []);
await ProcessManager.callKernelAPI(this.pid, 'Process.requestSelfTermination', []);
Best Practices
- Use bound API: Prefer
initArgs.kernelAPI.call() for security (prevents PID spoofing)
- Handle errors: Always wrap API calls in try-catch blocks
- Check permissions: Ensure program declares required permissions in
__info__()
- Log operations: Use KernelLogger for debugging (in kernel modules), never use
console.log
- Clean up resources: Unregister windows, clear caches, stop sessions on exit
- Follow patterns: Use existing modules as reference for structure
- VM/CLI programs: Use bound API for self-termination to avoid PID validation issues
- Error handling: Provide user-friendly error messages via notifications
- Resource lifecycle: Properly initialize and cleanup all resources (drag sessions, speech sessions, etc.)
- Security: Never bypass permission checks, always declare required permissions
Common Patterns
Async API Call Pattern
try {
const result = await this.kernelAPI.call('Module.method', [arg1, arg2]);
} catch (error) {
await this.kernelAPI.call('Notification.create', [{
title: 'Error',
content: error.message,
type: 'error'
}]);
}
Resource Cleanup Pattern
async __exit__(pid, force) {
try {
if (this.windowId) {
await this.kernelAPI.call('GUI.manageWindow', [this.windowId, 'close']);
}
if (this.dragSessionId) {
await this.kernelAPI.call('Drag.destroySession', [this.dragSessionId]);
}
if (this.speechSessionId) {
await this.kernelAPI.call('Speech.stopSession', [this.speechSessionId]);
}
await this.kernelAPI.call('Cache.delete', ['myCacheKey', { pid: this.pid }]);
if (this.registeredPorts) {
for (const port of this.registeredPorts) {
await this.kernelAPI.call('Network.Port.unregister', [port]);
}
}
if (this.taskbarIconId) {
await this.kernelAPI.call('Taskbar.removeIcon', [this.taskbarIconId]);
}
} catch (error) {
console.error('Cleanup error:', error);
}
}
Error Handling Pattern
async performOperation() {
try {
const result = await this.kernelAPI.call('FileSystem.read', ['D:/file.txt']);
return result;
} catch (error) {
if (error.message.includes('没有权限') || error.message.includes('permission')) {
await this.kernelAPI.call('Notification.create', [{
title: '权限不足',
content: '程序需要文件读取权限',
type: 'error',
duration: 5000
}]);
} else if (error.message.includes('不存在') || error.message.includes('not found')) {
await this.kernelAPI.call('Notification.create', [{
title: '文件不存在',
content: '无法找到指定的文件',
type: 'warning',
duration: 3000
}]);
} else {
await this.kernelAPI.call('Exception.report', [
'PROGRAM',
`Operation failed: ${error.message}`,
{ error: error.toString(), stack: error.stack },
this.pid
]);
}
throw error;
}
}
Background Process Pattern
async __init__(pid, initArgs) {
this.pid = pid;
this.kernelAPI = initArgs.kernelAPI;
this.isBackground = false;
await this.kernelAPI.call('Process.registerBackgroundTrayClick', [() => {
this.restoreWindow();
}]);
await this.kernelAPI.call('Process.registerBackgroundTrayContextMenu', [[
{ label: 'Show', action: () => this.restoreWindow() },
{ label: 'Settings', action: () => this.openSettings() }
]]);
}
async onWindowClose() {
await this.kernelAPI.call('Process.requestBackground', []);
this.hideWindow();
this.isBackground = true;
}
async restoreWindow() {
this.showWindow();
await this.kernelAPI.call('GUI.manageWindow', [this.windowId, 'focus']);
this.isBackground = false;
}
Security Considerations
PID Spoofing Prevention (CVS_ZEROS_009)
- Use bound API:
initArgs.kernelAPI.call() prevents PID spoofing
- Call stack validation: Standard API validates caller PID against call stack
- Exploit PID protection: Application layer cannot use Exploit PID (10000)
Permission Security
- Always declare permissions: Missing permissions cause API calls to fail
- DANGEROUS permissions: Require admin approval, highest security level
- Permission caching: 5-second TTL prevents excessive checks
- Audit trail: All permission operations are logged
Best Security Practices
- Never bypass permission checks
- Use bound API for sensitive operations
- Validate all user inputs before API calls
- Handle permission errors gracefully
- Report security issues via Exception.report
RandomSecurity & CVS-ZEROS-016
- 问题:RandomSecurity 接口(签发 SystemToken/UserToken)在修复前未校验请求来源,任意客户端传
type=SystemToken 即可未认证获取系统令牌并提权。
- 修复逻辑:SystemToken 仅在「该 randomValue 已通过
action=commit_for_system 在同一 IP 下提交且未消费」时签发。引导流程:前端生成 randomValue → 先 POST commit_for_system → 再 POST 签发 type=SystemToken + 同一 randomValue;后端校验并消费该提交后签发,否则 403。
- 前端:
kernel/core/safemode/randomSecurity.js 的 runSecurityCheck() 中先 commitRandomValueForSystem(_randomSecurityValue) 再 getJWTFromBackend(..., 'SystemToken')。
- 后端:PHP 使用
BOOT_COMMIT_FILE 存每 IP 一笔未消费提交,TTL 30s,5s 内不可覆盖(防占位),超 5s 可同 IP 覆盖(刷新恢复)。签发 SystemToken 时校验并删除该提交。
- 补充:NetworkManager 在携带 JWT 的请求收到 401 时触发系统级异常(蓝屏),同一会话只触发一次。
Multi-backend service URL(多后端服务地址)
- 统一管理:后端类型与端口由 SystemInformation 管理(
_backendConfig.type、phpPort、springBootPort),来自 LStorage system.backendConfig 或 URL 参数 ?backend= / ?backendType=。
- URL 拼装:有 SystemInformation 时一律用
SystemInformation.getXxxPath() / getXxxUrl() 或 buildServiceUrl(SERVICE_NAMES.xxx, params),内部按 backend 类型加后缀(PHP→.php,SpringBoot→无)并选对应端口。
- Fallback:无 SystemInformation 时与 FSDirve/LStorage 一致:默认 PHP 路径 + 当前页
window.location.origin,不按端口猜测、不读 URL 参数。用 Java 后端时需保证 SystemInformation 先加载并配置。
- 禁止:不要用
window.location.port === '8080' 等端口推断后端类型;新服务在 SystemInformation.SERVICE_NAMES 注册并视需要提供 getXxxPath() / getXxxUrl()。
Common Issues and Solutions
Issue: "API调用拒绝(PID校验)"
Cause: Call stack doesn't match provided PID (VM/CLI programs)
Solution: Use bound API this.kernelAPI.call() instead of ProcessManager.callKernelAPI(this.pid, ...)
Issue: "没有权限" / "Permission denied"
Cause: Missing permission declaration or insufficient user level
Solution:
- Add permission to
__info__().permissions
- For DANGEROUS permissions, ensure admin user
- Check permission level (NORMAL/SPECIAL/DANGEROUS)
Issue: "磁盘分区不存在"
Cause: Partition not initialized or invalid path format
Solution:
- Use correct path format:
"D:/path/to/file" (not "D:\path\to\file")
- Ensure partition exists:
Disk.diskSeparateMap.has('D:')
- Check NodeTree initialization
Issue: "模块未初始化"
Cause: Kernel module not loaded or initialization failed
Solution:
- Check module dependencies in
bootloader/starter.js
- Verify module registered to POOL
- Check KernelLogger for initialization errors
References
Core Documentation
- Kernel Developer Guide:
docs/KERNEL_DEVELOPER_GUIDE.md
- System Flow:
docs/SYSTEM_FLOW.md
- ZerOS Kernel:
docs/ZEROS_KERNEL.md
- Developer Guide:
docs/DEVELOPER_GUIDE.md
API Documentation
- ProcessManager API:
docs/API/ProcessManager.md
- PermissionManager API:
docs/API/PermissionManager.md
- GUIManager API:
docs/API/GUIManager.md
- Disk API:
docs/API/Disk.md
- ServerExpansion API:
docs/API/ServerExpansion.md
- API Index:
docs/API/README.md
Service Documentation
- Service Module Guide:
docs/SERVER/ServiceModule.md
- Server README:
docs/SERVER/README.md
Extension Documentation
- Plugins README:
docs/PLUGINS/README.md
- Language Pack:
docs/PLUGINS/LanguagePack.md