Skip to content

chore(deps): bump minimatch in /maestro-studio/web#7

Closed
dependabot[bot] wants to merge 1 commit into
mainfrom
dependabot/npm_and_yarn/maestro-studio/web/multi-d89474293d
Closed

chore(deps): bump minimatch in /maestro-studio/web#7
dependabot[bot] wants to merge 1 commit into
mainfrom
dependabot/npm_and_yarn/maestro-studio/web/multi-d89474293d

Conversation

@dependabot

@dependabot dependabot Bot commented on behalf of github Feb 25, 2026

Copy link
Copy Markdown

Bumps and minimatch. These dependencies needed to be updated together.
Updates minimatch from 3.1.2 to 3.1.4

Commits

Updates minimatch from 5.1.6 to 5.1.8

Commits

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


Dependabot commands and options

You can trigger Dependabot actions by commenting on this PR:

  • @dependabot rebase will rebase this PR
  • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
  • @dependabot show <dependency name> ignore conditions will show all of the ignore conditions of the specified dependency
  • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    You can disable automated security fix PRs for this repo from the Security Alerts page.

Bumps  and [minimatch](https://github.com/isaacs/minimatch). These dependencies needed to be updated together.

Updates `minimatch` from 3.1.2 to 3.1.4
- [Changelog](https://github.com/isaacs/minimatch/blob/main/changelog.md)
- [Commits](isaacs/minimatch@v3.1.2...v3.1.4)

Updates `minimatch` from 5.1.6 to 5.1.8
- [Changelog](https://github.com/isaacs/minimatch/blob/main/changelog.md)
- [Commits](isaacs/minimatch@v3.1.2...v3.1.4)

---
updated-dependencies:
- dependency-name: minimatch
  dependency-version: 3.1.4
  dependency-type: indirect
- dependency-name: minimatch
  dependency-version: 5.1.8
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
@dependabot dependabot Bot added dependencies Pull requests that update a dependency file javascript Pull requests that update javascript code labels Feb 25, 2026
@dependabot @github

dependabot Bot commented on behalf of github Mar 1, 2026

Copy link
Copy Markdown
Author

Superseded by #9.

@dependabot dependabot Bot closed this Mar 1, 2026
@dependabot
dependabot Bot deleted the dependabot/npm_and_yarn/maestro-studio/web/multi-d89474293d branch March 1, 2026 13:26
cem2ran pushed a commit that referenced this pull request Jul 10, 2026
…lat per-flow bundle, device logs & crash/ANR (mobile-dev-inc#3282)

* feat(orchestra): add listener-based artifact production (Phase 0)

Adds Orchestra hooks so consumers can produce flow-debug artifacts
through a single mechanism instead of each rolling their own callback
plumbing.

New public API in maestro-orchestra:
  - OrchestraListener interface (onFlowStart, onCommandStart,
    onCommandFinished, onCommandReset, onCommandMetadataUpdate,
    onFlowEnd) with default no-op methods
  - CommandOutcome sealed type (Completed / Skipped / Warned / Failed)
  - Orchestra ctor: artifactsDir: Path? = null,
    listeners: List<OrchestraListener> = emptyList()
  - Orchestra.debugOutput: FlowDebugOutput exposed as a property

Internal in maestro-orchestra:
  - ArtifactsGenerator always installed, produces the canonical bundle
    when artifactsDir is set:
      artifactsDir/maestro.log via ScopedLogCapture
      artifactsDir/commands.json at onFlowEnd
      artifactsDir/screenshot-❌-<ts>.png on first failure
    Failure-time hierarchy capture and screenshot capture run in
    independent try/catch — either failing logs a warning, the other
    still proceeds.
  - ScreenshotUtils relocated from maestro-cli to maestro-orchestra;
    CLI keeps a thin delegate for MaestroCommandRunner backwards-compat.

New in maestro-client:
  - ScopedLogCapture: per-flow Log4j2 FileAppender with a
    maestro-only filter; attaches/detaches without reconfiguring the
    global context. Temporarily lowers the root level to ALL while
    captured, restores on close.

Co-existence: Orchestra still fires the existing lambda callbacks at
each call-point alongside the new listener dispatch, so CLI / Studio /
worker continue working unchanged. Phase 1 migrates CLI; Phase 2/3
migrate the copilot consumers. Phase 4 removes the lambda callbacks.

Tests:
  - ArtifactsGeneratorTest: independence of hierarchy + screenshot
    capture, commands.json written at onFlowEnd, no-op when
    artifactsDir is null, MaestroException populates debugOutput.exception
  - ScopedLogCaptureTest: maestro-only filter, idempotent close,
    appender detached after close
  - OrchestraListenerDispatchTest: legacy lambdas and listeners both
    fire, debugOutput exposed on Orchestra

See copilot/docs/orchestra-artifacts-refactor.md for the full plan.

* feat(cli): migrate TestSuiteInteractor to Orchestra listeners (Phase 1)

Switches `maestro test` to produce its on-disk debug bundle through
Maestro's new internal `ArtifactsGenerator` (Phase 0 API). The 80-line
inline callback block in `TestSuiteInteractor.runFlow` that previously
duplicated debug-output population now collapses to a single
`Orchestra(artifactsDir = tempDir, listeners = listOf(CliConsoleListener))`
construction. Failure-time hierarchy capture, scoped maestro.log
capture, commands.json write, and the failure screenshot are all
handled inside Maestro now.

Behavior is preserved:
  - Files in `~/.maestro/tests/<ts>/` after a flow run are byte-identical
    to today: `commands-(flow_name).json`, `screenshot-<emoji>-<ts>-(flow_name).png`,
    session-level `maestro.log` from `LogConfig.configure` (untouched).
  - `TestExecutionSummary` and `captureSteps` step results read
    `orchestra.debugOutput` instead of a local FlowDebugOutput — same data.
  - `onCommandFailed` still returns `ErrorResolution.FAIL`, so
    `orchestra.runFlow` returns false on failure exactly as before.
  - `onCommandGeneratedOutput` (AI defects) stays a separate Orchestra
    lambda — orthogonal to the listener pattern.

New files:
  - maestro-cli/.../runner/CliConsoleListener.kt: ~30 lines, single
    responsibility = the "<flow> RUNNING / COMPLETED / FAILED / …"
    console lines users see.

TestDebugReporter:
  - Adds `copyToFlatLayout(sourceDir, destDir, flowName, shardIndex?)`
    — renames Maestro's canonical files into CLI's historic flat
    layout. Used by TestSuiteInteractor after each flow.
  - Keeps `saveFlow(...)` unchanged for `TestRunner.runSingle`
    (single-flow + continuous modes via MaestroCommandRunner have not
    been migrated yet; that's a follow-up).

Tests:
  - Existing two saveFlow filename-pinning tests stay green
    (saveFlow itself is unchanged).
  - Added three copyToFlatLayout tests: shard prefix renaming,
    flow-name slash sanitization, no-op when sourceDir is missing.

See copilot/docs/orchestra-artifacts-refactor.md for the full plan.

* chore(cli): route per-flow staging dir through TempFileHandler

Phase 1 was using java.nio.file.Files.createTempDirectory directly,
which skips the recursive-cleanup lifecycle TempFileHandler provides.
Long-lived JVMs (e.g. the cloud worker) leak /tmp content when
temp paths bypass the handler.

Swap to maestro.utils.TempFileHandler so close() in the finally
recursively cleans up the staging directory.

Also document the convention in AGENTS.md under Conventions so future
contributions don't reach for Files.createTempFile/Directory.

* fix(orchestra): dispatch listener lifecycle from executeSubflowCommands

Composite commands (runFlow / repeat / retry) route their nested bodies
through executeSubflowCommands, which only called the legacy lambdas.
The new OrchestraListener pipeline (incl. ArtifactsGenerator) therefore
only saw top-level commands — commands.json was missing every nested
entry and failure screenshot + hierarchy were skipped when a leaf
inside a composite failed.

Mirror the five dispatch sites from executeCommands: onCommandStart
listener notify with sequenceNumber + startedAt bookkeeping, and
dispatchFinished on Completed / Warned / Skipped / Failed branches.

Adds three RunFlow / Repeat / Retry tests in OrchestraListenerDispatchTest
that exercise Completed + Warned + Failed leaves inside each composite
and assert the listener sees every inner leaf. These tests went RED
on the regression before the fix and pass after.

* test(orchestra): expand listener-dispatch coverage to top-level + nested + reset

Replaces two near-vacuous empty-flow tests with three structural tests that
exercise the dispatch paths the empty-list cases couldn't:

  - top-level leaves (no composite wrapper) - the only path #7's composite
    tests didn't cover; locks down `executeCommands`-side dispatch.
  - Repeat -> RunFlow -> leaves - asserts dispatch chains through arbitrary
    nesting depth, not just one level.
  - Repeat with times=2 - asserts onCommandReset fires for the body leaf
    when Orchestra resets between iterations.

Each test now carries a KDoc with the YAML-shape of the flow it exercises,
so the structural intent of each case is visible in source.

The deleted tests ran `runFlow(emptyList())` and asserted that flowStart/
flowEnd fire and that debugOutput.commands is empty - both are tautological
once any non-empty flow runs through the listener pipeline, and empty
command lists don't happen in production (YAML reader rejects them upstream).

* fix(orchestra): guarantee onFlowEnd dispatches once onFlowStart has fired

executeDefineVariablesCommands sat between the onFlowStart dispatch and
runFlow's outer try/catch. A throw inside it (most commonly: a putEnv
failure when the user injects env vars via `--env` / a flow `env:` block /
MAESTRO_* shell vars, which Env.withEnv lowers into a synthesized
DefineVariablesCommand prepended to the flow) propagated out of runFlow
without entering the catch — so the finally never ran:

  - listener.onFlowEnd was never dispatched, so ArtifactsGenerator
    never wrote commands.json and never closed its ScopedLogCapture.
  - jsEngine.close() was skipped, leaking the JS engine.

Move executeDefineVariablesCommands and the DefineVariablesCommand-filter
inside the try, so any throw they emit is caught into `exception` and
re-thrown after finally (preserving caller-visible propagation) while
onFlowEnd and jsEngine.close run.

Adds a test that injects a JsEngine whose putEnv throws and asserts the
listener sees `flowEnd` in addition to `flowStart` and the failed-command
events. Test was RED on the regression and is GREEN with the fix.

* fix(orchestra): key commandStartTimes by sequenceNumber, not MaestroCommand

MaestroCommand is a data class — structurally identical commands are
equal as map keys. Today the dispatchFinished-removes-before-next-
onCommandStart-puts pattern makes this work by accident: every terminal
dispatch cleans up its own entry before the next start. Any future code
path that interleaves starts and finishes (concurrency, async retry,
parallel sub-execution) would silently fall into the `?: finishedAt`
fallback and report duration = 0.

Switch the key to the monotonic commandSequenceCounter assigned at
onCommandStart. Pass sequenceNumber explicitly to dispatchFinished so
lookup is unambiguous. Collisions become structurally impossible.

Adds a pin-down test that asserts two structurally identical
EvalScriptCommand("1") commands report independent non-zero start
timestamps and sequential ordering. Test was GREEN on the old code
(no observable bug today) and stays GREEN on the new — documents the
contract so a future regression that breaks the per-event timing would
fail visibly.

* fix(client): scope ScopedLogCapture level mutation to maestro loggers

Previous shape saved + restored the root logger level around each capture.
Overlapping captures (every sharded run, every long-lived Worker / Studio
JVM) raced on that shared state:

  - Capture B reads ALL as its "previous" because Capture A already lowered
    root; on close B restores ALL, leaving the host JVM's root logger
    permanently corrupted to ALL.
  - While A is closed but B is still active, root level reverts to the
    host's baseline (e.g. ERROR), silently dropping INFO/DEBUG events
    from maestro.* loggers before they reach B's per-flow file.

Replace the root mutation with a once-per-JVM lowering of the dedicated
`maestro` and `MAESTRO` LoggerConfig levels to ALL. Monotonic (never
restored), so concurrent / overlapping captures cannot corrupt anything.
Host's root logger and every non-maestro logger are left untouched.

Adds a test that interleaves two ScopedLogCaptures and asserts the host
root logger level is unchanged after both close. Test was RED on the old
save/restore behaviour (root stuck at ALL) and is GREEN with the fix.

Documented trade-off: hosts that embed Maestro and have their own root
appender now receive maestro.* events at all levels — they can opt out
by adding their own `maestro` LoggerConfig at a stricter level.

* chore(orchestra): centralize listener dispatch, log throwing listeners

Every listener-dispatch site was the same `effectiveListeners.forEach
{ runCatching { ... } }` shape — silent swallow of any listener
exception. A bug in a third-party listener (Studio SSE push, Worker API
reporter, future analytics hook) left no trace; users saw "flow ran
fine, dashboards empty" with nothing to diagnose.

Extract a single `dispatch(event, block)` helper that runs each
listener in isolation and logs at ERROR with the listener class name,
the event name, and the cause when a listener throws. Replace all
seven dispatch sites (onFlowStart / onFlowEnd / onCommandStart x2 /
onCommandFinished / onCommandReset / onCommandMetadataUpdate) with
calls to the helper.

Behavior unchanged for non-throwing listeners. For throwing listeners:
silent -> ERROR log with stack trace; flow still continues and other
listeners still fire.

* refactor(orchestra): return FlowResult from runFlow, drop debugOutput field

Per @steviec: exposing debugOutput as a mutable field on Orchestra
implied persistent state between runFlow and the post-hoc read,
and conflated the live-observation channel (OrchestraListener) with
the terminal record. Every caller already consumed debugOutput
strictly post-runFlow.

Make the lifetime explicit: runFlow now returns
  data class FlowResult(val success: Boolean, val debugOutput: FlowDebugOutput)
and the `val debugOutput` getter on Orchestra is gone.

Side benefit at the TestSuiteInteractor call site: the lateinit var
orchestra pattern is gone too. Construction failures no longer risk
masking the real error with an UninitializedPropertyAccessException
when the post-flow code tries to read orchestra.debugOutput — a
default FlowDebugOutput() now seeds the variable up front.

Callers updated:
  - TestSuiteInteractor — destructures result.success / result.debugOutput
  - MaestroCommandRunner — wraps with .success at the existing return site
  - IntegrationTest — 4 assertion patterns updated to .success

* remove: comment

* docs(orchestra): trim verbose KDoc/comments across the artifacts refactor

* feat(orchestra): typed ArtifactManifest + flat per-flow run-root bundle (mobile-dev-inc#3343)

* feat(orchestra-models): add ArtifactManifest taxonomy

* test(orchestra-models): pin both directions of manifest unknown-field tolerance

* feat(orchestra): ArtifactsGenerator emits ArtifactManifest on FlowResult

* refactor(orchestra): serialize manifest.json with the bundle's JSON style

* feat(cli): write flat-layout manifest.json in the session dir

* refactor(cli): serialize flat manifest.json with the shared bundle JSON style

* test(artifact-manifest): pin shard-prefixed flat paths + manifest content; drop unused imports

* refactor(orchestra): centralize canonical artifact filenames in ArtifactFiles

* feat(cli): add copyBundleToFlowDir for per-flow artifact folders

* feat(cli): write suite flows to per-flow folders

* refactor(cli): address review - accurate comment, verbatim-manifest test, consistent mkdir

* feat(cli): MaestroCommandRunner emits artifact bundle, returns FlowResult

* feat(cli): single-flow runs write a per-flow folder with manifest

* refactor(cli): simplify TestRunner error printing, revert needless reformat

Extract the per-type debug-message handling into printFlowError (a single
when over the MaestroException subtypes) so runSingle reads top-to-bottom,
and restore the original multi-line formatting of aiOutput/updatedEnv that
this branch had collapsed for no reason. Behavior unchanged.

* test: drop redundant artifact tests without losing coverage

- Remove the cli 'no clobber' test: with different flow names each lands in
  its own folder trivially; same-name clobber is already pinned by the
  numeric-suffix disambiguation test.
- Merge the two null-artifactsDir ArtifactsGenerator tests into one that
  asserts both no files on disk and an empty manifest.

* feat(client): add CapturedDeviceArtifact descriptor + device-log filenames

* feat(client): add device-log/crash capture methods to Driver (default no-op)

* feat(client): Maestro wrappers for device-log/crash capture

Add three suspend wrapper methods to Maestro class that delegate to Driver
capture methods (startDeviceLogCapture, stopAndCollectDeviceLogs,
collectCrashArtifacts), following the existing runInterruptible(Dispatchers.IO)
pattern.

* feat(orchestra): add DeviceArtifactCapturer helper

* feat(orchestra): capture device logs/crash into per-flow bundle + manifest

* feat(client): port dadb crash/ANR logcat helpers

* feat(client): port LogcatReader crash/ANR parser + tests

* feat(client): AndroidDriver captures logcat + crash + ANR

* feat(ios-driver): port iOS .ips crash parser + finder + tests

* feat(ios-driver): simctl log stream start helper

* feat(client): IOSDriver captures simulator log + .ips crash

* fix(device-logs): scope crash/ANR to flow start, clean up iOS log stream, harden tests

* feat(client): IOSDriver harvests xctest_runner.log as second DEVICE_LOG source

Threads the session logs dir (where LocalXCTestInstaller writes xctest_runner_*.log)
into IOSDriver via a nullable param; stopAndCollectDeviceLogs copies the newest one
into the per-flow bundle as DEVICE_LOG source=xctest. Closes the last worker-parity gap.

* chore(device-logs): shorten comments and drop internal doc reference

* feat(orchestra): make manifest.json self-documenting via bundled JSON Schema

Agents (and humans) reading a run's manifest.json had no in-band way to
learn what each field or ArtifactKind means. Make the manifest
self-describing:

  - Add a hand-written JSON Schema (manifest.schema.json) describing
    ArtifactManifest, with a description on every field and per-ArtifactKind
    docs via the oneOf/const pattern. Lifted from the model's KDoc.
  - ArtifactsGenerator.onFlowEnd now bundles the schema next to manifest.json
    in each run dir and writes a leading `$schema` pointing at it, so the
    manifest resolves its own schema offline.
  - Centralize both writes in TestOutputWriter (saveManifest injects $schema;
    saveManifestSchema copies the classpath resource).

Drift guard: ArtifactManifestSchemaTest fails the build if any
ArtifactKind/ArtifactFormat value is missing from the schema, so the
hand-written doc can't silently fall out of sync with the enums.

The on-disk manifest now carries `$schema`, an unknown property to the
typed model. No production code deserializes the manifest; the one test
that did used a strict mapper and now decodes tolerantly, matching the
model's documented contract (tolerance is the reader's choice).

* feat(orchestra): register screenshots/ and recordings/ folders in the manifest

* feat(orchestra): write takeScreenshot/startRecording into screenshots/ and recordings/

* feat(cli): pass the bundle dir as screenshotsDir so screenshots/recordings nest under it

* docs(orchestra): clarify assertScreenshot reference lookup order

* refactor: single artifact root for takeScreenshot/recording; --test-output-dir holds the full run bundle

* refactor: write each flow's artifacts directly to its output folder

Resolve the per-flow folder upfront and pass it as Orchestra's single
artifactsDir; Orchestra writes the bundle + screenshots/ + recordings/ +
manifest straight there. Drops the temp staging dir, copyBundleToFlowDir,
the separate screenshotsDir param, mediaRoot, and the now-vestigial
testOutputDir plumbing. Continuous mode keeps no bundle (artifactsDir null
-> takeScreenshot to CWD).

* feat(orchestra): nest bundle under artifacts/, flag-gated step screenshots + full recording (mobile-dev-inc#3348)

feat(orchestra): nest bundle under artifacts/, flag-gated step shots + full recording

Restructure the per-run artifact bundle so everything core writes lives under
an artifacts/ folder (zipped as one unit), while the two separately-served
outputs — per-step screenshots/ and the full-run screen-recording.mp4 — sit at
the run root.

- Rename takeScreenshot output screenshots/ -> artifacts/takeScreenshot/ and
  startRecording output recordings/ -> artifacts/startRecording/ so folders
  match the command that writes them.
- Move commands.json, maestro.log (now under logs/), and the failure screenshot
  under artifacts/.
- Add Orchestra flags captureStepScreenshots / captureScreenRecording (default
  off, so the local CLI bundle is unchanged; the worker turns them on). When on,
  ArtifactsGenerator writes screenshots/step-<seq>.png after each non-failed
  command and records the whole run to screen-recording.mp4.
- Manifest entries use the new relative paths and carry metadata.source to tell
  same-kind entries apart (failure/take_screenshot/step, start_recording/full_run).
- Update assertScreenshot reference lookup and the schema prose accordingly.

* feat(orchestra): point manifest $schema at the in-repo schema on main (mobile-dev-inc#3349)

Replace the per-run bundled manifest.schema.json with a stable identity: each
manifest.json now sets $schema to the hand-written schema served from this
repo's main branch via GitHub raw —
https://raw.githubusercontent.com/mobile-dev-inc/Maestro/main/maestro-orchestra-models/src/main/resources/maestro/orchestra/manifest.schema.json

A fixed branch keeps the URL constant while its content tracks the latest
schema, which is safe because the model tolerates unknown fields and a test
blocks undocumented artifact kinds. No extra hosting infrastructure is needed,
and the manifest stays self-describing even after it is moved away from its run
folder.

- Drop saveManifestSchema and the per-run schema-file copy; saveManifest writes
  the URL directly.
- Set the schema's own $id to the same URL.
- Keep the in-repo schema resource as the source of truth (it is the file the
  URL serves) and for the schema-coverage test.

Offline resolution is intentionally dropped.

* remove comment

* fix(orchestra): write device logs + crash/ANR into the logs/ dir

* refactor(orchestra): flatten run root into the bundle; version manifest schema as v1

Drop the intermediate artifacts/ folder — the run root is now itself the
zippable bundle, so commands.json, logs/ (maestro.log + device logs +
crash/ANR), takeScreenshot/, startRecording/, the failure screenshot,
screenshots/, and screen-recording.mp4 all sit directly under it next to
manifest.json.

Version the hand-written schema as manifest.v1.schema.json (file, $id, the
$schema URL embedded in every manifest, and the classpath resource), so a
future structural change ships as manifest.vN beside it while the v1 URL keeps
resolving for manifests already in the wild.

* docs(orchestra): device-log comments follow the flattened logs/ path

* feat(orchestra): per-command artifacts list on CommandDebugMetadata + onCommandArtifact hook

* feat(orchestra): takeScreenshot/startRecording report their output via onCommandArtifact

* feat(orchestra): attribute the failure screenshot to the failed command

* feat(orchestra): attribute per-step screenshots to their command

* docs(orchestra): mention per-command artifacts in ArtifactsGenerator KDoc

* docs(orchestra): refresh schema descriptions for the flattened layout + per-command artifacts

* feat(orchestra): split ArtifactKind into self-describing kinds + screen-hierarchy dir

* feat(orchestra): type per-command artifacts as {type, path} via ArtifactKind

* feat(orchestra): unify failure capture into screenshots/step-N.png; dedicated manifest kinds

* feat(orchestra): per-step screen-hierarchy files replace inline hierarchy in commands.json

* docs(orchestra): trim comments across the artifacts PR

* feat(orchestra): slim serialized errors in commands.json to message + debugMessage

* feat(orchestra): add ArtifactCollector that records artifacts on allocate/adopt

* refactor(orchestra): build the manifest from ArtifactCollector records, not a disk scan

* refactor(orchestra): consolidate capture flags into captureFullArtifacts

* refactor(orchestra): privatize bundle layout out of -models

The directory/filename layout constants in ArtifactFiles had no
cross-module consumer — only maestro-orchestra (the producer) read
them; consumers locate artifacts via each manifest entry's
relativePath at runtime. Keeping them in the shared -models module
made the layout look like an inter-module contract it never was.

Move them into a module-internal BundleLayout in maestro-orchestra,
so the bundle shape is the producer's private concern. The only
genuinely shared identity — the manifest schema URL/resource (the
-models schema test consumes the latter) — moves onto
ArtifactManifest, where it belongs with the type it describes.
ArtifactFiles is deleted; no behavior or on-disk layout changes.

* docs(orchestra): note one-app crash scoping assumption

* feat(orchestra): publish manifest schema to a public GCS bucket

Point each manifest.json's $schema (and the schema's own $id) at
https://storage.googleapis.com/maestro-schemas/artifact-manifest/v1.schema.json
— HTTPS, a versioned/immutable path served straight from a public GCS object we
control — replacing the github-raw URL on main. Fixes that URL's sharp edges:
404-until-merged, raw hotlink rate limits, and a mutable v1. Serving the object
directly (no load balancer / DNS) keeps schema resolution decoupled from any
other product's infra.

Add publish-schemas.yaml: on push to main (or manual), CI mirrors the in-repo
schema to gs://maestro-schemas/artifact-manifest/v1.schema.json via the existing
GCP_MOBILEDEV_BUCKET_CREDENTIALS service account. The repo file stays the source
of truth; the schema-coverage test is unchanged.

* docs(orchestra): schema spells out hierarchy is a separate artifact, not inline in commands.json

* test(orchestra): schema coverage guards entry/manifest fields, not just kinds

additionalProperties:false rejects any undocumented field, so a new model
field missing from the schema is now a build failure like a missing kind.

* build(orchestra-models): declare kotlin-reflect for the schema-coverage test

The field-coverage check reflects over the model via primaryConstructor;
make kotlin-reflect a direct test dep instead of leaning on jackson-module-kotlin's
transitive copy.

* refactor(orchestra): address manifest review — collector owns artifact paths, one version signal

- takeScreenshot/startRecording now allocate through ArtifactsGenerator/ArtifactCollector,
  the single owner of bundle paths; drop the onCommandArtifact listener hook and dead getFileSink
  so a file can't reach the bundle unrecorded
- drop the schemaVersion field — version lives only in the $schema vN path
- schema additionalProperties: true (root + entry) so additive fields stay forward-compatible
  against a cached older v1
- remove the unused USER_FILE kind

* fix(orchestra): gate per-step view hierarchy behind captureFullArtifacts

captureStepHierarchy() ran on every executed command, each a synchronous
maestro.viewHierarchy() device round-trip (~100 for a 100-command flow).
Per-step screenshots and the full-run recording are already gated behind
captureFullArtifacts for this reason; hierarchy was the outlier.

Capture per-step hierarchy only when captureFullArtifacts is on (worker);
the failed step's hierarchy is still captured locally so failures stay
debuggable. Align the test names with the same condition wording.

* fix(orchestra): per-command failure-screenshot dedup, not flow-wide

The dedup skipped a failure screenshot whenever any earlier screenshot in
the flow was FAILED. That swallowed every failure after the first in a
continue-on-failure / optional flow. Move the dedup out of ScreenshotUtils
(which can't see the command sequence) and into captureFailureScreenshot:
skip only a composite parent re-shooting its leaf's screen, identified by a
lower sequence number than the leaf that already captured. A genuinely later
failure has a higher number and keeps its own shot.

In worker mode (captureFullArtifacts on) every step is recorded individually,
so a failed composite parent keeps its own screenshot too — no dedup there.

Adds Orchestra-driven tests confirming repeat/retry produce one screenshot
per attempt and onFlowStart/onFlowComplete hooks each get their own step.

* fix(ios): wait for simctl to flush device log before collecting it

stopAndCollectDeviceLogs destroyed the `simctl log stream` process with an
async SIGTERM and copied the log file immediately, so the buffered tail —
often the lines around a crash — could be lost. Wait (bounded) for the
process to exit before copying, mirroring stopScreenRecording's close()+
waitFor(). The restart and teardown destroy() sites don't copy afterward,
so they stay no-wait.

* fix(orchestra): route WARNED + analyze screenshots through the manifest

WARNED and --analyze screenshots were captured outside the collector (flat
files via persistDebugScreenshots) and only on the single-flow path, so they
never reached manifest.json and single vs suite runs diverged.

- ArtifactsGenerator now captures a warned step's screenshot + hierarchy into
  the bundle on every run, so warned shots are first-class manifest artifacts
  on both single and suite.
- --analyze turns on captureFullArtifacts (single + suite), so the bundle holds
  a per-step screenshot for every command. The AI analysis already walks the
  debug folder and ingests every PNG, so this replaces the bespoke analyze
  capture entirely — no separate code path.
- Delete the bespoke analyze/warned capture, persistDebugScreenshots, and the
  now-dead ScreenshotUtils helpers. debugOutput.screenshots had no remaining
  reader, so drop it and simplify takeDebugScreenshot to (maestro, destFile).

* feat(orchestra): record AI-analyzed screenshots as AI_ANALYSIS in the manifest

assertWithAI / assertNoDefectsWithAI produced a screenshot the AI analyzed,
but it only fed the CLI's AI report and never reached the bundle/manifest.
Add an onAIArtifactGenerated listener hook; ArtifactsGenerator writes that
screenshot to ai-analysis/step-<seq>.png and records it as AI_ANALYSIS (with
a defectCount) attributed to the running command. The CLI report path is
unchanged, and the worker gets the same artifact for free.

* feat(orchestra): per-execution commands.json with nesting depth (mobile-dev-inc#3378)

* feat(orchestra): per-execution commands.json with nesting depth

commands.json was serialized from an identity-keyed map, so retry/repeat
re-runs of the same command object collapsed into one entry (last-attempt
status, all attempts' screenshots piled on). The worker couldn't drive its
per-attempt run_step table from it.

Record one entry per command execution instead:
- FlowDebugOutput gains executedSteps (one CommandDebugMetadata per
  onCommandStart, in order); the identity map stays for live attribution.
- Artifacts attribute by sequence number (ArtifactCollector.artifactsForStep),
  so each attempt keeps its own screenshot/hierarchy.
- OrchestraListener.onCommandStart carries depth; Orchestra tracks a
  subflowDepth around executeSubflowCommands. depth 0 at the top, +1 inside
  each runFlow/repeat/retry — the worker's subIndex.
- onCommandReset no longer mutates the finished entry (it shares the object
  with the identity map); a reset just precedes the next execution's entry.

A repeat/retry now yields one commands.json entry per iteration/attempt, each
with its own screenshot and depth — mapping 1:1 onto run_step(index, subIndex).
Verified locally on web for repeat and retry.

* refactor(orchestra): drop dead artifactsFor and command attribution

artifactsFor(command) had no caller once onFlowEnd switched to
artifactsForStep(sequenceNumber). Remove it and the now write-only
command field threaded through Record/allocate/allocateInCollection/adopt
and their call sites.

* refactor(orchestra): drop unused RRWEB artifact format

Web recording is MP4 (CDP screencast -> JCodec), so RRWEB had no producer
and no consumer. Removing it before v1.schema.json is published. Note added
on why enum values, unlike fields, must be reserved up front rather than
added additively later.

* fix: adapt new main test to FlowResult API; rename dadb logcat helpers

- IntegrationTest: main's new 'optional launchApp ... warned, not failed' test
  used runFlow's old Boolean return; this branch returns FlowResult, so assert
  result.success (surfaced only at test-compile after the main merge).
- Rename DadbExtensions.kt -> LogcatExtensions.kt and move from the
  maestro.android.dadb package into maestro.android: the helpers now extend
  AndroidDeviceConnection (not raw Dadb), so the 'dadb' name was stale.

---------

Co-authored-by: Proksh Luthra <35415752+proksh@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file javascript Pull requests that update javascript code

Development

Successfully merging this pull request may close these issues.

0 participants