Merge commit 'd1271beab323f7866cfdb1c9ff21dd4b3910674e'

This commit is contained in:
Alexa Amundson
2025-11-28 23:02:06 -06:00
28 changed files with 1732 additions and 0 deletions

28
.github/workflows/archive-ci.yml vendored Normal file
View File

@@ -0,0 +1,28 @@
name: Archive CI
on:
push:
branches: ["main"]
pull_request:
branches: ["main"]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
- name: Install dependencies
run: npm ci
- name: Type check
run: npm run typecheck
- name: Validate catalog and covers
run: npm run validate

4
.gitignore vendored
View File

@@ -84,3 +84,7 @@ output
.DS_Store .DS_Store
.env .env
archive.env archive.env
node_modules
.DS_Store
npm-debug.log*
dist

View File

@@ -198,3 +198,20 @@ pnpm add:beacon --env core --status ok
- `pnpm add:deploy --msg "..."` appends a deploy record to `/data/deploys/YYYY-MM-DD.json`. - `pnpm add:deploy --msg "..."` appends a deploy record to `/data/deploys/YYYY-MM-DD.json`.
- `pnpm add:beacon --env ENV --status STATUS` appends a beacon ping to `/data/beacons/YYYY-MM-DD.json`. - `pnpm add:beacon --env ENV --status STATUS` appends a beacon ping to `/data/beacons/YYYY-MM-DD.json`.
# blackroad-os-archive
Text-first archive and catalog for the BlackRoad OS constellation. This repo maintains validated indexes of repositories, domains, trademarks, and people handles, plus Archive Cover Sheets that explain why each asset matters. No binaries live here—only metadata, templates, and scripts to keep the archive current.
## Key directories
- `catalog/` YAML catalogs for repos, domains, trademarks, and people.
- `covers/` Archive Cover Sheets (YAML front-matter + narrative) for every major repo.
- `schemas/` JSON Schemas validating catalog and cover formats.
- `scripts/` Utilities to scan GitHub orgs, refresh catalogs, generate cover skeletons, and validate data.
- `snapshots/` Text descriptions of logical snapshots (never binary dumps).
- `docs/` Overview, templates, and migration playbooks for maintaining the archive.
## Scripts
- `npm run typecheck` TypeScript checks for scripts.
- `npm run validate` Validate catalogs and cover sheets against schemas.
- `npm run generate:covers` Generate missing cover sheet skeletons from the catalog.
- `npm run refresh:repos` Merge GitHub data into `catalog/repos.yaml` (requires `GITHUB_TOKEN` and `GITHUB_ORGS`).

17
catalog/domains.yaml Normal file
View File

@@ -0,0 +1,17 @@
domains:
- name: blackroad.io
purpose: main OS marketing + front door
primary_repo: blackroad-os-web
status: active
- name: blackroad.systems
purpose: infra / meta
primary_repo: blackroad-os-infra
status: active
- name: archive.blackroad.io
purpose: archive surface + catalogs
primary_repo: blackroad-os-archive
status: active
- name: lucidia.earth
purpose: intelligence / agents
primary_repo: lucidia
status: active

19
catalog/people.yaml Normal file
View File

@@ -0,0 +1,19 @@
people:
- handle: "@Alexa"
role: "Founder / Queen Root User"
areas: [strategy, brand, research, infra]
- handle: "@OpsTeam"
role: "Ops collective"
areas: [infra, ops, security]
- handle: "@ResearchCrew"
role: "Research collective"
areas: [research, intelligence, experimentation]
- handle: "@CreatorGuild"
role: "Creator Guild"
areas: [experience, packs, education]
- handle: "@DocsTeam"
role: "Documentation stewards"
areas: [docs, developer-relations]
- handle: "@Brand"
role: "Brand leads"
areas: [brand, marketing, web]

241
catalog/repos.yaml Normal file
View File

@@ -0,0 +1,241 @@
repos:
- id: core
full_name: BlackRoad-OS/blackroad-os-core
org: BlackRoad-OS
description: Core platform services and OS substrate for BlackRoad.
visibility: public
status: active
primary_domain: blackroad.io
home_pack: infra-devops
created_at: TBD-sync
updated_at: TBD-sync
tags: [platform, core]
owner_handles: ["@Alexa"]
- id: api
full_name: BlackRoad-OS/blackroad-os-api
org: BlackRoad-OS
description: Unified API layer for BlackRoad OS services.
visibility: public
status: active
primary_domain: api.blackroad.io
home_pack: infra-devops
created_at: TBD-sync
updated_at: TBD-sync
tags: [api, services]
owner_handles: ["@Alexa"]
- id: api-gateway
full_name: BlackRoad-OS/blackroad-os-api-gateway
org: BlackRoad-OS
description: Edge routing and gateway configuration for BlackRoad OS APIs.
visibility: private
status: active
primary_domain: gateway.blackroad.io
home_pack: infra-devops
created_at: TBD-sync
updated_at: TBD-sync
tags: [gateway, networking]
owner_handles: ["@OpsTeam"]
- id: operator
full_name: BlackRoad-OS/blackroad-os-operator
org: BlackRoad-OS
description: Control-plane operator and deployment orchestrator for BlackRoad services.
visibility: private
status: active
primary_domain: blackroad.systems
home_pack: infra-devops
created_at: TBD-sync
updated_at: TBD-sync
tags: [kubernetes, operator]
owner_handles: ["@OpsTeam"]
- id: agents
full_name: BlackRoad-OS/blackroad-os-agents
org: BlackRoad-OS
description: Agent runtimes and behaviors for Lucidia-powered BlackRoad experiences.
visibility: private
status: experimental
primary_domain: lucidia.earth
home_pack: intelligence
created_at: TBD-sync
updated_at: TBD-sync
tags: [agents, ai]
owner_handles: ["@ResearchCrew"]
- id: web
full_name: BlackRoad-OS/blackroad-os-web
org: BlackRoad-OS
description: Public web experience and marketing front door for BlackRoad OS.
visibility: public
status: active
primary_domain: blackroad.io
home_pack: creator-studio
created_at: TBD-sync
updated_at: TBD-sync
tags: [web, marketing]
owner_handles: ["@Brand"]
- id: prism-console
full_name: BlackRoad-OS/blackroad-os-prism-console
org: BlackRoad-OS
description: Prism administrative console for orchestrating OS modules and packs.
visibility: private
status: active
primary_domain: console.blackroad.io
home_pack: creator-studio
created_at: TBD-sync
updated_at: TBD-sync
tags: [console, admin]
owner_handles: ["@OpsTeam"]
- id: infra
full_name: BlackRoad-OS/blackroad-os-infra
org: BlackRoad-OS
description: Infrastructure-as-code, cloud topology, and platform bootstrapping.
visibility: private
status: active
primary_domain: blackroad.systems
home_pack: infra-devops
created_at: TBD-sync
updated_at: TBD-sync
tags: [infra, terraform]
owner_handles: ["@OpsTeam"]
- id: docs
full_name: BlackRoad-OS/blackroad-os-docs
org: BlackRoad-OS
description: Public documentation set and developer guides.
visibility: public
status: active
primary_domain: docs.blackroad.io
home_pack: creator-studio
created_at: TBD-sync
updated_at: TBD-sync
tags: [docs, guides]
owner_handles: ["@DocsTeam"]
- id: research
full_name: BlackRoad-OS/blackroad-os-research
org: BlackRoad-OS
description: Research notebooks, experiments, and prototypes for new OS capabilities.
visibility: private
status: experimental
primary_domain: null
home_pack: intelligence
created_at: TBD-sync
updated_at: TBD-sync
tags: [research, prototypes]
owner_handles: ["@ResearchCrew"]
- id: brand
full_name: BlackRoad-OS/blackroad-os-brand
org: BlackRoad-OS
description: Brand system, messaging, and identity guides for BlackRoad OS.
visibility: private
status: active
primary_domain: null
home_pack: brand-lab
created_at: TBD-sync
updated_at: TBD-sync
tags: [brand, guidelines]
owner_handles: ["@Brand"]
- id: archive
full_name: BlackRoad-OS/blackroad-os-archive
org: BlackRoad-OS
description: Canonical archive index, catalogs, and cover sheets for the BlackRoad constellation.
visibility: public
status: active
primary_domain: archive.blackroad.io
home_pack: infra-devops
created_at: TBD-sync
updated_at: TBD-sync
tags: [archive, catalog]
owner_handles: ["@OpsTeam"]
- id: beacon
full_name: BlackRoad-OS/blackroad-os-beacon
org: BlackRoad-OS
description: Monitoring, pings, and heartbeat telemetry for BlackRoad OS services.
visibility: private
status: active
primary_domain: null
home_pack: infra-devops
created_at: TBD-sync
updated_at: TBD-sync
tags: [observability, monitoring]
owner_handles: ["@OpsTeam"]
- id: pack-education
full_name: BlackRoad-OS/blackroad-os-pack-education
org: BlackRoad-OS
description: Education-focused pack bundling learning experiences and guidance.
visibility: private
status: active
primary_domain: null
home_pack: packs
created_at: TBD-sync
updated_at: TBD-sync
tags: [pack, education]
owner_handles: ["@CreatorGuild"]
- id: pack-home
full_name: BlackRoad-OS/blackroad-os-pack-home
org: BlackRoad-OS
description: Home and personal automation pack for BlackRoad OS.
visibility: private
status: experimental
primary_domain: null
home_pack: packs
created_at: TBD-sync
updated_at: TBD-sync
tags: [pack, home]
owner_handles: ["@CreatorGuild"]
- id: pack-creator-studio
full_name: BlackRoad-OS/blackroad-os-pack-creator-studio
org: BlackRoad-OS
description: Creator Studio pack aggregating web, console, and publishing workflows.
visibility: private
status: active
primary_domain: null
home_pack: packs
created_at: TBD-sync
updated_at: TBD-sync
tags: [pack, studio]
owner_handles: ["@CreatorGuild"]
- id: pack-infra-devops
full_name: BlackRoad-OS/blackroad-os-pack-infra-devops
org: BlackRoad-OS
description: Infra + DevOps pack bundling operator, gateway, and monitoring.
visibility: private
status: active
primary_domain: null
home_pack: packs
created_at: TBD-sync
updated_at: TBD-sync
tags: [pack, ops]
owner_handles: ["@OpsTeam"]
- id: pack-intelligence
full_name: BlackRoad-OS/blackroad-os-pack-intelligence
org: BlackRoad-OS
description: Intelligence pack centered on Lucidia agents and cognitive services.
visibility: private
status: experimental
primary_domain: lucidia.earth
home_pack: packs
created_at: TBD-sync
updated_at: TBD-sync
tags: [pack, ai]
owner_handles: ["@ResearchCrew"]
- id: pack-governance
full_name: BlackRoad-OS/blackroad-os-pack-governance
org: BlackRoad-OS
description: Governance and compliance pack for policy management and auditing.
visibility: private
status: legacy
primary_domain: null
home_pack: packs
created_at: TBD-sync
updated_at: TBD-sync
tags: [pack, governance]
owner_handles: ["@OpsTeam"]
- id: pack-beacon
full_name: BlackRoad-OS/blackroad-os-pack-beacon
org: BlackRoad-OS
description: Observability pack bundling beacon and telemetry components.
visibility: private
status: active
primary_domain: null
home_pack: packs
created_at: TBD-sync
updated_at: TBD-sync
tags: [pack, observability]
owner_handles: ["@OpsTeam"]

16
catalog/trademarks.yaml Normal file
View File

@@ -0,0 +1,16 @@
trademarks:
- mark: BLACKROAD
jurisdiction: US
serial_number: TBD
status: filed
notes: Core brand for the operating system constellation.
- mark: BLACKROAD OS
jurisdiction: US
serial_number: TBD
status: filed
notes: Platform and product suite mark for the OS.
- mark: LUCIDIA
jurisdiction: US
serial_number: TBD
status: pending
notes: Applied intelligence + agents brand within BlackRoad.

View File

@@ -0,0 +1,35 @@
---
id: blackroad-os-api
title: BlackRoad OS API
type: repo
status: active
timeframe: 2023-
primary_repo: blackroad-os-api
linked_repos:
- blackroad-os-core
- blackroad-os-api-gateway
- blackroad-os-operator
summary: Unified API surface exposing OS capabilities to web, console, and packs.
why_it_matters: Provides consistent, authenticated entry points for every client surface and integration.
risk_if_lost: Clients would fragment across legacy endpoints and lose a trusted contract for platform access.
recommended_action: keep-live
---
# BlackRoad OS API Archive Cover Sheet
## Narrative
The API repo defines service contracts, request flows, and orchestration that present BlackRoad capabilities to all clients. It aligns SDKs, policies, and telemetry around a single gateway front door.
## History
Born from multiple microservice experiments, the API consolidated endpoints into a single spec, then layered on gateway policies and observability to stabilize external access.
## Current Role
It powers the public and partner-facing interfaces for the console, web, and packs, routing through the gateway and operator-managed deployments.
## Dependencies
- Deployed through `blackroad-os-operator` and fronted by `blackroad-os-api-gateway`.
- Consumes shared contracts from `blackroad-os-core`.
- Exposes data used by `blackroad-os-web` and Prism Console.
## Migration / Future
Continue converging legacy endpoints, adopt schema-first workflows with the archive catalog, and automate policy sync with the gateway repo.

View File

@@ -0,0 +1,35 @@
---
id: blackroad-os-archive
title: BlackRoad OS Archive
type: repo
status: active
timeframe: 2024-
primary_repo: blackroad-os-archive
linked_repos:
- blackroad-os-docs
- blackroad-os-infra
- blackroad-os-prism-console
summary: Canonical catalog of repositories, domains, trademarks, and archive cover sheets for the BlackRoad constellation.
why_it_matters: Provides a single source of truth for what exists, its status, and how to preserve it.
risk_if_lost: Institutional memory would fragment and teams could not coordinate migrations or preservation.
recommended_action: keep-live
---
# BlackRoad OS Archive Archive Cover Sheet
## Narrative
This repo maintains the text-first archive for BlackRoad OS, holding catalogs, schemas, and cover sheets. It is designed to be lightweight and free of binaries while pointing to where artifacts live.
## History
Created to consolidate disparate spreadsheets, docs, and chat threads about the BlackRoad constellation into a searchable, validated index.
## Current Role
The archive curates repos, domains, trademarks, and people references, runs validation to keep metadata fresh, and seeds cover sheets for every major project.
## Dependencies
- References infrastructure details from `blackroad-os-infra` for storage locations.
- Links to public-facing explanations in `blackroad-os-docs`.
- Surfaces metadata into `blackroad-os-prism-console` dashboards.
## Migration / Future
Automate syncing with GitHub orgs, integrate with docs publishing, and add snapshot manifests in `snapshots/` as projects transition to legacy status.

View File

@@ -0,0 +1,35 @@
---
id: blackroad-os-core
title: BlackRoad OS Core
type: repo
status: active
timeframe: 2023-
primary_repo: blackroad-os-core
linked_repos:
- blackroad-os-api
- blackroad-os-operator
- blackroad-os-infra
summary: Core substrate for orchestrating services, identity, and platform runtime across the constellation.
why_it_matters: Anchor for platform primitives, routing, and shared libraries that other repos depend on.
risk_if_lost: Core service graph and shared contracts would fragment, slowing every other repo.
recommended_action: keep-live
---
# BlackRoad OS Core Archive Cover Sheet
## Narrative
BlackRoad OS Core holds the foundational runtime, shared contracts, and base services that knit together the constellation. It provides stable libraries, identity primitives, and platform APIs used by every pack and edge surface.
## History
The repo emerged as the convergence point for early BlackRoad services when separate prototypes needed common auth, logging, and configuration. It replaced ad-hoc glue with maintained modules and deployment conventions.
## Current Role
Today the core repo anchors platform dependencies and publishes reusable packages consumed by the API layer, operator pipelines, and packs. It acts as the canonical source for base images and common schema definitions.
## Dependencies
- Relies on `blackroad-os-operator` for deployment workflows.
- Publishes interfaces consumed by `blackroad-os-api` and `blackroad-os-web`.
- Shares infrastructure modules with `blackroad-os-infra`.
## Migration / Future
Continue hardening shared modules, keep release cadence aligned with operator rollouts, and prepare migration guides for any breaking changes so packs can update smoothly.

View File

@@ -0,0 +1,35 @@
---
id: blackroad-os-infra
title: BlackRoad OS Infra
type: repo
status: active
timeframe: 2022-
primary_repo: blackroad-os-infra
linked_repos:
- blackroad-os-operator
- blackroad-os-beacon
- blackroad-os-core
summary: Infrastructure-as-code, networking, and cloud topology definitions for the OS.
why_it_matters: Provides the base environment every service depends on and encodes security posture.
risk_if_lost: Unable to recreate clusters or audit changes; risk of drift and outages.
recommended_action: keep-live
---
# BlackRoad OS Infra Archive Cover Sheet
## Narrative
The infra repo captures cloud environments, networking, storage, and identity primitives. It is the source of truth for cluster provisioning and bootstrap automation.
## History
It began as a set of Terraform stacks for early experiments and gradually absorbed secrets management patterns, multi-region networking, and compliance controls.
## Current Role
Infra drives the baseline infrastructure for operator-managed workloads, networking for the API gateway, and monitoring pipelines for beacon.
## Dependencies
- Supplies clusters and networks consumed by `blackroad-os-operator` and `blackroad-os-api-gateway`.
- Feeds observability signals into `blackroad-os-beacon`.
- Shares module definitions with `blackroad-os-core`.
## Migration / Future
Continue modularizing IaC, align with GitOps triggers from the operator, and document snapshot procedures in the archive snapshots directory.

View File

@@ -0,0 +1,35 @@
---
id: blackroad-os-operator
title: BlackRoad OS Operator
type: repo
status: active
timeframe: 2023-
primary_repo: blackroad-os-operator
linked_repos:
- blackroad-os-core
- blackroad-os-api-gateway
- blackroad-os-infra
summary: Deployment orchestrator and control-plane automation for BlackRoad OS services.
why_it_matters: Keeps services converged, declarative, and policy-compliant across environments.
risk_if_lost: Drift would increase and deployments would become manual and brittle.
recommended_action: keep-live
---
# BlackRoad OS Operator Archive Cover Sheet
## Narrative
The operator encodes deployment pipelines, rollout strategies, and policy enforcement for the BlackRoad constellation. It provides the reconciliation logic that keeps staging and production aligned.
## History
Evolved from a collection of Terraform scripts and GitHub Actions, the operator centralized deployment definitions into a coherent controller-driven workflow.
## Current Role
Today it triggers builds, applies manifests, and coordinates configuration for the API, core, and surface repos. It integrates with observability hooks to gate releases.
## Dependencies
- Depends on `blackroad-os-infra` for base infrastructure and cluster definitions.
- Coordinates with `blackroad-os-api-gateway` for routing updates.
- Deploys workloads from `blackroad-os-core`, `blackroad-os-api`, and `blackroad-os-web`.
## Migration / Future
Move toward full GitOps parity, expand policy-as-code coverage, and wire archive catalog metadata into release dashboards.

View File

@@ -0,0 +1,35 @@
---
id: blackroad-os-pack-governance
title: BlackRoad OS Pack Governance
type: repo
status: legacy
timeframe: 2022-2023
primary_repo: blackroad-os-pack-governance
linked_repos:
- blackroad-os-operator
- blackroad-os-api-gateway
- blackroad-os-core
summary: Governance pack that bundled policy management, compliance controls, and audit integrations for BlackRoad OS.
why_it_matters: Captured compliance policies and audit pathways that still inform current operator and gateway rules.
risk_if_lost: Historical policy mappings and exceptions would be harder to trace during audits and migrations.
recommended_action: snapshot
---
# BlackRoad OS Pack Governance Archive Cover Sheet
## Narrative
The governance pack combined policy templates, compliance automation, and audit tooling into a bundled experience for regulated deployments. It shipped with dashboards and scripts to enforce change controls.
## History
Built during early enterprise pilots, this pack centralized governance logic before those features were absorbed by the operator and gateway repos.
## Current Role
Now maintained in legacy mode as a reference for policy baselines. Active enforcement lives in the operator and gateway configurations.
## Dependencies
- Integrated with `blackroad-os-operator` for policy-as-code rollouts.
- Provided rule sets consumed by `blackroad-os-api-gateway`.
- Relied on shared identities and logging from `blackroad-os-core`.
## Migration / Future
Keep as a documented snapshot, port any still-relevant controls into the operator repo, and retire duplicated scripts after verifying coverage in current pipelines.

View File

@@ -0,0 +1,35 @@
---
id: blackroad-os-prism-console
title: BlackRoad OS Prism Console
type: repo
status: active
timeframe: 2024-
primary_repo: blackroad-os-prism-console
linked_repos:
- blackroad-os-api
- blackroad-os-core
- blackroad-os-operator
summary: Administrative console for orchestrating modules, packs, and environment states across BlackRoad OS.
why_it_matters: Provides operators and creators with visibility and controls over deployments, packs, and telemetry.
risk_if_lost: Operational command surface would vanish, forcing manual scripts and reducing governance.
recommended_action: keep-live
---
# BlackRoad OS Prism Console Archive Cover Sheet
## Narrative
Prism Console is the UI layer that surfaces system health, deployments, and configuration knobs in one workspace. It is the primary control plane for operators and creators managing packs and releases.
## History
The console started as a thin dashboard over CI outputs and gradually evolved into a fully-featured admin interface as the number of packs and environments grew.
## Current Role
Today Prism Console consumes APIs from the core and operator to show topology, push releases, and review alerts. It links out to docs and archive entries for context.
## Dependencies
- Fetches data from `blackroad-os-api`.
- Uses shared components from `blackroad-os-core` and branding from `blackroad-os-brand`.
- Depends on `blackroad-os-operator` for deployment actions.
## Migration / Future
Integrate catalog insights directly into the UI, add runbooks for archived components, and standardize access control flows.

View File

@@ -0,0 +1,35 @@
---
id: blackroad-os-web
title: BlackRoad OS Web
type: repo
status: active
timeframe: 2023-
primary_repo: blackroad-os-web
linked_repos:
- blackroad-os-core
- blackroad-os-api
- blackroad-os-brand
summary: Public-facing web experience and marketing layer for BlackRoad OS and its packs.
why_it_matters: Serves as the canonical front door and narrative surface for the ecosystem.
risk_if_lost: Brand presence and onboarding funnels would disappear, weakening discoverability.
recommended_action: keep-live
---
# BlackRoad OS Web Archive Cover Sheet
## Narrative
This repo powers the primary marketing site, funneling visitors into docs, console, and pack entry points. It showcases launches, brand language, and status updates for the constellation.
## History
Originally launched as a static site, it evolved to integrate API-driven content, release announcements, and richer product storytelling as BlackRoad OS expanded.
## Current Role
The web repo orchestrates the front door experience, pulling metadata from the docs and archive catalogs while exposing links into Prism Console and docs.
## Dependencies
- Consumes service metadata from `blackroad-os-api`.
- Aligns on branding assets defined in `blackroad-os-brand`.
- Publishes updates referenced by `blackroad-os-docs`.
## Migration / Future
Move toward componentized content sourcing from the archive catalog and ensure preview environments are wired through the operator for rapid iteration.

View File

@@ -0,0 +1,44 @@
# Archive Cover Sheet Template
Use this template (also generated by `scripts/gen_cover_skeletons.ts`) for every repo or project that needs archival coverage.
```md
---
id: example-repo
title: Example Repo
type: repo
status: active
timeframe: 2025-
primary_repo: example-repo
linked_repos: []
summary: TODO
why_it_matters: TODO
risk_if_lost: TODO
recommended_action: keep-live
---
# Example Repo Archive Cover Sheet
## Narrative
TODO
## History
TODO
## Current Role
TODO
## Dependencies
TODO
## Migration / Future
TODO
```
## Writing guidance
- **Narrative**: Describe what the project is and who uses it.
- **History**: Capture why it was created and any major shifts or rewrites.
- **Current Role**: Explain how it fits the constellation today (deps, clients, surfaces).
- **Why it matters**: Spell out the unique value so stakeholders know why to keep it healthy.
- **Risk if lost**: List what would break or become slower/harder to rebuild.
- **Recommended action**: Choose from `keep-live`, `snapshot`, `deprecate`, `merge` and note any blocking steps.

21
docs/ARCHIVE_OVERVIEW.md Normal file
View File

@@ -0,0 +1,21 @@
# BlackRoad OS Archive Overview
The **BlackRoad OS Archive** is the canonical, text-first index for the BlackRoad constellation. It catalogs repositories, domains, trademarks, and people handles, and maintains Archive Cover Sheets that explain why each asset matters and how to preserve it. This repo is intentionally binary-free: it points to artifacts stored elsewhere and records how to retrieve or snapshot them.
## What lives here
- **Catalogs** in `/catalog/` for repos, domains, trademarks, and people.
- **Schemas** in `/schemas/` to validate catalog entries and cover sheets.
- **Archive Cover Sheets** in `/covers/` describing each major repo or project.
- **Scripts** in `/scripts/` to scan GitHub orgs, refresh catalogs, generate cover skeletons, and validate data.
- **Snapshots** in `/snapshots/` to describe logical snapshots (never binary blobs).
## How it pairs with other repos
- **blackroad-os-infra**: Source of infrastructure definitions and snapshot storage locations referenced from the archive.
- **blackroad-os-docs**: Public-facing documentation that can surface curated entries from the archive.
- **blackroad-os-research**: Home for experiments and theoretical work that the archive lists and tracks as experimental or legacy.
## Principles
- Text-first, no binary assets.
- Schema-validated to prevent drift.
- Clearly marked statuses (active, experimental, legacy, archived) with cover sheets for anything deprecated.
- Easy to regenerate and sync using the provided scripts.

View File

@@ -0,0 +1,29 @@
# Migration Playbook
Use this checklist to migrate legacy or out-of-date repos into the modern BlackRoad OS constellation.
1. **Catalog it**
- Add the repo entry to `catalog/repos.yaml` with status `legacy` or `archived`.
- Include owner handles, tags, and any known domains.
2. **Generate and fill a Cover Sheet**
- Run `npm run generate:covers` to create a skeleton if missing.
- Complete the narrative, history, and why-it-matters sections in `/covers/<repo>.cover.md`.
3. **Decide the path forward**
- Choose whether to merge into a core repo, split into packs, or deprecate.
- Note the recommended action on the cover sheet (`keep-live`, `snapshot`, `deprecate`, or `merge`).
4. **Link to the canonical destination**
- Update the cover sheet to reference modern equivalents (e.g., `blackroad-os-core`, `blackroad-os-operator`).
- Set the GitHub repo status to `archived` if it will no longer receive updates.
5. **Update infrastructure + docs**
- Ensure redirects or gateway rules are in place via `blackroad-os-operator` and `blackroad-os-api-gateway`.
- Add cross-links in `blackroad-os-docs` or Prism Console so stakeholders can find the new home.
6. **Snapshot (text-only) references**
- Document snapshot metadata in `/snapshots/` if necessary (never store binaries here).
7. **Validate**
- Run `npm run validate` to check schema compliance and ensure legacy items have cover sheets.

461
package-lock.json generated Normal file
View File

@@ -0,0 +1,461 @@
{
"name": "blackroad-os-archive",
"version": "0.1.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "blackroad-os-archive",
"version": "0.1.0",
"devDependencies": {
"@types/js-yaml": "^4.0.9",
"@types/node": "^20.14.9",
"ajv": "^8.17.1",
"ajv-formats": "^3.0.1",
"gray-matter": "^4.0.3",
"js-yaml": "^4.1.0",
"ts-node": "^10.9.2",
"typescript": "^5.4.5"
}
},
"node_modules/@cspotcode/source-map-support": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
"integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/trace-mapping": "0.3.9"
},
"engines": {
"node": ">=12"
}
},
"node_modules/@jridgewell/resolve-uri": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/sourcemap-codec": {
"version": "1.5.5",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
"dev": true,
"license": "MIT"
},
"node_modules/@jridgewell/trace-mapping": {
"version": "0.3.9",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
"integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/resolve-uri": "^3.0.3",
"@jridgewell/sourcemap-codec": "^1.4.10"
}
},
"node_modules/@tsconfig/node10": {
"version": "1.0.12",
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz",
"integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@tsconfig/node12": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz",
"integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==",
"dev": true,
"license": "MIT"
},
"node_modules/@tsconfig/node14": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
"integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
"dev": true,
"license": "MIT"
},
"node_modules/@tsconfig/node16": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz",
"integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/js-yaml": {
"version": "4.0.9",
"resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.9.tgz",
"integrity": "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/node": {
"version": "20.19.25",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.25.tgz",
"integrity": "sha512-ZsJzA5thDQMSQO788d7IocwwQbI8B5OPzmqNvpf3NY/+MHDAS759Wo0gd2WQeXYt5AAAQjzcrTVC6SKCuYgoCQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"undici-types": "~6.21.0"
}
},
"node_modules/acorn": {
"version": "8.15.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"dev": true,
"license": "MIT",
"bin": {
"acorn": "bin/acorn"
},
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/acorn-walk": {
"version": "8.3.4",
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz",
"integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==",
"dev": true,
"license": "MIT",
"dependencies": {
"acorn": "^8.11.0"
},
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/ajv": {
"version": "8.17.1",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
"dev": true,
"license": "MIT",
"dependencies": {
"fast-deep-equal": "^3.1.3",
"fast-uri": "^3.0.1",
"json-schema-traverse": "^1.0.0",
"require-from-string": "^2.0.2"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/epoberezkin"
}
},
"node_modules/ajv-formats": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz",
"integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"ajv": "^8.0.0"
},
"peerDependencies": {
"ajv": "^8.0.0"
},
"peerDependenciesMeta": {
"ajv": {
"optional": true
}
}
},
"node_modules/arg": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
"dev": true,
"license": "MIT"
},
"node_modules/argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
"dev": true,
"license": "Python-2.0"
},
"node_modules/create-require": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
"dev": true,
"license": "MIT"
},
"node_modules/diff": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
"dev": true,
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.3.1"
}
},
"node_modules/esprima": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
"dev": true,
"license": "BSD-2-Clause",
"bin": {
"esparse": "bin/esparse.js",
"esvalidate": "bin/esvalidate.js"
},
"engines": {
"node": ">=4"
}
},
"node_modules/extend-shallow": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
"integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
"dev": true,
"license": "MIT",
"dependencies": {
"is-extendable": "^0.1.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"dev": true,
"license": "MIT"
},
"node_modules/fast-uri": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz",
"integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/fastify"
},
{
"type": "opencollective",
"url": "https://opencollective.com/fastify"
}
],
"license": "BSD-3-Clause"
},
"node_modules/gray-matter": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz",
"integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"js-yaml": "^3.13.1",
"kind-of": "^6.0.2",
"section-matter": "^1.0.0",
"strip-bom-string": "^1.0.0"
},
"engines": {
"node": ">=6.0"
}
},
"node_modules/gray-matter/node_modules/argparse": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
"dev": true,
"license": "MIT",
"dependencies": {
"sprintf-js": "~1.0.2"
}
},
"node_modules/gray-matter/node_modules/js-yaml": {
"version": "3.14.2",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz",
"integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==",
"dev": true,
"license": "MIT",
"dependencies": {
"argparse": "^1.0.7",
"esprima": "^4.0.0"
},
"bin": {
"js-yaml": "bin/js-yaml.js"
}
},
"node_modules/is-extendable": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
"integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/js-yaml": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
"integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
"dev": true,
"license": "MIT",
"dependencies": {
"argparse": "^2.0.1"
},
"bin": {
"js-yaml": "bin/js-yaml.js"
}
},
"node_modules/json-schema-traverse": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
"dev": true,
"license": "MIT"
},
"node_modules/kind-of": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
"integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/make-error": {
"version": "1.3.6",
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
"dev": true,
"license": "ISC"
},
"node_modules/require-from-string": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/section-matter": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz",
"integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==",
"dev": true,
"license": "MIT",
"dependencies": {
"extend-shallow": "^2.0.1",
"kind-of": "^6.0.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/sprintf-js": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
"integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
"dev": true,
"license": "BSD-3-Clause"
},
"node_modules/strip-bom-string": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz",
"integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/ts-node": {
"version": "10.9.2",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz",
"integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@cspotcode/source-map-support": "^0.8.0",
"@tsconfig/node10": "^1.0.7",
"@tsconfig/node12": "^1.0.7",
"@tsconfig/node14": "^1.0.0",
"@tsconfig/node16": "^1.0.2",
"acorn": "^8.4.1",
"acorn-walk": "^8.1.1",
"arg": "^4.1.0",
"create-require": "^1.1.0",
"diff": "^4.0.1",
"make-error": "^1.1.1",
"v8-compile-cache-lib": "^3.0.1",
"yn": "3.1.1"
},
"bin": {
"ts-node": "dist/bin.js",
"ts-node-cwd": "dist/bin-cwd.js",
"ts-node-esm": "dist/bin-esm.js",
"ts-node-script": "dist/bin-script.js",
"ts-node-transpile-only": "dist/bin-transpile.js",
"ts-script": "dist/bin-script-deprecated.js"
},
"peerDependencies": {
"@swc/core": ">=1.2.50",
"@swc/wasm": ">=1.2.50",
"@types/node": "*",
"typescript": ">=2.7"
},
"peerDependenciesMeta": {
"@swc/core": {
"optional": true
},
"@swc/wasm": {
"optional": true
}
}
},
"node_modules/typescript": {
"version": "5.9.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"dev": true,
"license": "Apache-2.0",
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=14.17"
}
},
"node_modules/undici-types": {
"version": "6.21.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
"dev": true,
"license": "MIT"
},
"node_modules/v8-compile-cache-lib": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
"integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
"dev": true,
"license": "MIT"
},
"node_modules/yn": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
}
}
}
}

View File

@@ -29,5 +29,21 @@
"prettier-plugin-astro": "^0.13.0", "prettier-plugin-astro": "^0.13.0",
"prettier-plugin-svelte": "^3.2.6", "prettier-plugin-svelte": "^3.2.6",
"typescript": "^5.6.2" "typescript": "^5.6.2"
"description": "Canonical catalog and cover sheet archive for the BlackRoad OS constellation.",
"scripts": {
"typecheck": "tsc --noEmit",
"validate": "ts-node scripts/validate_catalog.ts",
"generate:covers": "ts-node scripts/gen_cover_skeletons.ts",
"refresh:repos": "ts-node scripts/refresh_repos_catalog.ts"
},
"devDependencies": {
"@types/js-yaml": "^4.0.9",
"@types/node": "^20.14.9",
"ajv": "^8.17.1",
"ajv-formats": "^3.0.1",
"gray-matter": "^4.0.3",
"js-yaml": "^4.1.0",
"ts-node": "^10.9.2",
"typescript": "^5.4.5"
} }
} }

36
schemas/cover.schema.json Normal file
View File

@@ -0,0 +1,36 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Archive Cover Sheet",
"type": "object",
"properties": {
"id": {"type": "string", "minLength": 1},
"title": {"type": "string", "minLength": 1},
"type": {"type": "string", "enum": ["repo", "project", "artifact"]},
"status": {"type": "string", "enum": ["active", "archived", "experimental", "legacy"]},
"timeframe": {"type": "string"},
"primary_repo": {"type": "string"},
"linked_repos": {
"type": "array",
"items": {"type": "string"},
"default": []
},
"summary": {"type": "string"},
"why_it_matters": {"type": "string"},
"risk_if_lost": {"type": "string"},
"recommended_action": {"type": "string", "enum": ["keep-live", "snapshot", "deprecate", "merge"]}
},
"required": [
"id",
"title",
"type",
"status",
"timeframe",
"primary_repo",
"linked_repos",
"summary",
"why_it_matters",
"risk_if_lost",
"recommended_action"
],
"additionalProperties": false
}

52
schemas/repos.schema.json Normal file
View File

@@ -0,0 +1,52 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "BlackRoad OS Repos Catalog",
"type": "object",
"properties": {
"repos": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {"type": "string", "minLength": 1},
"full_name": {"type": "string", "minLength": 1},
"org": {"type": "string", "minLength": 1},
"description": {"type": "string"},
"visibility": {"type": "string", "enum": ["public", "private"]},
"status": {"type": "string", "enum": ["active", "archived", "experimental", "legacy"]},
"primary_domain": {"type": ["string", "null"]},
"home_pack": {"type": "string"},
"created_at": {"type": "string"},
"updated_at": {"type": "string"},
"tags": {
"type": "array",
"items": {"type": "string"},
"default": []
},
"owner_handles": {
"type": "array",
"items": {"type": "string"},
"default": []
}
},
"required": [
"id",
"full_name",
"org",
"description",
"visibility",
"status",
"primary_domain",
"home_pack",
"created_at",
"updated_at",
"tags",
"owner_handles"
],
"additionalProperties": false
}
}
},
"required": ["repos"],
"additionalProperties": false
}

View File

@@ -0,0 +1,87 @@
import fs from "fs";
import path from "path";
import yaml from "js-yaml";
type RepoRecord = {
id: string;
full_name: string;
status: string;
};
type Catalog = { repos: RepoRecord[] };
function loadCatalog(catalogPath: string): Catalog {
const raw = fs.readFileSync(catalogPath, "utf8");
return yaml.load(raw) as Catalog;
}
function coverPathForRepo(repoName: string): string {
return path.join(process.cwd(), "covers", `${repoName}.cover.md`);
}
function formatTitle(repoName: string): string {
const words = repoName.replace(/[-_]/g, " ")
.replace(/\bos\b/i, "OS")
.split(" ")
.map((word) => word.charAt(0).toUpperCase() + word.slice(1));
return words.join(" ");
}
function createSkeleton(repoName: string, status: string): string {
const title = formatTitle(repoName);
return `---
id: ${repoName}
title: ${title}
type: repo
status: ${status}
timeframe: 2025-
primary_repo: ${repoName}
linked_repos: []
summary: TODO
why_it_matters: TODO
risk_if_lost: TODO
recommended_action: keep-live
---
# ${title} Archive Cover Sheet
## Narrative
TODO
## History
TODO
## Current Role
TODO
## Dependencies
TODO
## Migration / Future
TODO
`;
}
function ensureCover(repo: RepoRecord) {
const repoName = repo.full_name.split("/")[1];
const destination = coverPathForRepo(repoName);
if (fs.existsSync(destination)) {
return;
}
const skeleton = createSkeleton(repoName, repo.status ?? "active");
fs.writeFileSync(destination, skeleton);
console.log(`Generated cover skeleton for ${repoName}`);
}
function main() {
const catalogPath = path.join(process.cwd(), "catalog", "repos.yaml");
if (!fs.existsSync(catalogPath)) {
throw new Error("catalog/repos.yaml not found");
}
const catalog = loadCatalog(catalogPath);
catalog.repos.forEach((repo) => ensureCover(repo));
}
if (require.main === module) {
main();
}

View File

@@ -0,0 +1,97 @@
import fs from "fs";
import path from "path";
import yaml from "js-yaml";
import { scanGithubRepos } from "./scan_github_repos";
type RepoRecord = {
id: string;
full_name: string;
org: string;
description: string;
visibility: "public" | "private";
status: "active" | "archived" | "experimental" | "legacy";
primary_domain: string | null;
home_pack: string;
created_at: string;
updated_at: string;
tags: string[];
owner_handles: string[];
};
type Catalog = { repos: RepoRecord[] };
function loadLocalCatalog(catalogPath: string): Catalog {
if (!fs.existsSync(catalogPath)) {
throw new Error(`Catalog not found at ${catalogPath}`);
}
const raw = fs.readFileSync(catalogPath, "utf8");
const parsed = yaml.load(raw) as Catalog;
return parsed;
}
function mergeRepo(local: RepoRecord, remote: RepoRecord): RepoRecord {
return {
...local,
description: remote.description || local.description,
visibility: remote.visibility,
created_at: remote.created_at || local.created_at,
updated_at: remote.updated_at || local.updated_at
};
}
function normalizeRepo(repo: RepoRecord): RepoRecord {
return {
...repo,
tags: repo.tags || [],
owner_handles: repo.owner_handles || []
};
}
function writeCatalog(catalogPath: string, catalog: Catalog) {
const sorted = [...catalog.repos].sort((a, b) => a.id.localeCompare(b.id));
const payload: Catalog = { repos: sorted.map(normalizeRepo) };
const yamlOutput = yaml.dump(payload, { lineWidth: 120 });
fs.writeFileSync(catalogPath, yamlOutput);
}
async function main() {
try {
const catalogPath = path.join(process.cwd(), "catalog", "repos.yaml");
const localCatalog = loadLocalCatalog(catalogPath);
const remoteRepos = await scanGithubRepos();
const mergedMap = new Map<string, RepoRecord>();
// Seed with local entries
for (const repo of localCatalog.repos) {
mergedMap.set(repo.full_name, repo);
}
// Merge remote updates
for (const repo of remoteRepos) {
const existing = mergedMap.get(repo.full_name);
if (existing) {
mergedMap.set(repo.full_name, mergeRepo(existing, repo));
} else {
mergedMap.set(repo.full_name, {
...repo,
status: "active",
primary_domain: null,
home_pack: "tbd",
tags: [],
owner_handles: []
});
}
}
writeCatalog(catalogPath, { repos: Array.from(mergedMap.values()) });
console.log(`Catalog refreshed with ${mergedMap.size} entries.`);
} catch (error) {
console.error((error as Error).message);
process.exit(1);
}
}
if (require.main === module) {
main();
}

View File

@@ -0,0 +1,117 @@
import yaml from "js-yaml";
type RepoRecord = {
id: string;
full_name: string;
org: string;
description: string;
visibility: "public" | "private";
status: "active" | "archived" | "experimental" | "legacy";
primary_domain: string | null;
home_pack: string;
created_at: string;
updated_at: string;
tags: string[];
owner_handles: string[];
};
type GitHubRepo = {
name: string;
full_name: string;
private: boolean;
description: string | null;
created_at: string;
updated_at: string;
};
const TOKEN = process.env.GITHUB_TOKEN;
const ORGS = process.env.GITHUB_ORGS?.split(",").map((org) => org.trim()).filter(Boolean) ?? [];
async function githubFetch(url: string) {
const headers: Record<string, string> = {
Accept: "application/vnd.github+json",
"User-Agent": "blackroad-os-archive"
};
if (TOKEN) {
headers.Authorization = `Bearer ${TOKEN}`;
}
const response = await fetch(url, { headers });
if (!response.ok) {
throw new Error(`GitHub request failed: ${response.status} ${response.statusText} for ${url}`);
}
return response.json();
}
async function fetchReposForOrg(org: string): Promise<RepoRecord[]> {
const repos: RepoRecord[] = [];
let page = 1;
while (true) {
const url = `https://api.github.com/orgs/${org}/repos?per_page=100&page=${page}`;
const data: GitHubRepo[] = await githubFetch(url);
if (!data.length) break;
data.forEach((repo) => {
let id: string;
if (repo.name.startsWith("blackroad-os-")) {
id = repo.name.replace(/^blackroad-os-/, "");
} else {
id = `other-${repo.name}`;
console.warn(
`Repository '${repo.full_name}' does not start with 'blackroad-os-'. Assigned id: '${id}'.`
);
}
repos.push({
id,
full_name: repo.full_name,
org,
description: repo.description ?? "",
visibility: repo.private ? "private" : "public",
status: "active",
primary_domain: null,
home_pack: "tbd",
created_at: repo.created_at,
updated_at: repo.updated_at,
tags: [],
owner_handles: []
});
});
if (data.length < 100) break;
page += 1;
}
return repos;
}
export async function scanGithubRepos(): Promise<RepoRecord[]> {
if (!ORGS.length) {
throw new Error("GITHUB_ORGS env var is required (comma-separated list).");
}
const results: RepoRecord[] = [];
for (const org of ORGS) {
const repos = await fetchReposForOrg(org);
results.push(...repos);
}
return results;
}
async function main() {
try {
const repos = await scanGithubRepos();
const payload = { repos };
const yamlOutput = yaml.dump(payload, { lineWidth: 120 });
process.stdout.write(`# Generated by scan_github_repos.ts\n`);
process.stdout.write(yamlOutput);
} catch (error) {
console.error((error as Error).message);
process.exit(1);
}
}
if (require.main === module) {
main();
}

133
scripts/validate_catalog.ts Normal file
View File

@@ -0,0 +1,133 @@
import fs from "fs";
import path from "path";
import matter from "gray-matter";
import yaml from "js-yaml";
import Ajv from "ajv";
import addFormats from "ajv-formats";
type RepoRecord = {
id: string;
full_name: string;
status: "active" | "archived" | "experimental" | "legacy";
};
type Catalog = { repos: RepoRecord[] };
type CoverValidation = {
file: string;
valid: boolean;
errors?: string;
};
function loadSchema(schemaPath: string) {
const raw = fs.readFileSync(schemaPath, "utf8");
return JSON.parse(raw);
}
function loadCatalog(catalogPath: string): Catalog {
const raw = fs.readFileSync(catalogPath, "utf8");
return yaml.load(raw) as Catalog;
}
function validateCatalog(catalog: Catalog, schema: any, ajv: Ajv): boolean {
const validate = ajv.compile(schema);
const valid = validate(catalog);
if (!valid) {
console.error("Catalog validation errors:", validate.errors);
}
return Boolean(valid);
}
function listCoverFiles(coversDir: string): string[] {
if (!fs.existsSync(coversDir)) return [];
return fs.readdirSync(coversDir).filter((file) => file.endsWith(".cover.md"));
}
function validateCover(filePath: string, schema: any, ajv: Ajv): CoverValidation {
const raw = fs.readFileSync(filePath, "utf8");
const parsed = matter(raw);
const validate = ajv.compile(schema);
const valid = validate(parsed.data);
return {
file: path.basename(filePath),
valid: Boolean(valid),
errors: valid ? undefined : JSON.stringify(validate.errors, null, 2)
};
}
function summarizeRepos(repos: RepoRecord[]) {
const total = repos.length;
const counts = repos.reduce<Record<string, number>>((acc, repo) => {
acc[repo.status] = (acc[repo.status] ?? 0) + 1;
return acc;
}, {});
const summaryParts = [
`Repos: ${total} total`,
`active: ${counts.active ?? 0}`,
`legacy: ${counts.legacy ?? 0}`,
`experimental: ${counts.experimental ?? 0}`,
`archived: ${counts.archived ?? 0}`
];
console.log(summaryParts.join(" | "));
}
function summarizeCovers(covers: CoverValidation[], missing: string[]) {
const validCount = covers.filter((c) => c.valid).length;
console.log(`Cover Sheets: ${validCount} valid, ${covers.length} present, ${missing.length} missing`);
if (covers.some((c) => !c.valid)) {
console.error("Invalid cover sheets:");
covers
.filter((c) => !c.valid)
.forEach((c) => console.error(`- ${c.file}: ${c.errors}`));
}
if (missing.length) {
console.error("Missing cover sheets:");
missing.forEach((m) => console.error(`- ${m}`));
}
}
function ensureLegacyHasCovers(repos: RepoRecord[], coverNames: Set<string>): string[] {
return repos
.filter((repo) => repo.status === "archived" || repo.status === "legacy")
.map((repo) => repo.full_name.split("/")[1])
.filter((repoName) => !coverNames.has(`${repoName}.cover.md`));
}
function main() {
const catalogPath = path.join(process.cwd(), "catalog", "repos.yaml");
const coversDir = path.join(process.cwd(), "covers");
const catalogSchemaPath = path.join(process.cwd(), "schemas", "repos.schema.json");
const coverSchemaPath = path.join(process.cwd(), "schemas", "cover.schema.json");
const ajv = new Ajv({ allErrors: true, allowUnionTypes: true });
addFormats(ajv);
const catalog = loadCatalog(catalogPath);
const catalogSchema = loadSchema(catalogSchemaPath);
const catalogValid = validateCatalog(catalog, catalogSchema, ajv);
summarizeRepos(catalog.repos);
const coverFiles = listCoverFiles(coversDir);
const coverSchema = loadSchema(coverSchemaPath);
const coverValidations = coverFiles.map((file) =>
validateCover(path.join(coversDir, file), coverSchema, ajv)
);
coverValidations.forEach((result) => {
if (!result.valid) {
console.error(`Cover validation failed for ${result.file}`);
}
});
const missingForLegacy = ensureLegacyHasCovers(catalog.repos, new Set(coverFiles));
summarizeCovers(coverValidations, missingForLegacy);
const allValid = catalogValid && coverValidations.every((c) => c.valid) && missingForLegacy.length === 0;
if (!allValid) {
process.exit(1);
}
}
if (require.main === module) {
main();
}

3
snapshots/README.md Normal file
View File

@@ -0,0 +1,3 @@
# Snapshots
This directory tracks logical snapshot descriptions (no binary artifacts). Document planned or completed snapshots with pointers to their origins, storage locations, and validation hashes elsewhere.

View File

@@ -6,4 +6,18 @@
"~/*": ["src/*"] "~/*": ["src/*"]
} }
} }
"compilerOptions": {
"target": "ES2021",
"module": "CommonJS",
"moduleResolution": "Node",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true,
"resolveJsonModule": true,
"types": ["node"],
"lib": ["es2021", "dom"]
},
"include": ["scripts/**/*.ts"],
"exclude": ["node_modules"]
} }