Appearance
Publish flow
This is the present-state pipeline. Public-npm publish is target state and is not exercised today; see the npm publish safety audit.
High-level sequence
1. Build the package (turbo + tsc + each package's build.mjs)
2. Pack the tarball (npm pack)
3. Push to Gitea (npm publish to registry.hivecast.ai)
4. Update discovery-index.json next to the tarball
5. Consumers see the new latest immediatelyStep-by-step
1. Build
Standard monorepo build. From the repo root:
bash
pnpm install
pnpm build:affectedEach package builds to its own dist/ according to its build.mjs or package.json build script. The build artifact is what gets packed.
2. Pack
npm pack creates <package>-<version>.tgz containing exactly what npm publish would push:
bash
cd projects/matrix-3/packages/<name>
npm pack --dry-run # inspect what would be includedThe package.json "files" array controls inclusion. The npm publish safety audit lists 9 packages currently lacking "files" — fix those before any publish.
3. Publish
bash
cd projects/matrix-3/packages/<name>
NPM_CONFIG_REGISTRY=https://registry.hivecast.ai/api/packages/hivecast-admin/npm/ \
NPM_CONFIG__AUTH_TOKEN=<gitea-token> \
npm publishGitea accepts the tarball, stores it in its blob volume, and updates its package metadata so the version is discoverable via the npm packages API.
4. Update discovery-index.json
The catalog's discovery-index.json is separate from the artifact registry. Updating it is a publish-pipeline responsibility, not Gitea's. The current implementation lives in projects/matrix-3/packages/mx-cli/src/utils/discovery-index.ts.
Roughly:
typescript
// Read existing index
const index = JSON.parse(fs.readFileSync(`${registryRoot}/discovery-index.json`));
// Build new entry from package's matrix.json + package.json
const newEntry = extractDiscoveryMetadata(packagePath);
// Merge into index
index.packages[packageName] ??= { versions: {} };
index.packages[packageName].versions[version] = {
indexedAt: new Date().toISOString(),
indexedBy: 'publish-pipeline',
metadata: newEntry,
};
// Write back
fs.writeFileSync(`${registryRoot}/discovery-index.json`, JSON.stringify(index));The index is written to the same registry root the SystemPackageRegistryActor reads from (<host-home>/registry/ for local mode, or the equivalent path on the registry server for cloud mode).
5. Visibility
Once Gitea has the tarball and discovery-index.json has the entry:
npm install @open-matrix/<pkg>finds the new version (Gitea side).system.packages.registry.searchincludes the package in results (catalog side).- A consumer with a stale lockfile is unaffected until they
npm update.
Pre-publish gates
Before running publish, the publish-time pipeline must verify:
| Gate | Why |
|---|---|
pnpm build:affected succeeds | Tarball must be built |
npm pack --dry-run review | Catch accidental file inclusion |
pnpm test:affected green | Quality gate |
package.json.version is bumped | Otherwise npm publish rejects "already exists" |
package.json.files is set | The npm publish safety audit identifies 9 packages missing this |
No build artifacts in dist/matrix-artifact.json leak absolute paths | npm publish safety audit, item 1 |
Failure modes
| Failure | Cause | Fix |
|---|---|---|
403 Forbidden from Gitea | Token lacks write:package scope | Issue new token with correct scope |
409 Conflict | Version already published | Bump version |
404 from index update step | <registry-root>/discovery-index.json missing | Initialize empty index file or fix path |
| Search doesn't see the new version | Index update step skipped | Re-run discovery-index update |
Cloud (CI) vs. local publish
The .github/workflows/release.yml workflow is the canonical CI publish path (target state — currently dormant for public npm). For internal Gitea publishes, projects/deploy-cloud/deploy.sh runs publish-equivalent operations as part of the host-deploy pipeline, including the discovery-index update step.
Local manual publishing (developer's machine) is supported but discouraged outside of bootstrapping. CI publishes from a clean checkout to avoid leaking local artifact paths into tarballs.
See also
Source:
.github/workflows/release.yml,projects/deploy-cloud/deploy.sh,projects/matrix-3/packages/mx-cli/src/utils/discovery-index.ts.