Skip to content

Refactor gitignore patterns for generated agent resources#49

Merged
ainetx merged 2 commits into
mainfrom
zh-fixes
Jun 18, 2026
Merged

Refactor gitignore patterns for generated agent resources#49
ainetx merged 2 commits into
mainfrom
zh-fixes

Conversation

@ainetx

@ainetx ainetx commented Jun 18, 2026

Copy link
Copy Markdown
Collaborator

Replace wildcard patterns in the gitignore with explicit file paths for better clarity and maintenance. This change enhances the management of generated agent resources.

Summary by CodeRabbit

  • Refactor

    • Updated Copilot agent integration with revised artifact outputs
    • Streamlined agent installation detection with simplified signals
    • Refined Git ignore patterns to reflect managed artifacts
  • Bug Fixes

    • Removed legacy file management from agent generation workflow

@coderabbitai

coderabbitai Bot commented Jun 18, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Removes all legacy .github/copilot-instructions.md management from Copilot agent detection, config generation, and skill processing. Introduces list_managed_agent_output_paths() public API that enumerates generator-managed paths via dry-run, and wires it into init.py to replace hardcoded .gitignore globs. Cleans up kit.py metadata fallback and resource-binding merge logic, and removes the sdlc SKILL.md resource config.

Changes

Copilot Legacy Removal, Dynamic .gitignore, and Kit Cleanup

Layer / File(s) Summary
Remove legacy copilot-instructions.md from agent config, detection, and generation
skills/studio/scripts/studio/commands/agents.py
_default_agents_config() drops the .github/copilot-instructions.md template output; _has_non_openai_install_signal() and _is_agent_installed() drop legacy header/content inspection of that file; _process_skills() removes the user-authored guard; _collect_managed_result_paths() and list_managed_agent_output_paths() are added to enumerate all generator-managed output paths via dry-run.
Wire list_managed_agent_output_paths into .gitignore generation
skills/studio/scripts/studio/commands/init.py
Imports list_managed_agent_output_paths; adds project_root: Path parameter to _gitignore_patterns, _compute_gitignore_block, and propagates it through _write_gitignore_block; replaces hardcoded agent output globs with dynamically computed paths.
kit.py: remove legacy metadata fallback and fix resource-binding merge; drop sdlc SKILL.md config
skills/studio/scripts/studio/commands/kit.py, .bootstrap/config/core.toml
Removes _collect_kit_metadata() fallback helper; _collect_registered_kit_metadata exception path now returns empty values immediately; _sync_manifest_resource_bindings is updated to drop stale resource ids not present in the manifest; [kits.sdlc.resources.skill] TOML block removed.
Tests: Copilot detection, generation, and CLI integration
tests/test_agents_coverage.py, tests/test_cli_integration.py, tests/test_update.py
Inverts legacy copilot-instructions detection expectation; reshapes Copilot generation test to assert cf.prompt.md and .cf-installed; removes .github/copilot-instructions.md from CLI expected outputs; flips _maybe_regenerate_agents assertion to exclude copilot for legacy instructions files.
Tests: .gitignore footprint, kit aggregation skip, and manifest resource-binding
tests/test_init_update_footprint.py, tests/test_kit.py, tests/test_kit_manifest_install.py
Narrows gitignore assertions to specific filenames; asserts .github/copilot-instructions.md is not ignored; updates kit aggregation tests to assert agent headers are absent when resources not registered; adds test_sync_manifest_resource_bindings_drops_removed_resources verifying stale resources are dropped.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • constructorfabric/studio#32: Directly overlaps with the kit.py _collect_registered_kit_metadata and skill_nav/.gen/SKILL.md handling changes in the same metadata aggregation code path.

Poem

🐇 Hop, hop, away with the old instructions file,
No more copilot-instructions cluttering the aisle!
Dynamic gitignore paths now spring from dry-run,
Stale kit resources dropped — clean merges, well done.
The rabbit tidied up and bounded away with glee,
Legacy fallbacks gone, the codebase runs free! 🌿

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 42.86% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title is partially related to the changeset. While the PR does involve gitignore patterns for agent resources, the scope of changes is substantially broader—removing legacy Copilot file handling, introducing new public APIs, restructuring kit metadata collection, and updating tests—making the title incomplete and not representative of the main change. Consider a more comprehensive title that captures the primary refactoring scope, such as 'Remove legacy Copilot file handling and refactor agent resource management' or 'Refactor Copilot agent integration and gitignore patterns'.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch zh-fixes

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

ainetx added 2 commits June 18, 2026 16:09
…s for generated agent resources

Signed-off-by: ainetx <viator@via-net.org>
…anced resource metadata

Signed-off-by: ainetx <viator@via-net.org>
@sonarqubecloud

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
skills/studio/scripts/studio/commands/agents.py (2)

3795-3834: ⚖️ Poor tradeoff

Cognitive complexity exceeds threshold; consider decomposition.

SonarCloud flags complexity of 25 (allowed 15). The function performs multiple distinct tasks that could be extracted:

  1. Collecting install marker paths
  2. Collecting static skill output paths from config
  3. Running processors and aggregating their results

Extracting these into focused helpers would improve testability and maintainability.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@skills/studio/scripts/studio/commands/agents.py` around lines 3795 - 3834,
The function list_managed_agent_output_paths has exceeded the cognitive
complexity threshold of 15 with a complexity of 25. Refactor this function by
extracting its three main concerns into separate helper functions: create one
helper to collect install marker paths from _INSTALL_MARKERS, create another to
collect static skill output paths from the config (the logic handling agent_cfg,
skills_cfg, outputs, and rel_path extraction), and create a third helper to
execute all the processors (_process_workflows, _process_skills,
_process_kit_workflow_skills, _process_subagents, and
_process_kit_public_agents_and_rules) and aggregate their managed paths. Then
simplify list_managed_agent_output_paths to call these three helpers in sequence
and return the sorted result, significantly reducing its cognitive complexity.

Source: Linters/SAST tools


3758-3792: ⚖️ Poor tradeoff

Consider extracting helpers to reduce cognitive complexity.

SonarCloud flags cognitive complexity of 31 (allowed 15). The nested loops for key iteration, value iteration, and path normalization can be simplified by extracting a small _normalize_path_candidate helper.

♻️ Sketch of possible refactor
def _normalize_path_candidate(candidate: Any, project_root: Path) -> Optional[str]:
    """Normalize a single path candidate to project-relative string."""
    if not isinstance(candidate, str) or not candidate.strip():
        return None
    candidate_path = Path(candidate)
    if candidate_path.is_absolute():
        return _safe_relpath(candidate_path, project_root)
    return candidate.replace("\\", "/").strip("/") or None

def _collect_managed_result_paths(
    project_root: Path,
    section: Dict[str, Any],
) -> Set[str]:
    """Collect normalized project-relative output paths from a generator result."""
    paths: Set[str] = set()
    
    # Collect from status keys
    for key in ("created", "updated", "unchanged", "deleted"):
        for value in section.get(key, []) or []:
            raw = value[-1] if isinstance(value, tuple) and value else value
            if normalized := _normalize_path_candidate(raw, project_root):
                paths.add(normalized)
    
    # Collect from outputs
    for output in section.get("outputs", []) or []:
        if isinstance(output, dict):
            if normalized := _normalize_path_candidate(output.get("path"), project_root):
                paths.add(normalized)
    
    return paths
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@skills/studio/scripts/studio/commands/agents.py` around lines 3758 - 3792,
The _collect_managed_result_paths function has high cognitive complexity due to
nested loops and duplicated path normalization logic. Extract the path
normalization logic that currently appears twice (once in the key iteration loop
and once in the outputs loop) into a separate helper function
_normalize_path_candidate that takes a candidate value and project_root
parameter and returns Optional[str]. This helper should handle the string type
checking, stripping, absolute path resolution, and relative path normalization.
Then simplify both the key loop and outputs loop by calling this new helper
instead of repeating the normalization code inline.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@skills/studio/scripts/studio/commands/agents.py`:
- Around line 3768-3780: The code accesses value[-1] without checking if the
tuple is empty, which will raise an IndexError if an empty tuple is passed as a
value. Add a guard condition in the isinstance(value, tuple) check to ensure the
tuple is not empty before attempting to access its last element with value[-1].
Update the condition to verify both that value is a tuple and that it contains
at least one element before proceeding to access value[-1].

---

Nitpick comments:
In `@skills/studio/scripts/studio/commands/agents.py`:
- Around line 3795-3834: The function list_managed_agent_output_paths has
exceeded the cognitive complexity threshold of 15 with a complexity of 25.
Refactor this function by extracting its three main concerns into separate
helper functions: create one helper to collect install marker paths from
_INSTALL_MARKERS, create another to collect static skill output paths from the
config (the logic handling agent_cfg, skills_cfg, outputs, and rel_path
extraction), and create a third helper to execute all the processors
(_process_workflows, _process_skills, _process_kit_workflow_skills,
_process_subagents, and _process_kit_public_agents_and_rules) and aggregate
their managed paths. Then simplify list_managed_agent_output_paths to call these
three helpers in sequence and return the sorted result, significantly reducing
its cognitive complexity.
- Around line 3758-3792: The _collect_managed_result_paths function has high
cognitive complexity due to nested loops and duplicated path normalization
logic. Extract the path normalization logic that currently appears twice (once
in the key iteration loop and once in the outputs loop) into a separate helper
function _normalize_path_candidate that takes a candidate value and project_root
parameter and returns Optional[str]. This helper should handle the string type
checking, stripping, absolute path resolution, and relative path normalization.
Then simplify both the key loop and outputs loop by calling this new helper
instead of repeating the normalization code inline.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c0187146-dd2f-49dc-bd10-fe4c4910d538

📥 Commits

Reviewing files that changed from the base of the PR and between 0c22a85 and ab5f27e.

📒 Files selected for processing (10)
  • .bootstrap/config/core.toml
  • skills/studio/scripts/studio/commands/agents.py
  • skills/studio/scripts/studio/commands/init.py
  • skills/studio/scripts/studio/commands/kit.py
  • tests/test_agents_coverage.py
  • tests/test_cli_integration.py
  • tests/test_init_update_footprint.py
  • tests/test_kit.py
  • tests/test_kit_manifest_install.py
  • tests/test_update.py
💤 Files with no reviewable changes (1)
  • tests/test_cli_integration.py
🚧 Files skipped from review as they are similar to previous changes (7)
  • tests/test_init_update_footprint.py
  • tests/test_kit_manifest_install.py
  • tests/test_update.py
  • tests/test_agents_coverage.py
  • skills/studio/scripts/studio/commands/init.py
  • tests/test_kit.py
  • skills/studio/scripts/studio/commands/kit.py

Comment on lines +3768 to +3780
for value in values:
if isinstance(value, tuple):
candidates = [value[-1]]
else:
candidates = [value]
for candidate in candidates:
if not isinstance(candidate, str) or not candidate.strip():
continue
candidate_path = Path(candidate)
if candidate_path.is_absolute():
paths.add(_safe_relpath(candidate_path, project_root))
else:
paths.add(candidate.replace("\\", "/").strip("/"))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Guard against empty tuples to prevent IndexError.

If an empty tuple is passed as a value, value[-1] at line 3770 will raise an IndexError. While generators likely don't produce empty tuples, adding a guard improves robustness.

🛡️ Proposed fix
             for value in values:
-                if isinstance(value, tuple):
+                if isinstance(value, tuple) and value:
                     candidates = [value[-1]]
                 else:
                     candidates = [value]
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
for value in values:
if isinstance(value, tuple):
candidates = [value[-1]]
else:
candidates = [value]
for candidate in candidates:
if not isinstance(candidate, str) or not candidate.strip():
continue
candidate_path = Path(candidate)
if candidate_path.is_absolute():
paths.add(_safe_relpath(candidate_path, project_root))
else:
paths.add(candidate.replace("\\", "/").strip("/"))
for value in values:
if isinstance(value, tuple) and value:
candidates = [value[-1]]
else:
candidates = [value]
for candidate in candidates:
if not isinstance(candidate, str) or not candidate.strip():
continue
candidate_path = Path(candidate)
if candidate_path.is_absolute():
paths.add(_safe_relpath(candidate_path, project_root))
else:
paths.add(candidate.replace("\\", "/").strip("/"))
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@skills/studio/scripts/studio/commands/agents.py` around lines 3768 - 3780,
The code accesses value[-1] without checking if the tuple is empty, which will
raise an IndexError if an empty tuple is passed as a value. Add a guard
condition in the isinstance(value, tuple) check to ensure the tuple is not empty
before attempting to access its last element with value[-1]. Update the
condition to verify both that value is a tuple and that it contains at least one
element before proceeding to access value[-1].

@ainetx ainetx merged commit 94d99d4 into main Jun 18, 2026
21 checks passed
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.

1 participant