Skip to content

Add pub-dev-search skill - #3

Open
csells wants to merge 1 commit into
kevmoo:mainfrom
csells:pub-dev-search
Open

Add pub-dev-search skill#3
csells wants to merge 1 commit into
kevmoo:mainfrom
csells:pub-dev-search

Conversation

@csells

@csells csells commented Feb 15, 2026

Copy link
Copy Markdown

Summary

  • Add new pub-dev-search skill that searches pub.dev for Dart/Flutter packages and provides recommendations
  • Includes a Python script that queries the pub.dev API for search results, package metrics (quality points, likes, 30-day downloads), and publication dates
  • Recommends packages based on quality score, popularity, recency, Flutter Favorite status, and Dart 3 compatibility
  • Update README with the new skill entry

Test plan

  • Tested search script with multiple queries (state management, http client, json)
  • Verified both table and JSON output modes
  • Confirmed API endpoints return expected data (search, metrics, package info)
  • Validated skill packaging passes

Search pub.dev for Dart/Flutter packages and recommend based on quality
score, popularity, likes, download counts, and publication recency.
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello @csells, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request integrates a new pub-dev-search skill, significantly enhancing the agent's capability to assist with Dart and Flutter development. By leveraging a dedicated Python script, the skill can efficiently query the pub.dev repository and present well-informed package recommendations based on a robust set of metrics, streamlining the process of package discovery and selection for users.

Highlights

  • New Skill Added: Introduced a new pub-dev-search skill designed to search pub.dev for Dart/Flutter packages and provide recommendations.
  • Python Script for API Interaction: Developed a Python script (search_pub_dev.py) that queries the pub.dev API to retrieve search results, package metrics (quality points, likes, 30-day downloads), and publication dates.
  • Recommendation Logic: Implemented logic to recommend packages based on several criteria, including quality score, popularity, recency, Flutter Favorite status, and Dart 3 compatibility.
  • Documentation and README Update: Added comprehensive documentation for the new skill and updated the main README.md file to include it in the list of available skills.
Changelog
  • .agent/skills/pub-dev-search/SKILL.md
    • Added new skill documentation for pub-dev-search.
    • Included usage instructions for the associated Python script.
    • Detailed the criteria for making package recommendations.
  • .agent/skills/pub-dev-search/scripts/search_pub_dev.py
    • Implemented a new Python script to interact with the pub.dev API for package search and data retrieval.
    • Added functions for searching packages, fetching metrics, and getting detailed package information.
    • Included utility functions for formatting dates and download counts.
    • Provided command-line argument parsing for query, result count, and JSON output.
    • Structured the output to display package details in a formatted table or JSON.
  • README.md
    • Updated the skills table to include the new pub.dev Search skill.
Activity
  • No human activity has been recorded on this pull request yet.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@gemini-code-assist gemini-code-assist Bot left a comment

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.

Code Review

This pull request introduces a new pub-dev-search skill, which includes a Python script for querying the pub.dev API. While the implementation is well-structured, two critical security concerns have been identified: a potential command injection vulnerability in the skill's usage template in SKILL.md and a risk of indirect prompt injection in the handling of untrusted package descriptions in search_pub_dev.py. Additionally, there are opportunities to improve the skill's robustness and performance through comprehensive error handling for network requests, concurrent API calls, and more robust tag parsing against malformed data.

Run the search script with the user's query:

```bash
python3 <skill-dir>/scripts/search_pub_dev.py "<query>" -n <count>

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.

security-high high

The usage template in the SKILL.md file is vulnerable to command injection. The <query> placeholder is placed directly inside double quotes in a shell command context: python3 <skill-dir>/scripts/search_pub_dev.py "<query>" -n <count>. If the agent executor replaces this placeholder with unsanitized user input and executes the resulting string in a shell (e.g., using os.system or subprocess.run(shell=True)), an attacker can escape the double quotes and execute arbitrary commands on the host system. For example, a query like "; touch /tmp/pwned; " would result in the execution of touch /tmp/pwned. To remediate this, the skill definition should avoid suggesting shell-style command construction with string interpolation, or the agent framework should be configured to pass arguments safely (e.g., as a list to subprocess.run with shell=False).

Comment on lines +23 to +28
def get_package_score(package_name):
"""Get the score/metrics for a package."""
url = f"{BASE_URL}/packages/{urllib.parse.quote(package_name)}/metrics"
req = urllib.request.Request(url, headers={"Accept": "application/json"})
with urllib.request.urlopen(req) as resp:
return json.loads(resp.read().decode())

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.

high

The script currently doesn't handle network errors (e.g., timeouts, HTTP errors like 404 or 500) when making API requests to pub.dev. An unhandled error will cause the script to crash. It's important to wrap these requests in try...except blocks to gracefully handle failures. Also, it's good practice to set a User-Agent header and a timeout for requests.

This same feedback applies to the search_packages and get_package_info functions.

Suggested change
def get_package_score(package_name):
"""Get the score/metrics for a package."""
url = f"{BASE_URL}/packages/{urllib.parse.quote(package_name)}/metrics"
req = urllib.request.Request(url, headers={"Accept": "application/json"})
with urllib.request.urlopen(req) as resp:
return json.loads(resp.read().decode())
def get_package_score(package_name):
"""Get the score/metrics for a package."""
url = f"{BASE_URL}/packages/{urllib.parse.quote(package_name)}/metrics"
req = urllib.request.Request(
url, headers={"Accept": "application/json", "User-Agent": "pub-dev-search-skill/1.0"}
)
try:
with urllib.request.urlopen(req, timeout=15) as resp:
return json.loads(resp.read().decode())
except (urllib.error.URLError, urllib.error.HTTPError) as e:
print(f"Warning: Could not fetch score for {package_name}: {e}", file=sys.stderr)
return {}

)
# Print description on next line, truncated
desc = p["description"][:100] + ("..." if len(p["description"]) > 100 else "")
print(f" {desc}")

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.

security-medium medium

The script prints package descriptions directly from the pub.dev API to stdout. These descriptions are untrusted and could contain malicious instructions designed to manipulate the LLM's behavior (Indirect Prompt Injection). While the script already truncates the description to 100 characters, this does not fully eliminate the risk. Consider wrapping untrusted content in clear delimiters (e.g., [START OF UNTRUSTED CONTENT] ... [END OF UNTRUSTED CONTENT]) and providing instructions to the LLM to treat content within those delimiters as potentially untrusted.

Comment on lines +91 to +94
for pkg in packages:
name = pkg["package"]
info = get_package_info(name)
metrics = get_package_score(name)

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.

medium

The script currently fetches details for each package sequentially within a for loop. This results in 2 * N sequential network requests, which can be very slow if N is large. To significantly improve performance, consider fetching the details for all packages concurrently.

You can use concurrent.futures.ThreadPoolExecutor to parallelize the API calls. For example, you could define a function that fetches both info and metrics for a single package, and then use a ThreadPoolExecutor to run this function for all packages in parallel.

Comment on lines +118 to +139
"publisher": next(
(
t.split(":")[1]
for t in tags
if t.startswith("publisher:")
),
"",
),
"quality_points": f"{granted}/{max_pts}",
"quality_pct": quality_pct,
"likes": likes,
"downloads_30d": downloads_30d,
"published_date": pub_date,
"published_age": pub_age,
"flutter_favorite": is_flutter_fav,
"dart3_compatible": is_dart3,
"sdks": [
t.split(":")[1] for t in tags if t.startswith("sdk:")
],
"platforms": [
t.split(":")[1] for t in tags if t.startswith("platform:")
],

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.

medium

The current code for parsing tags like publisher, sdks, and platforms could raise an IndexError if a tag is malformed (e.g., publisher: without a value). To make this more robust, it's safer to check for the existence of a colon before splitting and accessing the value. Using t.split(':', 1) is also safer than t.split(':') as it only splits on the first occurrence.

                "publisher": next(
                    (
                        t.split(":", 1)[1]
                        for t in tags
                        if t.startswith("publisher:") and ":" in t
                    ),
                    "",
                ),
                "quality_points": f"{granted}/{max_pts}",
                "quality_pct": quality_pct,
                "likes": likes,
                "downloads_30d": downloads_30d,
                "published_date": pub_date,
                "published_age": pub_age,
                "flutter_favorite": is_flutter_fav,
                "dart3_compatible": is_dart3,
                "sdks": [
                    t.split(":", 1)[1] for t in tags if t.startswith("sdk:") and ":" in t
                ],
                "platforms": [
                    t.split(":", 1)[1] for t in tags if t.startswith("platform:") and ":" in t
                ],

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