oy/lib.rs
1//! # oy
2//!
3//! `oy` adds one focused coding-agent behavior and repeatable repository audit/review workflows
4//! to [OpenCode 2](https://v2.opencode.ai/) and Cursor. File-backed CLI preparation and
5//! finalization provide deterministic repository collection, ordered chunks, target-diff input,
6//! and normalized Markdown/SARIF reports. The selected host remains responsible for model
7//! execution, providers, authenticated sessions, permissions, and general coding tools. oy does
8//! not store provider credentials.
9//! The native CLI supports Linux and macOS; Windows users should run it in WSL2.
10//!
11//! ## Start with the CLI
12//!
13//! The command-line interface is the supported automation surface:
14//!
15//! ```text
16//! oy setup --dry-run # preview package/config migration
17//! oy setup # register the version-matched OpenCode package
18//! oy setup --cursor # install Cursor rule, subagent, and skills
19//! oy audit # write ISSUES.md
20//! oy review main # write REVIEW.md for git diff main
21//! oy enhance <finding-id> # remediate one reported finding
22//! ```
23//!
24//! See the [getting-started guide](https://oy.adonm.dev/getting-started.html),
25//! [workflow guide](https://oy.adonm.dev/workflows.html), and
26//! [CLI and OpenCode reference](https://oy.adonm.dev/reference.html) for the user-facing
27//! contract.
28//!
29//! ## Determinism boundary
30//!
31//! Input collection, ordering, limits, and report rendering are deterministic. Findings are
32//! produced by the model selected in opencode and are not deterministic. The collector also
33//! has documented exclusions; “all chunks” does not mean every byte in a repository.
34//!
35//! ## Rust API
36//!
37//! This crate exists primarily to keep the `oy` binary entrypoint small. [`run`] and
38//! [`err_line`] are public for that entrypoint and lightweight embedding, but spawning the
39//! `oy` executable is preferred for automation. Other modules and implementation details are
40//! private and may change without a semver-stable library API commitment.
41//!
42//! ```no_run
43//! # fn example() -> anyhow::Result<()> {
44//! // Arguments exclude the executable name, just like std::env::args().skip(1).
45//! let exit_code = oy::run(vec!["doctor".into(), "--json".into()])?;
46//! assert_eq!(exit_code, 0);
47//! # Ok(())
48//! # }
49//! ```
50
51#![recursion_limit = "256"]
52
53mod artifacts;
54mod audit;
55mod cli;
56mod cursor;
57mod opencode;
58mod review;
59mod tools;
60mod workflow;
61
62pub(crate) use cli::{config, ui};
63
64#[derive(Debug, Clone, Copy, PartialEq, Eq)]
65pub(crate) enum TextDecodeError {
66 Binary,
67 NonUtf8,
68}
69
70pub(crate) fn decode_utf8(raw: Vec<u8>) -> Result<String, TextDecodeError> {
71 if raw.contains(&0) {
72 return Err(TextDecodeError::Binary);
73 }
74 String::from_utf8(raw).map_err(|_| TextDecodeError::NonUtf8)
75}
76
77/// Runs the `oy` command dispatcher with arguments that exclude the executable name.
78///
79/// Normal command and delegated opencode exit statuses are returned as `Ok(code)`. Setup,
80/// filesystem, process-launch, and protocol failures are returned as errors. This function may
81/// update opencode integration config or launch child processes depending on the arguments.
82///
83/// Prefer invoking the `oy` executable when process isolation or concurrent invocations matter;
84/// CLI output configuration is process-global.
85pub fn run(argv: Vec<String>) -> anyhow::Result<i32> {
86 cli::app::run(argv)
87}
88
89/// Writes a formatted diagnostic line to standard error.
90///
91/// This is primarily exposed for the binary entrypoint.
92///
93/// ```
94/// oy::err_line(format_args!("error: {}", "example"));
95/// ```
96pub fn err_line(args: std::fmt::Arguments<'_>) {
97 ui::err_line(args);
98}