baa-conductor

git clone 

commit
259b731
parent
7138a3e
author
im_wower
date
2026-03-22 00:35:55 +0800 CST
Merge remote-tracking branch 'origin/feat/T-013-build-runtime' into integration/third-wave-20260322
8 files changed,  +51, -16
M apps/conductor-daemon/package.json
+2, -1
 1@@ -2,8 +2,9 @@
 2   "name": "@baa-conductor/conductor-daemon",
 3   "private": true,
 4   "type": "module",
 5+  "main": "dist/index.js",
 6   "scripts": {
 7-    "build": "pnpm exec tsc --noEmit -p tsconfig.json",
 8+    "build": "pnpm exec tsc -p tsconfig.json",
 9     "typecheck": "pnpm exec tsc --noEmit -p tsconfig.json"
10   }
11 }
M apps/control-api-worker/package.json
+2, -1
 1@@ -2,8 +2,9 @@
 2   "name": "@baa-conductor/control-api-worker",
 3   "private": true,
 4   "type": "module",
 5+  "main": "dist/index.js",
 6   "scripts": {
 7-    "build": "pnpm exec tsc --noEmit -p tsconfig.json",
 8+    "build": "pnpm exec tsc -p tsconfig.json && BAA_DIST_DIR=apps/control-api-worker/dist BAA_DIST_ENTRY=apps/control-api-worker/src/index.js BAA_IMPORT_ALIASES='@baa-conductor/auth=../../../packages/auth/src/index.js;@baa-conductor/db=../../../packages/db/src/index.js' BAA_FIX_RELATIVE_EXTENSIONS=true BAA_EXPORT_DEFAULT=true pnpm -C ../.. run build:runtime-postprocess",
 9     "typecheck": "pnpm exec tsc --noEmit -p tsconfig.json"
10   }
11 }
M apps/status-api/package.json
+2, -1
 1@@ -2,8 +2,9 @@
 2   "name": "@baa-conductor/status-api",
 3   "private": true,
 4   "type": "module",
 5+  "main": "dist/index.js",
 6   "scripts": {
 7-    "build": "pnpm exec tsc --noEmit -p tsconfig.json",
 8+    "build": "pnpm exec tsc -p tsconfig.json && BAA_DIST_DIR=apps/status-api/dist BAA_DIST_ENTRY=apps/status-api/src/index.js BAA_FIX_RELATIVE_EXTENSIONS=true pnpm -C ../.. run build:runtime-postprocess",
 9     "typecheck": "pnpm exec tsc --noEmit -p tsconfig.json"
10   }
11 }
M apps/worker-runner/package.json
+2, -1
 1@@ -2,8 +2,9 @@
 2   "name": "@baa-conductor/worker-runner",
 3   "private": true,
 4   "type": "module",
 5+  "main": "dist/index.js",
 6   "scripts": {
 7-    "build": "pnpm exec tsc --noEmit -p tsconfig.json",
 8+    "build": "pnpm exec tsc -p tsconfig.json && BAA_DIST_DIR=apps/worker-runner/dist BAA_DIST_ENTRY=apps/worker-runner/src/index.js BAA_IMPORT_ALIASES='@baa-conductor/logging=../../../packages/logging/src/index.js;@baa-conductor/checkpointing=../../../packages/checkpointing/src/index.js' BAA_FIX_RELATIVE_EXTENSIONS=true pnpm -C ../.. run build:runtime-postprocess",
 9     "typecheck": "pnpm exec tsc --noEmit -p tsconfig.json"
10   }
11 }
M coordination/tasks/T-013-build-runtime.md
+29, -9
 1@@ -1,10 +1,10 @@
 2 ---
 3 task_id: T-013
 4 title: Build 与 dist 产物
 5-status: todo
 6+status: review
 7 branch: feat/T-013-build-runtime
 8 repo: /Users/george/code/baa-conductor
 9-base_ref: main
10+base_ref: main@c5e007b
11 depends_on:
12   - T-011
13 write_scope:
14@@ -19,7 +19,7 @@ write_scope:
15   - apps/worker-runner/package.json
16   - apps/worker-runner/tsconfig.json
17   - docs/runtime/**
18-updated_at: 2026-03-21
19+updated_at: 2026-03-22T00:09:20+0800
20 ---
21 
22 # T-013 Build 与 dist 产物
23@@ -69,25 +69,45 @@ updated_at: 2026-03-21
24 
25 ## files_changed
26 
27-- 待填写
28+- `coordination/tasks/T-013-build-runtime.md`
29+- `package.json`
30+- `apps/conductor-daemon/package.json`
31+- `apps/control-api-worker/package.json`
32+- `apps/status-api/package.json`
33+- `apps/worker-runner/package.json`
34+- `docs/runtime/README.md`
35+- `docs/runtime/launchd.md`
36 
37 ## commands_run
38 
39-- 待填写
40+- `git worktree add /Users/george/code/baa-conductor-T013 -b feat/T-013-build-runtime c5e007b082772d085a030217691f6b88da9b3ee4`
41+- `npx --yes pnpm install`
42+- `npx --yes pnpm -r build`
43+- `node --input-type=module -e "await import('./apps/conductor-daemon/dist/index.js'); console.log('ok conductor-daemon');"`
44+- `node --input-type=module -e "await import('./apps/control-api-worker/dist/index.js'); console.log('ok control-api-worker');"`
45+- `node --input-type=module -e "await import('./apps/status-api/dist/index.js'); console.log('ok status-api');"`
46+- `node --input-type=module -e "await import('./apps/worker-runner/dist/index.js'); console.log('ok worker-runner');"`
47 
48 ## result
49 
50-- 待填写
51+- 四个 app 的 `build` 已从 `tsc --noEmit` 改成真实 emit,其中 `conductor-daemon` 直接输出 `dist/index.js`
52+- 为 `control-api-worker`、`status-api`、`worker-runner` 增加了统一 postbuild 处理:固定根入口到 `dist/index.js`,并在需要时改写编译后 import specifier
53+- `control-api-worker` 与 `worker-runner` 的编译产物已改写为引用同一 `dist/` 下同步生成的 package JS 文件,`worker-runner` 产物里的相对 import 也已补齐 `.js` 扩展
54+- `npx --yes pnpm -r build` 通过,四个 `apps/*/dist/index.js` 均存在,且可被 `node` 直接 `import(...)`
55+- `docs/runtime` 已更新为“先 build 再 launchd bootstrap”的当前约定,不再声明仓库缺少 `dist/index.js`
56 
57 ## risks
58 
59-- 待填写
60+- 目前 package 自身仍然只做 typecheck,没有形成独立发布级 `dist/`;`control-api-worker` 与 `worker-runner` 依赖 app build 阶段的产物改写
61+- 根 `package.json` 中的 postbuild helper 目前以内联脚本维护,后续如果构建规则继续变复杂,最好拆成独立脚本文件
62+- 本任务解决的是“产物路径稳定且可加载”,不是“服务运行时逻辑全部接好”;`T-014`、`T-015`、`T-017` 仍需补真正启动流程
63 
64 ## next_handoff
65 
66-- 待填写
67+- `T-014` 可以直接把 `apps/control-api-worker/dist/index.js` 当作稳定入口做运行时接线,不必再解决 bare workspace import 问题
68+- `T-015` 可以基于 `apps/conductor-daemon/dist/index.js` 继续补 CLI/daemon 启动逻辑,并复用文档里“先 build 再 bootstrap”的流程
69+- `T-017` 可以直接围绕 `apps/status-api/dist/index.js` 挂 HTTP 启动入口;若后续需要 package 级独立 dist,可另拆构建任务
70 
71 ## notes
72 
73 - `2026-03-21`: 创建第三波任务卡
74-
M docs/runtime/README.md
+4, -1
 1@@ -2,7 +2,9 @@
 2 
 3 本目录定义 `mini` 与 `mac` 上的本地 runtime 约定:目录布局、环境变量和 `launchd` 安装方式。
 4 
 5-当前仓库里的 app 仍是骨架实现,`pnpm build` 只做 TypeScript 校验,不生成 `apps/*/dist/index.js`。因此 `ops/launchd/*.plist` 现在是部署模板,先把路径和环境约定固定下来,等真实产物接上后继续沿用同一套安装步骤。
 6+当前仓库已经把 app 级 `build` 从单纯 typecheck 推进到真实 emit。执行 `npx --yes pnpm -r build` 后,`apps/*/dist/index.js` 会生成,`ops/launchd/*.plist` 里的入口路径也因此固定下来。
 7+
 8+这仍然不代表所有长期服务都已经完成运行时接线。当前阶段解决的是“产物路径存在且一致”,而不是“所有 daemon/worker 逻辑都已可直接上线”。
 9 
10 ## 内容
11 
12@@ -22,3 +24,4 @@
13 1. 先按 [`layout.md`](./layout.md) 初始化 runtime 根目录。
14 2. 再按 [`environment.md`](./environment.md) 准备共享变量和节点变量,特别是 `BAA_SHARED_TOKEN`。
15 3. 最后按 [`launchd.md`](./launchd.md) 复制、调整并加载 plist。
16+4. 每次准备加载或重载本地服务前,先在 repo 根目录执行一次 `npx --yes pnpm -r build`,确认目标 app 的 `dist/index.js` 已更新。
M docs/runtime/launchd.md
+9, -1
 1@@ -150,4 +150,12 @@ tail -n 50 /Users/george/code/baa-conductor/logs/launchd/so.makefile.baa-conduct
 2 tail -n 50 /Users/george/code/baa-conductor/logs/launchd/so.makefile.baa-worker-runner.err.log
 3 ```
 4 
 5-当前仓库还没有真实的 `dist/index.js` 产物,因此真正执行 `bootstrap` 后,服务进程仍可能因为入口文件不存在而启动失败。这不影响本任务交付的部署约定;后续只要服务构建产物落到约定路径,安装方式不需要再改。
 6+当前仓库已经能为 app 生成基础 `dist/index.js` 产物,因此 launchd 不再依赖“未来某天才会出现的入口文件”。在执行 `launchctl bootstrap` 之前,先在 repo 根目录跑一次:
 7+
 8+```bash
 9+npx --yes pnpm -r build
10+```
11+
12+这样可以确保 plist 指向的 `apps/*/dist/index.js` 已刷新到最新代码。
13+
14+需要注意的是,第三波后续任务还会继续补各服务的真正运行时接线,所以“入口文件存在”不等于“业务逻辑已经全部落地”。这里解决的是部署路径与构建产物的一致性。
M package.json
+1, -1
 1@@ -4,6 +4,7 @@
 2   "packageManager": "pnpm@10.6.0",
 3   "scripts": {
 4     "build": "pnpm -r build",
 5+    "build:runtime-postprocess": "node --input-type=module -e \"import { mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from 'node:fs'; import { join } from 'node:path'; const distDir = process.env.BAA_DIST_DIR; const entry = process.env.BAA_DIST_ENTRY; if (!distDir || !entry) { throw new Error('BAA_DIST_DIR and BAA_DIST_ENTRY are required.'); } const aliasPairs = (process.env.BAA_IMPORT_ALIASES ?? '').split(';').filter(Boolean).map((pair) => { const separatorIndex = pair.indexOf('='); if (separatorIndex <= 0) { throw new Error('Invalid alias pair: ' + pair); } return [pair.slice(0, separatorIndex), pair.slice(separatorIndex + 1)]; }); const fixRelativeExtensions = process.env.BAA_FIX_RELATIVE_EXTENSIONS === 'true'; const jsFiles = []; const collect = (directory) => { for (const entryName of readdirSync(directory)) { const entryPath = join(directory, entryName); const stats = statSync(entryPath); if (stats.isDirectory()) { collect(entryPath); continue; } if (entryPath.endsWith('.js')) { jsFiles.push(entryPath); } } }; collect(distDir); for (const filePath of jsFiles) { let source = readFileSync(filePath, 'utf8'); for (const [from, to] of aliasPairs) { source = source.replaceAll('\\\"' + from + '\\\"', '\\\"' + to + '\\\"').replaceAll(\\\"'\\\" + from + \\\"'\\\", \\\"'\\\" + to + \\\"'\\\"); } if (fixRelativeExtensions) { source = source.replace(/((?:from|import)\\s*[\\\"'])(\\.\\.?\\/[^\\\"'()]+?)([\\\"'])/g, (match, prefix, specifier, suffix) => /\\.[cm]?[jt]sx?$/.test(specifier) || specifier.endsWith('.json') ? match : prefix + specifier + '.js' + suffix); } writeFileSync(filePath, source); } mkdirSync(distDir, { recursive: true }); const entrySpecifier = './' + entry; const shimLines = ['export * from ' + JSON.stringify(entrySpecifier) + ';']; if (process.env.BAA_EXPORT_DEFAULT === 'true') { shimLines.push('export { default } from ' + JSON.stringify(entrySpecifier) + ';'); } writeFileSync(join(distDir, 'index.js'), shimLines.join('\\n') + '\\n');\"",
 6     "typecheck": "pnpm -r typecheck",
 7     "lint": "echo 'TODO: add linting'",
 8     "test": "echo 'TODO: add tests'",
 9@@ -13,4 +14,3 @@
10     "typescript": "^5.8.2"
11   }
12 }
13-