diff --git a/AGENTS.md b/AGENTS.md
index 268944d..b4cf50e 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -12,6 +12,8 @@
- Choose validation from the affected component's `package.json`. For a
documentation-only change, check the diff and local links; report those
checks separately from build, runtime, or live-app verification.
+- Plugin development, package inspection, contribution, and GitHub prerelease
+ steps are maintained in [`plugin/DEVELOPMENT.md`](plugin/DEVELOPMENT.md).
## Shared quality configuration
diff --git a/README.md b/README.md
index 9a3f465..f974a51 100644
--- a/README.md
+++ b/README.md
@@ -29,10 +29,10 @@
OpenAI Imperium contains a CordisX reasoning-intensity presentation plugin and
a Reset petition site. Each component has its own runtime and maintenance entry:
-| Component | Usage and maintenance |
-| ------------------------------------- | ---------------------------------------------------------------------------------------------- |
-| CordisX plugin (`plugin/`) | [Plugin README](plugin/README.md): configuration, Host compatibility, and development commands |
-| Reset petition site (repository root) | [Site README](app/README.md): experience, local development, and persistent ledger |
+| Component | Usage and maintenance |
+| ------------------------------------- | ---------------------------------------------------------------------------------------- |
+| CordisX plugin (`plugin/`) | [Plugin README](plugin/README.md): installation, usage, configuration, and compatibility |
+| Reset petition site (repository root) | [Site README](app/README.md): experience, local development, and persistent ledger |

@@ -40,8 +40,8 @@ a Reset petition site. Each component has its own runtime and maintenance entry:
The plugin contributes an ascension presentation for reasoning intensity and an
optional session backdrop. CordisX Host owns native interaction and rendering.
-[`plugin/README.md`](plugin/README.md) is the source for plugin usage,
-configuration, and development instructions.
+[`plugin/README.md`](plugin/README.md) is the source for plugin installation,
+usage, configuration, and compatibility.
### Plugin configuration
@@ -54,8 +54,8 @@ history. Its [README](app/README.md) owns feature, runtime, and ledger details.
## Run locally
-Choose the [plugin development instructions](plugin/README.md#development) or
-[petition site instructions](app/README.md#run-locally) for the component you need.
+Choose the [plugin maintainer guide](plugin/DEVELOPMENT.md) or [petition site
+instructions](app/README.md#run-locally) for the component you need.
## License
diff --git a/README.zh-CN.md b/README.zh-CN.md
index d4137aa..9c71cd9 100644
--- a/README.zh-CN.md
+++ b/README.zh-CN.md
@@ -16,7 +16,7 @@
我来,我见,我 Reset。
- CordisX 插件
+ CordisX 插件
· 加入 Reset 请愿
· 源码
· 反馈
@@ -27,7 +27,7 @@ OpenAI Imperium 在同一仓库中提供 CordisX 思考强度视觉插件与 Res
| 组件 | 使用与维护说明 |
| -------------------------- | ------------------------------------------------------------------- |
-| CordisX 插件(`plugin/`) | [插件 README](plugin/README.md#中文):配置、Host 兼容条件与开发命令 |
+| CordisX 插件(`plugin/`) | [插件 README](plugin/README.zh-Hans.md):安装、使用、配置与兼容条件 |
| Reset 请愿站(仓库根目录) | [请愿站 README](app/README.zh-CN.md):体验介绍、本地运行与持久账本 |

@@ -35,12 +35,12 @@ OpenAI Imperium 在同一仓库中提供 CordisX 思考强度视觉插件与 Res
## CordisX 插件
插件提供思考强度的升阶外观及可选会话背景,原生交互和渲染由 CordisX Host
-负责。插件的使用、配置与开发说明统一维护在
-[`plugin/README.md`](plugin/README.md#中文)。
+负责。插件的安装、使用、配置与兼容说明统一维护在
+[`plugin/README.zh-Hans.md`](plugin/README.zh-Hans.md)。
### 插件配置
-请参阅[插件配置说明](plugin/README.md#configuration)。
+请参阅[插件配置说明](plugin/README.zh-Hans.md#配置)。
## Reset 请愿站
@@ -49,7 +49,7 @@ OpenAI Imperium 在同一仓库中提供 CordisX 思考强度视觉插件与 Res
## 本地运行
-根据要运行的组件选择[插件开发说明](plugin/README.md#development)或
+根据要运行的组件选择[插件维护指南](plugin/DEVELOPMENT.md)或
[请愿站本地运行说明](app/README.zh-CN.md#本地运行)。
## 许可证与声明
diff --git a/plugin/DEVELOPMENT.md b/plugin/DEVELOPMENT.md
new file mode 100644
index 0000000..d044b6d
--- /dev/null
+++ b/plugin/DEVELOPMENT.md
@@ -0,0 +1,51 @@
+# Codex Ascension Maintainer Guide
+
+Run all commands in this guide from `plugin/`. Node.js 22.19 or newer is
+required.
+
+## Develop and verify
+
+```sh
+npm ci
+npm run check
+npm run dev:dry-run
+npm run dev
+```
+
+`npm run check` type-checks the source, regenerates embedded image modules,
+builds the TypeScript library and portable browser bundle, runs the focused
+tests, and inspects the package archive. Also run `git diff --check` from the
+repository root before committing.
+
+The browser bundle keeps Cordis and `cordisx/contracts` as Host-provided
+facades. It bundles Schemastery and plugin-owned image data so the archive does
+not depend on a sibling `node_modules` directory.
+
+## Package
+
+`cordisx-package.json` is the install descriptor. Its version must match
+`package.json`; its runtime-manifest digest must match the exact bytes of
+`runtime-manifest.json`. The runtime manifest must remain identical to the
+plugin's exported manifest, including the empty capability list.
+
+Build and create the archive with:
+
+```sh
+npm run check
+npm pack
+```
+
+The archive must contain both READMEs, `cordisx-package.json`,
+`runtime-manifest.json`, and the entry named by the package descriptor.
+
+## Release
+
+Releases use a GitHub prerelease, not npm. Merge through a protected pull
+request, build the exact merged `main` commit, and create the private-package
+archive with `npm pack`. Publish the archive as
+`cordisx-codex-ascension-.tgz` together with `SHA256SUMS` under the
+matching `v` tag. Download both assets afterward and verify their
+hashes and archive contents.
+
+The Marketplace owner adds the artifact URL and SHA-256 digest separately.
+Do not copy an older trust, Official, or Certified record.
diff --git a/plugin/README.md b/plugin/README.md
index 8f4f772..63dd676 100644
--- a/plugin/README.md
+++ b/plugin/README.md
@@ -1,77 +1,88 @@
-# @cordisx/codex-ascension
+# Codex Ascension
-The CordisX plugin for the OpenAI Imperium reasoning-intensity presentation.
-It contributes five localized semantic stages—plastic, bronze, steel, silver,
-and gold—through `composer.reasoning-intensity`, plus an optional staged
-portrait and effects projection through `session.backdrop`.
+[简体中文](README.zh-Hans.md)
-The reasoning presentation declares an explicit `replace` claim named
-`imperium`. It requests only the Host-safe `reasoningIntensity` property,
-`setReasoningIntensity` command, and `reasoningIntensityChanged` event. CordisX
-Host owns authorization, exclusive selection, native fallback, lease state,
-native range discovery, DOM, styling, motion, accessibility, value mapping,
-and cleanup. This plugin contains no selectors, CSS, callbacks, setting
-mutations, native event code, or fabricated lease state.
+Codex Ascension gives CordisX's reasoning-intensity control five theatrical
+stages, from plastic through gold. It can also project a matching portrait and
+ambient effects into the active session background.
-The optional `session.backdrop` contribution remains a legacy structured
-`compose` contribution and does not claim controlled-point ownership.
+## Install
+
+Plugin ID: `codex-ascension`. Current release: `0.1.1`.
+
+```sh
+FEED_URL=https://raw.githubusercontent.com/cordisx/marketplace/main/marketplace.json
+npx cordisx@beta source add "$FEED_URL" --yes
+npx cordisx@beta plugin install codex-ascension --source "$FEED_URL" --version 0.1.1
+```
+
+Skip `source add` when that exact feed is already enabled. For another profile,
+add the same `--profile ` argument to both commands. `--source` selects
+an already configured and enabled source; it does not register one. `--yes`
+confirms the source change only and does not approve plugin permissions. A
+discovery source is not a trust root.
+
+The install command becomes available after the Marketplace v3 entry lists the
+verified `0.1.1` artifact. Until then, download the archive and `SHA256SUMS`
+from the
+[GitHub prerelease](https://github.com/cordisx/plugin-codex-ascension/releases/tag/v0.1.1).
+
+## Use
+
+Open a Codex session in CordisX and choose a reasoning-intensity value. The
+native control keeps its normal behavior while the selected value is presented
+as one of five Ascension stages:
+
+| Reasoning stage | Ascension presentation |
+| --------------- | ---------------------- |
+| Lowest | Promptly Bankrupt |
+| Low | Bronze Builder |
+| Medium | Tool-Forged Tribune |
+| High | Silver Context |
+| Highest | Codex Maximus |
+
+The session backdrop follows the same stage when its portrait or effects are
+enabled.
## Configuration
-CordisX renders the plugin's structured configuration form. Each option is
-enabled by default and can be changed independently:
+CordisX renders three settings, all enabled by default:
-| Option | Effect when disabled |
+| Setting | Effect when disabled |
| ------------------------ | -------------------------------------------------------- |
| Replace reasoning slider | Leaves the native reasoning-intensity control unchanged. |
-| Show backdrop portrait | Does not mount portrait images in the session backdrop. |
-| Enable backdrop effects | Does not mount the glow or architectural effect layers. |
+| Show backdrop portrait | Hides the staged portrait. |
+| Enable backdrop effects | Hides the glow and architectural effects. |
-If both backdrop options are disabled, the plugin does not register a
-`session.backdrop` contribution. Saved changes apply with a plugin restart.
+Saved changes apply after the plugin restarts. If both backdrop settings are
+disabled, the plugin does not register a session backdrop.
-## Development
+## Permissions and limits
-Run the following commands from `plugin/`. Its
-[`package.json`](package.json) defines the Node.js requirement and checks;
-the repository-root package runs the separate petition site.
+Codex Ascension requests no CordisX capabilities. The Host owns authorization,
+the reasoning value, native control behavior, rendering, accessibility, and
+cleanup. The plugin changes presentation only; it does not change model
+reasoning policy or submit settings on the user's behalf.
-Requires a published CordisX prerelease containing
-[cordisx/cordisx#187](https://github.com/cordisx/cordisx/pull/187).
+The reasoning-control replacement requires a CordisX Host that supports the
+controlled `composer.reasoning-intensity` contribution. The session backdrop
+uses the legacy structured `session.backdrop` contribution.
-```bash
-npm install
-npm run check
-npm run dev:dry-run
-npm run dev
-```
+## Troubleshooting
+
+- **Version `0.1.1` is not found:** confirm the Marketplace entry lists the
+ release artifact. `--source` cannot add or repair a feed.
+- **The native slider is unchanged:** enable **Replace reasoning slider**, save,
+ and restart the plugin.
+- **The backdrop is missing:** enable at least one backdrop setting and restart
+ the plugin.
+
+## License
-## Brand icon and source distribution
-
-The plugin owns its approved 256×256 brand PNG at
-[`src/assets/identity/ascension.png`](src/assets/identity/ascension.png). The build
-embeds these exact bytes in the public module `icon` export as
-`{ mediaType: 'image/png', data }`, so Host plugin lists can consume the icon
-without fetching a site asset. The petition site icons remain independent.
-
-This private package is distributed from repository source; merging the PNG and
-its generated module to `main` updates that source distribution. No npm release
-or version tag is required for the icon change. `npm run check` verifies the
-built export against the selected PNG hash and dimensions.
-
-## 中文
-
-这是 OpenAI Imperium 的 CordisX 思考强度主题插件。插件声明塑料白、青铜、
-钢、银、金五个语义档位,并可选提供会话背景人像与特效。思考强度外观通过
-名为 `imperium` 的显式 `replace` claim 接入,只请求 Host 安全投影的
-`reasoningIntensity` 属性、`setReasoningIntensity` 命令和
-`reasoningIntensityChanged` 事件;授权、排他选择、原生回退、lease 状态、
-原生滑块定位、DOM、样式、动画、可访问性、数值映射和卸载清理由 CordisX Host
-统一负责。插件不包含 selector、CSS、callback、原生事件代码或伪造的 lease
-状态。`session.backdrop` 仍是 legacy structured `compose` contribution,不声明
-受控点所有权。
-
-CordisX 会从插件的结构化 Schema 渲染三个默认开启、可独立组合的配置项:
-「替换思考强度 Slider」「显示背景人像」「启用背景特效」。关闭某项后 Host
-不会挂载对应视觉层;两项背景配置都关闭时,插件不会注册 `session.backdrop`。
-保存配置后通过插件重启生效。
+The source code is available under the repository's
+[MIT License](https://github.com/cordisx/plugin-codex-ascension/blob/main/LICENSE).
+Portrait and brand-asset terms are described in the repository's
+[asset notice](https://github.com/cordisx/plugin-codex-ascension/blob/main/ASSETS-LICENSE.md).
+Maintainer setup, checks, packaging, and release instructions are in the source
+repository's
+[maintainer guide](https://github.com/cordisx/plugin-codex-ascension/blob/main/plugin/DEVELOPMENT.md).
diff --git a/plugin/README.zh-Hans.md b/plugin/README.zh-Hans.md
new file mode 100644
index 0000000..0b3b7ae
--- /dev/null
+++ b/plugin/README.zh-Hans.md
@@ -0,0 +1,77 @@
+# Codex Ascension
+
+[English](README.md)
+
+Codex Ascension 为 CordisX 的思考强度控件提供五阶戏剧化外观,从塑料白一路
+升至黄金。插件还可以在当前会话背景中显示与档位对应的人像和环境特效。
+
+## 安装
+
+插件 ID:`codex-ascension`。当前版本:`0.1.1`。
+
+```sh
+FEED_URL=https://raw.githubusercontent.com/cordisx/marketplace/main/marketplace.json
+npx cordisx@beta source add "$FEED_URL" --yes
+npx cordisx@beta plugin install codex-ascension --source "$FEED_URL" --version 0.1.1
+```
+
+若该 feed 已启用,可以跳过 `source add`。使用其他 profile 时,两条命令都要添加
+相同的 `--profile `。`--source` 只能选择已配置并启用的来源,不会注册
+来源;`--yes` 只确认来源变更,不会批准插件权限。发现来源也不等同于 trust root。
+
+Marketplace v3 条目列出验证后的 `0.1.1` artifact 后,安装命令才可用。在此之前,
+可从
+[GitHub 预发布](https://github.com/cordisx/plugin-codex-ascension/releases/tag/v0.1.1)
+下载压缩包与 `SHA256SUMS`。
+
+## 使用
+
+在 CordisX 中打开 Codex 会话并选择思考强度。原生控件行为保持不变,所选档位会
+显示为五种 Ascension 外观之一:
+
+| 思考档位 | Ascension 外观 |
+| -------- | -------------- |
+| 最低 | 提示词破产 |
+| 低 | 青铜构筑者 |
+| 中 | 工具锻造官 |
+| 高 | 白银上下文 |
+| 最高 | Codex Maximus |
+
+启用背景人像或特效后,会话背景会跟随相同档位变化。
+
+## 配置
+
+CordisX 会渲染三个默认开启的设置:
+
+| 设置 | 关闭后的效果 |
+| ------------------- | ---------------------------- |
+| 替换思考强度 Slider | 保留原生思考强度控件的外观。 |
+| 显示背景人像 | 隐藏当前档位的人像。 |
+| 启用背景特效 | 隐藏光晕和建筑纹样特效。 |
+
+保存后需重启插件才能生效。两个背景设置都关闭时,插件不会注册会话背景。
+
+## 权限与限制
+
+Codex Ascension 不请求任何 CordisX capability。授权、思考强度值、原生控件行为、
+渲染、可访问性和清理由 Host 负责。插件只改变外观,不会更改模型的思考策略,也不会
+代替用户提交设置。
+
+思考强度替换需要 Host 支持受控的 `composer.reasoning-intensity` contribution;
+会话背景使用 legacy structured `session.backdrop` contribution。
+
+## 排错
+
+- **找不到 `0.1.1`:**确认 Marketplace 条目已列出该版本的 release artifact;
+ `--source` 不会添加或修复 feed。
+- **原生 Slider 外观未变化:**启用「替换思考强度 Slider」,保存并重启插件。
+- **没有会话背景:**至少启用一个背景设置,然后重启插件。
+
+## 许可证
+
+源代码采用仓库的
+[MIT License](https://github.com/cordisx/plugin-codex-ascension/blob/main/LICENSE)。
+肖像与品牌素材条款见仓库的
+[素材声明](https://github.com/cordisx/plugin-codex-ascension/blob/main/ASSETS-LICENSE.md)。
+维护者的环境、检查、打包与发布说明见源码仓库的
+[维护指南](https://github.com/cordisx/plugin-codex-ascension/blob/main/plugin/DEVELOPMENT.md)。
diff --git a/plugin/cordisx-package.json b/plugin/cordisx-package.json
new file mode 100644
index 0000000..e9c1fab
--- /dev/null
+++ b/plugin/cordisx-package.json
@@ -0,0 +1,25 @@
+{
+ "$schema": "https://raw.githubusercontent.com/cordisx/cordisx-protocol/main/schemas/plugin-package.v3.schema.json",
+ "schemaVersion": 3,
+ "id": "codex-ascension",
+ "version": "0.1.1",
+ "entry": "./dist/runtime/module.js",
+ "readme": "./README.md",
+ "canonicalSource": "https://github.com/cordisx/plugin-codex-ascension",
+ "distribution": {
+ "mode": "explicit-local-v1",
+ "signature": "unsupported"
+ },
+ "compatibility": {
+ "runtimeAbi": 1,
+ "protocolSchemas": [
+ "https://raw.githubusercontent.com/cordisx/cordisx-protocol/main/schemas/plugin-manifest.v1.schema.json"
+ ]
+ },
+ "dependencies": [],
+ "runtimeManifest": {
+ "path": "./runtime-manifest.json",
+ "schema": "https://raw.githubusercontent.com/cordisx/cordisx-protocol/main/schemas/plugin-manifest.v1.schema.json",
+ "digest": "sha256:6de4f425b84029aa6e04c27d76232ee92a5a1781460141dca4eb7f5a98e7f226"
+ }
+}
diff --git a/plugin/package-lock.json b/plugin/package-lock.json
index 7df5e4d..c04c584 100644
--- a/plugin/package-lock.json
+++ b/plugin/package-lock.json
@@ -1,17 +1,18 @@
{
"name": "@cordisx/codex-ascension",
- "version": "0.1.0",
+ "version": "0.1.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@cordisx/codex-ascension",
- "version": "0.1.0",
+ "version": "0.1.1",
"license": "MIT",
"devDependencies": {
"@deepseek-ai/cordis": "4.0.1",
"@deepseek-ai/schemastery": "^3.18.1",
"cordisx": "0.1.0-beta.1",
+ "esbuild": "0.28.2",
"typescript": "^5.9.2"
},
"engines": {
diff --git a/plugin/package.json b/plugin/package.json
index 88ca8e0..47d56ab 100644
--- a/plugin/package.json
+++ b/plugin/package.json
@@ -1,24 +1,33 @@
{
"name": "@cordisx/codex-ascension",
- "version": "0.1.0",
+ "version": "0.1.1",
"private": true,
"license": "MIT",
"description": "OpenAI Imperium reasoning-intensity presentation for CordisX",
"type": "module",
- "main": "./dist/codex-ascension.js",
+ "main": "./dist/runtime/module.js",
"types": "./dist/codex-ascension.d.ts",
+ "files": [
+ "dist",
+ "README.md",
+ "README.zh-Hans.md",
+ "cordisx-package.json",
+ "runtime-manifest.json"
+ ],
"scripts": {
- "build": "node scripts/generate-portrait-modules.mjs && tsc -p tsconfig.json",
- "check": "npm run typecheck && npm run build && npm test",
+ "build": "node scripts/clean-dist.mjs && node scripts/generate-portrait-modules.mjs && tsc -p tsconfig.json && node scripts/build-runtime-bundle.mjs",
+ "check": "npm run typecheck && npm run build && npm test && npm run pack:check",
"dev": "cordisx dev ./src/codex-ascension.ts",
"dev:dry-run": "cordisx dev ./src/codex-ascension.ts --dry-run",
- "test": "node --test test/manifest.mjs",
+ "pack:check": "node scripts/check-package.mjs",
+ "test": "node --test test/*.mjs",
"typecheck": "node scripts/generate-portrait-modules.mjs && tsc -p tsconfig.json --noEmit"
},
"devDependencies": {
"@deepseek-ai/cordis": "4.0.1",
"@deepseek-ai/schemastery": "^3.18.1",
"cordisx": "0.1.0-beta.1",
+ "esbuild": "0.28.2",
"typescript": "^5.9.2"
},
"engines": {
diff --git a/plugin/runtime-manifest.json b/plugin/runtime-manifest.json
new file mode 100644
index 0000000..d757231
--- /dev/null
+++ b/plugin/runtime-manifest.json
@@ -0,0 +1,7 @@
+{
+ "$schema": "https://raw.githubusercontent.com/cordisx/cordisx-protocol/main/schemas/plugin-manifest.v1.schema.json",
+ "schemaVersion": 1,
+ "id": "codex-ascension",
+ "name": "Codex Ascension",
+ "capabilities": []
+}
diff --git a/plugin/scripts/build-runtime-bundle.mjs b/plugin/scripts/build-runtime-bundle.mjs
new file mode 100644
index 0000000..be17cec
--- /dev/null
+++ b/plugin/scripts/build-runtime-bundle.mjs
@@ -0,0 +1,13 @@
+import { build } from 'esbuild';
+
+await build({
+ bundle: true,
+ entryPoints: ['src/codex-ascension.ts'],
+ external: ['@deepseek-ai/cordis', 'cordisx/contracts'],
+ format: 'esm',
+ metafile: true,
+ outfile: 'dist/runtime/module.js',
+ platform: 'browser',
+ sourcemap: false,
+ target: ['chrome120'],
+});
diff --git a/plugin/scripts/check-package.mjs b/plugin/scripts/check-package.mjs
new file mode 100644
index 0000000..154d673
--- /dev/null
+++ b/plugin/scripts/check-package.mjs
@@ -0,0 +1,63 @@
+import assert from 'node:assert/strict';
+import { spawnSync } from 'node:child_process';
+import { createHash } from 'node:crypto';
+import { mkdtemp, readFile, rm } from 'node:fs/promises';
+import { tmpdir } from 'node:os';
+import { join } from 'node:path';
+
+const hostContracts = import.meta.resolve('cordisx/contracts');
+const { runtimeManifestV1 } = await import(new URL('./launcher/plugin-package.js', hostContracts));
+const { JsonPackageManifestV2Resolver } = await import(new URL('./launcher/packages/manifest.js', hostContracts));
+
+const packageManifest = JSON.parse(await readFile('cordisx-package.json', 'utf8'));
+const runtimeBytes = await readFile('runtime-manifest.json');
+const runtimeManifest = JSON.parse(runtimeBytes);
+const packageJson = JSON.parse(await readFile('package.json', 'utf8'));
+const builtPlugin = await import(new URL('../dist/codex-ascension.js', import.meta.url));
+
+assert.equal(packageManifest.id, runtimeManifest.id);
+assert.equal(packageManifest.version, packageJson.version);
+assert.equal(packageManifest.entry, packageJson.main);
+assert.equal(packageManifest.runtimeManifest.schema, runtimeManifest.$schema);
+assert.equal(
+ packageManifest.runtimeManifest.digest,
+ `sha256:${createHash('sha256').update(runtimeBytes).digest('hex')}`,
+);
+assert.deepEqual(runtimeManifest.capabilities, []);
+assert.deepEqual(builtPlugin.manifest, runtimeManifest);
+
+const runtimeSource = await readFile(packageManifest.entry, 'utf8');
+assert.doesNotMatch(runtimeSource, /from\s+['"]@deepseek-ai\/schemastery['"]/u);
+assert.match(runtimeSource, /from\s+['"]cordisx\/contracts['"]/u);
+
+const resolver = new JsonPackageManifestV2Resolver({
+ runtimeValidators: {
+ [runtimeManifest.$schema]: value => runtimeManifestV1(value, runtimeManifest.id),
+ },
+});
+const resolved = await resolver.resolve(process.cwd());
+assert.equal(resolved.packageManifest.pluginId, packageManifest.id);
+assert.equal(resolved.packageManifest.version, packageManifest.version);
+assert.deepEqual(resolved.runtimeManifest, runtimeManifest);
+
+const temporary = await mkdtemp(join(tmpdir(), 'codex-ascension-pack-'));
+try {
+ const packed = spawnSync('npm', ['pack', '--json', '--pack-destination', temporary], {
+ encoding: 'utf8',
+ stdio: ['ignore', 'pipe', 'inherit'],
+ });
+ assert.equal(packed.status, 0, packed.stdout);
+ const [metadata] = JSON.parse(packed.stdout);
+ const files = new Set(metadata.files.map(file => file.path));
+ for (
+ const required of [
+ 'README.md',
+ 'README.zh-Hans.md',
+ 'cordisx-package.json',
+ 'runtime-manifest.json',
+ packageManifest.entry.slice(2),
+ ]
+ ) assert.ok(files.has(required), `package is missing ${required}`);
+} finally {
+ await rm(temporary, { force: true, recursive: true });
+}
diff --git a/plugin/scripts/clean-dist.mjs b/plugin/scripts/clean-dist.mjs
new file mode 100644
index 0000000..e47a24d
--- /dev/null
+++ b/plugin/scripts/clean-dist.mjs
@@ -0,0 +1,3 @@
+import { rm } from 'node:fs/promises';
+
+await rm('dist', { force: true, recursive: true });