/** * One-shot generator for man/pages/*.json (run after changing commands list). * node packages/bare-os-coreutils/scripts/seed-man-pages.mjs */ import { mkdir, writeFile } from 'fs/promises' import { dirname, join } from 'path' import { fileURLToPath } from 'url' import { COREUTILS_COMMANDS, MAN_EXTRA_PAGES } from '../lib/commands.mjs' const __dirname = dirname(fileURLToPath(import.meta.url)) const pagesDir = join(__dirname, '../man/pages') const STUB = new Set(['chgrp', 'chown']) const POSIX_TITLE = { awk: 'pattern scanning and processing language', basename: 'strip directory and suffix from pathnames', cat: 'concatenate and print files', chgrp: 'change file group ownership', chmod: 'change file mode bits', chown: 'change file owner and group', cksum: 'write file checksums and sizes', clear: 'clear the terminal screen', cp: 'copy files', crontab: 'user crontab manipulation', cut: 'cut out selected fields of each line', date: 'display or set date and time', dirname: 'return directory portion of a pathname', du: 'estimate file space usage', echo: 'write arguments to standard output', env: 'set the environment for command invocation', exit: 'exit the shell or booter session', false: 'return false value', find: 'find files', getconf: 'get configuration values', grep: 'pattern matching utility', head: 'copy the first part of files', hdms: 'Hyperswarm distributed map store', help: 'Bare OS help summary', hostname: 'set or print hostname', id: 'return user identity', jq: 'command-line JSON processor (jq language subset)', ln: 'link files', login: 'begin a session on the system', logout: 'end session (save vault)', logname: "return the user's login name", ls: 'list directory contents', man: 'display on-line manual pages', mkdir: 'make directories', mkfifo: 'make FIFO special files', mv: 'move or rename files', nl: 'line numbering utility', od: 'octal dump', pathchk: 'check pathname portability', printenv: 'print environment variables', printf: 'format and print', pwd: 'return working directory name', readlink: 'print symbolic link targets', rm: 'remove files', rmdir: 'remove empty directories', savevault: 'encrypt snapshot of personal drive', sed: 'stream editor', seq: 'print sequences of numbers', sleep: 'suspend execution for an interval', sort: 'sort lines', stat: 'display file status', tail: 'copy the last part of a file', tee: 'duplicate standard input', test: 'evaluate a condition', time: 'time a simple command', touch: 'change file timestamps or create files', tr: 'translate or delete characters', true: 'return true value', tty: "return user's terminal name", uname: 'return operating system name', wc: 'word, line, and byte or character count', which: 'locate a command', whoami: 'display effective user ID', xargs: 'construct argument lists and invoke utility' } /** * cheat.sh-style snippets: { caption?, code } — shown under EXAMPLES in man output. * @type {Record>} */ const EXAMPLES = {} EXAMPLES.awk = [ { caption: 'print column 1', code: "awk '{print $1}' file.txt" }, { caption: 'field separator', code: "awk -F: '{print $1}' /etc/passwd" }, { caption: 'sum numbers in first column', code: "awk '{s+=$1} END{print s}' nums.txt" }, { caption: 'lines matching /re/', code: 'awk \'/error/{print NR": "$0}\' log.txt' } ] EXAMPLES.basename = [ { caption: 'strip directory', code: 'basename /home/user/docs/readme.md' }, { caption: 'strip suffix', code: 'basename -s .md /path/readme.md' } ] EXAMPLES.cat = [ { caption: 'stdout several files', code: 'cat a.txt b.txt' }, { caption: 'number lines (use nl)', code: 'cat -n file.txt # if supported; else nl file' }, { caption: 'here-string via echo pipe', code: 'echo hello | cat' } ] EXAMPLES.chgrp = [ { caption: 'not supported — use identity model', code: '# chgrp is a stub; group is display metadata only' } ] EXAMPLES.chmod = [ { caption: 'octal', code: 'chmod 644 ~/.profile' }, { caption: 'recursive-ish (run find + chmod per file)', code: 'find . -type f -name "*.sh" -print' }, { caption: 'symbolic user bits', code: 'chmod u+x script.sh' }, { caption: 'all read, owner write', code: 'chmod a+r,u+w shared.txt' } ] EXAMPLES.chown = [ { caption: 'not supported', code: '# chown stub — see man identity / login' } ] EXAMPLES.cksum = [ { caption: 'checksum file', code: 'cksum iso.img' }, { caption: 'verify pipeline', code: 'cat f | cksum' } ] EXAMPLES.clear = [{ caption: 'wipe screen', code: 'clear' }] EXAMPLES.cp = [ { caption: 'copy file', code: 'cp src.txt dest.txt' }, { caption: 'into directory', code: 'cp a b c ~/backup/' }, { caption: 'preserve implied (if implemented)', code: 'cp -R proj proj.bak' } ] EXAMPLES.crontab = [ { caption: 'list jobs', code: 'crontab -l' }, { caption: 'install from file', code: 'crontab ~/.crontab' }, { caption: 'remove all', code: 'crontab -r' } ] EXAMPLES.cut = [ { caption: 'fields by delimiter', code: 'cut -d: -f1,3 /etc/passwd' }, { caption: 'characters', code: 'cut -c1-16 file.txt' } ] EXAMPLES.date = [ { caption: 'RFC-ish output', code: 'date' }, { caption: 'epoch seconds', code: 'date +%s' } ] EXAMPLES.dirname = [ { caption: 'parent path', code: 'dirname /a/b/c.txt' }, { caption: 'compose with basename', code: 'p=/x/y/z; echo $(dirname $p)/$(basename $p)' } ] EXAMPLES.du = [ { caption: 'sizes under cwd', code: 'du .' }, { caption: 'human (if supported)', code: 'du -h ~' } ] EXAMPLES.echo = [ { caption: 'literal', code: 'echo hello world' }, { caption: 'no newline (if -n supported)', code: 'echo -n OK' } ] EXAMPLES.env = [ { caption: 'print environment', code: 'env' }, { caption: 'run with override', code: 'env PATH=/bin:/usr/bin man ls' } ] EXAMPLES.exit = [ { caption: 'leave session with status', code: 'exit 0' }, { caption: 'from script', code: '/bin/exit 42' } ] EXAMPLES.false = [ { caption: 'force failure in pipeline tests', code: 'false; echo $?' } ] EXAMPLES.find = [ { caption: 'files by name glob', code: 'find . -name "*.js"' }, { caption: 'directories only', code: 'find . -type d' }, { caption: 'max depth', code: 'find . -maxdepth 2 -type f' }, { caption: 'OR names', code: 'find . \\( -name "*.c" -o -name "*.h" \\)' } ] EXAMPLES.getconf = [ { caption: 'path length limit', code: 'getconf PATH_MAX' }, { caption: 'list known names and values', code: 'getconf -a' } ] EXAMPLES.grep = [ { caption: 'recursive feel (grep each file)', code: 'grep -n error *.log' }, { caption: 'case insensitive', code: 'grep -i todo NOTES.md' }, { caption: 'invert (lines without)', code: "grep -v '^#' config" }, { caption: 'fixed string (no regex)', code: 'grep -F "v1.0" CHANGES' }, { caption: 'count matches', code: 'grep -c FAIL build.log' }, { caption: 'only filenames', code: 'grep -l main *.js' }, { caption: 'multiple patterns', code: 'grep -e foo -e bar file.txt' } ] EXAMPLES.head = [ { caption: 'first 10 lines', code: 'head /etc/os-release' }, { caption: 'first N', code: 'head -n 50 big.log' }, { caption: 'stdin', code: 'cat long.txt | head' } ] EXAMPLES.hdms = [ { caption: 'when booter wires HDMS', code: 'hdms ls /mnt' }, { caption: 'otherwise', code: '# prints unavailable without ctx.runHdms' } ] EXAMPLES.help = [ { caption: 'quick index', code: 'help' }, { caption: 'then deep dive', code: 'man grep' } ] EXAMPLES.hostname = [{ caption: 'show host', code: 'hostname' }] EXAMPLES.id = [{ caption: 'who am I numerically', code: 'id' }] EXAMPLES.ln = [ { caption: 'symlink', code: 'ln -s target name' }, { caption: 'hard link (if supported)', code: 'ln file linkname' } ] EXAMPLES.login = [ { caption: 'unlock existing identity', code: 'login my passphrase words here' }, { caption: 'register new', code: 'login --new first time passphrase' } ] EXAMPLES.logout = [ { caption: 'end session', code: 'logout' }, { caption: 'save vault hint', code: 'logout --save' } ] EXAMPLES.logname = [{ caption: 'login name', code: 'logname' }] EXAMPLES.ls = [ { caption: 'long + hidden', code: 'ls -la ~' }, { caption: 'one per line', code: 'ls -1 /bin | head' }, { caption: 'multiple paths', code: 'ls /bin /etc' } ] EXAMPLES.man = [ { caption: 'open page', code: 'man sed' }, { caption: 'handbook TOC (section 7)', code: 'man handbook' }, { caption: 'handbook chapter by section', code: 'man 7 handbook-01-introduction' }, { caption: 'apropos', code: 'man -k copy' }, { caption: 'whatis', code: 'man -f grep' }, { caption: 'all pages', code: 'man -l' }, { caption: 'narrow terminal', code: 'MANWIDTH=64 man awk' } ] EXAMPLES.mkdir = [ { caption: 'one dir', code: 'mkdir proj' }, { caption: 'parents', code: 'mkdir -p a/b/c' } ] EXAMPLES.mkfifo = [ { caption: 'stub', code: '# FIFOs not on Hyperdrive — use shell pipelines' } ] EXAMPLES.mv = [ { caption: 'rename', code: 'mv old.txt new.txt' }, { caption: 'into dir', code: 'mv *.txt ~/inbox/' } ] EXAMPLES.nl = [{ caption: 'number all lines', code: 'nl README.md' }] EXAMPLES.od = [{ caption: 'hex dump vibe', code: 'od -c file.bin | head' }] EXAMPLES.pathchk = [ { caption: 'portable path check', code: 'pathchk -p "$HOME/file name"' } ] EXAMPLES.printenv = [ { caption: 'one variable', code: 'printenv HOME' }, { caption: 'all', code: 'printenv' } ] EXAMPLES.printf = [ { caption: 'format', code: 'printf "hex=%x dec=%d\\n" 255 255' }, { caption: 'no newline', code: 'printf "%s" OK' } ] EXAMPLES.pwd = [{ caption: 'where am I', code: 'pwd' }] EXAMPLES.readlink = [{ caption: 'symlink target', code: 'readlink ~/.config' }] EXAMPLES.rm = [ { caption: 'file', code: 'rm tmp.txt' }, { caption: 'tree', code: 'rm -rf build/' } ] EXAMPLES.rmdir = [{ caption: 'empty dir', code: 'rmdir olddir' }] EXAMPLES.savevault = [ { caption: 'snapshot encrypted vault', code: 'savevault' } ] EXAMPLES.sed = [ { caption: 'substitute first per line', code: "sed 's/foo/bar/' file.txt" }, { caption: 'global per line', code: "sed 's/ //g' spaced.txt" }, { caption: 'in-place (if supported)', code: "sed -i.bak 's/^/# /' f.cfg" }, { caption: 'print line 5 only', code: "sed -n '5p' file" }, { caption: 'delete blank lines', code: "sed '/^$/d' file" } ] EXAMPLES.seq = [ { caption: '1..10', code: 'seq 1 10' }, { caption: 'step', code: 'seq 0 2 20' } ] EXAMPLES.sleep = [{ caption: 'pause seconds', code: 'sleep 2' }] EXAMPLES.sort = [ { caption: 'lexicographic', code: 'sort names.txt' }, { caption: 'numeric', code: 'sort -n scores.txt' }, { caption: 'unique', code: 'sort -u tags.txt' } ] EXAMPLES.stat = [{ caption: 'metadata', code: 'stat ~/README.md' }] EXAMPLES.tail = [ { caption: 'last lines', code: 'tail -n 20 app.log' }, { caption: 'follow vibe (Bare: poll manually)', code: 'tail error.log' } ] EXAMPLES.tee = [ { caption: 'copy stdout to file', code: 'cat x | tee copy.txt | wc -l' } ] EXAMPLES.test = [ { caption: 'file exists', code: 'test -f ~/.barerc && echo yes' }, { caption: 'directory', code: 'test -d /home/user' }, { caption: 'string equal', code: 'test "$USER" = guest' } ] EXAMPLES.time = [{ caption: 'wall time a command', code: 'time sort big.txt' }] EXAMPLES.touch = [ { caption: 'create empty', code: 'touch newfile' }, { caption: 'refresh mtime', code: 'touch -c existing' } ] EXAMPLES.tr = [ { caption: 'uppercase', code: "echo hi | tr 'a-z' 'A-Z'" }, { caption: 'delete chars', code: "tr -d '\\r' < win.txt" } ] EXAMPLES.true = [{ caption: 'always success', code: 'true && echo ok' }] EXAMPLES.tty = [{ caption: 'am I a tty', code: 'tty' }] EXAMPLES.uname = [{ caption: 'kernel-ish info', code: 'uname -a' }] EXAMPLES.wc = [ { caption: 'lines words bytes', code: 'wc README.md' }, { caption: 'stdin only', code: 'cat f | wc -l' } ] EXAMPLES.which = [{ caption: 'resolve on PATH', code: 'which ls' }] EXAMPLES.whoami = [{ caption: 'effective user', code: 'whoami' }] EXAMPLES.xargs = [ { caption: 'pass lines as arguments', code: "printf 'a\\nb\\n' | xargs echo" }, { caption: 'one argument per run', code: "printf 'a\\nb\\n' | xargs -n1 echo" }, { caption: 'workaround for complex scripts', code: '# for f in *.txt; do grep -l foo $f; done' } ] /** @type {Record>} */ const EXTRA = {} EXTRA.chgrp = { description: 'Changing group ownership is not supported on Bare OS: Hyperdrive metadata is single-session oriented.', diagnostics: ['chgrp: changing group is not supported on Bare OS'], bareOsNotes: 'Single-user identity; gid fields exist for display only.' } EXTRA.chown = { description: 'Changing file owner is not supported on Bare OS (single-user Hyperdrive metadata).', diagnostics: ['chown: changing owner is not supported on Bare OS'], bareOsNotes: 'Use identity login/logout instead of POSIX ownership changes.' } EXTRA.xargs = { description: 'Reads stdin into argument batches and runs **`ctx.runBinCommand`** (same as the shell). Enforces stdin size, token count, batch size, and invocation limits for safety.', options: [ { flag: '-0, --null', meaning: 'Input items are null-terminated, not whitespace-separated' }, { flag: '-n, --max-args', meaning: 'Up to N arguments per utility invocation (capped at 128)' } ], bareOsNotes: 'No host process spawn; not full POSIX xargs (no -I, -P, etc.). See src/xargs.js for limits.' } EXTRA.getconf = { description: 'Prints a fixed subset of configuration limits for Bare OS (JavaScript runtime and VFS). There is no host sysconf(3); values are documented constants, not live kernel queries.', options: [ { flag: '-a', meaning: 'Write all known variables (name then value per pair)' } ], bareOsNotes: 'Unknown variable names exit with status 1. Not a full Issue 7 getconf implementation.' } EXTRA.mkfifo = { description: 'FIFO special files are not implemented on Hyperdrive. The command reports failure.', bareOsNotes: 'Documented stub; no real pipes as kernel objects.' } EXTRA.chmod = { synopsis: [ 'chmod MODE FILE...', 'MODE is octal (e.g. 644) or symbolic (e.g. u+rw)' ], description: 'Sets file mode bits on the VFS. Supports POSIX-style symbolic modes (u/g/o/a, +/-/=, rwxX) and octal modes.', options: [], keywords: ['chmod', 'mode', 'permission', 'octal', 'symbolic'], diagnostics: ['chmod: No such file', 'chmod: invalid mode'], bareOsNotes: 'Applies to Hyperdrive metadata; not a host inode.' } EXTRA.grep = { synopsis: [ 'grep [-E|-F] [-i] [-v] [-n] [-c] [-l] [-q] [-s] [-H|-h] [-e pat] ... [-f file] ... [pattern] [file...]' ], description: 'Searches input or files for lines matching a pattern. Uses JavaScript RegExp unless -F (fixed string). Not bit-identical to GNU grep.', options: [ { flag: '-E', meaning: 'Extended regex (accepted; patterns use JS RegExp)' }, { flag: '-F', meaning: 'Fixed string match' }, { flag: '-i', meaning: 'Ignore case' }, { flag: '-v', meaning: 'Invert match' }, { flag: '-n', meaning: 'Prefix lines with line number' }, { flag: '-c', meaning: 'Count matching lines only' }, { flag: '-l', meaning: 'List files with matches' }, { flag: '-q', meaning: 'Quiet (exit status only)' }, { flag: '-s', meaning: 'Suppress error messages' }, { flag: '-H / -h', meaning: 'Force / suppress filename prefix' }, { flag: '-e pat', meaning: 'Specify pattern' }, { flag: '-f file', meaning: 'Read patterns from file' } ], keywords: ['grep', 'search', 'regex', 'pattern', 'filter'], seeAlso: [ { name: 'sed', section: 1 }, { name: 'awk', section: 1 } ], bareOsNotes: 'UTF-16 strings and JS regex differ from strict POSIX/GNU.' } EXTRA.sed = { description: 'Stream editor with a subset of POSIX sed. Large engine is vendored in lib/sed-engine.js.', keywords: ['sed', 'stream', 'edit', 'substitute'], seeAlso: [ { name: 'awk', section: 1 }, { name: 'grep', section: 1 } ], bareOsNotes: 'JavaScript implementation; edge cases differ from GNU sed.' } EXTRA.awk = { description: 'Pattern-directed scanning and processing. Engine in lib/awk-engine.js; not full POSIX awk.', keywords: ['awk', 'pattern', 'field', 'script'], seeAlso: [ { name: 'sed', section: 1 }, { name: 'grep', section: 1 } ], bareOsNotes: 'See handbook ch.9 for divergence from Issue 7.' } EXTRA.dircolors = { synopsis: ['dircolors [-b] [FILE]', 'dircolors -p'], description: 'Print LS_COLORS from a dircolors database (GNU subset: TERM blocks, key/value pairs). -p prints the default Bare OS database.', options: [ { flag: '-b, --sh', meaning: 'Bourne-shell export LS_COLORS' }, { flag: '-p, --print-database', meaning: 'Print default database' } ], keywords: ['dircolors', 'LS_COLORS', 'color'], bareOsNotes: 'FILE read via VFS.' } EXTRA.theme = { synopsis: ['theme [list|current|set |apply]'], description: 'Switch Bare OS UI preset: updates ~/.barerc theme line, sets BARE_OS_THEME, calls bareOsApplyTheme when available.', keywords: ['theme', 'colors', 'prompt'], bareOsNotes: 'list/current work without booter hooks; set/apply need ctx.bareOsApplyTheme.' } EXTRA.ls = { synopsis: ['ls [-1al] [--color[=never|auto|always]] [FILE...]'], description: 'Lists directory contents. Long format shows mode, links, owner, group, size, mtime, and symlink targets. With color (default auto on a TTY), directories, symlinks, executables, and permission bits are highlighted.', options: [ { flag: '-a', meaning: 'Include names starting with .' }, { flag: '-l', meaning: 'Long listing' }, { flag: '-1', meaning: 'One name per line (short format)' }, { flag: '--color[=never|auto|always]', meaning: 'ANSI colors: never, auto (TTY only), or always; plain --color is auto' } ], environment: ['NO_COLOR — disable color even when a TTY or --color=always'], keywords: ['ls', 'list', 'directory', 'dir'], bareOsNotes: 'Hides .bareos_empty marker like other tools.' } EXTRA.man = { synopsis: [ 'man [-k keyword] [-f name] [-l] [[section] name]', 'man reads /share/man/man.json on the system drive.' ], description: 'Displays manual pages from the merged JSON database. Section 1: /bin and git/shell pages. Section 7: handbook (man handbook) and developer guide (man devguide), merged at build from handbook/*.md and developer-guide/*.md.', options: [ { flag: '-k, --apropos', meaning: 'Search keywords and titles (substring)' }, { flag: '-f, --whatis', meaning: 'One-line description for exact name' }, { flag: '-l, --list', meaning: 'List pages grouped by category (/bin, git/shell, handbook, developer guide), then alphabetically' } ], environment: [ 'MANWIDTH — wrap width (default 72, min 40)', 'NO_COLOR — disable bold headings on TTY' ], keywords: [ 'man', 'manual', 'help', 'documentation', 'apropos', 'whatis', 'cheat', 'examples' ], seeAlso: [ { name: 'help', section: 1 }, { name: 'bare-os-handbook', section: 7 }, { name: 'bare-os-developer-guide', section: 7 } ], bareOsNotes: 'No troff; no embedded DB fallback in v1.' } EXTRA.help = { synopsis: ['help'], description: 'Prints a one-screen summary of shell builtins and /bin command names. Use man for long-form documentation.', keywords: ['help', 'summary', 'builtins', 'commands'], seeAlso: [ { name: 'man', section: 1 }, { name: 'bare-os-shell', section: 1 } ] } EXTRA.exit = { synopsis: ['exit [status]'], description: 'When run as /bin/exit, requests the booter to end the session via ctx.requestBooterExit. Status defaults to 0.', bareOsNotes: 'Also available as a shell builtin with different wiring.' } EXTRA.hdms = { description: 'Invokes ctx.runHdms when the booter provides HDMS integration; otherwise prints unavailable.', keywords: ['hdms', 'hyperswarm', 'map'], bareOsNotes: 'Optional booter capability.' } EXTRA.find = { synopsis: ['find [PATH...] [EXPRESSION]'], description: 'Walks directories and applies expressions (-name, -type, -print, -maxdepth, logical -and/-or/-not).', keywords: ['find', 'directory', 'walk', 'search'], bareOsNotes: 'Expression syntax is a simplified subset.' } EXTRA.jq = { synopsis: [ 'jq [-n] [-R] [-s] [-c] [-r] [-e] [-f file] filter [file...]', 'jq reads JSON (concatenated values or NDJSON-style streams) from files or stdin.' ], description: 'Runs a jq filter program against JSON values. The engine is vendored jqjs (pure JavaScript), not the C implementation at https://github.com/jqlang/jq — language coverage and edge cases differ.', options: [ { flag: '-n, --null-input', meaning: 'Use null as the sole input (ignore file/stdin for input)' }, { flag: '-R, --raw-input', meaning: 'Treat each line as a string instead of JSON' }, { flag: '-s, --slurp', meaning: 'Read all inputs into one array; run the filter once' }, { flag: '-c, --compact-output', meaning: 'Compact JSON on output' }, { flag: '-r, --raw-output', meaning: 'Print strings without JSON quotes' }, { flag: '-e, --exit-status', meaning: 'Set exit status from outputs (no output → 4; last false/null → 1)' }, { flag: '-f, --from-file', meaning: 'Read filter program from file' } ], keywords: ['jq', 'json', 'query', 'filter', 'jqjs'], seeAlso: [ { name: 'grep', section: 1 }, { name: 'awk', section: 1 } ], bareOsNotes: 'Engine: lib/jq-engine.js from @sscots/jqjs (mwh/jqjs). Missing vs C jq: try/catch, user-defined functions, recurse, many builtins, modules, full Unicode. See upstream jqjs README for the feature matrix.', examples: [ { caption: 'pretty-print', code: 'jq . data.json' }, { caption: 'field', code: 'jq .version package.json' }, { caption: 'slurp array', code: "jq -s 'map(.x) | add' parts.jsonl" }, { caption: 'compact', code: "jq -c '.[] | select(.ok)' items.json" } ] } EXTRA.login = { description: 'When invoked from /bin, behavior aligns with session identity hooks (see booter). Prefer the shell builtin for passphrase entry.', keywords: ['login', 'identity', 'passphrase'], seeAlso: [{ name: 'logout', section: 1 }] } EXTRA.logout = { description: 'Ends session; may persist vault depending on booter and flags.', keywords: ['logout', 'session'], seeAlso: [{ name: 'login', section: 1 }] } EXTRA.savevault = { description: 'Encrypts a copy of the personal drive under /.bare/vault/ when identity services are available.', keywords: ['savevault', 'vault', 'encrypt', 'backup'], seeAlso: [{ name: 'login', section: 1 }] } function basePage(name) { const title = POSIX_TITLE[name] || name const p = { name, section: 1, title, synopsis: [`${name} [OPTION]... [OPERAND]...`], description: `Bare OS implementation of ${title}. Full behavior is defined in packages/bare-os-coreutils/src/${name}.js.`, options: [], keywords: [name, 'bare-os', 'coreutils'] } if (STUB.has(name)) { p.stub = true p.keywords.push('stub') } const ex = EXTRA[name] if (ex) Object.assign(p, ex) if (EXAMPLES[name]) p.examples = EXAMPLES[name] return p } function gitPage() { return { name: 'git', section: 1, title: 'Bare OS git front-end (isomorphic-git)', synopsis: ['git [-C dir] [ARGUMENTS...]'], description: 'Runs isomorphic-git against the VFS-backed adapter. Remote HTTP(S) uses BARE_OS_GIT_HTTP when set; otherwise Pear bare module fetch.', options: [{ flag: '-C dir', meaning: 'Run as if git was started in dir' }], environment: [ 'BARE_OS_GIT_HTTP — optional fetch implementation for remotes', 'GIT_* — standard hints where supported' ], keywords: [ 'git', 'version control', 'repository', 'clone', 'commit', 'isomorphic-git' ], bareOsNotes: 'Not a separate /bin script; booter delegates argv[0]=git to git-cli.js.', seeAlso: [{ name: 'bare-os-shell', section: 1 }], examples: [ { caption: 'new repo', code: 'git init -C ~/myrepo' }, { caption: 'status', code: 'git -C ~/myrepo status' }, { caption: 'clone over HTTP (needs remote + fetch)', code: 'git clone https://example.com/repo.git ~/work/repo' }, { caption: 'config local', code: 'git -C ~/myrepo config user.email "you@example.com"' }, { caption: 'log one line', code: 'git -C ~/myrepo log --oneline -5' } ] } } function curlPage() { return { name: 'curl', section: 1, title: 'transfer a URL (Fetch-based client, not libcurl)', synopsis: [ 'curl [options] URL...', 'curl uses Fetch in the booter (Node fetch or bare-fetch), not libcurl.' ], description: 'HTTP/HTTPS client delegated from the booter. Subset of curl(1) flags; see man page JSON for full options and exit codes.', options: [ { flag: '-X, --request METHOD', meaning: 'HTTP method' }, { flag: '-H, --header LINE', meaning: 'Request header (repeatable)' }, { flag: '-d, --data / --json', meaning: 'Request body' }, { flag: '-o, --output FILE', meaning: 'Write response to VFS path' }, { flag: '-T, --upload-file PATH', meaning: 'PUT file from VFS' }, { flag: '-I / -i / -L / -f / -s / -S / -v / -u / -m / -w', meaning: 'See full man curl.json' } ], keywords: ['curl', 'http', 'https', 'fetch', 'download'], bareOsNotes: 'Not https://curl.se libcurl; booter curl-cli.js. URLs: http(s), data:, file://.', seeAlso: [ { name: 'git', section: 1 }, { name: 'jq', section: 1 } ] } } function wgetPage() { return { name: 'wget', section: 1, title: 'non-interactive network download (Fetch-based, not GNU wget2)', synopsis: [ 'wget [options] URL...', 'wget is implemented in the booter with the Fetch API (Node fetch or bare-fetch), not the C GNU wget2 tree.' ], description: 'Downloads resources over HTTP or HTTPS into the VFS. Bare OS does not ship GNU wget or wget2 (C); this command is a small compatibility-oriented subset built on JavaScript fetch. It is delegated from the booter (like curl and git), not loaded from a /bin script on the system drive.', options: [ { flag: '-O, --output-document FILE', meaning: 'Write the body to FILE; use - for stdout. Only one URL allowed.' }, { flag: '-P, --directory-prefix DIR', meaning: 'Save under DIR using a name derived from the URL (last path segment, or index.html if the path ends with /)' }, { flag: '-q, --quiet', meaning: 'Suppress non-error messages on stderr (saved path lines)' }, { flag: '-U, --user-agent STRING', meaning: 'Set User-Agent request header' }, { flag: '-T, --timeout SECONDS', meaning: 'Abort the request after SECONDS (AbortController)' }, { flag: '--header LINE', meaning: 'Extra header Name: value (repeatable)' }, { flag: '--post-data STRING', meaning: 'POST body (sets method POST; default Content-Type application/x-www-form-urlencoded)' }, { flag: '--post-file PATH', meaning: 'POST body read from a file on the VFS' }, { flag: '-V, --version', meaning: 'Print Bare OS wget version string' }, { flag: '-h, --help', meaning: 'Short usage' } ], environment: [], keywords: ['wget', 'download', 'http', 'https', 'fetch', 'mirror'], bareOsNotes: 'Not GNU wget2 (https://gitlab.com/gnuwget/wget2). URLs must start with http://, https://, data:, or file://. No recursive retrieval, FTP, or WARC. Cannot combine -O and -P. On Pear/Bare, use bare-fetch for global fetch. Tests may set ctx.httpFetch.', seeAlso: [ { name: 'curl', section: 1 }, { name: 'git', section: 1 } ], examples: [ { caption: 'save with default name in cwd', code: 'wget https://example.com/README' }, { caption: 'choose output path', code: 'wget -O ~/page.html https://example.com/' }, { caption: 'directory prefix', code: 'wget -P ~/dl https://example.com/a/b.bin' }, { caption: 'stdout', code: 'wget -O - -q https://example.com/robots.txt' } ], exitStatus: [ '0 — success', '1 — generic error (reserved)', '2 — bad usage or options', '3 — file I/O error (e.g. --post-file unreadable)', '4 — network failure or no fetch implementation', '8 — HTTP 4xx/5xx response' ] } } function shellPage() { return { name: 'bare-os-shell', section: 1, title: 'Bare OS interactive shell builtins', synopsis: ['# builtins only — no full POSIX sh grammar'], description: 'The line-at-a-time shell supports aliases, simple pipelines (simulated), redirection, and the builtins below. Compound commands (if, for, while) are not available.', options: [], aliases: ['sh-builtins'], keywords: [ 'shell', 'builtin', 'cd', 'export', 'alias', 'bare-os-shell', 'sh-builtins' ], builtins: [ { name: 'alias', synopsis: ['alias', 'alias name=value ...', 'unalias name ...'], description: 'Define or list command aliases. unalias removes definitions.' }, { name: 'cd', synopsis: ['cd [DIR]'], description: 'Change working directory via vfs.chdir; default is HOME.' }, { name: 'export', synopsis: ['export NAME=value ...'], description: 'Set environment variables visible to child /bin invocations.' }, { name: 'unset', synopsis: ['unset NAME ...'], description: 'Remove variables; readonly names cannot be unset.' }, { name: 'readonly', synopsis: ['readonly NAME[=value] ...'], description: 'Mark variables read-only.' }, { name: 'umask', synopsis: ['umask [octal]'], description: 'Show or set shell file creation mask (stored in env UMASK).' }, { name: 'command', synopsis: ['command -v|-V NAME', 'command ARGV...'], description: 'Resolve or run a command without using shell functions (none) or aliases for -v/-V.' }, { name: 'type', synopsis: ['type NAME'], description: 'Report whether NAME is a builtin or a path under PATH.' }, { name: 'login / logout', synopsis: ['login [--new] passphrase...', 'logout [--save]'], description: 'Identity unlock/register and session teardown; require booter hooks.' }, { name: ':', synopsis: [':'], description: 'No-op builtin.' }, { name: 'exit', synopsis: ['exit [n]'], description: 'Request booter exit with status n (builtin path).' } ], seeAlso: [ { name: 'help', section: 1 }, { name: 'man', section: 1 } ], bareOsNotes: 'Pipelines do not use OS pipes; see handbook ch.4 and ch.9.', examples: [ { caption: 'pipeline (simulated)', code: 'ls -1 /bin | grep man' }, { caption: 'redirect out', code: 'echo hi > ~/hello.txt' }, { caption: 'append', code: 'date >> ~/log.txt' }, { caption: 'alias + use', code: "alias ll='ls -la'\nll ~" }, { caption: 'export for children', code: 'export EDITOR=ed\nman ls' }, { caption: 'temp var for one command', code: 'PATH=/bin man which' } ] } } async function main() { await mkdir(pagesDir, { recursive: true }) for (const name of COREUTILS_COMMANDS) { const p = basePage(name) await writeFile( join(pagesDir, `${name}.json`), JSON.stringify(p, null, 2) + '\n' ) } for (const name of MAN_EXTRA_PAGES) { const p = name === 'git' ? gitPage() : name === 'curl' ? curlPage() : name === 'wget' ? wgetPage() : shellPage() await writeFile( join(pagesDir, `${name}.json`), JSON.stringify(p, null, 2) + '\n' ) } } await main()