Imports:
  - Types:
      - ProjectConfig
      - load_project_config
    Usages:
      - project-configuration
    From: goga/config
  - Types:
      - resync_registered_agents
    From: goga/connect

Usages:
  convention: .goga/usages/conventions.md
  click: .goga/usages/cooks/click.md

Annotations: |
  The `convention` practice is used for:
  - Working with the codebase
  - Organizing the REPL development cycle
  - Debugging and testing
  - Organizing the test infrastructure
  - Understanding the general principles and rules of development and testing in the project

  Use the `click` practice to build the command, its options, the optional
  positional argument, the --no-connect flag, and exit-code propagation.

  Use the `project-configuration` practice when the bulk path needs to read
  .goga/config.yml — load_project_config is the single entrypoint for config consumption,
  and its tools field is a raw mapping validated structurally only.

  After a successful pip install in single and bulk mode, activate every agent
  recorded in ~/.goga/connect.yml via `resync_registered_agents`; the --no-connect
  flag suppresses this activation, and empty mode never activates.

---

"resolve_version(form: str | None) -> spec: str | None":
  location: install.py
  annotations: |
    Sole owner of the four-form version grammar. Maps a version-form string to a
    pip specifier; raises ValueError on operator-prefixed or malformed input.
    Used by both the single path (--version CLI flag) and the bulk path
    (config.tools expansion).

    `form`: version-form string in one of the four grammar forms, or None when
      the --version CLI flag is absent (single path only)
    `spec`: resolved pip specifier to append to the package identifier, or None
      when no specifier should be appended (latest / null marker)

    Algorithm:
    1. If `form` is None or equals the literal string "latest" → return None
       (no specifier — pip selects the newest version under the upgrade request)
    2. If `form` starts with a PEP 440 operator prefix (==, >=, <=, ~=, !=, <,
       >, ===) → raise ValueError (operator-prefixed forms are rejected — this
       routine owns the operator and emits it from the resolved grammar form)
    3. If `form` matches the major x-range pattern "N.x" (exactly one dot, the
       last segment is the literal "x", the first segment is a non-empty
       numeric) → return a compatible-release specifier pinning the lower bound
       on major version N (the form ~=N.0, PEP 440: >=N.0,<(N+1).0)
    4. If `form` matches the minor x-range pattern "N.M.x" (exactly two dots,
       the last segment is the literal "x", the first two segments are
       non-empty numerics) → return a compatible-release specifier pinning the
       lower bound on minor version N.M (the form ~=N.M.0, PEP 440:
       >=N.M.0,<N.(M+1).0). The trailing .0 in ~=N.M.0 is required — ~=N.M
       alone has only a major bound (<(N+1).0) and would NOT pin the minor
       upper limit
    5. If `form` matches the concrete-version pattern "N", "N.M", or "N.M.K"
       (dot-separated non-empty numeric segments, no trailing "x" literal) →
       return an exact-pin specifier (the form ==<form>)
    6. Otherwise → raise ValueError (malformed form)

    Distinguish major x-range ("1.x") from minor x-range ("1.0.x") by counting
    dots — do NOT use prefix matching. The count of dots determines the lower
    bound: one dot pins the major version (form ~=N.0, PEP 440 upper bound
    <(N+1).0), two dots pin the minor version (form ~=N.M.0, PEP 440 upper
    bound <N.(M+1).0). The trailing .0 in the minor case is what actually
    drives the tighter upper bound — do NOT emit ~=N.M (major-only bound).

    Apply `convention` for docstring style and the pure-function discipline
    (no side effects, deterministic output).

    Requirements:
    - The four accepted forms are: "N.x" (major x-range), "N.M.x" (minor
      x-range), "N(.M)?(.K)?" (concrete numeric), "latest"
    - None input is accepted and resolves to None — this exists for the absent
      --version CLI flag in the single path; it is NOT a valid config.tools
      value (loader rejects YAML-null structurally)
    - "latest" and None produce identical output (None) but "latest" is the
      only canonical no-specifier marker inside config.tools
    - Every operator-prefixed form (==, >=, <=, ~=, !=, <, >, ===) raises
      ValueError — resolve_version owns the operator and emits it from the
      resolved grammar form
    - Pip specifier output is always prefixed with the operator (== or ~=);
      no operator is injected when None is returned

    Constraints:
    - Do NOT accept pre-release, post-release, or local-segment versions
      (1.0.0a1, 1.0.0.post1, 1.0.0+local) — anything richer than the four-form
      grammar is rejected; pip handles richer forms after resolution
    - Do NOT validate that the numeric segments form a real PEP 440 version —
      the routine recognises shape (dot-separated numerics), not existence
    - Do NOT read .goga/config.yml — this routine is a pure transformer
    - Do NOT log or perform I/O — it is a pure function

"install(ctx: click.Context, name: str | None, sudo: bool, version: str | None, local: str | None, no_connect: bool = False) -> exit_code: int":
  location: install.py
  annotations: |
    Install one or more goga-tool packages into the current runtime interpreter
    via pip and, on success, activate every already-connected agent. Branches
    across four paths: single (one named tool from PyPI with an optional
    four-form version), bulk (every tool declared in config.tools in a single
    pip invocation), empty (Nothing to install), and LOCAL (one pip-installable
    local directory). After a successful pip in single, local, and bulk mode,
    runs the activation re-sync unless `no_connect` is set. Propagates pip's
    returncode as the exit code whenever pip is invoked or re-sync is skipped;
    otherwise propagates the re-sync outcome (first non-zero per-agent failure).

    `exit_code`: pip's outcome when pip is invoked or re-sync is skipped; the
      first non-zero per-agent re-sync failure otherwise; 0 in the empty path.
    `ctx`: Click execution context used to control process exit codes.
    `name`: optional tool identifier without the goga-tool- / goga_tool_ prefix
      (CLI positional argument). When present, the single path runs and the
      config is ignored. When absent, the bulk/empty path runs from cfg.tools.
    `sudo`: when True, run pip under sudo with HOME preserved (Unix-only).
    `version`: optional version-form string in the four-form grammar. Used by
      the single path only (ignored in the bulk path). Resolved by
      resolve_version; operator-prefixed or malformed forms raise ValueError
      at resolution time. The CLI flag binding the callback's `version`
      parameter MUST expose both forms: the primary long form --version and
      the secondary short alias -v — Click receives them on a single Option
      so both deserialise into the same parameter.
    `local`: optional path to a pip-installable local directory. When set (and
      `name` is None), the LOCAL path runs: pip installs from the local
      directory instead of resolving goga-tool-<name> from PyPI. Mutually
      exclusive with `name`; `version` is rejected in this mode.
    `no_connect`: when True, skip the post-install activation re-sync — the
      command performs the pip install only. Defaults to False (re-sync enabled).

    Algorithm:
    0. VALIDATIONS (first, before any path):
       0.1. If `name` is not None AND `local` is not None -> raise a user-facing
            ClickException (mutual exclusion: a PyPI tool name and a local source
            path cannot be combined); exit non-zero.
       0.2. If `local` is not None AND `version` is not None -> raise a user-facing
            ClickException (--version applies to the SINGLE path only and is
            meaningless for a local source); exit non-zero.
    1. If `name` is not None → SINGLE PATH:
       1.1. Resolve `version` via resolve_version; on rejection, surface a
            user-facing CLI exception with a non-zero exit
       1.2. Compose the package identifier from `name` and the resolved specifier
            (empty when resolve_version returned None)
       1.3. Issue one pip install invocation against the current interpreter with
            the composed identifier and an upgrade request; apply sudo with HOME
            preservation when `sudo` is set
       1.4. Propagate pip's outcome as the pip exit code
    2. Else if `local` is not None -> LOCAL PATH:
       2.1. Issue one pip install invocation against the current interpreter with
            the local directory path as the install target and an upgrade request;
            apply sudo with HOME preservation when `sudo` is set. Do NOT validate
            path existence at the CLI layer — pip owns that error and its return
            code is translated unchanged.
       2.2. Propagate pip's outcome as the pip exit code.
    3. If `name` is None → BULK / EMPTY PATH:
       3.1. Load configuration via `load_project_config`; the result is a `ProjectConfig` instance.
            Loader exceptions (OSError, KeyError, ValueError, yaml.YAMLError)
            MUST be wrapped into a user-facing ClickException (non-zero exit) —
            never let a raw loader exception surface as a traceback.
       3.2. Read the tools mapping from cfg.tools (treat None as empty)
       3.3. If the mapping is empty → EMPTY PATH: print "Nothing to install" to
            stdout and exit 0 without invoking pip and without activation
       3.4. Else → BULK PATH: for each (tool_name, form) preserving insertion
            order, resolve the form via resolve_version (surface rejection as a
            user-facing CLI exception), compose the identifier, collect it; issue
            exactly one pip install invocation with every collected identifier
            and an upgrade request; apply sudo with HOME preservation when `sudo`
            is set; propagate pip's outcome as the pip exit code
    4. ACTIVATION (single, local, and bulk paths only, after pip):
       (LOCAL participates by the same rules as single/bulk)
       4.1. If `no_connect` is True → keep the pip exit code and stop
       4.2. If the pip exit code is non-zero → keep the pip exit code and stop
       4.3. Otherwise call `resync_registered_agents` with the current user's goga
            home (~/.goga); the routine reads ~/.goga/connect.yml and re-activates
            every recorded agent
       4.4. The final exit code becomes the re-sync outcome (0 on full success or
            a missing/empty registry; otherwise the first non-zero per-agent failure)

    Apply `click` for the command shape, the optional positional argument, the
    flags, the options (including the --local/-l secondary short alias on a
    single Option, like --version/-v), the mutex/version ClickException,
    ctx.pass_context, ctx.exit, click.echo for the empty-path message, and
    exit-code propagation. Apply `convention` for the CLI command docstring rule
    (--help rendered verbatim by Click; omit Args/Returns/Raises), import
    discipline, and structured logging. Apply `project-configuration` for
    load_project_config() semantics and the no-validation contract on cfg.tools;
    `project-configuration` is NOT used by the LOCAL path (config is ignored,
    same as SINGLE).

    Requirements:
    - The single path MUST ignore cfg.tools entirely — name + flags fully
      determine the call
    - The bulk path MUST issue exactly one pip invocation whose argv contains
      every resolved goga-tool-<name><spec> in YAML order
    - The empty path MUST print "Nothing to install" to stdout and exit 0
      without invoking pip and without activation
    - The --version option is used by the single path only; the bulk path
      MUST NOT consult it
    - The version flag MUST be registered with both the long form --version
      and the short alias -v on the same Click Option (Click secondary
      flag); both forms bind the callback's `version` parameter identically
    - --sudo MUST apply sudo with HOME preservation to the (single) pip argv in
      both single and bulk modes; activation never runs under sudo
    - Activation MUST run only when pip succeeded (exit 0) in single or bulk
      mode and `no_connect` is False; it MUST NOT run in the empty path or after
      a non-zero pip
    - The final exit code MUST equal the pip outcome when pip failed, when
      `no_connect` is set, or in the empty path; otherwise it MUST equal the
      activation re-sync outcome
    - pip MUST be invoked through the current interpreter with an upgrade
      request present in every invocation
    - The LOCAL path MUST install exactly one local directory via a single pip
      invocation with an upgrade request; the local path replaces the PyPI source
    - `name` and --local MUST be mutually exclusive — combining them is a
      user-facing error (non-zero exit)
    - --version MUST be rejected in the LOCAL path (non-zero exit); SINGLE only
    - The LOCAL path MUST participate in post-install activation by the same
      rules as SINGLE/BULK: activation runs when pip succeeded (exit 0) and
      `no_connect` is False; --no-connect suppresses it
    - The LOCAL path MUST translate pip's return code unchanged (including pip's
      own errors for a missing/non-installable path)
    - --sudo MUST apply sudo with HOME preservation to the single pip argv in
      the LOCAL path; activation never runs under sudo
    - The --local/-l flag MUST be registered with both the long form --local
      and the short alias -l on the same Click Option

    Constraints:
    - Do NOT validate, parse, or modify `version` outside resolve_version —
      resolve_version is the sole owner of the grammar and the single point
      where malformed forms raise ValueError
    - Do NOT accept operator-prefixed forms in either --version or cfg.tools —
      they raise ValueError at resolution time
    - Do NOT install packages sequentially in the bulk path — all resolved
      packages MUST land in one pip argv
    - Do NOT auto-select sudo — the caller opts in via --sudo
    - Do NOT run activation under sudo — activation operates on the local user
      home; only pip honors --sudo
    - Do NOT write ~/.goga/connect.yml directly — activation goes through
      `resync_registered_agents`; connect is the single writer of the registry,
      and this command never writes it
    - Do NOT probe whether the package is already installed — the upgrade
      request handles it
    - Do NOT chunk the bulk argv — even a long argv is issued as a single pip
      invocation
    - On Windows, --sudo is unavailable (sudo is Unix-only)
    - Do NOT install in editable mode (-e) in the LOCAL path — install the
      local directory the same way SINGLE/BULK install from PyPI (regular
      install with -U)
    - Do NOT validate the local path's existence at the CLI layer — let pip
      surface the error and translate its exit code
    - Do NOT resolve a goga-tool-<name> identifier in the LOCAL path — the local
      directory is the install target as-is
    - Do NOT consult `version` in the LOCAL path — it is rejected at validation
      time

---

Author: Goga
CreatedAt: 13/07/26

Description: |
  Installs one or more goga-tool packages into the current runtime interpreter
  via pip, propagates pip's outcome as the exit code, and — on success — activates
  every already-connected agent via the shared re-sync. Supports single-path install
  (one named tool with an optional four-form version), bulk-path install (every tool
  declared in config.tools in a single pip invocation), empty-path no-op
  (Nothing to install), and local-path install (one pip-installable local directory
  via the --local/-l option). The four-form version grammar is owned by
  resolve_version; the --no-connect flag suppresses post-install activation; --version
  applies to the single path only and is rejected in local mode.
