diff --git a/.github/workflows/deploy_docs.yaml b/.github/workflows/deploy_docs.yaml new file mode 100644 index 000000000..74b0b72d8 --- /dev/null +++ b/.github/workflows/deploy_docs.yaml @@ -0,0 +1,36 @@ +name: Deploy MkDocs + +on: + push: + branches: + - main # Trigger deployment on pushes to main + paths: + - 'docs/**' + - 'mkdocs.yml' + +jobs: + deploy: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.x' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install mkdocs mkdocs-material + + - name: Build the documentation + run: mkdocs build + + - name: Deploy to GitHub Pages + uses: peaceiris/actions-gh-pages@v3 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./site diff --git a/.goosehints b/.goosehints index f445dda0e..8b6535a63 100644 --- a/.goosehints +++ b/.goosehints @@ -1,3 +1,3 @@ This is a python CLI app that uses UV. Read CONTRIBUTING.md for information on how to build and test it as needed. Some key concepts are that it is run as a command line interface, dependes on the "ai-exchange" package, and has the concept of toolkits which are ways that its behavior can be extended. Look in src/goose and tests. -Once the user has UV installed it should be able to be used effectively along with uvx to run tasks as needed \ No newline at end of file +Once the user has UV installed it should be able to be used effectively along with uvx to run tasks as needed diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 000000000..e69de29bb diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4f638f8ce..332deafba 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,7 +2,6 @@

Prerequisites • -EvaluationsDeveloping and testingBuilding from sourceDeveloping goose-plugins • @@ -37,7 +36,7 @@ Plugins added directly to Goose are subject to rigorous review. This is because Plugins in `goose-plugins` undergo less detailed reviews and are more modular or experimental. They can prove their value through usage or iteration over time and may be eventually moved over to Goose. -To see how to add a toolkit, see the [toolkits documentation][toolkits]. +To see how to add a toolkit, see the [toolkits documentation][adding-toolkit]. ### Running tests ```sh @@ -123,4 +122,4 @@ This project follows the [Conventional Commits](https://www.conventionalcommits. [uv]: https://docs.astral.sh/uv/ [ruff]: https://docs.astral.sh/ruff/ [just]: https://github.com/casey/just -[toolkits]: docs/docs/toolkits.md \ No newline at end of file +[adding-toolkit]: https://square.github.io/goose/configuration.html#adding-a-toolkit diff --git a/README.md b/README.md index 84397e3c5..d9fa65136 100644 --- a/README.md +++ b/README.md @@ -1,245 +1,187 @@

-goose +Goose is your on-machine developer agent, automating engineering tasks seamlessly within your IDE or terminal

-

goose is a programming agent that runs on your machine.

-

- - + Goose Drawing +

+

+ Generated by Goose from its VincentVanCode toolkit.

-Usage • -Configuration • -Tips • -FAQ • -Open Source + + + + +

-`goose` assists in solving a wide range of programming and operational tasks. It is a live virtual developer you can interact with, guide, and learn from. -To solve problems, `goose` breaks down instructions into sequences of tasks and carries them out using tools. Its ability to connect its changes with real outcomes (e.g. errors) and course correct is its most powerful and exciting feature. `goose` is free open source software and is built to be extensible and customizable. -![goose_demo](https://github.com/user-attachments/assets/0794eaba-97ab-40ef-af64-6fc7f68eb8e2) +

+Unique features 🤖 • + Block Employees on Goose Block Emoji • +Quick start guide 🚀 • +Getting involved! 👋 +> [!TIP] +> **Quick install:** +> ``` +> pipx install goose-ai +> ``` +**Goose** is a developer agent that supercharges your software development by automating an array of coding tasks directly within your terminal or IDE. Guided by you, it can intelligently assess your project's needs, generate the required code or modifications, and implement these changes on its own. Goose can **interact with a multitude of tools via external APIs** such as Jira, GitHub, Slack, infrastructure and data pipelines, and more -- if your task uses a **shell command or can be carried out by a Python script, Goose can do it for you too!** Like semi-autonomous driving, Goose handles the heavy lifting, allowing you to focus on other priorities. Simply set it on a task and return later to find it completed, boosting your productivity with less manual effort. -## Usage -### Installation +

+

-To install `goose`, we recommend `pipx` -First make sure you've [installed pipx][pipx] - for example -``` sh -brew install pipx -pipx ensurepath -``` +## Unique Features of Goose Compared to Other AI Assistants -Then you can install `goose` with +- **Autonomy**: A copilot should be able to also fly the plane at times, which in the development world means running code, debugging tests, installing dependencies, not just providing text output and autocomplete or search. Goose moves beyond just generating code snippets by (1) **using the shell** and (2) by seeing what happens with the code it writes and starting a feedback loop to solve harder problems, **refining solutions iteratively like a human developer**. Your code's best wingman. -```sh -pipx install goose-ai -``` -#### IDEs -There is an early version of a VS Code extension with goose support you can try here: https://github.com/square/goose-vscode - more to come soon. +- **Extensibility**: Open-source and fully customizable, Goose integrates with your workflow and allows you to extend it for even more control. **Toolkits let you add new capabilities to Goose.** They are anything you can implement as a Python function (e.g. API requests, deployments, search, etc). We have a growing library of toolkits to use, but more importantly you can create your own. This gives Goose the ability to run these commands and decide if and when a tool is needed to complete your request! **Creating your own toolkits give you a way to bring your own private context into Goose's capabilities.** And you can use *any* LLM you want under the hood, as long as it supports tool use. -### LLM provider access setup -`goose` works on top of LLMs (you need to bring your own LLM). By default, `goose` uses `openai` as LLM provider. You need to set OPENAI_API_KEY as an environment variable if you would like to use `openai`. -```sh -export OPENAI_API_KEY=your_open_api_key -``` +## What Block employees have to say about Goose -Otherwise, please refer Configuration to customise `goose` +> With Goose, I feel like I am Maverick. +> +> Thanks a ton for creating this. 🙏 +> I have been having way too much fun with it today. -### Start `goose` session -From your terminal, navigate to the directory you'd like to start from and run: -```sh -goose session start -``` +-- P, Machine Learning Engineer -You will see a prompt `G❯`: -``` -G❯ type your instructions here exactly as you would tell a developer. -``` -Now you are interact with `goose` in conversational sessions - something like a natural language driven code interpreter. -The default toolkit lets it take actions through shell commands and file edits. -You can interrupt `goose` at any time to help redirect its efforts. +> I wanted to construct some fake data for an API with a large request body and business rules I haven't memorized. So I told Goose which object to update and a test to run that calls the vendor. Got it to use the errors descriptions from the vendor response to keep correcting the request until it was successful. So good! -### Exit `goose` session -If you are looking to exit, use `CTRL+D`, although `goose` should help you figure that out if you forget. See below for some examples. +-- J, Software Engineer -### Resume `goose` session -When you exit a session, it will save the history in `~/.config/goose/sessions` directory and you can resume it later on: +> I asked Goose to write up a few Google Scripts that mimic Clockwise's functionality (particularly, creating blocks on my work calendar based on events in my personal calendar, as well as color-coding calendar entries based on type and importance). Took me under an hour. If you haven't tried Goose yet, I highly encourage you to do so! -``` sh -goose session resume -``` +-- M, Software Engineer -## Configuration -`goose` can detect what LLM and toolkits it can work with from the configuration file `~/.config/goose/profiles.yaml` automatically. +> If anyone was looking for another reason to check it out: I just asked Goose to break a string-array into individual string resources across eleven localizations, and it performed amazingly well and saved me a bunch of time doing it manually or figuring out some way to semi-automate it. -### Configuration options -Example: +-- A, Android Engineer -```yaml -default: - provider: openai - processor: gpt-4o - accelerator: gpt-4o-mini - moderator: truncate - toolkits: - - name: developer - requires: {} - - name: screen - requires: {} -``` -You can edit this configuration file to use different LLMs and toolkits in `goose`. `goose can also be extended to support any LLM or combination of LLMs +> Hi team, thank you for much for making Goose, it's so amazing. Our team is working on migrating Dashboard components to React components. I am working with Goose to help the migration. -#### provider -Provider of LLM. LLM providers that currently are supported by `goose` (more can be supported by plugins): +-- K, Software Engineer -| Provider | Required environment variable(s) to access provider | -| :----- | :------------------------------ | -| openai | `OPENAI_API_KEY` | -| anthropic | `ANTHROPIC_API_KEY` | -| databricks | `DATABRICKS_HOST` and `DATABRICKS_TOKEN` | -| ollama * | `OLLAMA_HOST` and ollama running | -* ollama is for local LLMs, and is limited by the tool calling model you can choose and run on local hardware, considered experimental. +> Got Goose to update a dependency, run tests, make a branch and a commit... it was 🤌. Not that complicated but I was impressed it figured out how to run tests from the README. -#### processor -Model for complex, multi-step tasks such as writing code and executing commands. Example: `gpt-4o`. You should choose the model based the provider you configured. +-- J, Software Engineer -#### accelerator -Small model for fast, lightweight tasks. Example: `gpt-4o-mini`. You should choose the model based the provider you configured. -#### moderator -Rules designed to control or manage the output of the model. Moderators that currently are supported by `goose`: +> Wanted to document what I had Goose do -- took about 30 minutes end to end! I created a custom CLI command in the `gh CLI` library to download in-line comments on PRs about code changes (currently they aren't directly viewable). I don't know Go *that well* and I definitely didn't know where to start looking in the code base or how to even test the new command was working and Goose did it all for me 😁 -- `passive`: does not actively intervene in every response -- `truncate`: truncates the first contexts when the contexts exceed the max token size +-- L, Software Engineer -#### toolkits -`goose` can be extended with toolkits, and out of the box there are some available: +> Hi Team, just wanted to share my experience of using Goose as a non-engineer! ... I just asked Goose to ensure that my environment is up to date and copied over a guide into my prompt. Goose managed everything flawlessly, keeping me informed at every step... I was truly impressed with how well it works and how easy it was to get started! 😍 -* `developer`: for general-purpose development capabilities, including plan management, shell execution, and file operations, with default shell strategies like using ripgrep. -* `screen`: for letting goose take a look at your screen to help debug or work on designs (gives goose eyes) -* `github`: for awareness and suggestions on how to use github -* `repo_context`: for summarizing and understanding a repository you are working in. -* `jira`: for working with JIRA (issues, backlogs, tasks, bugs etc) +-- M, Product Manager +**See more of our use-cases in our [docs][use-cases]!** -#### Configuring goose per repo +## Quick start guide -If you are using the `developer` toolkit, `goose` adds the content from `.goosehints` - file in working directory to the system prompt of the `developer` toolkit. The hints -file is meant to provide additional context about your project. The context can be -user-specific or at the project level in which case, you -can commit it to git. `.goosehints` file is Jinja templated so you could have something -like this: -``` -Here is an overview of how to contribute: -{% include 'CONTRIBUTING.md' %} +### Installation -The following justfile shows our common commands: -```just -{% include 'justfile' %} +To install Goose, use `pipx`. First ensure [pipx][pipx] is installed: + +``` sh +brew install pipx +pipx ensurepath ``` -### Examples -#### provider as `anthropic` +Then install Goose: -```yaml -default: - provider: anthropic - processor: claude-3-5-sonnet-20240620 - accelerator: claude-3-5-sonnet-20240620 -... -``` -#### provider as `databricks` -```yaml -default: - provider: databricks - processor: databricks-meta-llama-3-1-70b-instruct - accelerator: databricks-meta-llama-3-1-70b-instruct - moderator: passive - toolkits: - - name: developer - requires: {} +```sh +pipx install goose-ai ``` -## Tips - -Here are some collected tips we have for working efficiently with `goose` +### Running Goose -- **`goose` can and will edit files**. Use a git strategy to avoid losing anything - such as staging your - personal edits and leaving `goose` edits unstaged until reviewed. Or consider using individual commits which can be reverted. -- **`goose` can and will run commands**. You can ask it to check with you first if you are concerned. It will check commands for safety as well. -- You can interrupt `goose` with `CTRL+C` to correct it or give it more info. -- `goose` works best when solving concrete problems - experiment with how far you need to break that problem - down to get `goose` to solve it. Be specific! E.g. it will likely fail to `"create a banking app"`, - but probably does a good job if prompted with `"create a Fastapi app with an endpoint for deposit and withdrawal - and with account balances stored in mysql keyed by id"` -- If `goose` doesn't have enough context to start with, it might go down the wrong direction. Tell it - to read files that you are referring to or search for objects in code. Even better, ask it to summarize - them for you, which will help it set up its own next steps. -- Refer to any objects in files with something that is easy to search for, such as `"the MyExample class" -- `goose` *loves* to know how to run tests to get a feedback loop going, just like you do. If you tell it how you test things locally and quickly, it can make use of that when working on your project -- You can use `goose` for tasks that would require scripting at times, even looking at your screen and correcting designs/helping you fix bugs, try asking it to help you in a way you would ask a person. -- `goose` will make mistakes, and go in the wrong direction from times, feel free to correct it, or start again. -- You can tell `goose` to run things for you continuously (and it will iterate, try, retry) but you can also tell it to check with you before doing things (and then later on tell it to go off on its own and do its best to solve). -- `goose` can run anywhere, doesn't have to be in a repo, just ask it! +#### Start a session +From your terminal, navigate to the directory you'd like to start from and run: -### Examples +```sh +goose session start +``` -Here are some examples that have been used: +You will see the Goose prompt `G❯`: ``` -G❯ Looking at the in progress changes in this repo, help me finish off the feature. CONTRIBUTING.md shows how to run the tests. +G❯ type your instructions here exactly as you would tell a developer. ``` -``` -G❯ In this golang project, I want you to add open telemetry to help me get started with it. Look in the moneymovements module, run the `just test` command to check things work. -``` +Now you are interacting with Goose in conversational sessions - something like a natural language driven code interpreter. The default toolkit allows Goose to take actions through shell commands and file edits. You can interrupt Goose with `CTRL+D` or `ESC+Enter` at any time to help redirect its efforts. -``` -G❯ This project uses an old version of jooq. Upgrade to the latest version, and ensure there are no incompatibilities by running all tests. Dependency versions are in gradle/libs.versions.toml and to run gradle, use the binary located in bin/gradle -``` +#### Exit the session -``` -G❯ This is a fresh checkout of a golang project. I do not have my golang environment set up. Set it up and run tests for this project, and ensure they pass. Use the zookeeper jar included in this repository rather than installing zookeeper via brew. -``` +If you are looking to exit, use `CTRL+D`, although Goose should help you figure that out if you forget. -``` -G❯ In this repo, I want you to look at how to add a new provider for azure. -Some hints are in this github issue: https://github.com/square/exchange/issues -/4 (you can use gh cli to access it). -``` +#### Resume a session -``` -G❯ I want you to help me increase the test coverage in src/java... use mvn test to run the unit tests to check it works. +When you exit a session, it will save the history in `~/.config/goose/sessions` directory and you can resume it later on: + +``` sh +goose session resume ``` -## FAQ +To see more documentation on the CLI commands currently available to Goose check out the documentation [here][cli]. If you’d like to develop your own CLI commands for Goose, check out the [Contributing document][contributing]. -**Q:** Why did I get error message of "The model `gpt-4o` does not exist or you do not have access to it.` when I talked goose? +### Next steps -**A:** You can find out the LLM provider and models in the configuration file `~/.config/goose/profiles.yaml` here to check whether your LLM provider account has access to the models. For example, after you have made a successful payment of $5 or more (usage tier 1), you'll be able to access the GPT-4, GPT-4 Turbo, GPT-4o models via the OpenAI API. [How can I access GPT-4, GPT-4 Turbo, GPT-4o, and GPT-4o mini?](https://help.openai.com/en/articles/7102672-how-can-i-access-gpt-4-gpt-4-turbo-gpt-4o-and-gpt-4o-mini). +Learn how to modify your Goose profiles.yaml file to add and remove functionality (toolkits) and providing context to get the most out of Goose in our [Getting Started Guide][getting-started]. -## Open Source +**Want to move out of the terminal and into an IDE?** -Yes, `goose` is open source and always will be. `goose` is released under the ASL2.0 license meaning you can use it however you like. -See LICENSE.md for more details. +We have some experimental IDE integrations for VSCode and JetBrains IDEs: +* https://github.com/square/goose-vscode +* https://github.com/Kvadratni/goose-intellij -To run `goose` from source, please see `CONTRIBUTING.md` for instructions on how to set up your environment and you can then run `uv run `goose` session start`. +## Getting involved! +There is a lot to do! If you're interested in contributing, a great place to start is picking a `good-first-issue`-labelled ticket from our [issues list][gh-issues]. More details on how to develop Goose can be found in our [Contributing Guide][contributing]. We are a friendly, collaborative group and look forward to working together![^1] + + +Check out and contribute to more experimental features in [Goose Plugins][goose-plugins]! + +Let us know what you think in our [Discussions][discussions] or the [**`#goose`** channel on Discord][goose-channel]. + +[^1]: Yes, Goose is open source and always will be. Goose is released under the ASL2.0 license meaning you are free to use it however you like. See [LICENSE.md][license] for more details. + + + +[goose-plugins]: https://github.com/block-open-source/goose-plugins [pipx]: https://github.com/pypa/pipx?tab=readme-ov-file#install-pipx +[contributing]: CONTRIBUTING.md +[license]: LICENSE.md + +[goose-docs]: https://block-open-source.github.io/goose/ +[toolkits]: https://block-open-source.github.io/goose/plugins/available-toolkits.html +[configuration]: https://block-open-source.github.io/goose/configuration.html +[cli]: https://block-open-source.github.io/goose/plugins/cli.html +[providers]: https://block-open-source.github.io/goose/providers.html +[use-cases]: https://block-open-source.github.io/goose/guidance/applications.html +[getting-started]: https://block-open-source.github.io/goose/guidance/getting-started.html + +[discord-invite]: https://discord.gg/7GaTvbDwga +[gh-issues]: https://github.com/block-open-source/goose/issues +[van-code]: https://github.com/block-open-source/goose-plugins/blob/de98cd6c29f8e7cd3b6ace26535f24ac57c9effa/src/goose_plugins/toolkits/artify.py +[discussions]: https://github.com/block-open-source/goose/discussions +[goose-channel]: https://discord.com/channels/1287729918100246654/1287729920319033345 +[goose-ai-pypi]: https://pypi.org/project/goose-ai/ + + diff --git a/docs/docs/assets/bg.png b/docs/assets/bg.png similarity index 100% rename from docs/docs/assets/bg.png rename to docs/assets/bg.png diff --git a/docs/docs/assets/bg2.png b/docs/assets/bg2.png similarity index 100% rename from docs/docs/assets/bg2.png rename to docs/assets/bg2.png diff --git a/docs/docs/assets/bg3.png b/docs/assets/bg3.png similarity index 100% rename from docs/docs/assets/bg3.png rename to docs/assets/bg3.png diff --git a/docs/docs/assets/bg4.png b/docs/assets/bg4.png similarity index 100% rename from docs/docs/assets/bg4.png rename to docs/assets/bg4.png diff --git a/docs/docs/assets/docs.css b/docs/assets/docs.css similarity index 100% rename from docs/docs/assets/docs.css rename to docs/assets/docs.css diff --git a/docs/docs/assets/docs.js b/docs/assets/docs.js similarity index 100% rename from docs/docs/assets/docs.js rename to docs/assets/docs.js diff --git a/docs/assets/goose-in-action.gif b/docs/assets/goose-in-action.gif new file mode 100644 index 000000000..bd4d71831 Binary files /dev/null and b/docs/assets/goose-in-action.gif differ diff --git a/docs/assets/goose-in-action.mp4 b/docs/assets/goose-in-action.mp4 new file mode 100644 index 000000000..83f3270e8 Binary files /dev/null and b/docs/assets/goose-in-action.mp4 differ diff --git a/docs/assets/goose.png b/docs/assets/goose.png new file mode 100644 index 000000000..6c9e8e9ef Binary files /dev/null and b/docs/assets/goose.png differ diff --git a/docs/docs/assets/logo.gif b/docs/assets/logo.gif similarity index 100% rename from docs/docs/assets/logo.gif rename to docs/assets/logo.gif diff --git a/docs/docs/assets/logo.ico b/docs/assets/logo.ico similarity index 100% rename from docs/docs/assets/logo.ico rename to docs/assets/logo.ico diff --git a/docs/docs/assets/logo.png b/docs/assets/logo.png similarity index 100% rename from docs/docs/assets/logo.png rename to docs/assets/logo.png diff --git a/docs/docs/configuration.md b/docs/configuration.md similarity index 99% rename from docs/docs/configuration.md rename to docs/configuration.md index c30668645..4e7d81f26 100644 --- a/docs/docs/configuration.md +++ b/docs/configuration.md @@ -1,47 +1,5 @@ # Configuring Goose -## Adding a toolkit -To make a toolkit available to Goose, add it to your project's pyproject.toml. For example in the Goose pyproject.toml file: -``` -[project.entry-points."goose.toolkit"] -developer = "goose.toolkit.developer:Developer" -github = "goose.toolkit.github:Github" -# Add a line like this - the key becomes the name used in profiles -my-new-toolkit = "goose.toolkit.my_toolkits:MyNewToolkit" # this is the path to the class that implements the toolkit -``` - -Then to set up a profile that uses it, add something to `~/.config/goose/profiles.yaml`: -```yaml -my-profile: - provider: openai - processor: gpt-4o - accelerator: gpt-4o-mini - moderator: passive - toolkits: # new toolkit gets added here - - developer - - my-new-toolkit -``` - -And now you can run Goose with this new profile to use the new toolkit! - -```sh -goose session start --profile my-profile -``` - -Or, if you're developing a new toolkit and want to test it: -```sh -uv run goose session start --profile my-profile -``` - -## Tuning it to your repo - -Goose ships with the ability to read in the contents of a file named `.goosehints` from your repo. If you find yourself repeating the same information across sessions to Goose, this file is the right place to add this information. - -This file will be read into the Goose system prompt if it is present in the current working directory. - -> [!NOTE] -> `.goosehints` follows [jinja templating rules][jinja-guide] in case you want to leverage templating to insert file contents or variables. - ## Profiles If you need to customize goose, one way is via editing: `~/.config/goose/profiles.yaml`. @@ -146,3 +104,46 @@ unit-test-gen: ``` [jinja-guide]: https://jinja.palletsprojects.com/en/3.1.x/ + + +## Adding a toolkit +To make a toolkit available to Goose, add it to your project's pyproject.toml. For example in the Goose pyproject.toml file: +``` +[project.entry-points."goose.toolkit"] +developer = "goose.toolkit.developer:Developer" +github = "goose.toolkit.github:Github" +# Add a line like this - the key becomes the name used in profiles +my-new-toolkit = "goose.toolkit.my_toolkits:MyNewToolkit" # this is the path to the class that implements the toolkit +``` + +Then to set up a profile that uses it, add something to `~/.config/goose/profiles.yaml`: +```yaml +my-profile: + provider: openai + processor: gpt-4o + accelerator: gpt-4o-mini + moderator: passive + toolkits: # new toolkit gets added here + - developer + - my-new-toolkit +``` + +And now you can run Goose with this new profile to use the new toolkit! + +```sh +goose session start --profile my-profile +``` + +Or, if you're developing a new toolkit and want to test it: +```sh +uv run goose session start --profile my-profile +``` + +## Tuning Goose to your repo + +Goose ships with the ability to read in the contents of a file named `.goosehints` from your repo. If you find yourself repeating the same information across sessions to Goose, this file is the right place to add this information. + +This file will be read into the Goose system prompt if it is present in the current working directory. + +> [!NOTE] +> `.goosehints` follows [jinja templating rules][jinja-guide] in case you want to leverage templating to insert file contents or variables. \ No newline at end of file diff --git a/docs/contributing.md b/docs/contributing.md new file mode 120000 index 000000000..44fcc6343 --- /dev/null +++ b/docs/contributing.md @@ -0,0 +1 @@ +../CONTRIBUTING.md \ No newline at end of file diff --git a/docs/docs/css/code_select.css b/docs/css/code_select.css similarity index 100% rename from docs/docs/css/code_select.css rename to docs/css/code_select.css diff --git a/docs/docs/contributing.md b/docs/docs/contributing.md deleted file mode 120000 index f939e75f2..000000000 --- a/docs/docs/contributing.md +++ /dev/null @@ -1 +0,0 @@ -../../CONTRIBUTING.md \ No newline at end of file diff --git a/docs/docs/index.md b/docs/docs/index.md deleted file mode 100644 index b2b993a6a..000000000 --- a/docs/docs/index.md +++ /dev/null @@ -1,18 +0,0 @@ -# Goose - -Github: [`square/goose`][square/goose] - - -### goose -* PyPi package name: [`goose-ai`][goose-ai] -* GitHub: [square/goose] - -### exchange -* PyPi package name: [`ai-exchange`][ai-exchange] -* GitHub: [square/exchange] - -[goose-ai]: https://pypi.org/project/goose-ai/ -[square/goose]: https://github.com/square/goose -[ai-exchange]: https://pypi.org/project/ai-exchange/ -[square/exchange]: https://github.com/square/exchange -[install]: installation.md diff --git a/docs/docs/providers.md b/docs/docs/providers.md deleted file mode 100644 index aab25c5ed..000000000 --- a/docs/docs/providers.md +++ /dev/null @@ -1,3 +0,0 @@ -# Providers - -Providers in Goose mean "LLM providers" that Goose can interact with. Providers are defined in the Exchange library for the most part, but you can define your own. \ No newline at end of file diff --git a/docs/docs/tips.md b/docs/docs/tips.md deleted file mode 100644 index d07bac48c..000000000 --- a/docs/docs/tips.md +++ /dev/null @@ -1,20 +0,0 @@ -## tips - -Here are some collected tips we have for working efficiently with `goose` - -- **`goose` can and will edit files**. Use a git strategy to avoid losing anything - such as staging your -personal edits and leaving `goose` edits unstaged until reviewed. Or consider using individual commits which can be reverted. -- **`goose` can and will run commands**. You can ask it to check with you first if you are concerned. It will check commands for safety as well. -- You can interrupt `goose` with `CTRL+C` to correct it or give it more info. -- `goose` works best when solving concrete problems - experiment with how far you need to break that problem -down to get `goose` to solve it. Be specific! E.g. it will likely fail to `"create a banking app"`, -but probably does a good job if prompted with `"create a Fastapi app with an endpoint for deposit and withdrawal and with account balances stored in mysql keyed by id"` -- If `goose` doesn't have enough context to start with, it might go down the wrong direction. Tell it -to read files that you are referring to or search for objects in code. Even better, ask it to summarize -them for you, which will help it set up its own next steps. -- Refer to any objects in files with something that is easy to search for, such as `"the MyExample class" -- `goose` *loves* to know how to run tests to get a feedback loop going, just like you do. If you tell it how you test things locally and quickly, it can make use of that when working on your project -- You can use `goose` for tasks that would require scripting at times, even looking at your screen and correcting designs/helping you fix bugs, try asking it to help you in a way you would ask a person. -- `goose` will make mistakes, and go in the wrong direction from times, feel free to correct it, or start again. -- You can tell `goose` to run things for you continuously (and it will iterate, try, retry) but you can also tell it to check with you before doing things (and then later on tell it to go off on its own and do its best to solve). -- `goose` can run anywhere, doesn't have to be in a repo, just ask it! \ No newline at end of file diff --git a/docs/docs/toolkits.md b/docs/docs/toolkits.md deleted file mode 100644 index a308d6074..000000000 --- a/docs/docs/toolkits.md +++ /dev/null @@ -1,202 +0,0 @@ -# Toolkits - -This page contains information about building and using toolkits in Goose. Toolkits are a way to extend Goose's capabilities by adding new tools and functionalities. You can create your own toolkits or use the existing ones provided by Goose. - -## Using Toolkits - -Use `goose toolkit list` to list the available toolkits. - -### Toolkits defined in Goose - -Using Goose with toolkits is simple. You can add toolkits to your profile in the `profiles.yaml` file. Here's an example of how to add `my-toolkit` toolkit to your profile: - -```yaml -my-profile: - provider: openai - processor: gpt-4o - accelerator: gpt-4o-mini - moderator: passive - toolkits: - - my-toolkit -``` - -Then run Goose with the specified profile: - -```sh -goose session start --profile my-profile -``` - -### Toolkits defined in Goose Plugins - -1. First make sure that `goose-plugins` is intalled with Goose: -```sh -pipx install goose-ai --preinstall goose-plugins -``` -2. Update the `profiles.yaml` file to include the desired toolkit: -```yaml -my-profile: - provider: openai - processor: gpt-4o - accelerator: gpt-4o-mini - moderator: passive - toolkits: - - my-goose-plugins-toolkit -``` - -## Building a Toolkit - -To add a toolkit, in your code (which doesn't necessarily need to be in the Goose package thanks to [plugin metadata][plugin]!), create a class that derives from the `Toolkit` class. - -### Example toolkit class -Below is an example of a simple toolkit called `Demo` that derives from the `Toolkit` class. This toolkit provides an `authenticate` tool that outputs an authentication code for a user. It also provides system instructions for the model. -```python -import os -import platform - -from goose.toolkit.base import Toolkit, tool - - -class Demo(Toolkit): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - # Provide any additional tools as needed! - # The docstring of the tool provides instructions to the LLM, so they are important to tune - # you do not have to provide any tools, but any function decorated with @tool will be available - @tool - def authenticate(self, user: str): - """Output an authentication code for this user - - Args: - user (str): The username to authenticate for - """ - # notifier supports any rich renderable https://rich.readthedocs.io/en/stable/introduction.html#quick-start - self.notifier.log(f"[bold red]auth: {str(hash(user))}[/]") - - # Provide any system instructions for the model - # This can be generated dynamically, and is run at startup time - def system(self) -> str: - print("new") - return f"""**You must preceed your first message by using the authenticate tool for the current user** - - ``` - platform: {platform.system()} - cwd: {os.getcwd()} - user: {os.environ.get('USER')} - ``` - """ -``` - -### Exposing the new toolkit to Goose - -To make the toolkit available, add it to the `pyproject.toml` file and then update your `profiles.yaml` file. - -#### Update the `pyproject.toml` file -If you're adding the new toolkit to Goose or the Goose Plugins repo, simply find the `[project.entry-points."goose.toolkit"]` section in `pyproject.toml` and add a line like this: -```toml -[project.entry-points."goose.toolkit"] -developer = "goose.toolkit.developer:Developer" -github = "goose.toolkit.github:Github" -# Add a line like this - the key becomes the name used in profiles -demo = "goose.toolkit.demo:Demo" -``` - -If you are adding the toolkit to a different package, see the docs for `goose-plugins` for more information on how to create a plugins repository that can be used by Goose. - -#### Update the `profiles.yaml` file -And then to set up a profile that uses it, add something to ~/.config/goose/profiles.yaml -```yaml -default: - provider: openai - processor: gpt-4o - accelerator: gpt-4o-mini - moderator: passive - toolkits: - - name: developer - requires: {} -demo: - provider: openai - processor: gpt-4o - accelerator: gpt-4o-mini - moderator: passive - toolkits: - - developer - - demo -``` - -And now you can run goose with this new profile to use the new toolkit! - -```sh -goose session start --profile demo -``` - -> [!NOTE] -> If you're using a plugin from `goose-plugins`, make sure `goose-plugins` is installed in your environment. You can install it via pip: -> -> `pipx install goose-ai --preinstall goose-plugins` - -## Available Toolkits in Goose - -To see the available toolkits to you, run `goose toolkit list`, this will show the toolkits defined below as well as any other Goose modules you have installed (for example, `goose-plugins`). - -Goose provides a variety of toolkits designed to help developers with different tasks. Here's an overview of each available toolkit and its functionalities: - -### 1. Developer Toolkit - -The **Developer** toolkit offers general-purpose development capabilities, including: - -- **System Configuration Details:** Retrieves system configuration details. -- **Task Management:** Update the plan by overwriting all current tasks. -- **File Operations:** - - `patch_file`: Patch a file by replacing specific content. - - `read_file`: Read the content of a specified file. - - `write_file`: Write content to a specified file. -- **Shell Command Execution:** Execute shell commands with safety checks. - -### 2. GitHub Toolkit - -The **GitHub** toolkit provides detailed configuration and procedural guidelines for GitHub operations. - -### 3. Lint Toolkit - -The **Lint** toolkit ensures that all toolkits have proper documentation. It performs the following checks: - -- Toolkit must have a docstring. -- The first line of the docstring should contain more than 5 words and fewer than 12 words. -- The first letter of the docstring should be capitalized. - -### 4. RepoContext Toolkit - -The **RepoContext** toolkit provides context about the current repository. It includes: - -- **Repository Size:** Get the size of the repository. -- **Monorepo Check:** Determine if the repository is a monorepo. -- **Project Summarization:** Summarize the current project based on the repository or the current project directory. - -### 5. Screen Toolkit - -The **Screen** toolkit assists users in taking screenshots for debugging or designing purposes. It provides: - -- **Take Screenshot:** Capture a screenshot and provide the path to the screenshot file. -- **System Instructions:** Instructions on how to work with screenshots. - -### 6. SummarizeRepo Toolkit - -The **SummarizeRepo** toolkit helps in summarizing a repository. It includes: - -- **Summarize Repository:** Clone the repository (if not already cloned) and summarize the files based on specified extensions. - -### 7. SummarizeProject Toolkit - -The **SummarizeProject** toolkit generates or retrieves a summary of a project directory based on specified file extensions. It includes: - -- **Get Project Summary:** Generate or retrieve a summary of the project in the specified directory. - -### 8. SummarizeFile Toolkit - -The **SummarizeFile** toolkit helps in summarizing a specific file. It includes: - -- **Summarize File:** Summarize the contents of a specified file with optional instructions. - -[plugin]: https://packaging.python.org/en/latest/guides/creating-and-discovering-plugins/#using-package-metadata -[goose-plugins]: https://github.com/square/goose-plugins diff --git a/docs/guidance/applications.md b/docs/guidance/applications.md new file mode 100644 index 000000000..9f974d9f7 --- /dev/null +++ b/docs/guidance/applications.md @@ -0,0 +1,15 @@ +## Uses of Goose so Far + +We've been using Goose to help us with a variety of tasks. Here are some examples: + +- Conduct code migrations like: + - Ember to React + - Ruby to Kotlin + - Prefect-1 to Prefect-2 +- Dive into a new project in an unfamiliar coding language +- Transition a code-base from field-based injection to constructor-based injection in a dependency injection framework +- Conduct performance benchmarks for a build command using a build automation tool +- Increasing code coverage above a specific threshold +- Scaffolding an API for data retention +- Creating Datadog monitors +- Removing or adding feature flags diff --git a/docs/guidance/getting-started.md b/docs/guidance/getting-started.md new file mode 100644 index 000000000..eeaf5fed4 --- /dev/null +++ b/docs/guidance/getting-started.md @@ -0,0 +1,140 @@ +# Your first run with Goose + +This page contains two sections that will help you get started with Goose: + +1. [Configuring Goose with the `profiles.yaml` file](#configuring-goose-with-the-profilesyaml-file): how to set up Goose with the right LLMs and toolkits. +2. [Working with Goose](#working-with-goose): how to guide Goose through a task, and how to provide context for Goose to work with. + +## Configuring Goose with the `profiles.yaml` file +On the first run, Goose will detect what LLMs are available from your environment, and generate a configuration file at `~/.config/goose/profiles.yaml`. You can edit those profiles to further configure goose. + +Here’s what the default `profiles.yaml` could look like if Goose detects an OpenAI API key: + +```yaml +default: + provider: openai + processor: gpt-4o + accelerator: gpt-4o-mini + moderator: truncate + toolkits: + - name: developer + requires: {} +``` + +You can edit this configuration file to use different LLMs and toolkits in Goose. Check out the [configuration docs][configuration] to better understand the different fields of the `profiles.yaml` file! You can add new profiles with different settings to change how goose works from one section to the next - use `goose session start --profile {profile}` to select which to use. + +### LLM provider access setup + +Goose works on top of LLMs. You'll need to configure one before using it. By default, Goose uses `openai` as the LLM provider but you can customize it as needed. You need to set OPENAI_API_KEY as an environment variable if you would like to use `openai`. + +To learn more about providers and modes of access, check out the [provider docs][providers]. +```sh +export OPENAI_API_KEY=your_open_api_key +``` + +## Working with Goose + +Goose works best with some amount of context or instructions for a given task. You can guide goose through gathering the context it needs by giving it instructions or asking it to explore with its tools. But to make this easier, context in Goose can be extended a few additional ways: + +1. User-directed input +2. A `.goosehints` file +3. Toolkits +4. Plans + +### User-directed input + +Directing Goose to read a specific file before requesting changes ensures that the file's contents are loaded into its operational context. Similarly, asking Goose to summarize the current project before initiating changes across multiple files provides a detailed overview of the project structure, including the locations of specific classes, functions, and other components. + +### `.goosehints` + +If you are using the `developer` toolkit, `goose` adds the content from `.goosehints` file in the working directory to the system prompt. The hints file is meant to provide additional context about your project. The context can be user-specific or at the project level in which case, you can commit it to git. `.goosehints` file is Jinja templated so you could have something like this: + +``` +Here is an overview of how to contribute: +{% include 'CONTRIBUTING.md' %} + +The following justfile shows our common commands: +{% include 'justfile' %} + +Write all code comments in French +``` + +### Toolkits + +Toolkits expand Goose’s capabilities and tailor its functionality to specific development tasks. Toolkits provide Goose with additional contextual information and interactive abilities, allowing for a more comprehensive and efficient workflow. + +Here are some out-of-the-box examples: + +* `developer`: for general-purpose development capabilities, including plan management, shell execution, and file operations, with default shell strategies like using ripgrep. +* `screen`: for letting goose take a look at your screen to help debug or work on designs (gives goose eyes) +* `github`: for suggestions on how to use Github +* `repo_context`: for summarizing and understanding a repository you are working in. +* `jira`: for working with JIRA (issues, backlogs, tasks, bugs etc.) + +You can see the current toolkits available to Goose [here][available-toolkits]. There's also a [public plugins repository where toolkits are defined][goose-plugins] for Goose that has toolkits you can try out. + +### Plans + +Goose creates plans for itself to execute to achieve its goals. In some cases, you may already have a plan in mind for Goose — this is where you can define your own `plan.md` file, and it will set the first message and also hard code Goose's initial plan. + +The plan.md file can be text in any format and uses `jinja` templating, and the last group of lines that start with “-” will be considered the plan. + +Here are some examples: + +#### Basic example plan + +```md +Your goal is to refactor this fastapi application to use a sqlite database. Use `pytest -s -v -x` to run the tests when needed. + +- Use ripgrep to find the fastapi app and its tests in this directory +- read the files you found +- Add sqlalchemy and alembic as dependencies with poetry +- Run alembic init to set up the basic configuration +- Add sqlite dependency with Poetry +- Create new module for database code and include sqlalchemy and alembic setup +- Define an accounts table with SQLAlchemy +- Implement CRUD operations for accounts table +- Update main.py to integrate with SQLite database and use CRUD operation +- Use alembic to create the table +- Use conftest to set up a test database with a new DB URL +- Run existing test suite and ensure all tests pass. Do not edit the test case behavior, instead use tests to find issues. +``` + +The starting plan is specified with the tasks. Each list entry is a different step in the plan. This is a pretty detailed set of tasks, but is really just a break-down of the conversation we had in the previous section. + +The kickoff message is what gets set as the first user message when goose starts running (with the plan). This message should contain the overall goal of the tasks and could also contain extra context you want to include for this problem. In our case, we are just mentioning the test command we want to use to run the tests. + +To run Goose with this plan: + +``` sh +goose session start --plan plan.md +``` + +#### Injecting arguments into a plan + +You can also inject arguments into your plan. `plan.md` files can be templated with `jinja` and can include variables that are passed in when you start the session. + +The kickoff message gives Goose directions to use poetry and a dependency, and then a plan is to open a file, run a test, and set up a repo: + +```md +Here is the python repo + +- use {{ dep }} +- use poetry + +Here is the plan: + +- Open a file +- Run a test +- Set up {{ repo }} +``` + +To run Goose with this plan with the arguments `dep=pytest,repo=github`, you would run the following command: + +```sh +goose session start --plan plan.md --args dep=pytest,repo=github +``` + +[configuration]: ../configuration.md +[available-toolkits]: ../plugins/available-toolkits.md +[providers]: ../plugins/providers.md \ No newline at end of file diff --git a/docs/guidance/tips.md b/docs/guidance/tips.md new file mode 100644 index 000000000..edd827fae --- /dev/null +++ b/docs/guidance/tips.md @@ -0,0 +1,20 @@ +## Tips for working with Goose: + +Here are some collected tips we have for working efficiently with Goose + +- **Goose can and will edit files**. Use a git strategy to avoid losing anything - such as staging your +personal edits and leaving Goose edits unstaged until reviewed. Or consider using individual commits which can be reverted. +- **Goose can and will run commands**. You can ask it to check with you first if you are concerned. It will check commands for safety as well. +- You can interrupt Goose with `CTRL+C` to correct it or give it more info. +- Goose works best when solving concrete problems - experiment with how far you need to break that problem +down to get Goose to solve it. Be specific! E.g. it will likely fail to `"create a banking app"`, +but probably does a good job if prompted with `"create a Fastapi app with an endpoint for deposit and withdrawal and with account balances stored in mysql keyed by id"` +- If Goose doesn't have enough context to start with, it might go down the wrong direction. Tell it +to read files that you are referring to or search for objects in code. Even better, ask it to summarize +them for you, which will help it set up its own next steps. +- Refer to any objects in files with something that is easy to search for, such as `"the MyExample class" +- Goose *loves* to know how to run tests to get a feedback loop going, just like you do. If you tell it how you test things locally and quickly, it can make use of that when working on your project +- You can use Goose for tasks that would require scripting at times, even looking at your screen and correcting designs/helping you fix bugs, try asking it to help you in a way you would ask a person. +- Goose will make mistakes, and go in the wrong direction from times, feel free to correct it, or start again. +- You can tell Goose to run things for you continuously (and it will iterate, try, retry) but you can also tell it to check with you before doing things (and then later on tell it to go off on its own and do its best to solve). +- Goose can run anywhere, doesn't have to be in a repo, just ask it! \ No newline at end of file diff --git a/docs/index.md b/docs/index.md new file mode 120000 index 000000000..32d46ee88 --- /dev/null +++ b/docs/index.md @@ -0,0 +1 @@ +../README.md \ No newline at end of file diff --git a/docs/docs/installation.md b/docs/installation.md similarity index 100% rename from docs/docs/installation.md rename to docs/installation.md diff --git a/docs/docs/available-toolkits.md b/docs/plugins/available-toolkits.md similarity index 100% rename from docs/docs/available-toolkits.md rename to docs/plugins/available-toolkits.md diff --git a/docs/docs/cli.md b/docs/plugins/cli.md similarity index 100% rename from docs/docs/cli.md rename to docs/plugins/cli.md diff --git a/docs/docs/creating-a-new-toolkit.md b/docs/plugins/creating-a-new-toolkit.md similarity index 100% rename from docs/docs/creating-a-new-toolkit.md rename to docs/plugins/creating-a-new-toolkit.md diff --git a/docs/docs/plugins.md b/docs/plugins/plugins.md similarity index 100% rename from docs/docs/plugins.md rename to docs/plugins/plugins.md diff --git a/docs/plugins/providers.md b/docs/plugins/providers.md new file mode 100644 index 000000000..fdf09697d --- /dev/null +++ b/docs/plugins/providers.md @@ -0,0 +1,14 @@ +# Providers + +Providers in Goose mean "LLM providers" that Goose can interact with. Providers are defined in the [Exchange library][exchange-providers] for the most part, but you can define your own. + +**Currently available providers:** + +* Anthropic +* Azure +* Bedrock +* Databricks +* Ollama +* OpenAI + +[exchange-providers]: https://github.com/square/exchange/tree/main/src/exchange/providers \ No newline at end of file diff --git a/docs/docs/using-toolkits.md b/docs/plugins/using-toolkits.md similarity index 100% rename from docs/docs/using-toolkits.md rename to docs/plugins/using-toolkits.md diff --git a/docs/reference/goose/build.md b/docs/reference/goose/build.md new file mode 100644 index 000000000..bbeed2811 --- /dev/null +++ b/docs/reference/goose/build.md @@ -0,0 +1 @@ +::: goose.build \ No newline at end of file diff --git a/docs/reference/goose/cli/config.md b/docs/reference/goose/cli/config.md new file mode 100644 index 000000000..daa19236d --- /dev/null +++ b/docs/reference/goose/cli/config.md @@ -0,0 +1 @@ +::: goose.cli.config \ No newline at end of file diff --git a/docs/reference/goose/cli/index.md b/docs/reference/goose/cli/index.md new file mode 100644 index 000000000..90b9e4082 --- /dev/null +++ b/docs/reference/goose/cli/index.md @@ -0,0 +1 @@ +::: goose.cli \ No newline at end of file diff --git a/docs/reference/goose/cli/main.md b/docs/reference/goose/cli/main.md new file mode 100644 index 000000000..03542bff4 --- /dev/null +++ b/docs/reference/goose/cli/main.md @@ -0,0 +1 @@ +::: goose.cli.main \ No newline at end of file diff --git a/docs/reference/goose/cli/prompt/completer.md b/docs/reference/goose/cli/prompt/completer.md new file mode 100644 index 000000000..fd51b520c --- /dev/null +++ b/docs/reference/goose/cli/prompt/completer.md @@ -0,0 +1 @@ +::: goose.cli.prompt.completer \ No newline at end of file diff --git a/docs/reference/goose/cli/prompt/create.md b/docs/reference/goose/cli/prompt/create.md new file mode 100644 index 000000000..9fb517150 --- /dev/null +++ b/docs/reference/goose/cli/prompt/create.md @@ -0,0 +1 @@ +::: goose.cli.prompt.create \ No newline at end of file diff --git a/docs/reference/goose/cli/prompt/goose_prompt_session.md b/docs/reference/goose/cli/prompt/goose_prompt_session.md new file mode 100644 index 000000000..e92b0fa9d --- /dev/null +++ b/docs/reference/goose/cli/prompt/goose_prompt_session.md @@ -0,0 +1 @@ +::: goose.cli.prompt.goose_prompt_session \ No newline at end of file diff --git a/docs/reference/goose/cli/prompt/index.md b/docs/reference/goose/cli/prompt/index.md new file mode 100644 index 000000000..fdcbffd28 --- /dev/null +++ b/docs/reference/goose/cli/prompt/index.md @@ -0,0 +1 @@ +::: goose.cli.prompt \ No newline at end of file diff --git a/docs/reference/goose/cli/prompt/lexer.md b/docs/reference/goose/cli/prompt/lexer.md new file mode 100644 index 000000000..90c2e3ed5 --- /dev/null +++ b/docs/reference/goose/cli/prompt/lexer.md @@ -0,0 +1 @@ +::: goose.cli.prompt.lexer \ No newline at end of file diff --git a/docs/reference/goose/cli/prompt/prompt_validator.md b/docs/reference/goose/cli/prompt/prompt_validator.md new file mode 100644 index 000000000..1f71b5fc5 --- /dev/null +++ b/docs/reference/goose/cli/prompt/prompt_validator.md @@ -0,0 +1 @@ +::: goose.cli.prompt.prompt_validator \ No newline at end of file diff --git a/docs/reference/goose/cli/prompt/user_input.md b/docs/reference/goose/cli/prompt/user_input.md new file mode 100644 index 000000000..12d7d049e --- /dev/null +++ b/docs/reference/goose/cli/prompt/user_input.md @@ -0,0 +1 @@ +::: goose.cli.prompt.user_input \ No newline at end of file diff --git a/docs/reference/goose/cli/session.md b/docs/reference/goose/cli/session.md new file mode 100644 index 000000000..4b6461478 --- /dev/null +++ b/docs/reference/goose/cli/session.md @@ -0,0 +1 @@ +::: goose.cli.session \ No newline at end of file diff --git a/docs/reference/goose/command/base.md b/docs/reference/goose/command/base.md new file mode 100644 index 000000000..d5a77f02a --- /dev/null +++ b/docs/reference/goose/command/base.md @@ -0,0 +1 @@ +::: goose.command.base \ No newline at end of file diff --git a/docs/reference/goose/command/file.md b/docs/reference/goose/command/file.md new file mode 100644 index 000000000..b9b83b6b2 --- /dev/null +++ b/docs/reference/goose/command/file.md @@ -0,0 +1 @@ +::: goose.command.file \ No newline at end of file diff --git a/docs/reference/goose/command/index.md b/docs/reference/goose/command/index.md new file mode 100644 index 000000000..2869685a3 --- /dev/null +++ b/docs/reference/goose/command/index.md @@ -0,0 +1 @@ +::: goose.command \ No newline at end of file diff --git a/docs/reference/goose/index.md b/docs/reference/goose/index.md new file mode 100644 index 000000000..33f433469 --- /dev/null +++ b/docs/reference/goose/index.md @@ -0,0 +1 @@ +::: goose \ No newline at end of file diff --git a/docs/reference/goose/notifier.md b/docs/reference/goose/notifier.md new file mode 100644 index 000000000..2e585d282 --- /dev/null +++ b/docs/reference/goose/notifier.md @@ -0,0 +1 @@ +::: goose.notifier \ No newline at end of file diff --git a/docs/reference/goose/profile.md b/docs/reference/goose/profile.md new file mode 100644 index 000000000..ebd8a9a12 --- /dev/null +++ b/docs/reference/goose/profile.md @@ -0,0 +1 @@ +::: goose.profile \ No newline at end of file diff --git a/docs/reference/goose/toolkit/base.md b/docs/reference/goose/toolkit/base.md new file mode 100644 index 000000000..5452fb0a1 --- /dev/null +++ b/docs/reference/goose/toolkit/base.md @@ -0,0 +1 @@ +::: goose.toolkit.base \ No newline at end of file diff --git a/docs/reference/goose/toolkit/developer.md b/docs/reference/goose/toolkit/developer.md new file mode 100644 index 000000000..0dac07692 --- /dev/null +++ b/docs/reference/goose/toolkit/developer.md @@ -0,0 +1 @@ +::: goose.toolkit.developer \ No newline at end of file diff --git a/docs/reference/goose/toolkit/github.md b/docs/reference/goose/toolkit/github.md new file mode 100644 index 000000000..53d15b997 --- /dev/null +++ b/docs/reference/goose/toolkit/github.md @@ -0,0 +1 @@ +::: goose.toolkit.github \ No newline at end of file diff --git a/docs/reference/goose/toolkit/index.md b/docs/reference/goose/toolkit/index.md new file mode 100644 index 000000000..8a615c5eb --- /dev/null +++ b/docs/reference/goose/toolkit/index.md @@ -0,0 +1 @@ +::: goose.toolkit \ No newline at end of file diff --git a/docs/reference/goose/toolkit/lint.md b/docs/reference/goose/toolkit/lint.md new file mode 100644 index 000000000..16f875a8c --- /dev/null +++ b/docs/reference/goose/toolkit/lint.md @@ -0,0 +1 @@ +::: goose.toolkit.lint \ No newline at end of file diff --git a/docs/reference/goose/toolkit/repo_context/index.md b/docs/reference/goose/toolkit/repo_context/index.md new file mode 100644 index 000000000..e7cb5edb3 --- /dev/null +++ b/docs/reference/goose/toolkit/repo_context/index.md @@ -0,0 +1 @@ +::: goose.toolkit.repo_context \ No newline at end of file diff --git a/docs/reference/goose/toolkit/repo_context/repo_context.md b/docs/reference/goose/toolkit/repo_context/repo_context.md new file mode 100644 index 000000000..79b964dd0 --- /dev/null +++ b/docs/reference/goose/toolkit/repo_context/repo_context.md @@ -0,0 +1 @@ +::: goose.toolkit.repo_context.repo_context \ No newline at end of file diff --git a/docs/reference/goose/toolkit/repo_context/utils.md b/docs/reference/goose/toolkit/repo_context/utils.md new file mode 100644 index 000000000..f1adc4327 --- /dev/null +++ b/docs/reference/goose/toolkit/repo_context/utils.md @@ -0,0 +1 @@ +::: goose.toolkit.repo_context.utils \ No newline at end of file diff --git a/docs/reference/goose/toolkit/screen.md b/docs/reference/goose/toolkit/screen.md new file mode 100644 index 000000000..62f5c9f77 --- /dev/null +++ b/docs/reference/goose/toolkit/screen.md @@ -0,0 +1 @@ +::: goose.toolkit.screen \ No newline at end of file diff --git a/docs/reference/goose/toolkit/summarization/index.md b/docs/reference/goose/toolkit/summarization/index.md new file mode 100644 index 000000000..d8360eefe --- /dev/null +++ b/docs/reference/goose/toolkit/summarization/index.md @@ -0,0 +1 @@ +::: goose.toolkit.summarization \ No newline at end of file diff --git a/docs/reference/goose/toolkit/summarization/summarize_file.md b/docs/reference/goose/toolkit/summarization/summarize_file.md new file mode 100644 index 000000000..08c2f80ad --- /dev/null +++ b/docs/reference/goose/toolkit/summarization/summarize_file.md @@ -0,0 +1 @@ +::: goose.toolkit.summarization.summarize_file \ No newline at end of file diff --git a/docs/reference/goose/toolkit/summarization/summarize_project.md b/docs/reference/goose/toolkit/summarization/summarize_project.md new file mode 100644 index 000000000..b8da8a157 --- /dev/null +++ b/docs/reference/goose/toolkit/summarization/summarize_project.md @@ -0,0 +1 @@ +::: goose.toolkit.summarization.summarize_project \ No newline at end of file diff --git a/docs/reference/goose/toolkit/summarization/summarize_repo.md b/docs/reference/goose/toolkit/summarization/summarize_repo.md new file mode 100644 index 000000000..6f4855bbe --- /dev/null +++ b/docs/reference/goose/toolkit/summarization/summarize_repo.md @@ -0,0 +1 @@ +::: goose.toolkit.summarization.summarize_repo \ No newline at end of file diff --git a/docs/reference/goose/toolkit/summarization/utils.md b/docs/reference/goose/toolkit/summarization/utils.md new file mode 100644 index 000000000..4dcab4ae1 --- /dev/null +++ b/docs/reference/goose/toolkit/summarization/utils.md @@ -0,0 +1 @@ +::: goose.toolkit.summarization.utils \ No newline at end of file diff --git a/docs/reference/goose/toolkit/utils.md b/docs/reference/goose/toolkit/utils.md new file mode 100644 index 000000000..22f9daf44 --- /dev/null +++ b/docs/reference/goose/toolkit/utils.md @@ -0,0 +1 @@ +::: goose.toolkit.utils \ No newline at end of file diff --git a/docs/reference/goose/utils/ask.md b/docs/reference/goose/utils/ask.md new file mode 100644 index 000000000..629a4badf --- /dev/null +++ b/docs/reference/goose/utils/ask.md @@ -0,0 +1 @@ +::: goose.utils.ask \ No newline at end of file diff --git a/docs/reference/goose/utils/check_shell_command.md b/docs/reference/goose/utils/check_shell_command.md new file mode 100644 index 000000000..d28665593 --- /dev/null +++ b/docs/reference/goose/utils/check_shell_command.md @@ -0,0 +1 @@ +::: goose.utils.check_shell_command \ No newline at end of file diff --git a/docs/reference/goose/utils/diff.md b/docs/reference/goose/utils/diff.md new file mode 100644 index 000000000..746fe963d --- /dev/null +++ b/docs/reference/goose/utils/diff.md @@ -0,0 +1 @@ +::: goose.utils.diff \ No newline at end of file diff --git a/docs/reference/goose/utils/file_utils.md b/docs/reference/goose/utils/file_utils.md new file mode 100644 index 000000000..af9feeb25 --- /dev/null +++ b/docs/reference/goose/utils/file_utils.md @@ -0,0 +1 @@ +::: goose.utils.file_utils \ No newline at end of file diff --git a/docs/reference/goose/utils/index.md b/docs/reference/goose/utils/index.md new file mode 100644 index 000000000..86b0901a8 --- /dev/null +++ b/docs/reference/goose/utils/index.md @@ -0,0 +1 @@ +::: goose.utils \ No newline at end of file diff --git a/docs/reference/goose/utils/session_file.md b/docs/reference/goose/utils/session_file.md new file mode 100644 index 000000000..c0a7f5b12 --- /dev/null +++ b/docs/reference/goose/utils/session_file.md @@ -0,0 +1 @@ +::: goose.utils.session_file \ No newline at end of file diff --git a/docs/reference/goose/view.md b/docs/reference/goose/view.md new file mode 100644 index 000000000..e38281a4d --- /dev/null +++ b/docs/reference/goose/view.md @@ -0,0 +1 @@ +::: goose.view \ No newline at end of file diff --git a/docs/reference/index.md b/docs/reference/index.md new file mode 100644 index 000000000..f5b5a17fd --- /dev/null +++ b/docs/reference/index.md @@ -0,0 +1,39 @@ +# Reference Documentation + +## Goose +- [goose.build](goose/build.md) +- [goose.notifier](goose/notifier.md) +- [goose.profile](goose/profile.md) +- [goose.view](goose/view.md) + +## Command +- [goose.command.base](goose/command/base.md) +- [goose.command.file](goose/command/file.md) + +## CLI +- [goose.cli.config](goose/cli/config.md) +- [goose.cli.main](goose/cli/main.md) +- [goose.cli.prompt.create](goose/cli/prompt/create.md) +- [goose.cli.prompt.goose_prompt_session](goose/cli/prompt/goose_prompt_session.md) +- [goose.cli.session](goose/cli/session.md) + +## Toolkits + [goose.toolkit.base](goose/toolkit/base.md) +- [goose.toolkit.developer](goose/toolkit/developer.md) +- [goose.toolkit.github](goose/toolkit/github.md) +- [goose.toolkit.repo_context.repo_context](goose/toolkit/repo_context/repo_context.md) +- [goose.toolkit.repo_context.utils](goose/toolkit/repo_context/utils.md) +- [goose.toolkit.screen](goose/toolkit/screen.md) +- [goose.toolkit.summarization.summarize_file](goose/toolkit/summarization/summarize_file.md) +- [goose.toolkit.summarization.summarize_project](goose/toolkit/summarization/summarize_project.md) +- [goose.toolkit.summarization.summarize_repo](goose/toolkit/summarization/summarize_repo.md) +- [goose.toolkit.summarization.utils](goose/toolkit/summarization/utils.md) +- [goose.toolkit.utils](goose/toolkit/utils.md) + +## Utils +- [goose.utils](goose/utils/index.md) +- [goose.utils.ask](goose/utils/ask.md) +- [goose.utils.check_shell_command](goose/utils/check_shell_command.md) +- [goose.utils.diff](goose/utils/diff.md) +- [goose.utils.file_utils](goose/utils/file_utils.md) +- [goose.utils.session_file](goose/utils/session_file.md) \ No newline at end of file diff --git a/docs/scripts/gen_ref_pages.py b/docs/scripts/gen_ref_pages.py index 29ee2ed65..da964e59c 100644 --- a/docs/scripts/gen_ref_pages.py +++ b/docs/scripts/gen_ref_pages.py @@ -1,5 +1,3 @@ -"""Generate the code reference pages and navigation.""" - from pathlib import Path import mkdocs_gen_files @@ -9,9 +7,16 @@ root = Path(__file__).parent.parent.parent src = root / "src" +# Collecting all modules for the index page +module_links = [] +core_modules = [] +toolkit_modules = [] +utils_modules = [] + for path in sorted(src.rglob("*.py")): - module_path = path.relative_to(src).with_suffix("") - doc_path = path.relative_to(src).with_suffix(".md") + module_path = path.relative_to(src).with_suffix("") # Removes the '.py' suffix + doc_path = path.relative_to(src).with_suffix(".md") # Creates .md path + full_doc_path = Path("reference", doc_path) parts = tuple(module_path.parts) @@ -23,13 +28,41 @@ elif parts[-1] == "__main__": continue - nav[parts] = doc_path.as_posix() + # Construct a dynamic identifier based on module path + ident = ".".join(parts) + + # Organize modules into categories + if "toolkit" in ident: + toolkit_modules.append(f"- [{ident}]({doc_path})") + elif "utils" in ident: + utils_modules.append(f"- [{ident}]({doc_path})") + else: + core_modules.append(f"- [{ident}]({doc_path})") + # Generate the markdown file for each module with mkdocs_gen_files.open(full_doc_path, "w") as fd: - ident = ".".join(parts) fd.write(f"::: {ident}") - mkdocs_gen_files.set_edit_path(full_doc_path, path.relative_to(root)) + nav[parts] = doc_path.as_posix() +# Write the enhanced SUMMARY.md with categories with mkdocs_gen_files.open("reference/SUMMARY.md", "w") as nav_file: - nav_file.writelines(nav.build_literate_nav()) \ No newline at end of file + nav_file.write("# Reference Documentation Summary\n\n") + + nav_file.write("## Core Modules\n") + nav_file.write("\n".join(core_modules) + "\n\n") + + nav_file.write("## Toolkit Modules\n") + nav_file.write("\n".join(toolkit_modules) + "\n\n") + + nav_file.write("## Utility Modules\n") + nav_file.write("\n".join(utils_modules) + "\n\n") + +# Create an index.md file for the reference section +with mkdocs_gen_files.open("reference/index.md", "w") as index_file: + index_file.write("# Reference Documentation\n\n") + index_file.write("Welcome to the reference documentation for the project's Python modules.\n\n") + index_file.write("Below is a list of available modules:\n\n") + index_file.write("\n".join(core_modules + toolkit_modules + utils_modules)) + + diff --git a/justfile b/justfile index 08adc2c66..9b89e6a9e 100644 --- a/justfile +++ b/justfile @@ -17,7 +17,8 @@ coverage *FLAGS: uv run coverage lcov -o lcov.info docs: - cd docs && uv sync && uv run mkdocs serve + uv sync && uv run mkdocs serve + ai-exchange-version: curl -s https://pypi.org/pypi/ai-exchange/json | jq -r .info.version diff --git a/docs/mkdocs.yml b/mkdocs.yml similarity index 64% rename from docs/mkdocs.yml rename to mkdocs.yml index d6e6a0206..c920667e6 100644 --- a/docs/mkdocs.yml +++ b/mkdocs.yml @@ -1,10 +1,13 @@ site_name: Goose Documentation site_author: Block site_description: Documentation for Goose -repo_url: https://github.com/square/goose +repo_url: https://github.com/block-open-source/goose repo_name: "square/goose" -edit_uri: "https://github.com/square/goose/blob/main/docs/docs/" -# site_url: https://goose-docs.squarecloudservices.com +edit_uri: "https://github.com/block-open-source/goose/blob/main/docs/" +site_url: 'https://block-open-source.github.io/goose/' +use_directory_urls: false + +# theme theme: name: material features: @@ -36,14 +39,29 @@ theme: favicon: assets/logo.ico icon: logo: assets/logo.ico + +# plugins plugins: - include-markdown - callouts - glightbox + - mkdocstrings: + handlers: + python: + setup_commands: + - "import sys; sys.path.append('src')" # Add src folder to Python path - search: separator: '[\s\u200b\-_,:!=\[\]()"`/]+|\.(?!\d)|&[lg]t;|(?!\b)(?=[A-Z][a-z])' - redirects: redirect_maps: + - git-committers: # Show git committers + branch: main + enabled: !ENV [ ENV_PROD, false ] + repository: square/goose + - git-revision-date-localized: # Show git revision date + enable_creation_date: true + enabled: !ENV [ ENV_PROD, false ] + extra: annotate: json: @@ -52,6 +70,7 @@ extra: analytics: provider: google property: !ENV GOOGLE_ANALYTICS_KEY + markdown_extensions: - abbr - admonition @@ -92,19 +111,26 @@ markdown_extensions: - pymdownx.tilde - toc: permalink: true + nav: - Home: index.md - 'Installation': installation.md - - 'Configuration': configuration.md - 'Contributing': contributing.md + - Guidance: + - 'Getting Started': guidance/getting-started.md + - 'Quick Tips': guidance/tips.md + - 'Applications of Goose': guidance/applications.md - Plugins: - - 'Overview': plugins.md + - 'Overview': plugins/plugins.md - Toolkits: - - 'Using Toolkits': using-toolkits.md - - 'Creating a New Toolkit': creating-a-new-toolkit.md - - 'Available Toolkits': available-toolkits.md + - 'Using Toolkits': plugins/using-toolkits.md + - 'Creating a New Toolkit': plugins/creating-a-new-toolkit.md + - 'Available Toolkits': plugins/available-toolkits.md - CLI Commands: - - 'Available CLI Commands': cli.md + - 'Available CLI Commands': plugins/cli.md - Providers: - - 'Available Providers': providers.md - - 'Tips': tips.md + - 'Available Providers': plugins/providers.md + - Advanced: + - Configuration: configuration.md + - 'Reference': + - 'API Docs': reference/index.md diff --git a/pyproject.toml b/pyproject.toml index bc6b6ac67..8913104c3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,17 +48,21 @@ build-backend = "hatchling.build" [tool.uv] dev-dependencies = [ - "pytest>=8.3.2", "codecov>=2.1.13", - "mkdocstrings>=0.26.1", - "mkdocs-literate-nav>=0.6.1", + "mkdocs-callouts>=1.14.0", "mkdocs-gen-files>=0.5.0", - "mkdocs-section-index>=0.3.9", - "mkdocs-material>=9.5.34", - "mkdocstrings-python>=1.11.1", + "mkdocs-git-authors-plugin>=0.9.0", + "mkdocs-git-committers-plugin>=0.2.3", "mkdocs-git-revision-date-localized-plugin", + "mkdocs-git-revision-date-localized-plugin>=1.2.9", "mkdocs-glightbox>=0.4.0", - "mkdocs-redirects>=1.2.1", "mkdocs-include-markdown-plugin>=6.2.2", - "mkdocs-callouts>=1.14.0", + "mkdocs-literate-nav>=0.6.1", + "mkdocs-material>=9.5.34", + "mkdocs-redirects>=1.2.1", + "mkdocs-section-index>=0.3.9", + "mkdocstrings-python>=1.11.1", + "mkdocstrings>=0.26.1", + "pytest-mock>=3.14.0", + "pytest>=8.3.2" ] diff --git a/src/goose/cli/main.py b/src/goose/cli/main.py index 3bdf84a5e..2d19b9672 100644 --- a/src/goose/cli/main.py +++ b/src/goose/cli/main.py @@ -1,3 +1,4 @@ +import os from datetime import datetime from pathlib import Path from typing import Optional @@ -10,6 +11,7 @@ from goose.cli.session import Session from goose.toolkit.utils import render_template, parse_plan from goose.utils import load_plugins +from goose.utils.autocomplete import SUPPORTED_SHELLS, setup_autocomplete from goose.utils.session_file import list_sorted_session_files @@ -43,6 +45,38 @@ def get_version() -> None: print(f" [red]Could not retrieve version for {module}: {e}[/red]") +def get_current_shell() -> str: + return os.getenv("SHELL", "").split("/")[-1] + + +@goose_cli.command(name="shell-completions", help="Manage shell completions for goose") +@click.option("--install", is_flag=True, help="Install shell completions") +@click.option("--generate", is_flag=True, help="Generate shell completions") +@click.argument( + "shell", + type=click.Choice(SUPPORTED_SHELLS), + default=get_current_shell(), +) +@click.pass_context +def shell_completions(ctx: click.Context, install: bool, generate: bool, shell: str) -> None: + """Generate or install shell completions for goose + + Args: + shell (str): shell to install completions for + install (bool): installs completions if true, otherwise generates + completions + """ + if not any([install, generate]): + print("[red]One of --install or --generate must be specified[/red]\n") + raise click.UsageError(ctx.get_help()) + + if sum([install, generate]) > 1: + print("[red]Only one of --install or --generate can be specified[/red]\n") + raise click.UsageError(ctx.get_help()) + + setup_autocomplete(shell, install=install) + + @goose_cli.group() def session() -> None: """Start or manage sessions""" @@ -102,20 +136,37 @@ def session_planned(plan: str, log_level: str, args: Optional[dict[str, str]]) - session.run() +def autocomplete_session_files(ctx: click.Context, args: str, incomplete: str) -> None: + return [ + f"{session_name}" + for session_name in sorted(get_session_files().keys(), reverse=True, key=lambda x: x.lower()) + if session_name.startswith(incomplete) + ] + + +def get_session_files() -> dict[str, Path]: + return list_sorted_session_files(SESSIONS_PATH) + + @session.command(name="resume") -@click.argument("name", required=False) +@click.argument("name", required=False, shell_complete=autocomplete_session_files) @click.option("--profile") @click.option("--log-level", type=click.Choice(["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]), default="INFO") def session_resume(name: Optional[str], profile: str, log_level: str) -> None: """Resume an existing goose session""" + session_files = get_session_files() if name is None: - session_files = get_session_files() if session_files: name = list(session_files.keys())[0] print(f"Resuming most recent session: {name} from {session_files[name]}") else: print("No sessions found.") return + else: + if name in session_files: + print(f"Resuming session: {name}") + else: + print(f"Creating new session: {name}") session = Session(name=name, profile=profile, log_level=log_level) session.run() @@ -137,10 +188,6 @@ def session_clear(keep: int) -> None: session_file.unlink() -def get_session_files() -> dict[str, Path]: - return list_sorted_session_files(SESSIONS_PATH) - - @click.group( invoke_without_command=True, name="goose", diff --git a/src/goose/toolkit/developer.py b/src/goose/toolkit/developer.py index e5cc864c5..6e44313a7 100644 --- a/src/goose/toolkit/developer.py +++ b/src/goose/toolkit/developer.py @@ -170,7 +170,6 @@ def shell(self, command: str) -> str: r"\(y/N\)", # Yes/No prompt r"Press any key to continue", # Awaiting keypress r"Waiting for input", # General waiting message - r"\?\s", # Prompts starting with '? ' ] compiled_patterns = [re.compile(pattern, re.IGNORECASE) for pattern in interaction_patterns] diff --git a/src/goose/utils/autocomplete.py b/src/goose/utils/autocomplete.py new file mode 100644 index 000000000..6feb0807e --- /dev/null +++ b/src/goose/utils/autocomplete.py @@ -0,0 +1,100 @@ +import sys +from pathlib import Path + +from rich import print + +SUPPORTED_SHELLS = ["bash", "zsh", "fish"] + + +def is_autocomplete_installed(file: Path) -> bool: + if not file.exists(): + print(f"[yellow]{file} does not exist, creating file") + with open(file, "w") as f: + f.write("") + + # https://click.palletsprojects.com/en/8.1.x/shell-completion/#enabling-completion + if "_GOOSE_COMPLETE" in open(file).read(): + print(f"auto-completion already installed in {file}") + return True + return False + + +def setup_bash(install: bool) -> None: + bashrc = Path("~/.bashrc").expanduser() + if install: + if is_autocomplete_installed(bashrc): + return + f = open(bashrc, "a") + else: + f = sys.stdout + print(f"# add the following to your bash config, typically {bashrc}") + + with f: + f.write('eval "$(_GOOSE_COMPLETE=bash_source goose)"\n') + + if install: + print(f"installed auto-completion to {bashrc}") + print(f"run `source {bashrc}` to enable auto-completion") + + +def setup_fish(install: bool) -> None: + completion_dir = Path("~/.config/fish/completions").expanduser() + if not completion_dir.exists(): + completion_dir.mkdir(parents=True, exist_ok=True) + + completion_file = completion_dir / "goose.fish" + if install: + if is_autocomplete_installed(completion_file): + return + f = open(completion_file, "a") + else: + f = sys.stdout + print(f"# add the following to your fish config, typically {completion_file}") + + with f: + f.write("_GOOSE_COMPLETE=fish_source goose | source\n") + + if install: + print(f"installed auto-completion to {completion_file}") + + +def setup_zsh(install: bool) -> None: + zshrc = Path("~/.zshrc").expanduser() + if install: + if is_autocomplete_installed(zshrc): + return + f = open(zshrc, "a") + else: + f = sys.stdout + print(f"# add the following to your zsh config, typically {zshrc}") + + with f: + f.write("autoload -U +X compinit && compinit\n") + f.write("autoload -U +X bashcompinit && bashcompinit\n") + f.write('eval "$(_GOOSE_COMPLETE=zsh_source goose)"\n') + + if install: + print(f"installed auto-completion to {zshrc}") + print(f"run `source {zshrc}` to enable auto-completion") + + +def setup_autocomplete(shell: str, install: bool) -> None: + """Installs shell completions for goose + + Args: + shell (str): shell to install completions for + install (bool): whether to install or generate completions + """ + + match shell: + case "bash": + setup_bash(install=install) + + case "zsh": + setup_zsh(install=install) + + case "fish": + setup_fish(install=install) + + case _: + print(f"Shell {shell} not supported") diff --git a/tests/test_autocomplete.py b/tests/test_autocomplete.py new file mode 100644 index 000000000..789b5ec23 --- /dev/null +++ b/tests/test_autocomplete.py @@ -0,0 +1,34 @@ +import sys +import unittest.mock as mock + +from goose.utils.autocomplete import SUPPORTED_SHELLS, is_autocomplete_installed, setup_autocomplete + + +def test_supported_shells(): + assert SUPPORTED_SHELLS == ["bash", "zsh", "fish"] + + +def test_install_autocomplete(tmp_path): + file = tmp_path / "test_bash_autocomplete" + assert is_autocomplete_installed(file) is False + + file.write_text("_GOOSE_COMPLETE") + assert is_autocomplete_installed(file) is True + + +@mock.patch("sys.stdout") +def test_setup_bash(mocker: mock.MagicMock): + setup_autocomplete("bash", install=False) + sys.stdout.write.assert_called_with('eval "$(_GOOSE_COMPLETE=bash_source goose)"\n') + + +@mock.patch("sys.stdout") +def test_setup_zsh(mocker: mock.MagicMock): + setup_autocomplete("zsh", install=False) + sys.stdout.write.assert_called_with('eval "$(_GOOSE_COMPLETE=zsh_source goose)"\n') + + +@mock.patch("sys.stdout") +def test_setup_fish(mocker: mock.MagicMock): + setup_autocomplete("fish", install=False) + sys.stdout.write.assert_called_with("_GOOSE_COMPLETE=fish_source goose | source\n") diff --git a/tests/test_cli_main.py b/tests/test_cli_main.py new file mode 100644 index 000000000..9160be1bf --- /dev/null +++ b/tests/test_cli_main.py @@ -0,0 +1,21 @@ +from click.testing import CliRunner +from goose.cli.main import get_current_shell, shell_completions + + +def test_get_current_shell(mocker): + mocker.patch("os.getenv", return_value="/bin/bash") + assert get_current_shell() == "bash" + + +def test_shell_completions_install_invalid_combination(): + runner = CliRunner() + result = runner.invoke(shell_completions, ["--install", "--generate", "bash"]) + assert result.exit_code != 0 + assert "Only one of --install or --generate can be specified" in result.output + + +def test_shell_completions_install_no_option(): + runner = CliRunner() + result = runner.invoke(shell_completions, ["bash"]) + assert result.exit_code != 0 + assert "One of --install or --generate must be specified" in result.output