890 lines
31 KiB
JavaScript
890 lines
31 KiB
JavaScript
/**
|
|
* 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', 'mkfifo'])
|
|
|
|
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<string, Array<{ caption?: string, code: string }>>}
|
|
*/
|
|
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<string, Record<string, unknown>>} */
|
|
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.ls = {
|
|
synopsis: ['ls [-1al] [FILE...]'],
|
|
description:
|
|
'Lists directory contents. Long format shows mode, links, owner, group, size, mtime, and symlink targets.',
|
|
options: [
|
|
{ flag: '-a', meaning: 'Include names starting with .' },
|
|
{ flag: '-l', meaning: 'Long listing' },
|
|
{ flag: '-1', meaning: 'One name per line (short format)' }
|
|
],
|
|
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] <subcommand> [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 "[email protected]"'
|
|
},
|
|
{ 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()
|