feat: add AgentRun v0.1 control CLI

This commit is contained in:
Codex
2026-06-01 06:11:47 +00:00
parent 12d79a80bf
commit aa39b7582e
6 changed files with 256 additions and 1 deletions
+229
View File
@@ -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",
};
}