@phase2 @skills @agent_skills @agent_skills_loader
Feature: Agent Skills Loader
  As a CleverAgents developer
  I want to load Agent Skills Standard SKILL.md folders into structured tool definitions
  So that actors can discover and invoke instruction-driven multi-step workflows

  # ---------------------------------------------------------------------------
  # AgentSkillSpec — SKILL.md Parsing
  # ---------------------------------------------------------------------------

  @agent_skill_parse
  Scenario: Parse a minimal SKILL.md with only required frontmatter fields
    Given a SKILL.md file with frontmatter:
      """
      ---
      name: local/deploy-staging
      description: Deploy the current branch to the staging environment.
      ---
      Follow these steps to deploy.
      """
    When I parse the SKILL.md file
    Then the parsed skill name should be "local/deploy-staging"
    And the parsed skill description should be "Deploy the current branch to the staging environment."
    And the parsed skill body should contain "Follow these steps to deploy."

  @agent_skill_parse
  Scenario: Parse a SKILL.md with all optional frontmatter fields
    Given a SKILL.md file with frontmatter:
      """
      ---
      name: local/code-review
      description: Run a thorough code review checklist.
      version: 1.2.3
      compatibility:
        min_agent_version: "3.0.0"
      metadata:
        author: aditya
        tags: [review, quality]
      allowed-tools:
        - local/read-file
        - local/search-files
      ---
      ## Code Review Steps
      1. Check style
      2. Verify tests
      """
    When I parse the SKILL.md file
    Then the parsed skill name should be "local/code-review"
    And the parsed skill version should be "1.2.3"
    And the parsed skill allowed tools should include "local/read-file"
    And the parsed skill allowed tools should include "local/search-files"
    And the parsed skill metadata should have key "author" with value "aditya"

  @agent_skill_parse
  Scenario: Parse SKILL.md body text is preserved exactly
    Given a SKILL.md file with frontmatter:
      """
      ---
      name: local/test-skill
      description: Test skill for body parsing.
      ---
      # Multi-line Instructions

      Step 1: Do something important.
      Step 2: Do another thing.

      ```python
      code_example()
      ```
      """
    When I parse the SKILL.md file
    Then the parsed skill body should contain "Step 1: Do something important."
    And the parsed skill body should contain "Step 2: Do another thing."
    And the parsed skill body should contain "code_example()"

  @agent_skill_parse @error_handling
  Scenario: SKILL.md missing required name field raises error
    Given a SKILL.md file with frontmatter:
      """
      ---
      description: A skill without a name.
      ---
      Some body text.
      """
    When I parse the SKILL.md file expecting an error
    Then the agent skill parse error should mention "name"

  @agent_skill_parse @error_handling
  Scenario: SKILL.md missing required description field raises error
    Given a SKILL.md file with frontmatter:
      """
      ---
      name: local/no-desc
      ---
      Some body text.
      """
    When I parse the SKILL.md file expecting an error
    Then the agent skill parse error should mention "description"

  @agent_skill_parse @error_handling
  Scenario: SKILL.md with invalid namespaced name raises error
    Given a SKILL.md file with frontmatter:
      """
      ---
      name: invalid-name-no-slash
      description: A skill with a bad name.
      ---
      Body text.
      """
    When I parse the SKILL.md file expecting an error
    Then the agent skill parse error should mention "namespace"

  @agent_skill_parse @error_handling
  Scenario: File without YAML frontmatter delimiter raises error
    Given a SKILL.md file with frontmatter:
      """
      Just plain text without frontmatter.
      No YAML delimiter here.
      """
    When I parse the SKILL.md file expecting an error
    Then the agent skill parse error should mention "frontmatter"

  @agent_skill_parse @error_handling
  Scenario: Empty SKILL.md file raises error
    Given an empty SKILL.md file
    When I parse the SKILL.md file expecting an error
    Then the agent skill parse error should mention "frontmatter"

  # ---------------------------------------------------------------------------
  # AgentSkillFolder — Folder Discovery
  # ---------------------------------------------------------------------------

  @agent_skill_folder
  Scenario: Discover a valid Agent Skills folder with SKILL.md
    Given an agent skills folder with a valid SKILL.md:
      """
      ---
      name: local/folder-skill
      description: A skill loaded from a folder.
      ---
      Instructions here.
      """
    When I load the agent skills folder
    Then the loaded agent skill name should be "local/folder-skill"
    And the loaded agent skill description should be "A skill loaded from a folder."

  @agent_skill_folder
  Scenario: Agent Skills folder discovers scripts/ subfolder
    Given an agent skills folder with a valid SKILL.md:
      """
      ---
      name: local/scripted-skill
      description: A skill with bundled scripts.
      ---
      Use the scripts provided.
      """
    And the folder contains a script file "deploy.py" with content "print('deploying')"
    When I load the agent skills folder
    Then the loaded agent skill script paths should include "deploy.py"

  @agent_skill_folder
  Scenario: Agent Skills folder discovers references/ subfolder
    Given an agent skills folder with a valid SKILL.md:
      """
      ---
      name: local/ref-skill
      description: A skill with reference documents.
      ---
      See references/ for more.
      """
    And the folder contains a reference file "guide.md" with content "# Guide"
    When I load the agent skills folder
    Then the loaded agent skill reference paths should include "guide.md"

  @agent_skill_folder
  Scenario: Agent Skills folder discovers assets/ subfolder
    Given an agent skills folder with a valid SKILL.md:
      """
      ---
      name: local/asset-skill
      description: A skill with assets.
      ---
      See assets/ for resources.
      """
    And the folder contains an asset file "template.json" with content "{}"
    When I load the agent skills folder
    Then the loaded agent skill asset paths should include "template.json"

  @agent_skill_folder
  Scenario: Agent Skills folder with no optional subfolders loads successfully
    Given an agent skills folder with a valid SKILL.md:
      """
      ---
      name: local/bare-skill
      description: A minimal folder skill with no subfolders.
      ---
      Minimal instructions.
      """
    When I load the agent skills folder
    Then the loaded agent skill script paths should be empty
    And the loaded agent skill reference paths should be empty
    And the loaded agent skill asset paths should be empty

  @agent_skill_folder @error_handling
  Scenario: Loading a folder without SKILL.md raises error
    Given an agent skills folder without a SKILL.md file
    When I load the agent skills folder expecting an error
    Then the agent skill load error should mention "SKILL.md"

  @agent_skill_folder @error_handling
  Scenario: Loading a non-existent folder raises error
    Given a non-existent agent skills folder path
    When I load the agent skills folder expecting an error
    Then the agent skill load error should mention "not found"

  # ---------------------------------------------------------------------------
  # Tool Mapping — AgentSkillSpec → ToolDescriptor
  # ---------------------------------------------------------------------------

  @agent_skill_tool_mapping
  Scenario: Agent skill maps to a tool with source agent_skill
    Given an agent skills folder with a valid SKILL.md:
      """
      ---
      name: local/mapped-skill
      description: Maps to a tool descriptor.
      ---
      Do the task.
      """
    When I load the agent skills folder
    And I convert the loaded agent skill to a tool descriptor
    Then the tool descriptor source should be "agent_skill"
    And the tool descriptor name should be "local/mapped-skill"

  @agent_skill_tool_mapping
  Scenario: Agent skill tool descriptor is read-only by default
    Given an agent skills folder with a valid SKILL.md:
      """
      ---
      name: local/readonly-skill
      description: Should default to read-only.
      ---
      Read things.
      """
    When I load the agent skills folder
    And I convert the loaded agent skill to a tool descriptor
    Then the tool descriptor should have read_only set to True
    And the tool descriptor should have writes set to False

  @agent_skill_tool_mapping
  Scenario: Agent skill tool descriptor includes allowed-tools in metadata
    Given an agent skills folder with a valid SKILL.md:
      """
      ---
      name: local/allowed-tools-skill
      description: Skill with allowed tools declared.
      allowed-tools:
        - local/read-file
        - local/git-status
      ---
      Use allowed tools only.
      """
    When I load the agent skills folder
    And I convert the loaded agent skill to a tool descriptor
    Then the tool descriptor allowed tools should include "local/read-file"
    And the tool descriptor allowed tools should include "local/git-status"

  @agent_skill_tool_mapping
  Scenario: Agent skill tool descriptor agent_skill_path points to folder
    Given an agent skills folder with a valid SKILL.md:
      """
      ---
      name: local/path-skill
      description: Path should be captured in descriptor.
      ---
      Instructions.
      """
    When I load the agent skills folder
    And I convert the loaded agent skill to a tool descriptor
    Then the tool descriptor agent_skill_path should be set

  # ---------------------------------------------------------------------------
  # Progressive Disclosure — Three-Tier Model
  # ---------------------------------------------------------------------------

  @progressive_disclosure
  Scenario: Discovery tier loads only metadata (name + description)
    Given an agent skills folder with a valid SKILL.md:
      """
      ---
      name: local/disclosure-skill
      description: Progressive disclosure test skill.
      ---
      Full instructions that should only load on activate.
      Step 1: do this.
      Step 2: do that.
      """
    When I call discover on the agent skill
    Then the discover result should have name "local/disclosure-skill"
    And the discover result should have description "Progressive disclosure test skill."
    And the discover result body should be empty

  @progressive_disclosure
  Scenario: Activation tier loads the full SKILL.md body
    Given an agent skills folder with a valid SKILL.md:
      """
      ---
      name: local/activate-skill
      description: Activation loads the body.
      ---
      Step 1: do this.
      Step 2: do that.
      """
    When I call discover on the agent skill
    And I call activate on the agent skill
    Then the activate result body should contain "Step 1: do this."
    And the activate result body should contain "Step 2: do that."

  @progressive_disclosure
  Scenario: Resource tier lists available scripts on demand
    Given an agent skills folder with a valid SKILL.md:
      """
      ---
      name: local/resource-skill
      description: Resource tier test skill.
      ---
      Use the scripts.
      """
    And the folder contains a script file "helper.py" with content "# helper"
    When I call discover on the agent skill
    And I list available resources
    Then the resources list should include "helper.py"

  @progressive_disclosure
  Scenario: Deactivation clears the loaded body
    Given an agent skills folder with a valid SKILL.md:
      """
      ---
      name: local/deactivate-skill
      description: Deactivation clears body.
      ---
      Step 1: do this.
      """
    When I call discover on the agent skill
    And I call activate on the agent skill
    And I call deactivate on the agent skill
    Then the agent skill body should be cleared

  # ---------------------------------------------------------------------------
  # Namespaced Naming
  # ---------------------------------------------------------------------------

  @agent_skill_naming
  Scenario: Skill with local namespace is accepted
    Given a SKILL.md file with frontmatter:
      """
      ---
      name: local/my-skill
      description: A valid local skill.
      ---
      Body.
      """
    When I parse the SKILL.md file
    Then the parsed skill name should be "local/my-skill"

  @agent_skill_naming
  Scenario: Skill with custom namespace is accepted
    Given a SKILL.md file with frontmatter:
      """
      ---
      name: devops/deploy-pipeline
      description: A skill in the devops namespace.
      ---
      Body.
      """
    When I parse the SKILL.md file
    Then the parsed skill name should be "devops/deploy-pipeline"

  @agent_skill_naming
  Scenario: Skill name with underscores and hyphens is accepted
    Given a SKILL.md file with frontmatter:
      """
      ---
      name: local/my_complex-skill_v2
      description: Valid name with mixed characters.
      ---
      Body.
      """
    When I parse the SKILL.md file
    Then the parsed skill name should be "local/my_complex-skill_v2"

  @agent_skill_naming @error_handling
  Scenario: Skill name with special characters is rejected
    Given a SKILL.md file with frontmatter:
      """
      ---
      name: local/bad name!
      description: Invalid name.
      ---
      Body.
      """
    When I parse the SKILL.md file expecting an error
    Then the agent skill parse error should mention "namespace"

  # ---------------------------------------------------------------------------
  # Stable Step Ordering
  # ---------------------------------------------------------------------------

  @agent_skill_ordering
  Scenario: Steps in SKILL.md body are preserved in stable order
    Given a SKILL.md file with frontmatter:
      """
      ---
      name: local/ordered-skill
      description: Ordered steps skill.
      ---
      Step A: First action.
      Step B: Second action.
      Step C: Third action.
      """
    When I parse the SKILL.md file
    Then the parsed skill body steps should appear in order: "Step A", "Step B", "Step C"

  # ---------------------------------------------------------------------------
  # Folder path normalization and safety
  # ---------------------------------------------------------------------------

  @agent_skill_safety
  Scenario: Script paths are normalized to relative paths within the folder
    Given an agent skills folder with a valid SKILL.md:
      """
      ---
      name: local/safe-skill
      description: Path normalization test.
      ---
      Use scripts.
      """
    And the folder contains a script file "run.py" with content "# run"
    When I load the agent skills folder
    Then all script paths should be relative to the skill folder

  # ---------------------------------------------------------------------------
  # Edge case coverage — branch and statement completeness
  # ---------------------------------------------------------------------------

  @agent_skill_parse @error_handling @coverage
  Scenario: AgentSkillSpec.from_file on a non-existent path raises FileNotFoundError
    Given a non-existent SKILL.md path
    When I parse the non-existent SKILL.md file expecting an error
    Then the agent skill parse error should mention "SKILL.md"

  @agent_skill_parse @error_handling @coverage
  Scenario: SKILL.md with unclosed frontmatter delimiter raises error
    Given a SKILL.md file with frontmatter:
      """
      ---
      name: local/unclosed-skill
      description: This frontmatter is never closed.
      """
    When I parse the SKILL.md file expecting an error
    Then the agent skill parse error should mention "frontmatter"

  @agent_skill_parse @error_handling @coverage
  Scenario: SKILL.md with empty frontmatter block raises error
    Given a SKILL.md with an empty frontmatter block
    When I parse the SKILL.md file expecting an error
    Then the agent skill parse error should mention "frontmatter"

  @agent_skill_parse @error_handling @coverage
  Scenario: SKILL.md with malformed YAML in frontmatter raises error
    Given a SKILL.md with malformed YAML frontmatter
    When I parse the SKILL.md file expecting an error
    Then the agent skill parse error should mention "YAML"

  @agent_skill_parse @error_handling @coverage
  Scenario: SKILL.md with non-mapping YAML frontmatter raises error
    Given a SKILL.md with a YAML list as frontmatter instead of a mapping
    When I parse the SKILL.md file expecting an error
    Then the agent skill parse error should mention "mapping"

  @agent_skill_folder @coverage
  Scenario: AgentSkillLoader folder property returns resolved path
    Given an agent skills folder with a valid SKILL.md:
      """
      ---
      name: local/prop-skill
      description: Property access test skill.
      ---
      Body text.
      """
    When I load the agent skills folder
    Then the loaded agent skill folder property should be set

  @agent_skill_folder @error_handling @coverage
  Scenario: Loading a path that is a file not a directory raises error
    Given an agent skills folder path that is a file
    When I load the agent skills folder expecting an error
    Then the agent skill load error should mention "not a directory"

  @agent_skill_parse @coverage
  Scenario: SKILL.md with non-dict compatibility is handled gracefully
    Given a SKILL.md file with frontmatter:
      """
      ---
      name: local/bad-compat
      description: Skill with non-dict compatibility field.
      compatibility: "just a string"
      ---
      Body text.
      """
    When I parse the SKILL.md file
    Then the parsed skill name should be "local/bad-compat"

  @agent_skill_parse @coverage
  Scenario: SKILL.md with non-dict metadata is handled gracefully
    Given a SKILL.md file with frontmatter:
      """
      ---
      name: local/bad-meta
      description: Skill with non-dict metadata field.
      metadata: "just a string"
      ---
      Body text.
      """
    When I parse the SKILL.md file
    Then the parsed skill name should be "local/bad-meta"

  @agent_skill_folder @coverage
  Scenario: Sub-directories inside scripts/ are skipped during discovery
    Given an agent skills folder with a valid SKILL.md:
      """
      ---
      name: local/nested-skill
      description: Skill with nested directories in scripts/.
      ---
      Use scripts.
      """
    And the folder contains a script file "run.py" with content "# run"
    And the scripts folder contains a nested sub-directory
    When I load the agent skills folder
    Then the loaded agent skill script paths should include "run.py"
    And the loaded agent skill script paths should not include any directories

  @agent_skill_loader @error_handling @coverage
  Scenario: AgentSkillLoader constructor rejects None spec
    When I construct an AgentSkillLoader with None spec expecting an error
    Then the agent skill load error should mention "spec"

  @agent_skill_loader @error_handling @coverage
  Scenario: AgentSkillLoader constructor rejects None folder
    When I construct an AgentSkillLoader with None folder expecting an error
    Then the agent skill load error should mention "folder"

  @agent_skill_folder @error_handling @coverage
  Scenario: AgentSkillLoader.from_folder rejects None path
    When I call from_folder with None expecting an error
    Then the agent skill load error should mention "folder"

  # ---------------------------------------------------------------------------
  # Structured Steps — frontmatter steps list → SkillStep objects
  # ---------------------------------------------------------------------------

  @agent_skill_steps
  Scenario: SKILL.md with steps list in frontmatter parses into SkillStep objects
    Given a SKILL.md file with frontmatter:
      """
      ---
      name: local/step-skill
      description: Skill with structured steps.
      steps:
        - Run tests to verify everything passes
        - Push branch to remote repository
        - Deploy to staging environment
      ---
      Detailed instructions go here.
      """
    When I parse the SKILL.md file
    Then the parsed skill steps should have 3 entries
    And the parsed skill step 1 content should be "Run tests to verify everything passes"
    And the parsed skill step 2 content should be "Push branch to remote repository"
    And the parsed skill step 3 content should be "Deploy to staging environment"

  @agent_skill_steps
  Scenario: Structured steps maintain stable 1-based index ordering
    Given a SKILL.md file with frontmatter:
      """
      ---
      name: local/ordered-steps-skill
      description: Ordered structured steps.
      steps:
        - Alpha step
        - Beta step
        - Gamma step
      ---
      Body text.
      """
    When I parse the SKILL.md file
    Then the parsed skill step 1 index should be 1
    And the parsed skill step 2 index should be 2
    And the parsed skill step 3 index should be 3

  @agent_skill_steps
  Scenario: SKILL.md without steps field has empty steps list
    Given a SKILL.md file with frontmatter:
      """
      ---
      name: local/no-steps-skill
      description: Skill without steps field.
      ---
      Body text.
      """
    When I parse the SKILL.md file
    Then the parsed skill steps should have 0 entries

  @agent_skill_steps @error_handling
  Scenario: SKILL.md with steps as a non-list raises actionable error
    Given a SKILL.md file with frontmatter:
      """
      ---
      name: local/bad-steps-skill
      description: Skill with invalid steps field type.
      steps: "just a string instead of a list"
      ---
      Body text.
      """
    When I parse the SKILL.md file expecting an error
    Then the agent skill parse error should mention "steps"

  @agent_skill_steps @error_handling
  Scenario: SKILL.md with an empty step entry raises actionable error
    Given a SKILL.md file with frontmatter:
      """
      ---
      name: local/empty-step-skill
      description: Skill with an empty step in the list.
      steps:
        - First valid step
        -
      ---
      Body text.
      """
    When I parse the SKILL.md file expecting an error
    Then the agent skill parse error should mention "steps"

  # ---------------------------------------------------------------------------
  # Resource Binding Slots — read-only slots for discovered directories
  # ---------------------------------------------------------------------------

  @agent_skill_resource_slots
  Scenario: Tool descriptor includes resource binding slots for discovered directories
    Given an agent skills folder with a valid SKILL.md:
      """
      ---
      name: local/slotted-skill
      description: Skill with resource directories.
      ---
      Use scripts and references.
      """
    And the folder contains a script file "run.py" with content "# run"
    And the folder contains a reference file "guide.md" with content "# Guide"
    When I load the agent skills folder
    And I convert the loaded agent skill to a tool descriptor
    Then the tool descriptor should have 2 resource slot(s)
    And the tool descriptor resource slot "scripts" should have access "read_only"
    And the tool descriptor resource slot "references" should have access "read_only"

  @agent_skill_resource_slots
  Scenario: Tool descriptor with no resource directories has empty resource slots
    Given an agent skills folder with a valid SKILL.md:
      """
      ---
      name: local/no-slots-skill
      description: Skill with no resource directories.
      ---
      Instructions.
      """
    When I load the agent skills folder
    And I convert the loaded agent skill to a tool descriptor
    Then the tool descriptor should have 0 resource slot(s)
    And the loaded skill resource_slots property should be empty

  @agent_skill_resource_slots
  Scenario: Discover descriptor includes resource binding slots
    Given an agent skills folder with a valid SKILL.md:
      """
      ---
      name: local/discover-slots-skill
      description: Skill exposing slots at discover time.
      ---
      Instructions.
      """
    And the folder contains an asset file "config.json" with content "{}"
    When I call discover on the agent skill
    Then the discover result should have 1 resource slot(s)
    And the discover result resource slot "assets" should have access "read_only"
