openclaw/scripts/full-release-publication-contract.d.mts
Peter Steinberger cfd219c519
fix(release): skip pending ClawHub publications and surface recovery for failed ones (#161985)
The ClawHub release planner and prepared-artifact resolver read the new public publication-state endpoint (/api/v1/packages/{name}/versions/{version}/publication). Only absent versions are republished; pending ones are skipped, and failed ones are excluded, with the recover command printed to the step summary. A 404, or a 200 without a state field, falls back to the legacy version probe.
2026-09-30 09:35:54 -07:00

208 lines
6.7 KiB
TypeScript

import type { ClawHubPublicationState } from "./lib/clawhub-publication-state.mjs";
export const FULL_RELEASE_SOURCE_ADMISSION_CONTRACT: "1";
export const FULL_RELEASE_PUBLICATION_ADMISSION_CONTRACT: "1";
export type ValidationPurpose =
| "publish"
| "diagnostic"
| "main-qualification"
| "postpublish-confidence";
export interface PublicationSelection {
route: "normal" | "prepared" | "extended-stable";
npmDistTag: "beta" | "latest" | "extended-stable";
publishOpenclawNpm: boolean;
pluginPublishScope: "selected" | "all-publishable";
plugins: string[];
windowsNodeTag?: string;
windowsNodeInstallerDigests?: Record<string, string>;
}
export interface PublicationIntent {
validationPurpose: ValidationPurpose;
publicationSelection: PublicationSelection | null;
}
export interface PublicationDispatchEnvelope extends PublicationIntent {
trustedWorkflow: { ref: string; fullRef: string; sha: string } | null;
laneInputs?: { extension_test_exclude_patterns_json?: string };
}
export interface PublicationSourceRequest extends PublicationIntent {
repository: string;
candidateSha: string;
targetContextRef: string;
tooling: { ref: string; sha: string };
workflow: { ref: string; sha: string };
runId: string;
runAttempt: number;
coverage: Record<string, string>;
}
export interface PublicationSourceFact extends PublicationSourceRequest {
kind: "openclaw.full-release-source-admission/v1";
contract: "1";
status: "source-admitted" | "not-applicable";
inventoryDigest: string | null;
projection: {
version: string;
packages: Array<{ name: string; version: string; targets: string[] }>;
platforms: unknown[];
} | null;
digest: string;
}
export function publicationSourceContract(source: string): "1" | undefined;
export function publicationSourceJson(value: unknown): string;
export function normalizePublicationIntent(
purpose: unknown,
selectionJson?: unknown,
): PublicationIntent;
export function publicationIntentInputs(intent: PublicationIntent): {
validationPurpose: ValidationPurpose;
publicationSelectionJson: string;
};
export function decodePublicationDispatchEnvelope(raw: unknown): PublicationDispatchEnvelope;
export function normalizePublicationLaneInputs(
value: unknown,
): NonNullable<PublicationDispatchEnvelope["laneInputs"]>;
export function publicationDispatchEnvelope(
trustedWorkflow: PublicationDispatchEnvelope["trustedWorkflow"],
intent: PublicationIntent,
laneInputs?: PublicationDispatchEnvelope["laneInputs"],
): string;
export function publicationSourceRequest(
env: Record<string, string | undefined>,
): PublicationSourceRequest;
export function createPublicationSourceFact(
request: PublicationSourceRequest,
inventory: unknown,
projection: { version: string; packages: unknown[]; platforms: unknown[] } | null,
): PublicationSourceFact;
export function validatePublicationSourceBinding(
record: Record<string, unknown>,
expected?: Record<string, unknown>,
): PublicationSourceFact | undefined;
export function publicationSourceReuseIdentity(
fact: PublicationSourceFact | undefined,
):
| Pick<
PublicationSourceFact,
"validationPurpose" | "publicationSelection" | "inventoryDigest" | "projection"
>
| undefined;
export type PublicationNpmObservation = {
name: string;
version: string | null;
required: boolean;
observedAt: string;
} & (
| {
outcome: "observed";
state: {
packageExists: boolean;
hasVersionHistory: boolean;
selectedVersionExists: boolean;
latestVersion: string | null;
};
}
| { outcome: "unavailable"; error: string }
);
export interface PublicationClawHubObservation {
name: string;
version: string;
observedAt: string;
state: {
packageExists: boolean;
alreadyPublished: boolean;
publication?: ClawHubPublicationState;
hasTrustedPublisher: boolean;
trustedPublisher: {
provider: string | null;
repository: string | null;
workflowFilename: string | null;
environment: string | null;
} | null;
};
}
export interface PublicationPlanningSummary {
all: Array<{
name: string;
version: string;
alreadyPublished: boolean;
publication?: ClawHubPublicationState;
}>;
candidates: string[];
skippedPublished: string[];
warnings: string[];
}
export interface PublicationObservationCollection {
sourceDigest: string;
prerequisitesCompletedAt: string;
collectionStartedAt: string;
collectionCompletedAt: string;
npm: PublicationNpmObservation[];
clawhub: PublicationClawHubObservation[];
pendingAuthority: Array<{
registry: "npm" | "clawhub";
name: string;
action: string;
status: "unresolved";
}>;
plans: {
npm: PublicationPlanningSummary;
clawhub: PublicationPlanningSummary & {
bootstrapCandidates: string[];
missingTrustedPublisher: string[];
pendingPublication?: string[];
failedPublication?: string[];
};
};
}
export interface PublicationObservations extends PublicationObservationCollection {
kind: "openclaw.full-release-publication-observations/v1";
contract: "1";
}
export interface PublicationObservationArtifact {
id: string;
name: string;
digest: string;
sizeInBytes: number;
}
export interface PublicationAdmission {
observations: PublicationObservations;
binding: {
kind: "openclaw.full-release-publication-admission/v1";
contract: "1";
repository: string;
parentRunId: string;
parentRunAttempt: number;
workflow: { path: string; event: string; ref: string; sha: string };
sourceDigest: string;
observationsDigest: string;
artifact: PublicationObservationArtifact;
admittedAt: string;
status: "admitted-for-validation";
};
}
export function publicationAdmissionContract(source: string): "1" | undefined;
export function publicationObservationJson(value: unknown): string;
export function publicationPendingAuthority(
source: PublicationSourceFact,
registry: "npm" | "clawhub",
row: {
name: string;
version: string | null;
state:
| Extract<PublicationNpmObservation, { outcome: "observed" }>["state"]
| PublicationClawHubObservation["state"];
},
): PublicationObservationCollection["pendingAuthority"][number] | null;
export function createPublicationObservations(
source: PublicationSourceFact,
observations: PublicationObservationCollection,
): PublicationObservations;
export function createPublicationAdmission(
source: PublicationSourceFact,
observations: PublicationObservations,
artifact: PublicationObservationArtifact,
admittedAt: string,
): PublicationAdmission;
export function validatePublicationAdmissionBinding(
record: Record<string, unknown>,
expected?: Record<string, unknown>,
): PublicationAdmission | null | undefined;