Repository navigation
Commit 50646f0
fix(cli): the compiled plugin manifest filename is the runtime's constant (#28530)
domain:server#2 · os-project-manager · session_0186vfjHHMsRXC9EUT9hTFMo
<!-- claude-projects-attribution: {"github_login":"os-project-manager"}
-->
_Requested by **Leehom** · [project
thread](https://claude.ai/code/project/chan_01TenzsRopZj4jMbvjX8uz1X?thread=cmsg_01TenzsRopZj4jMbvjX8uz1XAzrBawWCXDWe5RxPWMYpti)_
Fixes #28080
Clause-②: yes (widening)
Metadata-protocol: none
## 维护者速读
- **改了什么**:CLI 里插件清单文件名 `MANIFEST_FILENAME` 不再自己写一遍字符串,直接取运行时的
`COMPILED_PLUGIN_MANIFEST_FILE`。为了不让 `os plugin` 每条命令多花约 1
秒加载整个运行时,运行时新开一个只含这个常量的轻量子路径
`@objectstack/runtime/compiled-plugin-manifest-file`。
- **为什么改**:卡 #28080:`os plugin build` 写入、`publish`/`install`
完整性检查豁免用的文件名,和运行时读取用的文件名是两份手抄的同一字符串,一旦漂移,build 出的包运行时找不到清单。
-
**风险与回滚**:文件名本身不变(`objectstack.plugin.json`),已构建的插件包照常可读;只是新增一个子路径导出。回滚即
revert。
-
**先看**:`packages/cli/src/utils/osplugin.ts`(常量改为引用);`packages/runtime/package.json`
与
`tsup.config.ts`(新子路径);`packages/adapters/hono/vitest.config.ts`(为新子路径补的一条测试别名)。
- **两分钟验证**:`pnpm --filter @objectstack/cli exec vitest run --project
unit test/osplugin-manifest-filename.test.ts` → 2 passed;把 osplugin.ts
里那行改成别的字面量,同一命令转红。
- **需要你做的**:无,席位落地。
## What changes
`MANIFEST_FILENAME` in `packages/cli/src/utils/osplugin.ts` was a
hand-kept twin of `COMPILED_PLUGIN_MANIFEST_FILE` in
`packages/runtime/src/compiled-plugin-manifest.ts`. It is now `export
const MANIFEST_FILENAME = COMPILED_PLUGIN_MANIFEST_FILE`, imported from
the runtime, so the entry `os plugin build` writes (`build.ts`), the
entry `os plugin publish` and `os plugin install` exempt from the
integrity map, the entry `computeIntegrity` leaves out, and the entry
`readCompiledPluginManifest` finds are one name. The tree now holds one
`'objectstack.plugin.json'` literal for it. `MANIFEST_FILENAME` stays as
an alias because ten CLI test files and three command files import it.
**Import path, measured.** The constant was not reachable from any
published runtime entry: `@objectstack/runtime` published only `.`, and
its root `index.ts` did not export it. Importing the root entry from
`osplugin.ts` is the heavy path that file's own header already refuses
(`readOspluginManifest` imports the runtime on call for this reason).
Measured on this box, three fresh `node` loads each:
| import | ms |
| :--- | :--- |
| `@objectstack/core` (osplugin.ts already imports it) | 335, 344, 355 |
| `@objectstack/runtime` root | 1447, 1388, 1363 |
| built `packages/cli/dist/utils/osplugin.js` after this change | 450,
417, 447 |
So the constant moved into its own import-free module,
`packages/runtime/src/compiled-plugin-manifest-file.ts`, published as
the subpath `@objectstack/runtime/compiled-plugin-manifest-file` (new
`tsup` entry, new `exports` key with `import`/`require` conditions,
matching the root entry's shape). `compiled-plugin-manifest.ts` imports
and re-exports it, so the runtime's own readers and tests are unchanged.
The runtime has no lean-entry gate of its own
(`check:lean-entry-closure` guards `@objectstack/objectql/core` only);
the module's header says it must stay import-free.
**Hono test alias.** `check:test-source-alias` resolves every published
subpath through every vitest alias table.
`packages/adapters/hono/vitest.config.ts` maps bare
`@objectstack/runtime` by prefix to a mock FILE, which would have sent
the new subpath to
`src/__mocks__/runtime.ts/compiled-plugin-manifest-file` (ENOTDIR). The
gate's remedy is applied: an anchored entry for the subpath ahead of the
prefix entry, pointing at the runtime source. The comment there that
said the runtime publishes only `.` is corrected. This file is outside
the claim's declared file surface; it is a forced consequence of the new
subpath (see Acceptance notes).
## Tests
`packages/cli/test/osplugin-manifest-filename.test.ts` (unit tier):
- `MANIFEST_FILENAME` is `COMPILED_PLUGIN_MANIFEST_FILE` (the runtime's
constant, imported from the new subpath), not compared to a literal.
- An archive whose manifest entry is named `MANIFEST_FILENAME` is read
`ok` by the runtime's `readCompiledPluginManifest`, and
`computeIntegrity` leaves exactly that entry out.
**Ablation** (head `9c90f75a`, the implementation committed first):
`node scripts/ablation-replace.mjs` replaced `export const
MANIFEST_FILENAME = COMPILED_PLUGIN_MANIFEST_FILE;` with `export const
MANIFEST_FILENAME = 'objectstack.plugin.drifted.json';` (anchor 1 → 0,
blob `89db86b4` → `76a05359`). Both cases red: `expected
'objectstack.plugin.drifted.json' to be 'objectstack.plugin.json'` and
`expected false to be true`. Restored: blob back to `89db86b4` = the
HEAD blob, `git diff HEAD` empty. The test imports `osplugin.ts` from
source, so no build sits between the mutation and the run.
## Acceptance notes
- The triage line says the CLI imports the constant "from the runtime".
It does, from a new runtime subpath rather than the root entry, because
the root costs about a second on every `os plugin` command (table
above). The order anticipated "export the constant from a new entry". A
home in `@objectstack/core` (which already holds the artifact tar reader
both sides share) would avoid the new subpath and the hono alias line;
it was not taken because it departs from the triage ruling.
- Claim file surface: `packages/adapters/hono/vitest.config.ts` was
added (one alias entry and a comment fix), forced by
`check:test-source-alias` once the subpath exists. The seat may amend
the claim's surface.
- `test/plugin-publish-manifest-entry.test.ts` still mocks a drifted
`MANIFEST_FILENAME` to prove publish's manifest read does not depend on
it. That drift can no longer happen in the real tree; the test stays
because it still pins publish's single decode. Not touched.
- `MANIFEST_FILENAME` also names the SOURCE manifest `os plugin build`
reads from the project directory (`build.ts`). That was already the same
string, so nothing changes; noted because the alias now ties the source
name to the runtime constant too.
- Commit trailers follow the repo's model-free pair
(`check:commit-card-trailers` refused the first push; the tip was
reworded before it was published).
## Verification
Final head `ce89ca90`. Local, per `.claude/agents/os-dev.md`:
- `pnpm --filter '@objectstack/cli^...' build`, then `pnpm --filter
@objectstack/runtime build` (new entry emitted:
`dist/compiled-plugin-manifest-file.{js,cjs,d.ts,d.cts}`;
`check-dts-emitted: 4/4`), `pnpm --filter @objectstack/cli build`.
- `pnpm --filter @objectstack/cli typecheck` and `pnpm --filter
@objectstack/runtime typecheck`: exit 0 (test layers held in their debt
files).
- `pnpm --filter @objectstack/cli exec vitest run --project unit
--maxWorkers=2`: 361 files, 5152 tests passed. The integration tier is
declared to CI (no integration file or spawn entry touched).
- `pnpm --filter @objectstack/runtime test`: 498 files passed, 8084
tests passed, 19 skipped.
- `pnpm --filter @objectstack/hono test`: 14 files, 231 tests passed.
- New subpath loads under both conditions from `packages/cli`:
`require(...)` and `import(...)` each answer `objectstack.plugin.json`.
- Derived gates (`node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack`, 76 commands on head `ce89ca90`): 74 exit 0,
including `check:test-source-alias`, `check:published-files`,
`check:dts-closure`, `check:type-check-debt`,
`check:undeclared-dep-imports`, `check:lean-entry-closure`,
`check:adr-0087-registration`. `check-plugin-teardown-shape --self-test`
needed its anchor commit fetched on this shallow clone, then exit 0.
- The other two read every package's build output and first answered
exit 3 (`PREREQUISITE NOT MET` / `COULD NOT MEASURE`, nothing measured).
After `turbo run build` over `./packages/**` and `./examples/**` (78/78
tasks), both exit 0: `check:dual-build-cjs-loads` (114 require entry
points across 70 packages load, the new subpath among them) and
`check:i18n-coverage` (14 configs, none new). So all 76 derived gates
exit 0 on `ce89ca90`.
- Hand gates: `check:commit-card-trailers` 0, `check:nul-bytes` 0,
`eslint --no-inline-config packages/cli packages/runtime
packages/adapters/hono` 0.
## Human Minimum
- [x] 1. Schemas start as Zod; `packages/spec` holds no runtime logic.
(`packages/spec` not touched.)
- [x] 2. Every name I added uses the casing for its kind.
- [x] 3. No formatter ran; `pnpm lint` passes. (Scoped to the touched
packages; the repo-wide run is CI's.)
- [x] 4. One issue, one branch off an up-to-date `main`, one pull
request.
- [x] 5. A change that publishes carries a changeset, and both
declaration lines are filled in here and in the changeset.
(`.changeset/28080-one-manifest-filename.md`: `@objectstack/cli` and
`@objectstack/runtime` `patch`.)
- [x] 6. `packages/spec` touched: n/a.
- [x] 7. No hand edits to `content/docs/references/`,
`packages/*/CHANGELOG.md` or `content/docs/releases/`.
- [x] 8. Title, body and comments are in English. (The maintainer brief
is in Chinese by the agent contract.)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01FEkQ5mhnqXsq7TSYsr6HPG
---
_Generated by [Claude
Code](https://claude.ai/code/session_01FEkQ5mhnqXsq7TSYsr6HPG)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 69dfac0 commit 50646f0
8 files changed
Lines changed: 98 additions & 6 deletions
File tree
- .changeset
- packages
- adapters/hono
- cli
- src/utils
- test
- runtime
- src
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
35 | 35 | | |
36 | 36 | | |
37 | 37 | | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
38 | 47 | | |
39 | 48 | | |
40 | | - | |
41 | | - | |
| 49 | + | |
42 | 50 | | |
43 | 51 | | |
44 | 52 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
39 | 39 | | |
40 | 40 | | |
41 | 41 | | |
| 42 | + | |
| 43 | + | |
42 | 44 | | |
43 | 45 | | |
44 | 46 | | |
| |||
70 | 72 | | |
71 | 73 | | |
72 | 74 | | |
73 | | - | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
74 | 82 | | |
75 | 83 | | |
76 | 84 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
17 | 17 | | |
18 | 18 | | |
19 | 19 | | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
20 | 30 | | |
21 | 31 | | |
22 | 32 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
18 | 18 | | |
19 | 19 | | |
20 | 20 | | |
| 21 | + | |
21 | 22 | | |
22 | | - | |
23 | | - | |
| 23 | + | |
| 24 | + | |
24 | 25 | | |
25 | 26 | | |
26 | 27 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
8 | | - | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
9 | 11 | | |
10 | 12 | | |
11 | 13 | | |
| |||
0 commit comments