diff --git a/.acecode/skills/verify-package/scripts/verify_package.py b/.acecode/skills/verify-package/scripts/verify_package.py index 0aefc17c..b018a920 100644 --- a/.acecode/skills/verify-package/scripts/verify_package.py +++ b/.acecode/skills/verify-package/scripts/verify_package.py @@ -376,23 +376,31 @@ def probe_desktop(report: Report, staged: Path, platform: str, shutil.rmtree(home, ignore_errors=True) return deadline = time.monotonic() + launch_timeout - while time.monotonic() < deadline: - if process.poll() is None: - report.add("desktop launch", "pass", - f"alive after launch (pid {process.pid}); terminating") - process.terminate() - try: - process.wait(timeout=15) - except subprocess.TimeoutExpired: - process.kill() - shutil.rmtree(home, ignore_errors=True) - return + while time.monotonic() < deadline and process.poll() is None: time.sleep(0.25) - if process.poll() == 0: - report.add("desktop launch", "fail", "exited immediately with code 0") + if process.poll() is None: + # Process survived the entire launch window: treat startup as + # successful, then stop it. + report.add("desktop launch", "pass", + f"alive after launch (pid {process.pid}); terminating") + process.terminate() + try: + process.wait(timeout=15) + except subprocess.TimeoutExpired: + process.kill() else: - report.add("desktop launch", "fail", - f"exited with code {process.returncode} during startup") + # Process exited at any point inside the window, including exit code 0. + # Verdicts must wait out the window instead of passing on the first + # poll() is None: right after spawn an immediately-exiting process + # (e.g. an `exit 0` stub) can still report poll() is None and would be + # wrongly marked "alive" (TOCTOU race). Waiting the full window makes + # the immediate-exit detection deterministic. + code = process.returncode + if code == 0: + report.add("desktop launch", "fail", "exited immediately with code 0") + else: + report.add("desktop launch", "fail", + f"exited with code {code} during startup") shutil.rmtree(home, ignore_errors=True) diff --git a/.agents/skills/verify-package/scripts/verify_package.py b/.agents/skills/verify-package/scripts/verify_package.py index 0aefc17c..b018a920 100644 --- a/.agents/skills/verify-package/scripts/verify_package.py +++ b/.agents/skills/verify-package/scripts/verify_package.py @@ -376,23 +376,31 @@ def probe_desktop(report: Report, staged: Path, platform: str, shutil.rmtree(home, ignore_errors=True) return deadline = time.monotonic() + launch_timeout - while time.monotonic() < deadline: - if process.poll() is None: - report.add("desktop launch", "pass", - f"alive after launch (pid {process.pid}); terminating") - process.terminate() - try: - process.wait(timeout=15) - except subprocess.TimeoutExpired: - process.kill() - shutil.rmtree(home, ignore_errors=True) - return + while time.monotonic() < deadline and process.poll() is None: time.sleep(0.25) - if process.poll() == 0: - report.add("desktop launch", "fail", "exited immediately with code 0") + if process.poll() is None: + # Process survived the entire launch window: treat startup as + # successful, then stop it. + report.add("desktop launch", "pass", + f"alive after launch (pid {process.pid}); terminating") + process.terminate() + try: + process.wait(timeout=15) + except subprocess.TimeoutExpired: + process.kill() else: - report.add("desktop launch", "fail", - f"exited with code {process.returncode} during startup") + # Process exited at any point inside the window, including exit code 0. + # Verdicts must wait out the window instead of passing on the first + # poll() is None: right after spawn an immediately-exiting process + # (e.g. an `exit 0` stub) can still report poll() is None and would be + # wrongly marked "alive" (TOCTOU race). Waiting the full window makes + # the immediate-exit detection deterministic. + code = process.returncode + if code == 0: + report.add("desktop launch", "fail", "exited immediately with code 0") + else: + report.add("desktop launch", "fail", + f"exited with code {code} during startup") shutil.rmtree(home, ignore_errors=True) diff --git a/.claude/skills/verify-package/scripts/verify_package.py b/.claude/skills/verify-package/scripts/verify_package.py index 0aefc17c..b018a920 100644 --- a/.claude/skills/verify-package/scripts/verify_package.py +++ b/.claude/skills/verify-package/scripts/verify_package.py @@ -376,23 +376,31 @@ def probe_desktop(report: Report, staged: Path, platform: str, shutil.rmtree(home, ignore_errors=True) return deadline = time.monotonic() + launch_timeout - while time.monotonic() < deadline: - if process.poll() is None: - report.add("desktop launch", "pass", - f"alive after launch (pid {process.pid}); terminating") - process.terminate() - try: - process.wait(timeout=15) - except subprocess.TimeoutExpired: - process.kill() - shutil.rmtree(home, ignore_errors=True) - return + while time.monotonic() < deadline and process.poll() is None: time.sleep(0.25) - if process.poll() == 0: - report.add("desktop launch", "fail", "exited immediately with code 0") + if process.poll() is None: + # Process survived the entire launch window: treat startup as + # successful, then stop it. + report.add("desktop launch", "pass", + f"alive after launch (pid {process.pid}); terminating") + process.terminate() + try: + process.wait(timeout=15) + except subprocess.TimeoutExpired: + process.kill() else: - report.add("desktop launch", "fail", - f"exited with code {process.returncode} during startup") + # Process exited at any point inside the window, including exit code 0. + # Verdicts must wait out the window instead of passing on the first + # poll() is None: right after spawn an immediately-exiting process + # (e.g. an `exit 0` stub) can still report poll() is None and would be + # wrongly marked "alive" (TOCTOU race). Waiting the full window makes + # the immediate-exit detection deterministic. + code = process.returncode + if code == 0: + report.add("desktop launch", "fail", "exited immediately with code 0") + else: + report.add("desktop launch", "fail", + f"exited with code {code} during startup") shutil.rmtree(home, ignore_errors=True) diff --git a/.codex/skills/verify-package/scripts/verify_package.py b/.codex/skills/verify-package/scripts/verify_package.py index 0aefc17c..b018a920 100644 --- a/.codex/skills/verify-package/scripts/verify_package.py +++ b/.codex/skills/verify-package/scripts/verify_package.py @@ -376,23 +376,31 @@ def probe_desktop(report: Report, staged: Path, platform: str, shutil.rmtree(home, ignore_errors=True) return deadline = time.monotonic() + launch_timeout - while time.monotonic() < deadline: - if process.poll() is None: - report.add("desktop launch", "pass", - f"alive after launch (pid {process.pid}); terminating") - process.terminate() - try: - process.wait(timeout=15) - except subprocess.TimeoutExpired: - process.kill() - shutil.rmtree(home, ignore_errors=True) - return + while time.monotonic() < deadline and process.poll() is None: time.sleep(0.25) - if process.poll() == 0: - report.add("desktop launch", "fail", "exited immediately with code 0") + if process.poll() is None: + # Process survived the entire launch window: treat startup as + # successful, then stop it. + report.add("desktop launch", "pass", + f"alive after launch (pid {process.pid}); terminating") + process.terminate() + try: + process.wait(timeout=15) + except subprocess.TimeoutExpired: + process.kill() else: - report.add("desktop launch", "fail", - f"exited with code {process.returncode} during startup") + # Process exited at any point inside the window, including exit code 0. + # Verdicts must wait out the window instead of passing on the first + # poll() is None: right after spawn an immediately-exiting process + # (e.g. an `exit 0` stub) can still report poll() is None and would be + # wrongly marked "alive" (TOCTOU race). Waiting the full window makes + # the immediate-exit detection deterministic. + code = process.returncode + if code == 0: + report.add("desktop launch", "fail", "exited immediately with code 0") + else: + report.add("desktop launch", "fail", + f"exited with code {code} during startup") shutil.rmtree(home, ignore_errors=True) diff --git a/external/ftxui b/external/ftxui index 658c942c..f98588b4 160000 --- a/external/ftxui +++ b/external/ftxui @@ -1 +1 @@ -Subproject commit 658c942c6eaceae88fd7ea4458ffa1f5a7775af7 +Subproject commit f98588b47b097674724100c7a35a3c9b8ec055e3 diff --git a/tests/scripts/verify_package_test.sh b/tests/scripts/verify_package_test.sh index 7e9298b6..b9d876cc 100644 --- a/tests/scripts/verify_package_test.sh +++ b/tests/scripts/verify_package_test.sh @@ -197,8 +197,11 @@ EOF chmod +x "$fixture/build/ACECode.app/Contents/MacOS/acecode-daemon" cp "$fixture/assets/models_dev/"* \ "$fixture/build/ACECode.app/Contents/Resources/share/acecode/models_dev/" - cp -R "$fixture/assets/seed" \ - "$fixture/build/ACECode.app/Contents/Resources/share/acecode/seed" + # The destination already exists (created by mkdir -p above), so plain + # `cp -R src dst` nests the tree as dst/seed instead of filling dst, which + # makes the packaged seed layout mismatch assets/seed. Copy the contents. + cp -R "$fixture/assets/seed/." \ + "$fixture/build/ACECode.app/Contents/Resources/share/acecode/seed/" expect_status 0 "darwin bundle flow" "$python_bin" "$verify_script" \ --skip-build --platform darwin --target desktop \ --repo "$fixture" --build-dir "$fixture/build" \