feat: add gitea actions cicd poc plan

This commit is contained in:
Codex
2026-07-05 05:50:34 +00:00
parent ab3566435c
commit 3039195c5b
4 changed files with 822 additions and 6 deletions
+488
View File
@@ -0,0 +1,488 @@
// SPEC: GH-1548 Gitea mirror/Actions visibility and controlled Docker builder POC.
// Responsibility: read-only YAML-first plan/status for the proposed CI/CD governance split.
import { existsSync, readFileSync } from "node:fs";
import { isAbsolute } from "node:path";
import { rootPath, type UniDeskConfig } from "./config";
import { renderMachine } from "./cicd-render";
import type { RenderedCliResult } from "./output";
const DEFAULT_CONFIG_PATH = "config/cicd-gitea-actions-poc.yaml";
type OutputMode = "text" | "json" | "yaml";
type Action = "plan" | "status" | "help";
interface Options {
action: Action;
configPath: string;
output: OutputMode;
targetId: string | null;
}
interface LoadedPoc {
configPath: string;
root: Record<string, unknown>;
spec: Record<string, unknown>;
errors: string[];
warnings: string[];
}
export function cicdGiteaActionsPocHelp(): unknown {
return {
command: "cicd gitea-actions-poc plan|status",
output: "text by default; use --json, --raw, or -o json|yaml for machine output",
usage: [
"bun scripts/cli.ts cicd gitea-actions-poc plan",
"bun scripts/cli.ts cicd gitea-actions-poc status",
"bun scripts/cli.ts cicd gitea-actions-poc plan --target agentrun-jd01-v02",
],
config: DEFAULT_CONFIG_PATH,
issue: "https://github.com/pikasTech/unidesk/issues/1548",
description: "Read-only P1/P2 plan for replacing branch-follower responsibilities with Gitea mirror, Gitea Actions visibility, controlled Docker/BuildKit builder plane, existing Tekton, existing Argo CD, and bounded UniDesk status while preserving env reuse.",
};
}
export async function runGiteaActionsPocCommand(_config: UniDeskConfig | null, args: string[], alias = "gitea-actions-poc"): Promise<RenderedCliResult> {
const options = parseOptions(args);
const command = `cicd ${alias}${options.action === "help" ? "" : ` ${options.action}`}`;
if (options.action === "help") return renderMachine(command, cicdGiteaActionsPocHelp(), options.output === "yaml" ? "yaml" : "json");
const loaded = loadPoc(options.configPath);
const payload = options.action === "plan" ? buildPlan(loaded, options) : buildStatus(loaded, options);
if (options.output === "json") return renderMachine(command, payload, "json", payload.ok !== false);
if (options.output === "yaml") return renderMachine(command, payload, "yaml", payload.ok !== false);
return {
ok: payload.ok !== false,
command,
renderedText: options.action === "plan" ? renderPlanHuman(payload) : renderStatusHuman(payload),
contentType: "text/plain",
};
}
function parseOptions(args: string[]): Options {
const actionToken = args[0];
const action: Action = actionToken === undefined || isHelpToken(actionToken) ? "help" : parseAction(actionToken);
const options: Options = {
action,
configPath: DEFAULT_CONFIG_PATH,
output: "text",
targetId: null,
};
for (let index = action === "help" ? 0 : 1; index < args.length; index += 1) {
const arg = args[index];
if (arg === undefined || isHelpToken(arg)) {
options.action = "help";
continue;
}
if (arg === "--json" || arg === "--raw") {
options.output = "json";
continue;
}
if (arg === "-o" || arg === "--output") {
const value = args[index + 1];
if (value === undefined) throw new Error(`${arg} requires text, json, or yaml`);
options.output = parseOutput(value, arg);
index += 1;
continue;
}
if (arg.startsWith("-o=")) {
options.output = parseOutput(arg.slice(3), "-o");
continue;
}
if (arg.startsWith("--output=")) {
options.output = parseOutput(arg.slice("--output=".length), "--output");
continue;
}
if (arg === "--config") {
const value = args[index + 1];
if (value === undefined || value.length === 0) throw new Error("--config requires a path");
options.configPath = value;
index += 1;
continue;
}
if (arg.startsWith("--config=")) {
options.configPath = arg.slice("--config=".length);
continue;
}
if (arg === "--target") {
const value = args[index + 1];
if (value === undefined || value.length === 0) throw new Error("--target requires a target id");
options.targetId = value;
index += 1;
continue;
}
if (arg.startsWith("--target=")) {
options.targetId = arg.slice("--target=".length);
continue;
}
if (arg === "--confirm") throw new Error("cicd gitea-actions-poc is read-only in GH-1548 P1/P2; --confirm is not accepted");
if (arg === "--dry-run" || arg === "--all") continue;
throw new Error(`unsupported cicd gitea-actions-poc option: ${arg}`);
}
return options;
}
function parseAction(value: string): Action {
if (value === "plan" || value === "status") return value;
if (isHelpToken(value)) return "help";
if (value === "apply" || value === "run-once" || value === "trigger-current") {
throw new Error(`cicd gitea-actions-poc ${value} is intentionally unavailable; GH-1548 first stage is read-only plan/status`);
}
throw new Error("cicd gitea-actions-poc usage: cicd gitea-actions-poc plan|status [--target <id>] [--config <path>]");
}
function parseOutput(value: string, flag: string): OutputMode {
if (value === "text" || value === "json" || value === "yaml") return value;
throw new Error(`${flag} must be text, json, or yaml`);
}
function isHelpToken(value: string): boolean {
return value === "help" || value === "--help" || value === "-h";
}
function loadPoc(configPath: string): LoadedPoc {
const absolutePath = isAbsolute(configPath) ? configPath : rootPath(configPath);
if (!existsSync(absolutePath)) throw new Error(`${configPath} does not exist`);
const root = record(Bun.YAML.parse(readFileSync(absolutePath, "utf8")), configPath);
const spec = record(root.spec, `${configPath}.spec`);
const errors: string[] = [];
const warnings: string[] = [];
validateRoot(root, spec, configPath, errors, warnings);
return { configPath, root, spec, errors, warnings };
}
function validateRoot(root: Record<string, unknown>, spec: Record<string, unknown>, configPath: string, errors: string[], warnings: string[]): void {
if (stringOrNull(root.kind) !== "CicdGiteaActionsPoc") errors.push(`${configPath}.kind must be CicdGiteaActionsPoc`);
const scope = optionalRecord(spec.scope);
if (scope?.productionFollowerReplacement !== false) errors.push(`${configPath}.spec.scope.productionFollowerReplacement must be false for first-stage POC`);
if (scope?.rolloutEnabled !== false) errors.push(`${configPath}.spec.scope.rolloutEnabled must be false for first-stage POC`);
const runtimePlane = optionalRecord(spec.runtimePlane);
if (runtimePlane?.dockerAllowed !== false) errors.push(`${configPath}.spec.runtimePlane.dockerAllowed must be false`);
if (runtimePlane?.buildAllowed !== false) errors.push(`${configPath}.spec.runtimePlane.buildAllowed must be false`);
if (runtimePlane?.dockerSocketAllowed !== false) errors.push(`${configPath}.spec.runtimePlane.dockerSocketAllowed must be false`);
const buildPlane = optionalRecord(spec.buildPlane);
if (buildPlane?.dockerAllowed !== true) errors.push(`${configPath}.spec.buildPlane.dockerAllowed must be true for the controlled builder POC`);
if (buildPlane?.forbidMasterServer !== true) errors.push(`${configPath}.spec.buildPlane.forbidMasterServer must be true`);
if (buildPlane?.forbidRuntimeNode !== true) errors.push(`${configPath}.spec.buildPlane.forbidRuntimeNode must be true`);
const reuse = optionalRecord(spec.reuse);
if (reuse?.p0NoRegression !== true) errors.push(`${configPath}.spec.reuse.p0NoRegression must be true`);
if (reuse?.ciConsumptionRequired !== true) errors.push(`${configPath}.spec.reuse.ciConsumptionRequired must be true`);
const decisions = stringArray(reuse?.requiredDecisions);
if (!decisions.includes("skipImageBuild")) errors.push(`${configPath}.spec.reuse.requiredDecisions must include skipImageBuild`);
if (!decisions.includes("reuseEnvImage")) errors.push(`${configPath}.spec.reuse.requiredDecisions must include reuseEnvImage`);
const targets = arrayRecords(spec.targets);
if (targets.length === 0) errors.push(`${configPath}.spec.targets must declare at least one POC target`);
const enabledTargets = targets.filter((target) => target.enabled !== false);
if (enabledTargets.length === 0) warnings.push(`${configPath}.spec.targets has no enabled target`);
if (arrayRecords(spec.componentSurvey).length === 0) warnings.push(`${configPath}.spec.componentSurvey is empty; component maturity evidence will be invisible`);
}
function buildPlan(loaded: LoadedPoc, options: Options): Record<string, unknown> {
const targets = selectedTargets(loaded, options);
const scope = optionalRecord(loaded.spec.scope);
return {
ok: loaded.errors.length === 0 && targets.errors.length === 0,
action: "plan",
configPath: loaded.configPath,
issue: stringOrNull(optionalRecord(loaded.root.metadata)?.issue),
specRef: stringOrNull(optionalRecord(loaded.root.metadata)?.specRef),
phase: stringOrNull(scope?.phase),
rolloutEnabled: scope?.rolloutEnabled === true,
productionFollowerReplacement: scope?.productionFollowerReplacement === true,
sourceAuthority: compactSourceAuthority(optionalRecord(loaded.spec.sourceAuthority)),
planes: [
compactRuntimePlane(optionalRecord(loaded.spec.runtimePlane)),
compactBuildPlane(optionalRecord(loaded.spec.buildPlane)),
],
reuse: compactReuse(optionalRecord(loaded.spec.reuse)),
targets: targets.items.map(compactTarget),
stages: arrayRecords(loaded.spec.stages).map(compactStage),
componentSurvey: arrayRecords(loaded.spec.componentSurvey).map(compactComponent),
statusProjection: compactStatusProjection(optionalRecord(loaded.spec.statusProjection)),
budgets: loaded.spec.budgets ?? null,
errors: [...loaded.errors, ...targets.errors],
warnings: loaded.warnings,
valuesRedacted: true,
next: nextCommands(loaded, targets.items[0]),
};
}
function buildStatus(loaded: LoadedPoc, options: Options): Record<string, unknown> {
const plan = buildPlan(loaded, options);
const targets = arrayRecords(plan.targets);
return {
...plan,
action: "status",
statusSource: "config-only",
statusMode: "declared-poc-not-applied",
checks: targets.map((target) => ({
target: target.id,
source: "declared",
giteaMirror: "not-applied",
actionsRun: "not-applied",
tekton: "existing-component",
builderPlane: "declared-controlled-docker",
argo: "existing-component",
runtimePlane: "zero-docker-required",
reuse: "p0-required-not-yet-proven-in-poc",
})),
};
}
function selectedTargets(loaded: LoadedPoc, options: Options): { items: Record<string, unknown>[]; errors: string[] } {
const targets = arrayRecords(loaded.spec.targets);
if (options.targetId === null) return { items: targets, errors: [] };
const selected = targets.filter((target) => stringOrNull(target.id) === options.targetId);
return selected.length > 0 ? { items: selected, errors: [] } : { items: [], errors: [`target ${options.targetId} not found in ${loaded.configPath}`] };
}
function compactSourceAuthority(value: Record<string, unknown> | null): Record<string, unknown> {
const mirror = optionalRecord(value?.giteaMirror);
return {
mode: stringOrNull(value?.mode),
allowMutableBranchAsCiSource: value?.allowMutableBranchAsCiSource === true,
allowHostWorktree: value?.allowHostWorktree === true,
existingMirrorRef: stringOrNull(value?.existingMirrorRef),
giteaMirrorEnabledForPoc: mirror?.enabledForPoc === true,
giteaInternalBaseUrl: stringOrNull(mirror?.internalBaseUrl),
snapshotRefPrefix: stringOrNull(mirror?.snapshotRefPrefix),
repositories: arrayRecords(mirror?.repositories).map((repo) => `${repo.repository ?? "-"}@${repo.upstreamBranch ?? "-"}`),
};
}
function compactRuntimePlane(value: Record<string, unknown> | null): Record<string, unknown> {
return {
plane: "runtime",
dockerAllowed: value?.dockerAllowed === true,
buildAllowed: value?.buildAllowed === true,
dockerSocketAllowed: value?.dockerSocketAllowed === true,
hostWorktreeAllowed: value?.hostWorktreeAllowed === true,
sourceAuthority: stringOrNull(value?.sourceAuthority),
deployMode: stringOrNull(value?.deployMode),
statusAuthority: stringArray(value?.statusAuthority),
};
}
function compactBuildPlane(value: Record<string, unknown> | null): Record<string, unknown> {
return {
plane: "ci-build",
dockerAllowed: value?.dockerAllowed === true,
buildAllowed: value?.buildAllowed === true,
dockerScope: stringOrNull(value?.dockerScope),
mode: stringOrNull(value?.mode),
engineCandidates: stringArray(value?.engineCandidates),
selectedEngineForPoc: stringOrNull(value?.selectedEngineForPoc),
forbidMasterServer: value?.forbidMasterServer === true,
forbidRuntimeNode: value?.forbidRuntimeNode === true,
endpointRef: stringOrNull(optionalRecord(value?.endpoint)?.ref),
registryRef: stringOrNull(optionalRecord(value?.registry)?.ref),
provenanceRequired: optionalRecord(value?.provenance)?.required === true,
provenanceFields: stringArray(optionalRecord(value?.provenance)?.fields),
};
}
function compactReuse(value: Record<string, unknown> | null): Record<string, unknown> {
return {
p0NoRegression: value?.p0NoRegression === true,
sourceTruth: stringOrNull(value?.sourceTruth),
sourceRead: stringOrNull(value?.sourceRead),
existingParser: stringOrNull(value?.existingParser),
existingAgentRunPlanner: stringOrNull(value?.existingAgentRunPlanner),
ciConsumptionRequired: value?.ciConsumptionRequired === true,
requiredDecisions: stringArray(value?.requiredDecisions),
requiredArtifacts: stringArray(value?.requiredArtifacts),
noRegressionChecks: stringArray(value?.noRegressionChecks),
};
}
function compactTarget(value: Record<string, unknown>): Record<string, unknown> {
return {
id: stringOrNull(value.id),
enabled: value.enabled !== false,
repository: stringOrNull(value.repository),
branch: stringOrNull(value.branch),
node: stringOrNull(value.node),
lane: stringOrNull(value.lane),
baselineSeconds: optionalRecord(value.baseline)?.currentBranchFollowerSeconds ?? null,
budgetRef: stringOrNull(optionalRecord(value.baseline)?.budgetRef),
snapshotRef: stringOrNull(optionalRecord(value.source)?.snapshotRef),
mirrorReadUrlRef: stringOrNull(optionalRecord(value.source)?.currentMirrorReadUrlRef),
workflowRef: stringOrNull(optionalRecord(value.actions)?.workflowRef),
pipelineRef: stringOrNull(optionalRecord(value.tekton)?.pipelineRef),
argoApplicationRef: stringOrNull(optionalRecord(value.argo)?.applicationRef),
runtimeNamespaceRef: stringOrNull(optionalRecord(value.runtime)?.namespaceRef),
workload: stringOrNull(optionalRecord(value.runtime)?.workload),
healthPath: stringOrNull(optionalRecord(value.closeout)?.healthPath),
requiredEvidence: stringArray(optionalRecord(value.closeout)?.requiredEvidence),
};
}
function compactStage(value: Record<string, unknown>): Record<string, unknown> {
return {
id: stringOrNull(value.id),
owner: stringOrNull(value.owner),
statusAuthority: stringOrNull(value.statusAuthority),
output: stringOrNull(value.output),
};
}
function compactComponent(value: Record<string, unknown>): Record<string, unknown> {
return {
component: stringOrNull(value.component),
role: stringOrNull(value.role),
maturity: stringOrNull(value.maturity),
directReuse: stringOrNull(value.directReuse),
docs: stringOrNull(value.docs),
risk: stringOrNull(value.risk),
};
}
function compactStatusProjection(value: Record<string, unknown> | null): Record<string, unknown> {
return {
mode: stringOrNull(value?.mode),
defaultOutputMustNotDump: value?.defaultOutputMustNotDump === true,
requiredFields: stringArray(value?.requiredFields),
drillDown: optionalRecord(value?.drillDown) ?? {},
};
}
function nextCommands(loaded: LoadedPoc, firstTarget: Record<string, unknown> | undefined): Record<string, unknown> {
const declared = optionalRecord(loaded.spec.next);
const targetId = stringOrNull(firstTarget?.id) ?? "agentrun-jd01-v02";
return {
plan: stringOrNull(declared?.plan) ?? "bun scripts/cli.ts cicd gitea-actions-poc plan",
status: stringOrNull(declared?.status) ?? "bun scripts/cli.ts cicd gitea-actions-poc status",
existingFollowerStatus: stringOrNull(declared?.existingFollowerStatus) ?? `bun scripts/cli.ts cicd branch-follower status --follower ${targetId}`,
pocIssue: stringOrNull(declared?.pocIssue),
};
}
function renderPlanHuman(payload: Record<string, unknown>): string {
const next = optionalRecord(payload.next);
const planes = arrayRecords(payload.planes);
const reuse = optionalRecord(payload.reuse);
const statusProjection = optionalRecord(payload.statusProjection);
const errors = stringArray(payload.errors);
const warnings = stringArray(payload.warnings);
return [
`CI/CD GITEA-ACTIONS POC PLAN (${payload.ok === false ? "blocked" : "ok"})`,
"",
table(["TARGET", "SOURCE", "NODE/LANE", "BASELINE", "SNAPSHOT", "TEKTON", "ARGO", "RUNTIME"], arrayRecords(payload.targets).map((target) => [
target.id,
`${target.repository ?? "-"}@${target.branch ?? "-"}`,
`${target.node ?? "-"}/${target.lane ?? "-"}`,
target.baselineSeconds === null ? "-" : `${target.baselineSeconds}s`,
target.snapshotRef,
target.pipelineRef,
target.argoApplicationRef,
target.workload,
])),
"",
"SOURCE AUTHORITY",
sourceAuthorityLine(optionalRecord(payload.sourceAuthority)),
"",
table(["PLANE", "DOCKER", "BUILDS", "MODE", "ENGINE", "MASTER", "RUNTIME_NODE", "AUTHORITY"], planes.map((plane) => [
plane.plane,
boolText(plane.dockerAllowed),
boolText(plane.buildAllowed),
plane.mode ?? plane.deployMode ?? "-",
plane.selectedEngineForPoc ?? "-",
plane.forbidMasterServer === true ? "forbidden" : "-",
plane.forbidRuntimeNode === true ? "forbidden" : "-",
plane.sourceAuthority ?? plane.endpointRef ?? "-",
])),
"",
"REUSE CONTRACT",
`source=${reuse?.sourceTruth ?? "-"} p0=${boolText(reuse?.p0NoRegression)} ciConsumption=${boolText(reuse?.ciConsumptionRequired)} decisions=${stringArray(reuse?.requiredDecisions).join(",") || "-"}`,
`artifacts=${stringArray(reuse?.requiredArtifacts).join(",") || "-"}`,
"",
table(["STAGE", "OWNER", "STATUS_AUTHORITY", "OUTPUT"], arrayRecords(payload.stages).map((stage) => [stage.id, stage.owner, stage.statusAuthority, stage.output])),
"",
table(["COMPONENT", "ROLE", "MATURITY", "DIRECT_REUSE", "RISK"], arrayRecords(payload.componentSurvey).map((component) => [component.component, component.role, component.maturity, component.directReuse, component.risk])),
"",
"STATUS FIELDS",
stringArray(statusProjection?.requiredFields).join(", ") || "-",
warnings.length === 0 ? "" : `\nWARNINGS\n${warnings.map((item) => `- ${item}`).join("\n")}`,
errors.length === 0 ? "" : `\nERRORS\n${errors.map((item) => `- ${item}`).join("\n")}`,
"",
"NEXT",
`status: ${next?.status ?? "-"}`,
`existing-follower: ${next?.existingFollowerStatus ?? "-"}`,
`issue: ${next?.pocIssue ?? payload.issue ?? "-"}`,
"",
].filter((line) => line !== "").join("\n");
}
function renderStatusHuman(payload: Record<string, unknown>): string {
const next = optionalRecord(payload.next);
const errors = stringArray(payload.errors);
return [
`CI/CD GITEA-ACTIONS POC STATUS (${payload.ok === false ? "blocked" : "declared-only"})`,
"",
`statusSource=${payload.statusSource ?? "-"} mode=${payload.statusMode ?? "-"}`,
"",
table(["TARGET", "SOURCE", "GITEA", "ACTIONS", "TEKTON", "BUILDER", "ARGO", "RUNTIME", "REUSE"], arrayRecords(payload.checks).map((check) => [
check.target,
check.source,
check.giteaMirror,
check.actionsRun,
check.tekton,
check.builderPlane,
check.argo,
check.runtimePlane,
check.reuse,
])),
errors.length === 0 ? "" : `\nERRORS\n${errors.map((item) => `- ${item}`).join("\n")}`,
"",
"NEXT",
`plan: ${next?.plan ?? "-"}`,
`existing-follower: ${next?.existingFollowerStatus ?? "-"}`,
"",
].filter((line) => line !== "").join("\n");
}
function sourceAuthorityLine(value: Record<string, unknown> | null): string {
return [
`mode=${value?.mode ?? "-"}`,
`mutableBranch=${boolText(value?.allowMutableBranchAsCiSource)}`,
`hostWorktree=${boolText(value?.allowHostWorktree)}`,
`giteaEnabled=${boolText(value?.giteaMirrorEnabledForPoc)}`,
`snapshot=${value?.snapshotRefPrefix ?? "-"}`,
].join(" ");
}
function record(value: unknown, path: string): Record<string, unknown> {
if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error(`${path} must be a YAML object`);
return value as Record<string, unknown>;
}
function optionalRecord(value: unknown): Record<string, unknown> | null {
return typeof value === "object" && value !== null && !Array.isArray(value) ? value as Record<string, unknown> : null;
}
function arrayRecords(value: unknown): Record<string, unknown>[] {
return Array.isArray(value) ? value.filter((item): item is Record<string, unknown> => typeof item === "object" && item !== null && !Array.isArray(item)) : [];
}
function stringArray(value: unknown): string[] {
return Array.isArray(value) ? value.filter((item): item is string => typeof item === "string" && item.length > 0) : [];
}
function stringOrNull(value: unknown): string | null {
return typeof value === "string" && value.length > 0 ? value : null;
}
function boolText(value: unknown): string {
return value === true ? "true" : value === false ? "false" : "-";
}
function table(headers: readonly string[], rows: readonly (readonly unknown[])[]): string {
const normalized = rows.map((row) => headers.map((_, index) => cell(row[index])));
const widths = headers.map((header, index) => Math.max(header.length, ...normalized.map((row) => row[index]?.length ?? 0)));
const format = (row: readonly string[]) => row.map((value, index) => value.padEnd(widths[index] ?? 0)).join(" ").trimEnd();
return [format(headers), format(headers.map((header) => "-".repeat(header.length))), ...normalized.map(format)].join("\n");
}
function cell(value: unknown): string {
if (value === null || value === undefined || value === "") return "-";
const text = String(value).replace(/\s+/gu, " ");
return text.length > 96 ? `${text.slice(0, 93)}...` : text;
}
+17 -4
View File
@@ -1,13 +1,26 @@
// SPEC: PJ2026-01060703 CI/CD branch follower draft-2026-07-03-p0-branch-follower.
// Responsibility: thin CI/CD top-level route entry; branch-follower logic lives in responsibility modules.
// SPEC: PJ2026-01060703 CI/CD branch follower and GH-1548 Gitea Actions POC.
// Responsibility: thin CI/CD top-level route entry; subcommand logic lives in responsibility modules.
import type { UniDeskConfig } from "./config";
import { renderMachine } from "./cicd-render";
import type { RenderedCliResult } from "./output";
import { cicdHelp as branchFollowerHelp, runCicdCommand as runBranchFollowerCommand } from "./cicd-branch-follower";
import { cicdGiteaActionsPocHelp, runGiteaActionsPocCommand } from "./cicd-gitea-actions-poc";
export function cicdHelp(): unknown {
return branchFollowerHelp();
return {
command: "cicd branch-follower|gitea-actions-poc",
output: "text by default for subcommands; top-level help is json",
subcommands: [
branchFollowerHelp(),
cicdGiteaActionsPocHelp(),
],
};
}
export async function runCicdCommand(config: UniDeskConfig | null, args: string[]): Promise<RenderedCliResult> {
return await runBranchFollowerCommand(config, args);
const top = args[0];
if (top === undefined || top === "help" || top === "--help" || top === "-h") return renderMachine("cicd", cicdHelp(), "json");
if (top === "branch-follower") return await runBranchFollowerCommand(config, args);
if (top === "gitea-actions-poc" || top === "gitea-builder-poc") return await runGiteaActionsPocCommand(config, args.slice(1), top);
throw new Error("cicd usage: cicd branch-follower|gitea-actions-poc");
}
+5 -2
View File
@@ -59,6 +59,7 @@ export function rootHelp(): unknown {
{ command: "decision show <id|docNo>", 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 origin/master:deploy.json environments; --commit overrides one reviewed artifact consumer such as frontend for release/v1 validation or rollback. code-queue artifact consumption is dev-only." },
{ command: "cicd branch-follower plan|apply|status|run-once|events|logs", description: "Deploy and inspect the YAML-first Kubernetes branch follower for HWLAB v0.3, AgentRun v0.2, and web-probe sentinel master without using host worktrees as source authority." },
{ command: "cicd gitea-actions-poc plan|status", description: "Inspect the GH-1548 Gitea mirror/Actions visibility and controlled Docker/BuildKit builder-plane POC plan while keeping runtime plane 0 Docker and env reuse as a P0 no-regression contract." },
{ 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, including D601 direct, k3s-managed, and code-queue dev-only consumers." },
{ command: "auth-broker contract|health --dry-run|credential-request --dry-run|pr-preflight --dry-run", description: "Inspect the P0 Rust auth broker and CLI adapter contract without reading token values, writing GitHub, or starting services." },
@@ -734,15 +735,17 @@ function webProbeHelpSummary(): unknown {
function cicdHelpSummary(): unknown {
return {
command: "cicd branch-follower plan|apply|status|run-once|events|logs",
command: "cicd branch-follower ... | gitea-actions-poc plan|status",
output: "text by default; use --json, --raw, or -o json|yaml for machine output",
usage: [
"bun scripts/cli.ts cicd branch-follower plan",
"bun scripts/cli.ts cicd branch-follower apply --confirm --wait",
"bun scripts/cli.ts cicd branch-follower status",
"bun scripts/cli.ts cicd branch-follower run-once --all --dry-run",
"bun scripts/cli.ts cicd gitea-actions-poc plan",
"bun scripts/cli.ts cicd gitea-actions-poc status",
],
description: "YAML-first Kubernetes branch follower for three CI/CD running planes, with K8s state and adapter drill-down visibility.",
description: "YAML-first Kubernetes branch follower plus the GH-1548 read-only Gitea mirror/Actions and controlled builder-plane POC.",
};
}