pray-cli 1.22.0

Package manager for the language placed before inference — Prayfile CLI (binary: pray)
pub(crate) const WORKFLOW_COMMANDS: &[&str] = &[
    "install [--locked|--frozen|--offline|--strict]  keep locked versions, re-embed listed locals",
    "plan [--remote]                        dry-run of install: dest after patch",
    "apply                                  apply the current plan",
    "verify [--strict]                      dest managed spans versus Prayfile.lock",
    "drift [--semantic]                     dest versus lock, then dest versus a fresh render",
    "render [--check]                       write dest and Prayfile.lock from current inputs",
    "format|fmt                             rewrite Prayfile to recommended destination DSL",
];

pub(crate) const PACKAGE_COMMANDS: &[&str] = &[
    "add <name> [constraint] [--path PATH]  declare a package in Prayfile",
    "remove <name>                          remove a package from Prayfile",
    "update [package] [--major|--latest|--dry-run|--json]  re-resolve packages and git sources within constraints",
    "unlock <package>                       clear a locked package pin",
    "vendor                                 copy resolved packages locally",
    "clean [--unused]                       remove local state or unused registry entries",
    "doctor [--migrate-git-cache]           report git cache layout; optional legacy quarantine",
];

#[cfg(feature = "auth")]
pub(crate) const DISTRIBUTION_COMMANDS: &[&str] = &[
    "publish [--root PATH|--server URL|--to NAME] [--dry-run] [--signing-key PATH] [--resign]",
    "yank <package> <version> [--root PATH | --to NAME] [--undo]",
    "token create|revoke [--root PATH | --to NAME] ...",
    "login --server URL --email EMAIL",
    "serve [--root PATH | --to NAME] [--host HOST] [--port PORT] [--stdio] [--allow-open-push]",
    "sync [--root PATH] [--peer URL ...]",
    "confess <package> | --from-lock SPAN_ID [--accepted|--rejected]",
];

#[cfg(not(feature = "auth"))]
pub(crate) const DISTRIBUTION_COMMANDS: &[&str] = &[
    "publish [--root PATH|--server URL|--to NAME] [--dry-run] [--signing-key PATH] [--resign]",
    "yank <package> <version> [--root PATH | --to NAME] [--undo]",
    "login --server URL --email EMAIL",
    "sync [--root PATH] [--peer URL ...]",
    "confess <package> | --from-lock SPAN_ID [--accepted|--rejected]",
];

pub(crate) const TRUST_COMMANDS: &[&str] =
    &["trust list|show|add-key|remove-key|set-signed|set-require-signed-packages|set-allow|import-repo|import-registry|check"];

pub(crate) const INSPECT_COMMANDS: &[&str] = &[
    "list                                   list declared packages",
    "search <query> [--source|--root|--url]  find packages in a distribution index",
    "outdated [--remote]                    show constraint vs resolved versions",
    "explain <package>                      show why a package was selected",
    "tree                                   print the dependency tree",
];

pub(crate) const META_COMMANDS: &[&str] = &[
    "init [--targets tool_a,tool_b]         create a starter Prayfile",
    "prayer init [name] [--path DIR]       scaffold a local prayer",
    "repo init                              scaffold a distribution root",
    "manifest                               print canonical Prayfile JSON",
    "package                                build a distributable prayer archive",
    "completion bash|zsh|fish               print shell completion script",
    "upgrade                                install the latest pray CLI release",
    "version | -V | --version               print the pray CLI version",
];

pub(crate) const GLOBAL_OPTIONS: &[&str] = &[
    "--path PATH           project root (default: current directory)",
    "--file-path PATH      Prayfile path",
    "--env NAME            environment name",
    "--no-input            disable prompts",
    "-q, --quiet           suppress non-error status stdout",
    "-v, --verbose         extra status detail on stdout",
    "--rm                  use an ephemeral home directory",
    "--trust [--global]    import trust on first use",
];

pub(crate) fn command_help_text(command: &str) -> Option<&'static str> {
    match command {
        "install" => Some(
            "keep locked package versions and re-embed listed local compose sources\n\n\
             Usage: pray install [--locked|--frozen|--offline|--strict]\n\n\
             Install renders dest and writes Prayfile.lock. Package versions stay at the lock.\n\
             Listed local compose files are re-embedded and their span checksums refresh.\n\
             A path package with spec.upstream copies upstream files when the path tree has no content yet.\n\
             Use pray update to re-resolve package versions and git sources.\n\
             Use pray plan to preview a write.\n\n\
             --locked   require an existing lockfile\n\
             --frozen   fail if dest or lock would change\n\
             --offline  use cache only\n\
             --strict   fail if a locked package version is yanked",
        ),
        "plan" => Some(
            "preview what install or apply would write after patch\n\n\
             Usage: pray plan [--remote]\n\n\
             This is the dry-run of a write. It does not write dest or the lock.",
        ),
        "apply" => Some("materialize the current resolution plan\n\nUsage: pray apply"),
        "verify" => Some(
            "compare dest managed spans versus Prayfile.lock\n\n\
             Usage: pray verify [--strict]\n\n\
             Read-only integrity check. It does not compare dest to a fresh render from current sources.\n\
             A changed local compose file is clean here when dest and lock still match.\n\
             Use pray drift to compare dest with a fresh render. Use pray plan to preview a write.\n\n\
             Without --strict, orphan-marker warnings print to stderr but exit 0.\n\
             With --strict, any finding fails with exit code 6.",
        ),
        "drift" => Some(
            "compare dest versus Prayfile.lock, then dest versus a fresh render\n\n\
             Usage: pray drift [--semantic]\n\n\
             Read-only finding report from current packages and listed local files. Not a line diff.\n\
             Exits with code 6 when drift is found.\n\
             --semantic prints package version arrows only.\n\
             Use pray plan to preview a write. Use pray verify for dest versus lock alone.",
        ),
        "render" => Some(
            "write dest and Prayfile.lock from current inputs\n\n\
             Usage: pray render [--check]\n\n\
             Without --check, render writes dest and the lock. Use pray plan to preview a write.\n\
             --check writes nothing. It fails unless dest already matches a fresh render from current inputs.\n\
             That is a dest identity gate, not a preview.",
        ),
        "format" | "fmt" => Some(
            "rewrite Prayfile to recommended destination DSL\n\n\
             Usage: pray format\n       pray fmt",
        ),
        "add" => Some(
            "declare a package in Prayfile\n\n\
             Usage: pray add <name> [constraint] [--path PATH]",
        ),
        "remove" => Some("remove a package from Prayfile\n\nUsage: pray remove <name>"),
        "update" => Some(
            "re-resolve package versions and git sources within current constraints\n\n\
             Usage: pray update [package] [--major] [--latest] [--dry-run] [--json]\n\n\
             With no package name, update re-resolves the whole graph within constraints\n\
             and refreshes git source revisions. A package name unlocks that package only.\n\
             Path-fork packages can refresh from upstream.\n\
             When a branded path fork conflicts, reset conflicting content to the locked upstream,\n\
             run update --latest, re-apply overlays, then bump the fork version.\n\
             Listed local compose files are re-embedded by pray install, not by update.\n\n\
             --major requires a package name.\n\
             --latest rewrites Prayfile constraints and exact spec.upstream pins to admit the latest versions, then refreshes those trees.\n\
             --latest --dry-run previews those versions, checks destination conflicts,\n\
             and lists would-conflict path-fork content paths before write.\n\
             If a destination conflicts, inspect it and move it aside before retrying.\n\
             --json prints machine-readable output.\n\
             For files from an older pray, install the original package version first.",
        ),
        "unlock" => Some("clear a locked package pin\n\nUsage: pray unlock <package>"),
        "vendor" => Some("copy resolved packages locally\n\nUsage: pray vendor"),
        "clean" => Some(
            "remove local cache and vendor trees, or only unused registry entries\n\n\
             Usage: pray clean [--unused]",
        ),
        "doctor" => Some(
            "report project git cache layout and shared-bare trust paths\n\n\
             Usage: pray doctor [--migrate-git-cache]\n\n\
             --migrate-git-cache renames matching project full clones to *.legacy-git.\n\
             Shallow plus partial clones remain the default for distribution git sources.",
        ),
        "publish" => Some(
            "upload path packages to a registry or local root\n\n\
             Usage: pray publish [--root PATH] [--server URL ...] [--to NAME] [--dry-run] [--signing-key PATH] [--resign]\n\n\
             Prayfile publish remotes supply dests when flags are omitted.\n\
             Live publish prints published or unchanged lines and a short count footer.\n\
             --dry-run prints the planned lines without writing.\n\
             Prefer --signing-key PATH or PRAY_SIGNING_KEY (32-byte ed25519 seed).\n\
             Without a signing key, publish records a legacy content digest.\n\
             --resign uses that key for unchanged versions in a local root.\n\
             Global -q/--quiet suppresses this stdout; -v/--verbose adds artifact paths.",
        ),
        "yank" => Some(
            "mark or unmark a published version as yanked in a distribution root\n\n\
             Usage: pray yank <package> <version> [--root PATH | --to NAME] [--undo]\n\n\
             Yank flips metadata only; artifact bytes stay immutable.\n\
             New resolves skip yanked versions. Locked installs may continue with a warning;\n\
             use pray install --strict to refuse them.",
        ),
        #[cfg(feature = "auth")]
        "token" => Some(
            "mint or revoke scoped publish tokens for a distribution root\n\n\
             Usage: pray token create [--root PATH | --to NAME] --email EMAIL [--scope publish]\n\
                    pray token revoke [--root PATH | --to NAME] TOKEN\n\n\
             Use the printed token as PRAY_PUBLISH_TOKEN for pray publish --server.",
        ),
        "search" => Some(
            "search a distribution index for package names\n\n\
             Usage: pray search <query> [--source NAME | --root PATH | --url URL]\n\n\
             Matches package names (substring, case-insensitive). Optional summaries come from\n\
             package metadata when available. No ranking.",
        ),
        "login" => Some(
            "authenticate to a registry server\n\n\
             Usage: pray login --server URL --email EMAIL \\\n\
                    (--passkey-key PATH --credential-id ID | --ssh-agent --public-key PATH)",
        ),
        #[cfg(feature = "auth")]
        "serve" => Some(
            "run a local registry server\n\n\
             Usage: pray serve [--root PATH | --to NAME] [--host HOST] [--port PORT] [--stdio] [--allow-open-push]",
        ),
        "sync" => Some(
            "sync packages with peer registries\n\n\
             Usage: pray sync [--root PATH] [--peer URL ...]",
        ),
        "confess" => Some(
            "record an acceptance or rejection for a package confession\n\n\
             Usage: pray confess <package> | --from-lock SPAN_ID [--accepted|--rejected]",
        ),
        "trust" => Some(
            "manage client trust policy for remote sources\n\n\
             Usage: pray trust <subcommand>\n\n\
             Subcommands: list, show, add-key, remove-key, set-signed, \
             set-require-signed-packages, set-allow, import-repo, import-registry, check",
        ),
        "list" => Some("list declared packages\n\nUsage: pray list"),
        "outdated" => Some(
            "show constraint vs resolved versions\n\n\
             Usage: pray outdated [--remote]\n\n\
             Path-fork files that differ from the locked upstream are listed.",
        ),
        "explain" => Some(
            "show why a package was selected\n\n\
             Usage: pray explain <package>",
        ),
        "tree" => Some("print the dependency tree\n\nUsage: pray tree"),
        "init" => Some("create a starter Prayfile\n\nUsage: pray init [--targets tool_a,tool_b]"),
        "prayer" => Some(
            "scaffold a local prayer under a path source\n\n\
             Usage: pray prayer init [name] [--path DIR]\n\n\
             With a Prayfile, writes <name>/ under the path source directory without a version.\n\
             The default directory is prayers/. Use --path to choose another.\n\
             Declares pray \"<source>/<name>\" once, such as pray \"local/project\", inside compose when a compose block exists.\n\
             The default name is project. The name v1 is reserved for the distribution layout.\n\
             Named prayers may sit beside prayers/v1/. Keep sources under prayers/<name>/.\n\
             Without a Prayfile, writes a versioned package spec in the current directory.\n\
             Add spec.version before pray package or pray publish.\n\
             A compose file such as .agents/project.md remains a shortcut for one local file.",
        ),
        "repo" => Some(
            "scaffold a distribution root\n\n\
             Usage: pray repo init\n\n\
             Writes prayers/v1/. Git install discovers that catalog. Named prayers may sit beside v1/.\n\
             Keep sources under prayers/<name>/.",
        ),
        "manifest" => Some("print canonical Prayfile JSON\n\nUsage: pray manifest"),
        "package" => Some("build a distributable prayer archive\n\nUsage: pray package"),
        "upgrade" => Some(
            "install the latest pray CLI release\n\n\
             Usage: pray upgrade\n\n\
             Runs `cargo install pray-cli --locked --force`.",
        ),
        "version" => Some("print the pray CLI version\n\nUsage: pray version\n       pray -V | --version"),
        "completion" => Some(
            "print a shell completion script\n\n\
             Usage: pray completion bash|zsh|fish\n\n\
             Redirect stdout into your shell completion directory.",
        ),
        "help" => Some(
            "show help for pray or one command\n\n\
             Usage: pray help [command]\n       pray [command] --help",
        ),
        _ => None,
    }
}