Files
bare-operating-system/scripts/gen-bare-holepunch-catalog.mjs
T
Raven Scott f79db04313 POSIX / synthetic syscalls
- Bump /proc/bare_os/syscalls.json to schema 7; socketMsgSurface (sendmsg/recvmsg ENOTSUP)
- POSIX profile 1.0.8; align syscalls.example.json, declared profile, compatibility matrix
- Bridged SOCK_DGRAM recv/recvfrom with bounded queue + poll/select readiness env knobs
- process_table.json schema 7; fdModel.processTableSchema and matrix/dashboard sync
- posix-conformance-matrix bareOsSyscallOps includes recvfrom

P2P / protocol / replication
- Optional Protomux bare-os-app-v1 (BARE_OS_PROTOMUX_APP_CHANNEL)
- Replication: guestReplicationPlan (BARE_OS_REPLICATION_PLAN_JSON), sync_window parallelismHint
- Blind-relay swarm protomuxBackpressure (BARE_OS_SWARM_PROTOMUX_BACKPRESSURE_COUNT)
- Remove bareOsProcBlindPeerRelayHintsStub; strict peer allowlist (BARE_OS_PEER_ALLOWLIST_STRICT)
- Kernel multisig gate before kernel.ext.d; Pear updater integrationHints + audit env docs

Tooling / tests / hygiene
- Default holepunch clone drift in pretest; document BARE_OS_HOLEPUNCH_DRIFT_CHECK=0
- Widen bare holepunch catalog overrides; Mermaid architecture in docs hub + README link
- Fix tests: corestore_snapshot proc schema 2, posixXsh schema 2, awk-engine export strip in xcu sweep
- pear-updater-bridge: shared integration hints; identity-session import order
- Handbook ch.3/7/9 + environment appendix updates; scripts README drift script behavior
2026-04-05 00:45:17 -04:00

262 lines
7.7 KiB
JavaScript

#!/usr/bin/env node
/**
* List holepunchto/bare-* repos, resolve npm latest via registry API,
* merge scripts/bare-catalog-overrides.json, write docs/bare-holepunch-catalog.json
*
* node scripts/gen-bare-holepunch-catalog.mjs
* HOLEPUNCH_MIRROR=/path/to/repos node scripts/gen-bare-holepunch-catalog.mjs
* node scripts/gen-bare-holepunch-catalog.mjs --check
*/
import { readFile, writeFile, readdir, stat, mkdir } from 'node:fs/promises'
import { dirname, join } from 'node:path'
import { fileURLToPath, pathToFileURL } from 'node:url'
import process from 'node:process'
const __dirname = dirname(fileURLToPath(import.meta.url))
const root = join(__dirname, '..')
const outPath = join(root, 'docs', 'bare-holepunch-catalog.json')
const overridesPath = join(__dirname, 'bare-catalog-overrides.json')
export function manifestCtxKeyForPackage(name) {
const legacy = {
b4a: 'b4a',
'compact-encoding': 'compactEncoding',
'safety-catch': 'safetyCatch',
'hypercore-id-encoding': 'hypercoreIdEncoding',
protomux: 'protomux',
'bare-url': 'bareUrl',
'bare-path': 'barePath',
'bare-encoding': 'bareEncoding',
'bare-events': 'bareEvents',
'bare-fetch': 'fetch',
'bare-readline': 'bareReadline',
'bare-crypto': 'bareCrypto'
}
if (legacy[name]) return legacy[name]
if (name.startsWith('bare-')) {
const parts = name.slice('bare-'.length).split('-')
const pascal = parts
.map((p) => (p.length ? p[0].toUpperCase() + p.slice(1) : ''))
.join('')
return 'bare' + pascal
}
return name.replace(/-([a-z])/g, (_, c) => c.toUpperCase())
}
async function loadOverrides() {
const raw = await readFile(overridesPath, 'utf8')
return JSON.parse(raw)
}
async function fetchGithubBareRepos() {
const all = []
let url = 'https://api.github.com/orgs/holepunchto/repos?per_page=100'
for (let i = 0; i < 15 && url; i++) {
const r = await fetch(url, {
headers: { 'User-Agent': 'bare-operating-system-catalog' }
})
if (!r.ok) throw new Error(`GitHub API ${r.status}: ${await r.text()}`)
const page = await r.json()
if (!Array.isArray(page)) throw new Error('GitHub: expected array')
all.push(...page)
const link = r.headers.get('link')
url = null
if (link) {
const m = link.match(/<([^>]+)>;\s*rel="next"/)
if (m) url = m[1]
}
}
return all.filter((x) => x.name?.startsWith('bare-'))
}
async function fetchMirrorBareRepos(mirrorRoot) {
const names = []
for (const ent of await readdir(mirrorRoot, { withFileTypes: true })) {
if (ent.isDirectory() && ent.name.startsWith('bare-')) names.push(ent.name)
}
return names.sort().map((name) => ({
name,
html_url: `https://github.com/holepunchto/${name}`,
description: ''
}))
}
async function npmLatestVersion(packageName) {
const r = await fetch(
`https://registry.npmjs.org/${encodeURIComponent(packageName)}`,
{ headers: { Accept: 'application/json' } }
)
if (r.status === 404) return null
if (!r.ok) throw new Error(`npm ${packageName}: ${r.status}`)
const j = await r.json()
const v = j['dist-tags']?.latest
return typeof v === 'string' ? v : null
}
async function batchNpmVersions(names, concurrency = 16) {
const m = new Map()
let i = 0
async function worker() {
while (i < names.length) {
const idx = i++
const n = names[idx]
try {
m.set(n, await npmLatestVersion(n))
} catch {
m.set(n, null)
}
}
}
await Promise.all(Array.from({ length: concurrency }, () => worker()))
return m
}
async function main() {
const check = process.argv.includes('--check')
const mirror = process.env.HOLEPUNCH_MIRROR
const overrides = await loadOverrides()
const unpublished = new Set(overrides.unpublishedRepos || [])
const excluded = new Map()
for (const e of overrides.excludedFromBooter || []) {
if (typeof e === 'string') excluded.set(e, 'excluded_from_booter')
else if (e && typeof e.repo === 'string')
excluded.set(e.repo, e.reason || 'excluded_from_booter')
}
let ghRepos
if (mirror) {
const st = await stat(mirror).catch(() => null)
if (!st?.isDirectory()) {
throw new Error(`HOLEPUNCH_MIRROR is not a directory: ${mirror}`)
}
ghRepos = await fetchMirrorBareRepos(mirror)
} else {
ghRepos = await fetchGithubBareRepos()
}
ghRepos.sort((a, b) => a.name.localeCompare(b.name))
const names = ghRepos.map((r) => r.name)
const npmMap = await batchNpmVersions(
names.filter((n) => !unpublished.has(n)),
16
)
const entries = []
for (const r of ghRepos) {
const name = r.name
const npmVersion = unpublished.has(name) ? null : npmMap.get(name) ?? null
const npmPublished = Boolean(npmVersion)
let exclusion = unpublished.has(name) ? 'unpublished' : null
if (excluded.has(name)) exclusion = 'excluded_from_booter'
const includedInBooter =
npmPublished && !unpublished.has(name) && !excluded.has(name)
entries.push({
repo: name,
githubUrl: r.html_url,
description: r.description || '',
npmName: npmPublished ? name : null,
npmPublished,
npmVersion,
includedInBooter,
exclusion,
exclusionDetail: excluded.get(name) || null,
manifestCtxKey: includedInBooter ? manifestCtxKeyForPackage(name) : null
})
}
for (const x of overrides.additionalCatalogEntries || []) {
if (!x || typeof x.repo !== 'string') continue
const name = x.repo.trim()
if (!name || entries.some((e) => e.repo === name)) continue
const npmHint = typeof x.npmHint === 'string' ? x.npmHint.trim() : name
let npmVersion = null
try {
npmVersion = await npmLatestVersion(npmHint)
} catch {
npmVersion = null
}
entries.push({
repo: name,
githubUrl: x.githubUrl || `https://github.com/holepunchto/${name}`,
description: x.description || '',
npmName: npmVersion ? npmHint : null,
npmPublished: Boolean(npmVersion),
npmVersion,
includedInBooter: false,
exclusion: 'p2p_aux_manual',
exclusionDetail: 'Listed for P2P stack integration research; not stock ctx.bare keys.',
manifestCtxKey: null
})
}
const out = {
schemaVersion: 1,
generatedAt: new Date().toISOString(),
source: mirror
? { mode: 'local-mirror', mirrorRoot: mirror }
: { mode: 'github-api', githubOrg: 'holepunchto' },
npmRegistry: 'https://registry.npmjs.org',
entries
}
const json = JSON.stringify(out, null, 2) + '\n'
if (check) {
let existingRaw = ''
try {
existingRaw = await readFile(outPath, 'utf8')
} catch {
console.error('[gen-bare-holepunch-catalog] --check: missing', outPath)
process.exit(1)
}
let existing
try {
existing = JSON.parse(existingRaw)
} catch {
console.error('[gen-bare-holepunch-catalog] --check: invalid JSON on disk')
process.exit(1)
}
const stable = (o) => ({
schemaVersion: o.schemaVersion,
source: o.source,
entries: o.entries
})
const a = JSON.stringify(stable(out))
const b = JSON.stringify(stable(existing))
if (a !== b) {
console.error(
'[gen-bare-holepunch-catalog] --check: drift; run gen:bare-catalog to refresh'
)
process.exit(1)
}
console.log('[gen-bare-holepunch-catalog] --check ok')
return
}
await mkdir(dirname(outPath), { recursive: true })
await writeFile(outPath, json, 'utf8')
console.log(
'Wrote',
outPath,
'entries=',
entries.length,
'npmPublished=',
entries.filter((e) => e.npmPublished).length,
'includedInBooter=',
entries.filter((e) => e.includedInBooter).length
)
}
if (
process.argv[1] &&
import.meta.url === pathToFileURL(process.argv[1]).href
) {
main().catch((e) => {
console.error(e)
process.exit(1)
})
}