diff --git a/AGENTS.md b/AGENTS.md index bcf0071..30d588b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -24,14 +24,15 @@ deep `verify_install` suite, and URL hygiene all live in PyAutoHeart now; `autohands verify_install` / `autohands url_check` / `autohands watch|status| tick|fix` are thin shims that delegate to `pyauto-heart`. Build keeps only the executor primitives: the build/notebook pipeline (`pre_build`, `generate*`, -`run_all` / `run*`), the navigator catalogue (the `navigator.py` / -`check_navigator.py` / `regenerate_navigator.py` modules — workflow-invoked, -not CLI verbs), tagging + release (`tag_and_merge`, `bump_colab_urls`, -`release.yml`), the release-notes and Slack tooling -(`generate_release_notes`, `slack_release_notes`), the release board -(`board`, published by `release_board.yml`), assistant seeding -(`clone_seed`), and `repro_command`. `bin/autohands help` is the registry of -what is a CLI verb; see `docs/internals.md` for the pipeline detail. +`run_all` / `run*`), the navigator catalogue and the workspace guards, tagging + +release (`tag_and_merge`, `bump_colab_urls`, `release.yml`), the release-notes +and Slack tooling (`generate_release_notes`, `slack_release_notes`), the release +board (`board`, published by `release_board.yml`), assistant seeding +(`clone_seed`), and `repro_command`. `bin/autohands help` is the **complete** +registry of `autohands/` — every module there is a CLI verb or an +`INTERNAL_MODULES` entry, enforced by `tests/test_autohands_registry.py`, so +read `help` rather than listing verbs here. See `docs/internals.md` for the +pipeline detail. See [`docs/internals.md`](docs/internals.md) for the build pipeline, workspace folder structure, config files, and `release.yml` details. Read it when diff --git a/autohands/generate_release_notes.py b/autohands/generate_release_notes.py index 76988f4..206463b 100644 --- a/autohands/generate_release_notes.py +++ b/autohands/generate_release_notes.py @@ -14,39 +14,9 @@ import subprocess import sys from argparse import ArgumentParser -from datetime import date from pathlib import Path -# Time-boxed announcement banner prepended to generated release notes. -# The banner is included only while today <= EXPIRY, then drops off -# automatically — no follow-up edit needed. Set EXPIRY to None (or move the -# date into the past) to disable. `repos` limits which repos show it; None -# means all repos. -ANNOUNCEMENT = { - "expiry": date(2026, 7, 24), - "repos": {"PyAutoLabs/PyAutoLens"}, - "markdown": ( - "> 📣 **Major Milestones Announcement** — PyAutoLens now ships an AI assistant " - "(conversational + agentic), full JAX GPU support, and agentic-AI development via " - "PyAutoScientist. " - "[Read the announcement →](https://github.com/PyAutoLabs/PyAutoLens/discussions/603)" - ), -} - - -def announcement_banner(repo, today=None): - """Return the announcement markdown for `repo`, or "" if none applies today.""" - today = today or date.today() - expiry = ANNOUNCEMENT.get("expiry") - if not expiry or today > expiry: - return "" - repos = ANNOUNCEMENT.get("repos") - if repos and repo not in repos: - return "" - return ANNOUNCEMENT.get("markdown", "") - - # Dependency chain: downstream repos include upstream changes UPSTREAM_DEPS = { "PyAutoLabs/PyAutoFit": [], @@ -197,12 +167,6 @@ def generate_notes(repo, version, prs, upstream_prs_by_repo): name = REPO_NAMES.get(repo, repo.split("/")[-1]) lines = [f"# {name} v{version}", ""] - # Time-boxed announcement banner (self-expiring; see ANNOUNCEMENT above). - banner = announcement_banner(repo) - if banner: - lines.append(banner) - lines.append("") - # Classify own PRs categories = {"breaking": [], "feature": [], "fix": [], "internal": []} for pr in prs: diff --git a/bin/autohands b/bin/autohands index e87221b..635dd23 100755 --- a/bin/autohands +++ b/bin/autohands @@ -21,6 +21,10 @@ ADMIN_JAMMY="$PYAUTOBASE/admin_jammy" # with "# " are rendered as section headers; everything else is a real # subcommand and must have a matching SHORT_DESC entry plus cmd_ and # help_ functions. +# +# Together with INTERNAL_MODULES below, this is the complete registry of +# autohands/: every module there is either a subcommand here or an internal +# module listed there. tests/test_autohands_registry.py enforces it. SUBCOMMAND_ORDER=( "# Build and release pipeline" @@ -31,17 +35,28 @@ SUBCOMMAND_ORDER=( bump_colab_urls "# Workspace operations (run from a workspace root)" generate + generate_markdown + regenerate_navigator run run_python run_all + "# Workspace guards (CI-invoked; runnable locally)" + check_navigator + check_search_memory + check_dataset_allowlist + validate_env_profiles "# Release support" board script_matrix aggregate_results slow_skip_check generate_release_notes + slack_release_notes create_analysis_issue tag_and_merge + tombstone + "# Assistant seeding" + clone_seed "# Triage support" repro_command "# Monitoring daemon (delegates to PyAutoHeart)" @@ -59,6 +74,12 @@ declare -A SHORT_DESC=( [url_check]="Shim → pyauto-heart url_check (forbidden Binder/Colab URL guard)" [bump_colab_urls]="Rewrite Colab URLs in cwd from old date-tag to new date-tag" [generate]="Convert workspace scripts/ to notebooks/ (run from a workspace root)" + [generate_markdown]="Render curated workspace scripts to executed markdown pages with figures" + [regenerate_navigator]="Rebuild a workspace's llms-full.txt + workspace_index.json catalogue" + [check_navigator]="Guard: navigator/instruction path references all resolve on disk" + [check_search_memory]="Guard: every MultiStart* search in a workspace sets batch_size explicitly" + [check_dataset_allowlist]="Guard: tracked dataset/ files are covered by the .gitignore allowlist" + [validate_env_profiles]="Guard: a workspace's smoke/release env profiles parse and resolve" [run]="Execute notebooks in a workspace folder" [run_python]="Execute Python scripts in a workspace folder" [run_all]="Run scripts across one or more workspaces and produce summary reports" @@ -67,8 +88,11 @@ declare -A SHORT_DESC=( [aggregate_results]="Aggregate per-job JSON results into a release-readiness report" [slow_skip_check]="Surface SLOW / NEEDS_FIX entries in workspace no_run.yaml files" [generate_release_notes]="Generate release notes from merged PRs and create GitHub Releases" + [slack_release_notes]="Convert a release body into the #pipreleases Slack payload" [create_analysis_issue]="Open a GitHub issue with the release report and assign Copilot" [tag_and_merge]="Commit and tag every library repo for a release" + [tombstone]="Build the sub-floor tombstone sdists that redirect users to a supported release" + [clone_seed]="Build (and optionally push) an assistant seed repo from a clone plan" [repro_command]="Emit the shell command autohands uses to run one script (for triage handoffs)" [watch]="Start the PyAutoHeart monitoring daemon (Ctrl-C to stop)" [status]="Print the latest PyAutoHeart state cache with green/yellow/red" @@ -77,6 +101,19 @@ declare -A SHORT_DESC=( [help]="List subcommands or show details for one" ) +# Modules in autohands/ that are deliberately NOT CLI verbs. Every *.py there +# must be a registered subcommand above or listed here — the completeness rule +# tests/test_autohands_registry.py enforces. Keep the reason on the line. +INTERNAL_MODULES=( + add_notebook_quotes # docstring->cell transform stage; its __main__ is a debug aid + run_notebook # per-notebook worker subprocess spawned by run.py + navigator # catalogue library behind regenerate_navigator / check_navigator + build_util # shared py_to_notebook machinery + env_config # env-profile resolution library + result_collector # per-run JSON result library + generate_autofit # generate.py's autofit-specific branch +) + # _python_in_autohands