feat: extend k3s artifact consumers

This commit is contained in:
Codex
2026-05-20 02:58:41 +00:00
parent 15a1a8b21a
commit 595de3d320
28 changed files with 1003 additions and 76 deletions
+4 -4
View File
@@ -38,9 +38,9 @@ UniDesk 是一个以主 server 为统一入口的分布式工作平台;本文
- `bun scripts/cli.ts microservice list/status/health/diagnostics/tunnel-self-test/proxy`:管理和验证挂载在主 server、计算节点 Docker 或 k3s 控制面上的用户服务,`proxy` 支持受控 JSON bodyOA Event Flow/Todo Note/Baidu Netdisk/Code Queue Manager on main-server、k3s Control/Code Queue 执行面/MDTODO/Decision Center/FindJob/Pipeline/MET Nonlinear on D601 的规则见 `docs/reference/microservices.md` - `bun scripts/cli.ts microservice list/status/health/diagnostics/tunnel-self-test/proxy`:管理和验证挂载在主 server、计算节点 Docker 或 k3s 控制面上的用户服务,`proxy` 支持受控 JSON bodyOA Event Flow/Todo Note/Baidu Netdisk/Code Queue Manager on main-server、k3s Control/Code Queue 执行面/MDTODO/Decision Center/FindJob/Pipeline/MET Nonlinear on D601 的规则见 `docs/reference/microservices.md`
- `bun scripts/cli.ts decision upload/list/show/health`:通过 backend-core 用户服务代理上传会议记录/决议 Markdown、列出记录和查看详情;Decision Center 运行在 D601 k3s,规则见 `docs/reference/microservices.md` - `bun scripts/cli.ts decision upload/list/show/health`:通过 backend-core 用户服务代理上传会议记录/决议 Markdown、列出记录和查看详情;Decision Center 运行在 D601 k3s,规则见 `docs/reference/microservices.md`
- `bun scripts/cli.ts decision diary import/list/months/show`:把带日期标题的工作日志 Markdown 拆成 `YYYY-MM/YYYY-MM-DD.md` 日记条目并写入 PostgreSQL,规则见 `docs/reference/microservices.md` - `bun scripts/cli.ts decision diary import/list/months/show`:把带日期标题的工作日志 Markdown 拆成 `YYYY-MM/YYYY-MM-DD.md` 日记条目并写入 PostgreSQL,规则见 `docs/reference/microservices.md`
- `bun scripts/cli.ts deploy check/plan/apply [--file deploy.json|--env dev|prod] [--service <id>]`:按根目录 `deploy.json``origin/master:deploy.json#environments.<env>` 的服务 repo 和 commit 期望状态校验或更新用户服务;`--env dev` 当前开放 D601 `backend-core` persistent dev rollout 以及 `frontend`/`baidu-netdisk`/`decision-center`/`project-manager`/`oa-event-flow`/`code-queue-mgr` artifact-consumer validation`todo-note` 仅 dry-run,规则见 `docs/reference/deploy.md``docs/reference/dev-environment.md` - `bun scripts/cli.ts deploy check/plan/apply [--file deploy.json|--env dev|prod] [--service <id>]`:按根目录 `deploy.json``origin/master:deploy.json#environments.<env>` 的服务 repo 和 commit 期望状态校验或更新用户服务;`--env dev` 开放 D601 `backend-core` rollout `frontend`/`baidu-netdisk`/`decision-center`/`mdtodo`/`claudeqq`/dev-only `code-queue`/direct consumer validation`code-queue` prod unsupported,规则见 `docs/reference/deploy.md``docs/reference/dev-environment.md`
- `bun scripts/cli.ts dev-env validate [--manifest path] [--kubectl-dry-run]` / `dev-env prewarm-images`:离线校验 D601 `unidesk-dev` 生产隔离护栏,或把开发底座基础镜像预热到 D601 原生 k3s containerd,规则见 `docs/reference/deploy.md``docs/reference/microservices.md` - `bun scripts/cli.ts dev-env validate [--manifest path] [--kubectl-dry-run]` / `dev-env prewarm-images`:离线校验 D601 `unidesk-dev` 生产隔离护栏和 dev workload manifests,或把开发底座基础镜像预热到 D601 原生 k3s containerd,规则见 `docs/reference/deploy.md``docs/reference/microservices.md`
- `bun scripts/cli.ts artifact-registry plan|render|status|health|install|deploy-backend-core|deploy-service`:管理 D601 host-managed CNCF Distribution registry,并通过短生命周期 relay 或 D601 pull/import 做 commit-pinned pull-only artifact CD`deploy-backend-core` 是 deprecated 兼容名,backend-core prod CD 标准入口是 `deploy apply --env prod --service backend-core`,规则见 `docs/reference/artifact-registry.md` - `bun scripts/cli.ts artifact-registry plan|render|status|health|install|deploy-backend-core|deploy-service`:管理 D601 host-managed CNCF Distribution registry,并通过短生命周期 relay 或 D601 pull/import 做 commit-pinned pull-only artifact CD`deploy-backend-core` 是 deprecated 兼容名,`mdtodo`/`claudeqq` 支持 dev/prod`code-queue` 只支持 dev,规则见 `docs/reference/artifact-registry.md`
- `bun scripts/cli.ts ci install/status/run/publish-backend-core/publish-user-service/run-dev-e2e/logs`:在 D601 原生 k3s 上安装和运行 Tekton CI,支持每 commit 检查、Code Queue 只读性能门禁、`CI.json` catalog 驱动的 backend-core 与 user-service commit-pinned 镜像发布和手动触发的 `origin/master:deploy.json#environments.dev` 临时 namespace e2ecatalog/producer/consumer 分工见 `docs/reference/cicd-standardization.md``run-dev-e2e` 的 Git 控制 runner、短 launcher 和 no-CD 边界见 `docs/reference/dev-ci-runner.md`Tekton 规则见 `docs/reference/ci.md` - `bun scripts/cli.ts ci install/status/run/publish-backend-core/publish-user-service/run-dev-e2e/logs`:在 D601 原生 k3s 上安装和运行 Tekton CI,支持每 commit 检查、Code Queue 只读性能门禁、`CI.json` catalog 驱动的 backend-core 与 user-service commit-pinned 镜像发布和手动触发的 `origin/master:deploy.json#environments.dev` 临时 namespace e2ecatalog/producer/consumer 分工见 `docs/reference/cicd-standardization.md``run-dev-e2e` 的 Git 控制 runner、短 launcher 和 no-CD 边界见 `docs/reference/dev-ci-runner.md`Tekton 规则见 `docs/reference/ci.md`
- `bun scripts/cli.ts codex deploy <commitId>`:旧 Code Queue 兼容部署入口已禁用,原因是它会绕过受控部署边界直连 D601 部署 Code Queue;规则见 `docs/reference/codex-deploy.md` - `bun scripts/cli.ts codex deploy <commitId>`:旧 Code Queue 兼容部署入口已禁用,原因是它会绕过受控部署边界直连 D601 部署 Code Queue;规则见 `docs/reference/codex-deploy.md`
- `bun scripts/cli.ts codex submit [prompt] [--prompt-file path|--prompt-stdin] [--queue <id>]`:通过 backend-core 私有代理提交 Code Queue 任务;控制面默认走主 server `code-queue-mgr` 写入 PostgreSQL`--dry-run` 可只检查请求体不入队,规则见 `docs/reference/cli.md` - `bun scripts/cli.ts codex submit [prompt] [--prompt-file path|--prompt-stdin] [--queue <id>]`:通过 backend-core 私有代理提交 Code Queue 任务;控制面默认走主 server `code-queue-mgr` 写入 PostgreSQL`--dry-run` 可只检查请求体不入队,规则见 `docs/reference/cli.md`
@@ -55,7 +55,7 @@ UniDesk 是一个以主 server 为统一入口的分布式工作平台;本文
## Runtime ## Runtime
- `bun`TypeScript 运行时固定使用 Bun,组件入口和 CLI 都直接运行 `.ts` 文件,约束见 `docs/reference/config.md` - `bun`TypeScript 运行时固定使用 Bun,组件入口和 CLI 都直接运行 `.ts` 文件,约束见 `docs/reference/config.md`
- `docker-compose.yml`:主 server 统一编排 core、frontend、dev-frontend-proxy、database、本机 provider gateway、Todo Note 后端、Baidu Netdisk 后端、OA Event Flow 后端和轻量 Code Queue Manager 控制面;Code Queue 执行面、MDTODO 和 Decision Center 由 D601 k3s/k8s 控制面代管,并经 `k3sctl-adapter` 的 Kubernetes API service proxy 单一路径接入,服务拓扑见 `docs/reference/deployment.md``docs/reference/dev-environment.md` - `docker-compose.yml`:主 server 统一编排 core、frontend、dev-frontend-proxy、database、本机 provider gateway、Todo Note 后端、Baidu Netdisk 后端、OA Event Flow 后端和轻量 Code Queue Manager 控制面;Code Queue 执行面、MDTODO、ClaudeQQ 和 Decision Center 由 D601 k3s/k8s 控制面代管,并经 `k3sctl-adapter` 的 Kubernetes API service proxy 单一路径接入,服务拓扑见 `docs/reference/deployment.md``docs/reference/dev-environment.md`
- `src/components/frontend`:前端源码固定使用 TypeScript + React`app.tsx` 只做 shell/router,左侧主模块与顶部子标签统一编译为模块前缀路由:`/ops/<tab>/``/nodes/<tab>/``/tasks/<tab>/``/config/<tab>/`,只有用户服务使用 `/app/<tab>/` 深链接,运行总览包含通用性能面板,资源监控含曲线和进程资源排序表,Todo Note、FindJob、Pipeline、MET Nonlinear、Baidu Netdisk、Code Queue、MDTODO、Decision Center、OA Event Flow、k3s Control 等业务页必须拆到独立 TSX 模块,界面规则见 `docs/reference/frontend.md` - `src/components/frontend`:前端源码固定使用 TypeScript + React`app.tsx` 只做 shell/router,左侧主模块与顶部子标签统一编译为模块前缀路由:`/ops/<tab>/``/nodes/<tab>/``/tasks/<tab>/``/config/<tab>/`,只有用户服务使用 `/app/<tab>/` 深链接,运行总览包含通用性能面板,资源监控含曲线和进程资源排序表,Todo Note、FindJob、Pipeline、MET Nonlinear、Baidu Netdisk、Code Queue、MDTODO、Decision Center、OA Event Flow、k3s Control 等业务页必须拆到独立 TSX 模块,界面规则见 `docs/reference/frontend.md`
- `backend-core / frontend performance`backend-core 暴露 `/api/performance`frontend 暴露同源 `/api/frontend-performance` 并在 `/ops/performance/` 汇总组件请求、失败请求、内部操作和慢操作,规则见 `docs/reference/observability.md`backend-core 当前为 Rust 服务,结构见 `docs/reference/repo-tree.md`Rust 编译边界见 `docs/reference/dev-environment.md` - `backend-core / frontend performance`backend-core 暴露 `/api/performance`frontend 暴露同源 `/api/frontend-performance` 并在 `/ops/performance/` 汇总组件请求、失败请求、内部操作和慢操作,规则见 `docs/reference/observability.md`backend-core 当前为 Rust 服务,结构见 `docs/reference/repo-tree.md`Rust 编译边界见 `docs/reference/dev-environment.md`
- `Unified OA event flow``oa-event-flow` 是独立主 server 用户服务,提供事件表、按 tag 订阅和 Trace/STEP 统计中心,Code Queue 与 Pipeline 都必须接入统一事件流;共享契约见 `docs/reference/oa-event-flow.md`Pipeline 专有控制流规则见 `docs/reference/pipeline-oa-event-flow.md` - `Unified OA event flow``oa-event-flow` 是独立主 server 用户服务,提供事件表、按 tag 订阅和 Trace/STEP 统计中心,Code Queue 与 Pipeline 都必须接入统一事件流;共享契约见 `docs/reference/oa-event-flow.md`Pipeline 专有控制流规则见 `docs/reference/pipeline-oa-event-flow.md`
+6 -4
View File
@@ -215,7 +215,8 @@
}, },
"image": { "image": {
"repository": "unidesk/mdtodo" "repository": "unidesk/mdtodo"
} },
"notes": "D601 k3s-managed user-service artifact. Dev consumer targets unidesk-dev/mdtodo-dev; prod consumer targets unidesk/mdtodo."
}, },
{ {
"serviceId": "claudeqq", "serviceId": "claudeqq",
@@ -228,12 +229,13 @@
}, },
"image": { "image": {
"repository": "unidesk/claudeqq" "repository": "unidesk/claudeqq"
} },
"notes": "External Gitee source repo. CI exports the claudeqq/ subtree and overlays the UniDesk Dockerfile plus adapter before building."
}, },
{ {
"serviceId": "code-queue", "serviceId": "code-queue",
"kind": "source-build", "kind": "source-build",
"status": "blocked", "status": "supported",
"producer": "ci publish-user-service", "producer": "ci publish-user-service",
"source": { "source": {
"repo": "https://github.com/pikasTech/unidesk", "repo": "https://github.com/pikasTech/unidesk",
@@ -242,7 +244,7 @@
"image": { "image": {
"repository": "unidesk/code-queue" "repository": "unidesk/code-queue"
}, },
"blockedReason": "D601 code-queue is limited to dev image validation in this phase. The catalog records its producer input, but publish-user-service must not run prod-oriented artifact publication for it yet." "notes": "Artifact producer is allowed for dev image validation only. The CD consumer for code-queue is dev-only; production artifact deploy, rollout and manifest mutation remain unsupported."
}, },
{ {
"serviceId": "filebrowser", "serviceId": "filebrowser",
+10
View File
@@ -122,6 +122,16 @@
"repo": "https://github.com/pikasTech/unidesk", "repo": "https://github.com/pikasTech/unidesk",
"commitId": "54c1f8e165f90fa8509fda1f0c01f8c3fa82cbee" "commitId": "54c1f8e165f90fa8509fda1f0c01f8c3fa82cbee"
}, },
{
"id": "mdtodo",
"repo": "https://github.com/pikasTech/unidesk",
"commitId": "75fb6757b2504ba86d61f2587fb34a9c9ed4019a"
},
{
"id": "claudeqq",
"repo": "https://gitee.com/lyon1998/agent_skills",
"commitId": "203b1f46684c91340ecbbd8a74502bd55e4f2011"
},
{ {
"id": "todo-note", "id": "todo-note",
"repo": "https://gitee.com/Lyon1998/todo_note", "repo": "https://gitee.com/Lyon1998/todo_note",
+14 -3
View File
@@ -71,6 +71,11 @@ bun scripts/cli.ts artifact-registry deploy-service --env dev --service findjob
bun scripts/cli.ts artifact-registry deploy-service --env dev --service pipeline --commit <full-sha> --dry-run bun scripts/cli.ts artifact-registry deploy-service --env dev --service pipeline --commit <full-sha> --dry-run
bun scripts/cli.ts artifact-registry deploy-service --env dev --service met-nonlinear --commit <full-sha> --dry-run bun scripts/cli.ts artifact-registry deploy-service --env dev --service met-nonlinear --commit <full-sha> --dry-run
bun scripts/cli.ts artifact-registry deploy-service --env prod --service k3sctl-adapter --commit <full-sha> --dry-run bun scripts/cli.ts artifact-registry deploy-service --env prod --service k3sctl-adapter --commit <full-sha> --dry-run
bun scripts/cli.ts artifact-registry deploy-service --service mdtodo --env dev --commit <full-sha>
bun scripts/cli.ts artifact-registry deploy-service --service mdtodo --env prod --commit <full-sha>
bun scripts/cli.ts artifact-registry deploy-service --service claudeqq --env dev --commit <full-sha>
bun scripts/cli.ts artifact-registry deploy-service --service claudeqq --env prod --commit <full-sha>
bun scripts/cli.ts artifact-registry deploy-service --service code-queue --env dev --commit <full-sha>
``` ```
`plan` 输出架构边界、依赖项、默认路径和 backend-core artifact CD 流程。`render` 输出 systemd unit、Compose 文件和 registry config 的完整内容与 SHA-256。`install --dry-run` 只列出将要执行的远端动作,不写 D601 文件、不启动容器、不 reload systemd。 `plan` 输出架构边界、依赖项、默认路径和 backend-core artifact CD 流程。`render` 输出 systemd unit、Compose 文件和 registry config 的完整内容与 SHA-256。`install --dry-run` 只列出将要执行的远端动作,不写 D601 文件、不启动容器、不 reload systemd。
@@ -79,7 +84,7 @@ bun scripts/cli.ts artifact-registry deploy-service --env prod --service k3sctl-
`deploy-backend-core` 是旧兼容入口,当前作为标准路径已禁用。Production backend-core CD 必须使用 `bun scripts/cli.ts deploy apply --env prod --service backend-core --commit <full-sha>`,由 deploy reconciler 先执行共同的 artifact-consumer guardrail,再调用通用 `deploy-service` consumer。旧入口只能返回 structured deprecated 结果,不得绕过 `deploy apply --env prod` `deploy-backend-core` 是旧兼容入口,当前作为标准路径已禁用。Production backend-core CD 必须使用 `bun scripts/cli.ts deploy apply --env prod --service backend-core --commit <full-sha>`,由 deploy reconciler 先执行共同的 artifact-consumer guardrail,再调用通用 `deploy-service` consumer。旧入口只能返回 structured deprecated 结果,不得绕过 `deploy apply --env prod`
`deploy-service` 是标准化后的最小通用 artifact consumer。它目前支持 `backend-core``baidu-netdisk`、prod/dev `frontend``decision-center``project-manager``oa-event-flow``code-queue-mgr``todo-note``findjob``pipeline``met-nonlinear``k3sctl-adapter`。所有路径都必须先通过 D601 registry 的 commit-pinned manifest 校验,再执行拉取、导入/retag、部署和健康验证;`code-queue-mgr` 的 prod live apply 仍需 supervisor 单独确认,`met-nonlinear``k3sctl-adapter` 当前只提供 plan/dry-run `deploy-service` 是标准化后的最小通用 artifact consumer。它目前支持 `backend-core``baidu-netdisk`、prod/dev `frontend``decision-center``mdtodo``claudeqq``project-manager``oa-event-flow``code-queue-mgr``todo-note``findjob``pipeline``met-nonlinear``k3sctl-adapter`,以及 dev-only `code-queue`。所有路径都必须先通过 D601 registry 的 commit-pinned manifest 校验,再执行拉取、导入/retag、部署和健康验证;`code-queue --env prod` 必须返回 structured unsupported,不能回退到生产 artifact deploy、rollout 或 manifest 变更;`code-queue-mgr` 的 prod live apply 仍需 supervisor 单独确认,`met-nonlinear``k3sctl-adapter` 当前只提供 plan/dry-run
```bash ```bash
bun scripts/cli.ts artifact-registry deploy-service --service baidu-netdisk --commit <full-sha> --run-now bun scripts/cli.ts artifact-registry deploy-service --service baidu-netdisk --commit <full-sha> --run-now
@@ -92,9 +97,14 @@ bun scripts/cli.ts artifact-registry deploy-service --env prod --service oa-even
bun scripts/cli.ts artifact-registry deploy-service --env prod --service todo-note --commit <full-sha> --run-now bun scripts/cli.ts artifact-registry deploy-service --env prod --service todo-note --commit <full-sha> --run-now
bun scripts/cli.ts artifact-registry deploy-service --env prod --service findjob --commit <full-sha> --run-now bun scripts/cli.ts artifact-registry deploy-service --env prod --service findjob --commit <full-sha> --run-now
bun scripts/cli.ts artifact-registry deploy-service --env prod --service pipeline --commit <full-sha> --run-now bun scripts/cli.ts artifact-registry deploy-service --env prod --service pipeline --commit <full-sha> --run-now
bun scripts/cli.ts artifact-registry deploy-service --env dev --service mdtodo --commit <full-sha> --run-now
bun scripts/cli.ts artifact-registry deploy-service --env prod --service mdtodo --commit <full-sha> --run-now
bun scripts/cli.ts artifact-registry deploy-service --env dev --service claudeqq --commit <full-sha> --run-now
bun scripts/cli.ts artifact-registry deploy-service --env prod --service claudeqq --commit <full-sha> --run-now
bun scripts/cli.ts artifact-registry deploy-service --env dev --service code-queue --commit <full-sha> --run-now
``` ```
dry-run 输出会暴露 registry probe URL、required labels、目标 image、部署形态和回滚信息。`baidu-netdisk` 的 Compose 路径会通过 provider-gateway Host SSH 把 `unidesk/baidu-netdisk:<commit>` 流式拉到 master serverretag 为 `baidu-netdisk``baidu-netdisk:<commit>`,写入 `UNIDESK_BAIDU_NETDISK_DEPLOY_*`,只 recreate `baidu-netdisk` service,并验证容器 image label 与 `/health.deploy.commit``findjob``pipeline``met-nonlinear` 的 D601 direct Compose 路径在 D601 本机验证 registry manifest、pull image、retag stable image、写入 `UNIDESK_*_DEPLOY_*` labels/env,并用 `docker compose up -d --no-build --no-deps --force-recreate <service>` 重新拉起对应 compose service;其中 `met-nonlinear` 当前因为 registered Dockerfile 和 long-running service contract 不一致而 live deploy blocked。`k3sctl-adapter` 是基础设施控制桥,只做 plan/dry-run,真实生产部署需要 supervisor 单独确认。`frontend --env prod` 使用同一 Compose artifact consumer,流式拉取 `unidesk/frontend:<commit>`retag 为 `unidesk-frontend``unidesk-frontend:<commit>`,写入 `UNIDESK_FRONTEND_DEPLOY_*`,只 recreate `frontend` service,并验证 image label 与 `/health.deploy.commit``frontend --env dev``decision-center` 的 k3s 路径会在 D601 上验证 commit image、导入 native k3s containerd、更新 Deployment image/env/annotations,并通过 Kubernetes API service proxy 验证 `/health` 中的 `deploy.commit``deploy.requestedCommit`dev frontend 还会在 rollout 前把主 server `config.json.auth` 同步到 `unidesk-dev` Secret/ConfigMap。`decision-center --env dev` 落到 `unidesk-dev/decision-center-dev`prod 落到 `unidesk/decision-center`。D601 direct Compose consumer 与 k3s-managed consumer 的区别是:前者只接触 D601 Docker/Compose 项目和私有 backend health,不创建 Kubernetes 对象;后者只通过 native k3s Deployment/Service、containerd import 和 Kubernetes API service proxy 验证 live commit。回滚信息通过同一 artifact consumer 的 `rollback` 字段暴露,提示操作者重新对一个旧 commit 运行相同命令,而不是切回 legacy maintenance-channel 构建。 dry-run 输出会暴露 registry probe URL、required labels、目标 image、部署形态、目标 Deployment 列表和回滚信息。`baidu-netdisk` 的 Compose 路径会通过 provider-gateway Host SSH 把 `unidesk/baidu-netdisk:<commit>` 流式拉到 master serverretag 为 `baidu-netdisk``baidu-netdisk:<commit>`,写入 `UNIDESK_BAIDU_NETDISK_DEPLOY_*`,只 recreate `baidu-netdisk` service,并验证容器 image label 与 `/health.deploy.commit``findjob``pipeline``met-nonlinear` 的 D601 direct Compose 路径在 D601 本机验证 registry manifest、pull image、retag stable image、写入 `UNIDESK_*_DEPLOY_*` labels/env,并用 `docker compose up -d --no-build --no-deps --force-recreate <service>` 重新拉起对应 compose service;其中 `met-nonlinear` 当前因为 registered Dockerfile 和 long-running service contract 不一致而 live deploy blocked。`k3sctl-adapter` 是基础设施控制桥,只做 plan/dry-run,真实生产部署需要 supervisor 单独确认。`frontend --env prod` 使用同一 Compose artifact consumer,流式拉取 `unidesk/frontend:<commit>`retag 为 `unidesk-frontend``unidesk-frontend:<commit>`,写入 `UNIDESK_FRONTEND_DEPLOY_*`,只 recreate `frontend` service,并验证 image label 与 `/health.deploy.commit``frontend --env dev``decision-center``mdtodo``claudeqq` 和 dev `code-queue` 的 k3s 路径会在 D601 上验证 commit image、导入 native k3s containerd、更新 Deployment image/env/annotations,并通过 Kubernetes API service proxy 验证 `/health` 中的 live commit 与 requested commitdev frontend 还会在 rollout 前把主 server `config.json.auth` 同步到 `unidesk-dev` Secret/ConfigMap。`decision-center --env dev` 落到 `unidesk-dev/decision-center-dev`prod 落到 `unidesk/decision-center``mdtodo``claudeqq` 使用同样的 dev 后 prod k3s consumer 结构。`code-queue --env dev` 只更新 `unidesk-dev` 中的 scheduler/read/write/provider-egress-proxy dev Deploymentsprod 没有 consumer target。D601 direct Compose consumer 与 k3s-managed consumer 的区别是:前者只接触 D601 Docker/Compose 项目和私有 backend health,不创建 Kubernetes 对象;后者只通过 native k3s Deployment/Service、containerd import 和 Kubernetes API service proxy 验证 live commit。回滚信息通过同一 artifact consumer 的 `rollback` 字段暴露,提示操作者重新对一个旧 commit 运行相同命令,而不是切回 legacy maintenance-channel 构建。
`status``health` 通过: `status``health` 通过:
@@ -138,7 +148,7 @@ docker compose -p unidesk-artifact-registry -f /home/ubuntu/.unidesk/artifact-re
6. Compose runtime retag 为 Compose 使用的镜像名,并执行 `docker compose up -d --no-build --no-deps --force-recreate <service>`k3s runtime 设置 Deployment image/env/annotations 并等待 rollout。 6. Compose runtime retag 为 Compose 使用的镜像名,并执行 `docker compose up -d --no-build --no-deps --force-recreate <service>`k3s runtime 设置 Deployment image/env/annotations 并等待 rollout。
7. 部署后通过 image label、runtime env、health payload 验证 live commit。 7. 部署后通过 image label、runtime env、health payload 验证 live commit。
Baidu Netdisk is the first main-server direct user-service sample in this flow. Its dev validation command and prod CD command both consume `127.0.0.1:5000/unidesk/baidu-netdisk:<commit>` and must not build source on the master server. Frontend is the standard UniDesk UI artifact sample: CI publishes `127.0.0.1:5000/unidesk/frontend:<commit>`, production CD consumes that artifact into the master-server Compose `frontend` service, and dev CD consumes the same artifact into D601 native k3s `frontend-dev`. Project Manager, OA Event Flow and Todo Note use the same master-server Compose artifact-consumer shape as Baidu Netdisk, with `project-manager-backend`, `oa-event-flow-backend` and `todo-note-backend` as the runtime containers; Todo Note keeps its external source repository and requires a pre-existing `127.0.0.1:5000/unidesk/todo-note:<commit>` artifact. Its consumer injects `UNIDESK_TODO_NOTE_DEPLOY_*` runtime metadata and the container health probe combines `/api/health` with that metadata before enforcing `deploy.commit` / `deploy.requestedCommit`. Code Queue Manager is supported as an artifact consumer for validation, but prod live apply is supervisor-gated. Neither path may use `server rebuild frontend`, dirty source, mutable `latest`, or target-side frontend source builds as release truth. Decision Center follows the same artifact-consumer pattern in both dev and prod, except the runtime target is native k3s on D601 instead of the master-server Compose stack. The consumer must check the registry manifest, pull the commit-pinned image, import it into `/run/k3s/containerd/containerd.sock`, set the Deployment image to the commit tag, stamp `UNIDESK_DEPLOY_*` env/annotations, and reject an old healthy revision if the live commit or requested commit does not match. Baidu Netdisk is the first main-server direct user-service sample in this flow. Its dev validation command and prod CD command both consume `127.0.0.1:5000/unidesk/baidu-netdisk:<commit>` and must not build source on the master server. Frontend is the standard UniDesk UI artifact sample: CI publishes `127.0.0.1:5000/unidesk/frontend:<commit>`, production CD consumes that artifact into the master-server Compose `frontend` service, and dev CD consumes the same artifact into D601 native k3s `frontend-dev`. Project Manager, OA Event Flow and Todo Note use the same master-server Compose artifact-consumer shape as Baidu Netdisk, with `project-manager-backend`, `oa-event-flow-backend` and `todo-note-backend` as the runtime containers; Todo Note keeps its external source repository and requires a pre-existing `127.0.0.1:5000/unidesk/todo-note:<commit>` artifact. Its consumer injects `UNIDESK_TODO_NOTE_DEPLOY_*` runtime metadata and the container health probe combines `/api/health` with that metadata before enforcing `deploy.commit` / `deploy.requestedCommit`. Code Queue Manager is supported as an artifact consumer for validation, but prod live apply is supervisor-gated. Neither path may use `server rebuild frontend`, dirty source, mutable `latest`, or target-side frontend source builds as release truth. Decision Center, MDTODO and ClaudeQQ follow the same artifact-consumer pattern in both dev and prod, except the runtime target is native k3s on D601 instead of the master-server Compose stack. Dev `code-queue` is a deliberately narrower consumer: it validates only the `unidesk-dev` Code Queue execution slice and has no prod target. The k3s consumer must check the registry manifest, pull the commit-pinned image, import it into `/run/k3s/containerd/containerd.sock`, set the Deployment image to the commit tag, stamp `UNIDESK_DEPLOY_*` env/annotations, verify health through the Kubernetes API service proxy, and reject an old healthy revision if the live commit or requested commit does not match.
这个 CD 路径必须满足: 这个 CD 路径必须满足:
@@ -147,4 +157,5 @@ Baidu Netdisk is the first main-server direct user-service sample in this flow.
- provider-gateway SSH image stream 是临时控制动作,不开放长期公网 registry。 - provider-gateway SSH image stream 是临时控制动作,不开放长期公网 registry。
- CI 可以有较多依赖;CD 只做拉取、retag、recreate 和 live commit 验证。 - CI 可以有较多依赖;CD 只做拉取、retag、recreate 和 live commit 验证。
- CD 不执行 `cargo build``docker build``docker compose build <service>` 或任何等价构建动作。 - CD 不执行 `cargo build``docker build``docker compose build <service>` 或任何等价构建动作。
- k3s-managed artifact consumers must not add NodePort, hostPort, public business ports or provider-gateway direct business backends.
- `artifact-registry deploy-backend-core``server rebuild backend-core``server rebuild baidu-netdisk` 仍是维护/兼容/非标准路径,不得作为 artifact CD 完成证据。 - `artifact-registry deploy-backend-core``server rebuild backend-core``server rebuild baidu-netdisk` 仍是维护/兼容/非标准路径,不得作为 artifact CD 完成证据。
+16 -2
View File
@@ -111,7 +111,7 @@ The artifact registry contract and CD consumption path are defined in `docs/refe
## User-Service Artifact Publication ## User-Service Artifact Publication
User-service image creation uses the same CI producer boundary as backend-core. Service identities, source repositories, Dockerfiles and image repositories come from root `CI.json`; runtime topology still comes from `config.json`, `deploy.json` and existing manifests. The reviewed sample services are `baidu-netdisk`, `decision-center` and `frontend`, and the catalog now also covers the other source-build services listed above. User-service image creation uses the same CI producer boundary as backend-core. Service identities, source repositories, Dockerfiles and image repositories come from root `CI.json`; runtime topology still comes from `config.json`, `deploy.json` and existing manifests. The reviewed sample services include `baidu-netdisk`, `decision-center`, `frontend`, `mdtodo`, `claudeqq` and `code-queue`, and the catalog also covers the other source-build services listed above. `code-queue` artifacts are allowed for dev validation only; production Code Queue artifact deploy remains unsupported.
The CI user-service artifact task must follow these rules: The CI user-service artifact task must follow these rules:
@@ -122,6 +122,7 @@ The CI user-service artifact task must follow these rules:
- The command output must include the common `artifactSummary` fields: `serviceId`, `sourceCommit`, `sourceRepo`, `dockerfile`, `imageRef`, `tag`, `digest` and `digestRef`. The digest ref is suitable as immutable input for later dev/prod deployment work. - The command output must include the common `artifactSummary` fields: `serviceId`, `sourceCommit`, `sourceRepo`, `dockerfile`, `imageRef`, `tag`, `digest` and `digestRef`. The digest ref is suitable as immutable input for later dev/prod deployment work.
- CI is an artifact producer only. It must not restart production services, call production `deploy apply`, mutate the production namespace, or change `deploy.json`. - CI is an artifact producer only. It must not restart production services, call production `deploy apply`, mutate the production namespace, or change `deploy.json`.
- `CI.json` may also list downstream consumer-only catalog entries for D601 direct Compose services such as `findjob`, `pipeline`, `met-nonlinear`, and `k3sctl-adapter`; these entries describe the artifact contract and dry-run/support status, not new producer behavior. - `CI.json` may also list downstream consumer-only catalog entries for D601 direct Compose services such as `findjob`, `pipeline`, `met-nonlinear`, and `k3sctl-adapter`; these entries describe the artifact contract and dry-run/support status, not new producer behavior.
- ClaudeQQ source comes from `https://gitee.com/lyon1998/agent_skills`; the producer exports the `claudeqq/` subtree and overlays the UniDesk Dockerfile plus API adapter from `src/components/microservices/claudeqq/` before building. Runtime topology and deploy intent still live in manifests and `deploy.json`, not in `CI.json`.
Publish a Baidu Netdisk artifact: Publish a Baidu Netdisk artifact:
@@ -147,6 +148,16 @@ bun scripts/cli.ts ci publish-user-service --service frontend --commit <full-sha
This command creates the `unidesk-user-service-artifact-publish` Tekton PipelineRun and pushes `127.0.0.1:5000/unidesk/frontend:<commit>`. The next step is CD consumption, not a source rebuild: `deploy apply --env dev --service frontend` imports the artifact into D601 native k3s `frontend-dev`, and `deploy apply --env prod --service frontend` recreates the master-server Compose `frontend` service with `--no-build` and live `/health.deploy.commit` verification. This command creates the `unidesk-user-service-artifact-publish` Tekton PipelineRun and pushes `127.0.0.1:5000/unidesk/frontend:<commit>`. The next step is CD consumption, not a source rebuild: `deploy apply --env dev --service frontend` imports the artifact into D601 native k3s `frontend-dev`, and `deploy apply --env prod --service frontend` recreates the master-server Compose `frontend` service with `--no-build` and live `/health.deploy.commit` verification.
Publish k3s-managed service artifacts:
```bash
bun scripts/cli.ts ci publish-user-service --service mdtodo --commit <full-sha> --wait-ms 1200000
bun scripts/cli.ts ci publish-user-service --service claudeqq --commit <full-sha> --wait-ms 1200000
bun scripts/cli.ts ci publish-user-service --service code-queue --commit <full-sha> --wait-ms 1200000
```
MDTODO and ClaudeQQ artifacts are consumed first by dev CD and then by production CD through the D601 registry artifact consumer. Code Queue artifacts are consumed only by the dev artifact consumer; CI publication does not enable production Code Queue deployment.
## Dev Namespace E2E ## Dev Namespace E2E
`ci run-dev-e2e` is the manual dev desired-state smoke flow. The single authoritative reference for its Git-controlled runner script, short launcher, result directory and no-CD boundary is `docs/reference/dev-ci-runner.md`. `ci run-dev-e2e` is the manual dev desired-state smoke flow. The single authoritative reference for its Git-controlled runner script, short launcher, result directory and no-CD boundary is `docs/reference/dev-ci-runner.md`.
@@ -198,9 +209,12 @@ Publish a user-service artifact:
```bash ```bash
bun scripts/cli.ts ci publish-user-service --service baidu-netdisk --commit <full-sha> --wait-ms 1200000 bun scripts/cli.ts ci publish-user-service --service baidu-netdisk --commit <full-sha> --wait-ms 1200000
bun scripts/cli.ts ci publish-user-service --service decision-center --commit <full-sha> --wait-ms 1200000 bun scripts/cli.ts ci publish-user-service --service decision-center --commit <full-sha> --wait-ms 1200000
bun scripts/cli.ts ci publish-user-service --service mdtodo --commit <full-sha> --wait-ms 1200000
bun scripts/cli.ts ci publish-user-service --service claudeqq --commit <full-sha> --wait-ms 1200000
bun scripts/cli.ts ci publish-user-service --service code-queue --commit <full-sha> --wait-ms 1200000
``` ```
This command is a CI producer action only. For Baidu Netdisk and Decision Center, it builds and pushes `127.0.0.1:5000/unidesk/<service-id>:<commit>` and reports the immutable digest without deploying production. This command is a CI producer action only. For reviewed user services, it builds and pushes `127.0.0.1:5000/unidesk/<service-id>:<commit>` and reports the immutable digest without deploying production. For `code-queue`, the supported consumer is dev-only.
Run the dev namespace e2e harness manually: Run the dev namespace e2e harness manually:
+1 -1
View File
@@ -2,7 +2,7 @@
`bun scripts/cli.ts codex deploy <commitId>` 是旧兼容入口,现已禁用。原因是它会通过 backend-core `host.ssh` 维护通道直连 D601 部署 Code Queue,把维护入口扩张成第二套部署系统。 `bun scripts/cli.ts codex deploy <commitId>` 是旧兼容入口,现已禁用。原因是它会通过 backend-core `host.ssh` 维护通道直连 D601 部署 Code Queue,把维护入口扩张成第二套部署系统。
Code Queue 后续正式部署必须走一条受控 target-side CD 路径:读取 `origin/master:deploy.json#environments.dev` 或生产 desired-state,在目标节点执行 source fetch、build、k3s image import、rollout、stamp 和 live commit 验证。当前阶段不提供 Code Queue CDpersistent dev apply 支持 backend-core target-side rollout 和 frontend artifact consumer,规则`docs/reference/dev-environment.md`Code Queue smoke 仍通过 `ci run-dev-e2e`,规则见 `docs/reference/dev-ci-runner.md` Code Queue 后续正式生产部署必须走一条受控 CD 路径并单独审查;当前阶段只提供 dev artifact consumer。`deploy apply --env dev --service code-queue``artifact-registry deploy-service --env dev --service code-queue` 可以消费 D601 registry 中的 `unidesk/code-queue:<commit>`,只更新 `unidesk-dev` Code Queue execution slice,并通过 Kubernetes API service proxy 验证健康。`--env prod --service code-queue` 必须明确 unsupported,不能执行生产 artifact deploy、rollout 或 manifest 变更。persistent dev apply 的完整服务范围`docs/reference/dev-environment.md`Code Queue temporary smoke 仍通过 `ci run-dev-e2e`,规则见 `docs/reference/dev-ci-runner.md`
## Command ## Command
+12 -6
View File
@@ -40,9 +40,9 @@ The root `deploy.json` is the single desired-state source for both prod and dev.
The optional non-service execution declaration under `environments.dev` is intentionally not specified here. The only currently allowed declaration is `ci`, and its authoritative `repo`, `scriptPath`, `timeoutMs`, short launcher, host fetch boundary and no-CD rules are defined only in `docs/reference/dev-ci-runner.md`. The optional non-service execution declaration under `environments.dev` is intentionally not specified here. The only currently allowed declaration is `ci`, and its authoritative `repo`, `scriptPath`, `timeoutMs`, short launcher, host fetch boundary and no-CD rules are defined only in `docs/reference/dev-ci-runner.md`.
Environment mode never reads the local dirty working tree manifest. `deploy check --env ...`, `deploy plan --env ...` and `deploy apply --env ...` fetch `origin/master`, read `origin/master:deploy.json`, select `environments.<env>`, and report the manifest commit/blob, service commit IDs, target namespace, database fingerprint and Provider identity. `deploy apply --env dev` is currently enabled for persistent D601 dev `backend-core` target-side rollout and for reviewed artifact consumers `frontend`, `baidu-netdisk`, `decision-center`, `project-manager`, `oa-event-flow`, `code-queue-mgr`, `todo-note`, `findjob`, `pipeline` and `met-nonlinear`. `deploy apply --env prod` exposes reviewed registry artifact consumers (`backend-core`, `frontend`, `baidu-netdisk`, `decision-center`, `project-manager`, `oa-event-flow`, `todo-note`, `findjob`, `pipeline` and `met-nonlinear`), while `code-queue-mgr` remains supervisor-gated and `k3sctl-adapter` is plan/dry-run only. Production backend-core artifact CD is a separate executor because its build target is D601 CI while its runtime target is the master server. The default user-service delivery policy, including CI build, registry publication, dev validation, production CD and manual acceptance, is documented in `docs/reference/user-service-delivery.md`. Environment mode never reads the local dirty working tree manifest. `deploy check --env ...`, `deploy plan --env ...` and `deploy apply --env ...` fetch `origin/master`, read `origin/master:deploy.json`, select `environments.<env>`, and report the manifest commit/blob, service commit IDs, target namespace, database fingerprint and Provider identity. `deploy apply --env dev` is currently enabled for persistent D601 dev `backend-core` target-side rollout and for reviewed artifact consumers `frontend`, `baidu-netdisk`, `decision-center`, `mdtodo`, `claudeqq`, dev-only `code-queue`, `project-manager`, `oa-event-flow`, `code-queue-mgr`, `todo-note`, `findjob`, `pipeline` and `met-nonlinear`. `deploy apply --env prod` exposes reviewed registry artifact consumers (`backend-core`, `frontend`, `baidu-netdisk`, `decision-center`, `mdtodo`, `claudeqq`, `project-manager`, `oa-event-flow`, `todo-note`, `findjob`, `pipeline` and `met-nonlinear`), while `code-queue` must report unsupported, `code-queue-mgr` remains supervisor-gated and `k3sctl-adapter` is plan/dry-run only. Production backend-core artifact CD is a separate executor because its build target is D601 CI while its runtime target is the master server. The default user-service delivery policy, including CI build, registry publication, dev validation, production CD and manual acceptance, is documented in `docs/reference/user-service-delivery.md`.
For services with reviewed production artifact consumers, local-manifest `deploy apply --file ...` is not a production fallback. The CLI blocks `backend-core`, `frontend`, `baidu-netdisk` and `decision-center` before source materialization or Docker build and directs operators to `deploy apply --env prod --service <id> --commit <full-sha>`. This prevents a dirty worktree, local manifest or target-side source build from bypassing the pull-only artifact CD guardrails. The broader precheck and legacy-path classification live in `docs/reference/cicd-standardization.md`. For services with reviewed production artifact consumers, local-manifest `deploy apply --file ...` is not a production fallback. The CLI blocks `backend-core`, `frontend`, `baidu-netdisk`, `decision-center`, `mdtodo`, `claudeqq` and other reviewed pull-only consumers before source materialization or Docker build and directs operators to `deploy apply --env prod --service <id> --commit <full-sha>`. This prevents a dirty worktree, local manifest or target-side source build from bypassing the pull-only artifact CD guardrails. The broader precheck and legacy-path classification live in `docs/reference/cicd-standardization.md`.
The current implementation has not yet enabled separate stable and integration dev lanes. Future lane names such as `dev-v1` and `dev-master`, or an equivalent nested schema, must be added as explicit `deploy.json` and CLI semantics before use. A deploy command must print the manifest ref it used and must not infer `release/v1` from a local branch, a dirty file, or an undocumented environment alias. The current implementation has not yet enabled separate stable and integration dev lanes. Future lane names such as `dev-v1` and `dev-master`, or an equivalent nested schema, must be added as explicit `deploy.json` and CLI semantics before use. A deploy command must print the manifest ref it used and must not infer `release/v1` from a local branch, a dirty file, or an undocumented environment alias.
@@ -85,7 +85,7 @@ Phase 3 introduces the dev backend/frontend manifest at `src/components/microser
`backend-core-dev` must use `unidesk-dev-runtime-config` and `unidesk-dev-runtime-secrets`, connect to `postgres-dev.../unidesk_dev`, expose HTTP on 8080 and provider ingress on 8081, and write logs under `/var/log/unidesk-dev`. `frontend-dev` must set `CORE_INTERNAL_URL=http://backend-core-dev.unidesk-dev.svc.cluster.local:8080` and must not proxy to production backend-core. `backend-core-dev` must use `unidesk-dev-runtime-config` and `unidesk-dev-runtime-secrets`, connect to `postgres-dev.../unidesk_dev`, expose HTTP on 8080 and provider ingress on 8081, and write logs under `/var/log/unidesk-dev`. `frontend-dev` must set `CORE_INTERNAL_URL=http://backend-core-dev.unidesk-dev.svc.cluster.local:8080` and must not proxy to production backend-core.
The manifest keeps placeholder image tags and deploy commit values in source control. The controlled `deploy apply --env dev --service backend-core` path fetches `origin/master:deploy.json`, materializes the requested source commit on D601, narrows the dev core control manifest to the selected Service/Deployment pair, replaces placeholders with the requested commit and dev image tag, builds on D601, imports the image into native k3s containerd, applies only the `unidesk-dev` objects and stamps the Deployment. `deploy apply --env dev --service frontend`, `decision-center`, `project-manager`, `oa-event-flow`, `code-queue-mgr`, `todo-note`, `findjob`, `pipeline` and `met-nonlinear` consume the existing D601 registry artifact instead of building source on the target. The direct Docker/Compose services currently use D601 registry pull + label/config dry-run + health contract as dev validation; they are not separate parallel dev instances yet. `code-queue-mgr` live prod apply remains supervisor-gated. Client dry-run and static validation remain useful checks before controlled apply: The manifest keeps placeholder image tags and deploy commit values in source control. The controlled `deploy apply --env dev --service backend-core` path fetches `origin/master:deploy.json`, materializes the requested source commit on D601, narrows the dev core control manifest to the selected Service/Deployment pair, replaces placeholders with the requested commit and dev image tag, builds on D601, imports the image into native k3s containerd, applies only the `unidesk-dev` objects and stamps the Deployment. `deploy apply --env dev --service frontend` uses the same selected dev manifest objects but consumes the existing D601 registry artifact `127.0.0.1:5000/unidesk/frontend:<commit>` instead of building frontend source on the target. Decision Center, MDTODO and ClaudeQQ use the same dev namespace but follow the D601 registry artifact consumer path instead of a source build: each verifies the commit-pinned image in D601 registry, imports it into native k3s containerd, applies its dev manifest, stamps the Deployment and verifies live commit/requestedCommit through the Kubernetes API service proxy. `project-manager`, `oa-event-flow`, `code-queue-mgr`, `todo-note`, `findjob`, `pipeline` and `met-nonlinear` consume existing D601 registry artifacts for direct Docker/Compose validation rather than separate parallel k3s dev instances; `code-queue-mgr` live prod apply remains supervisor-gated. Client dry-run and static validation remain useful checks before controlled apply:
- `bun scripts/cli.ts dev-env validate --manifest src/components/microservices/k3sctl-adapter/k3s/dev/unidesk-dev-core.k8s.yaml` - `bun scripts/cli.ts dev-env validate --manifest src/components/microservices/k3sctl-adapter/k3s/dev/unidesk-dev-core.k8s.yaml`
- `KUBECONFIG=/etc/rancher/k3s/k3s.yaml kubectl apply --dry-run=client --validate=false -f src/components/microservices/k3sctl-adapter/k3s/dev/unidesk-dev-core.k8s.yaml` - `KUBECONFIG=/etc/rancher/k3s/k3s.yaml kubectl apply --dry-run=client --validate=false -f src/components/microservices/k3sctl-adapter/k3s/dev/unidesk-dev-core.k8s.yaml`
@@ -98,7 +98,7 @@ Phase 5 introduces the dev Code Queue execution manifest at `src/components/micr
All dev Code Queue components must use `unidesk-dev-runtime-config` and `unidesk-dev-runtime-secrets`, connect to `postgres-dev.../unidesk_dev`, write logs and state under `/home/ubuntu/unidesk-dev-code-queue-deploy/state`, and expose HTTP on 4222 only as ClusterIP services. The scheduler uses `CODE_QUEUE_MAIN_PROVIDER_ID=D601-dev`, `CODE_QUEUE_WORKDIR=/workspace-dev`, `CODE_QUEUE_REMOTE_WORKDIR=/home/ubuntu/unidesk-dev-workspace`, disables ClaudeQQ notifications by default, and does not use the production `d601-tcp-egress-gateway` or production PostgreSQL route. All dev Code Queue components must use `unidesk-dev-runtime-config` and `unidesk-dev-runtime-secrets`, connect to `postgres-dev.../unidesk_dev`, write logs and state under `/home/ubuntu/unidesk-dev-code-queue-deploy/state`, and expose HTTP on 4222 only as ClusterIP services. The scheduler uses `CODE_QUEUE_MAIN_PROVIDER_ID=D601-dev`, `CODE_QUEUE_WORKDIR=/workspace-dev`, `CODE_QUEUE_REMOTE_WORKDIR=/home/ubuntu/unidesk-dev-workspace`, disables ClaudeQQ notifications by default, and does not use the production `d601-tcp-egress-gateway` or production PostgreSQL route.
Maintenance-channel direct D601 apply must not deploy dev Code Queue; the CLI rejects `deploy apply --env dev --service code-queue` and the old `codex deploy` compatibility entry is disabled. Dev Code Queue deployment must be implemented later as a controlled D601 target-side action that fetches `origin/master:deploy.json`, selects `environments.dev`, materializes the requested source commit on D601, uses the dev Code Queue control manifest from that D601 materialized commit, narrows it to Code Queue dev objects, replaces placeholders with the requested commit and `unidesk-code-queue:dev`, builds on D601, imports the image into native k3s containerd, applies only `unidesk-dev` objects and stamps the dev Deployments. Because Code Queue carries the agent toolchain and browser/runtime dependencies, dev builds may reuse an existing D601 `unidesk-code-queue:d601-build-base` or `unidesk-code-queue:d601` image when the dev build-base tag is absent, and the deploy executor allows a longer Code Queue build window than lightweight services. The scheduler has an explicit 5Gi memory limit and must use `Recreate` rollout strategy so an update does not temporarily require two scheduler replicas under the namespace quota. All dev Code Queue containers must set CPU limits so the namespace `LimitRange` does not inject a quota-breaking default CPU limit. Live health verification uses the Kubernetes API service proxy for the dev ClusterIP Service, not `kubectl exec` or debug binaries inside the application image. This first dev execution slice proves deployability, health and dev database isolation; wiring the dev frontend stable `code-queue` route through a dev `code-queue-mgr` is a separate later phase. Maintenance-channel direct D601 apply must not deploy dev Code Queue and the old `codex deploy` compatibility entry remains disabled. Dev Code Queue deployment is allowed only as the D601 registry artifact consumer for `deploy apply --env dev --service code-queue` or the equivalent `artifact-registry deploy-service --env dev --service code-queue`: it verifies the existing `127.0.0.1:5000/unidesk/code-queue:<commit>` artifact, imports it into native k3s containerd, applies only the `unidesk-dev` Code Queue manifest, stamps `code-queue-scheduler-dev`, `code-queue-read-dev`, `code-queue-write-dev` and `d601-dev-provider-egress-proxy`, and verifies the scheduler Service through the Kubernetes API service proxy. `deploy apply --env prod --service code-queue` and `artifact-registry deploy-service --env prod --service code-queue` must return explicit unsupported output and must not mutate production Code Queue manifests, Deployments or rollouts. The scheduler has an explicit 5Gi memory limit and must use `Recreate` rollout strategy so an update does not temporarily require two scheduler replicas under the namespace quota. All dev Code Queue containers must set CPU limits so the namespace `LimitRange` does not inject a quota-breaking default CPU limit. Live health verification uses the Kubernetes API service proxy for the dev ClusterIP Service, not `kubectl exec` or debug binaries inside the application image. This dev execution slice proves artifact deployability, health and dev database isolation; wiring the dev frontend stable `code-queue` route through a dev `code-queue-mgr` is a separate later phase.
## CLI ## CLI
@@ -108,7 +108,7 @@ Maintenance-channel direct D601 apply must not deploy dev Code Queue; the CLI re
`bun scripts/cli.ts deploy plan --env dev [--service <id>]` reads `origin/master:deploy.json#environments.dev` and prints a dry-run environment plan without checking or mutating live runtime resources. `deploy check --env dev` uses the same dry-run environment plan. `--env prod` is available for parity as a dry-run planning path; it reads `origin/master:deploy.json#environments.prod` and must not use a dirty local `deploy.json`. `bun scripts/cli.ts deploy plan --env dev [--service <id>]` reads `origin/master:deploy.json#environments.dev` and prints a dry-run environment plan without checking or mutating live runtime resources. `deploy check --env dev` uses the same dry-run environment plan. `--env prod` is available for parity as a dry-run planning path; it reads `origin/master:deploy.json#environments.prod` and must not use a dirty local `deploy.json`.
`bun scripts/cli.ts deploy apply [--file deploy.json | --env dev|prod] [--service <id>] [--commit <full-sha>] [--dry-run] [--force]` starts an asynchronous job only for supported targets. Use `bun scripts/cli.ts job status <jobId> --tail-bytes 30000` to observe progress. `--dry-run` resolves the same plan but does not build or replace runtime objects. `--force` rebuilds even when the live commit matches. Environment apply is not the dev e2e trigger; use `bun scripts/cli.ts ci run-dev-e2e` for the Git-controlled temporary namespace smoke flow. `--env dev` apply is enabled for persistent D601 `backend-core` target-side rollout and for `frontend`/`baidu-netdisk`/`decision-center`/`project-manager`/`oa-event-flow`/`code-queue-mgr`/`todo-note`/`findjob`/`pipeline`/`met-nonlinear` artifact consumers. `--env prod` apply exposes the D601 registry artifact consumer for `backend-core`, `frontend`, `baidu-netdisk`, `decision-center`, `project-manager`, `oa-event-flow`, `todo-note`, `findjob`, `pipeline` and `met-nonlinear`; `code-queue-mgr` prod live apply is supervisor-gated and `k3sctl-adapter` is plan/dry-run only. Unsupported prod services return a structured `unsupported` payload instead of silently falling back to a maintenance-channel source build. `bun scripts/cli.ts deploy apply [--file deploy.json | --env dev|prod] [--service <id>] [--commit <full-sha>] [--dry-run] [--force]` starts an asynchronous job only for supported targets. Use `bun scripts/cli.ts job status <jobId> --tail-bytes 30000` to observe progress. `--dry-run` resolves the same plan but does not build or replace runtime objects. `--force` rebuilds even when the live commit matches. Environment apply is not the dev e2e trigger; use `bun scripts/cli.ts ci run-dev-e2e` for the Git-controlled temporary namespace smoke flow. `--env dev` apply is enabled for persistent D601 `backend-core` target-side rollout and for `frontend`/`baidu-netdisk`/`decision-center`/`mdtodo`/`claudeqq`/dev-only `code-queue`/`project-manager`/`oa-event-flow`/`code-queue-mgr`/`todo-note`/`findjob`/`pipeline`/`met-nonlinear` artifact consumers. `--env prod` apply exposes the D601 registry artifact consumer for `backend-core`, `frontend`, `baidu-netdisk`, `decision-center`, `mdtodo`, `claudeqq`, `project-manager`, `oa-event-flow`, `todo-note`, `findjob`, `pipeline` and `met-nonlinear`; `code-queue-mgr` prod live apply is supervisor-gated and `k3sctl-adapter` is plan/dry-run only. Unsupported prod services, especially `code-queue`, return a structured `unsupported` payload instead of silently falling back to a maintenance-channel source build.
All deploy commands output JSON. Long operations must use `.state/jobs/` and bounded log tails; no deploy path may succeed with missing progress output. All deploy commands output JSON. Long operations must use `.state/jobs/` and bounded log tails; no deploy path may succeed with missing progress output.
@@ -141,6 +141,8 @@ The exception is narrow:
- `findjob` and `pipeline` are D601 direct Docker/Compose artifact consumers: CD runs on D601 through the existing provider-gateway/SSH maintenance bridge, verifies `127.0.0.1:5000/unidesk/<service>:<commit>` labels, writes deploy env/labels, and recreates only the target Compose service with `--no-build --no-deps --force-recreate`. - `findjob` and `pipeline` are D601 direct Docker/Compose artifact consumers: CD runs on D601 through the existing provider-gateway/SSH maintenance bridge, verifies `127.0.0.1:5000/unidesk/<service>:<commit>` labels, writes deploy env/labels, and recreates only the target Compose service with `--no-build --no-deps --force-recreate`.
- `met-nonlinear` has a D601 direct dry-run/plan contract, but live artifact deploy is blocked until the long-running `met-nonlinear-ts` image contract is separated from the ML image Dockerfile contract or otherwise proves the running container image label matches the requested commit. - `met-nonlinear` has a D601 direct dry-run/plan contract, but live artifact deploy is blocked until the long-running `met-nonlinear-ts` image contract is separated from the ML image Dockerfile contract or otherwise proves the running container image label matches the requested commit.
- `k3sctl-adapter` exposes only artifact consumer plan/dry-run here because it is an infrastructure control bridge; real prod deployment requires supervisor confirmation outside the standard user-service CD path. - `k3sctl-adapter` exposes only artifact consumer plan/dry-run here because it is an infrastructure control bridge; real prod deployment requires supervisor confirmation outside the standard user-service CD path.
- `mdtodo` and `claudeqq` are k3s-managed artifact consumers: CI publishes `127.0.0.1:5000/unidesk/<service-id>:<commit>`, dev CD lands in `unidesk-dev`, prod CD lands in `unidesk`, and both paths verify Deployment metadata plus health through the Kubernetes API service proxy.
- `code-queue` is a dev-only artifact consumer: CI may publish `127.0.0.1:5000/unidesk/code-queue:<commit>`, and dev CD may update only `unidesk-dev` Code Queue execution objects. Production artifact deploy, production rollout and production manifest mutation for `code-queue` are unsupported.
- This exception must not be generalized to other services unless their resource profile and runtime boundary are documented with the same CI-producer/CD-consumer split. - This exception must not be generalized to other services unless their resource profile and runtime boundary are documented with the same CI-producer/CD-consumer split.
The registry contract is defined in `docs/reference/artifact-registry.md`; the CI producer rules are defined in `docs/reference/ci.md`. The registry contract is defined in `docs/reference/artifact-registry.md`; the CI producer rules are defined in `docs/reference/ci.md`.
@@ -181,7 +183,7 @@ The reconciler selects the executor from `config.json`:
- `deployment.mode=internal-sidecar` on `main-server`: use the same main-server target-side source export, Docker build, image label stamping, fixed Compose project replacement and live commit verification as direct Compose services. This class is for private sidecars such as `code-queue-mgr`; it is still versioned by `deploy.json.commitId`, not by the operator's current worktree, and prod live apply remains supervisor-gated. - `deployment.mode=internal-sidecar` on `main-server`: use the same main-server target-side source export, Docker build, image label stamping, fixed Compose project replacement and live commit verification as direct Compose services. This class is for private sidecars such as `code-queue-mgr`; it is still versioned by `deploy.json.commitId`, not by the operator's current worktree, and prod live apply remains supervisor-gated.
- `deployment.mode=unidesk-direct` on a provider: this executor is disabled for D601 service deployment. The historical behavior dispatched `host.ssh` to the provider, built on the provider, then used the service's provider-local compose file and project; that shape must not remain a second deployment control plane. - `deployment.mode=unidesk-direct` on a provider: this executor is disabled for D601 service deployment. The historical behavior dispatched `host.ssh` to the provider, built on the provider, then used the service's provider-local compose file and project; that shape must not remain a second deployment control plane.
- Control bridges that UniDesk needs in order to inspect or repair an orchestrator must stay in this direct class. In particular, `k3sctl-adapter` is a UniDesk-managed bridge to native k3s and must remain outside k3s; Docker packaging on Docker Desktop/WSL must create an explicit host-local bridge, currently an adapter-container SSH local tunnel, to reach `/etc/rancher/k3s/k3s.yaml` and WSL `127.0.0.1:6443`. - Control bridges that UniDesk needs in order to inspect or repair an orchestrator must stay in this direct class. In particular, `k3sctl-adapter` is a UniDesk-managed bridge to native k3s and must remain outside k3s; Docker packaging on Docker Desktop/WSL must create an explicit host-local bridge, currently an adapter-container SSH local tunnel, to reach `/etc/rancher/k3s/k3s.yaml` and WSL `127.0.0.1:6443`.
- `deployment.mode=k3sctl-managed`: the target behavior is to build on the active control target unless the service has a reviewed artifact-consumer exception, verify native k3s on the host OS/WSL distro, import the image into native k3s/containerd, apply the existing Kubernetes manifest, stamp the Deployment and wait for rollout. On D601, persistent dev apply is currently allowed for `backend-core` target-side build plus `frontend` and `decision-center` artifact consumption in `unidesk-dev`; normal production services still cannot use a maintenance-channel direct rollout. The executor must use the native kubeconfig and containerd socket, for example `/etc/rancher/k3s/k3s.yaml` and `/run/k3s/containerd/containerd.sock`; running k3s itself in Docker is forbidden for both control-plane and worker nodes. A `rancher/k3s` image or legacy container may only be used as a temporary artifact source during migration, and any active containerized k3s control plane must be stopped before verification succeeds. The executor must preload a valid `rancher/mirrored-pause:3.6` sandbox image into native k3s containerd through the provider-gateway one-shot egress path, verify its entrypoint is `/pause`, and reject fake or sleep-based replacement images. Code Queue's k3s migration executor must also stop/remove the legacy direct Docker `code-queue-backend` after k3s rollout, so there is never a second scheduler running beside the native k3s scheduler. - `deployment.mode=k3sctl-managed`: the target behavior is to build on the active control target unless the service has a reviewed artifact-consumer exception, verify native k3s on the host OS/WSL distro, import the image into native k3s/containerd, apply the existing Kubernetes manifest, stamp the Deployment and wait for rollout. On D601, persistent dev apply is currently allowed for `backend-core` target-side build plus `frontend`, `decision-center`, `mdtodo`, `claudeqq` and dev-only `code-queue` artifact consumption in `unidesk-dev`; production artifact consumers are limited to reviewed services and exclude Code Queue. Normal production services still cannot use a maintenance-channel direct rollout. The executor must use the native kubeconfig and containerd socket, for example `/etc/rancher/k3s/k3s.yaml` and `/run/k3s/containerd/containerd.sock`; running k3s itself in Docker is forbidden for both control-plane and worker nodes. A `rancher/k3s` image or legacy container may only be used as a temporary artifact source during migration, and any active containerized k3s control plane must be stopped before verification succeeds. The executor must preload a valid `rancher/mirrored-pause:3.6` sandbox image into native k3s containerd through the provider-gateway one-shot egress path, verify its entrypoint is `/pause`, and reject fake or sleep-based replacement images. k3s-managed deploys must use ClusterIP Services and Kubernetes API service proxy health checks; they must not add NodePort, hostPort, public business ports or provider-gateway direct business backends.
D601 Docker local images are not the source of truth for k3s runtime availability. For Code Queue, the deploy gate must verify `unidesk-code-queue:d601` exists in native k3s containerd after import with `ctr --address /run/k3s/containerd/containerd.sock -n k8s.io images ls`, and it must fail before rollout if the tag is missing. The same gate must verify every production Code Queue Deployment that uses the image (`code-queue`, `code-queue-read`, `code-queue-write`, `d601-provider-egress-proxy`, `d601-tcp-egress-gateway`) still references exactly `unidesk-code-queue:d601`; otherwise kubelet may attempt an external registry pull and leave base gateways in `ImagePullBackOff`. D601 Docker local images are not the source of truth for k3s runtime availability. For Code Queue, the deploy gate must verify `unidesk-code-queue:d601` exists in native k3s containerd after import with `ctr --address /run/k3s/containerd/containerd.sock -n k8s.io images ls`, and it must fail before rollout if the tag is missing. The same gate must verify every production Code Queue Deployment that uses the image (`code-queue`, `code-queue-read`, `code-queue-write`, `d601-provider-egress-proxy`, `d601-tcp-egress-gateway`) still references exactly `unidesk-code-queue:d601`; otherwise kubelet may attempt an external registry pull and leave base gateways in `ImagePullBackOff`.
@@ -193,6 +195,10 @@ Baidu Netdisk is the main-server `unidesk-direct` sample for artifact CD. Contro
Decision Center is a standard `k3sctl-managed` service in this model, but D601 maintenance-channel direct apply must not deploy it. Controlled CD for Decision Center uses the D601 registry artifact consumer in both dev and prod: it verifies `unidesk/decision-center:<commit>` exists in the registry, imports `unidesk-decision-center:<commit>` into native k3s containerd, applies the appropriate Decision Center manifest, stamps the Deployment, and verifies health through `/api/microservices/decision-center/health` while proving the live and requested commit match. It must not add a main-server Compose service, NodePort, hostPort, or provider-gateway direct HTTP backend for Decision Center. Decision Center is a standard `k3sctl-managed` service in this model, but D601 maintenance-channel direct apply must not deploy it. Controlled CD for Decision Center uses the D601 registry artifact consumer in both dev and prod: it verifies `unidesk/decision-center:<commit>` exists in the registry, imports `unidesk-decision-center:<commit>` into native k3s containerd, applies the appropriate Decision Center manifest, stamps the Deployment, and verifies health through `/api/microservices/decision-center/health` while proving the live and requested commit match. It must not add a main-server Compose service, NodePort, hostPort, or provider-gateway direct HTTP backend for Decision Center.
MDTODO and ClaudeQQ are standard `k3sctl-managed` artifact consumers in the same model. Dev rollout lands in `unidesk-dev` using their dev manifests; production rollout lands in `unidesk` using the production manifests. Both services must pass dev validation before production rollout, must expose deploy metadata in health when practical, and must verify through the Kubernetes API service proxy instead of NodePort, hostPort or provider-gateway direct HTTP.
Code Queue is explicitly narrower. Only `--env dev --service code-queue` is a supported artifact consumer target, and it may mutate only `unidesk-dev` Code Queue execution objects. Production Code Queue artifact deploy, production rollout and production manifest mutation are unsupported and must fail visibly.
## CI Separation ## CI Separation
Continuous integration is intentionally separate from this deploy reconciler. D601 k3s hosts Tekton CI resources described in `docs/reference/ci.md`; PipelineRuns may clone, check, run read-only performance gates, create temporary CI-owned namespaces for dev manifest smoke e2e, or publish commit-pinned backend-core/user-service image artifacts to the D601 artifact registry. They must not call `deploy apply`, `codex deploy`, `kubectl rollout restart` for production services, mutate `deploy.json`, or write production namespaces. Continuous integration is intentionally separate from this deploy reconciler. D601 k3s hosts Tekton CI resources described in `docs/reference/ci.md`; PipelineRuns may clone, check, run read-only performance gates, create temporary CI-owned namespaces for dev manifest smoke e2e, or publish commit-pinned backend-core/user-service image artifacts to the D601 artifact registry. They must not call `deploy apply`, `codex deploy`, `kubectl rollout restart` for production services, mutate `deploy.json`, or write production namespaces.
+2 -2
View File
@@ -30,7 +30,7 @@ CLI 会优先使用 `docker compose` v2 plugin;当 v2 plugin 不存在时才
Compose v2 安装后仍然必须遵守 UniDesk 的服务控制入口:全栈生命周期用 `server start` / `server stop`,单服务重建用 `server rebuild <service>`。不要因为 v2 可用就直接在生产栈上手工执行未纳入 CLI 的 `up --build``down -v` 或跨项目清理命令;所有会影响容器的动作都应保持 job 可观测、Compose project 固定、database named volume 保留。主 server Compose 命令必须从 `providerGateway.upgrade.hostProjectRoot` 指定的 canonical UniDesk 根目录运行,临时 worktree、Code Queue 导出目录或实验分支不得复用生产 `-p unidesk` 和固定 `container_name` 去替换生产容器。 Compose v2 安装后仍然必须遵守 UniDesk 的服务控制入口:全栈生命周期用 `server start` / `server stop`,单服务重建用 `server rebuild <service>`。不要因为 v2 可用就直接在生产栈上手工执行未纳入 CLI 的 `up --build``down -v` 或跨项目清理命令;所有会影响容器的动作都应保持 job 可观测、Compose project 固定、database named volume 保留。主 server Compose 命令必须从 `providerGateway.upgrade.hostProjectRoot` 指定的 canonical UniDesk 根目录运行,临时 worktree、Code Queue 导出目录或实验分支不得复用生产 `-p unidesk` 和固定 `container_name` 去替换生产容器。
版本化用户服务部署优先使用 `bun scripts/cli.ts deploy apply` 已支持的受控路径;D601 persistent dev apply 当前支持 `backend-core` target-side rollout,以及 `frontend``baidu-netdisk``decision-center``project-manager``oa-event-flow``code-queue-mgr``todo-note``findjob``pipeline``met-nonlinear` 的 artifact consumer validation。`deploy.json` 只声明服务 `id``repo``commitId`;目标节点、Dockerfile、Compose、Kubernetes manifest、健康检查和代理路径继续来自 `config.json` 与现有 manifest。主 server 直管微服务和内部 sidecar,例如 `code-queue-mgr`,也必须支持这一路径:`deploy apply --service code-queue-mgr``deploy.json` 指定 commit 导出源码、构建镜像、替换固定 Compose service 并验证运行中镜像/健康信息的 commit,但 prod live apply 仍需 supervisor 确认。部署默认遵循 target-side build:服务部署到哪台 target,就在哪台 target 从 remote commit 导出源码、一次性代理构建镜像并部署;不得把中心构建镜像作为默认分发路径,也不得用 `docker commit` 或脏 worktree 作为部署输入。production backend-core 是明确例外;`frontend` 是用户服务 UI / 前端镜像化样板,`baidu-netdisk` 是主 server 直管微服务的镜像化样板,`findjob``pipeline` 是 D601 direct Docker/Compose pull-only 样板:D601 CI 构建并推送 commit-pinned 镜像到 D601 artifact registryCD 只拉取、retag 或导入、recreate/rollout 和验证,不在 master server 或 runtime target 执行 Compose build。`met-nonlinear` 当前只允许 dry-run/plan`k3sctl-adapter` 只允许 plan/dry-run 且真实 prod 部署需要 supervisor 确认。完整规则见 `docs/reference/deploy.md`D601 dev/Rust 边界见 `docs/reference/dev-environment.md`artifact registry 见 `docs/reference/artifact-registry.md` 版本化用户服务部署优先使用 `bun scripts/cli.ts deploy apply` 已支持的受控路径;D601 persistent dev apply 当前支持 `backend-core` target-side rollout`frontend`/`baidu-netdisk`/`decision-center`/`mdtodo`/`claudeqq` artifact consumer、dev-only `code-queue` artifact consumer,以及 `project-manager``oa-event-flow``code-queue-mgr``todo-note``findjob``pipeline``met-nonlinear` 的 artifact consumer validationdev desired-state smoke 使用 `ci run-dev-e2e``deploy.json` 只声明服务 `id``repo``commitId`;目标节点、Dockerfile、Compose、Kubernetes manifest、健康检查和代理路径继续来自 `config.json` 与现有 manifest。主 server 直管微服务和内部 sidecar,例如 `code-queue-mgr`,也必须支持这一路径:`deploy apply --service code-queue-mgr``deploy.json` 指定 commit 导出源码、构建镜像、替换固定 Compose service 并验证运行中镜像/健康信息的 commit,但 prod live apply 仍需 supervisor 确认。部署默认遵循 target-side build:服务部署到哪台 target,就在哪台 target 从 remote commit 导出源码、一次性代理构建镜像并部署;不得把中心构建镜像作为默认分发路径,也不得用 `docker commit` 或脏 worktree 作为部署输入。production backend-core 是明确例外;`frontend` 是用户服务 UI / 前端镜像化样板,`baidu-netdisk` 是主 server 直管微服务的镜像化样板,`decision-center``mdtodo``claudeqq` 是 k3s-managed artifact consumer 样板,`findjob``pipeline` 是 D601 direct Docker/Compose pull-only 样板:D601 CI 构建并推送 commit-pinned 镜像到 D601 artifact registryCD 只拉取、retag 或导入、recreate/rollout 和验证,不在 master server 或 runtime target 执行 Compose build。`met-nonlinear` 当前只允许 dry-run/plan`k3sctl-adapter` 只允许 plan/dry-run 且真实 prod 部署需要 supervisor 确认。`code-queue` 只允许 dev artifact consumerprod artifact deploy/rollout/manifest mutation 必须 unsupported。完整规则见 `docs/reference/deploy.md`D601 dev/Rust 边界见 `docs/reference/dev-environment.md`artifact registry 见 `docs/reference/artifact-registry.md`
## Main Server Swap ## Main Server Swap
@@ -46,7 +46,7 @@ swap 管理不能被强塞进所有热路径。`server start/status` 可以暴
## Single Service Rebuild ## Single Service Rebuild
前端、本机 provider-gateway、dev-frontend-proxy 或主 server 承载的 Todo Note/Code Queue Manager/Project Manager/Baidu Netdisk/OA Event Flow 用户服务需要非版本化本地重建时,统一使用 `bun scripts/cli.ts server rebuild <service>`,其中 `<service>` 只能是 `backend-core``frontend``dev-frontend-proxy``provider-gateway``todo-note``code-queue-mgr``project-manager``baidu-netdisk``oa-event-flow`。需要按 commit 上线或恢复到 desired-state 时必须改用 `bun scripts/cli.ts deploy apply --service <id>`、backend-core artifact CD、`deploy apply --env dev|prod --service frontend` artifact consumer `deploy apply --env dev|prod --service baidu-netdisk` artifact consumer;直管微服务也不能把脏工作树或手工重建作为部署真相。`server rebuild frontend``server rebuild baidu-netdisk``server rebuild project-manager``server rebuild oa-event-flow``server rebuild todo-note``server rebuild code-queue-mgr` 都只作为维护/非标准路径保留,不得作为标准发布完成证据。Rust backend-core 迭代不得在 master server 用 `server rebuild backend-core` 编译,生产 backend-core 也不得用该命令完成 Rust 构建,必须走 D601 dev deploy/CI 或 D601 artifact registry CD。D601 Code Queue 执行面、File Browser、FindJob、Pipeline、MET Nonlinear 和 ClaudeQQ 部署在计算节点,不属于主 server Compose 可重建服务;其中 D601 Code Queue 执行面不得再通过 `codex deploy` 或维护通道直连 D601 部署;未来正式 CD 必须经受控 target-side 路径执行 build-first、rollout 和 live commit 验证 前端、本机 provider-gateway、dev-frontend-proxy 或主 server 承载的 Todo Note/Code Queue Manager/Project Manager/Baidu Netdisk/OA Event Flow 用户服务需要非版本化本地重建时,统一使用 `bun scripts/cli.ts server rebuild <service>`,其中 `<service>` 只能是 `backend-core``frontend``dev-frontend-proxy``provider-gateway``todo-note``code-queue-mgr``project-manager``baidu-netdisk``oa-event-flow`。需要按 commit 上线或恢复到 desired-state 时必须改用 `bun scripts/cli.ts deploy apply --service <id>`、backend-core artifact CD、`deploy apply --env dev|prod --service frontend|baidu-netdisk|decision-center|mdtodo|claudeqq` artifact consumer dev-only `deploy apply --env dev --service code-queue` artifact consumer;直管微服务也不能把脏工作树或手工重建作为部署真相。`server rebuild frontend``server rebuild baidu-netdisk``server rebuild project-manager``server rebuild oa-event-flow``server rebuild todo-note``server rebuild code-queue-mgr` 都只作为维护/非标准路径保留,不得作为标准发布完成证据。Rust backend-core 迭代不得在 master server 用 `server rebuild backend-core` 编译,生产 backend-core 也不得用该命令完成 Rust 构建,必须走 D601 dev deploy/CI 或 D601 artifact registry CD。D601 Code Queue 执行面、File Browser、FindJob、Pipeline、MET Nonlinear 和 ClaudeQQ 部署在计算节点,不属于主 server Compose 可重建服务;其中 D601 Code Queue 执行面不得再通过 `codex deploy` 或维护通道直连 D601 部署,且本阶段 prod artifact deploy/rollout/manifest mutation 仍 unsupported
frontend 改动必须明确上线到公网:修改 `src/components/frontend/src/``src/components/frontend/public/style.css`、frontend 使用的共享 TSX/TS 模块或 WebUI 导航后,标准发布顺序是先把 pushed commit 交给 `bun scripts/cli.ts ci publish-user-service --service frontend --commit <full-sha>`,再用 `bun scripts/cli.ts deploy apply --env dev --service frontend``bun scripts/cli.ts deploy apply --env prod --service frontend` 消费同一个 commit-pinned artifact。公网 WebUI 的 `/app.js``unidesk-frontend` 镜像内运行时 bundle;只改工作区文件、只跑 `bun run check`、只跑 `Bun.build`、只刷新浏览器或只 `server rebuild frontend` 都不能作为标准版本发布证据。 frontend 改动必须明确上线到公网:修改 `src/components/frontend/src/``src/components/frontend/public/style.css`、frontend 使用的共享 TSX/TS 模块或 WebUI 导航后,标准发布顺序是先把 pushed commit 交给 `bun scripts/cli.ts ci publish-user-service --service frontend --commit <full-sha>`,再用 `bun scripts/cli.ts deploy apply --env dev --service frontend``bun scripts/cli.ts deploy apply --env prod --service frontend` 消费同一个 commit-pinned artifact。公网 WebUI 的 `/app.js``unidesk-frontend` 镜像内运行时 bundle;只改工作区文件、只跑 `bun run check`、只跑 `Bun.build`、只刷新浏览器或只 `server rebuild frontend` 都不能作为标准版本发布证据。
+1 -1
View File
@@ -69,7 +69,7 @@ Do not add a long-lived DevOps service, run broker, webhook listener or second d
} }
``` ```
`scriptPath` must be a repo-relative `scripts/ci/*.sh` path. Inline shell bodies, arbitrary script paths, local dirty scripts and separate `develop.json` or CI manifest files are forbidden. The script is fetched from the same full 40-character manifest commit that supplied `deploy.json`, so the runner logic is auditable and rollbackable with the desired state. Persistent dev rollout service scope is owned by `docs/reference/dev-environment.md`; this runner only consumes the dev service list for smoke verification and must not deploy it. `code-queue` is required in the dev service list for this smoke runner, but that does not enable `deploy apply --env dev --service code-queue`. `scriptPath` must be a repo-relative `scripts/ci/*.sh` path. Inline shell bodies, arbitrary script paths, local dirty scripts and separate `develop.json` or CI manifest files are forbidden. The script is fetched from the same full 40-character manifest commit that supplied `deploy.json`, so the runner logic is auditable and rollbackable with the desired state. Persistent dev rollout service scope is owned by `docs/reference/dev-environment.md`; this runner only consumes the dev service list for smoke verification and must not deploy it. `code-queue` is required in the dev service list for this smoke runner; its persistent dev deployment path is the separate dev-only registry artifact consumer, not this temporary e2e runner.
## Execution Path ## Execution Path
+14 -11
View File
@@ -38,12 +38,13 @@ The target release-governance model is to split stable maintenance validation fr
During a `release/v1` stabilization window, this same implemented `environments.dev` lane is temporarily reserved for v1 validation. Use pushed commits and explicit `deploy.json` pins to validate v1 fixes; do not add a parallel `dev-v1`/`dev-master` schema in the middle of the stabilization window unless that split is the blocker for v1. The detailed phase rule lives in `docs/reference/release-governance.md`. During a `release/v1` stabilization window, this same implemented `environments.dev` lane is temporarily reserved for v1 validation. Use pushed commits and explicit `deploy.json` pins to validate v1 fixes; do not add a parallel `dev-v1`/`dev-master` schema in the middle of the stabilization window unless that split is the blocker for v1. The detailed phase rule lives in `docs/reference/release-governance.md`.
The persistent dev rollout currently supports only: The persistent dev rollout currently supports:
- `backend-core` - `backend-core` as a D601 target-side build.
- `frontend` - `frontend`, `decision-center`, `mdtodo`, `claudeqq` and `code-queue` as D601 registry artifact consumers in `unidesk-dev`.
- `baidu-netdisk` as the main-server direct user-service artifact validation sample.
`baidu-netdisk` may appear in `environments.dev.services` as the first main-server direct user-service artifact validation sample. `deploy apply --env dev --service baidu-netdisk` consumes the D601 registry artifact and validates the main-server Compose service; it is not a persistent D601 k3s dev workload. `code-queue` is present in `environments.dev.services` only so `ci run-dev-e2e` can build a Git-pinned Code Queue image and run a temporary namespace smoke. It is not part of persistent dev apply: `deploy apply --env dev --service code-queue` must still be rejected. Decision Center, k3sctl-adapter and other D601 services are not part of persistent dev apply yet. Their smoke validation stays under `ci run-dev-e2e` or service-specific future designs. The `environments.dev.ci` declaration and short launcher runner are owned by `docs/reference/dev-ci-runner.md`. `deploy apply --env dev --service baidu-netdisk` consumes the D601 registry artifact and validates the main-server Compose service; it is not a persistent D601 k3s dev workload. `deploy apply --env dev --service code-queue` is intentionally dev-only and may mutate only `unidesk-dev` Code Queue scheduler/read/write/provider-egress-proxy objects. `deploy apply --env prod --service code-queue` must remain unsupported. The `environments.dev.ci` declaration and short launcher runner are owned by `docs/reference/dev-ci-runner.md`.
## Rust Backend-Core Boundary ## Rust Backend-Core Boundary
@@ -69,20 +70,20 @@ Rust checking is enabled only when the process is already running inside the D60
## Dev Deploy Path ## Dev Deploy Path
`deploy apply --env dev --service backend-core|frontend` is the controlled persistent dev rollout path. The controller runs on the master server, but the heavy work runs on D601. `backend-core` still uses the constrained dev target-side build path; `frontend` consumes the CI-published commit-pinned artifact from the D601 registry. `deploy apply --env dev --service backend-core|frontend|decision-center|mdtodo|claudeqq|code-queue` is the controlled persistent dev rollout path for D601 dev workloads. The controller runs on the master server, but the heavy work runs on D601. `backend-core` still uses the constrained dev target-side build path; the other listed services consume CI-published commit-pinned artifacts from the D601 registry.
1. Fetch `origin/master:deploy.json#environments.dev` and resolve the requested service commit to a full SHA. 1. Fetch `origin/master:deploy.json#environments.dev` and resolve the requested service commit to a full SHA.
2. Dispatch to D601 through the existing provider-gateway/Host SSH maintenance capability. 2. Dispatch to D601 through the existing provider-gateway/Host SSH maintenance capability.
3. On D601, fetch/export the requested Git commit through the node-local provider-gateway egress proxy `http://127.0.0.1:18789`. 3. On D601, fetch/export the requested Git commit through the node-local provider-gateway egress proxy `http://127.0.0.1:18789`.
4. For backend-core, use the target-side commit as the source for Dockerfile, build context and dev k3s manifest, then build the service image on D601 Docker. 4. For backend-core, use the target-side commit as the source for Dockerfile, build context and dev k3s manifest, then build the service image on D601 Docker.
5. For frontend, require the existing registry image `127.0.0.1:5000/unidesk/frontend:<commit>` produced by `ci publish-user-service --service frontend`; do not build frontend source in the dev target. 5. For artifact consumers, require the existing registry image `127.0.0.1:5000/unidesk/<service-id>:<commit>` produced by `ci publish-user-service --service <service-id>`; do not build that service source in the dev target.
6. Import the backend-core build output or frontend artifact into native k3s containerd at `/run/k3s/containerd/containerd.sock`. 6. Import the backend-core build output or registry artifact into native k3s containerd at `/run/k3s/containerd/containerd.sock`.
7. Apply only the selected `unidesk-dev` Service/Deployment objects from the dev manifest. 7. Apply only the selected `unidesk-dev` Service/Deployment objects from the dev manifest.
8. For `frontend`, sync auth/session settings from main-server `config.json.auth` into the dev runtime Secret/ConfigMap before rollout. 8. For `frontend`, sync auth/session settings from main-server `config.json.auth` into the dev runtime Secret/ConfigMap before rollout.
9. Stamp the Deployment with `UNIDESK_DEPLOY_*` env and `unidesk.ai/deploy-*` annotations. 9. Stamp the Deployment with `UNIDESK_DEPLOY_*` env and `unidesk.ai/deploy-*` annotations.
10. Verify health through the Kubernetes API service proxy and require the live commit to match the requested commit. 10. Verify health through the Kubernetes API service proxy and require the live commit to match the requested commit.
The dev path is not a fallback system. If GitHub fetch, provider-gateway egress, Docker build for backend-core, frontend artifact lookup, native k3s, containerd import, kubectl apply or live health verification fails, the job fails with logs. It must not fall back to building frontend source on the dev target, building on the master server, using a dirty worktree, direct D601 public ports, NodePort, or another deployment command. The dev path is not a fallback system. If GitHub fetch, provider-gateway egress, Docker build for backend-core, artifact lookup, native k3s, containerd import, kubectl apply or live health verification fails, the job fails with logs. It must not fall back to building artifact-consumer source on the dev target, building on the master server, using a dirty worktree, direct D601 public ports, NodePort, hostPort, provider-gateway business HTTP, or another deployment command. k3s-managed health verification must use the Kubernetes API service proxy.
## DevOps Hygiene ## DevOps Hygiene
@@ -96,13 +97,13 @@ Use this sequence for backend-core Rust and frontend dev work:
2. Run local non-Rust checks on the master server, for example `bun scripts/cli.ts check --files --scripts-typecheck --compose --logs`. 2. Run local non-Rust checks on the master server, for example `bun scripts/cli.ts check --files --scripts-typecheck --compose --logs`.
3. Commit and push the code to `origin master`; `deploy apply --env dev` cannot deploy unpushed local changes. 3. Commit and push the code to `origin master`; `deploy apply --env dev` cannot deploy unpushed local changes.
4. Update `deploy.json` `environments.dev.services` so `backend-core` and `frontend` point at the pushed commit, then commit and push that manifest update. 4. Update `deploy.json` `environments.dev.services` so `backend-core` and `frontend` point at the pushed commit, then commit and push that manifest update.
5. For frontend changes, publish the artifact first: `bun scripts/cli.ts ci publish-user-service --service frontend --commit <full-sha> --wait-ms 1200000`. 5. For artifact-consumer changes, publish the artifact first: `bun scripts/cli.ts ci publish-user-service --service <frontend|decision-center|mdtodo|claudeqq|code-queue> --commit <full-sha> --wait-ms 1200000`.
6. Run `bun scripts/cli.ts deploy apply --env dev --service backend-core` and observe the returned job with `bun scripts/cli.ts job status <jobId> --tail-bytes 30000`. 6. Run `bun scripts/cli.ts deploy apply --env dev --service backend-core` and observe the returned job with `bun scripts/cli.ts job status <jobId> --tail-bytes 30000`.
7. Run `bun scripts/cli.ts deploy apply --env dev --service frontend` and observe the job the same way; this must consume the registry artifact and verify `/health.deploy.commit`. 7. Run `bun scripts/cli.ts deploy apply --env dev --service <frontend|decision-center|mdtodo|claudeqq|code-queue>` and observe the job the same way; this must consume the registry artifact and verify live deploy metadata through the service health path.
8. If the dev service catalog changes, deploy the pushed `k3sctl-adapter` commit through the controlled local manifest exception, then verify `/api/control-plane` lists `k3s/dev/unidesk-dev-core.k3s.json`. 8. If the dev service catalog changes, deploy the pushed `k3sctl-adapter` commit through the controlled local manifest exception, then verify `/api/control-plane` lists `k3s/dev/unidesk-dev-core.k3s.json`.
9. Rebuild or verify `dev-frontend-proxy` on the main server with `bun scripts/cli.ts server rebuild dev-frontend-proxy` when the proxy config or port changes. 9. Rebuild or verify `dev-frontend-proxy` on the main server with `bun scripts/cli.ts server rebuild dev-frontend-proxy` when the proxy config or port changes.
10. Manually test `http://74.48.78.17:18083/` and the dev health endpoints. 10. Manually test `http://74.48.78.17:18083/` and the dev health endpoints.
11. Run D601 CI for the commit and the dev smoke runner: `bun scripts/cli.ts ci run --revision <commit> --wait-ms <ms>` and `bun scripts/cli.ts ci run-dev-e2e --wait-ms <ms>`. When Code Queue behavior changes, update the `code-queue` entry in `environments.dev.services` to the pushed commit before running the dev smoke; do not use `deploy apply --env dev --service code-queue`. 11. Run D601 CI for the commit and the dev smoke runner: `bun scripts/cli.ts ci run --revision <commit> --wait-ms <ms>` and `bun scripts/cli.ts ci run-dev-e2e --wait-ms <ms>`. When Code Queue behavior changes, update the `code-queue` entry in `environments.dev.services` to the pushed commit before running dev artifact validation or the temporary dev smoke.
## Validation Commands ## Validation Commands
@@ -113,6 +114,8 @@ bun scripts/cli.ts server status
bun scripts/cli.ts deploy plan --env dev bun scripts/cli.ts deploy plan --env dev
bun scripts/cli.ts deploy plan --env dev --service backend-core bun scripts/cli.ts deploy plan --env dev --service backend-core
bun scripts/cli.ts dev-env validate --manifest src/components/microservices/k3sctl-adapter/k3s/dev/unidesk-dev-core.k8s.yaml bun scripts/cli.ts dev-env validate --manifest src/components/microservices/k3sctl-adapter/k3s/dev/unidesk-dev-core.k8s.yaml
bun scripts/cli.ts dev-env validate --manifest src/components/microservices/k3sctl-adapter/k3s/dev/unidesk-dev-mdtodo.k8s.yaml
bun scripts/cli.ts dev-env validate --manifest src/components/microservices/k3sctl-adapter/k3s/dev/unidesk-dev-claudeqq.k8s.yaml
bun scripts/cli.ts dev-env validate --manifest src/components/microservices/k3sctl-adapter/k3s/dev/unidesk-dev-code-queue.k8s.yaml bun scripts/cli.ts dev-env validate --manifest src/components/microservices/k3sctl-adapter/k3s/dev/unidesk-dev-code-queue.k8s.yaml
bun scripts/cli.ts ci run-dev-e2e --wait-ms 600000 bun scripts/cli.ts ci run-dev-e2e --wait-ms 600000
bun scripts/cli.ts microservice proxy k3sctl-adapter /api/services/backend-core-dev/proxy/health --raw --full bun scripts/cli.ts microservice proxy k3sctl-adapter /api/services/backend-core-dev/proxy/health --raw --full
+8 -3
View File
@@ -158,7 +158,7 @@ Baidu Netdisk 在 UniDesk 语境中按纯后端服务管理:不得暴露百度
D601 开发环境底座只允许创建 `unidesk-dev` namespace 与 dev 专用对象,manifest 固定为 `src/components/microservices/k3sctl-adapter/k3s/dev/unidesk-dev-foundation.k8s.yaml`。该 manifest 包含 `postgres-dev` 独立 PostgreSQL StatefulSet/Service/PVC、dev-only secret/config 模板、dev DB 初始化 SQL 和迁移 Job、ResourceQuota/LimitRange,以及 `unidesk-dev-db-guard`。它不得修改生产 `unidesk` namespace、生产 PostgreSQL、生产 PVC、生产 Deployment/Service/Secret 或主 server Docker Compose。 D601 开发环境底座只允许创建 `unidesk-dev` namespace 与 dev 专用对象,manifest 固定为 `src/components/microservices/k3sctl-adapter/k3s/dev/unidesk-dev-foundation.k8s.yaml`。该 manifest 包含 `postgres-dev` 独立 PostgreSQL StatefulSet/Service/PVC、dev-only secret/config 模板、dev DB 初始化 SQL 和迁移 Job、ResourceQuota/LimitRange,以及 `unidesk-dev-db-guard`。它不得修改生产 `unidesk` namespace、生产 PostgreSQL、生产 PVC、生产 Deployment/Service/Secret 或主 server Docker Compose。
`postgres-dev` 是 dev backend-core 与未来 dev Code Queue 状态的默认唯一数据库。dev 运行时必须使用 `postgres-dev.unidesk-dev.svc.cluster.local:5432/unidesk_dev` 和 dev Provider 身份 `D601-dev`;不得共享生产 `d601-tcp-egress-gateway.../unidesk`。Persistent dev backend-core target-side rollout, frontend artifact rollout, public dev frontend port and Rust build boundary are defined in `docs/reference/dev-environment.md`; Code Queue dev rollout remains future work. `postgres-dev` 是 dev backend-core 与 dev Code Queue 状态的默认唯一数据库。dev 运行时必须使用 `postgres-dev.unidesk-dev.svc.cluster.local:5432/unidesk_dev` 和 dev Provider 身份 `D601-dev`;不得共享生产 `d601-tcp-egress-gateway.../unidesk`。Persistent dev backend-core target-side rollout, frontend/Decision Center/MDTODO/ClaudeQQ artifact rollout, dev-only Code Queue artifact rollout, public dev frontend port and Rust build boundary are defined in `docs/reference/dev-environment.md`.
验收入口:先运行 `bun scripts/cli.ts dev-env validate` 做静态资源与 DB URL 护栏检查;具备 D601 kubeconfig 时运行 `bun scripts/cli.ts dev-env validate --kubectl-dry-run` 做 Kubernetes client dry-run。首次或镜像缓存不确定时,先运行 `bun scripts/cli.ts dev-env prewarm-images`,把 `postgres:16-alpine` 和 local-path helper 所需的 `rancher/mirrored-library-busybox:1.36.1` 导入 D601 原生 k3s containerd;否则 D601 的 Docker 代理/缓存正常也不能保证 k3s/containerd 能实时拉到外部镜像。若实际 apply,只能 apply 到 `unidesk-dev`,随后用 `kubectl -n unidesk-dev get pods,svc,pvc` 验证 dev DB ready,并对比 apply 前后的 `kubectl -n unidesk get deploy,sts,svc,secret,pvc -o name` 证明生产 workload 未变化。 验收入口:先运行 `bun scripts/cli.ts dev-env validate` 做静态资源与 DB URL 护栏检查;具备 D601 kubeconfig 时运行 `bun scripts/cli.ts dev-env validate --kubectl-dry-run` 做 Kubernetes client dry-run。首次或镜像缓存不确定时,先运行 `bun scripts/cli.ts dev-env prewarm-images`,把 `postgres:16-alpine` 和 local-path helper 所需的 `rancher/mirrored-library-busybox:1.36.1` 导入 D601 原生 k3s containerd;否则 D601 的 Docker 代理/缓存正常也不能保证 k3s/containerd 能实时拉到外部镜像。若实际 apply,只能 apply 到 `unidesk-dev`,随后用 `kubectl -n unidesk-dev get pods,svc,pvc` 验证 dev DB ready,并对比 apply 前后的 `kubectl -n unidesk get deploy,sts,svc,secret,pvc -o name` 证明生产 workload 未变化。
@@ -172,12 +172,15 @@ D601 上必须显式使用原生 k3s kubeconfig`KUBECONFIG=/etc/rancher/k3s/k
`unidesk-dev-core.k8s.yaml` 当前使用 placeholder image/commit;正式 rollout 需要 `deploy apply --env dev` executor 从 `origin/master:deploy.json#environments.dev` 替换 commit 并构建镜像。当前验收只做静态校验和 Kubernetes client dry-run,不能把 placeholder manifest 当成已上线。 `unidesk-dev-core.k8s.yaml` 当前使用 placeholder image/commit;正式 rollout 需要 `deploy apply --env dev` executor 从 `origin/master:deploy.json#environments.dev` 替换 commit 并构建镜像。当前验收只做静态校验和 Kubernetes client dry-run,不能把 placeholder manifest 当成已上线。
`unidesk-dev-mdtodo.k8s.yaml``unidesk-dev-claudeqq.k8s.yaml``unidesk-dev-code-queue.k8s.yaml` 是 D601 registry artifact consumer 的 dev manifests。它们只能创建 `unidesk-dev` 内的 ClusterIP Service/Deployment 对象,不得修改生产 `unidesk` namespace、主 server Compose 或新增 NodePort/hostPort。受控 rollout 必须使用 commit-pinned registry artifact、stamp `UNIDESK_DEPLOY_*` metadata,并通过 Kubernetes API service proxy 检查服务健康。
### Code Queue k3s-Managed ### Code Queue k3s-Managed
当前对外 `id=code-queue` 是稳定用户服务 ID,实际按 master 控制面与 D601 执行面拆分。队列管理、提交、历史摘要、已读状态和轻量 Trace 读取默认由主 server `code-queue-mgr` 直管 PostgreSQLD601 k3s Code Queue 作为执行面代管,负责 scheduler/runner、dev-container、active run steer/interrupt、judge、输出/attempt/通知写回,并接入统一 `oa-event-flow` 发布 Trace/STEP 事实事件与读取统计中心: 当前对外 `id=code-queue` 是稳定用户服务 ID,实际按 master 控制面与 D601 执行面拆分。队列管理、提交、历史摘要、已读状态和轻量 Trace 读取默认由主 server `code-queue-mgr` 直管 PostgreSQLD601 k3s Code Queue 作为执行面代管,负责 scheduler/runner、dev-container、active run steer/interrupt、judge、输出/attempt/通知写回,并接入统一 `oa-event-flow` 发布 Trace/STEP 事实事件与读取统计中心:
- Orchestrator:稳定 `code-queue` ID 的控制/读取路径由 backend-core 分流到 `deployment.mode=internal-sidecar``code-queue-mgr`D601 执行面仍登记为 `deployment.mode=k3sctl-managed``deployment.adapterServiceId=k3sctl-adapter``deployment.k3sServiceId=code-queue``backend.proxyMode=k3sctl-adapter-http``backend.nodeBaseUrl=k3s://code-queue`。对外登记的 `code-queue` ID 保持稳定,frontend/CLI 不需要知道内部拆分。 - Orchestrator:稳定 `code-queue` ID 的控制/读取路径由 backend-core 分流到 `deployment.mode=internal-sidecar``code-queue-mgr`D601 执行面仍登记为 `deployment.mode=k3sctl-managed``deployment.adapterServiceId=k3sctl-adapter``deployment.k3sServiceId=code-queue``backend.proxyMode=k3sctl-adapter-http``backend.nodeBaseUrl=k3s://code-queue`。对外登记的 `code-queue` ID 保持稳定,frontend/CLI 不需要知道内部拆分。
- Direct path ban`code-queue` 不得再登记 `http://code-queue:4222``http://host.docker.internal:4222`、NodePort 或 provider-gateway `microservice.http` 作为业务代理目标;frontend 也不得使用旧 `/api/code-queue-direct` 兼容别名作为 Code Queue 页面数据源。provider-gateway 只允许用于维护 D601/D518、部署 adapter、部署 k3s/k8s 节点或诊断节点本机容器。 - Direct path ban`code-queue` 不得再登记 `http://code-queue:4222``http://host.docker.internal:4222`、NodePort 或 provider-gateway `microservice.http` 作为业务代理目标;frontend 也不得使用旧 `/api/code-queue-direct` 兼容别名作为 Code Queue 页面数据源。provider-gateway 只允许用于维护 D601/D518、部署 adapter、部署 k3s/k8s 节点或诊断节点本机容器。
- Artifact consumer boundary`code-queue` 只支持 dev artifact consumer。`--env dev --service code-queue` 可从 D601 registry 消费 `unidesk/code-queue:<commit>` 并更新 `unidesk-dev` 的 scheduler/read/write/provider-egress-proxy dev Deployments`--env prod --service code-queue` 必须明确 unsupported,不得执行 production artifact deploy、rollout 或 manifest 变更。
- Claim/move consistencymaster `code-queue-mgr` 和 D601 scheduler 都必须以 PostgreSQL 状态为权威;move 只允许未 claim 的 `queued`/`retry_wait` 行,merge 在 source/target queue 存在 `running`/`judging` 或 claim marker 时整体返回 409。稳定 `code-queue` 代理可用 `/api/queue-claim-move/self-test` 验证 claimed task move 会被拒绝且数据库仍保持 running/source queue 状态。 - Claim/move consistencymaster `code-queue-mgr` 和 D601 scheduler 都必须以 PostgreSQL 状态为权威;move 只允许未 claim 的 `queued`/`retry_wait` 行,merge 在 source/target queue 存在 `running`/`judging` 或 claim marker 时整体返回 409。稳定 `code-queue` 代理可用 `/api/queue-claim-move/self-test` 验证 claimed task move 会被拒绝且数据库仍保持 running/source queue 状态。
- D601 Service boundaryD601 内部可以继续保留 `code-queue-read``code-queue-write``code-queue-scheduler` 三个 Kubernetes Service 作为执行面兼容和过渡对象,但普通提交、queue CRUD、history、readAt 和轻量 overview 不得依赖 `code-queue-write` 或 D601 egress 可用;`code-queue-write` 不 ready 时,主 server `code-queue-mgr` 仍应保证 CLI/WebUI 的提交、列表和历史读取可用。需要 active run、dev-container、judge 或执行面健康的路径才进入 D601 scheduler。 - D601 Service boundaryD601 内部可以继续保留 `code-queue-read``code-queue-write``code-queue-scheduler` 三个 Kubernetes Service 作为执行面兼容和过渡对象,但普通提交、queue CRUD、history、readAt 和轻量 overview 不得依赖 `code-queue-write` 或 D601 egress 可用;`code-queue-write` 不 ready 时,主 server `code-queue-mgr` 仍应保证 CLI/WebUI 的提交、列表和历史读取可用。需要 active run、dev-container、judge 或执行面健康的路径才进入 D601 scheduler。
- 服务拆分语义:`code-queue-read` 只承载 GET/HEAD 查询、overview、任务详情、Trace/output/transcript、统计和只读健康,可多副本滚动更新;它必须设置 `CODE_QUEUE_SERVICE_ROLE=read``CODE_QUEUE_SCHEDULER_ENABLED=false`,且不得接受入队、queue 变更、已读、重试、移动、追加 prompt 或打断这类 mutation。`code-queue-write` 承载入队、queue 创建/合并/更新、已读、手动重试、移动等命令写入,初期保持单副本和 `CODE_QUEUE_SERVICE_ROLE=write`,只把命令和任务状态写入 PostgreSQL,不启动 agent 子进程。`code-queue-scheduler` 是唯一拥有 scheduler 和 active run 的执行服务,设置 `CODE_QUEUE_SERVICE_ROLE=scheduler``CODE_QUEUE_SCHEDULER_ENABLED=true`,负责从 PostgreSQL 热任务集轮询新写入任务、推进队列、启动 Codex/OpenCode、处理 running task 的 steer/interrupt、发送终态通知和暴露执行端 `/health`。普通 Service 负载均衡不得把 mutation 打到 read,也不得把 running task 控制打到 write。 - 服务拆分语义:`code-queue-read` 只承载 GET/HEAD 查询、overview、任务详情、Trace/output/transcript、统计和只读健康,可多副本滚动更新;它必须设置 `CODE_QUEUE_SERVICE_ROLE=read``CODE_QUEUE_SCHEDULER_ENABLED=false`,且不得接受入队、queue 变更、已读、重试、移动、追加 prompt 或打断这类 mutation。`code-queue-write` 承载入队、queue 创建/合并/更新、已读、手动重试、移动等命令写入,初期保持单副本和 `CODE_QUEUE_SERVICE_ROLE=write`,只把命令和任务状态写入 PostgreSQL,不启动 agent 子进程。`code-queue-scheduler` 是唯一拥有 scheduler 和 active run 的执行服务,设置 `CODE_QUEUE_SERVICE_ROLE=scheduler``CODE_QUEUE_SCHEDULER_ENABLED=true`,负责从 PostgreSQL 热任务集轮询新写入任务、推进队列、启动 Codex/OpenCode、处理 running task 的 steer/interrupt、发送终态通知和暴露执行端 `/health`。普通 Service 负载均衡不得把 mutation 打到 read,也不得把 running task 控制打到 write。
@@ -224,10 +227,11 @@ D601 上必须显式使用原生 k3s kubeconfig`KUBECONFIG=/etc/rancher/k3s/k
当前 ClaudeQQ 作为 `id=claudeqq``k3sctl-managed` 用户服务登记在 `config.json`,业务实例由 D601 k3s 控制面代管: 当前 ClaudeQQ 作为 `id=claudeqq``k3sctl-managed` 用户服务登记在 `config.json`,业务实例由 D601 k3s 控制面代管:
- Orchestrator`deployment.mode=k3sctl-managed``deployment.adapterServiceId=k3sctl-adapter``deployment.k3sServiceId=claudeqq``backend.proxyMode=k3sctl-adapter-http``backend.nodeBaseUrl=k3s://claudeqq`backend-core 对 ClaudeQQ 的正式链路只能是 `frontend -> backend-core -> k3sctl-adapter -> Kubernetes API service proxy -> Kubernetes Service claudeqq:3290` - Orchestrator`deployment.mode=k3sctl-managed``deployment.adapterServiceId=k3sctl-adapter``deployment.k3sServiceId=claudeqq``backend.proxyMode=k3sctl-adapter-http``backend.nodeBaseUrl=k3s://claudeqq`backend-core 对 ClaudeQQ 的正式链路只能是 `frontend -> backend-core -> k3sctl-adapter -> Kubernetes API service proxy -> Kubernetes Service claudeqq:3290`
- 部署引用:ClaudeQQ 业务源码来自 `https://gitee.com/lyon1998/agent_skills``claudeqq` 子目录;镜像构建 Dockerfile 和 `0.0.0.0:3290` API 适配器由 UniDesk 仓库 `src/components/microservices/claudeqq/` 作为 k3s 部署资产注入,不能依赖 D601 未提交工作树文件。Kubernetes 运行清单为 `src/components/microservices/k3sctl-adapter/k3s/claudeqq.k8s.yaml``config.json` 对外记录 k3s manifest `src/components/microservices/k3sctl-adapter/k3s/claudeqq.k3s.json`。旧 `docker-compose.unidesk.yml` 只作为迁移/本地诊断参考,不是正式运行入口。 - 部署引用:ClaudeQQ 业务源码来自 `https://gitee.com/lyon1998/agent_skills``claudeqq` 子目录;镜像构建 Dockerfile 和 `0.0.0.0:3290` API 适配器由 UniDesk 仓库 `src/components/microservices/claudeqq/` 作为 k3s 部署资产注入,不能依赖 D601 未提交工作树文件。Kubernetes 运行清单为 `src/components/microservices/k3sctl-adapter/k3s/claudeqq.k8s.yaml``config.json` 对外记录 k3s manifest `src/components/microservices/k3sctl-adapter/k3s/claudeqq.k3s.json`dev 环境使用 `src/components/microservices/k3sctl-adapter/k3s/dev/unidesk-dev-claudeqq.k8s.yaml``unidesk-dev-claudeqq.k3s.json`,服务名为 `claudeqq-dev``docker-compose.unidesk.yml` 只作为迁移/本地诊断参考,不是正式运行入口。
- 运行对象:ClaudeQQ Pod 在 D601 上以同 Pod 双容器运行 `claudeqq``napcat`,仅通过 ClusterIP Service 暴露 `claudeqq:3290` 给 UniDesk 代理和 Code Queue 通知链路;NapCat 的 `3000/3001/6099` 只在 Pod 内可达,不得作为 NodePort、hostPort 或 provider-gateway 业务直连目标。 - 运行对象:ClaudeQQ Pod 在 D601 上以同 Pod 双容器运行 `claudeqq``napcat`,仅通过 ClusterIP Service 暴露 `claudeqq:3290` 给 UniDesk 代理和 Code Queue 通知链路;NapCat 的 `3000/3001/6099` 只在 Pod 内可达,不得作为 NodePort、hostPort 或 provider-gateway 业务直连目标。
- 持久化路径:NapCat 登录态保存在 D601 hostPath `/home/ubuntu/.agents/skills/claudeqq/napcat/qq`,NapCat 配置和二维码缓存分别保存在 `napcat/config``napcat/cache`;ClaudeQQ 后端挂载同一业务目录中的 `config.json``bot_workspace``logs``.state` 和只读 `napcat`。这些路径不得改成匿名 volume,避免重建 Pod 后 QQ 登录态和事件/订阅状态丢失。 - 持久化路径:NapCat 登录态保存在 D601 hostPath `/home/ubuntu/.agents/skills/claudeqq/napcat/qq`,NapCat 配置和二维码缓存分别保存在 `napcat/config``napcat/cache`;ClaudeQQ 后端挂载同一业务目录中的 `config.json``bot_workspace``logs``.state` 和只读 `napcat`。这些路径不得改成匿名 volume,避免重建 Pod 后 QQ 登录态和事件/订阅状态丢失。
- 代理/API:只允许 `/health``/logs``/api/` 前缀;允许方法为 `GET``HEAD``POST``DELETE``POST /api/push/text` 接受 `userId``groupId``message`,由 ClaudeQQ 通过同 Pod NapCat HTTP API 发送 QQ 消息;NapCat 不可用时必须快速返回 `status=napcat_offline` 或可解释错误。 - 代理/API:只允许 `/health``/logs``/api/` 前缀;允许方法为 `GET``HEAD``POST``DELETE``POST /api/push/text` 接受 `userId``groupId``message`,由 ClaudeQQ 通过同 Pod NapCat HTTP API 发送 QQ 消息;NapCat 不可用时必须快速返回 `status=napcat_offline` 或可解释错误。
- Dev/prod CDClaudeQQ 的 dev/prod rollout 都必须走 D601 registry artifact consumer。CI 从 Gitee commit 导出 `claudeqq/` 源码并 overlay UniDesk Dockerfile/adapterCD 验证同一个 commit-pinned artifact contractdev 落到 `unidesk-dev/claudeqq-dev`prod 落到 `unidesk/claudeqq`,健康检查通过 Kubernetes API service proxy 完成;不得回退到维护通道直连或 NodePort/hostPort。
- UniDesk 前端:`用户服务 / ClaudeQQ` React 页面负责展示 D601、仓库引用、私有 k3s 后端映射、NapCat 登录二维码、NapCat HTTP/WS 状态、事件缓存、订阅表、订阅创建表单、消息推送表单、主用户私聊账号 `645275593`、最近 QQ 事件和已发送记录;完整原始 JSON 只能通过显式 `查看原始JSON` 打开。浏览器只能通过 UniDesk frontend 同源代理访问 ClaudeQQ,不得直接访问 D601 `3290/3000/3001/6099`,也不得 iframe ClaudeQQ 旧 WebUI。 - UniDesk 前端:`用户服务 / ClaudeQQ` React 页面负责展示 D601、仓库引用、私有 k3s 后端映射、NapCat 登录二维码、NapCat HTTP/WS 状态、事件缓存、订阅表、订阅创建表单、消息推送表单、主用户私聊账号 `645275593`、最近 QQ 事件和已发送记录;完整原始 JSON 只能通过显式 `查看原始JSON` 打开。浏览器只能通过 UniDesk frontend 同源代理访问 ClaudeQQ,不得直接访问 D601 `3290/3000/3001/6099`,也不得 iframe ClaudeQQ 旧 WebUI。
### Decision Center k3s-Managed ### Decision Center k3s-Managed
@@ -251,10 +255,11 @@ D601 上必须显式使用原生 k3s kubeconfig`KUBECONFIG=/etc/rancher/k3s/k
当前 MDTODO 作为 `id=mdtodo``k3sctl-managed` 用户服务登记在 `config.json`,用于把 D601 Windows 工作区 `F:\Work\vscode-mdtodo` 从 VS Code 扩展形态拆成 UniDesk 可代理的后端服务: 当前 MDTODO 作为 `id=mdtodo``k3sctl-managed` 用户服务登记在 `config.json`,用于把 D601 Windows 工作区 `F:\Work\vscode-mdtodo` 从 VS Code 扩展形态拆成 UniDesk 可代理的后端服务:
- Orchestrator`deployment.mode=k3sctl-managed``deployment.adapterServiceId=k3sctl-adapter``deployment.k3sServiceId=mdtodo``backend.proxyMode=k3sctl-adapter-http``backend.nodeBaseUrl=k3s://mdtodo`;正式链路只能是 `frontend -> backend-core -> k3sctl-adapter -> Kubernetes API service proxy -> Kubernetes Service mdtodo:4267` - Orchestrator`deployment.mode=k3sctl-managed``deployment.adapterServiceId=k3sctl-adapter``deployment.k3sServiceId=mdtodo``backend.proxyMode=k3sctl-adapter-http``backend.nodeBaseUrl=k3s://mdtodo`;正式链路只能是 `frontend -> backend-core -> k3sctl-adapter -> Kubernetes API service proxy -> Kubernetes Service mdtodo:4267`
- 代码与部署引用:后端源码位于 UniDesk 仓库 `src/components/microservices/mdtodo`Dockerfile 为 `src/components/microservices/mdtodo/Dockerfile`k3s manifest 为 `src/components/microservices/k3sctl-adapter/k3s/mdtodo.k3s.json`Kubernetes 运行清单为 `src/components/microservices/k3sctl-adapter/k3s/mdtodo.k8s.yaml`,镜像名固定为 `unidesk-mdtodo:d601` - 代码与部署引用:后端源码位于 UniDesk 仓库 `src/components/microservices/mdtodo`Dockerfile 为 `src/components/microservices/mdtodo/Dockerfile`k3s manifest 为 `src/components/microservices/k3sctl-adapter/k3s/mdtodo.k3s.json`Kubernetes 运行清单为 `src/components/microservices/k3sctl-adapter/k3s/mdtodo.k8s.yaml`,镜像名固定为 `unidesk-mdtodo:d601`dev 环境使用 `src/components/microservices/k3sctl-adapter/k3s/dev/unidesk-dev-mdtodo.k8s.yaml``unidesk-dev-mdtodo.k3s.json`,服务名为 `mdtodo-dev`
- 持久化边界:D601 的 `F:\Work\vscode-mdtodo` 先同步到 k3s 可见的 WSL hostPath `/home/ubuntu/cq-deploy/.state/mdtodo-workspace`Pod 将该目录挂载为 `/workspace`,后端直接读写 Markdown TODO 文件;`.state/mdtodo/logs` 只保存 JSONL 日志,不作为任务权威状态。该服务不得把原 VS Code webview 前端或 VSIX 构建产物作为浏览器入口。 - 持久化边界:D601 的 `F:\Work\vscode-mdtodo` 先同步到 k3s 可见的 WSL hostPath `/home/ubuntu/cq-deploy/.state/mdtodo-workspace`Pod 将该目录挂载为 `/workspace`,后端直接读写 Markdown TODO 文件;`.state/mdtodo/logs` 只保存 JSONL 日志,不作为任务权威状态。该服务不得把原 VS Code webview 前端或 VSIX 构建产物作为浏览器入口。
- API`GET /health``GET /live``GET /logs``GET /api/files``GET /api/tasks?file=...``GET|PATCH|DELETE /api/tasks/{id}``POST /api/tasks``GET|PUT /api/content``POST /api/execute-command``/health` 必须证明 hostPath 可读并至少能扫描到 TODO Markdown 文件。 - API`GET /health``GET /live``GET /logs``GET /api/files``GET /api/tasks?file=...``GET|PATCH|DELETE /api/tasks/{id}``POST /api/tasks``GET|PUT /api/content``POST /api/execute-command``/health` 必须证明 hostPath 可读并至少能扫描到 TODO Markdown 文件。
- 代理路径:只允许 `/health``/live``/logs``/api/` 前缀;允许方法为 `GET``HEAD``POST``PUT``PATCH``DELETE`。业务请求不得退化为 provider-gateway 直连、NodePort 或 D601 本机端口。 - 代理路径:只允许 `/health``/live``/logs``/api/` 前缀;允许方法为 `GET``HEAD``POST``PUT``PATCH``DELETE`。业务请求不得退化为 provider-gateway 直连、NodePort 或 D601 本机端口。
- Dev/prod CDMDTODO 的 dev/prod rollout 都必须走 D601 registry artifact consumer。dev manifest 在 `unidesk-dev` 中创建最小 ClusterIP Service/Deployment 并种子化一个 dev Markdown TODO 文件,保证 `/health` 可以真实扫描任务文件;prod 使用生产 `mdtodo` manifest。两边都要通过 Kubernetes API service proxy 验证 health/live deploy metadata,不能用 NodePort、hostPort 或 provider-gateway 业务直连替代。
- UniDesk 前端:`用户服务 / MDTODO` React 页面负责展示文件列表、任务树、任务状态、标题/正文编辑、新增/删除任务、执行命令生成和显式原始 JSON 按钮;默认页面不得裸铺完整 Markdown 或 JSON。 - UniDesk 前端:`用户服务 / MDTODO` React 页面负责展示文件列表、任务树、任务状态、标题/正文编辑、新增/删除任务、执行命令生成和显式原始 JSON 按钮;默认页面不得裸铺完整 Markdown 或 JSON。
## D601 User Services ## D601 User Services
+31 -1
View File
@@ -4,7 +4,7 @@ This document owns the default delivery path for UniDesk user services registere
## Scope ## Scope
User services are non-core business services mounted onto the UniDesk platform. They must remain deliverable without changing the base platform strategy. The default policy here applies to user services that are expected to reach production after validation, including the UniDesk user-service UI artifact (`frontend`), main-server direct services such as Baidu Netdisk, D601-managed k3s services such as Decision Center, and D601 direct Docker/Compose services such as FindJob and Pipeline. User services are non-core business services mounted onto the UniDesk platform. They must remain deliverable without changing the base platform strategy. The default policy here applies to user services that are expected to reach production after validation, including the UniDesk user-service UI artifact (`frontend`), main-server direct services such as Baidu Netdisk, D601-managed k3s services such as Decision Center, MDTODO and ClaudeQQ, and D601 direct Docker/Compose services such as FindJob and Pipeline. Code Queue is a special dev-only artifact consumer in this policy; its production execution plane must not be deployed by the user-service artifact consumer.
This policy does not apply to: This policy does not apply to:
@@ -14,6 +14,7 @@ This policy does not apply to:
- `k3sctl-adapter`; - `k3sctl-adapter`;
- `release/v1` governance; - `release/v1` governance;
- one-off infrastructure repair actions. - one-off infrastructure repair actions.
- production Code Queue artifact deploy or rollout.
`todo-note` is a special-case main-server service because its source repository remains external. Its master-server Compose artifact consumer still follows the runtime contract: `UNIDESK_TODO_NOTE_DEPLOY_*` is injected at recreate time, and the consumer health probe combines the service `/api/health` response with that runtime metadata before checking `deploy.commit` and `deploy.requestedCommit`. `todo-note` is a special-case main-server service because its source repository remains external. Its master-server Compose artifact consumer still follows the runtime contract: `UNIDESK_TODO_NOTE_DEPLOY_*` is injected at recreate time, and the consumer health probe combines the service `/api/health` response with that runtime metadata before checking `deploy.commit` and `deploy.requestedCommit`.
@@ -147,3 +148,32 @@ Decision Center is the canonical example of a user service that doubles as a pro
- Production acceptance is manual after the dev gate and must explicitly verify `health`, `records`, `diary editor`, the paired frontend page, no public business ports, and live commit / artifact information. - Production acceptance is manual after the dev gate and must explicitly verify `health`, `records`, `diary editor`, the paired frontend page, no public business ports, and live commit / artifact information.
Detailed service-level API and UI contracts remain in `docs/reference/microservices.md`. Detailed service-level API and UI contracts remain in `docs/reference/microservices.md`.
## MDTODO
MDTODO is a k3s-managed user-service artifact consumer.
- The minimal standard artifact command is `bun scripts/cli.ts ci publish-user-service --service mdtodo --commit <full-sha> --wait-ms 1200000`.
- The expected artifact is `127.0.0.1:5000/unidesk/mdtodo:<commit>` plus its registry digest from the CI output.
- Dev CD must run before prod CD and lands in `unidesk-dev/mdtodo-dev`; production CD lands in `unidesk/mdtodo`.
- Both paths must verify Deployment metadata and `/health` or `/live` deploy commit through the Kubernetes API service proxy.
- No MDTODO release may add NodePort, hostPort, public business ports or provider-gateway direct business backends.
## ClaudeQQ
ClaudeQQ is a k3s-managed user-service artifact consumer built from the external `https://gitee.com/lyon1998/agent_skills` repository with UniDesk deployment assets overlaid.
- The minimal standard artifact command is `bun scripts/cli.ts ci publish-user-service --service claudeqq --commit <full-sha> --wait-ms 1200000`.
- The expected artifact is `127.0.0.1:5000/unidesk/claudeqq:<commit>` plus its registry digest from the CI output.
- Dev CD must run before prod CD and lands in `unidesk-dev/claudeqq-dev`; production CD lands in `unidesk/claudeqq`.
- Both paths must verify Deployment metadata and service health through the Kubernetes API service proxy.
- No ClaudeQQ release may expose NapCat or backend ports through NodePort, hostPort, public business ports or provider-gateway direct business backends.
## Code Queue
Code Queue is dev-only for this artifact-consumer policy.
- The minimal standard artifact command is `bun scripts/cli.ts ci publish-user-service --service code-queue --commit <full-sha> --wait-ms 1200000`.
- The expected artifact is `127.0.0.1:5000/unidesk/code-queue:<commit>` plus its registry digest from the CI output.
- Dev CD may consume that artifact only with `deploy apply --env dev --service code-queue`, updating `unidesk-dev` scheduler/read/write/provider-egress-proxy objects and verifying health through the Kubernetes API service proxy.
- Production artifact deploy, production rollout and production manifest mutation for `code-queue` are unsupported and must fail visibly.
+175 -9
View File
@@ -74,11 +74,14 @@ const defaultOptions: ArtifactRegistryOptions = {
const supportedArtifactConsumerServices = [ const supportedArtifactConsumerServices = [
"backend-core", "backend-core",
"baidu-netdisk", "baidu-netdisk",
"claudeqq",
"code-queue",
"code-queue-mgr", "code-queue-mgr",
"decision-center", "decision-center",
"findjob", "findjob",
"frontend", "frontend",
"k3sctl-adapter", "k3sctl-adapter",
"mdtodo",
"met-nonlinear", "met-nonlinear",
"oa-event-flow", "oa-event-flow",
"pipeline", "pipeline",
@@ -124,6 +127,7 @@ interface ArtifactConsumerTarget {
servicePort: number; servicePort: number;
containerName: string; containerName: string;
healthPath: string; healthPath: string;
extraDeployments?: Array<string | { name: string; containerName?: string }>;
applySelector?: string; applySelector?: string;
podLabelSelector?: string; podLabelSelector?: string;
}; };
@@ -264,6 +268,116 @@ const artifactConsumerSpecs: Record<string, ArtifactConsumerSpec> = {
}, },
}, },
}, },
"mdtodo": {
serviceId: "mdtodo",
environment: "prod",
kind: "d601-k3s",
registryRepository: "unidesk/mdtodo",
dockerfile: "src/components/microservices/mdtodo/Dockerfile",
prodLiveApply: "enabled",
targets: {
dev: {
targetImage: "unidesk-mdtodo:dev",
targetCommitImage: (commit: string) => `unidesk-mdtodo:${commit}`,
deployRef: "deploy.json#environments.dev.services.mdtodo",
k3s: {
namespace: "unidesk-dev",
manifestRepoPath: "src/components/microservices/k3sctl-adapter/k3s/dev/unidesk-dev-mdtodo.k8s.yaml",
deploymentName: "mdtodo-dev",
serviceName: "mdtodo-dev",
servicePort: 4267,
containerName: "mdtodo",
healthPath: "/health",
podLabelSelector: "app.kubernetes.io/name=mdtodo,unidesk.ai/environment=dev",
},
},
prod: {
targetImage: "unidesk-mdtodo:d601",
targetCommitImage: (commit: string) => `unidesk-mdtodo:${commit}`,
deployRef: "deploy.json#environments.prod.services.mdtodo",
k3s: {
namespace: "unidesk",
manifestRepoPath: "src/components/microservices/k3sctl-adapter/k3s/mdtodo.k8s.yaml",
deploymentName: "mdtodo",
serviceName: "mdtodo",
servicePort: 4267,
containerName: "mdtodo",
healthPath: "/health",
},
},
},
},
"claudeqq": {
serviceId: "claudeqq",
environment: "prod",
kind: "d601-k3s",
registryRepository: "unidesk/claudeqq",
dockerfile: "claudeqq/Dockerfile",
sourceRepo: "https://gitee.com/lyon1998/agent_skills",
prodLiveApply: "enabled",
targets: {
dev: {
targetImage: "unidesk-claudeqq:dev",
targetCommitImage: (commit: string) => `unidesk-claudeqq:${commit}`,
deployRef: "deploy.json#environments.dev.services.claudeqq",
k3s: {
namespace: "unidesk-dev",
manifestRepoPath: "src/components/microservices/k3sctl-adapter/k3s/dev/unidesk-dev-claudeqq.k8s.yaml",
deploymentName: "claudeqq-dev",
serviceName: "claudeqq-dev",
servicePort: 3290,
containerName: "claudeqq",
healthPath: "/health",
podLabelSelector: "app.kubernetes.io/name=claudeqq,unidesk.ai/environment=dev",
},
},
prod: {
targetImage: "unidesk-claudeqq:d601",
targetCommitImage: (commit: string) => `unidesk-claudeqq:${commit}`,
deployRef: "deploy.json#environments.prod.services.claudeqq",
k3s: {
namespace: "unidesk",
manifestRepoPath: "src/components/microservices/k3sctl-adapter/k3s/claudeqq.k8s.yaml",
deploymentName: "claudeqq",
serviceName: "claudeqq",
servicePort: 3290,
containerName: "claudeqq",
healthPath: "/health",
},
},
},
},
"code-queue": {
serviceId: "code-queue",
environment: "dev",
kind: "d601-k3s",
registryRepository: "unidesk/code-queue",
dockerfile: "src/components/microservices/code-queue/Dockerfile",
prodLiveApply: "unsupported",
prodLiveBlockReason: "code-queue is dev-only for artifact consumer validation and has no prod artifact deploy, rollout, or manifest mutation target.",
targets: {
dev: {
targetImage: "unidesk-code-queue:dev",
targetCommitImage: (commit: string) => `unidesk-code-queue:${commit}`,
deployRef: "deploy.json#environments.dev.services.code-queue",
k3s: {
namespace: "unidesk-dev",
manifestRepoPath: "src/components/microservices/k3sctl-adapter/k3s/dev/unidesk-dev-code-queue.k8s.yaml",
deploymentName: "code-queue-scheduler-dev",
extraDeployments: [
{ name: "d601-dev-provider-egress-proxy", containerName: "provider-egress-proxy" },
"code-queue-read-dev",
"code-queue-write-dev",
],
serviceName: "code-queue-scheduler-dev",
servicePort: 4222,
containerName: "code-queue",
healthPath: "/health",
podLabelSelector: "app.kubernetes.io/name=code-queue,app.kubernetes.io/component=scheduler,unidesk.ai/environment=dev",
},
},
},
},
"frontend": { "frontend": {
serviceId: "frontend", serviceId: "frontend",
environment: "prod", environment: "prod",
@@ -809,6 +923,7 @@ function plan(options: ArtifactRegistryOptions): Record<string, unknown> {
"CI builds and publishes backend-core, frontend, and reviewed user-service artifacts on D601", "CI builds and publishes backend-core, frontend, and reviewed user-service artifacts on D601",
"CD only pulls, retags, recreates/imports artifacts, and verifies live commit", "CD only pulls, retags, recreates/imports artifacts, and verifies live commit",
"master server CD must not compile Rust or run docker compose build for artifact consumers", "master server CD must not compile Rust or run docker compose build for artifact consumers",
"code-queue is dev-only for artifact consumer validation and has no prod artifact deploy target",
], ],
renderedPaths: bundle.paths, renderedPaths: bundle.paths,
artifactConsumerFlow: [ artifactConsumerFlow: [
@@ -939,7 +1054,7 @@ function artifactConsumerSpec(serviceId: string, environment: ArtifactDeployEnvi
const explicit = artifactConsumerSpecs[key]; const explicit = artifactConsumerSpecs[key];
if (explicit !== undefined) return explicit; if (explicit !== undefined) return explicit;
const shared = artifactConsumerSpecs[serviceId]; const shared = artifactConsumerSpecs[serviceId];
return environment !== null && shared?.targets[environment] !== undefined ? shared : null; return shared ?? null;
} }
function supportedArtifactConsumers(): Array<{ environment: ArtifactDeployEnvironment; serviceId: SupportedArtifactConsumerService; kind: ArtifactConsumerSpec["kind"] }> { function supportedArtifactConsumers(): Array<{ environment: ArtifactDeployEnvironment; serviceId: SupportedArtifactConsumerService; kind: ArtifactConsumerSpec["kind"] }> {
@@ -1682,7 +1797,16 @@ function legacyDeployBackendCoreResult(options: ArtifactRegistryOptions): Record
function dryRunArtifactConsumerPlan(options: ArtifactRegistryOptions, spec: ArtifactConsumerSpec, target: ArtifactConsumerTarget, commit: string): Record<string, unknown> { function dryRunArtifactConsumerPlan(options: ArtifactRegistryOptions, spec: ArtifactConsumerSpec, target: ArtifactConsumerTarget, commit: string): Record<string, unknown> {
const environment = options.environment ?? "prod"; const environment = options.environment ?? "prod";
const verificationBlocked = spec.runtimeVerification === "blocked"; const verificationBlocked = spec.runtimeVerification === "blocked";
const livePolicy = environment === "prod" ? spec.prodLiveApply : "enabled";
const sourceImage = artifactImageRef(options, spec, commit); const sourceImage = artifactImageRef(options, spec, commit);
const k3sDeployments = target.k3s === undefined
? []
: [
{ name: target.k3s.deploymentName, containerName: target.k3s.containerName },
...(target.k3s.extraDeployments ?? []).map((deployment) => typeof deployment === "string"
? { name: deployment, containerName: target.k3s!.containerName }
: { name: deployment.name, containerName: deployment.containerName ?? target.k3s!.containerName }),
];
const common = { const common = {
ok: !verificationBlocked, ok: !verificationBlocked,
supported: !verificationBlocked, supported: !verificationBlocked,
@@ -1707,9 +1831,9 @@ function dryRunArtifactConsumerPlan(options: ArtifactRegistryOptions, spec: Arti
}, },
boundary: `${environment} CD is artifact-consumer only: verify commit-pinned registry image, pull/import, deploy, then verify live commit/image/health; it never builds source on the runtime target`, boundary: `${environment} CD is artifact-consumer only: verify commit-pinned registry image, pull/import, deploy, then verify live commit/image/health; it never builds source on the runtime target`,
liveApply: { liveApply: {
policy: spec.prodLiveApply, policy: livePolicy,
allowed: !verificationBlocked && (environment !== "prod" || spec.prodLiveApply === "enabled"), allowed: !verificationBlocked && (environment !== "prod" || spec.prodLiveApply === "enabled"),
reason: spec.runtimeVerificationBlockReason ?? spec.prodLiveBlockReason ?? null, reason: spec.runtimeVerificationBlockReason ?? (environment === "prod" ? spec.prodLiveBlockReason ?? null : null),
}, },
}; };
if (spec.kind === "compose" || spec.kind === "d601-compose") { if (spec.kind === "compose" || spec.kind === "d601-compose") {
@@ -1752,6 +1876,7 @@ function dryRunArtifactConsumerPlan(options: ArtifactRegistryOptions, spec: Arti
kind: "d601-k3s", kind: "d601-k3s",
namespace: target.k3s?.namespace, namespace: target.k3s?.namespace,
deployment: target.k3s?.deploymentName, deployment: target.k3s?.deploymentName,
deployments: k3sDeployments,
service: target.k3s?.serviceName, service: target.k3s?.serviceName,
stableImage: target.targetImage, stableImage: target.targetImage,
runtimeImage: target.targetCommitImage(commit), runtimeImage: target.targetCommitImage(commit),
@@ -1803,6 +1928,13 @@ function d601K3sArtifactDeployScript(options: ArtifactRegistryOptions, spec: Art
const sourceRepo = sourceRepoFor(options, spec); const sourceRepo = sourceRepoFor(options, spec);
const commitImage = target.targetCommitImage(commit); const commitImage = target.targetCommitImage(commit);
const k3s = target.k3s; const k3s = target.k3s;
const deploymentSpecs = [
{ name: k3s.deploymentName, containerName: k3s.containerName },
...(k3s.extraDeployments ?? []).map((deployment) => typeof deployment === "string"
? { name: deployment, containerName: k3s.containerName }
: { name: deployment.name, containerName: deployment.containerName ?? k3s.containerName }),
];
const deploymentSpecsBase64 = Buffer.from(JSON.stringify(deploymentSpecs), "utf8").toString("base64");
const labels = [ const labels = [
`unidesk.ai/deploy-service-id=${spec.serviceId}`, `unidesk.ai/deploy-service-id=${spec.serviceId}`,
`unidesk.ai/deploy-ref=${deployRefFor(options, spec)}`, `unidesk.ai/deploy-ref=${deployRefFor(options, spec)}`,
@@ -1827,6 +1959,7 @@ function d601K3sArtifactDeployScript(options: ArtifactRegistryOptions, spec: Art
`namespace=${shellQuote(k3s.namespace)}`, `namespace=${shellQuote(k3s.namespace)}`,
`deployment=${shellQuote(k3s.deploymentName)}`, `deployment=${shellQuote(k3s.deploymentName)}`,
`container_name=${shellQuote(k3s.containerName)}`, `container_name=${shellQuote(k3s.containerName)}`,
`deployment_specs_b64=${shellQuote(deploymentSpecsBase64)}`,
`service_name=${shellQuote(k3s.serviceName)}`, `service_name=${shellQuote(k3s.serviceName)}`,
`service_port=${shellQuote(String(k3s.servicePort))}`, `service_port=${shellQuote(String(k3s.servicePort))}`,
`health_path=${shellQuote(k3s.healthPath)}`, `health_path=${shellQuote(k3s.healthPath)}`,
@@ -1858,15 +1991,37 @@ function d601K3sArtifactDeployScript(options: ArtifactRegistryOptions, spec: Art
"root_exec ctr --address /run/k3s/containerd/containerd.sock -n k8s.io images ls | grep -F \"$stable_image\" >/dev/null", "root_exec ctr --address /run/k3s/containerd/containerd.sock -n k8s.io images ls | grep -F \"$stable_image\" >/dev/null",
"root_exec ctr --address /run/k3s/containerd/containerd.sock -n k8s.io images ls | grep -F \"$commit_image\" >/dev/null", "root_exec ctr --address /run/k3s/containerd/containerd.sock -n k8s.io images ls | grep -F \"$commit_image\" >/dev/null",
"printf '%s' \"$manifest_b64\" | base64 -d > \"$manifest\"", "printf '%s' \"$manifest_b64\" | base64 -d > \"$manifest\"",
"grep -F \"name: $deployment\" \"$manifest\" >/dev/null", "deployment_specs=$(mktemp /tmp/unidesk-artifact-k3s-deployments.XXXXXX.json)",
"printf '%s' \"$deployment_specs_b64\" | base64 -d > \"$deployment_specs\"",
"trap 'rm -f \"$archive\" \"$manifest\" \"$deployment_specs\" \"$health_tmp\"' EXIT",
"python3 - \"$deployment_specs\" \"$manifest\" <<'PY'",
"import json, sys",
"specs = json.load(open(sys.argv[1], encoding='utf-8'))",
"manifest = open(sys.argv[2], encoding='utf-8').read()",
"missing = [item['name'] for item in specs if f\"name: {item['name']}\" not in manifest]",
"if missing:",
" raise SystemExit('manifest missing deployment(s): ' + ','.join(missing))",
"PY",
"if [ -n \"$apply_selector\" ]; then kubectl apply -f \"$manifest\" -l \"$apply_selector\"; else kubectl apply -f \"$manifest\"; fi", "if [ -n \"$apply_selector\" ]; then kubectl apply -f \"$manifest\" -l \"$apply_selector\"; else kubectl apply -f \"$manifest\"; fi",
...(environment === "dev" && spec.serviceId === "frontend" ? [d601DevFrontendAuthPatchScript(readConfig())] : []), ...(environment === "dev" && spec.serviceId === "frontend" ? [d601DevFrontendAuthPatchScript(readConfig())] : []),
"previous_commit=$(kubectl -n \"$namespace\" get deployment \"$deployment\" -o jsonpath='{.metadata.annotations.unidesk\\.ai/deploy-commit}' 2>/dev/null || true)", "previous_commit=$(kubectl -n \"$namespace\" get deployment \"$deployment\" -o jsonpath='{.metadata.annotations.unidesk\\.ai/deploy-commit}' 2>/dev/null || true)",
"kubectl -n \"$namespace\" set image \"deployment/$deployment\" \"$container_name=$commit_image\"", "python3 - \"$deployment_specs\" <<'PY' | while IFS=$'\\t' read -r rollout_deployment rollout_container; do",
"kubectl -n \"$namespace\" set env \"deployment/$deployment\" \"UNIDESK_DEPLOY_SERVICE_ID=$service_id\" \"UNIDESK_DEPLOY_REF=$deploy_ref\" \"UNIDESK_DEPLOY_REPO=$source_repo\" \"UNIDESK_DEPLOY_COMMIT=$commit\" \"UNIDESK_DEPLOY_REQUESTED_COMMIT=$commit\"", "import json, sys",
`kubectl -n "$namespace" annotate "deployment/$deployment" ${labels.map(shellQuote).join(" ")} --overwrite`, "for item in json.load(open(sys.argv[1], encoding='utf-8')):",
"if [ -n \"$previous_commit\" ] && [ \"$previous_commit\" != \"$commit\" ]; then kubectl -n \"$namespace\" annotate \"deployment/$deployment\" \"unidesk.ai/deploy-previous-commit=$previous_commit\" --overwrite; fi", " print(f\"{item['name']}\\t{item['containerName']}\")",
"kubectl -n \"$namespace\" rollout status \"deployment/$deployment\" --timeout=180s", "PY",
" kubectl -n \"$namespace\" set image \"deployment/$rollout_deployment\" \"$rollout_container=$commit_image\"",
" kubectl -n \"$namespace\" set env \"deployment/$rollout_deployment\" \"UNIDESK_DEPLOY_SERVICE_ID=$service_id\" \"UNIDESK_DEPLOY_REF=$deploy_ref\" \"UNIDESK_DEPLOY_REPO=$source_repo\" \"UNIDESK_DEPLOY_COMMIT=$commit\" \"UNIDESK_DEPLOY_REQUESTED_COMMIT=$commit\" \"CODE_QUEUE_DEPLOY_COMMIT=$commit\" \"CODE_QUEUE_DEPLOY_REQUESTED_COMMIT=$commit\"",
` kubectl -n "$namespace" annotate "deployment/$rollout_deployment" ${labels.map(shellQuote).join(" ")} --overwrite`,
" if [ -n \"$previous_commit\" ] && [ \"$previous_commit\" != \"$commit\" ]; then kubectl -n \"$namespace\" annotate \"deployment/$rollout_deployment\" \"unidesk.ai/deploy-previous-commit=$previous_commit\" --overwrite; fi",
"done",
"python3 - \"$deployment_specs\" <<'PY' | while IFS= read -r rollout_deployment; do",
"import json, sys",
"for item in json.load(open(sys.argv[1], encoding='utf-8')):",
" print(item['name'])",
"PY",
" kubectl -n \"$namespace\" rollout status \"deployment/$rollout_deployment\" --timeout=180s",
"done",
"deployment_commit=$(kubectl -n \"$namespace\" get deployment \"$deployment\" -o jsonpath='{.metadata.annotations.unidesk\\.ai/deploy-commit}')", "deployment_commit=$(kubectl -n \"$namespace\" get deployment \"$deployment\" -o jsonpath='{.metadata.annotations.unidesk\\.ai/deploy-commit}')",
"deployment_requested_commit=$(kubectl -n \"$namespace\" get deployment \"$deployment\" -o jsonpath='{.metadata.annotations.unidesk\\.ai/deploy-requested-commit}')", "deployment_requested_commit=$(kubectl -n \"$namespace\" get deployment \"$deployment\" -o jsonpath='{.metadata.annotations.unidesk\\.ai/deploy-requested-commit}')",
"test \"$deployment_commit\" = \"$commit\"", "test \"$deployment_commit\" = \"$commit\"",
@@ -2069,6 +2224,11 @@ function localHelp(): Record<string, unknown> {
"bun scripts/cli.ts artifact-registry deploy-service --env dev --service pipeline --commit <full-sha> --dry-run [--provider-id D601]", "bun scripts/cli.ts artifact-registry deploy-service --env dev --service pipeline --commit <full-sha> --dry-run [--provider-id D601]",
"bun scripts/cli.ts artifact-registry deploy-service --env dev --service met-nonlinear --commit <full-sha> --dry-run [--provider-id D601]", "bun scripts/cli.ts artifact-registry deploy-service --env dev --service met-nonlinear --commit <full-sha> --dry-run [--provider-id D601]",
"bun scripts/cli.ts artifact-registry deploy-service --env prod --service k3sctl-adapter --commit <full-sha> --dry-run [--provider-id D601]", "bun scripts/cli.ts artifact-registry deploy-service --env prod --service k3sctl-adapter --commit <full-sha> --dry-run [--provider-id D601]",
"bun scripts/cli.ts artifact-registry deploy-service --env dev --service mdtodo --commit <full-sha> [--dry-run] [--run-now] [--provider-id D601]",
"bun scripts/cli.ts artifact-registry deploy-service --env prod --service mdtodo --commit <full-sha> [--dry-run] [--run-now] [--provider-id D601]",
"bun scripts/cli.ts artifact-registry deploy-service --env dev --service claudeqq --commit <full-sha> [--dry-run] [--run-now] [--provider-id D601]",
"bun scripts/cli.ts artifact-registry deploy-service --env prod --service claudeqq --commit <full-sha> [--dry-run] [--run-now] [--provider-id D601]",
"bun scripts/cli.ts artifact-registry deploy-service --env dev --service code-queue --commit <full-sha> [--dry-run] [--run-now] [--provider-id D601]",
], ],
firstStage: "install now writes the rendered systemd/Compose/config files and starts the registry", firstStage: "install now writes the rendered systemd/Compose/config files and starts the registry",
artifactConsumers: { artifactConsumers: {
@@ -2088,6 +2248,8 @@ function localHelp(): Record<string, unknown> {
"bun scripts/cli.ts deploy apply --env prod --service pipeline --dry-run", "bun scripts/cli.ts deploy apply --env prod --service pipeline --dry-run",
"bun scripts/cli.ts deploy apply --env prod --service met-nonlinear --dry-run", "bun scripts/cli.ts deploy apply --env prod --service met-nonlinear --dry-run",
"bun scripts/cli.ts deploy apply --env prod --service k3sctl-adapter --dry-run", "bun scripts/cli.ts deploy apply --env prod --service k3sctl-adapter --dry-run",
"bun scripts/cli.ts deploy apply --env prod --service mdtodo",
"bun scripts/cli.ts deploy apply --env prod --service claudeqq",
], ],
devCommands: [ devCommands: [
"bun scripts/cli.ts deploy apply --env dev --service frontend", "bun scripts/cli.ts deploy apply --env dev --service frontend",
@@ -2099,7 +2261,11 @@ function localHelp(): Record<string, unknown> {
"bun scripts/cli.ts deploy apply --env dev --service findjob --dry-run", "bun scripts/cli.ts deploy apply --env dev --service findjob --dry-run",
"bun scripts/cli.ts deploy apply --env dev --service pipeline --dry-run", "bun scripts/cli.ts deploy apply --env dev --service pipeline --dry-run",
"bun scripts/cli.ts deploy apply --env dev --service met-nonlinear --dry-run", "bun scripts/cli.ts deploy apply --env dev --service met-nonlinear --dry-run",
"bun scripts/cli.ts deploy apply --env dev --service mdtodo",
"bun scripts/cli.ts deploy apply --env dev --service claudeqq",
"bun scripts/cli.ts deploy apply --env dev --service code-queue",
], ],
devOnlyConsumers: ["code-queue"],
rollbackShape: "rerun the same artifact consumer with a previous commit-pinned image", rollbackShape: "rerun the same artifact consumer with a previous commit-pinned image",
}, },
legacyEntrypoints: { legacyEntrypoints: {
+92 -2
View File
@@ -30,7 +30,6 @@ const ciRuntimeImages = [
"alpine/git:2.45.2", "alpine/git:2.45.2",
ciCodeQueueImage, ciCodeQueueImage,
]; ];
interface CiOptions { interface CiOptions {
repoUrl: string; repoUrl: string;
revision: string; revision: string;
@@ -836,6 +835,91 @@ async function prepareUserServiceArtifactSource(config: UniDeskConfig, options:
}; };
} }
async function prepareClaudeqqArtifactSource(config: UniDeskConfig, options: CiPublishUserServiceArtifactOptions): Promise<Record<string, unknown>> {
const sourceRoot = `/home/ubuntu/.unidesk/ci/user-service-artifacts/${options.serviceId}`;
const sourceHostPath = options.sourceHostPath;
const repoCache = "/home/ubuntu/.unidesk/ci/git/claudeqq-agent-skills.git";
const repoFetchUrl = options.repoUrl;
const assets = [
{
relativePath: "claudeqq/Dockerfile",
sourcePath: rootPath("src/components/microservices/claudeqq/Dockerfile"),
label: "Dockerfile",
},
{
relativePath: "claudeqq/unidesk-adapter.cjs",
sourcePath: rootPath("src/components/microservices/claudeqq/adapter.js"),
label: "unidesk-adapter.cjs",
},
];
for (const asset of assets) {
if (!existsSync(asset.sourcePath)) throw new Error(`claudeqq artifact asset missing: ${asset.sourcePath}`);
}
const overlayCommands = assets.flatMap((asset) => {
const encoded = Buffer.from(readFileSync(asset.sourcePath, "utf8"), "utf8").toString("base64");
return [
`mkdir -p "$tmp_dir/$(dirname ${shellQuote(asset.relativePath)})"`,
`printf %s ${shellQuote(encoded)} | base64 -d > "$tmp_dir/${asset.relativePath}"`,
`printf 'user_service_artifact_overlay=%s\\n' ${shellQuote(asset.label)}`,
];
});
const script = [
"set -euo pipefail",
`service_id=${shellQuote(options.serviceId)}`,
`commit=${shellQuote(options.commit)}`,
`repo_url=${shellQuote(options.repoUrl)}`,
`repo_fetch_url=${shellQuote(repoFetchUrl)}`,
`dockerfile=${shellQuote(options.dockerfile)}`,
`source_root=${shellQuote(sourceRoot)}`,
`source_dir=${shellQuote(sourceHostPath)}`,
`repo_cache=${shellQuote(repoCache)}`,
`proxy_url=${shellQuote(providerGatewayWsEgressProxyUrl)}`,
"mkdir -p \"$(dirname \"$repo_cache\")\" \"$source_root\"",
"export HTTP_PROXY=\"$proxy_url\" HTTPS_PROXY=\"$proxy_url\" ALL_PROXY=\"$proxy_url\"",
"export NO_PROXY=\"localhost,127.0.0.1,::1,host.docker.internal,.svc,.cluster.local,kubernetes.default.svc\"",
"curl -fsSI --max-time 20 -x \"$proxy_url\" https://gitee.com >/dev/null",
"echo user_service_artifact_source_proxy=provider-gateway-ws-egress:$proxy_url",
"echo user_service_artifact_repo_fetch_url=$repo_fetch_url",
"echo user_service_artifact_service_id=$service_id",
"if [ ! -d \"$repo_cache\" ]; then git clone --mirror \"$repo_fetch_url\" \"$repo_cache\"; fi",
"git -C \"$repo_cache\" remote set-url origin \"$repo_fetch_url\"",
"git -C \"$repo_cache\" fetch --no-tags origin \"$commit\" || git -C \"$repo_cache\" fetch --no-tags origin '+refs/heads/*:refs/remotes/origin/*'",
"resolved=$(git -C \"$repo_cache\" rev-parse --verify \"$commit^{commit}\")",
"test \"$resolved\" = \"$commit\" || { echo \"user_service_artifact_resolved_commit_mismatch=$resolved expected=$commit\" >&2; exit 1; }",
"git -C \"$repo_cache\" cat-file -e \"$commit:claudeqq/scripts/src/server_ts/package.json\"",
"git -C \"$repo_cache\" cat-file -e \"$commit:claudeqq/scripts/src/server_ts/src\"",
"tmp_dir=\"$source_root/.tmp-$commit-$$\"",
"rm -rf \"$tmp_dir\"",
"mkdir -p \"$tmp_dir\"",
"git -C \"$repo_cache\" archive \"$commit\" claudeqq | tar -x -C \"$tmp_dir\"",
...overlayCommands,
"printf '%s\\n' \"$commit\" > \"$tmp_dir/.unidesk-source-commit\"",
"printf '%s\\n' \"$repo_url\" > \"$tmp_dir/.unidesk-source-repo\"",
"printf '%s\\n' \"$service_id\" > \"$tmp_dir/.unidesk-service-id\"",
"printf '%s\\n' \"$dockerfile\" > \"$tmp_dir/.unidesk-dockerfile\"",
"rm -rf \"$source_dir\"",
"mv \"$tmp_dir\" \"$source_dir\"",
"test -f \"$source_dir/$dockerfile\"",
"test -f \"$source_dir/claudeqq/unidesk-adapter.cjs\"",
"test -d \"$source_dir/claudeqq/scripts/src/server_ts/src\"",
"echo user_service_artifact_source_host_path=$source_dir",
].join("\n");
const result = await runRemoteBackground(`prepare-${options.serviceId}-source`, script, 300_000);
if (!result.ok) throw new Error(`failed to prepare ${options.serviceId} source on D601: ${result.stderr || result.stdout || JSON.stringify(result.raw)}`);
return {
ok: true,
mode: "d601-host-gitee-https-export-with-unidesk-overlay",
providerId: d601ProviderId,
repoUrl: options.repoUrl,
repoFetchUrl,
commit: options.commit,
serviceId: options.serviceId,
dockerfile: options.dockerfile,
sourceHostPath,
stdoutTail: result.stdout.slice(-4000),
};
}
async function remoteCreatePipelineRun(manifest: string): Promise<string> { async function remoteCreatePipelineRun(manifest: string): Promise<string> {
const encoded = Buffer.from(manifest, "utf8").toString("base64"); const encoded = Buffer.from(manifest, "utf8").toString("base64");
const token = randomUUID().replace(/-/gu, "").slice(0, 12); const token = randomUUID().replace(/-/gu, "").slice(0, 12);
@@ -1194,6 +1278,7 @@ async function publishUserServiceArtifact(config: UniDeskConfig, options: CiPubl
dockerfile: options.dockerfile, dockerfile: options.dockerfile,
imageRepository: options.imageRepository, imageRepository: options.imageRepository,
sourceHostPath: options.sourceHostPath, sourceHostPath: options.sourceHostPath,
...(options.serviceId === "claudeqq" ? { overlay: "UniDesk claudeqq Dockerfile and unidesk-adapter.cjs are injected before Tekton build" } : {}),
}, },
artifact: plannedArtifact.imageRef, artifact: plannedArtifact.imageRef,
artifactSummary: plannedArtifact, artifactSummary: plannedArtifact,
@@ -1203,7 +1288,9 @@ async function publishUserServiceArtifact(config: UniDeskConfig, options: CiPubl
], ],
}; };
} }
const source = await prepareUserServiceArtifactSource(config, options); const source = options.serviceId === "claudeqq"
? await prepareClaudeqqArtifactSource(config, options)
: await prepareUserServiceArtifactSource(config, options);
const name = await remoteCreatePipelineRun(userServiceArtifactPipelineRunManifest(options)); const name = await remoteCreatePipelineRun(userServiceArtifactPipelineRunManifest(options));
const wait = await waitForPipelineRun(name, options.waitMs); const wait = await waitForPipelineRun(name, options.waitMs);
const condition = wait === null ? null : await readPipelineRunCondition(name); const condition = wait === null ? null : await readPipelineRunCondition(name);
@@ -1519,6 +1606,9 @@ export function ciHelp(): Record<string, unknown> {
"bun scripts/cli.ts ci run --revision <commit>", "bun scripts/cli.ts ci run --revision <commit>",
"bun scripts/cli.ts ci publish-backend-core --commit <full-sha>", "bun scripts/cli.ts ci publish-backend-core --commit <full-sha>",
"bun scripts/cli.ts ci publish-user-service --service baidu-netdisk --commit <full-sha>", "bun scripts/cli.ts ci publish-user-service --service baidu-netdisk --commit <full-sha>",
"bun scripts/cli.ts ci publish-user-service --service mdtodo --commit <full-sha>",
"bun scripts/cli.ts ci publish-user-service --service claudeqq --commit <full-sha>",
"bun scripts/cli.ts ci publish-user-service --service code-queue --commit <full-sha>",
"bun scripts/cli.ts ci publish-user-service --service decision-center --commit <full-sha>", "bun scripts/cli.ts ci publish-user-service --service decision-center --commit <full-sha>",
"bun scripts/cli.ts ci publish-user-service --service frontend --commit <full-sha>", "bun scripts/cli.ts ci publish-user-service --service frontend --commit <full-sha>",
"bun scripts/cli.ts ci run-dev-e2e --wait-ms 600000", "bun scripts/cli.ts ci run-dev-e2e --wait-ms 600000",
+49 -19
View File
@@ -134,12 +134,12 @@ const nativeK3sInstallVersion = "v1.34.1+k3s1";
const nativeK3sImage = "rancher/k3s:v1.34.1-k3s1"; const nativeK3sImage = "rancher/k3s:v1.34.1-k3s1";
const nativeK3sCtrAddress = "/run/k3s/containerd/containerd.sock"; const nativeK3sCtrAddress = "/run/k3s/containerd/containerd.sock";
const unideskRepoUrl = "https://github.com/pikasTech/unidesk"; const unideskRepoUrl = "https://github.com/pikasTech/unidesk";
const d601MaintenanceDeployAllowedServiceIds = new Set<string>(["backend-core", "k3sctl-adapter", "code-queue"]); const d601MaintenanceDeployAllowedServiceIds = new Set<string>(["backend-core", "k3sctl-adapter"]);
const devApplySupportedServiceIds = new Set<string>(["backend-core"]); const devApplySupportedServiceIds = new Set<string>(["backend-core"]);
const devArtifactConsumerServiceIds = new Set<string>(["baidu-netdisk", "code-queue-mgr", "decision-center", "findjob", "frontend", "met-nonlinear", "oa-event-flow", "pipeline", "project-manager", "todo-note"]); const devArtifactConsumerServiceIds = new Set<string>(["baidu-netdisk", "claudeqq", "code-queue", "code-queue-mgr", "decision-center", "findjob", "frontend", "mdtodo", "met-nonlinear", "oa-event-flow", "pipeline", "project-manager", "todo-note"]);
const devArtifactConsumerProdDesiredFallbackServiceIds = new Set<string>(["code-queue-mgr", "oa-event-flow", "project-manager", "todo-note"]); const devArtifactConsumerProdDesiredFallbackServiceIds = new Set<string>(["code-queue-mgr", "oa-event-flow", "project-manager", "todo-note"]);
const prodArtifactConsumerServiceIds = new Set<string>(["backend-core", "baidu-netdisk", "code-queue-mgr", "decision-center", "findjob", "frontend", "k3sctl-adapter", "met-nonlinear", "oa-event-flow", "pipeline", "project-manager", "todo-note"]); const prodArtifactConsumerServiceIds = new Set<string>(["backend-core", "baidu-netdisk", "claudeqq", "code-queue-mgr", "decision-center", "findjob", "frontend", "k3sctl-adapter", "mdtodo", "met-nonlinear", "oa-event-flow", "pipeline", "project-manager", "todo-note"]);
const prodForbiddenTargetSideBuildServiceIds = new Set<string>(["backend-core", "baidu-netdisk", "decision-center", "findjob", "frontend", "k3sctl-adapter", "met-nonlinear", "pipeline"]); const prodForbiddenTargetSideBuildServiceIds = new Set<string>(["backend-core", "baidu-netdisk", "claudeqq", "decision-center", "findjob", "frontend", "k3sctl-adapter", "mdtodo", "met-nonlinear", "pipeline"]);
const prodArtifactLiveApplyBlockedServiceIds = new Map<string, string>([ const prodArtifactLiveApplyBlockedServiceIds = new Map<string, string>([
["code-queue-mgr", "code-queue-mgr is the main-server Code Queue control-plane sidecar; live production apply requires explicit supervisor confirmation."], ["code-queue-mgr", "code-queue-mgr is the main-server Code Queue control-plane sidecar; live production apply requires explicit supervisor confirmation."],
["met-nonlinear", "met-nonlinear is blocked for live artifact deploy because config.json points at docker/unidesk/Dockerfile.ml while the compose service is met-nonlinear-ts."], ["met-nonlinear", "met-nonlinear is blocked for live artifact deploy because config.json points at docker/unidesk/Dockerfile.ml while the compose service is met-nonlinear-ts."],
@@ -206,8 +206,8 @@ export function deployHelp(action: string | undefined = undefined): Record<strin
apply: "Start an async target-side reconcile job unless --run-now is explicitly present.", apply: "Start an async target-side reconcile job unless --run-now is explicitly present.",
}, },
options: [ options: [
{ name: "--file <path>", default: defaultDeployFile, description: "Desired-state manifest path relative to the repo root. JSON and ESM JS manifests are supported, for example deploy.json or develop.js. Local manifest apply allows k3sctl-adapter and explicit production code-queue controlled rollout on D601." }, { name: "--file <path>", default: defaultDeployFile, description: "Desired-state manifest path relative to the repo root. JSON and ESM JS manifests are supported, for example deploy.json or develop.js. Local D601 maintenance apply is limited to approved direct exceptions; Code Queue direct rollout is disabled." },
{ name: "--env <dev|prod>", description: "Read the named environment from origin/master:deploy.json. Dev apply supports backend-core target-side rollout plus reviewed artifact consumers for frontend, baidu-netdisk, decision-center, project-manager, oa-event-flow, code-queue-mgr, todo-note, findjob, pipeline, and met-nonlinear. Prod apply uses the D601 registry artifact consumer for reviewed services; code-queue-mgr and D601 direct infrastructure/incomplete contracts are dry-run or supervisor-gated." }, { name: "--env <dev|prod>", description: "Read the named environment from origin/master:deploy.json. Dev apply supports backend-core target-side rollout plus reviewed artifact consumers for frontend, baidu-netdisk, decision-center, mdtodo, claudeqq, dev-only code-queue, project-manager, oa-event-flow, code-queue-mgr, todo-note, findjob, pipeline, and met-nonlinear. Prod apply uses reviewed D601 registry artifact consumers; code-queue has no prod target and gated/incomplete services return structured unsupported or dry-run-only output." },
{ name: "--service <id>", description: "Limit reconcile to one service from the manifest." }, { name: "--service <id>", description: "Limit reconcile to one service from the manifest." },
{ name: "--commit <full-sha>", description: "Prod artifact rollback/apply override for a selected service; the image must already exist in D601 registry." }, { name: "--commit <full-sha>", description: "Prod artifact rollback/apply override for a selected service; the image must already exist in D601 registry." },
{ name: "--dry-run", description: "Prepare and validate without mutating the target service." }, { name: "--dry-run", description: "Prepare and validate without mutating the target service." },
@@ -636,6 +636,7 @@ function devK3sDeployService(id: string): UniDeskMicroserviceConfig | undefined
const specs: Record<string, { const specs: Record<string, {
name: string; name: string;
description: string; description: string;
repoUrl?: string;
dockerfile: string; dockerfile: string;
composeService: string; composeService: string;
composeFile: string; composeFile: string;
@@ -689,6 +690,35 @@ function devK3sDeployService(id: string): UniDeskMicroserviceConfig | undefined
allowedMethods: ["GET", "HEAD", "POST", "PUT", "PATCH", "DELETE"], allowedMethods: ["GET", "HEAD", "POST", "PUT", "PATCH", "DELETE"],
allowedPathPrefixes: ["/", "/api/", "/logs"], allowedPathPrefixes: ["/", "/api/", "/logs"],
}, },
mdtodo: {
name: "UniDesk Dev MDTODO",
description: "Isolated dev MDTODO deployed into D601 native k3s namespace unidesk-dev.",
dockerfile: "src/components/microservices/mdtodo/Dockerfile",
composeFile: "src/components/microservices/k3sctl-adapter/k3s/dev/unidesk-dev-mdtodo.k8s.yaml",
composeService: "mdtodo-dev",
containerName: "k3s:mdtodo-dev",
nodeBaseUrl: "k3s://mdtodo-dev",
nodePort: 4267,
healthPath: "/health",
route: "/dev/mdtodo",
allowedMethods: ["GET", "HEAD", "POST", "PUT", "PATCH", "DELETE"],
allowedPathPrefixes: ["/health", "/live", "/logs", "/api/"],
},
claudeqq: {
name: "UniDesk Dev ClaudeQQ",
description: "Isolated dev ClaudeQQ deployed into D601 native k3s namespace unidesk-dev.",
repoUrl: "https://gitee.com/lyon1998/agent_skills",
dockerfile: "claudeqq/Dockerfile",
composeFile: "src/components/microservices/k3sctl-adapter/k3s/dev/unidesk-dev-claudeqq.k8s.yaml",
composeService: "claudeqq-dev",
containerName: "k3s:claudeqq-dev",
nodeBaseUrl: "k3s://claudeqq-dev",
nodePort: 3290,
healthPath: "/health",
route: "/dev/claudeqq",
allowedMethods: ["GET", "HEAD", "POST", "DELETE"],
allowedPathPrefixes: ["/health", "/logs", "/api/"],
},
"code-queue": { "code-queue": {
name: "UniDesk Dev Code Queue", name: "UniDesk Dev Code Queue",
description: "Isolated dev Code Queue execution plane deployed into D601 native k3s namespace unidesk-dev.", description: "Isolated dev Code Queue execution plane deployed into D601 native k3s namespace unidesk-dev.",
@@ -712,7 +742,7 @@ function devK3sDeployService(id: string): UniDeskMicroserviceConfig | undefined
providerId: "D601", providerId: "D601",
description: spec.description, description: spec.description,
repository: { repository: {
url: unideskRepoUrl, url: spec.repoUrl ?? unideskRepoUrl,
commitId: "deploy-env", commitId: "deploy-env",
dockerfile: spec.dockerfile, dockerfile: spec.dockerfile,
composeFile: spec.composeFile, composeFile: spec.composeFile,
@@ -809,6 +839,7 @@ function selectServices(config: UniDeskConfig, manifest: DeployManifest, service
function unsupportedReason(service: UniDeskMicroserviceConfig): string | null { function unsupportedReason(service: UniDeskMicroserviceConfig): string | null {
if (service.repository.dockerfile.startsWith("docker.io/")) return "image-only service has no Dockerfile source artifact"; if (service.repository.dockerfile.startsWith("docker.io/")) return "image-only service has no Dockerfile source artifact";
if (service.repository.composeFile.startsWith("docker run")) return "docker-run image-only service has no compose/k8s build path"; if (service.repository.composeFile.startsWith("docker run")) return "docker-run image-only service has no compose/k8s build path";
if (isD601MaintenanceDeployBlocked(service)) return "D601 maintenance-channel deployment is not allowed for this service; use reviewed registry artifact consumers instead";
if (service.repository.commitId === "local") return null; if (service.repository.commitId === "local") return null;
return null; return null;
} }
@@ -2242,7 +2273,7 @@ async function readK8sCommit(config: UniDeskConfig, service: UniDeskMicroservice
} }
function manifestEnvironmentForService(service: UniDeskMicroserviceConfig): DeployEnvironment { function manifestEnvironmentForService(service: UniDeskMicroserviceConfig): DeployEnvironment {
return service.id === "decision-center" && service.deployment.namespace === "unidesk-dev" ? "dev" : "prod"; return service.deployment.namespace === "unidesk-dev" ? "dev" : "prod";
} }
function serviceDeployRef(service: UniDeskMicroserviceConfig): string { function serviceDeployRef(service: UniDeskMicroserviceConfig): string {
@@ -2250,9 +2281,7 @@ function serviceDeployRef(service: UniDeskMicroserviceConfig): string {
} }
function k3sDeploymentManifestPath(service: UniDeskMicroserviceConfig): string { function k3sDeploymentManifestPath(service: UniDeskMicroserviceConfig): string {
if (service.id === "decision-center" && service.deployment.namespace === "unidesk-dev") { if (service.deployment.namespace === "unidesk-dev") return k8sManifestPath(service);
return "src/components/microservices/k3sctl-adapter/k3s/dev/unidesk-dev-decision-center.k8s.yaml";
}
if (service.id === "decision-center") { if (service.id === "decision-center") {
return "src/components/microservices/k3sctl-adapter/k3s/decision-center.k8s.yaml"; return "src/components/microservices/k3sctl-adapter/k3s/decision-center.k8s.yaml";
} }
@@ -2649,7 +2678,7 @@ function blockedD601MaintenanceDeployServices(config: UniDeskConfig, manifest: D
} }
function d601MaintenanceDeployBlockMessage(blocked: string[]): string { function d601MaintenanceDeployBlockMessage(blocked: string[]): string {
return `D601 target-side deployment is enabled only for k3sctl-adapter and dev backend-core; artifact consumers must use registry CD. Blocked services: ${blocked.join(", ")}. Use ci run-dev-e2e for dev smoke verification.`; return `D601 target-side deployment is enabled only for k3sctl-adapter and dev backend-core; artifact consumers must use registry CD. Blocked services: ${blocked.join(", ")}. Code Queue is dev-only through artifact-registry/deploy --env dev and has no production direct rollout path.`;
} }
function selectedDevArtifactServices(manifest: DeployManifest, serviceId: string | null): DeployManifestService[] { function selectedDevArtifactServices(manifest: DeployManifest, serviceId: string | null): DeployManifestService[] {
@@ -2889,7 +2918,7 @@ export async function runDeployCommand(config: UniDeskConfig | null, args: strin
} }
const unsupported = unsupportedDevApplyServices(manifest, options.serviceId); const unsupported = unsupportedDevApplyServices(manifest, options.serviceId);
if (unsupported.length > 0) { if (unsupported.length > 0) {
throw new Error(`deploy apply --env dev currently supports backend-core target-side rollout plus frontend/baidu-netdisk/decision-center/project-manager/oa-event-flow/code-queue-mgr/todo-note/findjob/pipeline/met-nonlinear artifact consumers; unsupported selected services: ${unsupported.join(", ")}. Use ci run-dev-e2e for smoke verification.`); throw new Error(`deploy apply --env dev currently supports backend-core target-side rollout plus frontend/baidu-netdisk/decision-center/mdtodo/claudeqq/code-queue/project-manager/oa-event-flow/code-queue-mgr/todo-note/findjob/pipeline/met-nonlinear artifact consumers; unsupported selected services: ${unsupported.join(", ")}. Use ci run-dev-e2e for smoke verification.`);
} }
const devArtifactServices = selectedDevArtifactServicesWithProdFallback(manifest, options.serviceId); const devArtifactServices = selectedDevArtifactServicesWithProdFallback(manifest, options.serviceId);
const devTargetServices = selectedDevTargetServices(manifest, options.serviceId); const devTargetServices = selectedDevTargetServices(manifest, options.serviceId);
@@ -2909,15 +2938,16 @@ export async function runDeployCommand(config: UniDeskConfig | null, args: strin
return applyJob(config, args, options); return applyJob(config, args, options);
} }
if (config === null) throw new Error("deploy local manifest mode requires config.json"); if (config === null) throw new Error("deploy local manifest mode requires config.json");
const manifest = resolveManifestCommits(await readDeployManifest(options.file), options.serviceId); const rawManifest = await readDeployManifest(options.file);
if (action === "apply") {
const blocked = blockedD601MaintenanceDeployServices(config, rawManifest, options.serviceId);
if (blocked.length > 0) throw new Error(d601MaintenanceDeployBlockMessage(blocked));
}
const manifest = resolveManifestCommits(rawManifest, options.serviceId);
if (action === "check" || action === "plan") return await checkOrPlan(config, manifest, options, action); if (action === "check" || action === "plan") return await checkOrPlan(config, manifest, options, action);
const prodArtifactConsumers = selectedEnvironmentServices(manifest, options.serviceId) const prodArtifactConsumers = selectedEnvironmentServices(manifest, options.serviceId)
.filter((service) => manifest.environment !== "dev" && prodForbiddenTargetSideBuildServiceIds.has(service.id)); .filter((service) => manifest.environment !== "dev" && prodForbiddenTargetSideBuildServiceIds.has(service.id));
if (prodArtifactConsumers.length > 0) return prodArtifactConsumerLocalManifestResult(prodArtifactConsumers); if (prodArtifactConsumers.length > 0) return prodArtifactConsumerLocalManifestResult(prodArtifactConsumers);
if (!options.dryRun) {
const blocked = blockedD601MaintenanceDeployServices(config, manifest, options.serviceId);
if (blocked.length > 0) throw new Error(d601MaintenanceDeployBlockMessage(blocked));
}
if (options.dryRun || options.runNow) return await runApplyNow(config, manifest, options); if (options.dryRun || options.runNow) return await runApplyNow(config, manifest, options);
return applyJob(config, args, options); return applyJob(config, args, options);
} }
@@ -2926,5 +2956,5 @@ export async function runCodeQueueDeployCompatCommand(_config: UniDeskConfig, ar
if (args.includes("--skip-build")) throw new Error("codex deploy is disabled; --skip-build is not supported"); if (args.includes("--skip-build")) throw new Error("codex deploy is disabled; --skip-build is not supported");
const providerId = optionValue(args, ["--provider-id", "--provider"]) ?? "D601"; const providerId = optionValue(args, ["--provider-id", "--provider"]) ?? "D601";
if (providerId !== "D601") throw new Error(`codex deploy compatibility path only supports D601; got ${providerId}`); if (providerId !== "D601") throw new Error(`codex deploy compatibility path only supports D601; got ${providerId}`);
throw new Error("codex deploy is disabled because D601 maintenance-channel direct deployment must not deploy Code Queue. Current dev automation is CI-only; use ci run-dev-e2e for dev smoke verification."); throw new Error("codex deploy is disabled because D601 maintenance-channel direct deployment must not deploy Code Queue. Use the dev-only artifact consumer with deploy apply --env dev --service code-queue or artifact-registry deploy-service --env dev --service code-queue; production Code Queue artifact deployment is unsupported.");
} }
+11
View File
@@ -39,6 +39,14 @@ const codeQueueRequiredKinds = new Set([
"Deployment/code-queue-read-dev", "Deployment/code-queue-read-dev",
"Deployment/code-queue-write-dev", "Deployment/code-queue-write-dev",
]); ]);
const mdtodoRequiredKinds = new Set([
"Service/mdtodo-dev",
"Deployment/mdtodo-dev",
]);
const claudeqqRequiredKinds = new Set([
"Service/claudeqq-dev",
"Deployment/claudeqq-dev",
]);
interface ManifestDocument { interface ManifestDocument {
index: number; index: number;
@@ -172,6 +180,8 @@ function parseManifestDocuments(text: string): ManifestDocument[] {
function requiredResourcesFor(resources: string[]): Set<string> { function requiredResourcesFor(resources: string[]): Set<string> {
const resourceSet = new Set(resources); const resourceSet = new Set(resources);
if (resourceSet.has("Deployment/code-queue-scheduler-dev") || resourceSet.has("Service/code-queue-scheduler-dev")) return codeQueueRequiredKinds; if (resourceSet.has("Deployment/code-queue-scheduler-dev") || resourceSet.has("Service/code-queue-scheduler-dev")) return codeQueueRequiredKinds;
if (resourceSet.has("Deployment/mdtodo-dev") || resourceSet.has("Service/mdtodo-dev")) return mdtodoRequiredKinds;
if (resourceSet.has("Deployment/claudeqq-dev") || resourceSet.has("Service/claudeqq-dev")) return claudeqqRequiredKinds;
if (resourceSet.has("Deployment/backend-core-dev") || resourceSet.has("Deployment/frontend-dev")) return coreRequiredKinds; if (resourceSet.has("Deployment/backend-core-dev") || resourceSet.has("Deployment/frontend-dev")) return coreRequiredKinds;
return foundationRequiredKinds; return foundationRequiredKinds;
} }
@@ -301,6 +311,7 @@ function devEnvHelp(): Record<string, unknown> {
checks: [ checks: [
"all namespaced resources must target unidesk-dev", "all namespaced resources must target unidesk-dev",
"required foundation resources, backend-core-dev/frontend-dev resources, or code-queue-dev resources must exist", "required foundation resources, backend-core-dev/frontend-dev resources, or code-queue-dev resources must exist",
"mdtodo-dev and claudeqq-dev service manifests may be validated independently when those dev workload manifests are selected",
"dev DATABASE_URL values must target postgres-dev/unidesk_dev and not production routes", "dev DATABASE_URL values must target postgres-dev/unidesk_dev and not production routes",
"--kubectl-dry-run optionally asks kubectl to client-dry-run the manifest without applying it", "--kubectl-dry-run optionally asks kubectl to client-dry-run the manifest without applying it",
"prewarm-images imports dev foundation images from Docker into native k3s containerd on D601", "prewarm-images imports dev foundation images from Docker into native k3s containerd on D601",
+11 -4
View File
@@ -36,12 +36,12 @@ export function rootHelp(): unknown {
{ command: "decision list [--type ...] [--status ...] [--level ...] [--linked-goal-id id] [--limit N]", description: "List Decision Center records through the user-service proxy." }, { command: "decision list [--type ...] [--status ...] [--level ...] [--linked-goal-id id] [--limit N]", description: "List Decision Center records through the user-service proxy." },
{ command: "decision requirement list|upsert [--id id] [--title text] [--body-file path] [--type goal|decision|blocker|debt|experiment]", description: "Manage requirement records over the existing records model, excluding meeting records." }, { command: "decision requirement list|upsert [--id id] [--title text] [--body-file path] [--type goal|decision|blocker|debt|experiment]", description: "Manage requirement records over the existing records model, excluding meeting records." },
{ command: "decision show <id>", description: "Show one Decision Center record." }, { command: "decision show <id>", description: "Show one Decision Center record." },
{ command: "deploy check|plan|apply [--file deploy.json|--env dev|prod] [--service id] [--commit full-sha] [--dry-run] [--force]", description: "Reconcile services from a repo+commit manifest; --env reads origin/master:deploy.json environments and applies supported dev target-side rollouts or reviewed D601 registry artifact consumers." }, { command: "deploy check|plan|apply [--file deploy.json|--env dev|prod] [--service id] [--commit full-sha] [--dry-run] [--force]", description: "Reconcile services from a repo+commit manifest; --env reads origin/master:deploy.json environments and applies supported dev target-side rollouts or reviewed D601 registry artifact consumers. code-queue artifact consumption is dev-only." },
{ command: "dev-env validate|prewarm-images", description: "Validate D601 unidesk-dev guardrails or prewarm dev foundation images into native k3s containerd through a bounded async job." }, { command: "dev-env validate|prewarm-images", description: "Validate D601 unidesk-dev guardrails or prewarm dev foundation images into native k3s containerd through a bounded async job." },
{ command: "artifact-registry plan|render|status|health|install|deploy-backend-core|deploy-service", description: "Manage the D601 host-managed CNCF Distribution registry and run pull-only artifact CD for supported services; deploy-backend-core is a deprecated compatibility name." }, { command: "artifact-registry plan|render|status|health|install|deploy-backend-core|deploy-service", description: "Manage the D601 host-managed CNCF Distribution registry and run pull-only artifact CD for supported services, including k3s-managed dev/prod consumers and code-queue dev-only validation." },
{ command: "schedule list|get|runs|run|delete", description: "Manage backend-core scheduled tasks and run history; schedule run <id> supports --wait-ms N." }, { command: "schedule list|get|runs|run|delete", description: "Manage backend-core scheduled tasks and run history; schedule run <id> supports --wait-ms N." },
{ command: "schedule upsert-pgdata-backup [--time HH:MM] [--remote-base /SERVER_DATA/UNIDESK_PG_DATA]", description: "Create or update the daily PGDATA physical backup task that uploads monthly rotated archives to Baidu Netdisk." }, { command: "schedule upsert-pgdata-backup [--time HH:MM] [--remote-base /SERVER_DATA/UNIDESK_PG_DATA]", description: "Create or update the daily PGDATA physical backup task that uploads monthly rotated archives to Baidu Netdisk." },
{ command: "codex deploy <commitId> [--provider-id D601] [--timeout-ms N]", description: "Compatibility wrapper for deploy apply --service code-queue with a temporary repo+commit manifest." }, { command: "codex deploy <commitId> [--provider-id D601] [--timeout-ms N]", description: "Disabled legacy Code Queue deploy path; use the dev-only artifact consumer instead." },
{ command: "codex submit [prompt] [--prompt-file path|--prompt-stdin] [--queue queueId] [--provider-id id] [--cwd path] [--model model] [--execution-mode mode] [--max-attempts N] [--reference-task-id id] [--dry-run]", description: "Submit a Code Queue task through backend-core -> code-queue proxy; --dry-run shows the structured request without enqueueing." }, { command: "codex submit [prompt] [--prompt-file path|--prompt-stdin] [--queue queueId] [--provider-id id] [--cwd path] [--model model] [--execution-mode mode] [--max-attempts N] [--reference-task-id id] [--dry-run]", description: "Submit a Code Queue task through backend-core -> code-queue proxy; --dry-run shows the structured request without enqueueing." },
{ command: "codex task <taskId> [--trace --tail|--from-start|--after-seq N|--before-seq N --limit N] [--full]", description: "Fetch a compact Code Queue task summary; trace rows are opt-in and paged with next/previous commands to avoid output explosion." }, { command: "codex task <taskId> [--trace --tail|--from-start|--after-seq N|--before-seq N --limit N] [--full]", description: "Fetch a compact Code Queue task summary; trace rows are opt-in and paged with next/previous commands to avoid output explosion." },
{ command: "codex tasks [--queue id] [--limit N] [--unread-only]", description: "Show the current running, unread terminal, and recent completed Code Queue tasks in one JSON view." }, { command: "codex tasks [--queue id] [--limit N] [--unread-only]", description: "Show the current running, unread terminal, and recent completed Code Queue tasks in one JSON view." },
@@ -183,6 +183,7 @@ function codexHelp(): unknown {
command: "codex deploy|submit|task|tasks|output|judge|interrupt|cancel|queues|queue|move", command: "codex deploy|submit|task|tasks|output|judge|interrupt|cancel|queues|queue|move",
output: "json", output: "json",
usage: [ usage: [
"bun scripts/cli.ts codex deploy <commitId> # disabled legacy deployment entry",
"bun scripts/cli.ts codex submit [prompt] [--prompt-file path|--prompt-stdin] [--queue id] [--dry-run]", "bun scripts/cli.ts codex submit [prompt] [--prompt-file path|--prompt-stdin] [--queue id] [--dry-run]",
"bun scripts/cli.ts codex task <taskId> [--trace --tail|--from-start|--after-seq N|--before-seq N --limit N] [--full]", "bun scripts/cli.ts codex task <taskId> [--trace --tail|--from-start|--after-seq N|--before-seq N --limit N] [--full]",
"bun scripts/cli.ts codex tasks [--queue id] [--limit N] [--unread-only]", "bun scripts/cli.ts codex tasks [--queue id] [--limit N] [--unread-only]",
@@ -269,6 +270,11 @@ function artifactRegistryHelp(): unknown {
"bun scripts/cli.ts artifact-registry deploy-service --env prod --service oa-event-flow --commit <full-sha> [--dry-run] [--run-now] [--provider-id D601]", "bun scripts/cli.ts artifact-registry deploy-service --env prod --service oa-event-flow --commit <full-sha> [--dry-run] [--run-now] [--provider-id D601]",
"bun scripts/cli.ts artifact-registry deploy-service --env prod --service code-queue-mgr --commit <full-sha> --dry-run [--provider-id D601]", "bun scripts/cli.ts artifact-registry deploy-service --env prod --service code-queue-mgr --commit <full-sha> --dry-run [--provider-id D601]",
"bun scripts/cli.ts artifact-registry deploy-service --env prod --service todo-note --commit <full-sha> [--dry-run] [--run-now] [--provider-id D601]", "bun scripts/cli.ts artifact-registry deploy-service --env prod --service todo-note --commit <full-sha> [--dry-run] [--run-now] [--provider-id D601]",
"bun scripts/cli.ts artifact-registry deploy-service --env dev --service mdtodo --commit <full-sha> [--dry-run] [--run-now] [--provider-id D601]",
"bun scripts/cli.ts artifact-registry deploy-service --env prod --service mdtodo --commit <full-sha> [--dry-run] [--run-now] [--provider-id D601]",
"bun scripts/cli.ts artifact-registry deploy-service --env dev --service claudeqq --commit <full-sha> [--dry-run] [--run-now] [--provider-id D601]",
"bun scripts/cli.ts artifact-registry deploy-service --env prod --service claudeqq --commit <full-sha> [--dry-run] [--run-now] [--provider-id D601]",
"bun scripts/cli.ts artifact-registry deploy-service --env dev --service code-queue --commit <full-sha> [--dry-run] [--run-now] [--provider-id D601]",
], ],
description: "Manage the declaration, rendered files and readonly checks for the D601 host-managed CNCF Distribution artifact registry.", description: "Manage the declaration, rendered files and readonly checks for the D601 host-managed CNCF Distribution artifact registry.",
boundary: [ boundary: [
@@ -276,7 +282,8 @@ function artifactRegistryHelp(): unknown {
"service is host-managed by systemd + Docker Compose, not k3s-managed", "service is host-managed by systemd + Docker Compose, not k3s-managed",
"install writes the rendered host unit/config and starts the registry", "install writes the rendered host unit/config and starts the registry",
"deploy-backend-core only pulls commit-pinned backend-core artifacts and does not build backend-core on the master server", "deploy-backend-core only pulls commit-pinned backend-core artifacts and does not build backend-core on the master server",
"deploy-service currently supports backend-core, baidu-netdisk, prod/dev frontend, decision-center, project-manager, oa-event-flow, code-queue-mgr, and todo-note as standardized consumers; code-queue-mgr prod live apply remains supervisor-gated", "deploy-service currently supports backend-core, baidu-netdisk, prod/dev frontend, decision-center, mdtodo, claudeqq, project-manager, oa-event-flow, code-queue-mgr, todo-note, findjob, pipeline, met-nonlinear, k3sctl-adapter, and dev-only code-queue as standardized consumers",
"code-queue has no prod artifact deploy target and prod requests return structured unsupported",
"status and health use provider-gateway Host SSH readonly checks", "status and health use provider-gateway Host SSH readonly checks",
], ],
legacyEntrypoints: { legacyEntrypoints: {
@@ -41,7 +41,7 @@ services:
K3SCTL_NATIVE_SERVICE_URL_MDTODO: "${K3SCTL_NATIVE_SERVICE_URL_MDTODO:-}" K3SCTL_NATIVE_SERVICE_URL_MDTODO: "${K3SCTL_NATIVE_SERVICE_URL_MDTODO:-}"
K3SCTL_NATIVE_SERVICE_URL_DECISION_CENTER: "${K3SCTL_NATIVE_SERVICE_URL_DECISION_CENTER:-}" K3SCTL_NATIVE_SERVICE_URL_DECISION_CENTER: "${K3SCTL_NATIVE_SERVICE_URL_DECISION_CENTER:-}"
K3SCTL_NATIVE_SERVICE_URL_DEVOPS: "${K3SCTL_NATIVE_SERVICE_URL_DEVOPS:-}" K3SCTL_NATIVE_SERVICE_URL_DEVOPS: "${K3SCTL_NATIVE_SERVICE_URL_DEVOPS:-}"
K3SCTL_MANIFEST_PATHS: "${K3SCTL_MANIFEST_PATHS:-k3s/code-queue.k3s.json,k3s/mdtodo.k3s.json,k3s/claudeqq.k3s.json,k3s/decision-center.k3s.json,k3s/dev/unidesk-dev-core.k3s.json,k3s/dev/unidesk-dev-decision-center.k3s.json}" K3SCTL_MANIFEST_PATHS: "${K3SCTL_MANIFEST_PATHS:-k3s/code-queue.k3s.json,k3s/mdtodo.k3s.json,k3s/claudeqq.k3s.json,k3s/decision-center.k3s.json,k3s/dev/unidesk-dev-core.k3s.json,k3s/dev/unidesk-dev-decision-center.k3s.json,k3s/dev/unidesk-dev-mdtodo.k3s.json,k3s/dev/unidesk-dev-claudeqq.k3s.json,k3s/dev/unidesk-dev-code-queue.k3s.json}"
K3SCTL_SERVICES_JSON: "${K3SCTL_SERVICES_JSON:-[]}" K3SCTL_SERVICES_JSON: "${K3SCTL_SERVICES_JSON:-[]}"
UNIDESK_LOG_RETENTION_BYTES: "${UNIDESK_LOG_RETENTION_BYTES:-512MiB}" UNIDESK_LOG_RETENTION_BYTES: "${UNIDESK_LOG_RETENTION_BYTES:-512MiB}"
volumes: volumes:
@@ -633,6 +633,14 @@ spec:
cp -a "$source_dir/." "$(workspaces.source.path)/user-service-artifact-repo/" cp -a "$source_dir/." "$(workspaces.source.path)/user-service-artifact-repo/"
cd "$(workspaces.source.path)/user-service-artifact-repo" cd "$(workspaces.source.path)/user-service-artifact-repo"
test -f "$dockerfile" test -f "$dockerfile"
if [ "$service_id" = "claudeqq" ]; then
test -f "$(dirname "$dockerfile")/scripts/src/server_ts/package.json"
test -d "$(dirname "$dockerfile")/scripts/src/server_ts/src"
elif [ "$service_id" = "frontend" ]; then
test -d src/components/frontend/src
else
test -d "$(dirname "$dockerfile")/src"
fi
printf '%s\n' "$prepared_commit" | tee "$(workspaces.source.path)/user-service-artifact-commit.txt" printf '%s\n' "$prepared_commit" | tee "$(workspaces.source.path)/user-service-artifact-commit.txt"
printf '%s\n' "$service_id" | tee "$(workspaces.source.path)/user-service-artifact-service-id.txt" printf '%s\n' "$service_id" | tee "$(workspaces.source.path)/user-service-artifact-service-id.txt"
printf '%s\n' "$dockerfile" | tee "$(workspaces.source.path)/user-service-artifact-dockerfile.txt" printf '%s\n' "$dockerfile" | tee "$(workspaces.source.path)/user-service-artifact-dockerfile.txt"
@@ -684,6 +692,10 @@ spec:
command -v docker command -v docker
docker version >/dev/null docker version >/dev/null
docker run --rm --network host rancher/mirrored-library-busybox:1.36.1 wget -q -O- "http://$registry/v2/" >/dev/null docker run --rm --network host rancher/mirrored-library-busybox:1.36.1 wget -q -O- "http://$registry/v2/" >/dev/null
build_context=.
if [ "$service_id" = "claudeqq" ]; then
build_context="$(dirname "$dockerfile")"
fi
DOCKER_BUILDKIT=0 docker build \ DOCKER_BUILDKIT=0 docker build \
--network host \ --network host \
--build-arg HTTP_PROXY=http://127.0.0.1:18789 \ --build-arg HTTP_PROXY=http://127.0.0.1:18789 \
@@ -697,7 +709,7 @@ spec:
-t "$local_image" \ -t "$local_image" \
-t "$registry_image" \ -t "$registry_image" \
-f "$dockerfile" \ -f "$dockerfile" \
. "$build_context"
actual_service="$(docker image inspect "$registry_image" --format '{{ index .Config.Labels "unidesk.ai/service-id" }}')" actual_service="$(docker image inspect "$registry_image" --format '{{ index .Config.Labels "unidesk.ai/service-id" }}')"
actual_commit="$(docker image inspect "$registry_image" --format '{{ index .Config.Labels "unidesk.ai/source-commit" }}')" actual_commit="$(docker image inspect "$registry_image" --format '{{ index .Config.Labels "unidesk.ai/source-commit" }}')"
test "$actual_service" = "$service_id" test "$actual_service" = "$service_id"
@@ -116,6 +116,12 @@ spec:
value: "10000" value: "10000"
- name: UNIDESK_DEPLOY_SERVICE_ID - name: UNIDESK_DEPLOY_SERVICE_ID
value: "claudeqq" value: "claudeqq"
- name: UNIDESK_DEPLOY_REPO
value: "https://gitee.com/lyon1998/agent_skills"
- name: UNIDESK_DEPLOY_COMMIT
value: "replace-with-deploy-env-commit"
- name: UNIDESK_DEPLOY_REQUESTED_COMMIT
value: "replace-with-deploy-env-commit"
volumeMounts: volumeMounts:
- name: config-json - name: config-json
mountPath: /app/config.json mountPath: /app/config.json
@@ -0,0 +1,37 @@
{
"apiVersion": "unidesk.ai/k3s/v1",
"kind": "ManagedKubernetesService",
"metadata": {
"name": "claudeqq-dev",
"namespace": "unidesk-dev"
},
"spec": {
"adapterServiceId": "k3sctl-adapter",
"controlPlane": {
"type": "kubernetes",
"cluster": "unidesk-k3s",
"context": "unidesk-k3s"
},
"route": {
"kind": "kubernetes-service",
"serviceName": "claudeqq-dev",
"servicePort": 3290
},
"activeInstanceId": "D601-dev-claudeqq",
"singleWriter": true,
"expectedNodeIds": [
"D601"
],
"instances": [
{
"id": "D601-dev-claudeqq",
"nodeId": "D601",
"role": "primary",
"baseUrl": "kubernetes://unidesk-dev/services/claudeqq-dev:3290",
"healthPath": "/health",
"healthMode": "service-proxy"
}
],
"requireAllInstancesHealthy": true
}
}
@@ -0,0 +1,235 @@
apiVersion: v1
kind: Service
metadata:
name: claudeqq-dev
namespace: unidesk-dev
labels:
app.kubernetes.io/name: claudeqq
app.kubernetes.io/part-of: unidesk
app.kubernetes.io/component: claudeqq
unidesk.ai/environment: dev
unidesk.ai/deployment-mode: k3sctl-managed
unidesk.ai/deploy-service-id: claudeqq
spec:
type: ClusterIP
selector:
app.kubernetes.io/name: claudeqq
app.kubernetes.io/part-of: unidesk
app.kubernetes.io/component: claudeqq
unidesk.ai/environment: dev
ports:
- name: http
port: 3290
targetPort: http
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: claudeqq-dev
namespace: unidesk-dev
labels:
app.kubernetes.io/name: claudeqq
app.kubernetes.io/part-of: unidesk
app.kubernetes.io/component: claudeqq
unidesk.ai/environment: dev
unidesk.ai/deployment-mode: k3sctl-managed
unidesk.ai/deploy-service-id: claudeqq
annotations:
unidesk.ai/deploy-ref: deploy.json#environments.dev.services.claudeqq
unidesk.ai/deploy-service-id: claudeqq
unidesk.ai/image-source: deploy-env-commit
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app.kubernetes.io/name: claudeqq
app.kubernetes.io/part-of: unidesk
app.kubernetes.io/component: claudeqq
unidesk.ai/environment: dev
template:
metadata:
labels:
app.kubernetes.io/name: claudeqq
app.kubernetes.io/part-of: unidesk
app.kubernetes.io/component: claudeqq
unidesk.ai/environment: dev
unidesk.ai/node-id: D601
unidesk.ai/deploy-service-id: claudeqq
spec:
nodeSelector:
unidesk.ai/node-id: D601
terminationGracePeriodSeconds: 30
containers:
- name: napcat
image: mlikiowa/napcat-docker:latest
imagePullPolicy: IfNotPresent
ports:
- name: napcat-http
containerPort: 3000
- name: napcat-ws
containerPort: 3001
- name: napcat-webui
containerPort: 6099
env:
- name: WEBUI_PREFIX
value: "/webui"
- name: WEBUI_TOKEN
value: "unidesk-napcat-dev"
- name: NAPCAT_UID
value: "1000"
- name: NAPCAT_GID
value: "1000"
- name: ACCOUNT
value: "763382329"
volumeMounts:
- name: napcat-qq
mountPath: /app/.config/QQ
- name: napcat-config
mountPath: /app/napcat/config
- name: napcat-cache
mountPath: /app/napcat/cache
readinessProbe:
tcpSocket:
port: napcat-http
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 12
livenessProbe:
tcpSocket:
port: napcat-http
periodSeconds: 10
timeoutSeconds: 3
failureThreshold: 12
- name: claudeqq
image: unidesk-claudeqq:dev-placeholder
imagePullPolicy: IfNotPresent
workingDir: /app/scripts/src/server_ts
command:
- node
- unidesk-adapter.cjs
ports:
- name: http
containerPort: 3290
env:
- name: CLAUDEQQ_HOST
value: "0.0.0.0"
- name: CLAUDEQQ_PORT
value: "3290"
- name: CLAUDEQQ_ADAPTER_PORT
value: "3290"
- name: CLAUDEQQ_UPSTREAM_HOST
value: "127.0.0.1"
- name: CLAUDEQQ_UPSTREAM_PORT
value: "9082"
- name: CLAUDEQQ_WORKSPACE_DIR
value: "/bot_workspace"
- name: CLAUDEQQ_AUTO_REPLY
value: "false"
- name: CLAUDEQQ_NAPCAT_HTTP_HOST
value: "127.0.0.1"
- name: CLAUDEQQ_NAPCAT_HTTP_PORT
value: "3000"
- name: CLAUDEQQ_NAPCAT_WS_HOST
value: "127.0.0.1"
- name: CLAUDEQQ_NAPCAT_WS_PORT
value: "3001"
- name: CLAUDEQQ_NAPCAT_ACCOUNT
value: "763382329"
- name: CLAUDEQQ_NAPCAT_DATA_DIR
value: "/napcat"
- name: CLAUDEQQ_NAPCAT_WEBUI_URL
value: "http://127.0.0.1:6099/webui"
- name: CLAUDEQQ_ONLINE_NOTICE_ENABLED
value: "false"
- name: CLAUDEQQ_LOGIN_MONITOR_INTERVAL_MS
value: "10000"
- name: UNIDESK_DEPLOY_SERVICE_ID
value: claudeqq
- name: UNIDESK_DEPLOY_REPO
value: https://gitee.com/lyon1998/agent_skills
- name: UNIDESK_DEPLOY_COMMIT
value: replace-with-deploy-env-commit
- name: UNIDESK_DEPLOY_REQUESTED_COMMIT
value: replace-with-deploy-env-commit
volumeMounts:
- name: config-json
mountPath: /app/config.json
readOnly: true
- name: bot-workspace
mountPath: /bot_workspace
- name: logs
mountPath: /app/logs
- name: state
mountPath: /app/.state
- name: napcat-root
mountPath: /napcat
readOnly: true
- name: napcat-shell
mountPath: /app/NapCat.Shell.Windows.OneKey
readOnly: true
readinessProbe:
httpGet:
path: /health
port: http
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 20
livenessProbe:
httpGet:
path: /health
port: http
periodSeconds: 10
timeoutSeconds: 3
failureThreshold: 12
startupProbe:
httpGet:
path: /health
port: http
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 60
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
memory: 1Gi
volumes:
- name: config-json
hostPath:
path: /home/ubuntu/.agents/skills/claudeqq/config.json
type: File
- name: bot-workspace
hostPath:
path: /home/ubuntu/.agents/skills/claudeqq-dev/bot_workspace
type: DirectoryOrCreate
- name: logs
hostPath:
path: /home/ubuntu/.agents/skills/claudeqq-dev/logs
type: DirectoryOrCreate
- name: state
hostPath:
path: /home/ubuntu/.agents/skills/claudeqq-dev/.state
type: DirectoryOrCreate
- name: napcat-root
hostPath:
path: /home/ubuntu/.agents/skills/claudeqq-dev/napcat
type: DirectoryOrCreate
- name: napcat-qq
hostPath:
path: /home/ubuntu/.agents/skills/claudeqq-dev/napcat/qq
type: DirectoryOrCreate
- name: napcat-config
hostPath:
path: /home/ubuntu/.agents/skills/claudeqq-dev/napcat/config
type: DirectoryOrCreate
- name: napcat-cache
hostPath:
path: /home/ubuntu/.agents/skills/claudeqq-dev/napcat/cache
type: DirectoryOrCreate
- name: napcat-shell
hostPath:
path: /home/ubuntu/.agents/skills/claudeqq/NapCat.Shell.Windows.OneKey
type: DirectoryOrCreate
@@ -0,0 +1,37 @@
{
"apiVersion": "unidesk.ai/k3s/v1",
"kind": "ManagedKubernetesService",
"metadata": {
"name": "code-queue-dev",
"namespace": "unidesk-dev"
},
"spec": {
"adapterServiceId": "k3sctl-adapter",
"controlPlane": {
"type": "kubernetes",
"cluster": "unidesk-k3s",
"context": "unidesk-k3s"
},
"route": {
"kind": "kubernetes-service",
"serviceName": "code-queue-scheduler-dev",
"servicePort": 4222
},
"activeInstanceId": "D601-dev-code-queue",
"singleWriter": true,
"expectedNodeIds": [
"D601"
],
"instances": [
{
"id": "D601-dev-code-queue",
"nodeId": "D601",
"role": "primary",
"baseUrl": "kubernetes://unidesk-dev/services/code-queue-scheduler-dev:4222",
"healthPath": "/health",
"healthMode": "service-proxy"
}
],
"requireAllInstancesHealthy": true
}
}
@@ -0,0 +1,37 @@
{
"apiVersion": "unidesk.ai/k3s/v1",
"kind": "ManagedKubernetesService",
"metadata": {
"name": "mdtodo-dev",
"namespace": "unidesk-dev"
},
"spec": {
"adapterServiceId": "k3sctl-adapter",
"controlPlane": {
"type": "kubernetes",
"cluster": "unidesk-k3s",
"context": "unidesk-k3s"
},
"route": {
"kind": "kubernetes-service",
"serviceName": "mdtodo-dev",
"servicePort": 4267
},
"activeInstanceId": "D601-dev-mdtodo",
"singleWriter": true,
"expectedNodeIds": [
"D601"
],
"instances": [
{
"id": "D601-dev-mdtodo",
"nodeId": "D601",
"role": "primary",
"baseUrl": "kubernetes://unidesk-dev/services/mdtodo-dev:4267",
"healthPath": "/health",
"healthMode": "service-proxy"
}
],
"requireAllInstancesHealthy": true
}
}
@@ -0,0 +1,150 @@
apiVersion: v1
kind: Service
metadata:
name: mdtodo-dev
namespace: unidesk-dev
labels:
app.kubernetes.io/name: mdtodo
app.kubernetes.io/part-of: unidesk
app.kubernetes.io/component: mdtodo
unidesk.ai/environment: dev
unidesk.ai/deployment-mode: k3sctl-managed
unidesk.ai/deploy-service-id: mdtodo
spec:
type: ClusterIP
selector:
app.kubernetes.io/name: mdtodo
app.kubernetes.io/part-of: unidesk
app.kubernetes.io/component: mdtodo
unidesk.ai/environment: dev
ports:
- name: http
port: 4267
targetPort: http
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: mdtodo-dev
namespace: unidesk-dev
labels:
app.kubernetes.io/name: mdtodo
app.kubernetes.io/part-of: unidesk
app.kubernetes.io/component: mdtodo
unidesk.ai/environment: dev
unidesk.ai/deployment-mode: k3sctl-managed
unidesk.ai/deploy-service-id: mdtodo
annotations:
unidesk.ai/deploy-ref: deploy.json#environments.dev.services.mdtodo
unidesk.ai/deploy-service-id: mdtodo
unidesk.ai/image-source: deploy-env-commit
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app.kubernetes.io/name: mdtodo
app.kubernetes.io/part-of: unidesk
app.kubernetes.io/component: mdtodo
unidesk.ai/environment: dev
template:
metadata:
labels:
app.kubernetes.io/name: mdtodo
app.kubernetes.io/part-of: unidesk
app.kubernetes.io/component: mdtodo
unidesk.ai/environment: dev
unidesk.ai/node-id: D601
unidesk.ai/deploy-service-id: mdtodo
spec:
nodeSelector:
unidesk.ai/node-id: D601
terminationGracePeriodSeconds: 15
initContainers:
- name: seed-workspace
image: rancher/mirrored-library-busybox:1.36.1
imagePullPolicy: IfNotPresent
command:
- sh
- -c
- |
set -eu
mkdir -p /workspace
if [ ! -f /workspace/dev-mdtodo.md ]; then
cat > /workspace/dev-mdtodo.md <<'EOF'
# Dev MDTODO
## R1 Dev health seed
This seeded TODO file makes the dev health check prove readable hostPath storage.
EOF
fi
volumeMounts:
- name: workspace
mountPath: /workspace
containers:
- name: mdtodo
image: unidesk-mdtodo:dev-placeholder
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 4267
env:
- name: HOST
value: "0.0.0.0"
- name: PORT
value: "4267"
- name: MDTODO_ROOT_DIR
value: "/workspace"
- name: LOG_FILE
value: /var/log/unidesk-dev/mdtodo-dev.jsonl
- name: UNIDESK_DEPLOY_SERVICE_ID
value: mdtodo
- name: UNIDESK_DEPLOY_REPO
value: https://github.com/pikasTech/unidesk
- name: UNIDESK_DEPLOY_COMMIT
value: replace-with-deploy-env-commit
- name: UNIDESK_DEPLOY_REQUESTED_COMMIT
value: replace-with-deploy-env-commit
volumeMounts:
- name: workspace
mountPath: /workspace
- name: logs
mountPath: /var/log/unidesk-dev
readinessProbe:
httpGet:
path: /health
port: http
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 18
livenessProbe:
httpGet:
path: /live
port: http
periodSeconds: 10
timeoutSeconds: 3
failureThreshold: 6
startupProbe:
httpGet:
path: /live
port: http
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 30
resources:
requests:
cpu: 50m
memory: 96Mi
limits:
memory: 512Mi
volumes:
- name: workspace
hostPath:
path: /home/ubuntu/unidesk-dev-mdtodo-workspace
type: DirectoryOrCreate
- name: logs
hostPath:
path: /home/ubuntu/cq-deploy/.state/mdtodo-dev/logs
type: DirectoryOrCreate
@@ -42,6 +42,14 @@ spec:
value: "/workspace" value: "/workspace"
- name: LOG_FILE - name: LOG_FILE
value: "/var/log/unidesk/mdtodo.jsonl" value: "/var/log/unidesk/mdtodo.jsonl"
- name: UNIDESK_DEPLOY_SERVICE_ID
value: "mdtodo"
- name: UNIDESK_DEPLOY_REPO
value: "https://github.com/pikasTech/unidesk"
- name: UNIDESK_DEPLOY_COMMIT
value: "replace-with-deploy-env-commit"
- name: UNIDESK_DEPLOY_REQUESTED_COMMIT
value: "replace-with-deploy-env-commit"
- name: UNIDESK_LOG_RETENTION_BYTES - name: UNIDESK_LOG_RETENTION_BYTES
value: "512MiB" value: "512MiB"
volumeMounts: volumeMounts:
@@ -291,7 +291,7 @@ function mergeServices(services: ManagedService[]): ManagedService[] {
} }
function readConfig(): RuntimeConfig { function readConfig(): RuntimeConfig {
const paths = manifestPaths(envString("K3SCTL_MANIFEST_PATHS", "k3s/code-queue.k3s.json,k3s/mdtodo.k3s.json,k3s/claudeqq.k3s.json,k3s/decision-center.k3s.json,k3s/dev/unidesk-dev-core.k3s.json,k3s/dev/unidesk-dev-decision-center.k3s.json")); const paths = manifestPaths(envString("K3SCTL_MANIFEST_PATHS", "k3s/code-queue.k3s.json,k3s/mdtodo.k3s.json,k3s/claudeqq.k3s.json,k3s/decision-center.k3s.json,k3s/dev/unidesk-dev-core.k3s.json,k3s/dev/unidesk-dev-decision-center.k3s.json,k3s/dev/unidesk-dev-mdtodo.k3s.json,k3s/dev/unidesk-dev-claudeqq.k3s.json,k3s/dev/unidesk-dev-code-queue.k3s.json"));
const inlineServices = parseServices(envString("K3SCTL_SERVICES_JSON", "[]")); const inlineServices = parseServices(envString("K3SCTL_SERVICES_JSON", "[]"));
const manifestServices = readManifestServices(paths); const manifestServices = readManifestServices(paths);
return { return {
@@ -89,6 +89,10 @@ const rootRealPath = resolveRealWorkspaceRoot(workspaceRoot);
const maxFiles = envNumber("MDTODO_MAX_FILES", 250); const maxFiles = envNumber("MDTODO_MAX_FILES", 250);
const recentLogs: JsonRecord[] = []; const recentLogs: JsonRecord[] = [];
const logFile = envString("LOG_FILE", envString("MDTODO_LOG_FILE", "/var/log/unidesk/mdtodo.jsonl")); const logFile = envString("LOG_FILE", envString("MDTODO_LOG_FILE", "/var/log/unidesk/mdtodo.jsonl"));
const deployServiceId = envString("UNIDESK_DEPLOY_SERVICE_ID", "mdtodo");
const deployRepo = envString("UNIDESK_DEPLOY_REPO", "");
const deployCommit = envString("UNIDESK_DEPLOY_COMMIT", "");
const deployRequestedCommit = envString("UNIDESK_DEPLOY_REQUESTED_COMMIT", deployCommit);
const logWriter = logFile const logWriter = logFile
? createHourlyJsonlWriter({ ? createHourlyJsonlWriter({
baseLogFile: logFile, baseLogFile: logFile,
@@ -592,6 +596,12 @@ function healthSnapshot(): { body: JsonRecord; status: number } {
ok: healthy, ok: healthy,
service: "mdtodo", service: "mdtodo",
startedAt, startedAt,
deploy: {
serviceId: deployServiceId,
repo: deployRepo,
commit: deployCommit,
requestedCommit: deployRequestedCommit,
},
rootDir: workspaceRoot, rootDir: workspaceRoot,
rootExists, rootExists,
writable, writable,
@@ -622,7 +632,17 @@ async function route(req: Request): Promise<Response> {
const health = healthSnapshot(); const health = healthSnapshot();
return jsonResponse(health.body, health.status); return jsonResponse(health.body, health.status);
} }
if (url.pathname === "/live") return jsonResponse({ ok: true, service: "mdtodo", startedAt }); if (url.pathname === "/live") return jsonResponse({
ok: true,
service: "mdtodo",
startedAt,
deploy: {
serviceId: deployServiceId,
repo: deployRepo,
commit: deployCommit,
requestedCommit: deployRequestedCommit,
},
});
if (url.pathname === "/logs" && req.method === "GET") return jsonResponse({ ok: true, logs: recentLogs.slice(-100) }); if (url.pathname === "/logs" && req.method === "GET") return jsonResponse({ ok: true, logs: recentLogs.slice(-100) });
if (url.pathname === "/api/files" && req.method === "GET") return jsonResponse({ ok: true, rootDir: workspaceRoot, files: listTodoFiles() }); if (url.pathname === "/api/files" && req.method === "GET") return jsonResponse({ ok: true, rootDir: workspaceRoot, files: listTodoFiles() });
if (url.pathname === "/api/content" && req.method === "GET") { if (url.pathname === "/api/content" && req.method === "GET") {