mirror of
https://github.com/KRTirtho/spotube.git
synced 2026-08-05 19:59:51 +00:00
feat: add ChipTab component and refactor SearchScreen to use it
This commit is contained in:
parent
28ff68dcc9
commit
8870113e4d
@ -1,290 +0,0 @@
|
||||
---
|
||||
name: exploring_dependency_sources
|
||||
description: >
|
||||
Reads and searches source code across ALL scopes: external library dependencies, plugins (buildscript), and Gradle Build Tool internal source code;
|
||||
use whenever you need to UNDERSTAND an API — its shape, signature, parameters, overloads, or implementation — before writing any code that calls it;
|
||||
covers project dependencies (via project/configuration/source set scope), plugins (via `sourceSetPath=":buildscript"`), and Gradle internals (via `gradleSource: true`).
|
||||
Prefer this over the REPL for all API research; reading source is instantaneous and complete.
|
||||
Do NOT use for project source code (use grep/tilth), Gradle documentation (use `gradle_docs` via the `gradle` skill), or Maven Central discovery (use `managing_gradle_dependencies`).
|
||||
license: Apache-2.0
|
||||
metadata:
|
||||
author: https://github.com/rnett/gradle-mcp
|
||||
version: "2.0"
|
||||
---
|
||||
|
||||
# Authoritative Dependency, Plugin & Gradle Internal Source Exploration
|
||||
|
||||
Explores, navigates, and analyzes the internal logic, APIs, and symbol implementations of external libraries, Gradle plugins, and the Gradle Build Tool itself with absolute precision using high-performance, indexed searching.
|
||||
|
||||
## Constitution
|
||||
|
||||
- **ALWAYS** use `search_dependency_sources` as the primary discovery tool for external library, plugin, and Gradle internal code.
|
||||
- **ALWAYS** prefer reading source code over interactive REPL exploration for understanding unfamiliar library APIs.
|
||||
- **ALWAYS** provide absolute paths for `projectRoot`.
|
||||
- **ALWAYS** use the `{group}/{artifact}` prefix for reading specific files (e.g., `path="org.mongodb/mongodb-driver-sync/org/mongodb/client/MongoClient.kt"`). The `dependency` parameter should only be used to filter the search scope for
|
||||
performance when searching across libraries, not as the primary way to specify a path.
|
||||
- **ALWAYS** escape Lucene special characters (`:`, `=`, `+`, `-`, `*`, `/`) in `FULL_TEXT` searches using a backslash (e.g., `\:`) or double quotes.
|
||||
- **ALWAYS** use `read_dependency_sources` once a specific file path has been identified via search.
|
||||
- **ALWAYS** use `fresh: true` if a search returns a `SearchResponse` with an `error` indicating a missing index.
|
||||
- **BE AWARE** that indexing and extraction failures (e.g., `ZipException`) are propagated and will cause the tool to fail with a descriptive error.
|
||||
- **NOTE** that the `dependency` filter targets ONLY the specific library version matched, NOT its transitive dependencies.
|
||||
- **BE AWARE** that buildscript (plugin) dependencies are excluded from `search_dependency_sources` and `read_dependency_sources` by default to reduce noise.
|
||||
- **ALWAYS** use `sourceSetPath=":buildscript"` (root project) or `sourceSetPath=":app:buildscript"` (subproject) to search or read plugin source code. This targets the virtual `buildscript` source set which aggregates all classpath
|
||||
plugins.
|
||||
- **ALWAYS** use `gradleSource: true` in `search_dependency_sources` to target Gradle's internal engine when probing core Gradle behavior.
|
||||
- **ALWAYS** scope with a project, configuration, or source set (or use `gradleSource: true`) — unscoped search is no longer supported.
|
||||
- **ALWAYS** verify against the actual source implementation when researching Gradle internals.
|
||||
- **NEVER** use generic shell tools like `grep` or `find` to *locate* dependency sources; they reside in remote caches whose paths are not predictable in advance.
|
||||
- **MAY** use shell tools like `rg` or `ast-grep` to *operate on* a sources root path explicitly returned by `read_dependency_sources` or `search_dependency_sources` in the `Sources root: <path>` header line. Dependency directories inside
|
||||
the sources root are symlinks; always pass `--follow` to `rg` (e.g., `rg --follow <pattern> <sources-root>`).
|
||||
|
||||
## Directives
|
||||
|
||||
### Search Modes
|
||||
|
||||
- **DECLARATION**: Best for classes, methods, or interfaces. Matches against the simple name (tokenized for CamelCase) and the full path (exact literal). All declaration searches are **case-sensitive**. Do NOT include keywords like `class`,
|
||||
`interface`, or `fun`. Supports exact names, exact FQNs, glob wildcards (e.g., `*`, `**`), and regular expressions. Use `name:` (discovery) or `fqn:` (precision) prefix for field-specific searches.
|
||||
- **FULL_TEXT**: Best for literal strings, constants, and complex code patterns using Lucene. **Case-insensitive**.
|
||||
- **GLOB**: Best for finding specific files (XML, properties, etc.) by name or extension. **Case-insensitive**.
|
||||
|
||||
Glob wildcards for FQNs: `*` matches one segment, `**` matches multiple. Example: `fqn:org.gradle.*.Project` or `fqn:org.**.Project`.
|
||||
|
||||
Regex: Wrap query in `/` for a full regular expression on the `fqn` field. Example: `fqn:/.*\.internal\..*/` to find all internal declarations.
|
||||
|
||||
### Scoping
|
||||
|
||||
- **Project Dependencies**: Use `search_dependency_sources` with `projectPath`, `configurationPath`, or `sourceSetPath` to scope to project dependency code.
|
||||
- **Plugins (Buildscript)**: Use `sourceSetPath=":buildscript"` to target plugin source code.
|
||||
- **Gradle Internals**: Use `gradleSource: true` to target Gradle Build Tool source code.
|
||||
|
||||
### Performance
|
||||
|
||||
- **Target Libraries Directly**: Use the `dependency` parameter to filter searches to a single library (`group:name:version:variant`, `group:name:version`, `group:name`, or just `group`). This bypasses project-level index merging for
|
||||
instantaneous results.
|
||||
- **Troubleshoot Targeted Searches**: If a targeted search fails, use `inspect_dependencies` first to verify the exact coordinates of the dependency as resolved by Gradle.
|
||||
- **Refresh Indices**: Use `fresh: true` if project dependencies have recently changed.
|
||||
- **Use Returned Sources Root**: Every response includes a `Sources root: <absolute-path>` header. Use this path with `rg`, `ast-grep`, or other shell tools for operations not covered by the MCP tools. Always pass `--follow` to `rg` for
|
||||
symlinked dependency directories.
|
||||
|
||||
### Exploration
|
||||
|
||||
- **Explore Packages Authoritatively**: Use `read_dependency_sources` with a dot-separated package path (e.g., `org.gradle.api`) to list its direct symbols and sub-packages.
|
||||
- **Analyze Implementation**: Use `read_dependency_sources` to retrieve implementation logic. Use `pagination` for large files.
|
||||
- **Trace Symbols Authoritatively**: When encountering an unknown symbol, use `DECLARATION` search to jump directly to its definition.
|
||||
|
||||
## When to Use
|
||||
|
||||
> **Decision rule**: If the question is *"what does this API look like or how does it work?"* — use this skill. If you need to *run* code to see what it does at runtime — use `interacting_with_project_runtime` (REPL). Read before you run.
|
||||
|
||||
- **API & Symbol Discovery**: Finding implementation, signature, or documentation of a class/interface/method from a dependency, plugin, or Gradle itself.
|
||||
- **Library Usage Research**: Understanding how to use a library's API by reading its internal implementation.
|
||||
- **Internal Logic Auditing**: Researching how a dependency or Gradle engine handles specific operations.
|
||||
- **Resource File Location**: Searching for configuration files (XML, JSON, properties) or metadata packaged within library jars.
|
||||
- **Constant & Literal Research**: Searching for specific constant values, error strings, or literal keys within external code.
|
||||
- **Gradle Internal Exploration**: Probing Gradle engine classes (e.g., `org.gradle.api.Project`, `Task`, `DependencyHandler`) to understand internal behavior.
|
||||
- **Plugin Source Auditing**: Examining plugin implementations to understand how they configure the build at runtime.
|
||||
|
||||
## Workflows
|
||||
|
||||
### 1. Tracing a Symbol from Project Code
|
||||
|
||||
1. Identify the symbol name or fully qualified name from an import.
|
||||
2. Call `search_dependency_sources(query="<SymbolName>", searchType="DECLARATION", projectPath=":")`.
|
||||
3. Identify the correct file path from the results.
|
||||
4. Call `read_dependency_sources(path="<path>", projectPath=":")` to analyze the implementation.
|
||||
|
||||
### 2. Discovering API Usage through Source
|
||||
|
||||
1. Search for a known entry point (constructor, main class) using `DECLARATION` or `FULL_TEXT`.
|
||||
2. Once found, use `read_dependency_sources` to read the source.
|
||||
3. Look for internal calls, helper methods, or factory patterns to understand preferred usage.
|
||||
|
||||
### 3. Researching Gradle Internal Engine
|
||||
|
||||
1. Search for the class: `search_dependency_sources(query="<ClassName>", searchType="DECLARATION", gradleSource=true)`.
|
||||
2. Use glob wildcards for subpackage searches: `fqn:org.gradle.*.SomeApi` or `fqn:org.**.SomeApi`.
|
||||
3. Once identified, read the implementation: `read_dependency_sources(path="org/gradle/...", gradleSource=true)`.
|
||||
4. Check for breaking changes against specific versions via `gradle_docs` (see `gradle` skill).
|
||||
|
||||
### 4. Researching Plugin Source Code
|
||||
|
||||
1. Search plugins: `search_dependency_sources(query="<PluginName>", searchType="DECLARATION", sourceSetPath=":buildscript")`.
|
||||
2. Read plugin implementation: `read_dependency_sources(path="<group>/<artifact>/...", sourceSetPath=":buildscript")`.
|
||||
|
||||
### 5. Targeted Search for a Single Library
|
||||
|
||||
1. Identify dependency coordinates from `inspect_dependencies` or project files.
|
||||
2. Call `search_dependency_sources(query="<query>", dependency="<group:artifact>", projectPath=":")`.
|
||||
3. Results are scoped ONLY to that library for maximum speed and relevance.
|
||||
|
||||
### 6. Searching for Constants or Error Codes
|
||||
|
||||
1. Identify the constant name or error message snippet.
|
||||
2. Call `search_dependency_sources(query="<text>", projectPath=":")` (defaults to `FULL_TEXT`).
|
||||
3. Review matches to find where the value is defined or used.
|
||||
|
||||
### 7. Exploring Documentation (Gradle Docs)
|
||||
|
||||
For official Gradle documentation (User Guide, DSL, Release Notes), use the `gradle_docs` tool via the `gradle` skill. See [Internal Source Research](references/internal_source_research.md) for authoritative research patterns combining docs
|
||||
and source.
|
||||
|
||||
## Examples
|
||||
|
||||
### Search for a specific class definition (project deps)
|
||||
|
||||
Tool: `search_dependency_sources`
|
||||
|
||||
```json
|
||||
{
|
||||
"query": "JsonConfiguration",
|
||||
"searchType": "DECLARATION",
|
||||
"projectPath": ":"
|
||||
}
|
||||
// Reasoning: DECLARATION search for a class name across both name and FQN fields, scoped to the root project.
|
||||
```
|
||||
|
||||
### Search Gradle internal engine source code
|
||||
|
||||
Tool: `search_dependency_sources`
|
||||
|
||||
```json
|
||||
{
|
||||
"query": "Project",
|
||||
"searchType": "DECLARATION",
|
||||
"gradleSource": true
|
||||
}
|
||||
// Reasoning: Using gradleSource and DECLARATION search to find the ground-truth implementation of the core Project API.
|
||||
```
|
||||
|
||||
### Search for a specific class within a targeted library
|
||||
|
||||
Tool: `search_dependency_sources`
|
||||
|
||||
```json
|
||||
{
|
||||
"query": "MongoClient",
|
||||
"searchType": "DECLARATION",
|
||||
"dependency": "org.mongodb:mongodb-driver-sync",
|
||||
"projectPath": ":"
|
||||
}
|
||||
// Reasoning: The 'dependency' parameter targets only the 'mongodb-driver-sync' library for a fast, focused search.
|
||||
```
|
||||
|
||||
### Search plugin source code
|
||||
|
||||
Tool: `search_dependency_sources`
|
||||
|
||||
```json
|
||||
{
|
||||
"query": "KotlinPlugin",
|
||||
"searchType": "DECLARATION",
|
||||
"sourceSetPath": ":buildscript"
|
||||
}
|
||||
// Reasoning: Targeting the buildscript source set to find plugin implementation classes.
|
||||
```
|
||||
|
||||
### Search with FQN glob wildcards (Gradle internals)
|
||||
|
||||
Tool: `search_dependency_sources`
|
||||
|
||||
```json
|
||||
{
|
||||
"query": "fqn:org.gradle.*.Project",
|
||||
"searchType": "DECLARATION",
|
||||
"gradleSource": true
|
||||
}
|
||||
// Reasoning: Glob wildcard to find Project declarations in any direct sub-package of org.gradle.
|
||||
```
|
||||
|
||||
### Use regular expressions for internal APIs
|
||||
|
||||
Tool: `search_dependency_sources`
|
||||
|
||||
```json
|
||||
{
|
||||
"query": "fqn:/.*\\.internal\\..*/",
|
||||
"searchType": "DECLARATION",
|
||||
"gradleSource": true
|
||||
}
|
||||
// Reasoning: Regex on the 'fqn' field to find all internal Gradle declarations.
|
||||
```
|
||||
|
||||
### Search with name-specific discovery (CamelCase)
|
||||
|
||||
Tool: `search_dependency_sources`
|
||||
|
||||
```json
|
||||
{
|
||||
"query": "name:Configuration",
|
||||
"searchType": "DECLARATION",
|
||||
"projectPath": ":"
|
||||
}
|
||||
// Reasoning: The 'name:' prefix finds classes like 'JsonConfiguration' via CamelCase tokenization.
|
||||
```
|
||||
|
||||
### Search for a constant value assignment
|
||||
|
||||
Tool: `search_dependency_sources`
|
||||
|
||||
```json
|
||||
{
|
||||
"query": "DEFAULT_TIMEOUT_MS \\: 5000",
|
||||
"projectPath": ":"
|
||||
}
|
||||
// Reasoning: FULL_TEXT (default) with escaped colon to find a specific constant assignment.
|
||||
```
|
||||
|
||||
### Locate a specific file by its exact name
|
||||
|
||||
Tool: `search_dependency_sources`
|
||||
|
||||
```json
|
||||
{
|
||||
"query": "**/AndroidManifest.xml",
|
||||
"searchType": "GLOB",
|
||||
"projectPath": ":"
|
||||
}
|
||||
// Reasoning: GLOB search to find a specific file by name across the dependency graph.
|
||||
```
|
||||
|
||||
### Read sources from a specific dependency
|
||||
|
||||
Tool: `read_dependency_sources`
|
||||
|
||||
```json
|
||||
{
|
||||
"path": "org.jetbrains.kotlinx/kotlinx-coroutines-core/kotlinx/coroutines/Job.kt",
|
||||
"projectPath": ":"
|
||||
}
|
||||
// Reasoning: Reading 'Job.kt' using the recommended `{group}/{artifact}` syntax.
|
||||
```
|
||||
|
||||
### Read a specific Gradle internal class
|
||||
|
||||
Tool: `read_dependency_sources`
|
||||
|
||||
```json
|
||||
{
|
||||
"path": "org/gradle/api/Project.java",
|
||||
"gradleSource": true
|
||||
}
|
||||
// Reasoning: Retrieving the source code for a fundamental Gradle class for high-resolution analysis.
|
||||
```
|
||||
|
||||
### Explore a package via its FQN
|
||||
|
||||
Tool: `read_dependency_sources`
|
||||
|
||||
```json
|
||||
{
|
||||
"path": "org.gradle.api",
|
||||
"projectPath": ":"
|
||||
}
|
||||
// Reasoning: Listing the direct symbols and sub-packages of 'org.gradle.api' using index-backed exploration.
|
||||
```
|
||||
|
||||
## Resources
|
||||
|
||||
- [Internal Source Research](references/internal_source_research.md) — Combining `gradle_docs` documentation lookup with `gradleSource: true` source searches for authoritative research.
|
||||
- **Lucene Query Syntax**: Refer to the tool description for `search_dependency_sources` for details on complex queries and escaping.
|
||||
- **Troubleshooting Targeted Searches**: If `dependency` filter fails, run `inspect_dependencies` to confirm exact coordinates.
|
||||
@ -1,126 +0,0 @@
|
||||
# Gradle Internal Source Research
|
||||
|
||||
Guidance for researching Gradle Build Tool's internal implementation and third-party plugin source code using `search_dependency_sources` and `read_dependency_sources`.
|
||||
|
||||
## Searching the Gradle Engine
|
||||
|
||||
Use `gradleSource = true` and select the appropriate `searchType`:
|
||||
|
||||
### DECLARATION: Finding Class/Interface Definitions
|
||||
|
||||
```json
|
||||
{
|
||||
"query": "DefaultProject",
|
||||
"searchType": "DECLARATION",
|
||||
"gradleSource": true
|
||||
}
|
||||
```
|
||||
|
||||
Search by simple name, FQN, or partial package paths. All declaration searches are **case-sensitive**.
|
||||
|
||||
### DECLARATION with FQN Glob Wildcards
|
||||
|
||||
```json
|
||||
{
|
||||
"query": "fqn:org.gradle.*.Project",
|
||||
"searchType": "DECLARATION",
|
||||
"gradleSource": true
|
||||
}
|
||||
```
|
||||
|
||||
`*` matches one segment, `**` matches multiple. Example: `fqn:org.**.AbstractTask`.
|
||||
|
||||
### Regex on FQN for Internal APIs
|
||||
|
||||
```json
|
||||
{
|
||||
"query": "fqn:/.*\\.internal\\..*/",
|
||||
"searchType": "DECLARATION",
|
||||
"gradleSource": true
|
||||
}
|
||||
```
|
||||
|
||||
### FULL_TEXT: Searching Implementation Patterns
|
||||
|
||||
```json
|
||||
{
|
||||
"query": "configurationCache",
|
||||
"gradleSource": true
|
||||
}
|
||||
```
|
||||
|
||||
**Case-insensitive** text search. Escape Lucene special characters (`:`, `=`, `+`, `-`, `*`, `/`) with backslash.
|
||||
|
||||
### GLOB: Finding Internal Resource Files
|
||||
|
||||
```json
|
||||
{
|
||||
"query": "**/plugin.properties",
|
||||
"searchType": "GLOB",
|
||||
"gradleSource": true
|
||||
}
|
||||
```
|
||||
|
||||
**Case-insensitive** file name search.
|
||||
|
||||
## Reading Implementation Details
|
||||
|
||||
Once a class is identified via search, read its source:
|
||||
|
||||
```json
|
||||
{
|
||||
"path": "org/gradle/api/Project.java",
|
||||
"gradleSource": true
|
||||
}
|
||||
```
|
||||
|
||||
For large files, use `pagination`:
|
||||
|
||||
```json
|
||||
{
|
||||
"path": "org/gradle/api/Project.java",
|
||||
"gradleSource": true,
|
||||
"pagination": {
|
||||
"offset": 0,
|
||||
"limit": 100
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Researching Plugin Source Code
|
||||
|
||||
Plugin (buildscript) dependencies are excluded by default. Use `sourceSetPath=":buildscript"` to include them:
|
||||
|
||||
### Searching Plugin Classes
|
||||
|
||||
```json
|
||||
{
|
||||
"query": "KotlinPlugin",
|
||||
"searchType": "DECLARATION",
|
||||
"sourceSetPath": ":buildscript"
|
||||
}
|
||||
```
|
||||
|
||||
### Reading Plugin Source
|
||||
|
||||
```json
|
||||
{
|
||||
"path": "org.jetbrains.kotlin/kotlin-gradle-plugin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt",
|
||||
"sourceSetPath": ":buildscript"
|
||||
}
|
||||
```
|
||||
|
||||
## Tracing Symbols Across Scopes
|
||||
|
||||
When encountering an unknown Gradle API or plugin class:
|
||||
|
||||
1. Search with `gradleSource: true` for engine classes.
|
||||
2. Search with `sourceSetPath=":buildscript"` for plugin classes.
|
||||
3. Read the implementation with `read_dependency_sources`.
|
||||
4. Cross-reference with official documentation via `gradle_docs` (see `gradle` skill).
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **Source Not Found**: Some Gradle internal modules may not be fully indexed. Try a broader `FULL_TEXT` search or browse the directory structure via `read_dependency_sources` with `gradleSource: true`.
|
||||
- **Plugin Not Found**: Ensure the plugin is resolved in the buildscript classpath. Use `inspect_dependencies(sourceSetPath=":buildscript")` to verify.
|
||||
- **Index Error**: Use `fresh: true` if searching after dependency changes.
|
||||
@ -1,345 +0,0 @@
|
||||
---
|
||||
name: gradle
|
||||
description: >
|
||||
Provides authoritative guidance for ALL Gradle operations: executing builds, running tests with surgical filtering, introspecting project structure, creating modules, and diagnosing failures;
|
||||
ALWAYS use instead of raw shell `./gradlew` for build execution, test runs, task introspection, module creation, performance audits, and documentation research.
|
||||
Do NOT use for dependency graph auditing/updates (use `managing_gradle_dependencies`) or dependency/plugin/Gradle source exploration (use `exploring_dependency_sources`).
|
||||
license: Apache-2.0
|
||||
metadata:
|
||||
author: https://github.com/rnett/gradle-mcp
|
||||
version: "4.0"
|
||||
---
|
||||
|
||||
# Authoritative Gradle Build Execution, Testing & Project Introspection
|
||||
|
||||
Executes builds, runs tests with high-precision filtering, introspects project structure, and diagnoses failures using managed orchestration and structured diagnostics.
|
||||
|
||||
## Constitution
|
||||
|
||||
- **ALWAYS** use the `gradle` tool instead of `./gradlew` via shell.
|
||||
- **ALWAYS** provide absolute paths for `projectRoot`.
|
||||
- **ALWAYS** prefer foreground execution (default) unless the task is persistent (e.g., servers) or extremely long-running (>2 minutes), or you explicitly intend to perform independent research while it proceeds.
|
||||
- **ALWAYS** use `captureTaskOutput` when you need the isolated output of a specific task (e.g., `help`, `projects`, `tasks`, `properties`, `dependencies`).
|
||||
- **STRONGLY PREFERRED**: Use `query_build` for all diagnostics. It is more token-efficient than reading raw console logs and provides structured access to failures, problems, and per-test output.
|
||||
- **ALWAYS** use `query_build` with `kind="TESTS"` and `query="FullTestName"` to access full test output and stack traces.
|
||||
- **NEVER** use `taskPath` or `captureTaskOutput` to investigate specific test failures; these provide the overall task log which is often truncated and lacks per-test isolation. Per-test output (via `query`) is authoritative and includes
|
||||
full stack traces.
|
||||
- **NEVER** use `--rerun-tasks` unless investigating project-wide cache-specific corruption; prefer `--rerun` for individual tasks.
|
||||
- **NEVER** guess task names or options; use the `help --task <name>` command for authoritative documentation.
|
||||
- **NEVER** leave background builds running; use `stopBuildId` to release resources when finished.
|
||||
- **ALWAYS** prefer Kotlin DSL (`.kts`) unless the project explicitly uses Groovy.
|
||||
- **ALWAYS** use lazy APIs (e.g., `tasks.register<MyTask>("myTask")`) instead of eager APIs (e.g., `tasks.create<MyTask>("myTask")`) to maintain configuration performance.
|
||||
- **ALWAYS** use version catalogs (`libs.versions.toml`) for dependency management when present.
|
||||
- **ALWAYS** use `gradle_docs` for authoritative documentation lookup instead of generic web searches.
|
||||
- **ALWAYS** check for existing conventions in the current project before proposing changes.
|
||||
- **ALWAYS** use safe navigation (`?.url?.toString()`) and provide fallback values when accessing `ArtifactRepository` URLs in Gradle init scripts or plugins to prevent `NullPointerException`.
|
||||
- **ALWAYS** use `:properties --property <name>` for surgical property extraction.
|
||||
|
||||
## Directives
|
||||
|
||||
### Authoritative Task Path Syntax
|
||||
|
||||
Gradle uses two ways to identify tasks from the command line. Precision prevents running redundant tasks in multi-project builds.
|
||||
|
||||
#### Task Selectors (Recursive Execution)
|
||||
|
||||
Providing a task name **without a leading colon** (e.g., `test`, `build`) acts as a selector. Gradle executes that task in **every project** (root and all subprojects) that contains a task with that name.
|
||||
|
||||
- **Example**: `gradle(commandLine=["test"])` -> Executes `test` in **all** projects.
|
||||
|
||||
#### Absolute Task Paths (Targeted Execution)
|
||||
|
||||
Providing a task path **with a leading colon** (e.g., `:test`, `:app:test`) targets a **single specific project**.
|
||||
|
||||
- **Root Project Only**: Use a single leading colon. `gradle(commandLine=[":test"])` -> Root project ONLY.
|
||||
- **Subproject Only**: Use the subproject name(s) separated by colons. `gradle(commandLine=[":app:test"])` -> ':app' subproject ONLY.
|
||||
|
||||
### Authoritative Test Selection (`--tests`)
|
||||
|
||||
The `--tests` flag supports powerful, high-precision filtering:
|
||||
|
||||
- **Exact Class**: `--tests com.example.MyTest`
|
||||
- **Exact Method**: `--tests com.example.MyTest.myTestMethod`
|
||||
- **Wildcard Method**: `--tests com.example.MyTest.test*` (All methods starting with 'test')
|
||||
- **Package Filter**: `--tests com.example.service.*` (All tests in the 'service' package)
|
||||
- **Class Prefix**: `--tests *IntegrationTest` (All classes ending in 'IntegrationTest')
|
||||
- **Character Wildcard**: `--tests com.example.Test?` (Matches Test1, TestA, etc.)
|
||||
- **Multi-Filter**: `gradle(commandLine=["test", "--tests", "ClassA", "--tests", "ClassB"])`
|
||||
|
||||
Patterns match against the **fully qualified name** of the test class or method.
|
||||
|
||||
### Foreground vs. Background Execution
|
||||
|
||||
- **ALWAYS use foreground for authoritative runs**: If you intend to wait for a result, ALWAYS use foreground execution. It provides superior progressive disclosure and simpler control flow.
|
||||
- **Background ONLY for persistent tasks**: Use `background: true` ONLY for tasks that must remain active (e.g., `bootRun`, continuous builds) or when you intentionally intend to perform independent research while the build proceeds.
|
||||
- **Foreground is safe**: Do not fear running high-output suites in the foreground. The `gradle` tool uses progressive disclosure to provide concise summaries and structured results, keeping session history clean.
|
||||
|
||||
### `captureTaskOutput` Usage
|
||||
|
||||
Use `captureTaskOutput` when you need clean, isolated output from a specific task without Gradle's general console noise. This is ideal for introspection tasks:
|
||||
|
||||
- `captureTaskOutput: ":projects"` - Clean project list
|
||||
- `captureTaskOutput: ":app:tasks"` - Task list for a specific project
|
||||
- `captureTaskOutput: ":help"` - Documentation for a specific task
|
||||
- `captureTaskOutput: ":properties"` - Single property extraction
|
||||
- `captureTaskOutput: ":app:dependencyInsight"` - Dependency resolution path
|
||||
|
||||
### `gradle_docs` Tag Syntax
|
||||
|
||||
Use `gradle_docs` for authoritative documentation. Always scope with tags:
|
||||
|
||||
| Tag | Section |
|
||||
|----------------------|----------------------------------------------------|
|
||||
| `tag:userguide` | Official Gradle User Guide |
|
||||
| `tag:dsl` | Gradle DSL Reference (Groovy and Kotlin DSL) |
|
||||
| `tag:javadoc` | Gradle Java API Reference |
|
||||
| `tag:samples` | Official Gradle samples and examples |
|
||||
| `tag:release-notes` | Version-specific release insights |
|
||||
| `tag:best-practices` | Official best practices and performance guidelines |
|
||||
|
||||
Explore sections with `path="."`. Search scoped with `tag:<section> <term>`.
|
||||
|
||||
### Idiomatic DSL Patterns
|
||||
|
||||
- **Prefer `register` over `create` (Lazy APIs)**: Use `tasks.register<MyTask>("myTask")` to avoid eager task configuration.
|
||||
- **Use Type-Safe Accessors**: Prefer `tasks.test { ... }` or `tasks.named<Test>("test") { ... }` over `tasks.getByName("test")`.
|
||||
- **Use Lazy Properties**: Employ `Property<T>` and `Provider<T>` APIs for late binding and configuration cache compatibility.
|
||||
- **Use Version Catalogs**: Centralize dependencies in `gradle/libs.versions.toml`.
|
||||
- **Avoid `allprojects`/`subprojects`**: These blocks create tight coupling; use convention plugins and apply them selectively.
|
||||
- **Enable Configuration Cache**: Ensure build logic avoids accessing the `Project` object inside task actions.
|
||||
- **Use Specific Annotations**: Properly label task properties with `@Input`, `@OutputFiles`, `@Internal`, etc.
|
||||
- **Minimize Logic in Build Scripts**: Move complex logic into convention plugins or `build-logic`.
|
||||
|
||||
### Resource Management
|
||||
|
||||
- Use `query_build()` without arguments to view the build dashboard and ensure no orphaned background builds are consuming system resources.
|
||||
- Set `invocationArguments: { envSource: "SHELL" }` if Gradle cannot find expected env vars (e.g., `JAVA_HOME`).
|
||||
|
||||
### Diagnostic Inspection (See References)
|
||||
|
||||
For comprehensive guidance on using `query_build` and `wait_build` for diagnostics, including JSON examples for every inspection mode (DASHBOARD, SUMMARY, FAILURES, PROBLEMS, TASKS, TESTS, CONSOLE, PROGRESS), refer
|
||||
to: [query_build Diagnostics Reference](references/query_build_diagnostics.md).
|
||||
|
||||
## Workflows
|
||||
|
||||
### Running a Foreground Build
|
||||
|
||||
1. Identify the task(s) to run (e.g., `["clean", "build"]`).
|
||||
2. Call `gradle(commandLine=["...", "..."])`.
|
||||
3. If the build fails, the tool returns a high-signal failure summary. Use `query_build` with the `buildId` for deeper diagnostics via [query_build Diagnostics Reference](references/query_build_diagnostics.md).
|
||||
|
||||
### Running Specific Tests
|
||||
|
||||
1. Identify the project path (e.g., `:app`) and the test filter (e.g., `com.example.MyTestClass*`).
|
||||
2. Call `gradle(commandLine=[":app:test", "--tests", "com.example.MyTest"])`.
|
||||
3. If failures are reported, use `query_build` to get detailed test output.
|
||||
|
||||
### Orchestrating Background Jobs
|
||||
|
||||
1. Start the build with `background: true` to receive a `BuildId`.
|
||||
2. Use `wait_build(buildId=ID, timeout=..., waitFor=...)` to block until a specific state or log pattern is reached.
|
||||
3. Use `query_build()` (no arguments) to manage active jobs in the dashboard.
|
||||
4. Stop the job using `gradle(stopBuildId=ID)` when finished.
|
||||
|
||||
### Introspecting Project Structure
|
||||
|
||||
1. Run `gradle(commandLine=[":projects"], captureTaskOutput=":projects")` to map the multi-project hierarchy.
|
||||
2. Run `gradle(commandLine=[":app:tasks", "--all"], captureTaskOutput=":app:tasks")` to discover runnable tasks.
|
||||
3. Run `gradle(commandLine=[":help", "--task", "test"], captureTaskOutput=":help")` for task-specific documentation.
|
||||
4. Run `gradle(commandLine=[":properties", "--property", "version"], captureTaskOutput=":properties")` for surgical property extraction.
|
||||
5. For detailed dependency resolution paths: `gradle(commandLine=[":app:dependencyInsight", "--dependency", "slf4j-api", "--configuration", "compileClasspath"], captureTaskOutput=":app:dependencyInsight")`.
|
||||
|
||||
### Creating a New Module
|
||||
|
||||
1. Map the project structure: `gradle(commandLine=[":projects"], captureTaskOutput=":projects")` to find the correct parent path.
|
||||
2. Create directory structure: `New-Item -ItemType Directory -Force -Path "<module-name>/src/main/kotlin"`.
|
||||
3. Add to `settings.gradle.kts`: Append `include(":<module-name>")`.
|
||||
4. Create `build.gradle.kts` with idiomatic patterns (apply convention plugins, set up standard configuration).
|
||||
5. Verify: `gradle(commandLine=[":<module-name>:tasks"], captureTaskOutput=":<module-name>:tasks")`.
|
||||
|
||||
### Performance Audit
|
||||
|
||||
1. Check configuration cache status: `gradle(commandLine=[":help", "--configuration-cache"])`.
|
||||
2. Analyze task compatibility and identify violations.
|
||||
3. Propose fixes: migrate to lazy APIs (`Property<T>`, `Provider<T>`) or use `@Internal`/`@Input` annotations correctly.
|
||||
4. Verify against latest guidance: `gradle_docs(query="tag:best-practices", projectRoot="/path/to/project")`.
|
||||
|
||||
### Documentation Research
|
||||
|
||||
1. Search the user guide: `gradle_docs(query="tag:userguide <term>", projectRoot="/path/to/project")`.
|
||||
2. Navigate the DSL reference: `gradle_docs(path="dsl/org.gradle.api.Project.html", projectRoot="/path/to/project")`.
|
||||
3. Check for breaking changes: `gradle_docs(query="tag:release-notes", version="8.6")`.
|
||||
4. Find best practices: `gradle_docs(query="tag:best-practices dependency management", projectRoot="/path/to/project")`.
|
||||
5. Search for samples: `gradle_docs(query="tag:samples toolchains", projectRoot="/path/to/project")`.
|
||||
6. Search javadocs: `gradle_docs(query="tag:javadoc Project", projectRoot="/path/to/project")`.
|
||||
|
||||
### Investigating Test Failures
|
||||
|
||||
1. Identify the `BuildId` from the build result.
|
||||
2. Use `query_build(buildId=ID, kind="TESTS", outcome="FAILED")` to list all failed tests.
|
||||
3. Use `query_build(buildId=ID, kind="TESTS", query=TNAME)` to see the full output and stack trace for a specific test.
|
||||
4. **DO NOT** use `taskPath` or `captureTaskOutput` for test failure investigation.
|
||||
|
||||
## When to Use
|
||||
|
||||
- **Core Lifecycle Execution**: When you need to execute standard Gradle tasks (`build`, `assemble`, `clean`) with reliable, parseable output.
|
||||
- **Test Execution & Diagnostics**: When running tests with `--tests` filtering, isolating failures, or retrieving full stack traces.
|
||||
- **Introspection & Mapping**: When mapping multi-module project hierarchies, discovering runnable tasks, or auditing build configuration.
|
||||
- **Surgical Property Inspection**: When extracting a specific property value (artifact version, build directory) for use in a subsequent task.
|
||||
- **Persistent Development Processes**: When starting dev servers (`bootRun`) or continuous builds where background management is required.
|
||||
- **Task-Specific Information Retrieval**: When you need isolated output from a single task (`help`, `projects`, `tasks`) without build noise.
|
||||
- **Build Failure Diagnostics**: When performing deep-dive analysis of task failures, problems, or compilation errors.
|
||||
- **New Module Creation**: When adding a new project or module to a multi-project build.
|
||||
- **Build Logic Refactoring**: When cleaning up complex build scripts or creating convention plugins.
|
||||
- **Performance Troubleshooting**: When builds are slow or failing during the configuration phase.
|
||||
- **Documentation & DSL Research**: When looking up official Gradle syntax, user guide topics, or release notes.
|
||||
|
||||
## Examples
|
||||
|
||||
### Run build in all projects
|
||||
|
||||
Tool: `gradle`
|
||||
|
||||
```json
|
||||
{
|
||||
"commandLine": ["build"]
|
||||
}
|
||||
// Reasoning: Task selector (no colon) verifies build health across the entire multi-project structure.
|
||||
```
|
||||
|
||||
### Run a single test class in a specific subproject
|
||||
|
||||
Tool: `gradle`
|
||||
|
||||
```json
|
||||
{
|
||||
"commandLine": [":app:test", "--tests", "com.example.service.MyServiceTest"]
|
||||
}
|
||||
// Reasoning: Absolute task path with exact class filter for the fastest possible feedback loop.
|
||||
```
|
||||
|
||||
### Inspect help output for a specific task
|
||||
|
||||
Tool: `gradle`
|
||||
|
||||
```json
|
||||
{
|
||||
"commandLine": [":app:help", "--task", "test"],
|
||||
"captureTaskOutput": ":app:help"
|
||||
}
|
||||
// Reasoning: Using captureTaskOutput to retrieve clean, isolated documentation.
|
||||
```
|
||||
|
||||
### List all sub-projects in the build
|
||||
|
||||
Tool: `gradle`
|
||||
|
||||
```json
|
||||
{
|
||||
"commandLine": [":projects"],
|
||||
"captureTaskOutput": ":projects"
|
||||
}
|
||||
// Reasoning: Using captureTaskOutput to retrieve the project hierarchy list without startup noise.
|
||||
```
|
||||
|
||||
### Surgically inspect the 'version' property
|
||||
|
||||
Tool: `gradle`
|
||||
|
||||
```json
|
||||
{
|
||||
"commandLine": [":properties", "--property", "version"],
|
||||
"captureTaskOutput": ":properties"
|
||||
}
|
||||
// Reasoning: Using --property to isolate a single value and avoid retrieving thousands of unrelated properties.
|
||||
```
|
||||
|
||||
### Analyze a specific dependency conflict
|
||||
|
||||
Tool: `gradle`
|
||||
|
||||
```json
|
||||
{
|
||||
"commandLine": [
|
||||
":app:dependencyInsight",
|
||||
"--dependency",
|
||||
"com.google.guava:guava",
|
||||
"--configuration",
|
||||
"runtimeClasspath"
|
||||
],
|
||||
"captureTaskOutput": ":app:dependencyInsight"
|
||||
}
|
||||
// Reasoning: Using dependencyInsight to isolate the resolution path for a specific artifact.
|
||||
```
|
||||
|
||||
### Start a dev server and wait for readiness
|
||||
|
||||
Tool: `gradle`
|
||||
|
||||
```json
|
||||
// Step 1: Start the server in the background
|
||||
{
|
||||
"commandLine": [":app:bootRun"],
|
||||
"background": true
|
||||
}
|
||||
// Response: { "buildId": "build_123" }
|
||||
|
||||
// Step 2: Wait for readiness signal
|
||||
{
|
||||
"buildId": "build_123",
|
||||
"timeout": 60,
|
||||
"waitFor": "Started Application"
|
||||
}
|
||||
// Reasoning: Background orchestration allows the server to remain active while waiting for readiness.
|
||||
```
|
||||
|
||||
### Search official Gradle documentation
|
||||
|
||||
Tool: `gradle_docs`
|
||||
|
||||
```json
|
||||
{
|
||||
"query": "tag:dsl signing plugin",
|
||||
"projectRoot": "/absolute/path/to/project"
|
||||
}
|
||||
// Reasoning: Using the DSL tag to find authoritative syntax for the signing plugin configuration.
|
||||
```
|
||||
|
||||
### Create a new sub-project module
|
||||
|
||||
Tool: `run_shell_command`
|
||||
|
||||
```json
|
||||
{
|
||||
"command": "New-Item -ItemType Directory -Force -Path subproject/src/main/kotlin"
|
||||
}
|
||||
// Reasoning: Creating the standard directory structure for a Kotlin JVM project using correct PowerShell syntax.
|
||||
```
|
||||
|
||||
### List all failed tests in a build
|
||||
|
||||
Tool: `query_build`
|
||||
|
||||
```json
|
||||
{
|
||||
"buildId": "build_abc123",
|
||||
"kind": "TESTS",
|
||||
"outcome": "FAILED"
|
||||
}
|
||||
// Reasoning: Isolating only the failures from a large test suite for efficient triage.
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **Build Not Found**: If a `BuildId` is not recognized, it may have expired from the recent history cache. Check the dashboard (`query_build()`) for valid active and historical IDs.
|
||||
- **Task Output Not Captured**: Ensure the path provided to `captureTaskOutput` matches exactly one of the tasks in the `commandLine`.
|
||||
- **Missing environment variables**: Set `invocationArguments: { envSource: "SHELL" }` if Gradle cannot find expected env vars (e.g., `JAVA_HOME`).
|
||||
|
||||
## Resources
|
||||
|
||||
- [query_build Diagnostics Reference](references/query_build_diagnostics.md) — Complete diagnostic patterns for DASHBOARD, SUMMARY, FAILURES, PROBLEMS, TASKS, TESTS, CONSOLE, and PROGRESS.
|
||||
- [Background Monitoring Patterns](references/background_monitoring.md)
|
||||
- [Authoritative Diagnostic Tasks](references/diagnostic_tasks.md) — Built-in introspection tasks.
|
||||
- [Best Practices Snapshot](references/best_practices.md) — High-level best practices; always verify with `gradle_docs`.
|
||||
- [Common Build Patterns](references/common_build_patterns.md) — Idiomatic patterns for multi-project builds, convention plugins, and task registration.
|
||||
- [Official Gradle Documentation Research](references/gradle_docs_research.md) — Guidance on using `gradle_docs` for authoritative documentation.
|
||||
@ -1,105 +0,0 @@
|
||||
# Background Monitoring Patterns
|
||||
|
||||
This guide provides advanced patterns for monitoring and managing long-running background builds using `gradle`, `query_build`, and `wait_build`.
|
||||
|
||||
## Common Monitoring Patterns
|
||||
|
||||
### 1. Waiting for a Log Message
|
||||
|
||||
The most common pattern for background builds (like dev servers) is to wait for a specific log message that indicates the build is ready using `wait_build`.
|
||||
|
||||
```json
|
||||
{
|
||||
"buildId": "BUILD_ID",
|
||||
"timeout": 60,
|
||||
"waitFor": "Started Application"
|
||||
}
|
||||
```
|
||||
|
||||
- **`timeout`**: Max seconds to wait for the message.
|
||||
- **`waitFor`**: A regex pattern to match in the build logs.
|
||||
|
||||
### 2. Waiting for Task Completion
|
||||
|
||||
If you want to wait for a specific task to finish in a background build.
|
||||
|
||||
```json
|
||||
{
|
||||
"buildId": "BUILD_ID",
|
||||
"timeout": 120,
|
||||
"waitForTask": ":app:assemble"
|
||||
}
|
||||
```
|
||||
|
||||
- **`waitForTask`**: The path of the task to wait for.
|
||||
|
||||
### 3. Monitoring Progress Without Waiting
|
||||
|
||||
To check the current status of a background build without waiting for a specific event using `query_build`.
|
||||
|
||||
```json
|
||||
{
|
||||
"buildId": "BUILD_ID"
|
||||
}
|
||||
```
|
||||
|
||||
- This returns a summary of the current build state (e.g., `BUILD IN PROGRESS`, `SUCCESS`, `FAILURE`), failures, and problems.
|
||||
- **Example**: `query_build(buildId="ID")`
|
||||
|
||||
### 4. Inspecting Active Builds (Build Dashboard)
|
||||
|
||||
To see all currently running background builds and recent history.
|
||||
|
||||
```json
|
||||
{}
|
||||
```
|
||||
|
||||
- Call `query_build()` with **no arguments** to see the dashboard.
|
||||
- This is the easiest way to find `BuildId`s for active or recently finished builds.
|
||||
|
||||
## Advanced Management
|
||||
|
||||
### 1. Stopping a Background Build
|
||||
|
||||
Always stop background builds when they are no longer needed to free up resources.
|
||||
|
||||
```json
|
||||
{
|
||||
"stopBuildId": "BUILD_ID"
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Continuous Builds
|
||||
|
||||
For continuous builds (e.g., `gradle build --continuous`), use the background pattern and wait for the "Waiting for changes" message.
|
||||
|
||||
```json
|
||||
// Start the build
|
||||
{
|
||||
"commandLine": ["build", "--continuous"],
|
||||
"background": true
|
||||
}
|
||||
|
||||
// Wait for the first build to finish
|
||||
{
|
||||
"buildId": "BUILD_ID",
|
||||
"timeout": 120,
|
||||
"waitFor": "Waiting for changes"
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Handling Timeouts
|
||||
|
||||
If a build takes longer than the `timeout` time, `wait_build` will return the current status. You can then call it again with a new `timeout` time if needed.
|
||||
|
||||
## Troubleshooting Background Builds
|
||||
|
||||
- **Build Fails Immediately**: If a background build fails quickly, check the `failures` and `console` output using `query_build`.
|
||||
- **Log Message Not Found**: Ensure the `waitFor` regex is correct and that the message is actually being printed to the console.
|
||||
- **Resource Exhaustion**: If you have too many background builds running, stop the ones you don't need using `stopBuildId`.
|
||||
|
||||
## Functional Identity with Foreground Execution
|
||||
|
||||
Monitoring a background build using `query_build` or `wait_build` provides exactly the same rich diagnostic data as a foreground build. The primary difference is control flow: background execution allows you to yield control and perform
|
||||
other tasks,
|
||||
whereas foreground execution blocks until completion. Both methods utilize progressive disclosure to ensure session history remains clean and focused.
|
||||
@ -1,109 +0,0 @@
|
||||
# Gradle Build Logic Best Practices
|
||||
|
||||
**IMPORTANT**: This document provides a high-level snapshot of common best practices. However, Gradle is a rapidly evolving tool. **You MUST use the `gradle_docs` tool to retrieve the most up-to-date and comprehensive best practices
|
||||
directly from the official documentation.**
|
||||
|
||||
## 1. Authoritative Research Workflow
|
||||
|
||||
Before implementing significant build logic, always perform a search for the latest recommendations using scoped queries and project context.
|
||||
|
||||
### Example: Getting an Index of Best Practices
|
||||
|
||||
To find the authoritative index of best practices within the User Guide, first explore the `userguide/` directory to identify the correct files.
|
||||
|
||||
Tool: `gradle_docs`
|
||||
|
||||
```json
|
||||
{
|
||||
"path": "userguide/",
|
||||
"projectRoot": "/absolute/path/to/project"
|
||||
}
|
||||
```
|
||||
|
||||
**Reasoning**: This call lists the contents of the `userguide` directory. Look for files starting with `best_practices` (e.g., `best_practices.md`, `best_practices_dependency_management.md`). Once identified, read the main index:
|
||||
|
||||
Tool: `gradle_docs`
|
||||
|
||||
```json
|
||||
{
|
||||
"path": "userguide/best_practices.md",
|
||||
"projectRoot": "/absolute/path/to/project"
|
||||
}
|
||||
```
|
||||
|
||||
### Example: Searching for Best Practices
|
||||
|
||||
Tool: `gradle_docs`
|
||||
|
||||
```json
|
||||
{
|
||||
"query": "tag:best-practices dependency management",
|
||||
"projectRoot": "/absolute/path/to/project"
|
||||
}
|
||||
```
|
||||
|
||||
**Reasoning**: Using the authoritative `best-practices` tag ensures the returned content is filtered for high-signal architectural recommendations.
|
||||
|
||||
### Example: Searching for Specific Guidance
|
||||
|
||||
Tool: `gradle_docs`
|
||||
|
||||
```json
|
||||
{
|
||||
"query": "tag:userguide performance best practices",
|
||||
"projectRoot": "/absolute/path/to/project"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Engine-Level Discovery (The "Source of Truth")
|
||||
|
||||
To understand the core architectural principles behind best practices, you can explore Gradle's own source documentation.
|
||||
|
||||
### Example: Listing Core Concepts and Documentation
|
||||
|
||||
Use `gradle_docs` with `path="."` to explore the root documentation tree.
|
||||
|
||||
Tool: `gradle_docs`
|
||||
|
||||
```json
|
||||
{
|
||||
"path": ".",
|
||||
"projectRoot": "/absolute/path/to/project"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. High-Level Snapshot (Current Guidelines)
|
||||
|
||||
The following sections summarize established idiomatic patterns. Use these as a starting point, but verify against the official docs.
|
||||
|
||||
### Kotlin DSL Idiomatic Patterns
|
||||
|
||||
- **Use Type-Safe Accessors**: Prefer `tasks.test { ... }` or `tasks.named<Test>("test") { ... }` over `tasks.getByName("test")`.
|
||||
- **Prefer `register` over `create` (Lazy APIs)**: Use `tasks.register<MyTask>("myTask")` to avoid eager task configuration.
|
||||
- **Use Lazy Properties**: Employ the `Property<T>` and `Provider<T>` APIs for late binding and better configuration cache compatibility.
|
||||
|
||||
### Performance & Configuration Cache
|
||||
|
||||
- **Enable Configuration Cache**: Ensure build logic avoids accessing the `Project` object inside task actions.
|
||||
- **Use Specific Annotations**: Properly label task properties with `@Input`, `@OutputFiles`, `@Internal`, etc.
|
||||
- **Minimize Logic in Build Scripts**: Move complex logic into convention plugins or `buildSrc`.
|
||||
|
||||
### Dependency Management
|
||||
|
||||
- **Use Version Catalogs**: Centralize dependencies in `gradle/libs.versions.toml`.
|
||||
- **Avoid `allprojects` and `subprojects`**: These blocks create tight coupling; use convention plugins and apply them selectively instead.
|
||||
|
||||
### Project Integrity
|
||||
|
||||
- **Reproducible Builds**: Use fixed versions and commit the Gradle wrapper.
|
||||
- **Surgical Updates**: Only update what is necessary and verify with `check`.
|
||||
|
||||
## Resources (Official Source of Truth)
|
||||
|
||||
- [Official Gradle Best Practices](https://docs.gradle.org/current/userguide/best_practices.html)
|
||||
- [Gradle Performance Guide](https://docs.gradle.org/current/userguide/performance.html)
|
||||
- [Kotlin DSL Primer](https://docs.gradle.org/current/userguide/kotlin_dsl.html)
|
||||
@ -1,142 +0,0 @@
|
||||
# Common Gradle Build Patterns & Conventions
|
||||
|
||||
A collection of idiomatic patterns for common Gradle build scenarios, including multi-project setups, convention plugins, and task registration.
|
||||
|
||||
## 1. Multi-Project Build Structure
|
||||
|
||||
Standard project structure with a root project and multiple subprojects.
|
||||
|
||||
### Directory Structure
|
||||
|
||||
```
|
||||
root/
|
||||
├── build.gradle.kts
|
||||
├── settings.gradle.kts
|
||||
├── libs.versions.toml
|
||||
├── app/
|
||||
│ └── build.gradle.kts
|
||||
├── core/
|
||||
│ └── build.gradle.kts
|
||||
└── build-logic/
|
||||
├── build.gradle.kts
|
||||
└── settings.gradle.kts
|
||||
```
|
||||
|
||||
### `settings.gradle.kts`
|
||||
|
||||
```kotlin
|
||||
pluginManagement {
|
||||
includeBuild("build-logic")
|
||||
}
|
||||
|
||||
rootProject.name = "my-project"
|
||||
include(":app", ":core")
|
||||
|
||||
dependencyResolutionManagement {
|
||||
versionCatalogs {
|
||||
create("libs") {
|
||||
from(files("gradle/libs.versions.toml"))
|
||||
}
|
||||
}
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 2. Convention Plugins (The `build-logic` Pattern)
|
||||
|
||||
Move common project configuration logic into separate plugins to reduce duplication in `build.gradle.kts` files.
|
||||
|
||||
### `build-logic/build.gradle.kts`
|
||||
|
||||
```kotlin
|
||||
plugins {
|
||||
`kotlin-dsl`
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.0")
|
||||
}
|
||||
```
|
||||
|
||||
### `build-logic/src/main/kotlin/my-convention.gradle.kts`
|
||||
|
||||
```kotlin
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile>().configureEach {
|
||||
compilerOptions {
|
||||
jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Usage in Subprojects
|
||||
|
||||
```kotlin
|
||||
plugins {
|
||||
id("my-convention")
|
||||
}
|
||||
```
|
||||
|
||||
## 3. Registering Custom Tasks
|
||||
|
||||
Use lazy task registration and configure properties with the `Property` and `Provider` APIs.
|
||||
|
||||
```kotlin
|
||||
abstract class MyCustomTask : DefaultTask() {
|
||||
@get:Input
|
||||
abstract val message: Property<String>
|
||||
|
||||
@TaskAction
|
||||
fun action() {
|
||||
println("Message: ${message.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
tasks.register<MyCustomTask>("myTask") {
|
||||
message.set("Hello from custom task!")
|
||||
}
|
||||
```
|
||||
|
||||
## 4. Configuring Standard Plugins
|
||||
|
||||
### Java/Kotlin Library
|
||||
|
||||
```kotlin
|
||||
plugins {
|
||||
`java-library`
|
||||
kotlin("jvm")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api("com.example:some-api:1.0")
|
||||
implementation("com.example:some-impl:1.0")
|
||||
testImplementation(kotlin("test"))
|
||||
}
|
||||
```
|
||||
|
||||
### Application Plugin
|
||||
|
||||
```kotlin
|
||||
plugins {
|
||||
application
|
||||
}
|
||||
|
||||
application {
|
||||
mainClass.set("com.example.Main")
|
||||
}
|
||||
```
|
||||
|
||||
## Resources
|
||||
|
||||
- [Multi-project builds](https://docs.gradle.org/current/userguide/multi_project_builds.html)
|
||||
- [Developing Custom Gradle Plugins](https://docs.gradle.org/current/userguide/custom_plugins.html)
|
||||
- [Authoring maintainable builds](https://docs.gradle.org/current/userguide/authoring_maintainable_builds.html)
|
||||
@ -1,27 +0,0 @@
|
||||
# Authoritative Diagnostic Tasks
|
||||
|
||||
Gradle provides built-in tasks for deep introspection. Always use `captureTaskOutput` with these for the best experience.
|
||||
|
||||
### 1. Project & Task Discovery
|
||||
|
||||
- **`projects`**: Lists the sub-projects in the build.
|
||||
- `gradle(commandLine=[":projects"], captureTaskOutput=":projects")`
|
||||
- **`tasks`**: Lists runnable tasks. Use `--all` for a full list (including ungrouped tasks).
|
||||
- `gradle(commandLine=[":app:tasks", "--all"], captureTaskOutput=":app:tasks")`
|
||||
- **`help`**: Displays global or task-specific help.
|
||||
- `gradle(commandLine=[":help", "--task", "test"], captureTaskOutput=":help")`
|
||||
|
||||
### 2. Property & Environment Auditing
|
||||
|
||||
- **`properties`**: Lists all project properties. Use `--property <name>` for surgical extraction.
|
||||
- `gradle(commandLine=[":properties", "--property", "version"], captureTaskOutput=":properties")`
|
||||
- **`javaToolchains`**: Displays detected JVM toolchains and their properties.
|
||||
- `gradle(commandLine=[":javaToolchains"], captureTaskOutput=":javaToolchains")`
|
||||
|
||||
### 3. Low-Level Dependency & Variant Analysis
|
||||
|
||||
- **`dependencyInsight`**: Investigates why a specific dependency version was chosen.
|
||||
- `gradle(commandLine=[":app:dependencyInsight", "--dependency", "slf4j-api", "--configuration", "compileClasspath"], captureTaskOutput=":app:dependencyInsight")`
|
||||
- **`outgoingVariants`**: Displays the variants the project provides to consumers.
|
||||
- `gradle(commandLine=[":app:outgoingVariants"], captureTaskOutput=":app:outgoingVariants")`
|
||||
- **`resolvableConfigurations`**: Displays the configurations available for resolution.
|
||||
@ -1,100 +0,0 @@
|
||||
# Official Gradle Documentation Research
|
||||
|
||||
Guidance on using the `gradle_docs` tool for authoritative documentation lookup, including the User Guide, DSL Reference, Release Notes, samples, and API reference.
|
||||
|
||||
## Searching the User Guide
|
||||
|
||||
```json
|
||||
{
|
||||
"query": "tag:userguide working with files",
|
||||
"projectRoot": "/absolute/path/to/project"
|
||||
}
|
||||
```
|
||||
|
||||
## Navigating the DSL Reference
|
||||
|
||||
```json
|
||||
{
|
||||
"path": "dsl/org.gradle.api.Project.html",
|
||||
"projectRoot": "/absolute/path/to/project"
|
||||
}
|
||||
```
|
||||
|
||||
## Searching for Samples
|
||||
|
||||
Official code samples are indexed with the `tag:samples` metadata:
|
||||
|
||||
```json
|
||||
{
|
||||
"query": "tag:samples toolchains",
|
||||
"projectRoot": "/absolute/path/to/project"
|
||||
}
|
||||
```
|
||||
|
||||
## Searching Javadocs
|
||||
|
||||
Technical API documentation is indexed with the `tag:javadoc` metadata:
|
||||
|
||||
```json
|
||||
{
|
||||
"query": "tag:javadoc Project",
|
||||
"projectRoot": "/absolute/path/to/project"
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Getting an Index of Best Practices
|
||||
|
||||
First, explore the `userguide/` directory to identify the correct files:
|
||||
|
||||
```json
|
||||
{
|
||||
"path": "userguide/",
|
||||
"projectRoot": "/absolute/path/to/project"
|
||||
}
|
||||
```
|
||||
|
||||
This lists the contents of the `userguide` directory. Look for files starting with `best_practices` (e.g., `best_practices.md`, `best_practices_dependency_management.md`). Once identified, read the main index:
|
||||
|
||||
```json
|
||||
{
|
||||
"path": "userguide/best_practices.md",
|
||||
"projectRoot": "/absolute/path/to/project"
|
||||
}
|
||||
```
|
||||
|
||||
### Searching for Best Practices
|
||||
|
||||
```json
|
||||
{
|
||||
"query": "tag:best-practices dependency management",
|
||||
"projectRoot": "/absolute/path/to/project"
|
||||
}
|
||||
```
|
||||
|
||||
### Searching for Specific Guidance
|
||||
|
||||
```json
|
||||
{
|
||||
"query": "tag:userguide performance best practices",
|
||||
"projectRoot": "/absolute/path/to/project"
|
||||
}
|
||||
```
|
||||
|
||||
## Exploring the Documentation Tree
|
||||
|
||||
Use `gradle_docs` with `path="."` to explore the root documentation tree:
|
||||
|
||||
```json
|
||||
{
|
||||
"path": ".",
|
||||
"projectRoot": "/absolute/path/to/project"
|
||||
}
|
||||
```
|
||||
|
||||
## External Resources
|
||||
|
||||
- [Official Gradle Best Practices](https://docs.gradle.org/current/userguide/best_practices.html)
|
||||
- [Gradle Performance Guide](https://docs.gradle.org/current/userguide/performance.html)
|
||||
- [Kotlin DSL Primer](https://docs.gradle.org/current/userguide/kotlin_dsl.html)
|
||||
@ -1,380 +0,0 @@
|
||||
# query_build Diagnostics Reference
|
||||
|
||||
Comprehensive guide to inspecting build results, diagnosing failures, and monitoring progress with `query_build` and `wait_build`.
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| Goal | Tool Call |
|
||||
|--------------------------|--------------------------------------------------------------------------------|
|
||||
| See recent/active builds | `query_build()` |
|
||||
| Build-level summary | `query_build(buildId="ID")` |
|
||||
| Specific failure | `query_build(buildId="ID", kind="FAILURES", query="F0")` |
|
||||
| Specific problem | `query_build(buildId="ID", kind="PROBLEMS", query="P1")` |
|
||||
| Task output | `query_build(buildId="ID", kind="TASKS", query=":app:compileJava")` |
|
||||
| List failed tests | `query_build(buildId="ID", kind="TESTS", outcome="FAILED")` |
|
||||
| Per-test stack trace | `query_build(buildId="ID", kind="TESTS", query="com.example.MyTest.myMethod")` |
|
||||
| Console logs (regex) | `query_build(buildId="ID", kind="CONSOLE", query="ERROR")` |
|
||||
| Full export to file | `query_build(buildId="ID", kind="CONSOLE", outputFile="path/to/logs.txt")` |
|
||||
| Wait for log pattern | `wait_build(buildId="ID", timeout=60, waitFor="Started")` |
|
||||
| Wait for task | `wait_build(buildId="ID", timeout=120, waitForTask=":app:assemble")` |
|
||||
| Wait for finish | `wait_build(buildId="ID", timeout=600)` |
|
||||
|
||||
---
|
||||
|
||||
## 1. Build Dashboard (`query_build()`)
|
||||
|
||||
Call `query_build()` with no arguments to see the **Build Dashboard** — a list of active background builds and recently completed builds with `BuildId`, status, and failure counts. Use this to discover valid `BuildId`s and ensure no
|
||||
orphaned background builds are consuming resources.
|
||||
|
||||
```json
|
||||
{}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Build Summary (`query_build(buildId="ID")`)
|
||||
|
||||
Provide a `buildId` to get a structured summary of that specific build, including:
|
||||
|
||||
- Overall build status (SUCCESS, FAILED, etc.)
|
||||
- Failure IDs and descriptions
|
||||
- Problem IDs and descriptions
|
||||
- Test result counts (passed, failed, skipped, etc.)
|
||||
|
||||
The summary includes a guide on how to inspect specific details using the appropriate `kind`.
|
||||
|
||||
```json
|
||||
{
|
||||
"buildId": "BUILD_ID"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Failure Inspection (`kind="FAILURES"`)
|
||||
|
||||
Inspect a specific build failure to see the full error message and stack trace. Find failure IDs (`F0`, `F1`, etc.) in the build summary. If you provide a unique prefix instead of the exact ID, the tool auto-resolves it.
|
||||
|
||||
```json
|
||||
{
|
||||
"buildId": "BUILD_ID",
|
||||
"kind": "FAILURES",
|
||||
"query": "F0"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Problem Inspection (`kind="PROBLEMS"`)
|
||||
|
||||
Inspect a specific compilation or configuration problem. Find problem IDs (`P0`, `P1`, etc.) in the build summary. Provides file locations, error messages, and suggestions where available.
|
||||
|
||||
```json
|
||||
{
|
||||
"buildId": "BUILD_ID",
|
||||
"kind": "PROBLEMS",
|
||||
"query": "P1"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Task Output Inspection (`kind="TASKS"`)
|
||||
|
||||
If the failure is task-related, check the isolated output of a specific task. Supports prefix matching on the task path.
|
||||
|
||||
```json
|
||||
{
|
||||
"buildId": "BUILD_ID",
|
||||
"kind": "TASKS",
|
||||
"query": ":app:compileJava"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Test Inspection (`kind="TESTS"`)
|
||||
|
||||
### Listing Failed Tests (Summary Mode)
|
||||
|
||||
Quickly see which tests failed without being overwhelmed by logs:
|
||||
|
||||
```json
|
||||
{
|
||||
"buildId": "BUILD_ID",
|
||||
"kind": "TESTS",
|
||||
"outcome": "FAILED"
|
||||
}
|
||||
```
|
||||
|
||||
### Getting Detailed Test Output (Details Mode)
|
||||
|
||||
**CRITICAL**: Always use `kind="TESTS"` and `query` to see the complete stdout, stderr, and stack trace for a specific test. Supports unique prefix matching on the test name.
|
||||
|
||||
```json
|
||||
{
|
||||
"buildId": "BUILD_ID",
|
||||
"kind": "TESTS",
|
||||
"query": "com.example.MyTest.testMethod"
|
||||
}
|
||||
```
|
||||
|
||||
### Individual Test Case vs. Task Output
|
||||
|
||||
**DO NOT** use `taskPath` or `captureTaskOutput` for investigating specific test failures:
|
||||
|
||||
- **Task output** is the aggregated log of the entire test process. It is often truncated, interleaved, and lacks the full stack traces and per-test isolation needed for debugging.
|
||||
- **Individual test output** (retrieved via `query`) is authoritative, includes full stdout/stderr for just that test case, and provides the complete stack trace for any failure.
|
||||
|
||||
### Filtering by Name
|
||||
|
||||
Use `query` with summary mode to see all executions of a test across different projects or iterations:
|
||||
|
||||
```json
|
||||
{
|
||||
"buildId": "BUILD_ID",
|
||||
"kind": "TESTS",
|
||||
"query": "MyTest"
|
||||
}
|
||||
```
|
||||
|
||||
### Monitoring Test Progress
|
||||
|
||||
While a build is running, progress notifications provide real-time counts of passed, failed, and skipped tests. Call `query_build(buildId="ID")` repeatedly to see updated test counts: `(5 passed, 1 failed)`.
|
||||
|
||||
### Pagination for Large Test Suites
|
||||
|
||||
```json
|
||||
{
|
||||
"buildId": "BUILD_ID",
|
||||
"kind": "TESTS",
|
||||
"pagination": {
|
||||
"limit": 50,
|
||||
"offset": 0
|
||||
},
|
||||
"query": "com.example.service"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Console Log Inspection (`kind="CONSOLE"`)
|
||||
|
||||
If structured reports are insufficient, examine the raw console output. Use `query` as a regex filter.
|
||||
|
||||
### Head (first N lines)
|
||||
|
||||
```json
|
||||
{
|
||||
"buildId": "BUILD_ID",
|
||||
"kind": "CONSOLE",
|
||||
"pagination": {
|
||||
"limit": 100,
|
||||
"offset": 0
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Tail (last N lines)
|
||||
|
||||
```json
|
||||
{
|
||||
"buildId": "BUILD_ID",
|
||||
"kind": "CONSOLE",
|
||||
"pagination": {
|
||||
"limit": 100
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Filtered by Regex
|
||||
|
||||
```json
|
||||
{
|
||||
"buildId": "BUILD_ID",
|
||||
"kind": "CONSOLE",
|
||||
"query": "ERROR|FAILURE"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. Progress Monitoring (`wait_build`)
|
||||
|
||||
Use `wait_build` with `timeout`, `waitFor`, or `waitForTask` to block until a condition is met in a background build.
|
||||
|
||||
### Waiting for a Log Message
|
||||
|
||||
The most common pattern for background builds (dev servers) is waiting for a specific readiness message:
|
||||
|
||||
```json
|
||||
{
|
||||
"buildId": "BUILD_ID",
|
||||
"timeout": 60,
|
||||
"waitFor": "Started Application"
|
||||
}
|
||||
```
|
||||
|
||||
### Waiting for Task Completion
|
||||
|
||||
```json
|
||||
{
|
||||
"buildId": "BUILD_ID",
|
||||
"timeout": 120,
|
||||
"waitForTask": ":app:assemble"
|
||||
}
|
||||
```
|
||||
|
||||
### Waiting for Build Completion
|
||||
|
||||
If `timeout` is set without a wait condition, the tool waits for the build to finish:
|
||||
|
||||
```json
|
||||
{
|
||||
"buildId": "BUILD_ID",
|
||||
"timeout": 600
|
||||
}
|
||||
```
|
||||
|
||||
### Handling Timeouts
|
||||
|
||||
If a build takes longer than the `timeout` value, `wait_build` returns the current status. You can call it again with a new timeout.
|
||||
|
||||
### Continuous Builds
|
||||
|
||||
For continuous builds, wait for the "Waiting for changes" message after the first build completes:
|
||||
|
||||
```json
|
||||
// Start
|
||||
{ "commandLine": ["build", "--continuous"], "background": true }
|
||||
|
||||
// Wait
|
||||
{ "buildId": "BUILD_ID", "timeout": 120, "waitFor": "Waiting for changes" }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. Full Export (`outputFile`)
|
||||
|
||||
Use `outputFile="path/to/file.txt"` to write the entire result to a file. This bypasses pagination limits and reduces token usage. Works with all `kind` values.
|
||||
|
||||
```json
|
||||
{
|
||||
"buildId": "BUILD_ID",
|
||||
"kind": "CONSOLE",
|
||||
"outputFile": "C:/temp/build_output.txt"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. Diagnostic Workflow
|
||||
|
||||
When a build fails, follow this structured approach:
|
||||
|
||||
### Step 1: Get the Build Summary
|
||||
|
||||
```json
|
||||
{ "buildId": "BUILD_ID" }
|
||||
```
|
||||
|
||||
Provides the high-level overview: failures, problems, and failed tests.
|
||||
|
||||
### Step 2: Inspect Failures
|
||||
|
||||
```json
|
||||
{ "buildId": "BUILD_ID", "kind": "FAILURES", "query": "F0" }
|
||||
```
|
||||
|
||||
### Step 3: Inspect Problems
|
||||
|
||||
```json
|
||||
{ "buildId": "BUILD_ID", "kind": "PROBLEMS", "query": "P1" }
|
||||
```
|
||||
|
||||
### Step 4: Check Task Outputs
|
||||
|
||||
```json
|
||||
{ "buildId": "BUILD_ID", "kind": "TASKS", "query": ":app:compileJava" }
|
||||
```
|
||||
|
||||
### Step 5: Check Test Failures
|
||||
|
||||
```json
|
||||
{ "buildId": "BUILD_ID", "kind": "TESTS", "outcome": "FAILED" }
|
||||
```
|
||||
|
||||
Then drill into each failed test:
|
||||
|
||||
```json
|
||||
{ "buildId": "BUILD_ID", "kind": "TESTS", "query": "com.example.MyTest.shouldWork" }
|
||||
```
|
||||
|
||||
### Step 6: Fall Back to Console Logs
|
||||
|
||||
```json
|
||||
{ "buildId": "BUILD_ID", "kind": "CONSOLE", "pagination": { "limit": 100 } }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 11. Build Failures vs. Test Failures
|
||||
|
||||
Sometimes a test run fails because the build itself failed (compilation error, configuration error, task dependency failure), not because a test failed.
|
||||
|
||||
1. Check the build summary: `query_build(buildId="ID")`.
|
||||
2. If failures or problems are listed, inspect them directly via `kind="FAILURES"` or `kind="PROBLEMS"`.
|
||||
3. If the build failed but no tests are reported, focus on build-level failures and problems.
|
||||
|
||||
---
|
||||
|
||||
## 12. Common Failure Scenarios
|
||||
|
||||
### Compilation Errors
|
||||
|
||||
- Look for problems with the specific `severity: ERROR` in the build summary.
|
||||
- Check `kind="PROBLEMS"` for file location and error details.
|
||||
|
||||
### Dependency Resolution Issues
|
||||
|
||||
- Check `kind="FAILURES"` for messages like "Could not resolve all dependencies".
|
||||
- Use `inspect_dependencies` to investigate the dependency graph.
|
||||
|
||||
### Task Execution Failures
|
||||
|
||||
- Check `kind="TASKS"` to see which task failed and its output.
|
||||
|
||||
### Build Script Errors
|
||||
|
||||
- Usually appear in the `kind="FAILURES"` section with a stack trace and line reference.
|
||||
|
||||
### Assertion Failures
|
||||
|
||||
- Check `kind="TESTS"` with the specific test `query` for expected vs. actual values.
|
||||
|
||||
### Timeouts
|
||||
|
||||
- Tests that time out may be marked as ERROR or FAILED. Check console output for "Timeout" messages.
|
||||
|
||||
### Infrastructure Issues
|
||||
|
||||
- If many tests fail with similar errors (`NoClassDefFoundError`, `DatabaseConnectionException`), check build-level failures and problems.
|
||||
|
||||
---
|
||||
|
||||
## 13. Stopping Background Builds
|
||||
|
||||
Always stop background builds when they are no longer needed:
|
||||
|
||||
```json
|
||||
{
|
||||
"stopBuildId": "BUILD_ID"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 14. Foreground vs. Background Identity
|
||||
|
||||
Monitoring a background build using `query_build` or `wait_build` provides exactly the same rich diagnostic data as a foreground build, including progressive disclosure. The difference is control flow: background allows non-blocking work
|
||||
while the build proceeds; foreground blocks until completion.
|
||||
@ -1,119 +0,0 @@
|
||||
---
|
||||
name: interacting_with_project_runtime
|
||||
description: >
|
||||
Executes Kotlin code interactively within the project's full JVM classpath.
|
||||
Use when you need to RUN code: verify runtime behavior, experiment with logic, or render Compose UI previews.
|
||||
Do NOT use to understand an API's shape or signature — read its source with `exploring_dependency_sources` instead.
|
||||
license: Apache-2.0
|
||||
metadata:
|
||||
author: https://github.com/rnett/gradle-mcp
|
||||
version: "2.3"
|
||||
---
|
||||
|
||||
# Authoritative Project Runtime Interaction
|
||||
|
||||
Runs Kotlin code interactively within the project's exact JVM classpath — for when you need to execute, not just read.
|
||||
|
||||
## Constitution
|
||||
|
||||
- **The core decision rule**: If the question is *"what does this API look like or how does it work?"* → use `search_dependency_sources` / `read_dependency_sources` (read the source). If the question is *"what happens when I run this?"* →
|
||||
use `kotlin_repl`.
|
||||
- **NEVER** start a REPL session to learn about an API. Reading indexed sources is instantaneous, shows the full implementation with all overloads, and requires no JVM process.
|
||||
- **ALWAYS** use `kotlin_repl` instead of a standalone Kotlin REPL for project-aware interaction.
|
||||
- **ALWAYS** provide absolute paths for `projectRoot`.
|
||||
- **ALWAYS** start a REPL session with the correct `projectPath` and `sourceSet` (e.g., `main`, `test`).
|
||||
- **ALWAYS** restart the REPL (`stop` then `start`) after modifying project source code to pick up changes in the classpath.
|
||||
- **ALWAYS** use the `responder` API for rich output (images, markdown) to improve diagnostic visibility.
|
||||
- **NEVER** leave a REPL session running indefinitely; use `stop` when finished.
|
||||
- **REPL Session Management**: Explicitly terminate previous REPL sessions in `ReplTools` before starting new ones when session IDs are regenerated. This prevents leaking worker processes and ensures stable session management during
|
||||
concurrent or sequential tool calls.
|
||||
|
||||
## Directives
|
||||
|
||||
- **Read to understand, run to verify**: If you need to understand what an API does — its signature, parameters, overloads, or implementation — read its source via `search_dependency_sources` / `read_dependency_sources`. Only reach for the
|
||||
REPL once you know what you want to call and need to observe actual runtime output.
|
||||
- **ALWAYS use project-aware REPL**: Only the `kotlin_repl` tool provides full access to the project's exact classpath, dependencies, and source sets. NEVER attempt to use standalone runners for project-internal logic.
|
||||
- **Identify the environment**: When starting a session, ALWAYS ensure you select the appropriate `projectPath` (e.g., `:app`) and `sourceSet` (e.g., `main` for application code, `test` for test utility access).
|
||||
- **Pick up source changes**: The REPL uses a static snapshot of the classpath. If you change project code, you MUST `stop` and then `start` the session again to pick up the updated classes.
|
||||
- **Utilize the `responder`**: ALWAYS use `responder.render()` or specialized methods (`markdown`, `image`, `html`) to return rich content.
|
||||
- **Import necessary classes**: ALWAYS provide explicit imports for project-specific and library classes.
|
||||
- **Use `envSource: SHELL` if environment variables are missing**: If the REPL fails to find expected environment variables (e.g., `JAVA_HOME` or specific JDKs), it may be because the host process started before the shell environment was
|
||||
fully loaded. Set `env: { envSource: "SHELL" }` when calling `start` to force a new shell process to query the environment.
|
||||
- **Resolve `{baseDir}` manually**: If your environment does not automatically resolve the `{baseDir}` placeholder in reference links, treat it as the absolute path to the directory containing this `SKILL.md` file.
|
||||
|
||||
## When to Use (you need to RUN code)
|
||||
|
||||
- **Behavior Verification**: You know the API, you've written the call, and you need to observe the actual runtime output or side-effects.
|
||||
- **Logic Prototyping**: Experimenting with an algorithm or snippet of your own code before committing it to source.
|
||||
- **Visual Component Auditing**: Rendering Compose UI components to images for visual review.
|
||||
- **Dynamic Data Probing**: One-off data transformations using your project's existing utilities where the output depends on runtime state.
|
||||
|
||||
## When NOT to Use (you need to READ source instead)
|
||||
|
||||
Ask yourself: *"Am I trying to understand this API, or run it?"*
|
||||
|
||||
If you're trying to understand it — what methods it has, what its parameters are, how it's implemented — **stop and use `exploring_dependency_sources` first**. The REPL cannot tell you what you don't already know to ask; source reading can.
|
||||
Examples of what belongs in source reading, not the REPL:
|
||||
|
||||
- "What methods does `SomeClass` have?" → `search_dependency_sources` DECLARATION search
|
||||
- "What does this function do internally?" → `read_dependency_sources`
|
||||
- "What are the parameters / overloads of this function?" → `read_dependency_sources`
|
||||
- "Does this library have a class for X?" → `search_dependency_sources` FULL_TEXT or DECLARATION search
|
||||
|
||||
## Workflows
|
||||
|
||||
### Starting an Authoritative Session
|
||||
|
||||
1. Identify the project module (e.g., `:app`) and source set (e.g., `main`).
|
||||
2. Call `kotlin_repl(command="start")`.
|
||||
3. Optionally provide `env` for environment variables or `additionalDependencies` if you need external libraries not currently in the project.
|
||||
|
||||
### Probing Code & State
|
||||
|
||||
1. Use `kotlin_repl(command="run")` with your Kotlin code.
|
||||
2. Use `responder.render()` for rich diagnostics.
|
||||
3. Review the returned text or image content.
|
||||
|
||||
### Lifecycle Management
|
||||
|
||||
1. Use `kotlin_repl(command="stop")` once your investigation is complete to release system resources.
|
||||
|
||||
## Examples
|
||||
|
||||
### Probing a project utility function
|
||||
|
||||
```json
|
||||
// Start the session
|
||||
{
|
||||
"command": "start",
|
||||
"projectPath": ":my-project",
|
||||
"sourceSet": "main"
|
||||
}
|
||||
|
||||
// Execute the probe
|
||||
{
|
||||
"command": "run",
|
||||
"code": "import com.example.utils.MyHelper\nMyHelper.calculateSum(1, 2)"
|
||||
}
|
||||
// Reasoning: Using kotlin_repl to verify a utility function in the context of the main source set.
|
||||
```
|
||||
|
||||
### Visualizing a UI Component
|
||||
|
||||
```kotlin
|
||||
import androidx.compose.ui.test.*
|
||||
import com.example.ui.MyComposable
|
||||
|
||||
runComposeUiTest {
|
||||
setContent { MyComposable() }
|
||||
val bitmap = onRoot().captureToImage()
|
||||
responder.render(bitmap)
|
||||
}
|
||||
// Reasoning: Using the responder API to retrieve a high-resolution image of a Compose component.
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **REPL Not Started**: You must call `start` successfully before calling `run`.
|
||||
- **ClassNotFoundException**: Ensure the project has been built at least once and that you have selected the correct `sourceSet` (e.g., `test` if the class is in `src/test/kotlin`).
|
||||
- **Changes Not Reflected**: If your code changes aren't appearing, `stop` and `start` the REPL to refresh the classpath.
|
||||
@ -1,166 +0,0 @@
|
||||
---
|
||||
name: managing_gradle_dependencies
|
||||
description: >
|
||||
Audits and manages Gradle dependency graphs with high-resolution update checks, transitive tree analysis, and Maven Central discovery;
|
||||
use for dependency auditing, finding stable updates, and resolving GAV coordinates.
|
||||
Do NOT use for exploring dependency source code (use `exploring_dependency_sources`) or running builds/tests (use `gradle`).
|
||||
license: Apache-2.0
|
||||
metadata:
|
||||
author: https://github.com/rnett/gradle-mcp
|
||||
version: "3.4"
|
||||
---
|
||||
|
||||
# Authoritative Dependency Intelligence & Maven Central Search
|
||||
|
||||
Audits project dependencies, performs high-resolution update checks, and discovers new libraries on Maven Central with powerful, integrated search tools.
|
||||
|
||||
## Constitution
|
||||
|
||||
- **ALWAYS** use `inspect_dependencies` for querying project dependency information instead of raw Gradle tasks.
|
||||
- **ALWAYS** provide absolute paths for `projectRoot`.
|
||||
- **ALWAYS** use `updatesOnly: true` to quickly identify available library updates.
|
||||
- **ALWAYS** use `lookup_maven_versions` to find exact GAV coordinates for new libraries.
|
||||
- **NEVER** add a dependency to a project without verifying its authoritative version and existence on Maven Central.
|
||||
- **ALWAYS** use the `projectPath` argument to target specific modules in multi-project builds.
|
||||
|
||||
## Directives
|
||||
|
||||
- **Identify authoritative paths**: ALWAYS use the Gradle project path (e.g., `:app`) when querying dependencies.
|
||||
- **Inspect plugins and build scripts**: Build script dependencies (like plugins) are automatically included in `inspect_dependencies` output under configurations prefixed with `buildscript:` (e.g. `buildscript:classpath`).
|
||||
- **Monitor for updates**: ALWAYS use `updatesOnly: true` in `inspect_dependencies` to retrieve a flat, high-signal report of available library updates: `group:artifact: current → latest` with the project paths where each dep is used.
|
||||
Configuration and source-set detail is intentionally omitted; use `inspect_dependencies` with a specific `dependency` filter if that detail is needed.
|
||||
- **Target dependencies surgically**: Use the `dependency` parameter in `inspect_dependencies` to target a single library with a full-string Kotlin regex over `group:name:version[:variant]` coordinates.
|
||||
- **Efficient Transitive Isolation**: When isolating a single library, filter the flattened list of resolved components using the dependency filter rather than traversing the dependency graph. This naturally and efficiently excludes
|
||||
transitive dependencies that do not match the targeted filter.
|
||||
- **Discover libraries surgically**: ALWAYS use `lookup_maven_versions` to check the version history of an existing artifact.
|
||||
- **Use `gradle` for diagnostics**: For built-in tasks like `dependencyInsight`, ALWAYS use the `gradle` tool with `captureTaskOutput`.
|
||||
- **Audit full trees**: ALWAYS use `onlyDirect: false` in `inspect_dependencies` when you need to visualize the complete transitive dependency graph.
|
||||
|
||||
## When to Use
|
||||
|
||||
- **Dependency Tree Auditing**: When you need to visualize the full dependency graph for a specific project, configuration, or source set.
|
||||
- **Automated Update Detection**: When performing maintenance and you want a concise report on available stable or pre-release updates.
|
||||
- **Precision Artifact Discovery**: When looking for new libraries on Maven Central and you need to find exact GAV coordinates or explore an artifact's full version history.
|
||||
- **Version Conflict Resolution**: When you need to identify why a specific version of a library is being resolved and look for compatible alternatives.
|
||||
- **Targeted Audit**: When you only care about a specific library and want to bypass the cost of a full project resolution.
|
||||
|
||||
## Workflows
|
||||
|
||||
### 1. Auditing Dependencies
|
||||
|
||||
1. Identify the project module (e.g., `:app`).
|
||||
2. Call `inspect_dependencies(projectPath=":app")`.
|
||||
3. Optionally filter by `configuration` (e.g., `runtimeClasspath`) or `sourceSet` (e.g., `test`).
|
||||
|
||||
### 2. Checking for Stable Updates
|
||||
|
||||
1. Call `inspect_dependencies(updatesOnly=true, stableOnly=true)`.
|
||||
2. Review the flat list of upgradeable dependencies. Each entry shows `group:artifact: current → latest` and the project paths where it is used.
|
||||
|
||||
### 3. Discovering New Libraries
|
||||
|
||||
1. Use `lookup_maven_versions(coordinates="group:artifact")` to see all available versions for a specific library.
|
||||
|
||||
### 4. Targeted Dependency Inspection
|
||||
|
||||
1. Identify the dependency you want to check (e.g., `org.mongodb:mongodb-driver-sync`).
|
||||
2. Call `inspect_dependencies(dependency="^org\\.mongodb:mongodb-driver-sync(:.*)?$")`.
|
||||
3. The report will be focused ONLY on that library across all matched configurations.
|
||||
|
||||
### 5. Adding a New Dependency
|
||||
|
||||
1. **Search Maven Central**: Use `lookup_maven_versions(coordinates="group:artifact")` to find the artifact and its latest version.
|
||||
2. **Update Version Catalog**: Add the dependency coordinates to `gradle/libs.versions.toml`:
|
||||
```toml
|
||||
[versions]
|
||||
my-lib = "X.Y.Z"
|
||||
|
||||
[libraries]
|
||||
my-lib = { group = "com.example", name = "my-lib", version.ref = "my-lib" }
|
||||
```
|
||||
3. **Apply to `build.gradle.kts`**: Use the type-safe catalog accessor (e.g., `implementation(libs.my.lib)`) in the appropriate dependency configuration.
|
||||
4. **Verify Resolution**: Run `inspect_dependencies(fresh: true)` to confirm the dependency resolves correctly.
|
||||
|
||||
#### Example: Adding a dependency to a subproject
|
||||
|
||||
```json
|
||||
// Step 1: Discover the library
|
||||
{
|
||||
"coordinates": "com.squareup.retrofit2:retrofit"
|
||||
}
|
||||
// Step 2: Update libs.versions.toml with the version and library entry
|
||||
// Step 3: Add `implementation(libs.retrofit)` to the subproject's build.gradle.kts
|
||||
// Step 4: Verify
|
||||
{
|
||||
"projectPath": ":app",
|
||||
"dependency": "^com\\.squareup\\.retrofit2:retrofit(:.*)?$"
|
||||
}
|
||||
// Reasoning: Adding the Retrofit library to the 'app' module with full resolution verification.
|
||||
```
|
||||
|
||||
### 6. Verifying Plugin Dependencies
|
||||
|
||||
Build script dependencies (plugins) are automatically reported under `buildscript:` configurations. To specifically verify plugin resolution:
|
||||
|
||||
1. Call `inspect_dependencies(sourceSetPath=":buildscript")` for the root project, or `sourceSetPath=":app:buildscript"` for a subproject.
|
||||
2. Review the `buildscript:classpath` configuration for plugin dependencies.
|
||||
3. Use `fresh: true` if plugins were recently added or updated.
|
||||
|
||||
#### Example: Verifying a specific plugin
|
||||
|
||||
```json
|
||||
{
|
||||
"sourceSetPath": ":buildscript",
|
||||
"dependency": "^org\\.jetbrains\\.kotlin:kotlin-gradle-plugin(:.*)?$"
|
||||
}
|
||||
// Reasoning: Verifying the Kotlin plugin is properly resolved in the buildscript classpath.
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### List dependencies for a specific module
|
||||
|
||||
```json
|
||||
{
|
||||
"projectPath": ":app"
|
||||
}
|
||||
// Reasoning: Auditing the direct and transitive dependencies of the 'app' module to understand its runtime footprint.
|
||||
```
|
||||
|
||||
### Check for updates for a specific library
|
||||
|
||||
```json
|
||||
{
|
||||
"dependency": "^org\\.jetbrains\\.kotlinx:kotlinx-coroutines-core(:.*)?$",
|
||||
"updatesOnly": true
|
||||
}
|
||||
// Reasoning: Surgically checking if a specific library has available updates.
|
||||
```
|
||||
|
||||
### Check for stable updates across the project
|
||||
|
||||
```json
|
||||
{
|
||||
"updatesOnly": true,
|
||||
"stableOnly": true
|
||||
}
|
||||
// Reasoning: Performing a high-signal update audit that ignores unstable pre-release versions.
|
||||
```
|
||||
|
||||
### List all versions of a specific library
|
||||
|
||||
```json
|
||||
{
|
||||
"coordinates": "org.jetbrains.kotlinx:kotlinx-serialization-json"
|
||||
}
|
||||
// Reasoning: Retrieving the full version history of an artifact to identify the latest stable or specific version required.
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **Dependency Not Found**: Verify the `projectPath` using the `projects` task in the `gradle` skill.
|
||||
- **Update Not Showing**: If a known update is missing, ensure `stableOnly` is set correctly and check if a `versionFilter` is active.
|
||||
- **[UPDATE CHECK SKIPPED]**: This annotation means the dep was in scope for update checking but its resolution genuinely failed — it does NOT appear for dependencies intentionally excluded from the update-check scope (e.g., transitive deps
|
||||
when `onlyDirect=true`, or deps excluded by a `dependency` filter).
|
||||
- **Maven Search No Results**: Use broader search terms or verify the `group:artifact` format for version searches.
|
||||
- **Missing environment variables**: Set `invocationArguments: { envSource: "SHELL" }` if Gradle cannot find expected env vars (e.g., `JAVA_HOME`).
|
||||
@ -1,165 +0,0 @@
|
||||
---
|
||||
name: verifying_compose_ui
|
||||
description: >
|
||||
Visually verifies Compose UI components by rendering @Composable/@Preview functions to images from the project's JVM runtime;
|
||||
STRONGLY PREFERRED for rapid UI iteration and visual feedback on any composable.
|
||||
Do NOT use for build lifecycle tasks or dependency auditing.
|
||||
license: Apache-2.0
|
||||
metadata:
|
||||
author: https://github.com/rnett/gradle-mcp
|
||||
version: "2.2"
|
||||
---
|
||||
|
||||
## ⚠️ FUNDAMENTAL ANDROID LIMITATION
|
||||
|
||||
**IMPORTANT: `runComposeUiTest` and image capture methods (`node.captureToImage()`) are NOT supported on Android and CANNOT work.**
|
||||
|
||||
### Why This Cannot Work
|
||||
|
||||
The `runComposeUiTest` function requires a JVM-based test runtime with desktop Compose rendering (via Skiko on JVM/Desktop). Android's ART (Android Runtime) does not support the desktop Compose testing APIs, and image capture via
|
||||
`captureToImage()` relies on desktop-specific rendering pipelines that are fundamentally incompatible with Android.
|
||||
|
||||
### The Solution: Use a JVM Target
|
||||
|
||||
**For visual verification of Composables, you MUST use a JVM or Desktop target source set.** This is not a workaround—it is the only supported method.
|
||||
|
||||
Recommended approach:
|
||||
|
||||
1. **Put your Composables in a common source set** (`commonMain`) that is shared across all targets
|
||||
2. **Create or use a JVM target** (e.g., `jvmMain`, `desktopMain`) that depends on `commonMain`
|
||||
3. **Run the REPL on the JVM target** (`sourceSet: "jvmMain"` or `sourceSet: "jvmTest"`)
|
||||
|
||||
This is the standard KMP pattern and allows you to verify your UI code without needing an Android device or emulator.
|
||||
|
||||
### What WILL NOT Work
|
||||
|
||||
- ❌ Running the REPL with `sourceSet: "androidMain"`
|
||||
- ❌ Running the REPL with `sourceSet: "androidTest"`
|
||||
- ❌ Any attempt to use `runComposeUiTest` on Android
|
||||
- ❌ Any attempt to use `captureToImage()` on Android
|
||||
|
||||
### What WILL Work
|
||||
|
||||
- ✅ Running the REPL with `sourceSet: "jvmMain"` or `sourceSet: "jvmTest"`
|
||||
- ✅ Running the REPL with `sourceSet: "desktopMain"` or `sourceSet: "desktopTest"`
|
||||
- ✅ Using `runComposeUiTest` with `captureToImage()` on JVM/Desktop targets
|
||||
|
||||
---
|
||||
|
||||
# Authoritative Compose UI Preview & Visual Verification
|
||||
|
||||
Visually verifies and renders any @Composable or @Preview directly to high-quality images from the project-aware REPL for instant, authoritative visual feedback.
|
||||
|
||||
## Constitution
|
||||
|
||||
- **ALWAYS** use `kotlin_repl` to render Compose components instead of running the full application for visual checks.
|
||||
- **ALWAYS** provide absolute paths for `projectRoot`.
|
||||
- **ALWAYS** use `node.captureToImage()` and `responder.render(bitmap)` to return the visual output.
|
||||
- **ALWAYS** ensure the correct Compose UI testing dependencies are on the classpath, using `additionalDependencies` if necessary.
|
||||
- **NEVER** assume a UI component renders correctly without visual verification.
|
||||
- **ALWAYS** search for existing `@Preview` functions in the project source code before creating new ones.
|
||||
|
||||
## Directives
|
||||
|
||||
- **ALWAYS provide absolute `projectRoot`**: Ensure `projectRoot` is an **absolute file system path** for all `kotlin_repl` calls.
|
||||
- **Ensure dependencies**: ALWAYS ensure Compose UI testing dependencies (e.g., `androidx.compose.ui:ui-test-junit4`) are on the classpath.
|
||||
- **Note on versions**: ALWAYS check your project's version catalog and existing tests for the correct imports for `runComposeUiTest`.
|
||||
- **Render as image**: ALWAYS use `node.captureToImage()` and `responder.render(bitmap)` to return the visual output.
|
||||
- **Kotlin Multiplatform (KMP) Note**: The `kotlin_repl` currently only supports **JVM-based** source sets. ALWAYS select a JVM or Desktop target source set for visual checks.
|
||||
- **Use `envSource: SHELL` if environment variables are missing**: Set `env: { envSource: "SHELL" }` (REPL start) or `invocationArguments: { envSource: "SHELL" }` (Gradle tasks) if expected env vars (e.g., `JAVA_HOME`) are not found.
|
||||
|
||||
## When to Use
|
||||
|
||||
- **Rapid UI Prototyping & Iteration**: When you need to see the visual result of a Composable change instantly without the latency of a full application launch.
|
||||
- **Authoritative @Preview Verification**: When you want to verify the visual correctness of existing `@Preview` functions.
|
||||
- **Complex UI State & Interaction Testing**: When you need to capture visual state before and after interactions (like clicks or state changes).
|
||||
- **Multi-Configuration Visual Auditing**: When checking how a component renders across different data states or configurations (e.g., different view models or mock data).
|
||||
|
||||
## Workflows
|
||||
|
||||
### 1. Identifying the Component
|
||||
|
||||
1. Find the fully qualified name of the `@Composable` or `@Preview` function.
|
||||
2. Search for existing previews in the source code via `grep_search(pattern="@Preview")`.
|
||||
|
||||
### 2. Orchestrating the Session
|
||||
|
||||
1. Start the REPL with the `test` source set (preferred) or `main` with `additionalDependencies`.
|
||||
2. Use `kotlin_repl(command="start")`.
|
||||
3. Use `kotlin_repl(command="run")` to execute the rendering script.
|
||||
|
||||
### 3. Rendering & Verifying
|
||||
|
||||
1. Execute a script that uses `runComposeUiTest` to render and capture the component.
|
||||
2. Inspect the returned image for visual correctness.
|
||||
|
||||
## Examples
|
||||
|
||||
### Viewing a simple Composable
|
||||
|
||||
```kotlin
|
||||
import androidx.compose.ui.test.*
|
||||
import com.example.ui.MyButton
|
||||
|
||||
runComposeUiTest {
|
||||
setContent {
|
||||
MyButton(text = "Click Me")
|
||||
}
|
||||
val node = onRoot()
|
||||
responder.render(node.captureToImage())
|
||||
}
|
||||
// Reasoning: Using kotlin_repl to render a specific component and retrieve its visual representation via the responder API.
|
||||
```
|
||||
|
||||
### Viewing an existing @Preview
|
||||
|
||||
```kotlin
|
||||
import androidx.compose.ui.test.*
|
||||
import com.example.ui.MyButtonPreview // Top-level preview function
|
||||
|
||||
runComposeUiTest {
|
||||
setContent {
|
||||
MyButtonPreview()
|
||||
}
|
||||
val node = onRoot()
|
||||
responder.render(node.captureToImage())
|
||||
}
|
||||
// Reasoning: Reusing an existing authoritative preview function to verify its visual correctness.
|
||||
```
|
||||
|
||||
### Capturing State Transitions
|
||||
|
||||
```kotlin
|
||||
import androidx.compose.ui.test.*
|
||||
import com.example.ui.MyCounter
|
||||
import com.example.viewmodel.MyViewModel
|
||||
|
||||
runComposeUiTest {
|
||||
val viewModel = MyViewModel()
|
||||
setContent {
|
||||
MyCounter(viewModel)
|
||||
}
|
||||
|
||||
// Capture state before interaction
|
||||
responder.render("State before: ${viewModel.count}")
|
||||
responder.render(onRoot().captureToImage())
|
||||
|
||||
// Perform interaction
|
||||
onNodeWithText("Increment").performClick()
|
||||
|
||||
// Capture state after interaction
|
||||
responder.render("State after: ${viewModel.count}")
|
||||
responder.render(onRoot().captureToImage())
|
||||
}
|
||||
// Reasoning: Capturing visual snapshots before and after an interaction to verify state-dependent UI changes.
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **No Image Returned**: Ensure you are calling `responder.render(bitmap)`.
|
||||
- **ClassNotFoundException**: Check if you have the correct imports and that the required testing dependencies are on the classpath.
|
||||
- **Empty Image**: If the Composable is empty or has zero size, the image will be empty. Verify your Composable's modifiers.
|
||||
|
||||
## Resources
|
||||
|
||||
- [Troubleshooting]({baseDir}/references/troubleshooting.md)
|
||||
@ -1,87 +0,0 @@
|
||||
# Troubleshooting Compose in REPL
|
||||
|
||||
Common issues when rendering Compose components in the REPL and how to resolve them.
|
||||
|
||||
## Kotlin Multiplatform (KMP) Issues
|
||||
|
||||
The Gradle REPL only supports JVM-based source sets.
|
||||
|
||||
- **Issue**: Attempting to start the REPL on a common, iOS, or Android source set fails.
|
||||
- **Solution**: Select a JVM or Desktop target source set. Recommended names: `jvmMain`, `jvmTest`, `desktopMain`, `desktopTest`.
|
||||
- **Issue**: Dependencies from `commonMain` are not resolving.
|
||||
- **Solution**: Starting the REPL on a JVM-specific source set that *depends* on `commonMain` (which is standard KMP structure) will include all inherited dependencies. Ensure the project is built before starting.
|
||||
|
||||
## Android Limitation (FUNDAMENTAL)
|
||||
|
||||
**IMPORTANT: `runComposeUiTest` and `captureToImage()` CANNOT work on Android.**
|
||||
|
||||
This is not a bug or limitation that can be fixed—it is a fundamental architectural incompatibility:
|
||||
|
||||
- `runComposeUiTest` requires desktop Compose runtime with Skiko rendering
|
||||
- Android's ART does not support desktop Compose testing APIs
|
||||
- `captureToImage()` relies on desktop-specific rendering pipelines
|
||||
|
||||
**Solution**: Put your Composables in `commonMain` and run the REPL on a JVM target (`jvmMain`, `jvmTest`, `desktopMain`, or `desktopTest`).
|
||||
|
||||
## `ClassNotFoundException: androidx.compose.ui.test.junit4.DesktopComposeTestRule`
|
||||
|
||||
This occurs when the Compose UI Test dependencies are not on the REPL's classpath.
|
||||
The REPL uses the runtime classpath of the selected `sourceSet`.
|
||||
If you are using `sourceSet: "main"`, but the test dependencies are in `testImplementation`, they won't be included.
|
||||
|
||||
**Solutions:**
|
||||
|
||||
1. **(Preferred)** Start the REPL with `sourceSet: "test"`. This usually includes the required test dependencies.
|
||||
2. Add the dependency manually using `additionalDependencies` if using `sourceSet: "main"`:
|
||||
```json
|
||||
{
|
||||
"command": "start",
|
||||
"projectPath": ":my-app",
|
||||
"sourceSet": "main",
|
||||
"additionalDependencies": ["org.jetbrains.compose.ui:ui-test-junit4-desktop:1.7.0"]
|
||||
}
|
||||
```
|
||||
|
||||
## `java.lang.NoClassDefFoundError: org/jetbrains/skiko/SkiaLayer`
|
||||
|
||||
Skiko is the rendering engine for Compose Desktop. It might be missing if the project is not correctly configured for Compose Desktop or if dependencies are incomplete.
|
||||
|
||||
**Solution:**
|
||||
Ensure `compose.desktop.currentOs` is in the project's dependencies or add it to `additionalDependencies`.
|
||||
|
||||
## Composable Renders but No Image is Shown
|
||||
|
||||
The `project_repl` tool only returns content that is explicitly rendered via `responder.render(value)` or the result of the last expression in the script.
|
||||
|
||||
**Solution:**
|
||||
Ensure you call `responder.render(bitmap)` inside your `runComposeUiTest` block.
|
||||
|
||||
```kotlin
|
||||
runComposeUiTest {
|
||||
setContent { MyComposable() }
|
||||
responder.render(onRoot().captureToImage()) // <--- Important!
|
||||
}
|
||||
```
|
||||
|
||||
## `Unresolved reference: runComposeUiTest`
|
||||
|
||||
The `runComposeUiTest` function may be located in different packages depending on your version of Compose or whether you are using JetBrains Compose.
|
||||
|
||||
**Solutions:**
|
||||
|
||||
1. Check the correct import for your project. Common ones:
|
||||
- `androidx.compose.ui.test.runComposeUiTest`
|
||||
- `org.jetbrains.compose.ui.test.runComposeUiTest` (for older or specific JetBrains Compose versions)
|
||||
2. Ensure you are using a compatible version of the `ui-test` library. Some older versions used `runDesktopComposeUiTest` or similar.
|
||||
|
||||
## `Unresolved reference: responder`
|
||||
|
||||
The `responder` property is automatically injected into the REPL session by the worker.
|
||||
If it is unresolved, check if you have a custom `providedProperties` in your script configuration (usually not an issue for users).
|
||||
Ensure you are using the `project_repl` tool which uses the custom REPL worker.
|
||||
|
||||
## `java.lang.IllegalStateException: runComposeUiTest { ... } needs to be called from the main thread`
|
||||
|
||||
On some platforms, Compose UI tests might require being run on the main/UI thread.
|
||||
The REPL evaluates snippets on a background thread. `runComposeUiTest` usually handles its own thread management, but if you encounter this, try wrapping your code in a `SwingUtilities.invokeLater` (for Desktop) if applicable, though
|
||||
`runComposeUiTest` should be sufficient.
|
||||
@ -1,17 +1,5 @@
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"mcp": {
|
||||
"gradle": {
|
||||
"type": "local",
|
||||
"command": [
|
||||
"jbang",
|
||||
"run",
|
||||
"--java",
|
||||
"25",
|
||||
"--quiet",
|
||||
"--fresh",
|
||||
"gradle-mcp@rnett"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -176,7 +176,7 @@ private fun badgeGradient(colors: ButtonColors): Brush = remember(colors) {
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun buttonShadow(
|
||||
internal fun buttonShadow(
|
||||
shape: androidx.compose.ui.graphics.Shape,
|
||||
pressed: Boolean,
|
||||
primary: Boolean,
|
||||
|
||||
@ -0,0 +1,171 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Kingkor Roy Tirtho and Spotube Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package dev.krtirtho.spotube.core.ui.base
|
||||
|
||||
import androidx.compose.foundation.BorderStroke
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.hoverable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.interaction.collectIsHoveredAsState
|
||||
import androidx.compose.foundation.interaction.collectIsPressedAsState
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.RowScope
|
||||
import androidx.compose.foundation.layout.defaultMinSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.LocalContentColor
|
||||
import androidx.compose.material3.LocalTextStyle
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.ripple
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.draw.drawWithCache
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.graphicsLayer
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
|
||||
private val ChipTabShape = RoundedCornerShape(10.dp)
|
||||
private val ChipTabMinHeight = 36.dp
|
||||
|
||||
@Composable
|
||||
fun ChipTab(
|
||||
selected: Boolean,
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
enabled: Boolean = true,
|
||||
contentPadding: PaddingValues = PaddingValues(horizontal = 14.dp, vertical = 4.dp),
|
||||
content: @Composable RowScope.() -> Unit,
|
||||
) {
|
||||
val colors = rememberButtonColors()
|
||||
val interactionSource = remember { MutableInteractionSource() }
|
||||
val isPressed by interactionSource.collectIsPressedAsState()
|
||||
val isHovered by interactionSource.collectIsHoveredAsState()
|
||||
val gradient = if (selected) {
|
||||
primaryGradient(colors, isPressed)
|
||||
} else {
|
||||
outlinedGradient(colors, isPressed)
|
||||
}
|
||||
val borderColor = if (selected) {
|
||||
colors.accent
|
||||
} else {
|
||||
colors.border.copy(alpha = if (isPressed) 0.7f else 1f)
|
||||
}
|
||||
val contentColor = if (selected) colors.onAccent else colors.onContainer
|
||||
|
||||
Box(
|
||||
modifier = modifier
|
||||
.defaultMinSize(minHeight = ChipTabMinHeight)
|
||||
.hoverable(interactionSource = interactionSource, enabled = enabled)
|
||||
.then(
|
||||
buttonShadow(
|
||||
shape = ChipTabShape,
|
||||
pressed = isPressed,
|
||||
primary = selected,
|
||||
colors = colors,
|
||||
hovered = isHovered,
|
||||
)
|
||||
)
|
||||
.clip(ChipTabShape)
|
||||
.background(gradient, ChipTabShape)
|
||||
.border(BorderStroke(0.5.dp, borderColor), ChipTabShape)
|
||||
.clickable(
|
||||
enabled = enabled,
|
||||
interactionSource = interactionSource,
|
||||
indication = ripple(),
|
||||
onClick = onClick,
|
||||
)
|
||||
.drawWithCache {
|
||||
val highlight = if (selected) {
|
||||
Color.White.copy(alpha = 0.25f)
|
||||
} else {
|
||||
colors.highlight
|
||||
}
|
||||
val highlightBrush = Brush.verticalGradient(
|
||||
colors = listOf(highlight, Color.Transparent),
|
||||
startY = 0f,
|
||||
endY = size.height * 0.5f,
|
||||
)
|
||||
onDrawWithContent {
|
||||
drawContent()
|
||||
drawRect(
|
||||
brush = highlightBrush,
|
||||
topLeft = androidx.compose.ui.geometry.Offset.Zero,
|
||||
size = size,
|
||||
)
|
||||
}
|
||||
}
|
||||
.padding(contentPadding),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
CompositionLocalProvider(
|
||||
LocalContentColor provides contentColor,
|
||||
LocalTextStyle provides LocalTextStyle.current.copy(
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
fontSize = 14.sp,
|
||||
)
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(6.dp),
|
||||
content = content,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ChipTab(
|
||||
text: String,
|
||||
selected: Boolean,
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
enabled: Boolean = true,
|
||||
leadingIcon: @Composable (() -> Unit)? = null,
|
||||
contentPadding: PaddingValues = PaddingValues(horizontal = 16.dp, vertical = 8.dp),
|
||||
) {
|
||||
ChipTab(
|
||||
selected = selected,
|
||||
onClick = onClick,
|
||||
modifier = modifier,
|
||||
enabled = enabled,
|
||||
contentPadding = contentPadding,
|
||||
) {
|
||||
if (leadingIcon != null) {
|
||||
leadingIcon()
|
||||
}
|
||||
Text(
|
||||
text = text,
|
||||
maxLines = 1,
|
||||
softWrap = false,
|
||||
fontWeight = if (selected) FontWeight.SemiBold else FontWeight.Normal,
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -107,7 +107,7 @@ fun TextField(
|
||||
keyboardActions: KeyboardActions = KeyboardActions.Default,
|
||||
visualTransformation: VisualTransformation = VisualTransformation.None,
|
||||
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
|
||||
textStyle: TextStyle = LocalTextStyle.current,
|
||||
textStyle: TextStyle = TextStyle.Default,
|
||||
cursorBrush: Color = MaterialTheme.colorScheme.primary,
|
||||
) {
|
||||
val colors = rememberButtonColors()
|
||||
@ -167,7 +167,6 @@ fun TextField(
|
||||
if (leadingIcon != null) {
|
||||
leadingIcon()
|
||||
}
|
||||
|
||||
Box(modifier = Modifier.weight(1f)) {
|
||||
BasicTextField(
|
||||
value = value,
|
||||
|
||||
@ -27,7 +27,6 @@ import androidx.compose.animation.core.tween
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.animation.togetherWith
|
||||
import androidx.compose.foundation.BorderStroke
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
@ -38,7 +37,6 @@ import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.heightIn
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
@ -58,7 +56,6 @@ import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
@ -99,6 +96,7 @@ import dev.krtirtho.plugin_interfaces.plugin_apis.metadata.user.MetadataUser
|
||||
import dev.krtirtho.spotube.core.audioplayer.AudioPlayerQueue
|
||||
import dev.krtirtho.spotube.core.audioplayer.QueueEntry
|
||||
import dev.krtirtho.spotube.core.share.ShareService
|
||||
import dev.krtirtho.spotube.core.ui.base.ChipTab
|
||||
import dev.krtirtho.spotube.core.ui.component.AlbumCard
|
||||
import dev.krtirtho.spotube.core.ui.component.ApplicationMainBar
|
||||
import dev.krtirtho.spotube.core.ui.component.ArtistCard
|
||||
@ -613,49 +611,12 @@ private fun SearchTabs(
|
||||
) {
|
||||
items(types) { type ->
|
||||
val isSelected = selectedType == type
|
||||
SearchTab(
|
||||
label = type.tabTitle(),
|
||||
ChipTab(
|
||||
selected = isSelected,
|
||||
onClick = { onTabSelected(type) }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SearchTab(
|
||||
label: String,
|
||||
selected: Boolean,
|
||||
onClick: () -> Unit,
|
||||
) {
|
||||
Surface(
|
||||
onClick = onClick,
|
||||
shape = TabShape,
|
||||
color = if (selected)
|
||||
MaterialTheme.colorScheme.primaryContainer
|
||||
else
|
||||
MaterialTheme.colorScheme.surface,
|
||||
contentColor = if (selected)
|
||||
MaterialTheme.colorScheme.onPrimaryContainer
|
||||
else
|
||||
MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
border = if (selected)
|
||||
null
|
||||
else
|
||||
BorderStroke(1.dp, MaterialTheme.colorScheme.outlineVariant),
|
||||
modifier = Modifier.height(32.dp)
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 14.dp, vertical = 6.dp),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Text(
|
||||
text = label,
|
||||
style = MaterialTheme.typography.labelLarge,
|
||||
fontWeight = if (selected) FontWeight.SemiBold else FontWeight.Medium,
|
||||
maxLines = 1
|
||||
)
|
||||
) {
|
||||
Text(type.tabTitle())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user