Merge pull request #46 from sinanyuntu/09-12-normalize-onetalk-contract-package

将 OneTalk 合约包迁移至 packages 目录
This commit is contained in:
YBF
2026-09-12 14:15:54 +08:00
committed by GitHub
41 changed files with 282 additions and 52 deletions
+2 -1
View File
@@ -2,6 +2,7 @@ node_modules/
.pnpm-store/
dist/
apps/*/dist/
packages/*/dist/
.vite/
*.tsbuildinfo
.env
@@ -13,4 +14,4 @@ apps/chrome-extension/.keys/
mock-log.text
.claude/skills/gitnexus
.claude/skills/gitnexus
+1 -1
View File
@@ -164,7 +164,7 @@ packages:
mind-test-harness:
path: apps/mind-test-harness
onetalk-contract:
path: apps/onetalk-contract
path: packages/onetalk-contract
server:
path: apps/server
default_package: @trade-message-center/chrome-extension
@@ -288,7 +288,7 @@ decodeOneTalkMessageContent(source: OneTalkMessageContentSource) ->
| { status: "anomaly", code: OneTalkMediaAnomalyCode, mediaKind: "image" | "file" | "card" };
```
`apps/onetalk-contract/src/content.ts` 是这六个 kind、exact-shape guard 和跨层读取模型的唯一 owner。`message-observer/content-decoder.ts` 是历史 SDK tuple 分类、受控 Base64 摘要解码和白名单投影的唯一生产点;它对名片只生产 marker,不生产客户资料 view。`read-projection.ts` 是服务端读取时将 marker 与同一账号/会话的当前 profile 组合为 `OneTalkBusinessCardViewContent` 的唯一 owner。
`packages/onetalk-contract/src/content.ts` 是这六个 kind、exact-shape guard 和跨层读取模型的唯一 owner。`message-observer/content-decoder.ts` 是历史 SDK tuple 分类、受控 Base64 摘要解码和白名单投影的唯一生产点;它对名片只生产 marker,不生产客户资料 view。`read-projection.ts` 是服务端读取时将 marker 与同一账号/会话的当前 profile 组合为 `OneTalkBusinessCardViewContent` 的唯一 owner。
### 7.3 Contracts
+2 -2
View File
@@ -84,13 +84,13 @@ const retryLimit = options.retryLimit ?? DEFAULT_RETRY_LIMIT;
### 1. Scope / Trigger
- Trigger:根 package 版本跨 workspace package metadata、扩展构建/watch 和 release CI 传播,且这些边界不得各自补偿或推导版本。
- Scope:根 `package.json:version` 是唯一可编辑事实源;`apps/*/package.json` 的具体版本是同步镜像;扩展最终只加载生成的 `dist/manifest.json`
- Scope:根 `package.json:version` 是唯一可编辑事实源;`apps/*/package.json``packages/*/package.json` 的具体版本是同步镜像;扩展最终只加载生成的 `dist/manifest.json`
### 2. Signatures
- `validatePackageVersion(value: unknown, source?: string): string`:验证同时满足 package metadata 和 Chrome Manifest 的三段数字版本。
- `readRootPackageVersion(rootDir?: string): string`:只读取并验证 workspace 根 `package.json`
- `pnpm version:sync`:把根版本写入所有 `apps/*/package.json` 镜像。
- `pnpm version:sync`:把根版本写入所有 `apps/*/package.json``packages/*/package.json` 镜像。
- `pnpm version:check`:只检查镜像,不自动修复。
- `pnpm version:ensure`:先执行 `version:sync`,再执行 `version:check`;根级 dev/build/typecheck/test/format:check 通过它获得稳定的一致版本环境。
- `TMC_PACKAGE_VERSION`:由 workspace 根命令注入给下游扩展命令;扩展直接执行时缺失必须失败。
+1 -1
View File
@@ -86,7 +86,7 @@ export const isObjectRecord = (value: unknown): value is Record<string, unknown>
### 3. Contracts
- `apps/onetalk-contract/src/guards.ts` owns strict `isPlainRecord` and the
- `packages/onetalk-contract/src/guards.ts` owns strict `isPlainRecord` and the
contract root facade is the only cross-package import path. It accepts
current-realm plain objects and null-prototype objects, and rejects arrays,
primitives, class/custom-prototype values, and cross-realm ordinary objects.
@@ -8,11 +8,11 @@ scope_lanes:
path: /Users/ybf/work/trade-message-center
role: task-branch
owns:
- apps/onetalk-contract/src/content.ts
- apps/onetalk-contract/src/guards.ts
- apps/onetalk-contract/src/contact-profiles.ts
- apps/onetalk-contract/src/index.ts
- apps/onetalk-contract/test/contract.test.ts
- packages/onetalk-contract/src/content.ts
- packages/onetalk-contract/src/guards.ts
- packages/onetalk-contract/src/contact-profiles.ts
- packages/onetalk-contract/src/index.ts
- packages/onetalk-contract/test/contract.test.ts
- apps/chrome-extension/src/onetalk/main-page/message-observer/content-decoder.ts
- apps/chrome-extension/src/onetalk/main-page/message-observer/history.ts
- apps/chrome-extension/src/onetalk/page-bridge/model.ts
@@ -0,0 +1,3 @@
{"file":".trellis/spec/project/missing-values.md","reason":"Review the root version synchronization and build-environment invariants after multi-root workspace discovery changes."}
{"file":".trellis/spec/project/module-ownership.md","reason":"Review that the contract's canonical public package import and unique ownership remain unchanged by the physical move."}
{"file":".trellis/spec/mind-test-harness/development/boundary.md","reason":"Review that the test harness remains a one-way consumer and is not accidentally included in production build scope."}
@@ -0,0 +1,50 @@
# OneTalk Contract Package Migration Design
## Boundary
`@trade-message-center/onetalk-contract` remains the same private workspace package. Its
package name, `exports`, TypeScript source, test suite, and every consumer's `workspace:*`
dependency stay unchanged. The migration changes only its physical root from
`apps/onetalk-contract` to `packages/onetalk-contract` and updates repository metadata that
names the physical root.
## Workspace Layout
The root workspace declarations will explicitly include both application and shared-library
directories:
```yaml
packages:
- apps/*
- packages/*
```
The root `package.json#workspaces` mirrors those two globs. pnpm will then rewrite the
lockfile importer from `apps/onetalk-contract` to `packages/onetalk-contract`, and the
relative workspace links from app consumers will resolve as `../../packages/onetalk-contract`.
No consumer manifest needs a dependency-name change.
## Build and Release Metadata
All root commands retain their package-name filters. Only physical path references change:
- Docker copies the package manifest and source from `packages/onetalk-contract`.
- Generated-dist cleanup deletes `packages/onetalk-contract/dist`.
- `.gitignore` covers dist for both `apps/*` and `packages/*`.
- `listWorkspacePackagePaths` enumerates a named, deterministic list of both workspace root
directories. This preserves root-version mirroring for every package and is covered by
fixtures containing one app and one shared package.
## Documentation and Task Coordination
Current specs, the package registry, and non-archived technical docs will point at the new
path. Archived task records remain historical evidence and retain their original locations.
The live structured-message task's worktree registry will receive only the directory mapping;
its source and acceptance plan are not changed.
## Compatibility and Rollback
The package name and public API are stable, so imports and runtime resolution remain
compatible. The only operational compatibility condition is using the updated lockfile together
with the new workspace glob. Reverting is a single Git commit revert that restores the previous
directory and paths; no data migration or deployed protocol rollback is needed.
@@ -0,0 +1,3 @@
{"file":".trellis/spec/project/missing-values.md","reason":"Defines root version mirroring and workspace quality-command invariants affected by adding packages/* discovery."}
{"file":".trellis/spec/project/module-ownership.md","reason":"Defines the OneTalk contract as the canonical cross-package facade and constrains its stable public import path."}
{"file":".trellis/spec/mind-test-harness/development/boundary.md","reason":"Records harness dependency direction and contract consumption that must remain unchanged after relocation."}
@@ -0,0 +1,27 @@
# Implementation Plan
1. Establish the path-impact baseline: run GitNexus impact analysis for
`listWorkspacePackagePaths`, then confirm the package and generated-dist path references
found during planning.
2. Move the complete contract package unchanged from `apps/onetalk-contract/` to
`packages/onetalk-contract/` with Git-aware renames.
3. Update root workspace globs, Docker build copies, generated-dist cleanup, ignore patterns,
Trellis package registry, active-task coordination registry, and current documentation/spec
links. Leave archive paths unchanged.
4. Generalize workspace package discovery to both top-level workspace roots and update the
package-version/release fixtures to assert version mirroring and release file selection for
a shared package.
5. Regenerate the pnpm lockfile through pnpm so importer and link paths are canonical; verify
the frozen lockfile install path without changing dependency versions.
6. Run targeted script tests, contract build/test, root typecheck/test/build, formatting, and
a Dockerfile path/static check. Review the diff for source-content changes under the moved
package, stale non-archive paths, lockfile-only dependency churn, and unexpected execution
flow changes.
## Risk Gates
- Do not alter files below `packages/onetalk-contract/src/` or `test/` other than their Git
rename. A source-content diff is a stop-and-investigate condition.
- Do not update archive task/doc paths: they describe prior checkout state.
- If the live structured-message checkout begins editing the old package during this migration,
pause before destructive conflict resolution; preserve its work and report the required rebase.
@@ -0,0 +1,63 @@
# 规范化 OneTalk 合约包位置
## Goal
将共享 `@trade-message-center/onetalk-contract` 从应用目录迁移到共享库目录,使
monorepo 的目录语义、pnpm workspace 发现、构建和镜像打包路径一致,同时保持包名与
消费者行为不变。
## Confirmed Facts
-`package.json``pnpm-workspace.yaml` 当前仅发现 `apps/*`contract 因此被当作
app 纳入 workspace。
- contract 是 chrome extension、server 和 Mind test harness 的共同依赖,包名均为
`@trade-message-center/onetalk-contract`,依赖声明均为 `workspace:*`
- 根开发、构建、类型检查和测试脚本都按 package name 过滤 contract,因此迁移无需改变
filter 或消费者 import。
- `Dockerfile.server``scripts/clean-generated-dist.mjs`、lockfile importer、Trellis
package registry,以及当前非归档文档/规范中存在旧物理路径。
- `scripts/package-version.mjs` 当前只枚举 `apps/`,若 contract 移至 `packages/`
不调整,该共享包将脱离根版本镜像的校验。
- 另一个进行中的任务
`09-11-onetalk-structured-message-information-collection-classification` 在独立 checkout
中拥有 contract 源码与测试文件;其 task worktree registry 仍列出旧路径。
## Requirements
- R1:将 contract 的完整源码、测试、package manifest 与 TypeScript 配置迁移到
`packages/onetalk-contract/`;包名、exports、版本和 public API 不变。
- R2pnpm workspace 发现范围须同时包含 `apps/*``packages/*`;根 `workspaces` 声明
`pnpm-workspace.yaml` 保持一致。
- R3:所有生产构建、开发启动、清理和 Docker copy 路径必须指向新目录,且 contract 仍
在其消费者启动/构建前完成构建。
- R4:根版本同步/检查必须枚举 apps 和 packages 下全部 workspace package,且测试覆盖
该跨目录发现行为。
- R5:更新反映当前结构的 Trellis package registry、项目/包级规范与非归档技术文档;
不重写 archive 中的历史路径证据。
- R6:更新 pnpm lockfile importer 和 workspace links,使 frozen install 与依赖解析从
新位置工作。
- R7:立即执行迁移;仅做目录与路径/配置修正,不改变 contract 源码内容、协议、导出或
消费者业务逻辑。同步当前结构化消息任务的 worktree registry 路径,避免其后续工作误占
已失效目录。
## Acceptance Criteria
- [ ] AC1`packages/onetalk-contract/package.json` 存在,`apps/onetalk-contract/` 不再
存在,且 Git 识别为源码迁移而非内容重写。
- [ ] AC2`pnpm --filter @trade-message-center/onetalk-contract build`、contract test、
根 typecheck/test/build 在相应范围内成功,并证明 server、extension、harness 仍解析
相同的 workspace package。
- [ ] AC3`pnpm install --frozen-lockfile` 不因 importer 或 link 路径失效;lockfile 的
importer 和消费者 workspace link 均指向 `packages/onetalk-contract`
- [ ] AC4:版本镜像检查覆盖并通过 `apps/*``packages/*`,并有测试防止将来遗漏共享
package。
- [ ] AC5Docker build context 中 contract manifest 与源码 copy 均使用新路径;开发
启动的 dist 清理列表也使用新路径。
- [ ] AC6:当前规范/文档和 Trellis package registry 只指向新目录;归档资料保留原始
历史路径。
## Out of Scope
- 不改变 OneTalk 协议、类型、导出、消费者 import、运行时行为或 package name。
- 不合并、迁移或改写当前进行中任务在另一 checkout 的未合入源码变更。
- 不修改 archive 中作为历史证据记录的路径。
@@ -0,0 +1,26 @@
{
"id": "normalize-onetalk-contract-package",
"name": "normalize-onetalk-contract-package",
"title": "规范化 OneTalk 合约包位置",
"description": "将共享 onetalk-contract 从 apps 迁移到 packages,并更新 workspace 与构建路径引用",
"status": "completed",
"dev_type": null,
"scope": null,
"package": null,
"priority": "P2",
"creator": "ybf",
"assignee": "ybf",
"createdAt": "2026-09-12",
"completedAt": "2026-09-12",
"branch": "09-12-normalize-onetalk-contract-package",
"base_branch": "main",
"worktree_path": null,
"commit": null,
"pr_url": null,
"subtasks": [],
"children": [],
"parent": null,
"relatedFiles": [],
"notes": "",
"meta": {}
}
+3 -2
View File
@@ -8,7 +8,7 @@
<!-- @@@auto:current-status -->
- **Active File**: `journal-1.md`
- **Total Sessions**: 61
- **Total Sessions**: 62
- **Last Active**: 2026-09-12
<!-- @@@/auto:current-status -->
@@ -19,7 +19,7 @@
<!-- @@@auto:active-documents -->
| File | Lines | Status |
|------|-------|--------|
| `journal-1.md` | ~1321 | Active |
| `journal-1.md` | ~1343 | Active |
<!-- @@@/auto:active-documents -->
---
@@ -29,6 +29,7 @@
<!-- @@@auto:session-history -->
| # | Date | Title | Commits | Branch |
|---|------|-------|---------|--------|
| 62 | 2026-09-12 | 规范化 OneTalk 合约包位置 | `4d46b5b` | `09-12-normalize-onetalk-contract-package` |
| 61 | 2026-09-12 | 收敛 OneTalk WebSocket 路由分发 | `bd9cc6a` | `09-11-websocket-routing-single-source-of-truth` |
| 60 | 2026-09-11 | 隔离发送观测 pending | `1a899a9` | `send-observation-pending` |
| 59 | 2026-09-11 | 移除 pending-send 终态历史 | `63d9e5b` | `fix/remove-terminal-send-history` |
+22
View File
@@ -1319,3 +1319,25 @@ Moved Mind-only and Plugin-only WebSocket implementations to canonical endpoint
### Status
[OK] **Completed**
## Session 62: 规范化 OneTalk 合约包位置
<!-- trellis-session: v=2 fp=bd1df2949d2c5cd9 -->
**Date**: 2026-09-12
**Task**: 规范化 OneTalk 合约包位置
**Branch**: `09-12-normalize-onetalk-contract-package`
### Summary
将共享 onetalk-contract 从 apps 迁至 packages;同步 workspace、构建、锁文件、版本镜像、文档和任务路径,并完成独立验证。
### Git Commits
| Hash | Message |
|------|---------|
| `4d46b5b` | refactor(onetalk-contract): move shared contract to packages |
### Status
[OK] **Completed**
+2 -2
View File
@@ -8,13 +8,13 @@ RUN corepack enable && corepack prepare pnpm@11.7.0 --activate
ENV HUSKY=0
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml tsconfig.base.json ./
COPY apps/onetalk-contract/package.json apps/onetalk-contract/package.json
COPY packages/onetalk-contract/package.json packages/onetalk-contract/package.json
COPY apps/server/package.json apps/server/package.json
COPY apps/chrome-extension/package.json apps/chrome-extension/package.json
RUN pnpm install --frozen-lockfile --registry=https://registry.npmjs.org
COPY apps/onetalk-contract apps/onetalk-contract
COPY packages/onetalk-contract packages/onetalk-contract
COPY apps/server apps/server
RUN pnpm --filter @trade-message-center/server build && \
@@ -436,7 +436,7 @@ Base64
→ normalized image content
```
输出合同定义于 [`content.ts`](../apps/onetalk-contract/src/content.ts)
输出合同定义于 [`content.ts`](../packages/onetalk-contract/src/content.ts)
```ts
type OneTalkImageContent = {
@@ -688,7 +688,7 @@ raw `originalData` 只应在 MAIN world 短暂存在。send correlator 应消费
- live frame 分发:[`index.ts`](../apps/chrome-extension/src/onetalk/main-page/message-observer/index.ts)
- live message 解析:[`new.ts`](../apps/chrome-extension/src/onetalk/main-page/message-observer/new.ts)
- MAIN 内容归一化:[`content-decoder.ts`](../apps/chrome-extension/src/onetalk/main-page/message-observer/content-decoder.ts)
- 归一化媒体合同:[`content.ts`](../apps/onetalk-contract/src/content.ts)
- 归一化媒体合同:[`content.ts`](../packages/onetalk-contract/src/content.ts)
- observer/correlator 接线:[`page-script-entry.ts`](../apps/chrome-extension/src/onetalk/main-page/page-script-entry.ts)
- 当前文本发送确认:[`send-observation.ts`](../apps/chrome-extension/src/onetalk/main-page/message-observer/send-observation.ts)
- 当前页面命令入口:[`page-command.ts`](../apps/chrome-extension/src/onetalk/main-page/current-conversation-history/page-command.ts)
@@ -416,7 +416,7 @@ nodeName
### 10.1 共享内容解码器
`apps/onetalk-contract` 或其最近共同父目录增加一个唯一的内容投影器,输入原始 `content`,输出判别联合:
`packages/onetalk-contract` 或其最近共同父目录增加一个唯一的内容投影器,输入原始 `content`,输出判别联合:
```text
text
+2 -2
View File
@@ -902,8 +902,8 @@ aliIdEncrypt
| 历史只读 SDK | `apps/chrome-extension/src/onetalk/main-page/current-conversation-history/sdk.ts` | 调用 `fetchMessagesWithoutUpdateToRead` |
| 页面到 SW | `apps/chrome-extension/src/onetalk/service-worker/sync-engine/helpers.ts` | 原样复制观察字段 |
| IndexedDB 校验 | `apps/chrome-extension/src/onetalk/service-worker/storage.ts` | 只检查 JSON 与基础字段类型 |
| 共享合同 | `apps/onetalk-contract/src/model.ts` | `content` 为任意 JSON value |
| 共享 decoder | `apps/onetalk-contract/src/decoder.ts` | 不理解 text/image/file 语义 |
| 共享合同 | `packages/onetalk-contract/src/model.ts` | `content` 为任意 JSON value |
| 共享 decoder | `packages/onetalk-contract/src/decoder.ts` | 不理解 text/image/file 语义 |
| Bright 清洗 | `apps/server/src/onetalk/service.ts` | 按键过滤对象,字符串原样通过 |
| Bright 持久化 | `apps/server/src/database/schema/onetalk.ts` | `content jsonb``text nullable` |
| 开发展示 | `apps/mind-test-harness/src/harness.ts` | 只展示 raw JSON |
+2 -1
View File
@@ -3,7 +3,8 @@
"version": "0.8.27",
"private": true,
"workspaces": [
"apps/*"
"apps/*",
"packages/*"
],
"type": "module",
"scripts": {
+12 -12
View File
@@ -25,7 +25,7 @@ importers:
dependencies:
'@trade-message-center/onetalk-contract':
specifier: workspace:*
version: link:../onetalk-contract
version: link:../../packages/onetalk-contract
devDependencies:
'@types/node':
specifier: ^22.10.2
@@ -41,16 +41,7 @@ importers:
dependencies:
'@trade-message-center/onetalk-contract':
specifier: workspace:*
version: link:../onetalk-contract
devDependencies:
'@types/node':
specifier: ^22.10.2
version: 22.20.1
typescript:
specifier: ^5.7.3
version: 5.7.3
apps/onetalk-contract:
version: link:../../packages/onetalk-contract
devDependencies:
'@types/node':
specifier: ^22.10.2
@@ -66,7 +57,7 @@ importers:
version: 11.3.0
'@trade-message-center/onetalk-contract':
specifier: workspace:*
version: link:../onetalk-contract
version: link:../../packages/onetalk-contract
drizzle-orm:
specifier: ^0.45.2
version: 0.45.2(postgres@3.4.9)
@@ -87,6 +78,15 @@ importers:
specifier: ^5.7.3
version: 5.7.3
packages/onetalk-contract:
devDependencies:
'@types/node':
specifier: ^22.10.2
version: 22.20.1
typescript:
specifier: ^5.7.3
version: 5.7.3
packages:
'@drizzle-team/brocli@0.10.2':
+1
View File
@@ -1,4 +1,5 @@
packages:
- apps/*
- packages/*
allowBuilds:
esbuild: true
+1 -1
View File
@@ -6,7 +6,7 @@ import { fileURLToPath, pathToFileURL } from "node:url";
const workspaceDir = resolve(fileURLToPath(new URL(".", import.meta.url)), "..");
export const GENERATED_DIST_RELATIVE_PATHS = [
"apps/onetalk-contract/dist",
"packages/onetalk-contract/dist",
"apps/server/dist",
"apps/chrome-extension/dist",
];
+12 -6
View File
@@ -25,13 +25,19 @@ const readJsonFile = (filePath) => {
}
};
/** 枚举 apps 下可参与版本镜像的 workspace package。 */
const workspacePackageDirectories = ["apps", "packages"];
/** 按 workspace 根目录顺序枚举可参与版本镜像的 package。 */
export const listWorkspacePackagePaths = (rootDir = workspaceDir) =>
readdirSync(resolve(rootDir, "apps"), { withFileTypes: true })
.filter((entry) => entry.isDirectory())
.map((entry) => resolve(rootDir, "apps", entry.name, "package.json"))
.filter((packagePath) => existsSync(packagePath))
.sort();
workspacePackageDirectories.flatMap((directory) => {
const directoryPath = resolve(rootDir, directory);
if (!existsSync(directoryPath)) return [];
return readdirSync(directoryPath, { withFileTypes: true })
.filter((entry) => entry.isDirectory())
.map((entry) => resolve(directoryPath, entry.name, "package.json"))
.filter((packagePath) => existsSync(packagePath))
.sort();
});
/** 校验同时满足 npm 与 Chrome Manifest 的三段版本。 */
export const validatePackageVersion = (version, source = "package.json") => {
+20 -6
View File
@@ -3,13 +3,14 @@
import assert from "node:assert/strict";
import { mkdtempSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { join, relative } from "node:path";
import test from "node:test";
import {
bumpPackageVersion,
readRootPackageVersion,
validatePackageVersion,
listWorkspacePackagePaths,
writeRootPackageVersion,
} from "./package-version.mjs";
import { checkPackageVersions } from "./check-package-versions.mjs";
@@ -18,16 +19,17 @@ import { syncPackageVersions } from "./sync-package-versions.mjs";
const createWorkspace = (rootVersion, packageVersions) => {
const rootDir = mkdtempSync(join(tmpdir(), "tmc-package-version-"));
mkdirSync(join(rootDir, "apps"));
mkdirSync(join(rootDir, "packages"));
writeFileSync(
join(rootDir, "package.json"),
`${JSON.stringify({ name: "fixture", version: rootVersion }, null, 4)}\n`,
);
for (const [name, version] of Object.entries(packageVersions)) {
const packageDir = join(rootDir, "apps", name);
for (const [relativePackagePath, version] of Object.entries(packageVersions)) {
const packageDir = join(rootDir, relativePackagePath);
mkdirSync(packageDir);
writeFileSync(
join(packageDir, "package.json"),
`${JSON.stringify({ name, version }, null, 4)}\n`,
`${JSON.stringify({ name: relativePackagePath, version }, null, 4)}\n`,
);
}
return rootDir;
@@ -72,13 +74,25 @@ test("bumps and writes the root version without creating another version source"
assert.equal(readRootPackageVersion(rootDir), "0.8.17");
});
test("syncs and checks every app package against the root version", () => {
const rootDir = createWorkspace("1.2.3", { extension: "0.1.0", server: "0.1.0" });
test("syncs and checks app and shared workspace package mirrors against the root version", () => {
const rootDir = createWorkspace("1.2.3", {
"apps/extension": "0.1.0",
"apps/server": "0.1.0",
"packages/contract": "0.1.0",
});
assert.throws(() => checkPackageVersions(rootDir), /must equal root version 1.2.3/u);
syncPackageVersions(rootDir);
assert.equal(readRootPackageVersion(rootDir), "1.2.3");
checkPackageVersions(rootDir);
assert.deepEqual(
listWorkspacePackagePaths(rootDir).map((packagePath) => relative(rootDir, packagePath)),
[
"apps/extension/package.json",
"apps/server/package.json",
"packages/contract/package.json",
],
);
});
test("syncs version mirrors before root quality commands check them", () => {
+18 -6
View File
@@ -11,12 +11,17 @@ import { prepareRelease, publishRelease } from "./release.mjs";
const createWorkspace = (version = "0.8.16") => {
const rootDir = mkdtempSync(join(tmpdir(), "tmc-release-"));
mkdirSync(join(rootDir, "apps"));
mkdirSync(join(rootDir, "packages"));
writeFileSync(
join(rootDir, "package.json"),
`${JSON.stringify({ name: "fixture", version }, null, 4)}\n`,
);
for (const name of ["extension", "server"]) {
const packageDir = join(rootDir, "apps", name);
for (const [directory, name] of [
["apps", "extension"],
["apps", "server"],
["packages", "contract"],
]) {
const packageDir = join(rootDir, directory, name);
mkdirSync(packageDir);
writeFileSync(
join(packageDir, "package.json"),
@@ -41,7 +46,12 @@ const createRunner = (responses) => {
return { calls, execute };
};
const expectedFiles = ["package.json", "apps/extension/package.json", "apps/server/package.json"];
const expectedFiles = [
"package.json",
"apps/extension/package.json",
"apps/server/package.json",
"packages/contract/package.json",
];
test("prepares a patch release using only root-derived version mirrors", () => {
const rootDir = createWorkspace();
@@ -63,9 +73,11 @@ test("prepares a patch release using only root-derived version mirrors", () => {
assert.equal(prepareRelease({ rootDir, execute }), "0.8.17");
assert.equal(JSON.parse(readFileSync(join(rootDir, "package.json"), "utf8")).version, "0.8.17");
for (const packageName of ["extension", "server"]) {
const packagePath = join(rootDir, "apps", packageName, "package.json");
assert.equal(JSON.parse(readFileSync(packagePath, "utf8")).version, "0.8.17");
for (const packagePath of expectedFiles.slice(1)) {
assert.equal(
JSON.parse(readFileSync(join(rootDir, packagePath), "utf8")).version,
"0.8.17",
);
}
assert.deepEqual(
calls.filter(({ command }) => command === "pnpm").map(({ arguments_ }) => arguments_),