From 6cb907addb290ec59d7e6586cb5a4e465c5091b1 Mon Sep 17 00:00:00 2001 From: abrichr Date: Thu, 30 Jul 2026 12:40:57 -0400 Subject: [PATCH 1/2] fix: make quickstart independently verified --- README.md | 7 +++ openadapt/cli.py | 98 ++++++++++++++++++----------------------- platform-manifest.json | 18 ++++---- pyproject.toml | 16 +++---- tests/test_cli_smoke.py | 78 +++++++++++++++++++++++++------- uv.lock | 67 +++++++++++++++++++++------- 6 files changed, 179 insertions(+), 105 deletions(-) diff --git a/README.md b/README.md index a1bdd1443..f88167e04 100644 --- a/README.md +++ b/README.md @@ -48,11 +48,18 @@ target application, API key, or operating-system automation permissions: openadapt quickstart ``` +The tutorial records and compiles a synthetic task, certifies it with the +shipped clinical-write policy, and runs it under the Standard profile. A +separate read-only API confirms the saved record outside the screen that +performed the write. The healthy run returns `VERIFIED` with no model or Cloud +call. + You now have: - `openadapt-quickstart/recording/`: the demonstrated interaction and retained target evidence - `openadapt-quickstart/bundle/`: the inspectable compiled workflow - `openadapt-quickstart/run/REPORT.md`: the ordered actions, evidence, outcome, and any halt reason +- `openadapt-quickstart/run/receipt.json`: the privacy-safe local receipt for the synthetic verified run Inspect the program and its deployment gaps: diff --git a/openadapt/cli.py b/openadapt/cli.py index 19b55aab3..8089f22c3 100644 --- a/openadapt/cli.py +++ b/openadapt/cli.py @@ -25,7 +25,6 @@ openadapt doctor """ -import os import sys from pathlib import Path from typing import Optional @@ -172,75 +171,62 @@ def _run_flow(argv: list[str]) -> None: "--headed", is_flag=True, help="Show the browser while the tutorial runs." ) def quickstart(out: Path, headed: bool) -> None: - """Run the complete local tutorial: record, compile, check, and replay. + """Run a verified local tutorial against the bundled synthetic app. This is the shortest path to a real OpenAdapt run. It uses the bundled - synthetic tutorial, keeps every artifact on this computer, and enables no - model or Cloud call. The output directory is never overwritten. + synthetic tutorial, verifies the write through an independent read-only + system-of-record interface, keeps every artifact on this computer, and + enables no model or Cloud call. The output directory is never overwritten. """ + import os + root = out.expanduser().resolve() if root.exists(): raise click.UsageError( f"Output already exists: {root}. Pass --out with a new directory." ) - recording = root / "recording" - bundle = root / "bundle" - run_dir = root / "run" - steps = [ - ("Record the tutorial", ["demo-record", "--out", str(recording)]), - ( - "Compile the recording", - [ - "compile", - str(recording), - "--out", - str(bundle), - "--name", - "local-quickstart", - ], - ), - ( - "Certify the tutorial", - ["certify", str(bundle), "--policy", "permissive"], - ), - ( - "Replay locally", - ["replay", str(bundle), "--run-dir", str(run_dir)], - ), + argv = [ + "tutorial", + "--out", + str(root), + "--name", + "local-quickstart", ] if headed: - steps[0][1].append("--headed") - steps[-1][1].append("--headed") - - for index, (label, argv) in enumerate(steps, start=1): - click.echo(f"\n[{index}/{len(steps)}] {label}") - # The bundled tutorial contains synthetic identity-like strings. Keep - # the ordinary report warning meaningful for real workflows by making - # this one known-safe fixture explicit, then restore the operator's - # environment immediately after replay. - scrub = os.environ.get("OPENADAPT_FLOW_SCRUB") - if argv[0] == "replay" and scrub in (None, "auto"): - os.environ["OPENADAPT_FLOW_SCRUB"] = "off" - try: - code = _invoke_flow(argv) - finally: - if argv[0] == "replay" and scrub in (None, "auto"): - if scrub is None: - os.environ.pop("OPENADAPT_FLOW_SCRUB", None) - else: - os.environ["OPENADAPT_FLOW_SCRUB"] = scrub - if code: - raise click.ClickException( - f"{label} stopped with exit code {code}. " - f"Any completed artifacts remain in {root}." - ) + argv.append("--headed") + + # The bundled tutorial contains only fixed synthetic data. Keep an + # installed-but-unconfigured privacy provider from blocking this known-safe + # fixture, then restore the operator's setting immediately. + scrub = os.environ.get("OPENADAPT_FLOW_SCRUB") + if scrub in (None, "auto"): + os.environ["OPENADAPT_FLOW_SCRUB"] = "off" + try: + code = _invoke_flow(argv) + finally: + if scrub in (None, "auto"): + if scrub is None: + os.environ.pop("OPENADAPT_FLOW_SCRUB", None) + else: + os.environ["OPENADAPT_FLOW_SCRUB"] = scrub + if code: + raise click.ClickException( + f"The verified tutorial stopped with exit code {code}. " + f"Any completed artifacts remain in {root}." + ) click.echo("\nLocal quickstart complete.") - click.echo(f"Bundle: {bundle}") - click.echo(f"Run evidence: {run_dir}") + click.echo(f"Bundle: {root / 'bundle'}") + click.echo(f"Run evidence: {root / 'run'}") + click.echo("Outcome: VERIFIED under the Standard profile.") + click.echo("The synthetic write was confirmed through a read-only system-of-record API.") click.echo("No model or Cloud call was enabled.") - click.echo(f"Inspect qualification gaps: openadapt flow lint {bundle}") + click.echo(f"Inspect qualification gaps: openadapt flow lint {root / 'bundle'}") + click.echo( + "See a fail-safe halt: openadapt flow replay " + f"{root / 'bundle'} --drift modal --run-dir {root}-halt" + ) click.echo( "Connect this computer when you want Cloud history and collaboration: " "https://app.openadapt.ai/dashboard/settings/ingest" diff --git a/platform-manifest.json b/platform-manifest.json index 7180bdd25..341f60182 100644 --- a/platform-manifest.json +++ b/platform-manifest.json @@ -1,7 +1,7 @@ { "manifest_kind": "openadapt-platform-release-manifest", "schema_version": "1.0.0", - "generated_at": "2026-07-29T20:44:27+00:00", + "generated_at": "2026-07-30T16:36:43+00:00", "release_channel": "beta", "components": { "launcher": { @@ -26,21 +26,21 @@ }, "flow": { "package": "openadapt-flow", - "version": "1.26.0", + "version": "1.27.0", "source": "pypi", "requires_python": "<3.13,>=3.10", "artifacts": [ { "type": "bdist_wheel", - "filename": "openadapt_flow-1.26.0-py3-none-any.whl", - "url": "https://files.pythonhosted.org/packages/5d/67/9160ea77b039fd9c4fc6a02035eecf060528c9c74c15e0038f4a1da94b7f/openadapt_flow-1.26.0-py3-none-any.whl", - "sha256": "a6f07f16d06c549b20e21ce54957557a707331ffaaa3b8cadbe2adfb5170bfea" + "filename": "openadapt_flow-1.27.0-py3-none-any.whl", + "url": "https://files.pythonhosted.org/packages/42/e5/c08a34a0fc3ab4d05e37e55db11347fa1eb56fb86082de217f2970c35cd0/openadapt_flow-1.27.0-py3-none-any.whl", + "sha256": "1de9fd1fb89811e2411946fcc61bfbf08e433b746ff6a4008f3294332abb816b" }, { "type": "sdist", - "filename": "openadapt_flow-1.26.0.tar.gz", - "url": "https://files.pythonhosted.org/packages/07/6f/d7a0c3deca9ded1569eb94913b1cc8cddba65f6246d6c2075a2031e5c5ff/openadapt_flow-1.26.0.tar.gz", - "sha256": "83326969ca9e48a8fd3448a4ebbbb8c0f0d61e698fe81ce04e86b4031f7634a7" + "filename": "openadapt_flow-1.27.0.tar.gz", + "url": "https://files.pythonhosted.org/packages/8b/28/f29542489f2a45d3c80f28bde06a344e28d090d3e2721c760b2d6ebcba93/openadapt_flow-1.27.0.tar.gz", + "sha256": "2c0c1da300659ea6007d194cc07732e7436b06b2a0cbcf0386256f1064ebc107" } ] }, @@ -95,7 +95,7 @@ ">=0.1.0" ], "openadapt-flow": [ - ">=1.20.1,<2.0.0" + ">=1.25.1,<2.0.0" ], "openadapt-grounding": [ ">=0.1.0" diff --git a/pyproject.toml b/pyproject.toml index 796c0d0ac..bcf221300 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -33,7 +33,7 @@ classifiers = [ # All other capabilities (capture, ml, evals, ...) remain opt-in extras. dependencies = [ "click>=8.0.0", - "openadapt-flow[hosted]>=1.20.1,<2.0.0", + "openadapt-flow[hosted]>=1.25.1,<2.0.0", ] [project.optional-dependencies] @@ -49,22 +49,22 @@ browser = [ # separately provisioned executable, not a Python-package dependency. capture = [ "openadapt-capture>=1.0.4,<2.0.0", - "openadapt-flow[capture]>=1.20.1,<2.0.0", + "openadapt-flow[capture]>=1.25.1,<2.0.0", ] # Replay substrate dependencies stay separate from capture: recording observes # the human on the local interactive desktop, while replay may target a WAA # agent, a native app, or a remote framebuffer. windows = [ - "openadapt-flow[windows]>=1.20.1,<2.0.0", + "openadapt-flow[windows]>=1.25.1,<2.0.0", ] macos = [ - "openadapt-flow[macos]>=1.20.1,<2.0.0; sys_platform == 'darwin'", + "openadapt-flow[macos]>=1.25.1,<2.0.0; sys_platform == 'darwin'", ] linux = [ - "openadapt-flow[linux]>=1.20.1,<2.0.0; sys_platform == 'linux'", + "openadapt-flow[linux]>=1.25.1,<2.0.0; sys_platform == 'linux'", ] rdp = [ - "openadapt-flow[rdp]>=1.20.1,<2.0.0", + "openadapt-flow[rdp]>=1.25.1,<2.0.0", ] ml = [ "openadapt-ml>=0.2.0", @@ -82,13 +82,13 @@ retrieval = [ "openadapt-retrieval>=0.1.0", ] privacy = [ - "openadapt-flow[privacy]>=1.20.1,<2.0.0", + "openadapt-flow[privacy]>=1.25.1,<2.0.0", ] # `flow` now ships in the base install (see `dependencies` above). This # extra is kept for backward compatibility so `pip install openadapt[flow]` # and the `all` bundle still resolve. flow = [ - "openadapt-flow>=1.20.1,<2.0.0", + "openadapt-flow>=1.25.1,<2.0.0", ] # Bundles core = [ diff --git a/tests/test_cli_smoke.py b/tests/test_cli_smoke.py index 0fe61b49e..8e8649240 100644 --- a/tests/test_cli_smoke.py +++ b/tests/test_cli_smoke.py @@ -24,6 +24,7 @@ from __future__ import annotations import ast +import os import sys from pathlib import Path @@ -87,14 +88,59 @@ def test_quickstart_runs_one_local_lifecycle_without_overwriting(monkeypatch): result = runner.invoke(cli_main, ["quickstart", "--out", "first-run"]) assert result.exit_code == 0, result.output - assert [call[0] for call in calls] == [ - "demo-record", - "compile", - "certify", - "replay", - ] - assert calls[2][-1] == "permissive" - assert "No model or Cloud call was enabled" in result.output + assert len(calls) == 1 + assert calls[0][0] == "tutorial" + assert calls[0][1] == "--out" + assert calls[0][3:] == ["--name", "local-quickstart"] + + +def test_quickstart_forwards_the_headed_tutorial_option(monkeypatch): + calls = [] + monkeypatch.setattr( + "openadapt.cli._invoke_flow", + lambda argv: calls.append(list(argv)) or 0, + ) + + runner = CliRunner() + with runner.isolated_filesystem(): + result = runner.invoke( + cli_main, + ["quickstart", "--headed", "--out", "headed-run"], + ) + + assert result.exit_code == 0, result.output + assert len(calls) == 1 + assert calls[0][0] == "tutorial" + assert calls[0][-1] == "--headed" + + +def test_quickstart_restores_the_operator_scrub_setting(monkeypatch): + monkeypatch.setenv("OPENADAPT_FLOW_SCRUB", "auto") + monkeypatch.setattr("openadapt.cli._invoke_flow", lambda _argv: 0) + + runner = CliRunner() + with runner.isolated_filesystem(): + result = runner.invoke(cli_main, ["quickstart", "--out", "first-run"]) + + assert result.exit_code == 0, result.output + assert os.environ["OPENADAPT_FLOW_SCRUB"] == "auto" + + +def test_quickstart_retains_artifacts_when_the_engine_halts(monkeypatch): + def halt_after_writing(argv): + root = Path(argv[argv.index("--out") + 1]) + root.mkdir(parents=True) + (root / "halt-evidence.json").write_text("{}") + return 2 + + monkeypatch.setattr("openadapt.cli._invoke_flow", halt_after_writing) + + runner = CliRunner() + with runner.isolated_filesystem(): + result = runner.invoke(cli_main, ["quickstart", "--out", "halted-run"]) + + assert result.exit_code != 0 + assert Path("halted-run/halt-evidence.json").is_file() def test_quickstart_refuses_an_existing_output(monkeypatch): @@ -207,22 +253,22 @@ def test_launcher_flow_and_substrate_extras_metadata(): )["project"] extras = metadata["optional-dependencies"] - assert metadata["dependencies"].count("openadapt-flow[hosted]>=1.20.1,<2.0.0") == 1 - assert extras["flow"] == ["openadapt-flow>=1.20.1,<2.0.0"] + assert metadata["dependencies"].count("openadapt-flow[hosted]>=1.25.1,<2.0.0") == 1 + assert extras["flow"] == ["openadapt-flow>=1.25.1,<2.0.0"] assert extras["browser"] == ["playwright>=1.44"] - assert extras["privacy"] == ["openadapt-flow[privacy]>=1.20.1,<2.0.0"] + assert extras["privacy"] == ["openadapt-flow[privacy]>=1.25.1,<2.0.0"] assert extras["capture"] == [ "openadapt-capture>=1.0.4,<2.0.0", - "openadapt-flow[capture]>=1.20.1,<2.0.0", + "openadapt-flow[capture]>=1.25.1,<2.0.0", ] - assert extras["windows"] == ["openadapt-flow[windows]>=1.20.1,<2.0.0"] + assert extras["windows"] == ["openadapt-flow[windows]>=1.25.1,<2.0.0"] assert extras["macos"] == [ - "openadapt-flow[macos]>=1.20.1,<2.0.0; sys_platform == 'darwin'" + "openadapt-flow[macos]>=1.25.1,<2.0.0; sys_platform == 'darwin'" ] assert extras["linux"] == [ - "openadapt-flow[linux]>=1.20.1,<2.0.0; sys_platform == 'linux'" + "openadapt-flow[linux]>=1.25.1,<2.0.0; sys_platform == 'linux'" ] - assert extras["rdp"] == ["openadapt-flow[rdp]>=1.20.1,<2.0.0"] + assert extras["rdp"] == ["openadapt-flow[rdp]>=1.25.1,<2.0.0"] assert extras["all"] == [ "openadapt[browser,core,grounding,retrieval,privacy,flow,windows,rdp]", "openadapt[macos]; sys_platform == 'darwin'", diff --git a/uv.lock b/uv.lock index d30886605..2ab17ff20 100644 --- a/uv.lock +++ b/uv.lock @@ -596,6 +596,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 }, ] +[[package]] +name = "comtypes" +version = "1.4.16" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c6/2a/65274c13327f637ec13af8d39f2cf579d9ebe7a0e683696b5f05236d2805/comtypes-1.4.16.tar.gz", hash = "sha256:cd66d1add01265cface4df51ba1e31cd1657e04463c281c802e737e79e1ba93c", size = 260252 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5f/7c/0eb685107290b6221c03c46d39214a4e42a124189691cb83ae3228257f46/comtypes-1.4.16-py3-none-any.whl", hash = "sha256:e18d85179ff12955524c5a8c3bc09cb3c0d890f1da4d7123d14244c7b78f84c8", size = 296230 }, +] + [[package]] name = "confection" version = "1.3.3" @@ -2331,14 +2340,14 @@ requires-dist = [ { name = "openadapt", extras = ["macos"], marker = "sys_platform == 'darwin' and extra == 'all'" }, { name = "openadapt-capture", marker = "extra == 'capture'", specifier = ">=1.0.4,<2.0.0" }, { name = "openadapt-evals", marker = "extra == 'evals'", specifier = ">=0.1.0" }, - { name = "openadapt-flow", marker = "extra == 'flow'", specifier = ">=1.20.1,<2.0.0" }, - { name = "openadapt-flow", extras = ["capture"], marker = "extra == 'capture'", specifier = ">=1.20.1,<2.0.0" }, - { name = "openadapt-flow", extras = ["hosted"], specifier = ">=1.20.1,<2.0.0" }, - { name = "openadapt-flow", extras = ["linux"], marker = "sys_platform == 'linux' and extra == 'linux'", specifier = ">=1.20.1,<2.0.0" }, - { name = "openadapt-flow", extras = ["macos"], marker = "sys_platform == 'darwin' and extra == 'macos'", specifier = ">=1.20.1,<2.0.0" }, - { name = "openadapt-flow", extras = ["privacy"], marker = "extra == 'privacy'", specifier = ">=1.20.1,<2.0.0" }, - { name = "openadapt-flow", extras = ["rdp"], marker = "extra == 'rdp'", specifier = ">=1.20.1,<2.0.0" }, - { name = "openadapt-flow", extras = ["windows"], marker = "extra == 'windows'", specifier = ">=1.20.1,<2.0.0" }, + { name = "openadapt-flow", marker = "extra == 'flow'", specifier = ">=1.25.1,<2.0.0" }, + { name = "openadapt-flow", extras = ["capture"], marker = "extra == 'capture'", specifier = ">=1.25.1,<2.0.0" }, + { name = "openadapt-flow", extras = ["hosted"], specifier = ">=1.25.1,<2.0.0" }, + { name = "openadapt-flow", extras = ["linux"], marker = "sys_platform == 'linux' and extra == 'linux'", specifier = ">=1.25.1,<2.0.0" }, + { name = "openadapt-flow", extras = ["macos"], marker = "sys_platform == 'darwin' and extra == 'macos'", specifier = ">=1.25.1,<2.0.0" }, + { name = "openadapt-flow", extras = ["privacy"], marker = "extra == 'privacy'", specifier = ">=1.25.1,<2.0.0" }, + { name = "openadapt-flow", extras = ["rdp"], marker = "extra == 'rdp'", specifier = ">=1.25.1,<2.0.0" }, + { name = "openadapt-flow", extras = ["windows"], marker = "extra == 'windows'", specifier = ">=1.25.1,<2.0.0" }, { name = "openadapt-grounding", marker = "extra == 'grounding'", specifier = ">=0.1.0" }, { name = "openadapt-ml", marker = "extra == 'ml'", specifier = ">=0.2.0" }, { name = "openadapt-retrieval", marker = "extra == 'retrieval'", specifier = ">=0.1.0" }, @@ -2350,7 +2359,7 @@ requires-dist = [ [[package]] name = "openadapt-capture" -version = "1.0.4" +version = "1.2.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "alembic" }, @@ -2359,22 +2368,22 @@ dependencies = [ { name = "matplotlib" }, { name = "mss" }, { name = "numpy" }, - { name = "openai" }, { name = "pillow" }, { name = "psutil" }, { name = "pydantic" }, { name = "pydantic-settings" }, { name = "pympler" }, { name = "pyobjc-framework-applicationservices", marker = "sys_platform == 'darwin'" }, + { name = "pywinauto", marker = "sys_platform == 'win32'" }, { name = "sounddevice" }, { name = "soundfile" }, { name = "sqlalchemy" }, { name = "tqdm" }, { name = "websockets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9e/b7/d7002739f0eca1bcdaa748c4e47154b8c0c785387ae3f1f584d13f8062e1/openadapt_capture-1.0.4.tar.gz", hash = "sha256:990b93ed81f58c55ae0b5ee2dd09bcf1714740e7d995768d119ca742fb2ce9fc", size = 11976924 } +sdist = { url = "https://files.pythonhosted.org/packages/19/ff/fdba52fe9ca72c3d3acca72d3382d4bb12870aa134a8958ea4c8bec00d59/openadapt_capture-1.2.2.tar.gz", hash = "sha256:6f4298d3daadf9cced8994207e34b3116a79209ef792e98f778a0770e2f3406c", size = 974499 } wheels = [ - { url = "https://files.pythonhosted.org/packages/25/39/31677da3654aae8671c80abcca51ac805bf3331e62d95aa1c825a274dfb1/openadapt_capture-1.0.4-py3-none-any.whl", hash = "sha256:a5e93317e054f5faef6dd88ce9a50878770b16cffca97e21d59e6c171b4c6808", size = 185407 }, + { url = "https://files.pythonhosted.org/packages/48/11/d737d8125155f98695e2331c8d16084869946d39fb97a52e694c1ef80e3e/openadapt_capture-1.2.2-py3-none-any.whl", hash = "sha256:550fffe50990fa8431d332bdd5fe4755976d83baa7ad62553f50ad9e4ddcd1ae", size = 202545 }, ] [[package]] @@ -2415,7 +2424,7 @@ wheels = [ [[package]] name = "openadapt-flow" -version = "1.20.1" +version = "1.27.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cryptography" }, @@ -2424,15 +2433,14 @@ dependencies = [ { name = "numpy" }, { name = "opencv-python-headless" }, { name = "pillow" }, - { name = "playwright" }, { name = "pydantic" }, { name = "pyyaml" }, { name = "rapidocr-onnxruntime" }, { name = "tomli", marker = "python_full_version < '3.11'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/76/c6/89fdb1162a3e2473b88349d010a4c85d51630f29267c1e135bbffe893e09/openadapt_flow-1.20.1.tar.gz", hash = "sha256:b65dbe853f25f8d259ba848eb5c7ae3494ef12c472ae0d9c3758687fee1650a1", size = 18851535 } +sdist = { url = "https://files.pythonhosted.org/packages/8b/28/f29542489f2a45d3c80f28bde06a344e28d090d3e2721c760b2d6ebcba93/openadapt_flow-1.27.0.tar.gz", hash = "sha256:2c0c1da300659ea6007d194cc07732e7436b06b2a0cbcf0386256f1064ebc107", size = 19780272 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ba/12/e7b2630b231fa85ebe559e6934298dd5bfa8b4ae36dec884114dd5de85e7/openadapt_flow-1.20.1-py3-none-any.whl", hash = "sha256:9b8b7677bcb39f1c0448e012ec9791b6c44dce4e0a8c04734165e663c99cc8f3", size = 1182939 }, + { url = "https://files.pythonhosted.org/packages/42/e5/c08a34a0fc3ab4d05e37e55db11347fa1eb56fb86082de217f2970c35cd0/openadapt_flow-1.27.0-py3-none-any.whl", hash = "sha256:1de9fd1fb89811e2411946fcc61bfbf08e433b746ff6a4008f3294332abb816b", size = 1685766 }, ] [package.optional-dependencies] @@ -3462,6 +3470,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/7c/de/4ee4d1022fcf6519471d84aa662beadcc2e3b656f28a566a8688a727f4d6/python_gdcm-3.2.6-cp312-cp312-win_amd64.whl", hash = "sha256:3ad86fffde082e068a9ebef940be21079c5d80dae30787eaaccf822ecaac964d", size = 34239099 }, ] +[[package]] +name = "python-xlib" +version = "0.33" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six", marker = "sys_platform != 'darwin' and sys_platform != 'linux'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/86/f5/8c0653e5bb54e0cbdfe27bf32d41f27bc4e12faa8742778c17f2a71be2c0/python-xlib-0.33.tar.gz", hash = "sha256:55af7906a2c75ce6cb280a584776080602444f75815a7aff4d287bb2d7018b32", size = 269068 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fc/b8/ff33610932e0ee81ae7f1269c890f697d56ff74b9f5b2ee5d9b7fa2c5355/python_xlib-0.33-py2.py3-none-any.whl", hash = "sha256:c3534038d42e0df2f1392a1b30a15a4ff5fdc2b86cfa94f072bf11b10a164398", size = 182185 }, +] + [[package]] name = "python3-xlib" version = "0.15" @@ -3499,6 +3519,21 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/de/3d/8161f7711c017e01ac9f008dfddd9410dff3674334c233bde66e7ba65bbf/pywin32_ctypes-0.2.3-py3-none-any.whl", hash = "sha256:8a1513379d709975552d202d942d9837758905c8d01eb82b8bcc30918929e7b8", size = 30756 }, ] +[[package]] +name = "pywinauto" +version = "0.6.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "comtypes", marker = "sys_platform == 'win32'" }, + { name = "python-xlib", marker = "platform_system == 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux'" }, + { name = "pywin32", marker = "sys_platform == 'win32'" }, + { name = "six", marker = "sys_platform != 'darwin' and sys_platform != 'linux'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2c/85/cc65e3b64e7473cc86c07f0b5c415d509402c03ef19dadc39c583835eb5f/pywinauto-0.6.9.tar.gz", hash = "sha256:94d710bfa796df245250f952ffa65d97233d9807bcd42e052b71b81af469b6de", size = 434734 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/44/46/f2283648e0c237af451dc50ebc42121abfd198d12391fd9ad4df1c6b97d2/pywinauto-0.6.9-py2.py3-none-any.whl", hash = "sha256:5924b3072864a1d730c5546bbeb17cf4063ba518b618dbc5e43c18276c7c9356", size = 363041 }, +] + [[package]] name = "pyyaml" version = "6.0.3" From 95232e9253b047ea205b8aa56c8aa09ae0050cb5 Mon Sep 17 00:00:00 2001 From: abrichr Date: Thu, 30 Jul 2026 12:47:02 -0400 Subject: [PATCH 2/2] style: format quickstart output --- openadapt/cli.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openadapt/cli.py b/openadapt/cli.py index 8089f22c3..04adf4fa5 100644 --- a/openadapt/cli.py +++ b/openadapt/cli.py @@ -220,7 +220,9 @@ def quickstart(out: Path, headed: bool) -> None: click.echo(f"Bundle: {root / 'bundle'}") click.echo(f"Run evidence: {root / 'run'}") click.echo("Outcome: VERIFIED under the Standard profile.") - click.echo("The synthetic write was confirmed through a read-only system-of-record API.") + click.echo( + "The synthetic write was confirmed through a read-only system-of-record API." + ) click.echo("No model or Cloud call was enabled.") click.echo(f"Inspect qualification gaps: openadapt flow lint {root / 'bundle'}") click.echo(