Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
94ddc00
feat(linter): emit GitHub Actions annotations when GITHUB_ACTIONS=true
xen0n Mar 14, 2026
7497bc4
feat(linter): include intent text in GitHub Actions annotations
xen0n Mar 14, 2026
3cfac1a
docs(linter): approve all non-stale intents
xen0n Mar 14, 2026
893ce1c
docs(design): add StaleReviewed as third approve candidate type
xen0n Mar 14, 2026
1d4a8ae
refactor(linter): add CandidateKind, ApproveFilter, and kind-aware TUI
xen0n Mar 14, 2026
10b3484
feat(linter): stale-reviewed approval flow
xen0n Mar 14, 2026
d1699e9
feat(linter): req-changed approval flow with global requirement registry
xen0n Mar 14, 2026
42bda9c
docs(linter): update sidecar specs for stale-reviewed and req-changed…
xen0n Mar 14, 2026
cc97475
docs(linter): approve all non-stale intents
xen0n Mar 14, 2026
dd4cc26
docs(linter): approve run_check intent
xen0n Mar 14, 2026
011d225
fix(linter): escape documentary `@liyi:intent` mention in comment
xen0n Mar 14, 2026
468d899
docs(linter): approve check_sidecar intent
xen0n Mar 14, 2026
8f2a93b
refactor(linter): extract run_check into composable helpers
xen0n Mar 14, 2026
487814a
refactor(linter): extract check_sidecar item sub-checks
xen0n Mar 14, 2026
bc63c20
refactor(linter): extract check_requirement_hash from check_sidecar
xen0n Mar 14, 2026
73b9b71
refactor(linter): extract item hash checking from check_sidecar
xen0n Mar 14, 2026
7206e74
docs(linter): update check.rs sidecar for refactored helpers
xen0n Mar 14, 2026
095c11d
docs(linter): approve all but 1 intent
xen0n Mar 14, 2026
9626175
refactor(linter): rename emit_discovery_warnings to emit_ambiguous_si…
xen0n Mar 14, 2026
3a7dcc7
docs(linter): approve the renamed fn
xen0n Mar 14, 2026
f6291a6
style: cargo fmt && liyi check --fix && liyi approve
xen0n Mar 14, 2026
89650ba
ci: fix loongarch64 and riscv64 builds not being static by default
xen0n Mar 14, 2026
765a4b3
docs(ci): approve intents
xen0n Mar 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,12 @@ jobs:
- name: Build release binary (cross)
if: matrix.cross
run: |
# aarch64-unknown-linux-musl produces static binaries by default, but
# loongarch64 and riscv64 musl targets require explicit flags
export CROSS_LOONGARCH64_UNKNOWN_LINUX_MUSL_LINKER=loongarch64-unknown-linux-musl-gcc
export CROSS_RISCV64GC_UNKNOWN_LINUX_MUSL_LINKER=riscv64-unknown-linux-musl-gcc
export CROSS_LOONGARCH64_UNKNOWN_LINUX_MUSL_RUSTFLAGS='-C target-feature=+crt-static'
export CROSS_RISCV64GC_UNKNOWN_LINUX_MUSL_RUSTFLAGS='-C target-feature=+crt-static'
cross build --release -p liyi-cli --target ${{ matrix.target }}
ls -alF target/${{ matrix.target }}/release/

Expand All @@ -78,7 +84,7 @@ jobs:
strip target/${{ matrix.target }}/release/liyi
else
# cross-compiled binaries may not be strippable by host strip
${{ matrix.arch }}-linux-musl-strip target/${{ matrix.target }}/release/liyi 2>/dev/null || true
${{ matrix.arch }}-unknown-linux-musl-strip target/${{ matrix.target }}/release/liyi 2>/dev/null || true
fi

- name: Package binary
Expand Down
52 changes: 27 additions & 25 deletions .github/workflows/release.yml.liyi.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@
"intent": "Build one release tarball per configured musl target and publish each tarball as an artifact for the downstream release job. The job must choose native or cross compilation per matrix entry, produce the `liyi` CLI binary from package `liyi-cli`, and package the binary together with licenses and README.",
"source_span": [
17,
96
102
],
"tree_path": "key.jobs::key.build",
"source_hash": "sha256:71f4a0f6d299fbf42ee8ba8eb3da5a4c46a157deb550e9c7cced6e9f55e4e537",
"source_hash": "sha256:ec4f57c4102358a0f0d1aeca3c15cb616e07bd1899103060109b8b6d0eb848f7",
"source_anchor": " build:"
},
{
Expand Down Expand Up @@ -90,58 +90,58 @@
{
"item": "build::build-cross-binary",
"reviewed": true,
"intent": "For cross targets, build package `liyi-cli` in release mode through `cross` for the selected target triple. The post-build directory listing must verify that the expected target release directory was populated before later packaging steps run.",
"intent": "For cross targets, build package `liyi-cli` in release mode through `cross` for the selected target triple. Must set explicit linker and `crt-static` rustflags environment variables for loongarch64 and riscv64 musl targets, which do not produce static binaries by default. The post-build directory listing must verify that the expected target release directory was populated before later packaging steps run.",
"source_span": [
69,
73
71,
79
],
"tree_path": "key.jobs::key.build::key.steps[6]::key.run",
"source_hash": "sha256:f0516755de82a5ca1b26380cc0157a046918dc7a99005c5e2a8954ecfef9084d",
"source_anchor": " - name: Build release binary (cross)"
"source_hash": "sha256:3c849bccad993cf25ddb56402d6ad2e135c8d203656e7ccfad9f509bc69b76b3",
"source_anchor": " run: |"
},
{
"item": "build::strip-binary",
"reviewed": true,
"intent": "Attempt to strip the produced `liyi` binary after compilation to reduce release artifact size. Native builds must use the host `strip`; cross builds must try the target-specific musl strip tool but tolerate its absence so packaging can still proceed.",
"source_span": [
75,
82
82,
88
],
"tree_path": "key.jobs::key.build::key.steps[7]::key.run",
"source_hash": "sha256:3e21374960929ccbaed4d37fc5b285dc0b4b77cf5c75bddfda431871b20374d1",
"source_anchor": " - name: Strip binary"
"source_hash": "sha256:aa870f6b6cb901f17480e9d6936ef6d18a18b543d1083ba0a6987543e42308a0",
"source_anchor": " run: |"
},
{
"item": "build::package-binary",
"reviewed": true,
"intent": "Assemble the release tarball for the current target by copying the built `liyi` binary, the repository license files, and `README.md` into `dist/`, then creating `liyi-<tag>-<target>.tar.gz` in the workspace root. The tarball name must stay stable because the upload and release steps consume that exact filename pattern.",
"source_span": [
84,
90
91,
96
],
"tree_path": "key.jobs::key.build::key.steps[8]::key.run",
"source_hash": "sha256:3e07ffc6ef6e4854235d2668749ade3536be6eece60e8c0f592244f701e506d5",
"source_anchor": " - name: Package binary"
"source_hash": "sha256:79785e2a57cf8c8df91bef86bb8d7804f12d5ae25e6a353a3267460caed0dd54",
"source_anchor": " run: |"
},
{
"item": "build::upload-artifact",
"reviewed": true,
"intent": "Upload the packaged tarball as a GitHub Actions artifact named `dist-artifact-<target>`. The artifact naming convention must remain consistent with the release job's download pattern so every target tarball is collected for publication.",
"source_span": [
92,
96
100,
102
],
"tree_path": "key.jobs::key.build::key.steps[9]::key.with",
"source_hash": "sha256:b53367295c966328cd1ed89adb45574227d5a1b28a929e9442f7fd7e86d994a5",
"source_anchor": " - name: Upload artifact"
"source_hash": "sha256:a3cb5812e6a5f176e8d803c906ea3f0118fd29add0e6b1c29bd46728df82c3b9",
"source_anchor": " with:"
},
{
"item": "jobs::release",
"reviewed": true,
"intent": "Wait for all build-matrix artifacts, gather the packaged tarballs into one directory, and publish them on the GitHub release corresponding to the pushed tag. The job must not try to publish before the build job succeeds.",
"source_span": [
98,
123
104,
129
],
"tree_path": "key.jobs::key.release",
"source_hash": "sha256:1c505f0c2dda23075de3f2b6265714e95dad26cf4b7840c3ce3fe070bc540eda",
Expand All @@ -152,9 +152,10 @@
"reviewed": true,
"intent": "Download every target tarball artifact emitted by the build matrix into the local `artifacts/` directory. The `dist-artifact-*` pattern and `merge-multiple: true` setting must gather all per-target uploads into one flat directory so the release step can attach them with a single glob.",
"source_span": [
105,
110
111,
116
],
"tree_path": "key.jobs::key.release::key.steps[1]::key.with",
"source_hash": "sha256:5cb97468bcd3e1686454133b658486b7359407a75637bd46c408dc622c757ea8",
"source_anchor": " - name: Download all artifacts"
},
Expand All @@ -163,9 +164,10 @@
"reviewed": true,
"intent": "Create or update the GitHub release only when the event is a tag push, then attach every `artifacts/*.tar.gz` asset, keep the release non-draft and non-prerelease, generate release notes, and authenticate with `GITHUB_TOKEN`. The explicit `if` guard must prevent accidental release publication from any future non-tag trigger added to this workflow.",
"source_span": [
114,
123
120,
129
],
"tree_path": "key.jobs::key.release::key.steps[3]::key.with",
"source_hash": "sha256:216ea36572f4dc28e5641bc4cc64b64e769140ce0517f9cd84a7483b914891c4",
"source_anchor": " - name: Create Release"
}
Expand Down
12 changes: 12 additions & 0 deletions crates/liyi-cli/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,5 +113,17 @@ pub enum Commands {
/// Filter to a specific item by name
#[arg(long)]
item: Option<String>,

/// Only show unreviewed items
#[arg(long, conflicts_with_all = ["stale_only", "req_only"])]
unreviewed_only: bool,

/// Only show stale-reviewed items
#[arg(long, conflicts_with_all = ["unreviewed_only", "req_only"])]
stale_only: bool,

/// Only show requirement-changed items
#[arg(long, conflicts_with_all = ["unreviewed_only", "stale_only"])]
req_only: bool,
},
}
6 changes: 3 additions & 3 deletions crates/liyi-cli/src/cli.rs.liyi.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,13 @@
{
"item": "Commands",
"reviewed": true,
"intent": "Enumerate all CLI subcommands (Check, Migrate, Init, Approve) with their full set of flags and arguments, providing defaults and mutual constraints (e.g. --level filters diagnostic output). Init includes --no-discover to skip tree-sitter item discovery and --trivial-threshold to configure the line-count cutoff for suggested trivial items.",
"intent": "Enumerate all CLI subcommands (Check, Migrate, Init, Approve) with their full set of flags and arguments, providing defaults and mutual constraints. Init includes --no-discover and --trivial-threshold. Approve includes mutually exclusive kind filters: --unreviewed-only, --stale-only, --req-only.",
"source_span": [
28,
117
129
],
"tree_path": "enum.Commands",
"source_hash": "sha256:bc8e82f094939279c1359d7f376e0b199fbb8a535468e6d27777188532b68689",
"source_hash": "sha256:ee8fd6ce38ecdf1267174eff76d48e2d7958bf89a109ee817909a645481190b0",
"source_anchor": "pub enum Commands {"
}
]
Expand Down
62 changes: 45 additions & 17 deletions crates/liyi-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ fn main() {
process::exit(exit_code as i32);
}

let github_actions = env::var("GITHUB_ACTIONS").is_ok_and(|v| v == "true");

// Print summary first for immediate visibility
let summary = liyi::diagnostics::format_summary(&diagnostics);
println!("{summary}\n");
Expand Down Expand Up @@ -95,7 +97,14 @@ fn main() {
continue;
}
}
println!("{}", d.display_with_root(&repo_root));
if github_actions {
println!(
"{}",
liyi::diagnostics::format_github_actions(d, &repo_root)
);
} else {
println!("{}", d.display_with_root(&repo_root));
}
}

process::exit(exit_code as i32);
Expand Down Expand Up @@ -167,25 +176,41 @@ fn main() {
yes,
dry_run,
item,
unreviewed_only,
stale_only,
req_only,
} => {
let targets = if paths.is_empty() {
vec![env::current_dir().unwrap_or_default()]
} else {
paths
};

let kind_filter = if unreviewed_only {
liyi::approve::ApproveFilter::UnreviewedOnly
} else if stale_only {
liyi::approve::ApproveFilter::StaleOnly
} else if req_only {
liyi::approve::ApproveFilter::ReqOnly
} else {
liyi::approve::ApproveFilter::All
};

let is_interactive = !yes && is_tty();

if is_interactive {
// Collect candidates, run TUI, apply decisions.
let candidates =
match liyi::approve::collect_approval_candidates(&targets, item.as_deref()) {
Ok(c) => c,
Err(e) => {
eprintln!("Error: {e}");
process::exit(2);
}
};
let candidates = match liyi::approve::collect_approval_candidates(
&targets,
item.as_deref(),
kind_filter,
) {
Ok(c) => c,
Err(e) => {
eprintln!("Error: {e}");
process::exit(2);
}
};

if candidates.is_empty() {
println!("nothing to approve");
Expand Down Expand Up @@ -216,14 +241,17 @@ fn main() {
}
} else {
// Batch mode: collect + auto-approve all.
let candidates =
match liyi::approve::collect_approval_candidates(&targets, item.as_deref()) {
Ok(c) => c,
Err(e) => {
eprintln!("Error: {e}");
process::exit(2);
}
};
let candidates = match liyi::approve::collect_approval_candidates(
&targets,
item.as_deref(),
kind_filter,
) {
Ok(c) => c,
Err(e) => {
eprintln!("Error: {e}");
process::exit(2);
}
};

let decisions = vec![liyi::approve::Decision::Yes; candidates.len()];
match liyi::approve::apply_approval_decisions(&candidates, &decisions, dry_run) {
Expand Down
8 changes: 4 additions & 4 deletions crates/liyi-cli/src/main.rs.liyi.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,19 @@
"intent": "=doc",
"source_span": [
26,
246
274
],
"tree_path": "fn.main",
"source_hash": "sha256:600b1ce9423150de057f3c12c610117e6f0fcdf5eb372f87192d947b7075dc83",
"source_hash": "sha256:46a500d70b9f6a301936362a77822a29214be9bfefa26d3d2abe1691a7e772b8",
"source_anchor": "fn main() {"
},
{
"item": "is_tty",
"reviewed": true,
"intent": "=doc",
"source_span": [
252,
254
280,
282
],
"tree_path": "fn.is_tty",
"source_hash": "sha256:021dc096ffc5aa501d5fe90e8fd1835c4ce784a7de59434995a9be221f97e40f",
Expand Down
Loading
Loading