Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion .claude/skills/detail-bugs/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ The user must be authenticated. Assume that the user is authed and run commands

## Repository Inference

The Detail CLI infers the repository from the git remote; if the user specifies a different repo, pass it explicitly to the CLI commands.
The Detail CLI infers the repository from the git or jj remote; if the user specifies a different repo, pass it explicitly to the CLI commands.

## Subcommands

Expand Down
2 changes: 1 addition & 1 deletion .claude/skills/detail-create-rules/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Guide the user through creating one or more new rules for their repository.

## Determining the Repository

The Detail CLI infers the repository from the git remote; if the user specifies a different repo, pass it explicitly to the CLI commands.
The Detail CLI infers the repository from the git or jj remote; if the user specifies a different repo, pass it explicitly to the CLI commands.

## Prerequisites

Expand Down
12 changes: 6 additions & 6 deletions docs/HELP.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ List bugs for a given repository

###### **Arguments:**

* `<REPO>` — Repository by owner/repo (e.g., usedetail/cli) or repo (e.g., cli). If omitted, inferred from the git remote (origin)
* `<REPO>` — Repository by owner/repo (e.g., usedetail/cli) or repo (e.g., cli). If omitted, inferred from the git or jj remote (origin)

###### **Options:**

Expand Down Expand Up @@ -274,7 +274,7 @@ Submit a rule creation request for a repository

###### **Arguments:**

* `<REPO>` — Repository by owner/repo (e.g., usedetail/cli) or repo name. If omitted, inferred from the git remote (origin)
* `<REPO>` — Repository by owner/repo (e.g., usedetail/cli) or repo name. If omitted, inferred from the git or jj remote (origin)

###### **Options:**

Expand All @@ -292,7 +292,7 @@ Ask Detail to propose rules for a repository

###### **Arguments:**

* `<REPO>` — Repository by owner/repo (e.g., usedetail/cli) or repo name. If omitted, inferred from the git remote (origin)
* `<REPO>` — Repository by owner/repo (e.g., usedetail/cli) or repo name. If omitted, inferred from the git or jj remote (origin)



Expand All @@ -317,7 +317,7 @@ List rule creation requests for a repository

###### **Arguments:**

* `<REPO>` — Repository by owner/repo (e.g., usedetail/cli) or repo name. If omitted, inferred from the git remote (origin)
* `<REPO>` — Repository by owner/repo (e.g., usedetail/cli) or repo name. If omitted, inferred from the git or jj remote (origin)

###### **Options:**

Expand Down Expand Up @@ -350,7 +350,7 @@ List completed rules for a repository

###### **Arguments:**

* `<REPO>` — Repository by owner/repo (e.g., usedetail/cli) or repo name. If omitted, inferred from the git remote (origin)
* `<REPO>` — Repository by owner/repo (e.g., usedetail/cli) or repo name. If omitted, inferred from the git or jj remote (origin)

###### **Options:**

Expand Down Expand Up @@ -454,7 +454,7 @@ List recent scans for a repository

###### **Arguments:**

* `<REPO>` — Repository in owner/repo format or just repo name. If omitted, inferred from the git remote (origin)
* `<REPO>` — Repository in owner/repo format or just repo name. If omitted, inferred from the git or jj remote (origin)

###### **Options:**

Expand Down
4 changes: 2 additions & 2 deletions src/commands/bugs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ use crate::api::types::{
};
use crate::output::{output_list, SectionRenderer};
use crate::utils::datetime::{format_datetime, parse_time_spec};
use crate::utils::git::resolve_repo_arg;
use crate::utils::pagination::page_to_offset;
use crate::utils::repos::resolve_repo_id;
use crate::utils::vcs::resolve_repo_arg;

/// Return only bugs where `isSecurityVulnerability` is `true`.
fn filter_vulns_only(bugs: &[Bug]) -> Vec<Bug> {
Expand Down Expand Up @@ -116,7 +116,7 @@ pub enum BugCommands {
/// List bugs for a given repository
List {
/// Repository by owner/repo (e.g., usedetail/cli) or repo (e.g., cli).
/// If omitted, inferred from the git remote (origin).
/// If omitted, inferred from the git or jj remote (origin).
repo: Option<String>,

/// Status filter — repeat the flag or comma-separate values to
Expand Down
10 changes: 5 additions & 5 deletions src/commands/rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@ use crate::api::types::{
};
use crate::output::{output_list, Formattable, SectionRenderer};
use crate::utils::datetime::{format_date, format_datetime};
use crate::utils::git::resolve_repo_arg;
use crate::utils::repos::resolve_repo_id;
use crate::utils::vcs::resolve_repo_arg;

#[derive(Subcommand)]
pub enum RuleCommands {
/// Submit a rule creation request for a repository
Create {
/// Repository by owner/repo (e.g., usedetail/cli) or repo name.
/// If omitted, inferred from the git remote (origin).
/// If omitted, inferred from the git or jj remote (origin).
repo: Option<String>,

/// Description of the rule to create
Expand All @@ -39,7 +39,7 @@ pub enum RuleCommands {
/// Ask Detail to propose rules for a repository
Propose {
/// Repository by owner/repo (e.g., usedetail/cli) or repo name.
/// If omitted, inferred from the git remote (origin).
/// If omitted, inferred from the git or jj remote (origin).
repo: Option<String>,
},

Expand All @@ -50,7 +50,7 @@ pub enum RuleCommands {
/// List completed rules for a repository
List {
/// Repository by owner/repo (e.g., usedetail/cli) or repo name.
/// If omitted, inferred from the git remote (origin).
/// If omitted, inferred from the git or jj remote (origin).
repo: Option<String>,

/// Output format
Expand Down Expand Up @@ -80,7 +80,7 @@ pub enum RuleRequestCommands {
/// List rule creation requests for a repository
List {
/// Repository by owner/repo (e.g., usedetail/cli) or repo name.
/// If omitted, inferred from the git remote (origin).
/// If omitted, inferred from the git or jj remote (origin).
repo: Option<String>,

/// Output format
Expand Down
4 changes: 2 additions & 2 deletions src/commands/scans.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@ use crate::api::client::ApiClient;
use crate::api::types::{RepoId, Scan, ScanType, ScansResponse, WorkflowStatus};
use crate::output::output_list;
use crate::utils::datetime::parse_time_spec;
use crate::utils::git::resolve_repo_arg;
use crate::utils::pagination::page_to_offset;
use crate::utils::repos::resolve_repo_id;
use crate::utils::vcs::resolve_repo_arg;

#[derive(Subcommand)]
pub enum ScanCommands {
/// List recent scans for a repository
List {
/// Repository in owner/repo format or just repo name.
/// If omitted, inferred from the git remote (origin).
/// If omitted, inferred from the git or jj remote (origin).
repo: Option<String>,

/// Filter by workflow status (e.g. failed scans in the last day).
Expand Down
38 changes: 3 additions & 35 deletions src/commands/skill.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use std::fs;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::str;

use anyhow::{Context, Result};
use clap::Subcommand;
use homedir::my_home;

use crate::utils::vcs::repo_root;

const BUGS_SKILL_CONTENT: &str = include_str!("../../.claude/skills/detail-bugs/SKILL.md");
const RULES_SKILL_CONTENT: &str = include_str!("../../.claude/skills/detail-create-rules/SKILL.md");

Expand All @@ -17,12 +17,6 @@ pub enum SkillCommands {
Rules,
}

fn parse_git_root_output(success: bool, stdout: &[u8]) -> Result<PathBuf> {
anyhow::ensure!(success, "not inside a git repository");
let root = str::from_utf8(stdout).context("git output was not valid UTF-8")?;
Ok(PathBuf::from(root.trim()))
}

fn skill_install_path(base: &Path, skill_name: &str) -> PathBuf {
base.join(".claude")
.join("skills")
Expand All @@ -36,14 +30,6 @@ fn user_home() -> Result<PathBuf> {
.context("home directory not found")
}

fn git_root() -> Result<PathBuf> {
let output = Command::new("git")
.args(["rev-parse", "--show-toplevel"])
.output()
.context("failed to run git")?;
parse_git_root_output(output.status.success(), &output.stdout)
}

fn install_skill(repo_root: &Path, skill_name: &str, content: &str) -> Result<()> {
let path = skill_install_path(repo_root, skill_name);
let dir = path
Expand All @@ -59,7 +45,7 @@ fn install_skill(repo_root: &Path, skill_name: &str, content: &str) -> Result<()
}

pub fn handle(command: Option<&SkillCommands>, user: bool) -> Result<()> {
let base = if user { user_home()? } else { git_root()? };
let base = if user { user_home()? } else { repo_root()? };
match command {
None => install_skill(&base, "detail-bugs", BUGS_SKILL_CONTENT),
Some(SkillCommands::Rules) => {
Expand All @@ -72,24 +58,6 @@ pub fn handle(command: Option<&SkillCommands>, user: bool) -> Result<()> {
mod tests {
use super::*;

#[test]
fn parse_git_root_trims_newline() {
let root = parse_git_root_output(true, b"/tmp/repo\n").unwrap();
assert_eq!(root, PathBuf::from("/tmp/repo"));
}

#[test]
fn parse_git_root_errors_when_not_in_repo() {
let err = parse_git_root_output(false, b"").unwrap_err();
assert!(err.to_string().contains("not inside a git repository"));
}

#[test]
fn parse_git_root_errors_on_invalid_utf8() {
let err = parse_git_root_output(true, &[0xff]).unwrap_err();
assert!(err.to_string().contains("git output was not valid UTF-8"));
}

#[test]
fn skill_install_path_is_repo_relative() {
let path = skill_install_path(Path::new("/work/repo"), "detail-bugs");
Expand Down
2 changes: 1 addition & 1 deletion src/utils/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pub mod datetime;
pub mod git;
pub mod pagination;
pub mod repos;
pub mod vcs;
Loading
Loading