Skip to content

feat: Implement per-run Git cache and restructure add/sync flows.#67

Open
EriiYenn wants to merge 54 commits intowestonplatter:mainfrom
EriiYenn:feat/git-improvements
Open

feat: Implement per-run Git cache and restructure add/sync flows.#67
EriiYenn wants to merge 54 commits intowestonplatter:mainfrom
EriiYenn:feat/git-improvements

Conversation

@EriiYenn
Copy link
Copy Markdown
Contributor

@EriiYenn EriiYenn commented Feb 10, 2026

Summary by CodeRabbit

  • New Features

    • Per-entry sync progress with clearer up‑to‑date messaging.
    • Add command accepts ASSET_TYPE positional plus --path and --ref; improved repo identifier handling.
  • Improvements

    • Optimized Git operations with per‑run clone reuse and shallow-clone support for faster syncs.
    • Smarter skip/upgrade behavior for git-backed assets and lockfile-aware checksum checks.
  • Documentation

    • Renamed “skills” → “assets”; expanded README, lockfile/manifest docs and migration notes.

EriiYenn and others added 30 commits January 29, 2026 16:31
Add PR_MESSAGE markdown file (WIP) to store Pull Request message back to Weston's origin.
Fixed based on PR westonplatter#51 issues from CodeRabbit.
Fix of Minor issue with `exists` based on CodeRabbit.
Removed Claude Hooks integration due to problematic approach with `settings.json` and already existing implementation of Claude Settings.
Fixed Symlink remove check based on CodeRabbit.
Removed bumped version configuration, as the `release-please` will take care of it.
Finalization of the pull request. Upgraded Trunk packages. Fixed README formatting.
Verified correct implementation of Git caching. Upgraded some Trunk linters.
EriiYenn and others added 9 commits February 5, 2026 13:42
Fixed based on CodeRabbit.
Added better integration of `aps add` command with processing SSH urls and more customizability.
Changed the Lockfile name to derive from manifest name to allow multiple manifests in the same repository, e.g. having manifest for Cursor and Codex.
Added documentation about new Lockfile changes.
Added simple Sync Progress outside the Verbose output.
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Feb 10, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Per-run Git clone caching added; lockfile naming moved to manifest-derived ".lock.yaml" with legacy-name migration; add command refactored to accept flexible positional arguments (asset type + URL/path) plus --path/--ref; git shallow flag exposed; README, docs, and tests updated; new error variants and per-entry sync progress added.

Changes

Cohort / File(s) Summary
CLI Interface & Add Flow
src/cli.rs, src/commands.rs
AddArgs now uses positionals (ASSET_TYPE_OR_URL) and new flags --path, --ref; parse_add_positionals/parse_asset_kind added; asset kind threaded through add handlers; per-entry progress/status helpers introduced; many function signatures updated to accept AssetKind.
Repository & URL Parsing
src/github_url.rs
New ParsedRepoIdentifier and parse_repo_identifier support GitHub blob/tree URLs, HTTPS/SSH, and SCP-like SSH URLs; extracts repo_url, git_ref, and path.
Git Clone Cache & Resolvers
src/sources/git.rs, src/sources/mod.rs
Introduces public GitCloneCache with resolve_latest/resolve_commit; adds resolve_git_source_with_cache and resolve_git_source_at_commit_with_cache; module exports updated to expose cache APIs.
Install & Shallow Clone Handling
src/install.rs, src/manifest.rs
install_entry/install_composite_entry now accept &mut GitCloneCache; callers updated to use cache-backed resolution; Source::git_shallow() accessor added; skip/upgrade logic uses computed checksums.
Lockfile Naming & Migration
src/lockfile.rs
Lockfile name derived from manifest (<manifest>.lock.yaml); LEGACY_LOCKFILE_NAMES added; load tries canonical then legacy names; save removes legacy files after writing canonical path.
Error Variants
src/error.rs
Added InvalidRepoSpecifier { value, reason } and InvalidAddArguments { message } variants to ApsError.
Tests
tests/cli.rs
Expanded tests for custom manifest/lockfile naming and migration, per-entry progress output, clone reuse behavior, many Git URL forms, CLI help/flags, and manifest field expectations.
Docs, README & Config
README.md, docs/architecture.md, .trunk/trunk.yaml, .gitignore
README revised to "assets" terminology, examples for --path/--ref and SSH/private repos, lockfile migration notes; architecture doc documents per-run clone reuse; lint deps bumped; .claude added to .gitignore.
Lockfile Content
aps.lock.yaml
Minor entry add/remove churn with no net functional change.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant CLI as CLI Parser
    participant AddCmd as Add Command
    participant RepoParser as Repo Parser
    participant Cache as GitCloneCache
    participant GitOps as Git Operations

    User->>CLI: aps add [ASSET_TYPE] <URL/PATH>
    CLI->>AddCmd: parsed AddArgs (positionals, --path, --ref)
    AddCmd->>RepoParser: parse_add_positionals() / parse_repo_identifier()
    RepoParser-->>AddCmd: ParsedRepoIdentifier{repo_url, git_ref, path}
    AddCmd->>Cache: resolve_git_source_with_cache(repo_url, git_ref, shallow)
    alt cache hit
        Cache-->>AddCmd: ResolvedGitSource (cached)
    else cache miss
        Cache->>GitOps: clone_and_resolve(repo_url, git_ref, shallow)
        GitOps-->>Cache: ResolvedGitSource
        Cache->>Cache: store resolved source
        Cache-->>AddCmd: ResolvedGitSource
    end
    AddCmd->>AddCmd: create manifest entry
    AddCmd-->>User: asset added
Loading
sequenceDiagram
    actor User
    participant Sync as Sync Command
    participant Manifest as Manifest Loader
    participant Install as Install Flow
    participant Cache as GitCloneCache
    participant GitOps as Git Operations
    participant Lockfile as Lockfile Manager

    User->>Sync: aps sync [--manifest PATH]
    Sync->>Manifest: load(manifest_path)
    Manifest-->>Sync: Entries
    Sync->>Install: create GitCloneCache
    loop each entry
        Install->>Cache: resolve_git_source_at_commit_with_cache(repo, commit, shallow)
        alt cache hit
            Cache-->>Install: cached clone path
        else
            Cache->>GitOps: clone_at_commit(repo, commit, shallow)
            GitOps-->>Cache: cloned path
            Cache->>Cache: store by commit
            Cache-->>Install: cloned path
        end
        Install->>Install: install_entry(entry)
        Install->>Lockfile: update checksums/[current]
    end
    Sync->>Lockfile: path_for_manifest(manifest)
    Lockfile-->>Sync: <manifest>.lock.yaml
    Sync->>Lockfile: save(canonical_path)
    Lockfile->>Lockfile: remove legacy lockfiles
    Lockfile-->>User: sync complete
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

🐰 Hopping through branches and refs with glee,

Caching clones so syncs run swift and free,
Manifests find locks named just right,
Assets arrive with per-entry light,
A tiny rabbit cheers: "One cache for thee!"

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly summarizes the main changes: implementing per-run Git cache and restructuring add/sync flows, which are the primary functional modifications evident across multiple files.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Fixed Clippy build in CI Lint.
@EriiYenn
Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Feb 10, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @.trunk/trunk.yaml:
- Around line 25-33: The Trunk plugin version bumps for checkov@3.2.500 and
trufflehog@3.93.0 must be validated against Trunk v1.7.4: review the release
notes/changelogs for checkov and trufflehog between the validated versions
(checkov 3.2.490 and trufflehog 3.90.13) and run the Trunk integration tests
locally using Trunk v1.7.4 (exercise the checkov and trufflehog checks), then
either confirm no breaking changes and add a short comment in the PR that
compatibility is validated, or revert these entries to the tested pins
(checkov@3.2.490, trufflehog@3.90.13) or update the Trunk plugin manifest to a
new compatible manifest version if breaking changes require it.
🧹 Nitpick comments (3)
src/lockfile.rs (1)

382-407: Verify path comparison handles relative vs. absolute paths correctly.

The comparison legacy_path == path at line 388 could fail if path was provided as a relative path while legacy_path is constructed as an absolute path (or vice versa), potentially leading to the canonical lockfile being incorrectly deleted if it matches a legacy name.

Consider canonicalizing both paths before comparison for robustness:

♻️ Proposed fix
         for legacy_name in LEGACY_LOCKFILE_NAMES {
             let legacy_path = dir.join(legacy_name);
-            if !legacy_path.exists() || legacy_path == path {
+            // Canonicalize to handle relative vs. absolute path comparison
+            let same_file = legacy_path
+                .canonicalize()
+                .ok()
+                .zip(path.canonicalize().ok())
+                .map(|(a, b)| a == b)
+                .unwrap_or(false);
+            if !legacy_path.exists() || same_file {
                 continue;
             }
src/github_url.rs (1)

160-263: Local path fallback may produce unexpected results.

The function checks Path::new(input).exists() (line 250) as a fallback, which could match unintended inputs if a directory happens to exist with a name that looks like a repository identifier. For example, if a user typos a URL and a local directory with that name exists, it will silently succeed.

Consider whether this behavior is intentional. If local paths are a supported use case, it may be worth documenting this behavior prominently or requiring a file:// prefix for local paths to make the intent explicit.

tests/cli.rs (1)

967-1104: Avoid asserting cache behavior via log strings.
Matching on "Cloning git repository:" / "Reusing cached clone" is a brittle implementation detail; consider asserting a stable user-visible signal (e.g., a reported cache hit metric) or injecting a lightweight counter for tests. As per coding guidelines: Add unit tests for behavior, not implementation in Rust.

@EriiYenn EriiYenn marked this pull request as ready for review February 10, 2026 10:02
@EriiYenn EriiYenn changed the title feat: Git Improvements & More feat: Implement per-run Git cache and restructure add/sync flows. Feb 10, 2026
@westonplatter
Copy link
Copy Markdown
Owner

@EriiYenn can you explain more about the features/functionality changes in the PR related to the changes in the README? I'm thinking of specifically this part,

- `aps.yaml` → `aps.lock.yaml`
- `aps-rules.yaml` → `aps-rules.lock.yaml`
- `custom` → `custom.lock.yaml`

@EriiYenn
Copy link
Copy Markdown
Contributor Author

@EriiYenn can you explain more about the features/functionality changes in the PR related to the changes in the README? I'm thinking of specifically this part,

- `aps.yaml` → `aps.lock.yaml`
- `aps-rules.yaml` → `aps-rules.lock.yaml`
- `custom` → `custom.lock.yaml`

@westonplatter Yes, absolutely. I made the lockfiles dependent on the specific manifest because, in my case, multiple people can work in the same repository and not everyone uses the same provider (e.g., Cursor vs. Copilot). I tried maintaining two separate manifests (one for Cursor and one for Copilot), but the second run ended up overwriting the existing lockfile.

My goal with this approach was to avoid that collision and make the lockfile deterministic per manifest. That said, if lockfiles are kept separate and/or not committed to Git, this may not be an issue at all.

Let me know what you prefer — I’m happy to revert the change if you’d rather keep the current behavior.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/error.rs`:
- Around line 168-178: The enum variant MissingAddPath is declared but unused;
either remove the MissingAddPath { asset_type: String, hint: String } variant
from the error enum to eliminate dead code, or add a short doc comment above the
variant explaining it's intentionally reserved for future use and why (e.g.,
"Reserved for add subcommand validations when an asset type requires a repo
path"). Update references near InvalidRepoSpecifier and InvalidAddArguments to
ensure no callers expect MissingAddPath, and run cargo check to confirm there
are no remaining references to MissingAddPath.
🧹 Nitpick comments (5)
src/github_url.rs (1)

225-234: Minor inconsistency: Some("") vs None for path/ref on repo-level URLs.

When a GitHub tree/<ref> URL with no subpath (e.g., https://github.com/owner/repo/tree/main) matches Lines 226–228, parse_github_url returns an empty path and a concrete git_ref. This produces ParsedRepoIdentifier { path: Some(""), git_ref: Some("main") }, while a bare repo URL (e.g., https://github.com/owner/repo) at Line 237 returns { path: None, git_ref: None }. Callers in commands.rs treat empty-string path and None equivalently (unwrap_or_default), so this works today, but the semantic gap could surprise future consumers.

src/lockfile.rs (1)

370-406: Serialization error uses LockfileReadError — slightly misleading variant name.

Line 372 maps a serialization failure to ApsError::LockfileReadError, but this is a write path. This predates your changes and is a pre-existing issue, so not blocking.

tests/cli.rs (1)

967-1036: Good integration test for clone caching, but note log-message coupling.

The test validates a key optimization (reusing clones for same-repo entries) by matching on verbose log messages ("Cloning git repository:", "Reusing cached clone"). This is inherently coupled to the log format — if the message changes, the test breaks silently (passes with 0 counts). Consider adding a comment noting this dependency, or asserting on the absence of unexpected counts as a safety net.

src/commands.rs (2)

1056-1113: Early return on sync error discards partial lockfile updates.

If entry N fails, Lines 1111–1112 return immediately. The lockfile updates at Lines 1124–1144 are never reached, so successfully-synced entries (1..N−1) won't be recorded. On the next run, those entries will be re-synced unnecessarily. This is the transactional "all-or-nothing" approach, which is safe but suboptimal for long sync runs. Consider whether persisting partial results (or at least logging a warning) would improve the experience.


315-340: --path override logic in cmd_add works but has a dead branch.

Lines 337–339 contain an empty else if with a comment:

} else if search_path.is_empty() && asset_kind == AssetKind::AgentSkill {
    // Repo-level agent_skill with no path: keep discovery (will clone to find skills)
}

This is a no-op conditional that exists solely as documentation. While harmless, it could be clearer as a plain comment before the if let block rather than an empty branch — or collapsed into the if let Some(ref path) = args.path guard.

Commented unused error.
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@src/error.rs`:
- Around line 176-179: Remove the commented-out enum variant and its attributes
related to MissingAddPath in src/error.rs: delete the three commented lines (the
#[error(...)] and #[diagnostic(...)] attributes and the MissingAddPath {
asset_type: String, hint: String }, declaration) so the unused "Not used at the
moment" placeholder is removed from the codebase; rely on VCS to restore it if
needed later.

@westonplatter
Copy link
Copy Markdown
Owner

@EriiYenn thanks for the description. Could you send over a real world example of the manifests/resource list for aps-rules.yaml and custom? I'm curious to see what this looks like from a dev experience.

@EriiYenn
Copy link
Copy Markdown
Contributor Author

@EriiYenn thanks for the description. Could you send over a real world example of the manifests/resource list for aps-rules.yaml and custom? I'm curious to see what this looks like from a dev experience.

@westonplatter The core challenge across providers is that each one has different target locations for where rules/skills/etc. need to be written. For example, the same “skill” ends up in .cursor/skills for Cursor, .copilot/skills for Copilot, and .codex/skills for Codex. That alone pushes you toward separate manifests — and, by extension, separate lockfiles — to keep things deterministic.

Beyond paths, there are also real format and compatibility differences. Skills are fairly standardized, but rules vary between Cursor/Copilot/Codex, Cursor Commands don’t translate cleanly to Copilot or Codex, and there are other provider-specific behaviors on top of that.

So in practice, each provider needs its own sync handling, and separate lockfiles are the cleanest way to track and archive exactly what was synchronized for each provider.

Skills

# Cursor Manifest
- id: general-skills
  kind: cursor_skills_root
  source:
      type: git
      repo: <SAME_REPO>
      ref: master
      path: skills/general
  dest: ~/.cursor/skills/general

# Copilot Manifest
- id: general-skills
  kind: cursor_skills_root
  source:
      type: git
      repo: <SAME_REPO>
      ref: master
      path: skills/general
  dest: ~/.copilot/skills/general

Rules

# Cursor Manifest
- id: general-rules
  kind: cursor_rules
  source:
    type: git
    repo: <SAME_REPO>
    ref: master
    path: rules/general
  dest: .cursor/rules/general

# Copilot Manifest
- id: ai-task-flow-instruction
  kind: agents_md
  source:
    type: git
    repo: <SAME_REPO>
    ref: master
    path: rules/general/ai-task-flow.mdc # Cursor Rule with additional Copilot headers
  dest: .github/instructions/ai-task-flow.instruction.md
# ...

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
src/commands.rs (3)

104-105: ⚠️ Potential issue | 🟡 Minor

File name comparison should be case-insensitive.

The check for SKILL.md only handles two specific cases (SKILL.md and skill.md). Per coding guidelines, all file name comparisons must be case-insensitive to handle variations like Skill.md or SKILL.MD.

🛠️ Proposed fix using directory listing with case-insensitive match
-        let has_skill_md =
-            expanded_path.join("SKILL.md").exists() || expanded_path.join("skill.md").exists();
+        let has_skill_md = expanded_path
+            .read_dir()
+            .ok()
+            .and_then(|entries| {
+                entries
+                    .filter_map(|e| e.ok())
+                    .find(|e| e.file_name().to_string_lossy().eq_ignore_ascii_case("skill.md"))
+            })
+            .is_some();

As per coding guidelines: "All file name comparisons must be case-insensitive using eq_ignore_ascii_case in Rust."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/commands.rs` around lines 104 - 105, The check for SKILL.md is currently
case-sensitive; update the logic that sets has_skill_md to perform a
case-insensitive filename match instead of only checking "SKILL.md" and
"skill.md". Modify the code around has_skill_md / expanded_path to iterate the
directory entries (e.g., std::fs::read_dir(expanded_path) or
expanded_path.read_dir()) and set has_skill_md true if any
entry.file_name().to_string_lossy().eq_ignore_ascii_case("skill.md"); ensure you
handle and ignore any read_dir errors appropriately so the rest of the function
(the code referencing has_skill_md) behaves unchanged.

1425-1428: ⚠️ Potential issue | 🟡 Minor

File name comparison should be case-insensitive.

The check for SKILL.md uses exact case matching. To align with coding guidelines, this should use case-insensitive comparison.

🛠️ Proposed fix
-        let skill_md_path = skill_path.join("SKILL.md");
-
-        if !skill_md_path.exists() {
+        let has_skill_md = skill_path
+            .read_dir()
+            .ok()
+            .and_then(|entries| {
+                entries
+                    .filter_map(|e| e.ok())
+                    .find(|e| e.file_name().to_string_lossy().eq_ignore_ascii_case("skill.md"))
+            })
+            .is_some();
+
+        if !has_skill_md {

As per coding guidelines: "All file name comparisons must be case-insensitive using eq_ignore_ascii_case in Rust."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/commands.rs` around lines 1425 - 1428, The code currently builds
skill_md_path = skill_path.join("SKILL.md") and tests its existence with
skill_md_path.exists(), which does a case-sensitive check; replace that logic
with a case-insensitive filename check by scanning the entries in the skill_path
(e.g., using fs::read_dir or iterating dir_entry entries) and matching each
entry.file_name().to_string_lossy().eq_ignore_ascii_case("SKILL.md") to
determine presence of the SKILL.md file; update the logic around skill_name and
the block that used skill_md_path.exists() to use this case-insensitive test
instead.

1-5: ⚠️ Potential issue | 🔴 Critical

Remove unused AddAssetKind import that no longer exists in the CLI module.

The AddAssetKind enum has been removed from crate::cli but is still imported on line 3. This will cause a compilation error. The import is also unused—no code in commands.rs references it.

Fix
 use crate::cli::{
-    AddArgs, AddAssetKind, CatalogGenerateArgs, InitArgs, ListArgs, ManifestFormat, StatusArgs,
+    AddArgs, CatalogGenerateArgs, InitArgs, ListArgs, ManifestFormat, StatusArgs,
     SyncArgs, ValidateArgs,
 };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/commands.rs` around lines 1 - 5, Remove the obsolete AddAssetKind import
from the use crate::cli import list in commands.rs and update the import line to
only include existing symbols (AddArgs, CatalogGenerateArgs, InitArgs, ListArgs,
ManifestFormat, StatusArgs, SyncArgs, ValidateArgs); search the file for any
remaining references to AddAssetKind to confirm none exist and run cargo build
to verify the compilation error is resolved.
🧹 Nitpick comments (1)
src/commands.rs (1)

338-341: Empty conditional block reduces readability.

The else if branch on lines 338-340 contains only a comment and no code. This can be refactored for clarity.

♻️ Suggested refactor to eliminate empty block
     if let ParsedAddTarget::GitHubDiscovery {
         repo_url,
         git_ref,
         search_path,
     } = &target
     {
-        if let Some(ref path) = args.path {
+        // --path overrides discovery: treat as single entry with explicit path
+        if let Some(ref path) = args.path {
             target = ParsedAddTarget::GitHubSkill {
                 repo_url: repo_url.clone(),
                 git_ref: git_ref.clone(),
                 skill_path: path.clone(),
                 skill_name: path
                     .rsplit('/')
                     .next()
                     .filter(|s| !s.is_empty())
                     .map(String::from),
             };
-        } else if search_path.is_empty() && asset_kind == AssetKind::AgentSkill {
-            // Repo-level agent_skill with no path: keep discovery (will clone to find skills)
         }
+        // Note: Repo-level agent_skill with no --path keeps discovery mode
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/commands.rs` around lines 338 - 341, The else-if branch that checks
search_path.is_empty() && asset_kind == AssetKind::AgentSkill contains only a
comment, harming readability; remove this empty branch and either fold its
intent into the surrounding logic (e.g., include the condition in the previous
if/else chain) or replace it with a brief explanatory comment above the relevant
if to document "repo-level agent_skill with no path: keep discovery (will clone
to find skills)"; update any control flow so the case is still handled
consistently without an empty else-if for search_path and AssetKind::AgentSkill.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@src/commands.rs`:
- Around line 104-105: The check for SKILL.md is currently case-sensitive;
update the logic that sets has_skill_md to perform a case-insensitive filename
match instead of only checking "SKILL.md" and "skill.md". Modify the code around
has_skill_md / expanded_path to iterate the directory entries (e.g.,
std::fs::read_dir(expanded_path) or expanded_path.read_dir()) and set
has_skill_md true if any
entry.file_name().to_string_lossy().eq_ignore_ascii_case("skill.md"); ensure you
handle and ignore any read_dir errors appropriately so the rest of the function
(the code referencing has_skill_md) behaves unchanged.
- Around line 1425-1428: The code currently builds skill_md_path =
skill_path.join("SKILL.md") and tests its existence with skill_md_path.exists(),
which does a case-sensitive check; replace that logic with a case-insensitive
filename check by scanning the entries in the skill_path (e.g., using
fs::read_dir or iterating dir_entry entries) and matching each
entry.file_name().to_string_lossy().eq_ignore_ascii_case("SKILL.md") to
determine presence of the SKILL.md file; update the logic around skill_name and
the block that used skill_md_path.exists() to use this case-insensitive test
instead.
- Around line 1-5: Remove the obsolete AddAssetKind import from the use
crate::cli import list in commands.rs and update the import line to only include
existing symbols (AddArgs, CatalogGenerateArgs, InitArgs, ListArgs,
ManifestFormat, StatusArgs, SyncArgs, ValidateArgs); search the file for any
remaining references to AddAssetKind to confirm none exist and run cargo build
to verify the compilation error is resolved.

---

Nitpick comments:
In `@src/commands.rs`:
- Around line 338-341: The else-if branch that checks search_path.is_empty() &&
asset_kind == AssetKind::AgentSkill contains only a comment, harming
readability; remove this empty branch and either fold its intent into the
surrounding logic (e.g., include the condition in the previous if/else chain) or
replace it with a brief explanatory comment above the relevant if to document
"repo-level agent_skill with no path: keep discovery (will clone to find
skills)"; update any control flow so the case is still handled consistently
without an empty else-if for search_path and AssetKind::AgentSkill.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f1147ef and 91f478d.

📒 Files selected for processing (3)
  • README.md
  • src/cli.rs
  • src/commands.rs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants