Skip to content

fix(macos): attach to a running app instead of launching a duplicate on open - #3707

Merged
thymikee merged 6 commits into
mainfrom
t3/prevent-duplicate-macos-launch
Oct 16, 2026
Merged

thymikee merged 6 commits into
mainfrom
t3/prevent-duplicate-macos-launch

Conversation

@thymikee

@thymikee thymikee commented Oct 16, 2026 •

Copy link
Copy Markdown
Member

Summary

Part of #3406. macOS open checks LaunchServices registration when an app-shaped process is already running, preserving the selected instance and arguments. The 2500 ms probe remains best-effort; unconfirmed registration retains normal open behavior and may duplicate. Process-table reads use the same provider executor as the other tools.

Validation

Head: ee2a12ef551548e133bb78c5ef72104240c4db3e.

  • Direct exact-head gate run-YjbGPz passed with exit 0, exactCommit: true and matching clean fingerprints. Fresh isolated r9 review found no findings, reproduced 973 tests, and killed restored process-error, plist-pairing and budget-guard mutations.
  • Current-head live A/B passed: both opens dispatched during an asserted unlisted window near 300 ms. Base produced two copies; head retained one original with its arguments. Snapshot and deep-link delivery reached the same instance (comment 6220965202).
  • Current iOS smoke failed during public-CLI prepare ios-runner: daemon startup exceeded 15000 ms, the child was gracefully retired, and no owner metadata appeared. Native runner compilation passed; no smoke scenario or XCTest assertion ran. Daemon log empty; cause unestablished; owner investigating startup and transitive imports. No CI retry taken.

CI: 17 successes, one failure, one skip and one neutral; macOS Smoke passed. The same preflight signature hit cac1247ac (#3345) and 9c7d2602c in the same window while 9203a7a40 reported success at 17:50:12Z — evidence pinned in comment 6221775611; cause unestablished, not classified as infra. The 42228dfb6 masked-field assertion is separate and historical; this preflight failure does not establish whether it passes here — at b85783148 the suite ran 117/0 with it passing.

@thymikee
thymikee marked this pull request as draft October 16, 2026 09:49
@github-actions

github-actions Bot commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Size Report

Metric Base Current Diff
Installed (including dependencies) 5.30 MB 5.30 MB +2.3 kB
Package (unpacked) 5.30 MB 5.30 MB +2.3 kB
Package (download) 1.60 MB 1.60 MB +753 B

Startup median (7 runs, lower is better):

Scenario Base Current Diff
CLI --version 17.9 ms 18.4 ms +0.5 ms
CLI --help 51.5 ms 52.2 ms +0.7 ms

@github-actions

github-actions Bot commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor
PR Preview Action v1.8.1
Preview removed because the pull request was closed.
2026-10-16 18:52 UTC

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 5 files

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

Comment thread CHANGELOG.md Outdated
Comment thread packages/platform-apple/src/os/macos/launch-services-registration.test.ts Outdated
Comment thread CHANGELOG.md Outdated
Comment thread website/docs/docs/commands.md Outdated
@thymikee

Copy link
Copy Markdown
Member Author

The code change in 746cfa8 is not ready yet. The new probe fails the eager-closure check, and the live evidence for the changed open route is missing.

Coverage fails in scripts/__tests__/eager-closure-budgets.test.ts. The diff causes this. The three static imports at host-provider.ts:12-14 pull host-kit diagnostics, process and retry into six Apple facades. The four Smoke Tests lanes were cancelled, not failed, so I make no call on them. I know of no conflicts.

The change touches the device-facing macOS open <bundleId> route at host-provider.ts:30. The only live evidence is one sentence in the PR body, with no command, pid listing or output. The head must also change again for the eager-closure fix, so a run on this head will not prove the final head. Please repeat the live run on the final head and post the transcript. First, start <App>.app/Contents/MacOS/<exe> <custom args> directly, then run agent-device open <bundleId> --platform macos within about 300 ms. pgrep -lf <exe> should show two pids on base and exactly one on head, the one you started, with its arguments. A following snapshot should drive that app. Second, time open for an app that is not running, head against base. Third, show that open <bundleId> <url> still delivers the deep link.

Could the probe live in its own os/macos module that openBundle loads with await import(...)? Then no Apple facade would evaluate host-kit diagnostics, process or retry eagerly, and host-provider.ts would shrink to a one-line call. I looked for an existing macOS running-app query that sees processes LaunchServices has not listed yet and found none. NSRunningApplication and the helper share that blind spot, so the process-table read looks needed. Exact-process targeting (open reports the attached pid, the helper resolves by pid instead of .first) seems to belong in a follow-up that extends the existing <bundleId>@<pid> identity. What would have to change first? Only the lazy-import move and the budget decision.

Not blocking, and fine to take or leave: the doc block at host-provider.ts:125 says the 5 s budget is longer than the open it precedes on purpose, while line 118 says the probe cannot outlive the open it protects. AGENTS.md wants an optional probe to stay shorter than the operation it precedes, and a first launch on a loaded host can pay up to 4.5 s of reads before open -b, so please size the budget below a typical open -b or get the exception approved. Also, "Closes #3406" goes further than the code, because the helper at main.swift:757 still picks runningApplications(withBundleIdentifier:).first with no pid or path target, so "Part of #3406" or a follow-up for pid-resolved targeting would fit better.

On the open inline threads, three still apply: the CHANGELOG overstates the wait, the first launch pays an uncounted lsappinfo find, and commands.md says "instead of launching a second copy". The test-cleanup thread at discussion_r4293269394 does not fail at this head, since Coverage ran host-provider-open.test.ts with all 19 tests passing, though a mockClear in afterEach would still make the tests order-safe, so you can resolve it.

I did not run the tests or any live macOS run. I also did not verify that lsappinfo find bundleid=X pid=Y matches both keys together. I did not check whether a closing app that is still in ps makes a later open wait out the full poll window, so please time that case in the live run.

The next step is to move the probe behind the lazy import so eager-closure-budgets passes. Then post the live transcript on that final head, showing one pid with the caller's arguments where base shows two.

@thymikee
thymikee force-pushed the t3/prevent-duplicate-macos-launch branch 2 times, most recently from 3122789 to 1a0d1b0 Compare October 16, 2026 11:07
@thymikee
thymikee marked this pull request as ready for review October 16, 2026 11:33

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 6 files

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

@thymikee

Copy link
Copy Markdown
Member Author

The earlier concern about the static import is fixed at 1a0d1b0: the lazy import removes that edge, and the stale CHANGELOG and docs wording is corrected. The code now looks right to me, but the live evidence asked for earlier is still missing.

The change affects the real macOS open <bundleId> route (host-provider.ts). All current coverage uses a fake runCommand and a mocked listHostProcesses. Nothing yet shows that a real, just-spawned, unlisted copy is attached instead of duplicated. Nothing shows that lsappinfo find bundleid=X pid=Y lists the pid once it registers. Nothing shows that a cold launch costs only about 0.3 s more, or that reopening right after close does not wait out the full 2 s poll while the old process lingers in ps. Please post a transcript from a real macOS host on 1a0d1b0 with four parts. (1) Start <App>.app/Contents/MacOS/<exe> <custom args> directly, then run agent-device open <bundleId> --platform macos within about 300 ms. pgrep -lf <exe> must show one pid carrying the custom args on head and two on base, and a following snapshot must show that app. (2) Time open for a not-running app, head against base. (3) Show that open <bundleId> <url> still delivers the deep link. (4) Time close <app> followed immediately by open <app>.

Not blocking, take or leave: the doc block on LAUNCH_SERVICES_PROBE_BUDGET_MS in launch-services-registration.ts quotes AGENTS.md and points to the PR discussion. Could it state only the invariant (every read fails open, the ceiling bounds the whole probe) and leave the budget exception to the PR?

On the open threads, I checked each earlier thread against 1a0d1b0. The three P2 threads on the CHANGELOG count and wording, on the docs wording and on the mockClear in beforeEach are fixed at this head, so please resolve r4293269371, r4293269394, r4293269411 and r4293269429. The P1 thread on multi-file plutil -extract does not apply: a read-only multi-file run on macOS 26.6.2 printed one row per readable plist and named failures on stderr, which is what readAppBundleIds parses (older macOS not checked), so please resolve r4294247823.

Smoke Tests failed in "Preflight iOS runner through public CLI" with daemon_startup_failed. This looks unrelated: the diff only touches the macOS openBundle path, behind a dynamic import, and daemon startup and the iOS runner preflight never reach it. Please rerun to confirm. There are no conflicts. I did not run the test suite or a live macOS open. The only remaining step before merge is the live transcript above.

@thymikee
thymikee force-pushed the t3/prevent-duplicate-macos-launch branch from 1a0d1b0 to 15c8c96 Compare October 16, 2026 13:02

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 2 files (changes from recent commits).

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

Comment thread packages/platform-apple/src/os/macos/launch-services-registration.test.ts Outdated
@thymikee

Copy link
Copy Markdown
Member Author

Live head-vs-base evidence on the public route (fixture dev.ad.issue3406.fixture, bundle id registered fresh each leg; every open dispatched only after lsappinfo find bundleid=… pid=<spawned> asserted the copy UNLISTED; driver v6, SLEEP=1.6 pre-registration window). Production at 96b43c584 is test-only-changed from the 15c8c96b1 tree this ran on (git diff 15c8c96b1 96b43c584 touches only the test file).

Base full CLI agent-device open during the asserted-unlisted window → two pids; head → one pid with arguments preserved:

== B1 BASE full CLI during asserted-unlisted window ==
[cli-base] daemon warm rc=0
[cli-base] pid 59938 UNLISTED at t=0.3s (asserted); opening now
[cli-base] cli rc=0 cli-wall=1.255s
[cli-base] listing of spawned pid right after open: LISTED; copies=2 [59938 61069 ]
    59938 …/ADIssue3406Fixture -ProofFlag race-cli-base -PreRegisterSleep 1.6
    61069 …/ADIssue3406Fixture
B1 PASS: base CLI duplicated during the window

== B2 HEAD full CLI during asserted-unlisted window (expect 1 copy, original pid) ==
[cli-head] daemon warm rc=0
[cli-head] pid 65867 UNLISTED at t=0.3s (asserted); opening now
[cli-head] cli rc=0 cli-wall=1.484s
[cli-head] listing of spawned pid right after open: LISTED; copies=1 [65867 ]
    65867 …/ADIssue3406Fixture -ProofFlag race-cli-head -PreRegisterSleep 1.6
B2 PASS: head CLI attached to the single running copy

== C HEAD full CLI: snapshot + deep link on the attached copy ==
C open rc=0 (pid 66328)
C snapshot rc=0
C open-with-url rc=0
C PASS: snapshot drove pid 66328, deep link received by pid 66328, single copy

The seam-level comparison (open -b directly vs the provider seam, outside the CLI) reported 1 copy on both sides this run: the script's ~1 s start-up landed open -b after the fixture registered, so the window was no longer open at dispatch. I keep it out of the claim — B1/B2 on the real CLI route are the comparison.

Probe cost and the budget question from review (measured, same host):

  • Typical open pays one lsappinfo find bundleid=…: 31–40 ms; a miss adds the process-table scan (~0.145 s) plus one real plutil batch over candidate plists (10–80 ms at 62 paths).
  • Cold open with nothing running: base 0.264 s, head 0.666 s, bare open -b 0.071 s — the probe's full-miss path costs ~0.4 s on the CLI route.
  • App closing but still in ps: next open returned in 0.649 s (rc=0) — the wait is bounded by reads, not by the poll window.
  • Probe ceiling is 2.5 s (2 s poll + reads). Widening to 5 s would only delay the fallback open on genuinely-absent apps; the race this fixes resolves well inside 2 s (B1's duplicate appeared at ~1.2 s on base).

Reproduction notes: the window must be asserted unlisted before dispatch — with warm LaunchServices state, open -b can resolve the bundle id and attach before the pre-registration sleep ends, which is why earlier runs without the assertion showed 1 copy on base too.

@thymikee
thymikee force-pushed the t3/prevent-duplicate-macos-launch branch from 96b43c5 to b6fbc2e Compare October 16, 2026 13:41
@thymikee

Copy link
Copy Markdown
Member Author

Final-head live CLI proof at 42228dfb6 (rebased onto origin/main 87fe3ea83 after the CONFLICTING state; production files byte-identical to the reviewed 96b43c584 tree — the rebase resolved only the CHANGELOG adjacency, and the delta since is one test-comment fix). Same driver as before, CLI legs only: every open dispatched after lsappinfo find bundleid=… pid=<spawned> asserted the copy UNLISTED; base leg's claim fully released (daemon-free device status shows "claims": []) before the head leg; copies counted before releasing own session; own fixture pids and state dirs only. Driver exit 0, all assertions pass:

== V7-B1 BASE full CLI during asserted-unlisted window (expect 2 copies) ==
[cli-base] daemon warm rc=0
[cli-base] pid 28820 UNLISTED at t=0.3s (asserted); opening via full CLI now
[cli-base] cli rc=0 cli-wall=0.629s
[cli-base] copies=2 pids=[28820 29455]
    28820 …/ADIssue3406Fixture -ProofFlag race-cli-base -PreRegisterSleep 1.6
    29455 …/ADIssue3406Fixture
B1 PASS: base CLI duplicated during the window

== V7-B2 HEAD full CLI at 42228dfb6c19ad60bac751238c974e08808aba0f ==
[cli-head] daemon warm rc=0
[cli-head] pid 30284 UNLISTED at t=0.3s (asserted); opening via full CLI now
[cli-head] cli rc=0 cli-wall=1.451s
[cli-head] copies=1 pids=[30284]
    30284 …/ADIssue3406Fixture -ProofFlag race-cli-head -PreRegisterSleep 1.6
B2 PASS: head CLI attached to the single running copy

== V7-C HEAD snapshot + deep link on the attached copy ==
C open rc=0 (pid 31570)
C snapshot rc=0
C snapshot drives pid 31570
C open-with-url rc=0
C deep link received by pid 31570
C PASS: single copy throughout

Gate at this head: pnpm check:affected --run --head 42228dfb6… --json → exactCommit: true (receipt run-Xzu4vS). A fresh independent review at 96b43c584 (production-identical tree) returned APPROVE with one P2 — a routing comment naming a nonexistent test file — fixed here as test(macos): point the probe routing comment at its owning test; the reviewer also re-measured the plutil batch and lsappinfo pinning contracts independently. A final review of this exact head follows.

@thymikee

Copy link
Copy Markdown
Member Author

The earlier fixes in 1a0d1b0 now hold at 42228df, and the code looks right. I did not run the tests or a live macOS open, so the author's live transcripts are checked only against the route and the production-identical trees by diff. The cold-open and close-then-open timings come from 15c8c96 (production-identical to this head), not from a run at 42228df. The test fixes are in: the real-plutil stub now registers only for the paired pid, and a 3-plist batch covers the multi-file plutil output, so the two inline threads can be resolved: #3707 (comment) (stub pairing, fixed at head) and #3707 (comment) (multi-file plutil rows, benign because readAppBundleIds refuses mismatched counts).

Should the process-table read go through the same injected AppleToolCommandExecutor as the lsappinfo, plutil and open calls, using listHostProcesses({ runCommand, timeoutMs })? findUnlistedInstancePids currently escapes the executor override and always runs ps on the daemon's own host (https://github.com/callstack/agent-device/blob/42228df/packages/platform-apple/src/os/macos/launch-services-registration.ts#L150). With a scoped Apple tool provider, the probe could then take pids from one host and pass them to the provider's lsappinfo and plutil on another. With that change the probe has one seam end to end, and the tests can script ps through fakeMacHost instead of vi.mock.

Not blocking: the ps seam above is the only open note, and you can take it or leave it.

The macOS Smoke Tests job is still queued, so CI has no result yet. It runs the macOS command coverage contract, which may reach the changed macOS openBundle route, so a failure there would not be clearly unrelated. Required evidence is satisfied. There are no conflicts. Before merge, Smoke Tests must finish green, and I will check the macOS command coverage contract lane when it does.

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 2 files (changes from recent commits).

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

Comment thread packages/platform-apple/src/os/macos/launch-services-registration.test.ts Outdated
…on open

A macOS app started directly — by a supervisor or a dev script — is not
listed by LaunchServices until half a second or so after it spawns. During
that window `open -b` sees no instance and starts a second copy with no
arguments, which the session then drives instead of the copy the caller
owns (#3406).

The bundle open now reads the same view `open -b` consults and, when it
lists nothing while a process of that bundle is running, waits until
LaunchServices names the running copy before running `open` unchanged. An
already-listed bundle and a bundle with nothing running reach `open` on the
first read; the wait, every read, and the process scan share one budget, and
anything the probe cannot answer fails open so an open is never withheld.
The probe's 5 s ceiling exceeded the healthy open it precedes by an order
of magnitude while the case it waits out registers within ~0.75 s. The
ceiling now covers the full poll plus the reads ahead of it with measured
room (reads cost well under 300 ms together on a healthy host), so a host
too loaded to answer within the wait is dropped at the remaining-budget
floor instead of holding the open for seconds the race never needs.

The batched bundle-identifier read gains a hermetic invariant against the
real plutil: one -extract answers for every plist it is named, in argument
order, so one call can pair every candidate bundle; the unit fakes cannot
carry that proof because they script the rows.
The registration stub answered any pid-pinned read, so a batch that paired
an identifier with the wrong bundle's process could still end the wait
green. Only pid 4242's query now reports an ASN and the test asserts the
exact read transcript, so a rotation of the row-to-path pairing (verified
by a disposable mutation: 3 failed, 17 passed) fails this test on the
target's pid rather than passing on another bundle's.
The final review caught that the comment in the routing test named
host-provider-open.test.ts, which does not exist. The probe assertions
live in launch-services-registration.test.ts, the file the comment
should route a reader to.
The probe ran lsappinfo, plutil and the open through the injected Apple
tool executor but read ps on the daemon's own host through the host-kit
default. A scoped Apple provider could then pair pids found on one host
with its lsappinfo and plutil on another. listHostProcesses({runCommand,
timeoutMs}) routes the scan through the same seam and deadline the other
reads already share, so the probe answers about one host end to end. The
owning tests now script ps through fakeMacHost instead of mocking the
process module.
… read

fakeMacHost recorded the ps call and returned the table before consulting
the responder, so the scan could not be made to throw, fail, or time out
even though the probe now runs it through the same executor seam the
Error-answering stub exists for. The responder is consulted first and the
table is only the default answer. Three owning scenarios pin what the
probe does when the scan itself fails: a tool that cannot spawn and a
read killed at its budget end the probe with a typed diagnostic and the
original open, and a non-zero ps exit is the unreadable table the empty
answer already was — never 'nothing runs'.
@thymikee
thymikee force-pushed the t3/prevent-duplicate-macos-launch branch from b857831 to ee2a12e Compare October 16, 2026 17:19
@thymikee

Copy link
Copy Markdown
Member Author

Rebased onto origin/main f633525b1 (head ee2a12ef5); the rebase resolved CHANGELOG entry adjacency only — git diff origin/main...HEAD is still exactly the same six files, and the Apple probe/host files are byte-identical to b85783148. Because d076853b1 changed a production line (ps through the provider executor), the live race A/B was re-run at this head rather than inherited. Driver exit 0, every open dispatched after lsappinfo asserted the spawned copy UNLISTED, own pids/state dirs, claim released ("claims": []) between legs, copies counted before release:

== B1 BASE full CLI during asserted-unlisted window ==
pid 25640 UNLISTED at t=0.3s (asserted); cli rc=0 wall=0.589s; copies=2
    25640 …/ADIssue3406Fixture -ProofFlag race-cli-base -PreRegisterSleep 1.6
    25784 …/ADIssue3406Fixture                     <- duplicate, no args
== B2 HEAD full CLI at ee2a12ef5 ==
pid 26334 UNLISTED at t=0.3s (asserted); cli rc=0 wall=1.549s; copies=1
    26334 …/ADIssue3406Fixture -ProofFlag race-cli-head -PreRegisterSleep 1.6
== C HEAD snapshot + deep link on the attached copy ==
C snapshot drives pid 26841; deep link received by pid 26841; single copy

Gate at this head: pnpm check:affected --run --head ee2a12ef5… --json → passed, exactCommit: true (receipt run-YjbGPz). Focused suites 973 passed (upstream grew the eager-closure suite; my three files unchanged at 23/5/7). r8's APPROVE at b85783148 stands as the previous-head certificate; a fresh final review of this SHA follows.

@thymikee

thymikee commented Oct 16, 2026 •

Copy link
Copy Markdown
Member Author

CI blocker at ee2a12ef5: iOS preflight daemon startup — cause not established

The iOS Smoke lane failed (run 38938772746 / job 117100873516). Full job log and artifacts checked, not just annotations.

What actually failed: TEST BUILD SUCCEEDED and ios-simulator.boot ended success (111 s). The next step, pnpm clean:daemon + node --experimental-strip-types src/bin.ts prepare ios-runner ... --timeout 420000, failed at 17:55:53Z with COMMAND_FAILED / kind: daemon_startup_failed, startupTimeoutMs: 15000, startupAttempts: 1, daemon pid 6800 started 17:55:37 and retired gracefully, metadataState hasInfo/hasLock false, daemon.log zero bytes, single NDJSON diagnostic line (id mvb9qcys-cf730b66, phase daemon_startup, 16556 ms). No smoke scenario or XCTest assertion executed. This is not the 42228dfb6 masked-field XCTest recurrence, and it resolves nothing about it either way — that test is not reached here. (Separately, log-pinned: the b85783148 lane ran the same suite 117 tests / 0 failures, with testSynthesizedReplacementLeavesAMaskedFieldUnverified passed at 17:05:44Z.) The older 42228dfb6 masked failure stays historical and unattributed.

Not isolated to this head (same signature, same macos-26 pool, ~35-minute window):

Counter-evidence against a deterministic tree cause: 9203a7a40 ran the same step successfully (preflight began 17:49:28Z; success JSON at 17:50:12Z) inside the same window and also contains the #3711/#3712 extractions present in all three failing trees. Same for 27473b1ae and 28c6cf1a6. So the shared-factor window (post-#3711 trees, congested iOS queue) does not deterministically reproduce, and I am not classifying this as infrastructure — repeated occurrence does not prove infra.

This PR's causal distance: git diff origin/main...HEAD is six files; zero bytes in src/daemon*, daemon entry/startup, apple/, or the preflight path. ee2a12ef5 differs from the green-lane b85783148 only by upstream #3711/#3712/#3717/#3718/#3719/#3730 plus CHANGELOG/commands docs lines here.

State kept honest: head CI 17 passed / 1 failed (this preflight) / 2 skipped; macOS Smoke passed at this head. Gate run-YjbGPz exactCommit: true, live A/B (comment 6220965202), and r9 zero-findings approve stand — none of that claims CI green. No retry requested (no infra proof yet), no budget widening, no code change manufactured for this event. #3345 owner cross-notified with the shared startup evidence.

@thymikee

Copy link
Copy Markdown
Member Author

I reviewed ee2a12e and found no code problems. The earlier fixes are in: the fakeMacHost test now calls respond() before the ps fallback, and three new tests cover a ps that throws, times out or exits non-zero. The cubic-dev-ai P2 thread on that test is fixed at this head, so you can resolve it: #3707 (comment)

Smoke Tests failed in "Preflight iOS runner through public CLI" with daemon_startup_failed (15000 ms, 1 attempt, empty daemon log) before any scenario ran. This diff only touches the macOS openBundle path, the changelog and docs, so it does not look related to this change. The same failure shows up on other PRs in the same window, and macOS Smoke passed at this head. Please rerun Smoke Tests; it must pass green before merge.

For evidence, I did not run the live macOS transcript or the unit suites at ee2a12e myself. The 2-vs-1 copy result and the snapshot and deep-link checks come from your comment (#3707 (comment)). Two small notes that need no change here. The timeout test uses a hand-written AppError, and I did not confirm that isCommandTimeoutError treats it like a real exec timeout. Either way the probe ends with a diagnostic and the original open. listHostProcesses still checks the daemon host's Windows flag before using the injected runCommand, which cannot fire for the local macOS host provider today.

@thymikee thymikee added the ready-for-human Valid work that needs human implementation, judgment, or maintainer merge label Oct 16, 2026
@thymikee
thymikee merged commit bace781 into main Oct 16, 2026
19 of 20 checks passed
@thymikee
thymikee deleted the t3/prevent-duplicate-macos-launch branch October 16, 2026 18:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-for-human Valid work that needs human implementation, judgment, or maintainer merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant