Skip to content

feat: publish scripts from active sessions#1357

Merged
thymikee merged 3 commits into
mainfrom
agent/active-session-script-publication
Jul 21, 2026
Merged

feat: publish scripts from active sessions#1357
thymikee merged 3 commits into
mainfrom
agent/active-session-script-publication

Conversation

@thymikee

Copy link
Copy Markdown
Member

Summary

Adds session save-script [path] [--force] for publishing an armed open-to-destination recording without closing the live session.

Implements the accepted ADR 0016 lifecycle and portability contract, including terminal aborted/published states, descriptor-driven mutation ordering, target-evidence validation, atomic no-clobber publication, CLI/client/MCP metadata, help guidance, and provider-backed coverage.

Closes #1346.

Validation

  • pnpm format:check
  • pnpm typecheck
  • pnpm lint
  • Focused Vitest suite: 91 tests
  • pnpm build
  • Full coverage suite before rebase: 4,548 tests across 540 files

@github-actions

github-actions Bot commented Jul 21, 2026

Copy link
Copy Markdown

Size Report

Metric Base Current Diff
JS raw 1.8 MB 1.8 MB +10.5 kB
JS gzip 575.2 kB 578.0 kB +2.8 kB
npm tarball 689.7 kB 692.7 kB +3.1 kB
npm unpacked 2.4 MB 2.4 MB +10.9 kB

Startup median (7 runs, lower is better):

Scenario Base Current Diff
CLI --version 26.8 ms 27.8 ms +1.0 ms
CLI --help 57.2 ms 58.0 ms +0.8 ms

Top changed chunks:

Chunk Raw diff Gzip diff
dist/src/session.js +3.6 kB +1.0 kB
dist/src/snapshot-diagnostics.js +3.6 kB +989 B
dist/src/sdk-batch.js +3.1 kB +802 B
dist/src/cli-help.js +953 B +355 B
dist/src/registry.js +857 B +281 B

@thymikee

Copy link
Copy Markdown
Member Author

Four blockers before readiness:

  1. [P1] assertActivePublicationPortability treats any positional beginning with @ as a session ref. That rejects valid portable literal inputs such as type @alice or fill 'id="handle"' @alice, even though the @alice value is action text, not a target. Restrict ref validation to the target/ref positional of selector-targeting actions and add literal-@ regressions.

  2. [P1] Mutating find … click|fill|focus|type actions are recorded as the original find request without target-v1 evidence. readTargetBindingToken does not classify find, so active publication accepts and writes these steps despite ADR 0012/0016’s recording-time identity requirement. Either record canonical target evidence for mutating find or fail publication loudly; add a regression that would fail under the current path.

  3. [P1] A second successful open correctly adds the terminal-abort warning to the daemon response, but AgentDeviceClient.apps.open() drops warnings, AppOpenResult has no warning field, and serializeOpenResult/the CLI formatter do not render it. The provider test calls the daemon directly, so normal CLI and Node users receive no immediate notice that their armed recording is now irreversibly ABORTED. Preserve and render the warning through the public route, with a client/CLI regression.

  4. The provider-backed scenario is fixture-backed, and the Android/iOS smoke jobs do not exercise this new workflow. ADR 0016 explicitly requires live Android and iOS proof of publish → artifact → still-live session → cold replay → returned-session handoff. Please attach exact-head runs on both platforms.

CI is green and the branch is mergeable, but these code findings and missing device evidence keep ready-for-human off.

@thymikee

Copy link
Copy Markdown
Member Author

Addressed the review points:

  1. ADR 0016 already contains both disputed decisions on main from docs: propose active-session script publication #1347. Its accepted text defines the three-state ARMED / ABORTED / PUBLISHED lifecycle and requires a portable selector/selector-chain wait, explicitly refusing duration, stable, and @ref waits. This PR therefore only changes the ADR status from Proposed to Accepted.
  2. Live validation now passes on both backends (details below).
  3. Persisted force is target-scoped: applySaveScriptRetarget clears saveScriptForce when the path changes without a live --force. Commit bcc08ae adds the publication-handler regression: retargeting to a different existing file refuses the write, preserves its bytes, leaves the recording ARMED, and clears the old force authorization.

Live iOS evidence

  • Target: Agent Device Maestro iOS18 iPhone16 (CC9F9625-1B16-4D6B-8DB0-2DE2932ACD5B)
  • Published artifact: /private/tmp/adr0016-ios-e2bb8914.ad, 2 actions
  • Artifact:
context platform=ios device="Agent Device Maestro iOS18 iPhone16" kind=simulator theme=unknown
open "settings" --relaunch
wait "id=\"com.apple.settings.general\""
  • After publication, get text 'id="com.apple.settings.general"' returned General on the still-live authoring session.
  • Cold replay completed both steps and returned adr0016-ios-replay3; the same get text command then returned General on that replay session.

Live Android evidence

  • Target: Pixel 9 Pro XL API 37 (emulator-5554)
  • Snapshot proof: androidSnapshot.backend=android-helper, helperVersion=0.19.3
  • Published artifact: /private/tmp/adr0016-android-e2bb8914-v2.ad, 2 actions
  • Artifact:
context platform=android device="Pixel 9 Pro XL API 37" kind=emulator theme=unknown
open "settings" --relaunch
wait "label=\"Network & internet\""
  • After publication, get text 'label="Network & internet"' returned Network & internet on the still-live authoring session.
  • Cold replay completed both steps and returned adr0016-android-replay; the same get text command then succeeded on that replay session.

Replays used the persistent worktree daemon so the returned live session remained addressable for the required continuation command. All validation sessions were closed; session list --json returned an empty list afterward.

Final local gates: formatting, typecheck, lint, Fallow, build, 106 focused tests across 7 files, and both provider-route scenarios pass.

@thymikee

Copy link
Copy Markdown
Member Author

Addressed in 8f5ff18ef.

  1. Literal @ data: portability validation now checks only target-bearing positions (plus the selector position of wait). Literal values such as type @thymikee, fill ... @someone, and read-only find ... @handle are accepted. The regression covers the validator and the full publication writer path.

  2. Mutating find: publication now fails loudly before filesystem work for mutating find actions because replay cannot currently verify their target identity. The error is non-retriable within that recording and directs the user to re-record with an explicit selector-targeted action. This avoids publishing an artifact with a target-v1 guarantee the replay path cannot enforce.

  3. Second-open warning: AppOpenResult now carries daemon warnings through the typed client, result serialization, and CLI output. The CLI renders the abort warning immediately as Warning: ...; tests cover filtering/serialization and human output.

  4. Retry metadata: structural recording failures and missing target evidence are now retriable: false; destination-guard, no-clobber, and filesystem publication failures remain retriable. The daemon regression asserts the fresh-session recovery hint and no filesystem creation for a structural failure.

  5. Smaller parser/client points: the typed client preserves an explicitly empty save path so daemon validation rejects it, and session list / session state-dir now reject save-script-only path/--force inputs before transport.

Validation on this head:

  • pnpm format:check
  • pnpm typecheck
  • pnpm lint
  • pnpm build
  • 108 focused tests across the publication validator, daemon route, client, CLI, serializer, and both provider-route scenarios

The broad affected-test fanout also exercised these touched tests successfully, but unrelated suites hit the repository's documented host-contention timeouts; the affected paths above were rerun together with two workers and passed cleanly.

Live iOS/Android publish → cold replay → continue evidence is already attached here: #1357 (comment). This follow-up commit changes validation/client/CLI behavior only and does not modify either device provider.

@thymikee
thymikee marked this pull request as ready for review July 21, 2026 18:20
@thymikee
thymikee merged commit b1b26f3 into main Jul 21, 2026
24 checks passed
@thymikee
thymikee deleted the agent/active-session-script-publication branch July 21, 2026 18:24
@github-actions

Copy link
Copy Markdown
PR Preview Action v1.8.1
Preview removed because the pull request was closed.
2026-07-21 18:25 UTC

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Publish an open-to-destination script without closing the session

1 participant