feat: add AgentRun v0.1 control CLI
This commit is contained in:
@@ -178,6 +178,7 @@ UniDesk 是一个以主 server 为统一入口的分布式工作平台;本文
|
||||
- `bun scripts/cli.ts gh preflight|auth status|issue ...|pr list|files|diff --stat|read|view|preflight|closeout|create|edit|update|comment|merge` / `bun scripts/code-queue-pr-preflight-example.ts`:通过 REST 执行安全 GitHub issue 读写、脱敏 auth/status 诊断、body-file Markdown 写入、当日滚动简报时间线 ClaudeQQ 通知、escape 扫描、只读 cleanup-plan 和 #20 board-audit、PR changed-file/stat summary、PR 创建/评论 dry-run、REST-only 低噪声 PR title/body 编辑、PR 收口元数据观察(含 merged/closed 区分与 merge commit)、低噪声 PR 收口 preflight、guarded PR merge 与 runner PR preflight;`gh issue/pr read|view` 支持 `owner/repo#number` shorthand,`--raw|--full` 是显式完整披露别名,`gh pr diff` 仅支持 `--stat` 紧凑 JSON,`gh pr merge` 会先执行 closeout 预检并拒绝非 open、draft、冲突、非 CLEAN、失败或 pending checks 的 PR,规则见 `docs/reference/cli.md` 和 `docs/reference/code-queue-supervision.md`。
|
||||
- `bun scripts/cli.ts commander contract|plan --dry-run|smoke --dry-run|approval request --dry-run|prompt-lint --kind gpt55-pr`:查看 host Codex 指挥官直管微服务 skeleton 的 source/contract、无 daemon smoke 验证计划、.state/commander/ 状态模型、trace summary 聚合、ClaudeQQ 高风险请示草案和 GPT-5.5 PR prompt 边界辅助 lint;当前只返回 dry-run 计划和 backend-core `microservice proxy claudeqq` 授权后候选命令,不接 live bridge、不接管人工指挥官,不发送消息,`prompt-lint` 不作为业务 PR 门禁也不改变 `codex submit` 默认行为,规则见 `docs/reference/host-codex-commander.md`。
|
||||
- `bun scripts/cli.ts hwlab g14 monitor-prs`:一行启动异步监控 HWLAB base=G14 的未合并 PR;可合并时走 UniDesk `gh pr merge` 合并、监控 G14 Tekton/GitOps/Argo DEV rollout,并向 #7 索引的北京日期每日简报追加 CI/CD 耗时与上线 changelog,规则见 `docs/reference/g14.md` 与 `docs/reference/cli.md`。
|
||||
- `bun scripts/cli.ts agentrun v01 control-plane status|trigger-current [--dry-run|--confirm]`:通过 G14 route 只读观察或手动触发 AgentRun `v0.1` commit-pinned Tekton/Argo PipelineRun,规则见 `docs/reference/agentrun.md` 与 `docs/reference/cli.md`。
|
||||
- `bun scripts/cli.ts hwlab cd audit --env dev` / `status|preflight|apply --dry-run`:旧 D601 HWLAB DEV CD 指挥侧 wrapper,仅用于显式 legacy 诊断和迁移对照;当前 HWLAB DEV/PROD source/runtime truth 已迁到 G14 `/root/hwlab` 与 G14 k3s/GitOps,规则见 `docs/reference/hwlab.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 e2e;catalog/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`。
|
||||
|
||||
@@ -57,6 +57,18 @@ tran G14:k3s kubectl get pods -n agentrun-v01
|
||||
|
||||
不得把临时 NodePort、host port、pod IP、provider-gateway 业务 HTTP proxy 或一次性 port-forward 固化为 AgentRun 部署路径。任何公网入口、UniDesk/HWLAB 集成入口或跨服务访问路径,都必须先通过 AgentRun 仓库内经过审查的变更引入;UniDesk 只在后续记录对应运维入口。
|
||||
|
||||
## 受控 CI/CD 入口
|
||||
|
||||
AgentRun `v0.1` 的 Tekton/Argo 控制面写操作必须通过 UniDesk 高层 CLI 执行:
|
||||
|
||||
```bash
|
||||
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
|
||||
```
|
||||
|
||||
`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` 轮询。
|
||||
|
||||
## UniDesk 边界
|
||||
|
||||
UniDesk 是 AgentRun 的综合分布式开发和运维中心。UniDesk 可以记录:
|
||||
|
||||
@@ -6,7 +6,7 @@ CLI 可以从 `master` 快速演进,但必须兼容 `deploy.json` 固定的 CI
|
||||
|
||||
## CI/CD Control Boundary
|
||||
|
||||
CI/CD、GitOps、rollout、artifact 发布、PR 合并后的 DEV/PROD 滚动、PipelineRun 重跑/清理、Argo refresh 和运行面 retention 都必须由 UniDesk CLI 的高层子命令控制。稳定入口包括 `gh pr ...`、`hwlab g14 monitor-prs`、`deploy check|plan|apply`、`ci install|status|run|publish-*|logs`、`artifact-registry ...`、`server rebuild ...`、`dev-env ...` 和后续为特定运行面补充的同级命令。原生 `kubectl`、`argo`、`tkn`、`gh`、`curl` 或临时 shell 可以作为实现细节存在于 CLI 内部,但不能作为人工或 runner 的正式控制面。
|
||||
CI/CD、GitOps、rollout、artifact 发布、PR 合并后的 DEV/PROD 滚动、PipelineRun 重跑/清理、Argo refresh 和运行面 retention 都必须由 UniDesk CLI 的高层子命令控制。稳定入口包括 `gh pr ...`、`hwlab g14 monitor-prs`、`agentrun v01 control-plane ...`、`deploy check|plan|apply`、`ci install|status|run|publish-*|logs`、`artifact-registry ...`、`server rebuild ...`、`dev-env ...` 和后续为特定运行面补充的同级命令。原生 `kubectl`、`argo`、`tkn`、`gh`、`curl` 或临时 shell 可以作为实现细节存在于 CLI 内部,但不能作为人工或 runner 的正式控制面。
|
||||
|
||||
`ssh`/`tran <route> kubectl|logs|get|describe` 仍是 CLI 介导的低层诊断底座,用于短查询、日志尾部、只读证据和一次性故障定位。它不应承载可重复的 CI/CD 写操作:创建/删除 PipelineRun、patch Pipeline/CronJob/RBAC、annotate Argo Application、触发/回滚 rollout、修改 retention 策略或清理运行面资源,都应该先落成 `bun scripts/cli.ts ...` 子命令,再由该子命令输出结构化 dry-run、执行摘要、保护对象、后续观察命令和失败分类。
|
||||
|
||||
@@ -43,6 +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 '<payload>' --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-<short>`、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 <number> --source-commit <sha>` 手动补记,手动补记同样会按 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-<short12>` PipelineRun。confirmed trigger 只提交 CI/CD 工作并返回后续 `status` 命令,不等待完整 PipelineRun;同名 PipelineRun 运行中或已成功时拒绝重复触发,只允许失败态重建或首次创建。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 探针。`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-<short12>` 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。
|
||||
|
||||
@@ -27,6 +27,7 @@ import { runServerCleanupCommand } from "./src/server-cleanup";
|
||||
import { runHwlabCdCommand } from "./src/hwlab-cd";
|
||||
import { runHwlabG14Command } from "./src/hwlab-g14";
|
||||
import { runGcCommand } from "./src/gc";
|
||||
import { runAgentRunCommand } from "./src/agentrun";
|
||||
|
||||
const remoteOptions = extractRemoteCliOptions(process.argv.slice(2));
|
||||
const args = remoteOptions.args;
|
||||
@@ -303,6 +304,14 @@ async function main(): Promise<void> {
|
||||
return;
|
||||
}
|
||||
|
||||
if (top === "agentrun") {
|
||||
const result = await runAgentRunCommand(readConfig(), args.slice(1));
|
||||
const ok = (result as { ok?: unknown }).ok !== false;
|
||||
emitJson(commandName, result, ok);
|
||||
if (!ok) process.exitCode = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
const config = readConfig();
|
||||
const autoRemoteCiPublishPlan = autoRemoteCiPublishUserServiceDryRunPlan(config, args);
|
||||
if (autoRemoteCiPublishPlan.enabled && autoRemoteCiPublishPlan.host !== null) {
|
||||
|
||||
@@ -0,0 +1,229 @@
|
||||
import type { UniDeskConfig } from "./config";
|
||||
import { runSshCommandCapture, type SshCaptureResult } from "./ssh";
|
||||
|
||||
const g14SourceRoute = "G14:/root/agentrun-v01";
|
||||
const g14K3sRoute = "G14:k3s";
|
||||
const sourceBranch = "v0.1";
|
||||
const runtimeNamespace = "agentrun-v01";
|
||||
const ciNamespace = "agentrun-ci";
|
||||
const pipelineName = "agentrun-v01-ci-image-publish";
|
||||
|
||||
export function agentRunHelp(): unknown {
|
||||
return {
|
||||
command: "agentrun v01 control-plane status|trigger-current",
|
||||
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",
|
||||
],
|
||||
description: "Operate AgentRun v0.1 Tekton/Argo control plane through G14 routes; trigger-current is short-return and status is read-only.",
|
||||
};
|
||||
}
|
||||
|
||||
export async function runAgentRunCommand(config: UniDeskConfig, args: string[]): Promise<Record<string, unknown>> {
|
||||
const [lane, group, action] = args;
|
||||
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)));
|
||||
return unsupported(args);
|
||||
}
|
||||
|
||||
interface TriggerOptions {
|
||||
confirm: boolean;
|
||||
dryRun: boolean;
|
||||
}
|
||||
|
||||
function parseTriggerOptions(args: string[]): TriggerOptions {
|
||||
return {
|
||||
confirm: args.includes("--confirm"),
|
||||
dryRun: args.includes("--dry-run") || !args.includes("--confirm"),
|
||||
};
|
||||
}
|
||||
|
||||
async function status(config: UniDeskConfig): Promise<Record<string, unknown>> {
|
||||
const source = await capture(config, g14SourceRoute, ["script", "--", [
|
||||
"cd /root/agentrun-v01",
|
||||
"git fetch origin v0.1 >/dev/null 2>&1 || true",
|
||||
"printf 'sourceCommit='",
|
||||
"git rev-parse HEAD",
|
||||
"printf 'originV01='",
|
||||
"git rev-parse origin/v0.1 2>/dev/null || true",
|
||||
"git status --short --branch",
|
||||
].join("\n")]);
|
||||
const sourceCommit = matchLine(source.stdout, "sourceCommit=");
|
||||
const pipelineRun = sourceCommit ? pipelineRunName(sourceCommit) : null;
|
||||
const k3s = await capture(config, g14K3sRoute, ["script", "--", statusScript(pipelineRun)]);
|
||||
return {
|
||||
ok: source.exitCode === 0 && k3s.exitCode === 0,
|
||||
command: "agentrun v01 control-plane status",
|
||||
lane: "v0.1",
|
||||
sourceCommit,
|
||||
expectedPipelineRun: pipelineRun,
|
||||
source: compactCapture(source),
|
||||
runtime: compactCapture(k3s),
|
||||
next: { triggerCurrent: "bun scripts/cli.ts agentrun v01 control-plane trigger-current --confirm" },
|
||||
};
|
||||
}
|
||||
|
||||
async function triggerCurrent(config: UniDeskConfig, options: TriggerOptions): Promise<Record<string, unknown>> {
|
||||
const source = await capture(config, g14SourceRoute, ["script", "--", [
|
||||
"set -eu",
|
||||
"cd /root/agentrun-v01",
|
||||
"git fetch origin v0.1",
|
||||
"git pull --ff-only origin v0.1",
|
||||
"printf 'sourceCommit='",
|
||||
"git rev-parse HEAD",
|
||||
].join("\n")]);
|
||||
const sourceCommit = matchLine(source.stdout, "sourceCommit=");
|
||||
const pipelineRun = sourceCommit ? pipelineRunName(sourceCommit) : null;
|
||||
if (source.exitCode !== 0 || !sourceCommit || !isGitSha(sourceCommit) || !pipelineRun) {
|
||||
return { ok: false, command: "agentrun v01 control-plane trigger-current", degradedReason: "source-head-unresolved", source: compactCapture(source) };
|
||||
}
|
||||
const plan = {
|
||||
lane: "v0.1",
|
||||
sourceBranch,
|
||||
sourceCommit,
|
||||
pipelineRun,
|
||||
namespace: ciNamespace,
|
||||
pipeline: pipelineName,
|
||||
runtimeNamespace,
|
||||
};
|
||||
if (options.dryRun || !options.confirm) {
|
||||
return {
|
||||
ok: true,
|
||||
command: "agentrun v01 control-plane trigger-current",
|
||||
dryRun: true,
|
||||
plan,
|
||||
next: { confirm: "bun scripts/cli.ts agentrun v01 control-plane trigger-current --confirm" },
|
||||
};
|
||||
}
|
||||
const created = await capture(config, g14K3sRoute, ["script", "--", triggerScript(sourceCommit, pipelineRun)]);
|
||||
return {
|
||||
ok: created.exitCode === 0,
|
||||
command: "agentrun v01 control-plane trigger-current",
|
||||
dryRun: false,
|
||||
plan,
|
||||
created: compactCapture(created),
|
||||
next: {
|
||||
status: "bun scripts/cli.ts agentrun v01 control-plane status",
|
||||
logs: `bun scripts/cli.ts ssh G14:k3s logs -n ${ciNamespace} -l tekton.dev/pipelineRun=${pipelineRun} --tail 120`,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function statusScript(pipelineRun: string | null): string {
|
||||
const pr = pipelineRun ?? "";
|
||||
return [
|
||||
"set -eu",
|
||||
"printf 'pipelineRun\\tstatus\\treason\\tstart\\tcompletion\\n'",
|
||||
pr.length > 0
|
||||
? `kubectl -n ${ciNamespace} get pipelinerun ${shQuote(pr)} -o 'jsonpath={.metadata.name}{\"\\t\"}{.status.conditions[0].status}{\"\\t\"}{.status.conditions[0].reason}{\"\\t\"}{.status.startTime}{\"\\t\"}{.status.completionTime}{\"\\n\"}' 2>/dev/null || true`
|
||||
: "true",
|
||||
"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",
|
||||
"printf 'workloads\\n'",
|
||||
`kubectl -n ${runtimeNamespace} get deploy,sts,pod -o wide 2>/dev/null || true`,
|
||||
].join("\n");
|
||||
}
|
||||
|
||||
function triggerScript(sourceCommit: string, pipelineRun: string): string {
|
||||
return [
|
||||
"set -eu",
|
||||
"cd /root/agentrun-v01",
|
||||
`if kubectl -n ${ciNamespace} get pipelinerun ${shQuote(pipelineRun)} >/dev/null 2>&1; then`,
|
||||
` existing_status="$(kubectl -n ${ciNamespace} get pipelinerun ${shQuote(pipelineRun)} -o 'jsonpath={.status.conditions[0].status}:{.status.conditions[0].reason}' 2>/dev/null || true)"`,
|
||||
" case \"$existing_status\" in",
|
||||
" False:*)",
|
||||
" printf 'deleteExisting=%s\\n' \"$existing_status\"",
|
||||
` kubectl -n ${ciNamespace} delete pipelinerun ${shQuote(pipelineRun)} --wait=true --timeout=20s`,
|
||||
" ;;",
|
||||
" *)",
|
||||
" printf 'refuseExisting=%s\\n' \"$existing_status\"",
|
||||
" printf 'reason=existing-pipelinerun-active-or-succeeded\\n'",
|
||||
" exit 20",
|
||||
" ;;",
|
||||
" esac",
|
||||
"fi",
|
||||
"kubectl apply -f deploy/templates/tekton/rbac.yaml",
|
||||
"kubectl apply -f deploy/templates/tekton/pipeline.yaml",
|
||||
"kubectl apply -f deploy/templates/argocd/project.yaml",
|
||||
"kubectl apply -f deploy/templates/argocd/application-v01.yaml",
|
||||
"cat <<'YAML' | kubectl create -f -",
|
||||
"apiVersion: tekton.dev/v1",
|
||||
"kind: PipelineRun",
|
||||
"metadata:",
|
||||
` name: ${pipelineRun}`,
|
||||
` namespace: ${ciNamespace}`,
|
||||
"spec:",
|
||||
" pipelineRef:",
|
||||
` name: ${pipelineName}`,
|
||||
" taskRunTemplate:",
|
||||
" serviceAccountName: agentrun-v01-tekton-runner",
|
||||
" podTemplate:",
|
||||
" hostNetwork: true",
|
||||
" dnsPolicy: ClusterFirstWithHostNet",
|
||||
" securityContext:",
|
||||
" fsGroup: 1000",
|
||||
" params:",
|
||||
" - name: revision",
|
||||
` value: ${sourceCommit}`,
|
||||
" workspaces:",
|
||||
" - name: source",
|
||||
" volumeClaimTemplate:",
|
||||
" spec:",
|
||||
" accessModes: [\"ReadWriteOnce\"]",
|
||||
" resources:",
|
||||
" requests:",
|
||||
" storage: 5Gi",
|
||||
" - name: git-ssh",
|
||||
" secret:",
|
||||
" secretName: agentrun-git-ssh",
|
||||
"YAML",
|
||||
`printf 'created=${pipelineRun}\\n'`,
|
||||
].join("\n");
|
||||
}
|
||||
|
||||
async function capture(config: UniDeskConfig, target: string, args: string[]): Promise<SshCaptureResult> {
|
||||
return await runSshCommandCapture(config, target, args);
|
||||
}
|
||||
|
||||
function compactCapture(result: SshCaptureResult): Record<string, unknown> {
|
||||
return {
|
||||
exitCode: result.exitCode,
|
||||
stdoutTail: tail(result.stdout, 8000),
|
||||
stderrTail: tail(result.stderr, 4000),
|
||||
};
|
||||
}
|
||||
|
||||
function pipelineRunName(sourceCommit: string): string {
|
||||
return `agentrun-v01-ci-${sourceCommit.slice(0, 12)}`;
|
||||
}
|
||||
|
||||
function matchLine(text: string, prefix: string): string | null {
|
||||
const line = text.split(/\r?\n/u).find((item) => item.startsWith(prefix));
|
||||
return line ? line.slice(prefix.length).trim() || null : null;
|
||||
}
|
||||
|
||||
function isGitSha(value: string): boolean {
|
||||
return /^[0-9a-f]{40}$/u.test(value);
|
||||
}
|
||||
|
||||
function tail(text: string, maxChars: number): string {
|
||||
return text.length > maxChars ? text.slice(-maxChars) : text;
|
||||
}
|
||||
|
||||
function shQuote(value: string): string {
|
||||
return `'${value.replace(/'/gu, "'\\''")}'`;
|
||||
}
|
||||
|
||||
function unsupported(args: string[]): Record<string, unknown> {
|
||||
return {
|
||||
ok: false,
|
||||
command: `agentrun ${args.join(" ")}`.trim(),
|
||||
degradedReason: "unsupported-command",
|
||||
message: "supported commands: agentrun v01 control-plane status|trigger-current",
|
||||
};
|
||||
}
|
||||
@@ -2,6 +2,7 @@ import { ghHelp } from "./gh";
|
||||
import { authBrokerHelp } from "./auth-broker";
|
||||
import { hwlabHelp } from "./hwlab-cd";
|
||||
import { hwlabG14Help } from "./hwlab-g14";
|
||||
import { agentRunHelp } from "./agentrun";
|
||||
|
||||
export function rootHelp(): unknown {
|
||||
return {
|
||||
@@ -58,6 +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: "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 <id> supports --wait-ms N and retry-run reuses the failed run's schedule." },
|
||||
@@ -600,6 +602,7 @@ export function staticNamespaceHelp(args: string[]): unknown | null {
|
||||
if (top === "artifact-registry") return artifactRegistryHelp();
|
||||
if (top === "auth-broker") return authBrokerHelp();
|
||||
if (top === "gh") return ghHelp();
|
||||
if (top === "agentrun") return agentRunHelp();
|
||||
if (top === "hwlab" && sub === "g14") return hwlabG14Help();
|
||||
if (top === "hwlab") return hwlabHelp();
|
||||
return null;
|
||||
|
||||
Reference in New Issue
Block a user