{"protected":false,"mode":"f","metadata":{"name":"mrrp","author":"Luna Magdalena :3","version":[1,2],"dependencies":[],"paths":{"mrrp.js":"%B/mrrp.js","mrrp":"%D/mrrp","mrrp.packaging":"%D/mrrp.packaging"}},"content":"{\"mrrp.js\":{\"protected\":true,\"metadata\":{\"runner\":[]},\"mode\":\"f\",\"content\":\"let yarnball\\nlet repoNode = fs.getNode(\\\"/itty/repos.json\\\")\\nlet repoList = JSON.parse(repoNode.content)\\nlet pkgList\\nlet updateList = []\\nlet world = io.flines(fs.getNode(\\\"/itty/world\\\")).filter(Boolean)\\nlet unwantedPkgs\\n\\n// we use some env vars, parse them\\nconst dirs = {\\n bin: fs.resolve(itty.env.dir_bin).slice(0, -1) || \\\"/itty/bin\\\",\\n docs: fs.resolve(itty.env.dir_docs).slice(0, -1) || \\\"/itty/docs\\\",\\n conf: fs.resolve(itty.env.dir_conf) + \\\"examples\\\" || \\\"/conf/examples\\\",\\n lib: fs.resolve(itty.env.dir_lib).slice(0, -1) || \\\"/itty/lib\\\"\\n}\\n\\n// cache repo indexes, so querying and updating is faster\\nlet repoCache = fs.getNode(\\\"/.tmp/mrrp/repocache\\\")\\nif (!repoCache) {\\n fs.makeDir(\\\"/.tmp/mrrp/\\\")\\n fs.makeNode(\\\"/.tmp/mrrp/repocache\\\", \\\"f\\\")\\n await refreshCache()\\n} else {\\n repoCache = JSON.parse(repoCache.content) \\n}\\n\\n// refresh the repo cache!\\nasync function refreshCache() {\\n repoCache = fs.getNode(\\\"/.tmp/mrrp/repocache\\\")\\n const list = {}\\n for (let r of Object.entries(repoList)) {\\n let rj\\n try {\\n rj = await fetch(r[1].url + \\\"repo.json\\\")\\n rj = await rj.json()\\n } catch {\\n display.print(\\\"Cannot fetch repository info for \\\" + r[0], 0x9000)\\n continue\\n }\\n rj.url = r[1].url\\n list[r[0]] = rj\\n }\\n repoCache.content = JSON.stringify(list)\\n repoCache = list\\n}\\n\\n// confirmation as to whether to do things\\nasync function ask(message) {\\n const res = await io.read([[message + \\\" [y/N]: \\\"]])\\n\\n if (res.toLowerCase() !== \\\"y\\\" && res.toLowerCase() !== \\\"yes\\\") {\\n display.print(\\\"Aborting...\\\", 0x9000)\\n return false\\n }\\n\\n display.print(\\\"Proceeding...\\\", 0x3000)\\n return true\\n}\\n\\n// install a program\\nasync function install(yarnball, reponame, interactive = true, wanted) {\\n wanted = wanted || world.includes(yarnball.metadata.name)\\n\\n const listNode = fs.getNode(\\\"/itty/packages.json\\\")\\n let list = JSON.parse(listNode.content)\\n\\n // substitute %B, %C and %D in paths with env vars\\n for (let path of Object.keys(yarnball.metadata.paths)) {\\n let p = yarnball.metadata.paths[path]\\n p = p.replaceAll(\\\"%B\\\", dirs.bin)\\n p = p.replaceAll(\\\"%D\\\", dirs.docs)\\n p = p.replaceAll(\\\"%C\\\", dirs.conf)\\n p = p.replaceAll(\\\"%L\\\", dirs.lib)\\n yarnball.metadata.paths[path] = p\\n }\\n\\n // ask the user!\\n if (interactive) {\\n const v = yarnball.metadata.version\\n display.print(\\\"Installing \\\" + yarnball.metadata.name + \\\" version \\\" + v[0] + (v[1] ? \\\".\\\" + v[1] : \\\".0\\\") + (v[2] ? \\\".\\\" + v[2] : \\\"\\\") + \\\" from \\\" + reponame, 0x5000)\\n display.print(\\\"Warning: this will affect the following path(s):\\\", 0x2000)\\n for (let path in yarnball.metadata.paths) {\\n display.print(yarnball.metadata.paths[path], 0x2000)\\n }\\n if (yarnball.metadata.dependencies.length)\\n display.print(\\\"The following dependencies also need to be installed:\\\", 0x6000)\\n for (let d of yarnball.metadata.dependencies) {\\n if (!list[d])\\n display.print(d, 0x6000)\\n }\\n if (!await ask(\\\"Proceed?\\\"))\\n return\\n }\\n\\n // uninstall if already installed\\n if (list[yarnball.metadata.name])\\n await uninstall(yarnball.metadata.name, false)\\n\\n // unspool the yarnball\\n fs.removeNode(\\\"/.tmp/mrrp/x\\\")\\n fs.makeDir(\\\"/.tmp/mrrp/x\\\")\\n const node = fs.getNode(\\\"/.tmp/mrrp/x\\\")\\n let content\\n\\n try {\\n content = JSON.parse(yarnball.content)\\n } catch {\\n io.error([5, \\\"Cannot parse yarnball\\\"])\\n }\\n\\n for (let file of Object.keys(content)) {\\n if (node.content[file])\\n continue\\n const obj = content[file]\\n node.content[file] = obj\\n }\\n fs.refreshPathAttributes(node)\\n\\n // move files accordingly\\n for (let path of Object.entries(yarnball.metadata.paths)) {\\n const paths = fs.splitPath(path[1])\\n makeDir(paths[0])\\n const parent = fs.getNode(paths[0])\\n parent.content[paths[1]] = fs.getNode(\\\"/.tmp/mrrp/x/\\\" + path[0], false)\\n fs.refreshPathAttributes(parent)\\n }\\n\\n // keep track!\\n list[yarnball.metadata.name] = {\\n name: yarnball.metadata.name,\\n repo: reponame,\\n version: yarnball.metadata.version,\\n paths: [],\\n dependencies: yarnball.metadata.dependencies\\n }\\n\\n for (let path of Object.entries(yarnball.metadata.paths))\\n list[yarnball.metadata.name].paths.push(path[1])\\n\\n listNode.content = JSON.stringify(list)\\n\\n if (wanted && !world.includes[yarnball.metadata.name])\\n world.push(yarnball.metadata.name)\\n\\n if (interactive)\\n display.print(\\\"Package \\\" + yarnball.metadata.name + \\\" installed\\\", 0x6000)\\n\\n // handle dependencies but after install because we only keep one package in the cache hehe this is awful i'm sorry\\n for (let d of yarnball.metadata.dependencies) {\\n if (list[d])\\n continue\\n const reponame = await fetchPkg(d)\\n if (!reponame) {\\n display.print(\\\"Could not install dependency \\\" + d, 0x9000)\\n continue\\n }\\n const yarnball = fs.getNode(\\\"/.tmp/mrrp/dl/yarn\\\")\\n await install(yarnball, reponame, interactive)\\n }\\n}\\n\\nasync function uninstall(package, interactive = true) {\\n const listNode = fs.getNode(\\\"/itty/packages.json\\\")\\n let list = JSON.parse(listNode.content)\\n\\n const pkginfo = list[package]\\n if (!pkginfo) {\\n if (interactive)\\n display.print(\\\"Package is not installed\\\", 0x6000)\\n return\\n }\\n \\n // ask the user!\\n if (interactive) {\\n display.print(\\\"Removing \\\" + pkginfo.name, 0x5000)\\n display.print(\\\"Warning: this will affect the following path(s):\\\", 0x2000)\\n for (let path of pkginfo.paths)\\n display.print(path, 0x2000)\\n \\n if (!await ask(\\\"Proceed?\\\"))\\n return\\n }\\n\\n // actually remove\\n for (let path of pkginfo.paths) {\\n const paths = fs.splitPath(path)\\n delete fs.getNode(paths[0]).content[paths[1]]\\n }\\n\\n delete list[pkginfo.name]\\n list = JSON.stringify(list)\\n listNode.content = list\\n\\n const i = world.indexOf(pkginfo.name)\\n if (i > -1)\\n world.splice(i)\\n\\n if (interactive)\\n display.print(\\\"Package removed\\\", 0x6000)\\n}\\n\\nasync function fetchPkg(package, repo, reponame, interactive = true) {\\n let repojson\\n let rlist = []\\n if (repo) {\\n repojson = repo\\n \\n if (!repojson) {\\n display.print(\\\"Cannot find repository info for \\\" + reponame, 0x2000)\\n io.error([1, \\\"Cannot find repository info\\\"])\\n }\\n } else {\\n // look for package in repos\\n for (let r of Object.entries(repoCache)) {\\n let rj = r[1]\\n \\n if (rj.packages[package])\\n rlist.push([r[0], r[1], rj])\\n }\\n \\n switch (rlist.length) {\\n case 0:\\n display.print(\\\"Cannot find package \\\" + package, 0x9000)\\n return false\\n case 1:\\n repojson = rlist[0][2]\\n repo = rlist[0][1]\\n reponame = rlist[0][0]\\n break\\n case 2:\\n display.print(\\\"Package \\\" + package + \\\" is available in the following repositories:\\\", 0x5000)\\n for (let i=0; i < rlist.length; i++) {\\n const v = rlist[i][2].packages[package].version\\n display.buffer(\\\"[\\\" + (i + 1) + \\\"] \\\")\\n display.buffer(rlist[i][0], 0x2000)\\n display.print(\\\" v\\\" + v[0] + (v[1] ? \\\".\\\" + v[1] : \\\".0\\\") + (v[2] ? \\\".\\\" + v[2] : \\\"\\\"), 0x4000)\\n }\\n const sel = await io.read([[\\\"Selection: \\\"]])\\n if (!sel)\\n return false\\n else {\\n repojson = rlist[sel-1][2]\\n repo = rlist[sel-1][1]\\n reponame = rlist[sel-1][0]\\n }\\n }\\n }\\n\\n // download\\n\\n let pkg\\n try {\\n pkg = await fetch(repojson.packages[package].url.replace(/^~/, repo.url))\\n pkg = await pkg.json()\\n } catch {\\n display.print(\\\"Cannot fetch package \\\" + package + \\\" from repository \\\" + reponame, 0x9000)\\n throw [2, \\\"Cannot fetch package\\\"]\\n }\\n\\n fs.removeNode(\\\"/.tmp/mrrp/dl\\\")\\n fs.makeDir(\\\"/.tmp/mrrp/dl\\\")\\n const dl = fs.getNode(\\\"/.tmp/mrrp/dl\\\")\\n dl.content.yarn = pkg\\n fs.refreshPathAttributes(dl)\\n\\n return reponame\\n}\\n\\nfunction want(package) {\\n const index = unwantedPkgs.indexOf(package)\\n if (index > -1)\\n unwantedPkgs.splice(index)\\n\\n if (pkgList[pkg])\\n for (let dep of pkgList[package].dependencies)\\n want(dep)\\n}\\n\\nswitch (args[0]) {\\n case \\\"yarn\\\":\\n if (args.length < 2) {\\n display.print(\\\"Not enough arguments\\\", 0x1000)\\n quit()\\n }\\n try {\\n yarnball = fs.getNode(args[1])\\n } catch {\\n io.error([1, \\\"Cannot find yarnball\\\"])\\n }\\n\\n await install(yarnball, \\\"local yarnball\\\", true, true)\\n break\\n case \\\"uninstall\\\":\\n case \\\"remove\\\":\\n if (args.length < 2) {\\n display.print(\\\"Not enough arguments\\\", 0x1000)\\n quit()\\n }\\n await uninstall(args[1])\\n break\\n case \\\"list-repos\\\":\\n for (let repo of Object.entries(repoList)) {\\n display.write(repo[0] + \\\" \\\", 0x2000)\\n display.print(repo[1].url)\\n }\\n break\\n case \\\"remove-repo\\\":\\n if (args.length < 2) {\\n display.print(\\\"Not enough arguments\\\", 0x1000)\\n quit()\\n }\\n delete repoList[args[1]]\\n repoNode.content = JSON.stringify(repoList)\\n display.print(\\\"Removed repo \\\" + args[1], 0x6000)\\n await refreshCache()\\n break\\n case \\\"add-repo\\\":\\n if (args.length < 3) {\\n display.print(\\\"Not enough arguments\\\", 0x1000)\\n quit()\\n }\\n \\n args[2] = args[2].replace(/([^\\\\/])$/, \\\"$1/\\\")\\n\\n // fetch repo\\n try {\\n repo = await fetch(args[2] + \\\"repo.json\\\")\\n } catch {\\n display.print(\\\"Cannot fetch repository info\\\", 0x9000)\\n quit()\\n }\\n\\n if (repoList[args[1]]) {\\n display.print(\\\"Repository \\\" + args[1] + \\\" already exists.\\\", 0x2000)\\n if (!await ask(\\\"Overwrite?\\\"))\\n quit()\\n }\\n\\n repoList[args[1]] = {\\n url: args[2]\\n }\\n\\n repoNode.content = JSON.stringify(repoList)\\n display.print(\\\"Added repo \\\" + args[1] + \\\" with url \\\" + args[2], 0x6000)\\n await refreshCache()\\n break\\n case \\\"install\\\":\\n if (args.length < 2) {\\n display.print(\\\"Not enough arguments\\\", 0x1000)\\n quit()\\n }\\n const reponame = await fetchPkg(args[1])\\n if (!reponame)\\n quit()\\n yarnball = fs.getNode(\\\"/.tmp/mrrp/dl/yarn\\\")\\n await install(yarnball, reponame, true, true)\\n break\\n case \\\"refresh-repos\\\":\\n await refreshCache()\\n display.print(\\\"Refreshed repository cache\\\", 0x6000)\\n break\\n case \\\"update\\\":\\n try {\\n pkgList = JSON.parse(fs.getNode(\\\"/itty/packages.json\\\").content)\\n } catch {\\n display.print(\\\"Cannot parse package list\\\", 0x9000)\\n quit() \\n }\\n\\n for (let pkg of Object.entries(pkgList)) {\\n if (pkg[1].repo === \\\"local yarnball\\\" || !repoCache[pkg[1].repo])\\n continue\\n\\n const iv = pkg[1].version\\n const rv = repoCache[pkg[1].repo].packages[pkg[0]].version\\n\\n iv[1] = iv[1] || 0\\n iv[2] = iv[2] || 0\\n rv[1] = rv[1] || 0\\n rv[2] = rv[2] || 0\\n\\n if (rv[0] > iv[0] || rv[0] == iv[0] && rv[1] > iv[1] || rv[0] == iv[0] && rv[1] == iv[1] && rv[2] > iv[2])\\n updateList.push([pkg[0], pkg[1].repo, repoCache[pkg[1].repo]])\\n }\\n\\n if (!updateList.length) {\\n display.print(\\\"No packages need updating\\\", 0x3000)\\n quit()\\n }\\n\\n if (args[1] !== \\\"bg\\\") {\\n display.print(\\\"Packages to update:\\\", 0x6000)\\n for (let pkg of updateList)\\n display.print(pkg[0], 0x2000)\\n if (!await ask(\\\"Proceed?\\\"))\\n quit()\\n }\\n\\n for (let pkg of updateList) {\\n let f\\n try {\\n f = await fetchPkg(pkg[0], pkg[2], pkg[1], false)\\n } catch {\\n if (args[1] !== \\\"bg\\\")\\n display.print(\\\"Could not fetch \\\" + pkg[0] + \\\" from \\\" + pkg[1], 0x1000)\\n continue\\n }\\n if (f) {\\n yarnball = fs.getNode(\\\"/.tmp/mrrp/dl/yarn\\\")\\n await install(yarnball, pkg[1], false)\\n }\\n }\\n\\n if (args[1] !== \\\"bg\\\")\\n display.print(\\\"Updated packages\\\", 0x3000)\\n break\\n case \\\"list\\\":\\n try {\\n pkgList = JSON.parse(fs.getNode(\\\"/itty/packages.json\\\").content)\\n } catch {\\n display.print(\\\"Cannot parse package list\\\", 0x9000)\\n quit() \\n }\\n\\n for (let pkg of Object.entries(pkgList)) {\\n display.buffer(pkg[0], 0x6000)\\n const v = pkg[1].version\\n display.buffer(\\\" v\\\" + v[0] + (v[1] ? \\\".\\\" + v[1] : \\\".0\\\") + (v[2] ? \\\".\\\" + v[2] : \\\"\\\") + \\\" \\\", 0x4000)\\n display.buffer(\\\"(\\\")\\n display.buffer(pkg[1].repo, 0x2000)\\n display.print(\\\")\\\")\\n }\\n break\\n case \\\"query\\\":\\n if (args.length < 2) {\\n display.print(\\\"Not enough arguments\\\", 0x1000)\\n quit()\\n }\\n try {\\n pkgList = JSON.parse(fs.getNode(\\\"/itty/packages.json\\\").content)\\n } catch {\\n display.print(\\\"Cannot parse package list\\\", 0x9000)\\n quit() \\n }\\n \\n for (let repo of Object.entries(repoCache)) {\\n for (let pkg of Object.entries(repo[1].packages)) {\\n if (pkg[0].match(args[1])) {\\n display.buffer(\\\"[\\\")\\n display.buffer(repo[0], 0x2000)\\n display.buffer(\\\"]\\\\t\\\")\\n display.buffer(pkg[0], 0x6000)\\n const v = pkg[1].version\\n display.buffer(\\\" v\\\" + v[0] + (v[1] ? \\\".\\\" + v[1] : \\\".0\\\") + (v[2] ? \\\".\\\" + v[2] : \\\"\\\"), 0x4000)\\n if (pkgList[pkg[0]] && pkgList[pkg[0]].repo == repo[0]) {\\n display.buffer(\\\"\\\\t(\\\")\\n const v = pkgList[pkg[0]].version\\n if (pkg[1].version[0] != v[0] || pkg[1].version[1] != v[1] || pkg[1].version[2] != v[2])\\n display.buffer(\\\"v\\\" + v[0] + (v[1] ? \\\".\\\" + v[1] : \\\".0\\\") + (v[2] ? \\\".\\\" + v[2] : \\\"\\\") + \\\" \\\", 0x5000)\\n display.buffer(\\\"installed\\\", 0x5000)\\n display.buffer(\\\")\\\")\\n }\\n display.write(\\\"\\\\n\\\")\\n }\\n }\\n }\\n break\\n case \\\"prune\\\":\\n try {\\n pkgList = JSON.parse(fs.getNode(\\\"/itty/packages.json\\\").content)\\n } catch {\\n display.print(\\\"Cannot parse package list\\\", 0x9000)\\n quit() \\n }\\n unwantedPkgs = Object.keys(pkgList)\\n\\n for (let pkg of world)\\n want(pkg)\\n\\n if (unwantedPkgs.length) {\\n display.print(\\\"The following packages will be removed:\\\", 0x6000)\\n for (let pkg of unwantedPkgs)\\n display.print(pkg, 0x2000)\\n\\n if (await ask(\\\"Proceed?\\\"))\\n for (let pkg of unwantedPkgs)\\n uninstall(pkg, false)\\n } else\\n display.print(\\\"No unwanted packages to remove\\\", 0x3000)\\n break\\n case \\\"batch\\\":\\n if (args.length < 2) {\\n display.print(\\\"Not enough arguments\\\", 0x1000)\\n quit()\\n }\\n const batchList = io.flines(fs.getNode(args[1])).filter(Boolean)\\n if (!batchList) {\\n display.print(\\\"Cannot find file\\\", 0x9000)\\n quit()\\n }\\n for (let pkg of batchList) {\\n const reponame = await fetchPkg(pkg)\\n if (!reponame)\\n quit()\\n yarnball = fs.getNode(\\\"/.tmp/mrrp/dl/yarn\\\")\\n await install(yarnball, reponame, true, true)\\n }\\n}\\n\\nconst worldfile = io.open(\\\"/itty/world\\\", \\\"w\\\")\\nfor (let w of world)\\n worldfile.print(w)\\nworldfile.writeOut()\\n\\nquit()\\n\\n// fs functions but copies that don't care about protectedness\\nfunction makeNode(path, mode) {\\n path = fs.resolve(path)\\n\\n // mode is bad?\\n if (mode != \\\"d\\\" && mode != \\\"f\\\")\\n throw [2, \\\"Invalid mode\\\"]\\n\\n // skip if it exists\\n const node = fs.getNode(path)\\n if (node && node.mode === \\\"d\\\")\\n return\\n else if (node)\\n throw [1, \\\"Node already exists\\\"]\\n\\n const paths = fs.splitPath(path)\\n const parentNode = fs.getNode(paths[0])\\n const pathEnd = paths[1]\\n\\n if (!parentNode)\\n throw [10, \\\"Parent node does not exist\\\"]\\n\\n // make the node\\n parentNode.content[pathEnd] = {\\n mode: mode,\\n protected: parentNode.protected ? true : false,\\n content: mode === \\\"d\\\" ? {} : \\\"\\\",\\n }\\n fs.setPathAttributes(parentNode.content[pathEnd], parentNode, pathEnd)\\n}\\n\\nfunction makeDir(path) {\\n path = fs.resolve(path)\\n const pathArray = path.split(\\\"/\\\").filter(Boolean)\\n let currentPath = \\\"\\\"\\n for (let part of pathArray) {\\n currentPath += \\\"/\\\" + part\\n makeNode(currentPath, \\\"d\\\")\\n }\\n}\\n\\nfunction onQuit() {\\n fs.save()\\n}\"},\"mrrp\":{\"protected\":false,\"metadata\":{},\"mode\":\"f\",\"content\":\"\\u0011[sD050]MRRP - Manager for Retrieving and Removing Packages\\u0011[s7000]\\n\\n\\t\\u0011[s4000]mrrp.packaging\\u0011[s7000]\\n\\nMRRP is a simple package manager for itty. it features a world file, and allows installing packages from yarnballs and remote repositories, as well as updating these packages\\n\\n\\u0011[s5040]Usage\\u0011[s7000]\\n\\tmrrp \\u0011[s6040]subcommand\\n\\n\\u0011[s4020]Subcommands:\\n\\t\\u0011[s6010]yarn \\u0011[s2040]path-to-yarnball\\u0011[s7000]\\n\\t\\tattempt to install a package from a yarnball\\n\\t\\u0011[s6010]install \\u0011[s2040]package\\u0011[s7000]\\n\\t\\tattempt to install a package from the remote repositories\\n\\t\\u0011[s6010]remove \\u0011[s2040]package\\u0011[s7000]\\n\\t\\tremove the package from the system\\n\\t\\u0011[s6010]update\\u0011[s7000]\\n\\t\\tsearch repositories for package updates and install them\\n\\t\\u0011[s6010]list\\u0011[s7000]\\n\\t\\tshow a list of all installed packages\\n\\t\\u0011[s6010]query \\u0011[s2040]package\\u0011[s7000]\\n\\t\\tsearch for a string in the remote repositories and show a list of matching packages\\n\\t\\u0011[s6010]prune\\u0011[s7000]\\n\\t\\tremove unwanted packages (those not in \\u0011[sA000]world\\u0011[s7000] and unneeded dependencies)\\n\\t\\u0011[s6010]batch \\u0011[s2040]path-to-file\\u0011[s7000]\\n\\t\\tinstall all packages listed in the given file, which must only contain exact package names separated by newlines\\n\\t\\u0011[s6010]list-repos\\u0011[s7000]\\n\\t\\tlist all repositories that \\u0011[sA000]mrrp\\u0011[s7000] is configured to use\\n\\t\\u0011[s6010]add-repo \\u0011[s2040]repo\\u0011[s0000] \\u0011[s2040]url\\u0011[s7000]\\n\\t\\tadd a repository under the given name, with the provided url\\n\\t\\u0011[s6010]remove-repo \\u0011[s2040]repo\\u0011[s7000]\\n\\t\\tremove a repository from the list\\n\\t\\u0011[s6010]refresh-repos\\u0011[s7000]\\n\\t\\tupdate cached repository data\\n\\n\\u0011[s5040]Environment\\u0011[s7000]\\n\\u0011[sC000]- \\u0011[s6020]dir_bin\\u0011[s7000] (\\u0011[sE000]string\\u0011[s7000]): the directory to install programs to\\n\\u0011[sC000]- \\u0011[s6020]dir_lib\\u0011[s7000] (\\u0011[sE000]string\\u0011[s7000]): the directory to install libraries to\\n\\u0011[sC000]- \\u0011[s6020]dir_conf\\u0011[s7000] (\\u0011[sE000]string\\u0011[s7000]): the directory to install example config files to. example config files go in the \\u0011[sA000]/example\\u0011[s7000] subdirectory of this directory\\n\\u0011[sC000]- \\u0011[s6020]dir_docs\\u0011[s7000] (\\u0011[sE000]string\\u0011[s7000]): the directory to install documentation to\\n\\n\\u0011[s5040]Files\\u0011[s7000]\\n\\u0011[sC000]- \\u0011[s2040]/itty/world\\u0011[s7000]: a newline separated list of packages wanted by the user. this is used to distinguish wanted and unwanted dependencies\\n\\u0011[sC000]- \\u0011[s2040]/itty/packages.json\\u0011[s7000]: JSON containing information about installed packages, such as their files, dependencies, version and repo\\n\\u0011[sC000]- \\u0011[s2040]/itty/repos.json\\u0011[s7000]: JSON containing a list of remote repositories and their URLs\"},\"mrrp.packaging\":{\"protected\":false,\"metadata\":{},\"mode\":\"f\",\"content\":\"\\u0011[sD050]Packaging for MRRP\\u0011[s7000]\\n\\n \\u0011[s4000] mrrp\\n\\n\\u0011[s5040]Creating a package yarnball\\u0011[s7000]\\nif what you are packaging is a \\u0011[sA000]program\\u0011[s7000], then the file needs to be executable. check \\u0011[sA000]exec.md\\u0011[s7000] in the itty docs for instructions on how to do that\\n\\nsecond, itty packages are \\u0011[sA000]yarnfiles\\u0011[s7000], you can make a yarnfile from itty with the \\u0011[sA000]yarn\\u0011[s7000] utility, or from a non-itty device with the \\u0011[sA000]thread\\u0011[s7000] utility provided in the \\u0011[sA000]utils\\u0011[s7000] directory of the itty repository\\n\\nthe files inside your yarnball should be the files you are going to package, and the yarnball's metadata should contain the following fields:\\n- \\u0011[s6000]name\\u0011[s7000]: this is the package name, the user will use this name when looking up the package or uninstalling it\\n- \\u0011[s6000]version\\u0011[s7000]: this an array with 3 integer values, the \\u0011[sA000]major version\\u0011[s7000], \\u0011[sA000]minor version\\u0011[s7000] and \\u0011[sA000]patch version\\u0011[s7000]. the package manager will use this to know whether your package has received an update\\n- \\u0011[s6000]dependencies\\u0011[s7000]: this is an array, which may be empty. each value is a string containing a program name, which the package manager will look up and attempt to install\\n- \\u0011[s6000]paths\\u0011[s7000]: this is an object, where every key is the relative path to a file or node inside the yarnball and its value is the destination path it should have. a file can have multiple destinations. you can use \\u0011[sA000]%B\\u0011[s7000] as a shortcut for the binaries directory, \\u0011[sA000]%C\\u0011[s7000] as a shortcut for the config directory, \\u0011[sA000]%D\\u0011[s7000] for the documentation directory, and \\u0011[sA000]%L\\u0011[s7000] for the libraries directory. additionally, libraries go in a subdirectory in the libraries directory according to language. for example, javascript libraries go in \\u0011[sA000]%L/js/\\u0011[s7000]\\n- \\u0011[s6000]author\\u0011[s7000], \\u0011[s6000]license\\u0011[s7000], \\u0011[s6000]source\\u0011[s7000] and \\u0011[s6000]contact\\u0011[s7000]: these are information fields for the package's author, license, link to source code, and a way to contact the author if needed\\n\\na package yarnball can be installed with the \\u0011[sA000]mrrp\\u0011[s7000] package manager by using \\u0011[sE800] mrrp yarn \\u0011[s7000] and a path to the yarnball. you can also add your package to a repo\\n\\n\\u0011[s5040]Setting up a repository\\u0011[s7000]\\na repository is a collection of files hosted in servers whose CORS policies allow any browser to fetch from them. repositories are added by their URL, and a file \\u0011[sA000]URL/repo.json\\u0011[s7000] must be available to provide repo info\\n\\nthe \\u0011[sA000]repo.json\\u0011[s7000] file is JSON with a \\u0011[sA000]name\\u0011[s7000] field containing the repository name, and a \\u0011[sA000]packages\\u0011[s7000] field\\n\\nthe \\u0011[sA000]packages\\u0011[s7000] field is an object where every key is the \\u0011[sA000]name\\u0011[s7000] of a package. this is the same name as reported in the yarnball's metadata\\nthe value will be another object with the following fields:\\n\\u0011[sC000]- \\u0011[s6000]url\\u0011[s7000]: the url to the package yarnball, using \\u0011[sA000]~\\u0011[s7000] as a shortcut for the repo's URL\\n\\u0011[sC000]- \\u0011[s6000]version\\u0011[s7000]: an array with 3 number values which must be the same as the yarnball's metadata version value. a mismatch in the version or name between the repo and the yarnball will cause problems while updating\"}}"}