Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/agent-task-contracts.yml
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ jobs:
- run: npm run test:native-agent-task-interruption
- run: npm run test:trusted-apply-artifact-channel
- run: npm run test:runtime-command-artifact-bounds
- run: npm run test:recipe-declared-artifacts
- run: npm run test:redaction
- run: npm run test:browser-preview-routing
- run: npm run test:browser-routed-command-security
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@
"test:recipe-secret-env": "tsx tests/recipe-secret-env.test.ts",
"test:preview-options": "tsx tests/preview-options.test.ts",
"test:evidence-bundle-digest-and-recipe-artifact": "tsx tests/evidence-bundle-digest-and-recipe-artifact.test.ts",
"test:recipe-declared-artifacts": "tsx tests/recipe-declared-artifacts.test.ts",
"test:runtime-overlay-descriptors": "tsx tests/runtime-overlay-descriptors.test.ts",
"test:composer-package-overlay-revision": "tsx scripts/composer-backed-source-hydration-smoke.ts",
"test:composer-package-overlay-autoload-layout": "tsx scripts/composer-package-overlay-autoload-layout-smoke.ts",
Expand Down
16 changes: 9 additions & 7 deletions packages/cli/src/commands/recipe-declared-artifacts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,30 @@ import { Buffer } from "node:buffer"
import { DEFAULT_CAPTURED_ARTIFACT_MAX_BYTES, STRUCTURED_ARTIFACT_SCHEMA, TYPED_ARTIFACT_INDEX_SCHEMA, materializeStructuredArtifactFiles, redactJsonValue, workspaceRecipeRuntimeCollectedArtifacts, type ArtifactBundle, type Runtime, type StructuredArtifactPayload, type TypedArtifactRef, type WorkspaceRecipe, type WorkspaceRecipeDeclaredArtifact, type WorkspaceRecipeTypedArtifact } from "@automattic/wp-codebox-core"
import { stripUndefined } from "@automattic/wp-codebox-core/internals"
import { appendRecipeRuntimeEvidenceFiles } from "../recipe-evidence.js"
import { rewriteInputMountPath, type InputMountPathMapping } from "../input-mount-paths.js"
import { serializeRecipeRunError, RecipeDeclaredArtifactFailureError, RecipeProbeFailureError } from "./recipe-run-output.js"
import type { RecipeRunDeclaredArtifact, RecipeRunDistributionSetupArtifact, RecipeRunDistributionStartupProbe, RecipeRunFixtureDatabase, RecipeRunProbe } from "./recipe-run-types.js"

const DECLARED_ARTIFACT_CAPTURE_MAX_BYTES = DEFAULT_CAPTURED_ARTIFACT_MAX_BYTES
const declaredArtifactContents = new WeakMap<RecipeRunDeclaredArtifact, Buffer>()

export async function collectRecipeDeclaredArtifacts(recipe: WorkspaceRecipe, runtime: Runtime): Promise<RecipeRunDeclaredArtifact[]> {
export async function collectRecipeDeclaredArtifacts(recipe: WorkspaceRecipe, runtime: Runtime, inputMountPathMap: readonly InputMountPathMapping[] = []): Promise<RecipeRunDeclaredArtifact[]> {
const results: RecipeRunDeclaredArtifact[] = []
for (const { kind, index, artifact } of workspaceRecipeRuntimeCollectedArtifacts(recipe)) {
const effectivePath = rewriteInputMountPath(artifact.path, inputMountPathMap)
results.push(kind === "typed"
? await collectRecipeTypedArtifact(runtime, artifact, index)
: await collectRecipeDeclaredArtifact(runtime, artifact, index))
? await collectRecipeTypedArtifact(runtime, artifact, index, effectivePath)
: await collectRecipeDeclaredArtifact(runtime, artifact, index, effectivePath))
}
return results
}

async function collectRecipeDeclaredArtifact(runtime: Runtime, artifact: WorkspaceRecipeDeclaredArtifact, index: number): Promise<RecipeRunDeclaredArtifact> {
async function collectRecipeDeclaredArtifact(runtime: Runtime, artifact: WorkspaceRecipeDeclaredArtifact, index: number, effectivePath: string): Promise<RecipeRunDeclaredArtifact> {
const required = artifact.required !== false
try {
const execution = await runtime.execute({
command: "wordpress.run-php",
args: [`code=${declaredArtifactReadCode(artifact.path, artifact.parseJson === true, false)}`],
args: [`code=${declaredArtifactReadCode(effectivePath, artifact.parseJson === true, false)}`],
})
const collected = JSON.parse(execution.stdout.trim() || "{}") as Record<string, unknown>
const exists = collected.exists === true
Expand Down Expand Up @@ -57,11 +59,11 @@ async function collectRecipeDeclaredArtifact(runtime: Runtime, artifact: Workspa
}
}

async function collectRecipeTypedArtifact(runtime: Runtime, artifact: WorkspaceRecipeTypedArtifact, index: number): Promise<RecipeRunDeclaredArtifact> {
async function collectRecipeTypedArtifact(runtime: Runtime, artifact: WorkspaceRecipeTypedArtifact, index: number, effectivePath: string): Promise<RecipeRunDeclaredArtifact> {
try {
const execution = await runtime.execute({
command: "wordpress.run-php",
args: [`code=${declaredArtifactReadCode(artifact.path, artifact.parseJson === true, true)}`],
args: [`code=${declaredArtifactReadCode(effectivePath, artifact.parseJson === true, true)}`],
})
const collected = JSON.parse(execution.stdout.trim() || "{}") as Record<string, unknown>
const exists = collected.exists === true
Expand Down
6 changes: 3 additions & 3 deletions packages/cli/src/commands/recipe-run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,7 @@ export async function runRecipe(options: RecipeRunOptions, interruption?: Recipe
}

let evidence = await phaseTracker.run("collect_artifacts", { includeLogs: true, includeObservations: true }, async () => {
declaredArtifacts = await awaitRecipe("recipe-artifacts.collect", collectRecipeDeclaredArtifacts(recipe, runtime!))
declaredArtifacts = await awaitRecipe("recipe-artifacts.collect", collectRecipeDeclaredArtifacts(recipe, runtime!, inputMountPathMap))
const declaredArtifactFailure = recipeDeclaredArtifactFailure(declaredArtifacts)
await awaitRecipe("runtime.observe:runtime-info", runtime!.observe({ type: "runtime-info" }))
await awaitRecipe("runtime.observe:mounts", runtime!.observe({ type: "mounts" }))
Expand Down Expand Up @@ -391,7 +391,7 @@ export async function runRecipe(options: RecipeRunOptions, interruption?: Recipe
artifacts = await awaitRecipe("runtime.collect-artifacts.preview-hold", collectRecipeRuntimeArtifacts(runtime, { includeLogs: true, includeObservations: true, previewHoldSeconds: options.previewHoldSeconds }, { snapshotTimeoutMs: SUCCESSFUL_RECIPE_RUNTIME_SNAPSHOT_TIMEOUT_MS, activeExecution: executions.at(-1) }))
browserEvidence = await recipeBrowserEvidence(artifacts, executions, recipe)
await artifactPointer.update({ runtime: await runtime.info(), artifacts, phases: phaseTracker.list(), browserEvidence })
declaredArtifacts = await collectRecipeDeclaredArtifacts(recipe, runtime)
declaredArtifacts = await collectRecipeDeclaredArtifacts(recipe, runtime, inputMountPathMap)
await materializeTypedRecipeDeclaredArtifacts(artifacts, declaredArtifacts)
await appendRecipeRuntimeEvidence(artifacts, recipeRuntimeEvidenceFiles(fixtureDatabases, distributionSetupArtifacts, distributionStartupProbes, probes, declaredArtifacts))
evidence = await finalizeRecipeArtifactEvidence(artifacts, recipe, workspaceMounts, stagedFiles, effectivePolicy, secretEnvSummary)
Expand Down Expand Up @@ -520,7 +520,7 @@ export async function runRecipe(options: RecipeRunOptions, interruption?: Recipe
await artifactPointer.update({ runtime: await activeRuntime.info(), artifacts, phases: phaseTracker.list(), browserEvidence })
try {
if (declaredArtifacts.length === 0) {
declaredArtifacts = await collectRecipeDeclaredArtifacts(recipe, activeRuntime)
declaredArtifacts = await collectRecipeDeclaredArtifacts(recipe, activeRuntime, inputMountPathMap)
}
await materializeTypedRecipeDeclaredArtifacts(artifacts, declaredArtifacts)
const evidenceFiles = await appendRecipeRuntimeEvidence(artifacts, [
Expand Down
2 changes: 1 addition & 1 deletion packages/runtime-core/src/command-registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1303,7 +1303,7 @@ export const commandRegistry = [
{ name: "capture", description: "Comma-separated artifacts to capture after opening the editor.", format: "steps,console,errors,html,screenshot,editor-state,editor-validity" },
{ name: "artifact-prefix", description: "Optional artifact directory relative to the runtime artifact root for this invocation; defaults to files/browser. Use files/browser/editor-open/<name> to isolate per-fixture editor-open evidence in a batch.", format: "relative artifact directory" },
],
outputShape: "JSON summary plus files/browser/editor-steps.jsonl, editor-summary.json, editor-state.json, optional editor-validity.json, and optional console/errors/html/screenshot artifacts. When artifact-prefix is supplied, every editor-open artifact is written under that directory instead of files/browser.",
outputShape: "JSON summary with additive editorPresentation iframe stylesheet URLs and generated-presentation identities, plus files/browser/editor-steps.jsonl, editor-summary.json, editor-state.json, optional editor-validity.json, and optional console/errors/html/screenshot artifacts. When artifact-prefix is supplied, every editor-open artifact is written under that directory instead of files/browser.",
policyRequirement: "Runtime policy commands must include wordpress.editor-open.",
recipe: true,
handler: { kind: "playground", method: "runEditorOpen" },
Expand Down
11 changes: 11 additions & 0 deletions packages/runtime-playground/src/browser-artifacts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ export interface BrowserArtifactSummary {
editorValidity?: BrowserEditorValiditySummary
editorValidateBlocks?: BrowserEditorValidateBlocksSummary
editorReadiness?: BrowserEditorReadinessSummary
editorPresentation?: BrowserEditorPresentationSummary
editorSave?: BrowserEditorSaveSummary
editorCanvas?: BrowserEditorCanvasProbeSummary
editorCapabilities?: { clipboard: "unsupported" }
Expand Down Expand Up @@ -287,6 +288,16 @@ export interface BrowserEditorReadinessSummary {
postType?: string
}

export interface BrowserEditorPresentationSummary {
schema: "wp-codebox/editor-presentation/v1"
canvasDocumentType: "iframe" | "parent"
iframeCount: number
iframeStylesheetUrlCount: number
iframeStylesheetUrls: string[]
generatedPresentationIdentityCount: number
generatedPresentationIdentities: string[]
}

export interface BrowserEditorSaveSummary {
schema: "wp-codebox/editor-save/v1"
status: "saved"
Expand Down
Loading
Loading