build(release): publish the vendored framework and the native packages publicly

The three release sequences shipped with publishConfig.access: restricted, so
nothing in the @deepseek-ai scope was installable from outside the organization.

A restricted dependency is what actually blocks a public consumer: every harness
package declares the vendored framework as a peerDependency, and
dsh-sandbox-local declares the Landlock entry as a dependency. Those two
sequences therefore go public first — the nine vendor/* packages and the three
native/landlock-run packages — while the dsh family stays restricted until its
own sequence is opened deliberately. No public package requires a restricted one
in this arrangement.

Access is now per sequence, so no publish path can pass --access: one flag
cannot express two levels and would override the manifest that owns the fact.
publish.ts stops passing it, matching the native workflow, and
check-workspace-constraints holds each manifest to its own sequence's level,
which is what stops the scope from drifting one package at a time.

Harness consumers reference the Landlock entry as workspace:^ instead of
workspace:*, so a published harness package accepts the entry's patch and minor
releases. The entry keeps workspace:* for its platform packages, where the
binary must match the entry version exactly.

Two rationales that named a private registry no longer describe the vendored
sequence; they now state the durable reason, which is that the verification must
not depend on the registry already carrying matching versions.
This commit is contained in:
imccyu
2026-08-13 14:05:48 +08:00
parent 1646b7617e
commit a213befd0f
29 changed files with 152 additions and 50 deletions
@@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write .agents/notes/implemented/process/2026-08-06-in-repository-landlock-release.md
2026-08-06-in-repository-landlock-release.md: 1540cebbf5a3dffa20003c70ffcec426aeca104b
2026-08-06-in-repository-landlock-release.zh.md: 5defa5f3ca83e5a420d0c11857ad4cf46555450b
2026-08-06-in-repository-landlock-release.md: 82b21cc0c30338ad11583797f011794b8dbcc90c
2026-08-06-in-repository-landlock-release.zh.md: 7ebd69f505c3b071216eb23f5eed35c392e6f844
@@ -18,7 +18,7 @@ The consolidation must preserve platform selection. The public distribution is d
`native/landlock-run` and `native/landlock-run/packages/*` belong to the repository's root pnpm workspace and use the root `pnpm-lock.yaml`. Harness consumers declare `@deepseek-ai/node-addon-landlock-run` with `workspace:*`, so development, type checking, builds, and pull-request tests resolve the entry package from the same checkout. The root TypeScript project graph builds that entry package before consumers, and the repository cleaner owns its direct `lib/` output.
The public npm boundary is three organization-owned packages with one launcher-family version: `@deepseek-ai/node-addon-landlock-run`, `@deepseek-ai/node-addon-landlock-run-linux-x64`, and `@deepseek-ai/node-addon-landlock-run-linux-arm64`. The entry package retains both platform packages as `optionalDependencies`; their `os` and `cpu` manifest fields let npm install only the compatible package. Repository constraints allow public publication only for those three names, require `publishConfig.access: public`, and require their versions to match the private launcher workspace root. The former unscoped names are not release targets of this repository; other repository workspaces remain private under the existing constraint.
The public npm boundary is three organization-owned packages with one launcher-family version: `@deepseek-ai/node-addon-landlock-run`, `@deepseek-ai/node-addon-landlock-run-linux-x64`, and `@deepseek-ai/node-addon-landlock-run-linux-arm64`. The entry package retains both platform packages as `optionalDependencies`; their `os` and `cpu` manifest fields let npm install only the compatible package. Repository constraints require `publishConfig.access: public` for those three names and require their versions to match the private launcher workspace root. The former unscoped names are not release targets of this repository. These three are no longer the only public packages: the [per-sequence access decision](2026-08-13-public-vendor-and-native-sequences.md) publishes the nine vendored framework packages publicly as well, while the dsh family stays restricted.
The main repository owns both native CI and publication. `Landlock Run` runs for relevant pull requests and `master` pushes and builds each platform on its matching native runner. The manually dispatched `Landlock Run Release` workflow builds both platform binaries, transfers them as workflow artifacts, assembles and verifies the complete package family, packs immutable npm tarballs, installs and exercises those tarballs, and only then permits the protected publish job. Platform tarballs publish before the entry tarball that optionally depends on them. Publication uses `landlock-run-vX.Y.Z` tags so launcher releases cannot collide with other release families in the monorepo; prereleases use the npm `next` dist-tag.
@@ -18,7 +18,7 @@ Status: implemented
`native/landlock-run``native/landlock-run/packages/*` 属于仓库根 pnpm workspace,并使用根 `pnpm-lock.yaml`。Harness 消费方将 `@deepseek-ai/node-addon-landlock-run` 声明为 `workspace:*`,因此开发、类型检查、构建和 PR 测试都会从同一个 checkout 解析入口包。根 TypeScript 项目图会先构建该入口包,再构建消费方;仓库清理器负责清理其直接生成的 `lib/` 输出目录。
公开 npm 分发边界由 3 个归组织所有的包组成,它们共用一个启动器包家族版本:`@deepseek-ai/node-addon-landlock-run``@deepseek-ai/node-addon-landlock-run-linux-x64``@deepseek-ai/node-addon-landlock-run-linux-arm64`。入口包继续通过 `optionalDependencies` 声明两个平台包;它们在 manifest(元数据清单)中的 `os``cpu` 字段让 npm 只安装兼容的包。仓库约束只允许公开发布这 3 个包名,要求设置 `publishConfig.access: public`,并要求其版本与私有启动器 workspace 根包一致。原先的非 scoped 包名不属于本仓库的发布目标;仓库中的其他 workspace 仍受现有约束保护,保持私有状态
公开 npm 分发边界由 3 个归组织所有的包组成,它们共用一个启动器包家族版本:`@deepseek-ai/node-addon-landlock-run``@deepseek-ai/node-addon-landlock-run-linux-x64``@deepseek-ai/node-addon-landlock-run-linux-arm64`。入口包继续通过 `optionalDependencies` 声明两个平台包;它们在 manifest(元数据清单)中的 `os``cpu` 字段让 npm 只安装兼容的包。仓库约束要求这 3 个包名设置 `publishConfig.access: public`,并要求其版本与私有启动器 workspace 根包一致。原先的非 scoped 包名不属于本仓库的发布目标。这 3 个已不再是唯一的公开包:[按序列区分 access 的决策](2026-08-13-public-vendor-and-native-sequences.md)让 vendored 框架九包也公开发布,而 dsh 族保持受限
主仓库同时负责原生 CI 和发布。`Landlock Run` 会为相关 PR 和 `master` 推送运行,并在各自匹配的原生 runner 上构建每个平台包。手动触发的 `Landlock Run Release` 工作流会构建两个平台的二进制文件,将其作为工作流产物传递,组装并验证完整的包家族,打包出内容不可变的 npm tarball,安装并实际运行这些 tarball,之后才允许受保护的发布作业执行。发布顺序是平台 tarball 在前,最后发布将它们列为可选依赖的入口 tarball。发布使用 `landlock-run-vX.Y.Z` tag,避免启动器版本与 monorepo 中其他发布家族发生冲突;预发布版本使用 npm 的 `next` dist-tag。
@@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write .agents/notes/implemented/process/2026-08-10-npm-release-sequences.md
2026-08-10-npm-release-sequences.md: 13f343911b6d684ec8738b2245ceae8d848e2f0c
2026-08-10-npm-release-sequences.zh.md: 4116b74b54e84d33df29fd0ab9169f8d38d5514d
2026-08-10-npm-release-sequences.md: e8138aef923e201cc0883232f48ce6921452ca00
2026-08-10-npm-release-sequences.zh.md: 7ce9fa01dbe10cbdae5585f64392d0ca6a9fb868
@@ -26,7 +26,7 @@ Two hard blockers sat in the way. All 217 workspace manifests set `private: true
| vendored framework | the nine `vendor/*` packages | each package on its own version line | `vendor-<package>-v<version>` (one per package) | `release-vendor.yml` |
| native | `native/landlock-run/packages/*` | its own `0.0.x` | `landlock-run-v<version>` | `landlock-run-release.yml` |
All three publish privately to the `@deepseek-ai` scope on npmjs.com. `publishConfig.access` in each manifest is `restricted` and no workflow passes `--access`, because a command-line flag overrides the manifest.
All three publish to the `@deepseek-ai` scope on npmjs.com, and access is per sequence rather than per scope: the vendored framework and the native packages are `public`, the dsh family is `restricted` ([rationale](2026-08-13-public-vendor-and-native-sequences.md)). No publish path passes `--access`, because one flag cannot serve sequences that disagree and would override the manifest that owns the level.
### Versions land in the repository from a local command; CI only checks and uploads
@@ -107,12 +107,12 @@ The verification also packs the Landlock entry, which `dsh-sandbox-local` declar
| Item | Content |
|---|---|
| release-set manifests | `private: true` removed; `publishConfig.access: restricted` and `repository` with each package's `directory` added |
| release-set manifests | `private: true` removed; `publishConfig.access` per sequence and `repository` with each package's `directory` added |
| release-set boundary | every member of `packages/*/*`, `apps/*`, and `vendor/*` |
| dependency protocol | workspace-internal references are `workspace:^`, with `check-workspace-constraints.ts` and the invariant-companion rule requiring it |
| root `AGENTS.md` | the convention that vendored packages are `private: true` no longer holds |
| `vendor/README.md` | records `src` joining `cordis`'s `files` as a local modification |
| the three native packages | `publishConfig.access: restricted`, and their workflow no longer passes `--access` |
| the three native packages | `publishConfig.access: public`, and their workflow passes no `--access` |
### Relationship to the earlier proposal
@@ -26,7 +26,7 @@ Status: implemented
| vendored framework | `vendor/*` 九个包 | 每包各自一条版本线 | `vendor-<包名>-v<版本>`(每包一个) | `release-vendor.yml` |
| native | `native/landlock-run/packages/*` | 自己的 `0.0.x` | `landlock-run-v<版本>` | `landlock-run-release.yml` |
三组一律发到 npmjs.com 的 `@deepseek-ai` scope 下的私有包。每个 manifest 的 `publishConfig.access` 都是 `restricted`,且没有任何 workflow 传 `--access`——命令行选项会覆盖 manifest。
三组一律发到 npmjs.com 的 `@deepseek-ai` scope,且 access 按序列而非按 scope 区分:vendored 框架与 native 包是 `public`dsh 族是 `restricted`[理由](2026-08-13-public-vendor-and-native-sequences.md))。没有任何发布路径传 `--access`——一个选项无法服务级别互不相同的序列,且会覆盖真正拥有该级别的 manifest。
### 版本由本地命令写进仓库,CI 只核对与上传
@@ -107,12 +107,12 @@ dsh 的验证会一并安装 vendored 族的 pack 产物。harness 的包把 ven
| 项 | 内容 |
|---|---|
| 发布集 manifest | 去掉 `private: true`;补 `publishConfig.access: restricted` 与带各自 `directory``repository` |
| 发布集 manifest | 去掉 `private: true`按序列`publishConfig.access` 与带各自 `directory``repository` |
| 发布集边界 | `packages/*/*``apps/*``vendor/*` 的全部成员 |
| 依赖协议 | workspace 内部引用为 `workspace:^`,由 `check-workspace-constraints.ts` 与 invariant companion 规则强制 |
| 根 `AGENTS.md` | 「vendored 包是 `private: true`」这条约定不再成立 |
| `vendor/README.md` | 记录「`src` 加入 `cordis``files`」这条本地修改 |
| native 三包 | `publishConfig.access: restricted`,且其 workflow 不`--access` |
| native 三包 | `publishConfig.access: public`,且其 workflow 不传 `--access` |
### 与先前提案的关系
@@ -0,0 +1,6 @@
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write .agents/notes/implemented/process/2026-08-13-public-vendor-and-native-sequences.md
2026-08-13-public-vendor-and-native-sequences.md: ada7c3bcbe5feb288d67fe8e7ee7204dda6b4597
2026-08-13-public-vendor-and-native-sequences.zh.md: 1f687d1134baf58c59f5cf6014e265b24a38042f
@@ -0,0 +1,45 @@
# Agent Note: npm access per release sequence: the vendored framework and the native packages publish publicly
Status: implemented
English | [中文](2026-08-13-public-vendor-and-native-sequences.zh.md)
## Problem
The [three release sequences](2026-08-10-npm-release-sequences.md) shipped with `publishConfig.access: restricted`, so every package published to the `@deepseek-ai` scope was visible only inside the organization. Five rehearsal publications ran that way, through `dsh@0.0.1-rc.5`, `vendor *-rc.4`, and `landlock-run@0.0.1`.
A restricted dependency is what actually blocks a public consumer. Every harness package declares the vendored framework as a `peerDependency`, and `dsh-sandbox-local` declares the Landlock entry as a `dependency`. A public package that requires a restricted one cannot be installed by anyone outside the organization, so those two sequences have to be public before the dsh family can be — and while the dsh family is still restricted, they are the only two whose artifacts an outside consumer would need to resolve.
## Decision
Access is a property of each release sequence, not of the scope:
| Sequence | Members | `publishConfig.access` |
|---|---|---|
| vendored framework | the nine `vendor/*` packages | `public` |
| native | the three `native/landlock-run/packages/*` packages | `public` |
| dsh | `packages/*/*` + `apps/*` (221 members) | `restricted` |
`check-workspace-constraints.ts` holds every manifest to its own sequence's level, which is what stops the scope from drifting: a new `vendor/*` package left at `restricted`, or a dsh member flipped to `public`, fails the workspace constraints.
**No publish path passes `--access`.** A single flag cannot serve sequences that disagree, and a flag overrides the manifest that owns the fact — so `publish.ts` passes none, and the native workflow continues to pass none. Each packed manifest decides.
Harness consumers reference the Landlock entry as `workspace:^` rather than `workspace:*`, so a published harness package accepts the entry's patch and minor releases instead of pinning one exact version. The entry keeps `workspace:*` for its two platform packages, where the binary must match the entry version exactly.
Access is a property of the package, not of a version: the twelve packages already published as restricted — `landlock-run@0.0.1` and the vendored `*-rc.*` versions — become world-readable at their next publication.
## Alternatives considered
**Flip the whole scope public at once.** Rejected for now: it would make the next dsh release public as a side effect of a manifest change rather than a deliberate release decision. Opening the two dependency sequences first is the order that keeps every published package installable at each step, and it is the precondition for opening dsh whenever that is decided.
**Keep everything restricted and grant a read-only team instead.** `npm access grant read-only <org:team> <package>` is per-package with no scope wildcard, so covering the set means one grant per package plus a standing reconciliation job for every package added afterwards. It also only reaches organization members, which does not serve an installable public artifact.
**Publish public from the publish path instead of the manifests.** Impossible for a mixed scope — one `--access` flag cannot express two levels — and it would override the manifest that the workspace constraint already checks.
## Consequences
- **The twelve packages are public from their next publication onward, and that is not cleanly reversible.** Returning to a restricted scope requires a paid plan plus per-package `npm access set status=private`, and anything already downloaded or mirrored stays out.
- **`@deepseek-ai/dsh` is still not installable from outside the organization.** Its manifests stay `restricted`; what changed is that its published dependencies no longer would be, so opening it later is a version decision rather than a dependency problem.
- **What ships from the two public sequences is now world-readable, so their payload policy carries more weight.** `vendor/cordis` publishes `src` deliberately, because its export map declares `./src/*`; the Landlock entry publishes `src/main.c` as a documented audit surface.
- **The private-packages plan is no longer required for these two sequences.** The `402 Payment Required` failure that blocked the first native publication cannot recur for a public package.
- **An unauthenticated `npm view` becomes a usable check for the public sequences.** While every package was restricted, a machine without credentials received `E404` for a package that existed, which is indistinguishable from an absent version.
@@ -0,0 +1,45 @@
# Agent Note: 按发布序列区分 npm access:vendored 框架与 native 包公开发布
Status: implemented
[English](2026-08-13-public-vendor-and-native-sequences.md) | 中文
## Problem
[三条发布序列](2026-08-10-npm-release-sequences.md)交付时带的是 `publishConfig.access: restricted`,因此发到 `@deepseek-ai` scope 的每个包只在组织内可见。五次排练发布都是这样跑的:`dsh@0.0.1-rc.5`、vendor 的 `*-rc.4``landlock-run@0.0.1`
真正卡住公开消费者的是**受限的依赖**。每个 harness 包都把 vendored 框架声明成 `peerDependency`,`dsh-sandbox-local` 把 Landlock 入口声明成 `dependency`。一个公开包若要求一个受限包,组织外的人根本装不上;所以这两条序列必须先公开,dsh 族才可能公开 —— 而在 dsh 族仍受限期间,它们也正是外部消费者唯一需要解析到的两条。
## Decision
access 是每条发布序列的属性,不是整个 scope 的属性:
| 序列 | 成员 | `publishConfig.access` |
|---|---|---|
| vendored 框架 | `vendor/*` 九包 | `public` |
| native | `native/landlock-run/packages/*` 三包 | `public` |
| dsh | `packages/*/*` + `apps/*`(221 个成员) | `restricted` |
`check-workspace-constraints.ts` 按各自序列的级别校验每个 manifest,这是阻止 scope 漂移的那道闸:新增的 `vendor/*` 包留在 `restricted`、或某个 dsh 成员被改成 `public`,都会让 workspace 约束失败。
**没有任何发布路径传 `--access`。** 一个选项无法服务级别互不相同的序列,而且选项会覆盖真正拥有这个事实的 manifest —— 所以 `publish.ts` 不传,native 的 workflow 也照旧不传,由各 packed manifest 决定。
harness 消费方引用 Landlock 入口改用 `workspace:^` 而非 `workspace:*`,于是发布出去的 harness 包接受该入口的 patch 与 minor 版本,而不是钉死一个精确版本。入口对它那两个平台包仍保持 `workspace:*` —— 那里二进制必须与入口版本完全一致。
access 是包的属性、不是版本的属性:已经以 restricted 发布的这十二个包(`landlock-run@0.0.1` 与 vendored 的 `*-rc.*`)会在**下一次发布**时变为全网可读。
## Alternatives considered
**一次性把整个 scope 改成 public。** 暂不采用:那会让下一次 dsh 发布因为一次 manifest 改动而顺带变成公开,而不是出自一个刻意的发布决定。先公开这两条依赖序列,是能让每一步的已发布包都保持可安装的顺序,也是将来决定公开 dsh 时的前置条件。
**全部保持受限,改为授予一个只读 team。** `npm access grant read-only <org:team> <包>` 是逐包的、没有 scope 通配,覆盖全集意味着每个包一次 grant,外加一个为后续新增包长期补齐的对账任务。它也只能覆盖组织成员,无法服务一个可安装的公开产物。
**在发布路径而不是 manifest 里指定公开。** 混合 scope 下不可能 —— 一个 `--access` 选项表达不了两种级别 —— 而且它会覆盖 workspace 约束正在校验的那个 manifest。
## Consequences
- **这十二个包从下一次发布起就是公开的,而且不能干净地回退。** 回到受限 scope 需要付费套餐加逐包 `npm access set status=private`,且已经被下载或镜像的内容收不回来。
- **`@deepseek-ai/dsh` 仍然装不了(组织外)。** 它的 manifest 保持 `restricted`;变化的是它已发布的依赖不再受限,所以将来公开它是一个版本决定,而不再是依赖问题。
- **两条公开序列交付的内容成为全网可读,它们的 payload 策略分量因此变重。** `vendor/cordis` 有意发布 `src`,因为其导出映射声明了 `./src/*`;Landlock 入口按既有约定发布 `src/main.c` 作为审计面。
- **这两条序列不再需要私有包套餐。** 阻塞过首次 native 发布的 `402 Payment Required` 失败形态对公开包不会再出现。
- **对公开序列,无凭据的 `npm view` 成为一个可用的检查手段。** 在所有包都受限的时期,没有凭据的机器对一个确实存在的包会收到 `E404`,与「版本不存在」无法区分。
+4 -2
View File
@@ -81,8 +81,10 @@ jobs:
run: pnpm run release:pack --family dsh --out dist/npm
# The harness packages declare the vendored framework as a peer, and this
# job has no credentials for the private registry, so the verification
# installs that family's pack output too. Only dist/npm is published.
# verification must not depend on the registry already carrying matching
# versions — one pull request may bump both families before either
# publishes — so it installs that family's pack output too. Only dist/npm
# is published.
- name: Pack the vendored framework for verification
run: pnpm run release:pack --family vendor --out dist/npm-vendor
@@ -32,7 +32,7 @@
},
"license": "BSD-3-Clause",
"publishConfig": {
"access": "restricted"
"access": "public"
},
"optionalDependencies": {
"@deepseek-ai/node-addon-landlock-run-linux-arm64": "workspace:*",
@@ -26,6 +26,6 @@
},
"license": "BSD-3-Clause",
"publishConfig": {
"access": "restricted"
"access": "public"
}
}
@@ -26,6 +26,6 @@
},
"license": "BSD-3-Clause",
"publishConfig": {
"access": "restricted"
"access": "public"
}
}
@@ -91,7 +91,7 @@
"@deepseek-ai/dsh-tool-jobs": "workspace:^",
"@deepseek-ai/dsh-tools": "workspace:^",
"@deepseek-ai/dsh-agent-instructions": "workspace:^",
"@deepseek-ai/node-addon-landlock-run": "workspace:*",
"@deepseek-ai/node-addon-landlock-run": "workspace:^",
"@deepseek-ai/cordis": "workspace:^"
},
"dependencies": {
+1 -1
View File
@@ -40,7 +40,7 @@
},
"dependencies": {
"@deepseek-ai/dsh-sandbox-windows-acl": "workspace:^",
"@deepseek-ai/node-addon-landlock-run": "workspace:*",
"@deepseek-ai/node-addon-landlock-run": "workspace:^",
"@deepseek-ai/schemastery": "workspace:^"
},
"devDependencies": {
+1 -1
View File
@@ -48,6 +48,6 @@
"@deepseek-ai/dsh-sandbox-local": "workspace:^",
"@deepseek-ai/dsh-sandbox-policy": "workspace:^",
"@deepseek-ai/cordis": "workspace:^",
"@deepseek-ai/node-addon-landlock-run": "workspace:*"
"@deepseek-ai/node-addon-landlock-run": "workspace:^"
}
}
+3 -9
View File
@@ -1124,12 +1124,6 @@ importers:
'@deepseek-ai/dsh-subagent':
specifier: workspace:^
version: link:../../subagent/subagent
'@deepseek-ai/dsh-subagent-claude-code':
specifier: workspace:^
version: link:../../subagent/subagent-claude-code
'@deepseek-ai/dsh-subagent-codex':
specifier: workspace:^
version: link:../../subagent/subagent-codex
'@deepseek-ai/dsh-subagent-fork-in-process':
specifier: workspace:^
version: link:../../subagent/subagent-fork-in-process
@@ -3922,7 +3916,7 @@ importers:
specifier: workspace:^
version: link:../../core/tools
'@deepseek-ai/node-addon-landlock-run':
specifier: workspace:*
specifier: workspace:^
version: link:../../../native/landlock-run/packages/entry
packages/examples/jsonrpc-demo:
@@ -5661,7 +5655,7 @@ importers:
specifier: workspace:^
version: link:../sandbox-windows-acl
'@deepseek-ai/node-addon-landlock-run':
specifier: workspace:*
specifier: workspace:^
version: link:../../../native/landlock-run/packages/entry
'@deepseek-ai/schemastery':
specifier: link:../../../vendor/schemastery
@@ -6451,7 +6445,7 @@ importers:
specifier: workspace:^
version: link:../../subprocess/subprocess-local
'@deepseek-ai/node-addon-landlock-run':
specifier: workspace:*
specifier: workspace:^
version: link:../../../native/landlock-run/packages/entry
packages/shell/pwsh-local:
+14 -6
View File
@@ -231,8 +231,8 @@ function checkWorkspace({ dir, manifest }: WorkspaceManifest): string[] {
if (manifest.private === true) {
errors.push(`${label}: published Landlock package must not set "private": true`)
}
if (manifest.publishConfig?.access !== 'restricted') {
errors.push(`${label}: published Landlock package must set publishConfig.access to "restricted"`)
if (manifest.publishConfig?.access !== 'public') {
errors.push(`${label}: published Landlock package must set publishConfig.access to "public"`)
}
const expectedDirectory = dir
if (manifest.repository?.type !== 'git'
@@ -242,13 +242,21 @@ function checkWorkspace({ dir, manifest }: WorkspaceManifest): string[] {
}
} else if (releaseMemberDirectory.test(dir)) {
// Release members state that they are publishable: npm refuses a private
// package, the scope is published privately, and the repository field is
// how a consumer of a private package finds its source.
// package, and the repository field is how a consumer finds the source of
// the package it installed.
//
// Access is per release sequence, not per scope: the vendored framework and
// the Landlock packages publish publicly because outside consumers install
// them, while the dsh family stays restricted until its own sequence goes
// public. A mixed scope is why no publish path passes `--access` — one flag
// cannot serve both, so each packed manifest decides
// ([rationale](../.agents/notes/implemented/process/2026-08-13-public-vendor-and-native-sequences.md)).
const expectedAccess = dir.startsWith('vendor/') ? 'public' : 'restricted'
if (manifest.private === true) {
errors.push(`${label}: release member must not set "private": true`)
}
if (manifest.publishConfig?.access !== 'restricted') {
errors.push(`${label}: release member must set publishConfig.access to "restricted"`)
if (manifest.publishConfig?.access !== expectedAccess) {
errors.push(`${label}: release member must set publishConfig.access to "${expectedAccess}"`)
}
if (manifest.repository?.type !== 'git'
|| manifest.repository.url !== publishedRepositoryUrl
+5 -4
View File
@@ -20,9 +20,6 @@ import { releaseFamily } from './families.ts'
import { attempt, isEntry, run } from './process.ts'
import { packedIdentity, readPublishOrder } from './tarball.ts'
/** npm access level for every package this repository publishes. */
const ACCESS = 'restricted'
/** What the registry knows about one version. */
type RegistryState =
| { readonly kind: 'absent' }
@@ -91,7 +88,11 @@ function main(): void {
}
// A prerelease version never takes the latest dist-tag.
const tagArgs = version.includes('-') ? ['--tag', 'next'] : []
run('npm', ['publish', tarball, '--access', ACCESS, ...tagArgs])
// No --access: the sequences do not share one access level, so a
// command-line flag could not serve both and would override the manifest
// that does. Each packed manifest decides, and
// check-workspace-constraints holds every manifest to its sequence's level.
run('npm', ['publish', tarball, ...tagArgs])
published += 1
}
+3 -2
View File
@@ -5,8 +5,9 @@
* Every tarball the installed tree needs comes from `--from`, so the only
* registry traffic is for external dependencies. That matters beyond hermetic
* verification: the harness packages declare the vendored framework as a peer,
* and those packages live in another release sequence that this credential-free
* job cannot fetch from a private registry — so a dsh verification passes the
* those packages live in another release sequence, and this job must not depend
* on the registry already carrying versions that match — one pull request may
* bump both families before either publishes — so a dsh verification passes the
* vendored family's pack output too, while publishing only its own
* ([rationale](../../.agents/notes/implemented/process/2026-08-10-npm-release-sequences.md)).
*
+1 -1
View File
@@ -3,7 +3,7 @@
"description": "Meta-Framework for Modern JavaScript Applications",
"version": "4.0.1-rc.4",
"publishConfig": {
"access": "restricted"
"access": "public"
},
"repository": {
"type": "git",
+1 -1
View File
@@ -3,7 +3,7 @@
"description": "A collection of common utilities",
"version": "1.8.2-rc.4",
"publishConfig": {
"access": "restricted"
"access": "public"
},
"repository": {
"type": "git",
+1 -1
View File
@@ -3,7 +3,7 @@
"description": "Nested plugin group for cordis",
"version": "1.0.1-rc.4",
"publishConfig": {
"access": "restricted"
"access": "public"
},
"repository": {
"type": "git",
+1 -1
View File
@@ -3,7 +3,7 @@
"description": "Hot Module Replacement Plugin for Cordis",
"version": "1.0.16-rc.4",
"publishConfig": {
"access": "restricted"
"access": "public"
},
"repository": {
"type": "git",
+1 -1
View File
@@ -3,7 +3,7 @@
"description": "Include files in cordis configurations",
"version": "1.0.6-rc.4",
"publishConfig": {
"access": "restricted"
"access": "public"
},
"repository": {
"type": "git",
+1 -1
View File
@@ -3,7 +3,7 @@
"description": "Plugin loader for cordis",
"version": "1.0.2-rc.4",
"publishConfig": {
"access": "restricted"
"access": "public"
},
"repository": {
"type": "git",
+1 -1
View File
@@ -3,7 +3,7 @@
"description": "Console logger exporter for cordis",
"version": "1.0.1-rc.4",
"publishConfig": {
"access": "restricted"
"access": "public"
},
"repository": {
"type": "git",
+1 -1
View File
@@ -3,7 +3,7 @@
"description": "Type driven schema validator",
"version": "3.18.1-rc.4",
"publishConfig": {
"access": "restricted"
"access": "public"
},
"repository": {
"type": "git",
+1 -1
View File
@@ -3,7 +3,7 @@
"description": "Timer service for cordis",
"version": "1.1.3-rc.4",
"publishConfig": {
"access": "restricted"
"access": "public"
},
"repository": {
"type": "git",