# Gitea Registry & `@bytelyst/*` Package Resolution

> **TL;DR** — `@bytelyst/*` packages resolve **two different ways** depending on
> context, and conflating them causes the most common onboarding failure:
>
> | Context | How `@bytelyst/*` resolves | Needs Gitea registry? | Needs `GITEA_NPM_TOKEN`? |
> |---|---|---|---|
> | **Local dev** (`pnpm install` on a laptop / dev box) | pnpm **workspace links** to the sibling `learning_ai_common_plat` checkout | **No** | **No** |
> | **Docker / CI build** (`docker build`, `deploy-*.sh`) | Pulled from the **Gitea npm registry** (`localhost:3300`) | **Yes** | **Yes** |
>
> If a local install is trying to reach `localhost:3300` or asking for a token,
> the repo isn't sitting beside `learning_ai_common_plat` — fix the layout, don't
> chase a token. See [The local-dev "registry offline" trap](#the-local-dev-registry-offline-trap).

---

## 1. What is Gitea here?

[Gitea](https://gitea.io) is the **self-hosted Git server + package registry** that
backs the ByteLyst ecosystem. It runs on the production VM and exposes a private
**npm registry** for the shared `@bytelyst/*` packages (`@bytelyst/cosmos`,
`@bytelyst/config`, `@bytelyst/ui`, `@bytelyst/telemetry`, etc.) that live in
`learning_ai_common_plat`.

- **Public host:** `https://gitea.bytelyst.com/`
- **npm registry API (on the VM / via tunnel):** `http://localhost:3300/api/packages/bytelyst/npm/`
- **Auth:** a personal access token exported as `GITEA_NPM_TOKEN`

The registry exists so that **Docker images and CI builds** can install
`@bytelyst/*` without needing the `learning_ai_common_plat` source tree copied
into the build context.

## 2. The two resolution paths (this is the whole story)

Every ByteLyst product repo (`learning_ai_invt_trdg`, `learning_ai_clock`, …) is a
pnpm workspace that depends on `@bytelyst/*`. There are exactly two ways those
deps get satisfied:

### Path A — Local dev: workspace links (no registry, no token)

Each product repo ships a `.pnpmfile.cjs` hook and a `pnpm-workspace.yaml` that,
**by default**, rewrite every `@bytelyst/*` dependency to `workspace:*` and point
it at the sibling `learning_ai_common_plat/packages/*` source on disk.

```
<parent>/
├── learning_ai_common_plat/      # source of @bytelyst/* packages
└── learning_ai_invt_trdg/        # product repo — resolves siblings via workspace links
```

- `pnpm-workspace.yaml` globs `../learning_ai_common_plat/packages/*`
- `.pnpmfile.cjs` (default `BYTELYST_PACKAGE_SOURCE=common-plat`) rewrites
  `@bytelyst/foo` → `workspace:*` **when it finds the package on disk**
- Both lookups are **relative to the repo's parent directory**

Result: `pnpm install` links packages straight from source. **No `localhost:3300`,
no `GITEA_NPM_TOKEN`, no published artifacts required.** This is the correct path
for all laptop / dev-box work.

> Override the sibling location if your checkout lives elsewhere:
> `BYTELYST_COMMON_PLAT_ROOT=/abs/path/to/learning_ai_common_plat pnpm install`

### Path B — Docker / CI build: the Gitea registry (token required)

Inside a Docker build there is no sibling source tree, so the build pulls
`@bytelyst/*` from the Gitea npm registry instead. Example
(`learning_ai_invt_trdg/backend/Dockerfile`):

```dockerfile
ARG GITEA_NPM_TOKEN
RUN printf '@bytelyst:registry=http://localhost:3300/api/packages/bytelyst/npm/\n//localhost:3300/api/packages/bytelyst/npm/:_authToken=${GITEA_NPM_TOKEN}\n' > .npmrc \
  && pnpm install --ignore-scripts --lockfile=false
```

The deploy wrapper `deploy-invttrdg.sh` (in this repo) sets this up:

1. **Pre-flight check** — verifies each required `@bytelyst/*` package is published
   (`curl -sf "${GITEA_REGISTRY}${package}"`); fails early with remediation if not.
2. **Token resolution** — reads `GITEA_NPM_TOKEN` from `/opt/bytelyst/.gitea_token`
   or `~/.gitea_npm_token`.
3. **Build** — `docker build --network host --build-arg GITEA_NPM_TOKEN=... …`
   (`--network host` lets the container reach `localhost:3300` on the VM).

## 3. The local-dev "registry offline" trap

**Symptom**

```
 WARN  GET http://localhost:3300/api/packages/.../@bytelyst%2Fcosmos error (ECONNREFUSED)
 ERR_PNPM_FETCH  GITEA_NPM_TOKEN ... 401 / registry offline
```

…on a plain `pnpm install`, on a laptop, with no Docker involved.

**Root cause**

The repo was cloned **standalone** (e.g. `D:\SANDBOX\learning_ai_invt_trdg`) with
**no sibling `learning_ai_common_plat`**. `.pnpmfile.cjs` couldn't find the package
source on disk, so it left the `@bytelyst/*` specifiers untouched and pnpm fell
back to the registry in `.npmrc` — which is the **Path B (Docker/CI) registry**,
not meant for local dev. With the VM tunnel down and no token, the install dies.

**Fix (layout, not token)**

Place the product repo **beside** `learning_ai_common_plat` under a common parent,
then reinstall:

```bash
# from the product repo
pnpm install                 # or: pnpm run install:common-plat
```

Or, if you can't move the checkout, point at the sibling explicitly:

```bash
BYTELYST_COMMON_PLAT_ROOT=/abs/path/to/learning_ai_common_plat pnpm install
```

That's it — no token, no running registry needed for local work.

> **How we hit & solved this (May 2026):** a Cosmos cost-optimization task required
> building/testing `learning_ai_invt_trdg`, but it had been cloned standalone under
> `D:\SANDBOX\`. `pnpm install` fell back to the offline `localhost:3300` registry
> and failed. The fix was **not** to restore the registry or mint a token — it was
> to move the repo beside `learning_ai_common_plat` (into the same workspace parent)
> so `.pnpmfile.cjs` could rewrite `@bytelyst/*` → `workspace:*`. Install then
> succeeded in seconds with zero registry involvement. The product repos'
> `AGENTS.md` / `README.md` were updated to document the required sibling layout
> and to stop implying `GITEA_NPM_TOKEN` is needed for local dev.

## 4. The deploy-side "package not published" issue

**Symptom** — `deploy-invttrdg.sh` aborts:

```
Required @bytelyst packages not published to Gitea registry:
@bytelyst/cosmos @bytelyst/config ...
```

**Root cause** — `learning_ai_common_plat` published new/changed packages that were
never pushed to the Gitea registry the Docker build pulls from.

**Fix** — republish the packages to Gitea, then re-run the deploy:

```bash
python3 /opt/bytelyst/republish_packages.py   # publishes all @bytelyst/* to Gitea
./deploy-invttrdg.sh
```

**Token-side failures** (`GITEA_NPM_TOKEN not set and no token file found`) — ensure
the token file exists at `/opt/bytelyst/.gitea_token` (preferred) or
`~/.gitea_npm_token`. The deploy script `unset`s any inherited env var first and
reads from file, so a stale shell export won't mask a missing/wrong file.

## 5. Troubleshooting quick reference

| Symptom | Context | Cause | Fix |
|---|---|---|---|
| `pnpm install` hits `localhost:3300` / ECONNREFUSED / 401 | Local laptop | Repo not beside `learning_ai_common_plat`; `.pnpmfile.cjs` fell back to registry | Move repo into the workspace parent, or set `BYTELYST_COMMON_PLAT_ROOT`; re-run `pnpm install` |
| `Cannot find module @bytelyst/...` after install | Local | `learning_ai_common_plat` packages not built | `cd ../learning_ai_common_plat && pnpm install && pnpm build` |
| `Required @bytelyst packages not published` | Deploy/CI | Packages missing from Gitea registry | `python3 /opt/bytelyst/republish_packages.py`, then redeploy |
| `GITEA_NPM_TOKEN not set / no token file` | Deploy/CI | Missing token file | Create `/opt/bytelyst/.gitea_token` or `~/.gitea_npm_token` |
| Docker build can't reach registry | Docker | Missing `--network host` | Build with `docker build --network host …` (deploy scripts already do) |

## 6. Mental model

```
                    @bytelyst/* dependency
                            │
            ┌───────────────┴────────────────┐
            │                                 │
     LOCAL DEV (laptop)                DOCKER / CI BUILD
   .pnpmfile.cjs → workspace:*      .npmrc → Gitea registry
   from sibling common_plat         http://localhost:3300 + token
            │                                 │
   no registry, no token            needs published pkgs + GITEA_NPM_TOKEN
                                     + docker build --network host
```

**Rule of thumb:** if you're on a laptop and you see `localhost:3300` or a token
prompt, you're on the wrong path — fix the **directory layout**, not the registry.

## Related

- Product repo guidance: `learning_ai_invt_trdg/AGENTS.md` → "Local Development Setup",
  `learning_ai_invt_trdg/README.md` → "Shared Dependencies"
- Resolution hook: `<product-repo>/.pnpmfile.cjs`, `<product-repo>/pnpm-workspace.yaml`
- Deploy wrapper: `deploy-invttrdg.sh` (this repo)
- Docker prep (tarball alternative used by some repos): `learning_ai_common_plat/scripts/docker-prep.sh`
