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
1 change: 1 addition & 0 deletions codex-rs/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions codex-rs/core-skills/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ codex-login = { workspace = true }
codex-model-provider = { workspace = true }
codex-otel = { workspace = true }
codex-protocol = { workspace = true }
codex-shell-command = { workspace = true }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Commit the Bazel lockfile update

Because this adds a Rust workspace dependency, the Bazel module lock must be refreshed and committed; otherwise Bazel lock/check can fail in CI or for Bazel users until the just bazel-lock-update output is included, per repo guidance.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ran just bazel-lock-update and just bazel-lock-check; both pass and MODULE.bazel.lock has no diff to commit.

codex-skills = { workspace = true }
codex-utils-absolute-path = { workspace = true }
codex-utils-output-truncation = { workspace = true }
Expand Down
29 changes: 8 additions & 21 deletions codex-rs/core-skills/src/invocation_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ use std::path::Path;

use crate::SkillLoadOutcome;
use crate::SkillMetadata;
use codex_protocol::parse_command::ParsedCommand;
use codex_shell_command::parse_command::parse_command_impl;
use codex_utils_absolute_path::AbsolutePathBuf;

pub(crate) fn build_implicit_skill_path_indexes(
Expand Down Expand Up @@ -101,33 +103,18 @@ fn detect_skill_doc_read(
tokens: &[String],
workdir: &AbsolutePathBuf,
) -> Option<SkillMetadata> {
if !command_reads_file(tokens) {
return None;
}

for token in tokens.iter().skip(1) {
if token.starts_with('-') {
continue;
}
let path = Path::new(token);
let candidate_path = canonicalize_if_exists(&workdir.join(path));
if let Some(candidate) = outcome.implicit_skills_by_doc_path.get(&candidate_path) {
return Some(candidate.clone());
for command in parse_command_impl(tokens) {
Comment thread
alexsong-oai marked this conversation as resolved.
Comment thread
alexsong-oai marked this conversation as resolved.
Comment thread
alexsong-oai marked this conversation as resolved.
if let ParsedCommand::Read { path, .. } = command {
let candidate_path = canonicalize_if_exists(&workdir.join(path.as_path()));
if let Some(candidate) = outcome.implicit_skills_by_doc_path.get(&candidate_path) {
return Some(candidate.clone());
}
}
}

None
}

fn command_reads_file(tokens: &[String]) -> bool {
const READERS: [&str; 8] = ["cat", "sed", "head", "tail", "less", "more", "bat", "awk"];
let Some(program) = tokens.first() else {
return false;
};
let program = command_basename(program).to_ascii_lowercase();
READERS.contains(&program.as_str())
}

fn command_basename(command: &str) -> String {
Path::new(command)
.file_name()
Expand Down
24 changes: 24 additions & 0 deletions codex-rs/core-skills/src/invocation_utils_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,30 @@ fn skill_doc_read_detection_matches_absolute_path() {
);
}

#[test]
fn skill_doc_read_detection_matches_shared_read_parser() {
let skill_doc_path = test_path_buf("/tmp/skill-test/SKILL.md").abs();
let normalized_skill_doc_path = canonicalize_if_exists(&skill_doc_path);
let skill = test_skill_metadata(skill_doc_path);
let outcome = SkillLoadOutcome {
implicit_skills_by_scripts_dir: Arc::new(HashMap::new()),
implicit_skills_by_doc_path: Arc::new(HashMap::from([(normalized_skill_doc_path, skill)])),
..Default::default()
};

let tokens = vec![
"nl".to_string(),
"-ba".to_string(),
test_path_display("/tmp/skill-test/SKILL.md"),
];
let found = detect_skill_doc_read(&outcome, &tokens, &test_path_buf("/tmp").abs());

assert_eq!(
found.map(|value| value.name),
Some("test-skill".to_string())
);
}

#[test]
fn skill_script_run_detection_matches_relative_path_from_skill_root() {
let skill_doc_path = test_path_buf("/tmp/skill-test/SKILL.md").abs();
Expand Down
Loading