From 9a9cdb7fdcb6f0ca579622849f1117dd392f91f2 Mon Sep 17 00:00:00 2001 From: Codex Date: Mon, 1 Jun 2026 14:47:58 +0000 Subject: [PATCH] fix: add agentrun argo refresh command --- docs/reference/agentrun.md | 4 +- docs/reference/cli.md | 2 +- scripts/src/agentrun.ts | 93 ++++++++++++++++++++++++++++++++++++-- scripts/src/help.ts | 2 +- 4 files changed, 94 insertions(+), 7 deletions(-) diff --git a/docs/reference/agentrun.md b/docs/reference/agentrun.md index 15614e52..6105eff5 100644 --- a/docs/reference/agentrun.md +++ b/docs/reference/agentrun.md @@ -65,9 +65,11 @@ AgentRun `v0.1` 的 Tekton/Argo 控制面写操作必须通过 UniDesk 高层 CL bun scripts/cli.ts agentrun v01 control-plane status bun scripts/cli.ts agentrun v01 control-plane trigger-current --dry-run bun scripts/cli.ts agentrun v01 control-plane trigger-current --confirm +bun scripts/cli.ts agentrun v01 control-plane refresh --dry-run +bun scripts/cli.ts agentrun v01 control-plane refresh --confirm ``` -`status` 只读观察 `G14:/root/agentrun-v01` 当前 commit、对应 PipelineRun、Argo Application 和 `agentrun-v01` workload 摘要。`trigger-current` 会先把固定 source worktree 快进到 `origin/v0.1`,再以当前 commit 创建 commit-pinned PipelineRun;同名 PipelineRun 正在运行或已经成功时必须拒绝重复触发,只允许在失败态或不存在时创建。该命令只提交 CI/CD 工作,不等待完整 PipelineRun 或 rollout 完成,后续用 `status` 轮询。 +`status` 只读观察 `G14:/root/agentrun-v01` 当前 commit、对应 PipelineRun、GitOps latest、Argo Application 和 `agentrun-v01` workload 摘要,并报告 Argo revision 是否对齐 `v0.1-gitops` latest。`trigger-current` 会先把固定 source worktree 快进到 `origin/v0.1`,再以当前 commit 创建 commit-pinned PipelineRun;同名 PipelineRun 正在运行或已经成功时必须拒绝重复触发,只允许在失败态或不存在时创建。该命令只提交 CI/CD 工作,不等待完整 PipelineRun 或 rollout 完成,后续用 `status` 轮询。`refresh` 只对 `argocd/agentrun-g14-v01` 执行 hard refresh,用于 GitOps promotion 已完成但 Argo 仍停留旧 revision 时的受控同步入口;它不直接 patch runtime workload。 ## UniDesk 边界 diff --git a/docs/reference/cli.md b/docs/reference/cli.md index 3de7ae0c..e35926bb 100644 --- a/docs/reference/cli.md +++ b/docs/reference/cli.md @@ -43,7 +43,7 @@ CI/CD、GitOps、rollout、artifact 发布、PR 合并后的 DEV/PROD 滚动、P - `artifact-registry plan|render|status|health|install|deploy-backend-core|deploy-service` 管理 D601 host-managed CNCF Distribution registry 的声明、安装、只读检查和 pull-only artifact CD。该 registry 固定为 D601 loopback `127.0.0.1:5000`,由 systemd + Docker Compose 管理,位于 native k3s 故障域外;`deploy-service` 只拉取 CI 已发布的 commit-pinned 镜像、retag/recreate 或导入 native k3s,并做 live commit 验证,不构建 runtime source。`deploy-backend-core` 是 deprecated 兼容名,标准 backend-core prod CD 入口是 `deploy apply --env prod --service backend-core`。长期规则见 `docs/reference/artifact-registry.md`。 - `commander contract|plan --dry-run|smoke --dry-run|approval request --dry-run|prompt-lint --kind gpt55-pr` 是 host Codex 指挥官直管微服务 skeleton 入口。当前命令返回 `phase=source-contract`、service/API/state/bridge/prompt/trace/#20/#46/ClaudeQQ 审批边界、.state/commander/ 状态模型、dev 无 daemon smoke contract、dry-run 计划和 GPT-5.5 PR prompt 边界辅助 lint,不接 live bridge、不注入 prompt、不发送 ClaudeQQ。`approval request --dry-run` 会生成 200 字以内中文纯文本 ClaudeQQ 审批草案、`notification-path-unavailable` blocker 和授权后唯一可用的 `bun scripts/cli.ts microservice proxy claudeqq /api/push/text --method POST --body-json '' --raw` 命令;不得提示使用本机 ClaudeQQ skill、powershell 或本地 server。`prompt-lint` 支持 `--prompt-file` 与 `--stdin`,输出 `ok`、`missingClauses`、`riskLevel`、`suggestedPatchSnippet` 且不回显完整 prompt;它是 commander 辅助检查,不是业务 PR 门禁,也不改变 `codex submit` 默认行为。`plan`、`smoke` 与 `approval request` 必须带 `--dry-run`;缺少时返回 `error=dry-run-required`。长期规则见 `docs/reference/host-codex-commander.md`。 - `hwlab g14 monitor-prs [--once] [--dry-run] [--interval-seconds N] [--max-cycles N] [--timeout-seconds N]` 是当前 HWLAB G14 PR -> CI/CD -> DEV rollout 的一行式入口。普通调用创建 `.state/jobs/` 异步 job 并立刻返回 `job.id`、`statusCommand` 和 stdout/stderr 路径;后台 worker 每轮通过 UniDesk `gh pr list/preflight/merge` 监控 `pikasTech/HWLAB` base=`G14` 的 open PR,ready 时合并,然后通过 UniDesk `ssh G14:k3s` 观察 `hwlab-g14-ci-poll-`、Argo `hwlab-g14-dev` 和 DEV `/health/live`,直到 DEV `Synced/Healthy` 且 Deployment/StatefulSet ready;历史 `Completed` smoke/debug pod 不作为 rollout blocker。每次成功 DEV rollout 后,worker 会定位或创建 #7“指挥简报索引”中的北京日期每日简报 issue,并追加 CI/CD 耗时、CI/CD 关键指标、语义化上线 changelog、自动 diff 摘要、PipelineRun、GitOps revision 和 DEV 验证摘要;关键指标来自 G14 Tekton TaskRun results,固定包含 `lazy build reused: x/y`、reused services、rebuild services 和每个 service 的独立耗时/状态/backend,用于观察 lazy build 机制效果。语义化 changelog 优先从 PR body 的 `## 修改`/`## 变更`/`## Changelog` 等段落提取,diff 摘要只作为文件和统计证据保留,不替代 changelog。也可用 `hwlab g14 record-rollout --pr --source-commit ` 手动补记,手动补记同样会按 PipelineRun 采集 TaskRun 指标。状态指针按用途分离:长期监控只写 `.state/hwlab-g14/latest-monitor-job.json`,`--once` 写 `latest-once-job.json`,`--dry-run` 写 `latest-dry-run-job.json`,`--once --dry-run` 写 `latest-once-dry-run-job.json`,避免一次性收口覆盖持续监控入口。`--once --dry-run` 只做单轮监控和 merge plan,不写 GitHub、不等待 rollout。该命令禁止使用原生 `gh` 或手拼 GitHub 请求;如果 UniDesk `gh` 子命令字段或行为不够,必须先改进 `scripts/src/gh.ts` 后再使用。 -- `agentrun v01 control-plane status|trigger-current [--dry-run|--confirm]` 是 AgentRun `v0.1` 在 G14 k3s 的受控 Tekton/Argo 入口。`status` 只读汇总固定 source worktree commit、对应 commit-pinned PipelineRun、Argo Application 和 `agentrun-v01` workload;`trigger-current` 先快进 `G14:/root/agentrun-v01` 到 `origin/v0.1`,再创建 `agentrun-v01-ci-` PipelineRun。confirmed trigger 只提交 CI/CD 工作并返回后续 `status` 命令,不等待完整 PipelineRun;同名 PipelineRun 运行中或已成功时拒绝重复触发,只允许失败态重建或首次创建。AgentRun 运行时和 SPEC 事实来源仍在 AgentRun 仓库,UniDesk 只维护受控运维入口。 +- `agentrun v01 control-plane status|trigger-current|refresh [--dry-run|--confirm]` 是 AgentRun `v0.1` 在 G14 k3s 的受控 Tekton/Argo 入口。`status` 只读汇总固定 source worktree commit、对应 commit-pinned PipelineRun、GitOps latest、Argo Application 和 `agentrun-v01` workload,并报告 Argo revision 是否对齐 `v0.1-gitops` latest;`trigger-current` 先快进 `G14:/root/agentrun-v01` 到 `origin/v0.1`,再创建 `agentrun-v01-ci-` PipelineRun。confirmed trigger 只提交 CI/CD 工作并返回后续 `status` 命令,不等待完整 PipelineRun;同名 PipelineRun 运行中或已成功时拒绝重复触发,只允许失败态重建或首次创建。`refresh` 只对 `argocd/agentrun-g14-v01` 执行 hard refresh,用于 GitOps promotion 已完成但 Argo 仍停留旧 revision 时的受控同步入口;它不直接 patch runtime workload。AgentRun 运行时和 SPEC 事实来源仍在 AgentRun 仓库,UniDesk 只维护受控运维入口。 - `hwlab g14 control-plane status|apply --lane v02 [--dry-run|--confirm]` 是 HWLAB `v0.2` 加法 lane 的受控 Tekton/Argo 控制面维护入口,source commit 只来自 G14 专用 bare repo `/root/hwlab-v02-cicd.git` 的 `refs/remotes/origin/v0.2`;`/root/hwlab-v02` 只作为人工开发和短连接源码工具 workspace 被观测,dirty/stale 状态必须输出为 isolated warning 而不能阻塞 CI/CD。该入口面向 branch `v0.2`、namespace `hwlab-ci` 和 Argo application `hwlab-g14-v02`;`status` 只读汇总 pipeline、RBAC/ServiceAccount、Argo、当前 commit PipelineRun、当前 PipelineRun 的 TaskRun 条件摘要、最近 PipelineRun 摘要、活跃 PipelineRun、遗留 v02 CronJob 清理状态、commit alignment,以及 19666/19667 的 Cloud Web 静态资源和 API live 探针。TaskRun 摘要的 `performance` 字段会把超过 120s 的 build TaskRun 标为慢任务、超过 180s 标为 critical warning,用于暴露 env reuse/git mirror 命中率回归,但不作为阻断门禁。`webAssets` 必须直接给出 `readonly-rpc` 删除、sidebar/workspace/event panel 关键 CSS、`/app.js` 是否可读取和字节数、`/health/live` 与 API revision;`apiRevision` 是 cloud-api 服务自身 revision,Cloud Web 静态资源变更时允许它与 source commit 不同,不能把这种差异误判成 Cloud Web 未发布。默认只读取必要字段,禁止把完整 PipelineRun spec、Tekton 内联脚本、历史大对象或整份 CSS/HTML/JS 展开到默认输出;`apply` 先自动 fetch `/root/hwlab-v02-cicd.git` 并从 commit-pinned detached worktree 执行 render check,再经 `G14:k3s` server-side apply `tekton-v02/rbac.yaml`、`pipeline.yaml`、`argocd/project.yaml` 和 `argocd/application-v02.yaml`,confirmed apply 会删除遗留 v02 CronJob,但不会应用 runtime-v02 workload、Secret 或数据迁移。 - `hwlab g14 control-plane trigger-current --lane v02 [--dry-run|--confirm]` 是 v02 标准手动触发入口:先自动 fetch `/root/hwlab-v02-cicd.git`,解析当前 `origin/v0.2` full SHA,创建 commit-pinned `hwlab-v02-ci-poll-` PipelineRun;读 Git 走 `git-mirror-http.devops-infra.svc.cluster.local`,GitOps promotion 写 `git-mirror-write.devops-infra.svc.cluster.local`;confirmed trigger 在删除/创建 PipelineRun 前会先按当前 source commit 在 G14 临时 detached worktree 中 render,再 server-side apply v02 Tekton RBAC、Pipeline 与 Argo Application,避免 CI/CD 脚本或 runtime-ready 逻辑已合并但集群仍执行旧 Pipeline 定义;该 render 不要求固定 `/root/hwlab-v02` 工作树 clean,也不得因 `.worktree/` 或其他并行未提交修改阻塞;同名 PipelineRun 成功或运行中时拒绝重复触发,失败或不存在时才删除旧对象并重新创建。 创建 PipelineRun 前会读取 `devops-infra` mirror refs,若 `localV02` 未等于当前 source commit,则自动执行一次受控 manual `git-mirror sync` Job 并复核 ref,复核失败时停止触发,避免 Tekton `prepare-source` 已知失败;services 参数只包含 v02 runtime service matrix,`hwlab-cli` 是固定 repo 短连接源码工具,不进入 PipelineRun service build。 diff --git a/scripts/src/agentrun.ts b/scripts/src/agentrun.ts index 547dada8..30a48020 100644 --- a/scripts/src/agentrun.ts +++ b/scripts/src/agentrun.ts @@ -7,15 +7,20 @@ const sourceBranch = "v0.1"; const runtimeNamespace = "agentrun-v01"; const ciNamespace = "agentrun-ci"; const pipelineName = "agentrun-v01-ci-image-publish"; +const argoNamespace = "argocd"; +const argoApplication = "agentrun-g14-v01"; +const gitopsBranch = "v0.1-gitops"; export function agentRunHelp(): unknown { return { - command: "agentrun v01 control-plane status|trigger-current", + command: "agentrun v01 control-plane status|trigger-current|refresh", output: "json", usage: [ "bun scripts/cli.ts agentrun v01 control-plane status", "bun scripts/cli.ts agentrun v01 control-plane trigger-current --dry-run", "bun scripts/cli.ts agentrun v01 control-plane trigger-current --confirm", + "bun scripts/cli.ts agentrun v01 control-plane refresh --dry-run", + "bun scripts/cli.ts agentrun v01 control-plane refresh --confirm", ], description: "Operate AgentRun v0.1 Tekton/Argo control plane through G14 routes; trigger-current is short-return and status is read-only.", }; @@ -26,6 +31,7 @@ export async function runAgentRunCommand(config: UniDeskConfig, args: string[]): if (lane !== "v01" || group !== "control-plane") return unsupported(args); if (action === "status") return await status(config); if (action === "trigger-current") return await triggerCurrent(config, parseTriggerOptions(args.slice(3))); + if (action === "refresh") return await refresh(config, parseConfirmOptions(args.slice(3))); return unsupported(args); } @@ -34,7 +40,17 @@ interface TriggerOptions { dryRun: boolean; } +interface ConfirmOptions { + confirm: boolean; + dryRun: boolean; +} + function parseTriggerOptions(args: string[]): TriggerOptions { + return parseConfirmOptions(args); +} + +function parseConfirmOptions(args: string[]): ConfirmOptions { + if (args.includes("--confirm") && args.includes("--dry-run")) throw new Error("accepts only one of --confirm or --dry-run"); return { confirm: args.includes("--confirm"), dryRun: args.includes("--dry-run") || !args.includes("--confirm"), @@ -49,20 +65,34 @@ async function status(config: UniDeskConfig): Promise> { "git rev-parse HEAD", "printf 'originV01='", "git rev-parse origin/v0.1 2>/dev/null || true", + "printf 'gitopsLatest='", + `git ls-remote origin ${gitopsBranch} 2>/dev/null | awk '{print $1}' || true`, "git status --short --branch", ].join("\n")]); const sourceCommit = matchLine(source.stdout, "sourceCommit="); + const gitopsLatest = matchLine(source.stdout, "gitopsLatest="); const pipelineRun = sourceCommit ? pipelineRunName(sourceCommit) : null; const k3s = await capture(config, g14K3sRoute, ["script", "--", statusScript(pipelineRun)]); + const argo = parseArgoStatus(k3s.stdout); return { ok: source.exitCode === 0 && k3s.exitCode === 0, command: "agentrun v01 control-plane status", lane: "v0.1", sourceCommit, + gitopsLatest, expectedPipelineRun: pipelineRun, source: compactCapture(source), runtime: compactCapture(k3s), - next: { triggerCurrent: "bun scripts/cli.ts agentrun v01 control-plane trigger-current --confirm" }, + runtimeAlignment: { + argoRevision: argo.revision, + argoSyncStatus: argo.syncStatus, + argoHealthStatus: argo.healthStatus, + syncedToGitopsLatest: Boolean(gitopsLatest && argo.revision === gitopsLatest), + }, + next: { + triggerCurrent: "bun scripts/cli.ts agentrun v01 control-plane trigger-current --confirm", + refresh: "bun scripts/cli.ts agentrun v01 control-plane refresh --confirm", + }, }; } @@ -112,6 +142,41 @@ async function triggerCurrent(config: UniDeskConfig, options: TriggerOptions): P }; } +async function refresh(config: UniDeskConfig, options: ConfirmOptions): Promise> { + const source = await capture(config, g14SourceRoute, ["script", "--", [ + "cd /root/agentrun-v01", + "printf 'gitopsLatest='", + `git ls-remote origin ${gitopsBranch} 2>/dev/null | awk '{print $1}' || true`, + ].join("\n")]); + const gitopsLatest = matchLine(source.stdout, "gitopsLatest="); + const plan = { + lane: "v0.1", + argoNamespace, + argoApplication, + gitopsBranch, + gitopsLatest, + }; + if (options.dryRun || !options.confirm) { + return { + ok: true, + command: "agentrun v01 control-plane refresh", + dryRun: true, + plan, + next: { confirm: "bun scripts/cli.ts agentrun v01 control-plane refresh --confirm" }, + }; + } + const refreshed = await capture(config, g14K3sRoute, ["script", "--", refreshScript()]); + return { + ok: source.exitCode === 0 && refreshed.exitCode === 0, + command: "agentrun v01 control-plane refresh", + dryRun: false, + plan, + source: compactCapture(source), + refreshed: compactCapture(refreshed), + next: { status: "bun scripts/cli.ts agentrun v01 control-plane status" }, + }; +} + function statusScript(pipelineRun: string | null): string { const pr = pipelineRun ?? ""; return [ @@ -131,12 +196,20 @@ function statusScript(pipelineRun: string | null): string { "printf 'recentPipelineRuns\\n'", `kubectl -n ${ciNamespace} get pipelinerun --sort-by=.metadata.creationTimestamp -o 'custom-columns=NAME:.metadata.name,STATUS:.status.conditions[0].status,REASON:.status.conditions[0].reason,CREATED:.metadata.creationTimestamp' --no-headers 2>/dev/null | tail -n 5 || true`, "printf 'argo\\n'", - "kubectl -n argocd get application agentrun-g14-v01 -o 'jsonpath={.status.sync.revision}{\"\\t\"}{.status.sync.status}{\"\\t\"}{.status.health.status}{\"\\n\"}' 2>/dev/null || true", + `kubectl -n ${argoNamespace} get application ${argoApplication} -o 'jsonpath={.status.sync.revision}{"\\t"}{.status.sync.status}{"\\t"}{.status.health.status}{"\\n"}' 2>/dev/null || true`, "printf 'workloads\\n'", `kubectl -n ${runtimeNamespace} get deploy,sts,pod -o wide 2>/dev/null || true`, ].join("\n"); } +function refreshScript(): string { + return [ + "set -eu", + `kubectl -n ${argoNamespace} annotate application ${argoApplication} argocd.argoproj.io/refresh=hard --overwrite`, + `kubectl -n ${argoNamespace} get application ${argoApplication} -o 'jsonpath={.status.sync.revision}{"\\t"}{.status.sync.status}{"\\t"}{.status.health.status}{"\\n"}' 2>/dev/null || true`, + ].join("\n"); +} + function triggerScript(sourceCommit: string, pipelineRun: string): string { return [ "set -eu", @@ -215,6 +288,18 @@ function matchLine(text: string, prefix: string): string | null { return line ? line.slice(prefix.length).trim() || null : null; } +function parseArgoStatus(text: string): { revision: string | null; syncStatus: string | null; healthStatus: string | null } { + const lines = text.split(/\r?\n/u); + const index = lines.findIndex((line) => line.trim() === "argo"); + if (index < 0) return { revision: null, syncStatus: null, healthStatus: null }; + const [revision, syncStatus, healthStatus] = (lines[index + 1] ?? "").split("\t"); + return { + revision: revision?.trim() || null, + syncStatus: syncStatus?.trim() || null, + healthStatus: healthStatus?.trim() || null, + }; +} + function isGitSha(value: string): boolean { return /^[0-9a-f]{40}$/u.test(value); } @@ -232,6 +317,6 @@ function unsupported(args: string[]): Record { ok: false, command: `agentrun ${args.join(" ")}`.trim(), degradedReason: "unsupported-command", - message: "supported commands: agentrun v01 control-plane status|trigger-current", + message: "supported commands: agentrun v01 control-plane status|trigger-current|refresh", }; } diff --git a/scripts/src/help.ts b/scripts/src/help.ts index aaf5e9fd..d108ecf3 100644 --- a/scripts/src/help.ts +++ b/scripts/src/help.ts @@ -59,7 +59,7 @@ export function rootHelp(): unknown { { command: "gh preflight|auth|issue|pr", description: "Run safe GitHub issue and PR CRUD/lifecycle operations through REST with body-file update replace/append, comment delete, token diagnostics, PR closeout preflight, hard delete unsupported, and guarded PR merge." }, { command: "commander contract|plan --dry-run|smoke --dry-run|approval request --dry-run|prompt-lint --kind gpt55-pr", description: "Host Codex commander skeleton contract, no-daemon smoke plan, dry-run approval preview, and advisory GPT-5.5 PR prompt boundary lint without live bridges, message sends, or submit gating." }, { command: "hwlab g14 monitor-prs | hwlab g14 control-plane status|apply|trigger-current|runtime-migration|cleanup-runs|cleanup-released-pvs | hwlab g14 git-mirror status|apply|sync|flush | hwlab g14 tools-image status|build", description: "Start the G14 PR monitor, run bounded v0.2 Tekton/Argo control-plane, manual PipelineRun trigger, runtime migration, CI workspace retention, manual devops-infra git mirror/relay maintenance, or fixed HWLAB CI tools image actions through UniDesk G14 routes; long confirmed trigger/sync/flush actions return async jobs by default." }, - { command: "agentrun v01 control-plane status|trigger-current", description: "Run bounded AgentRun v0.1 Tekton/Argo status and manual PipelineRun trigger operations through UniDesk G14 routes." }, + { command: "agentrun v01 control-plane status|trigger-current|refresh", description: "Run bounded AgentRun v0.1 Tekton/Argo status, manual PipelineRun trigger, and Argo refresh operations through UniDesk G14 routes." }, { command: "hwlab cd audit --env dev | hwlab cd status --env dev | hwlab cd apply --env dev --dry-run", description: "Legacy D601 HWLAB DEV CD wrapper kept for explicit old-path diagnostics; current HWLAB rollout uses G14 GitOps." }, { command: "code-agent-sandbox", description: "Independent Code Agent Sandbox service skeleton for adapter, mode, and credential-boundary diagnostics." }, { command: "schedule list|get|runs|run|retry-run|delete", description: "Manage backend-core scheduled tasks and run history; schedule run supports --wait-ms N and retry-run reuses the failed run's schedule." },