mirror of
https://github.com/mark3labs/kit.git
synced 2026-06-16 12:36:15 +00:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6a1b061d06 | |||
| 3a35bc5cec | |||
| 08c3d0fe3a |
@@ -39,6 +39,36 @@ jobs:
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# Keep floating major/minor tags (e.g. v1, v1.2) pointing at the latest
|
||||
# release so the composite action can be referenced as `mark3labs/kit@v1`.
|
||||
action-tags:
|
||||
runs-on: ubuntu-latest
|
||||
needs: goreleaser
|
||||
if: ${{ github.event_name == 'push' && needs.goreleaser.result == 'success' }}
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Update floating major/minor tags
|
||||
env:
|
||||
FULL_TAG: ${{ github.ref_name }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
# FULL_TAG looks like v1.2.3 — derive v1 and v1.2.
|
||||
VER="${FULL_TAG#v}"
|
||||
MAJOR="v${VER%%.*}"
|
||||
MINOR="v${VER%.*}"
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||
for t in "$MAJOR" "$MINOR"; do
|
||||
echo "Pointing $t at $FULL_TAG"
|
||||
git tag -f "$t" "$FULL_TAG"
|
||||
git push -f origin "refs/tags/$t"
|
||||
done
|
||||
|
||||
npm-publish:
|
||||
runs-on: ubuntu-latest
|
||||
needs: goreleaser
|
||||
|
||||
@@ -514,9 +514,12 @@ The generated workflow:
|
||||
After committing the workflow and setting the provider secret, comment
|
||||
`/kit <your request>` on any issue or pull request to trigger Kit.
|
||||
|
||||
The runtime that reads the event context, enforces permissions, drives the agent,
|
||||
and posts the response back is the
|
||||
[`github-handler`](examples/extensions/github-handler) example extension.
|
||||
The generated workflow uses the bundled [`mark3labs/kit`](action.yml) composite
|
||||
action, which installs the Kit binary and runs `kit github run`. That command
|
||||
reads the triggering event, enforces permissions, reacts with an emoji, runs the
|
||||
agent against the issue thread or pull request, posts the response as a comment,
|
||||
and — if the agent changed files — pushes a `kit-agent[bot]` branch and opens a
|
||||
pull request.
|
||||
|
||||
| Flag | Description |
|
||||
| --- | --- |
|
||||
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
name: "Kit"
|
||||
description: "Run Kit as an automated collaborator/reviewer on GitHub issues and pull requests."
|
||||
author: "mark3labs"
|
||||
branding:
|
||||
icon: "git-merge"
|
||||
color: "purple"
|
||||
|
||||
inputs:
|
||||
model:
|
||||
description: "Provider/model Kit should use (e.g. anthropic/claude-sonnet-4-5-20250929). Defaults to Kit's built-in default."
|
||||
required: false
|
||||
default: ""
|
||||
version:
|
||||
description: "Kit version to install (e.g. v0.77.0). Defaults to the latest release."
|
||||
required: false
|
||||
default: "latest"
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Install Kit
|
||||
shell: bash
|
||||
env:
|
||||
KIT_VERSION: ${{ inputs.version }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
VERSION="${KIT_VERSION:-latest}"
|
||||
if [ -z "$VERSION" ] || [ "$VERSION" = "latest" ]; then
|
||||
VERSION="$(curl -fsSL https://api.github.com/repos/mark3labs/kit/releases/latest \
|
||||
| grep -o '"tag_name": *"[^"]*"' | head -1 | cut -d'"' -f4)"
|
||||
fi
|
||||
if [ -z "$VERSION" ]; then
|
||||
echo "::error::could not determine Kit version to install" >&2
|
||||
exit 1
|
||||
fi
|
||||
VER="${VERSION#v}"
|
||||
|
||||
case "$(uname -s)" in
|
||||
Linux) OS=linux ;;
|
||||
Darwin) OS=darwin ;;
|
||||
*) echo "::error::unsupported OS $(uname -s)" >&2; exit 1 ;;
|
||||
esac
|
||||
case "$(uname -m)" in
|
||||
x86_64|amd64) ARCH=amd64 ;;
|
||||
aarch64|arm64) ARCH=arm64 ;;
|
||||
*) echo "::error::unsupported arch $(uname -m)" >&2; exit 1 ;;
|
||||
esac
|
||||
|
||||
URL="https://github.com/mark3labs/kit/releases/download/${VERSION}/kit_${VER}_${OS}_${ARCH}.tar.gz"
|
||||
echo "Installing Kit ${VERSION} from ${URL}"
|
||||
|
||||
TMP="$(mktemp -d)"
|
||||
curl -fsSL "$URL" | tar -xz -C "$TMP"
|
||||
mkdir -p "$HOME/.kit/bin"
|
||||
mv "$TMP/kit" "$HOME/.kit/bin/kit"
|
||||
chmod +x "$HOME/.kit/bin/kit"
|
||||
echo "$HOME/.kit/bin" >> "$GITHUB_PATH"
|
||||
rm -rf "$TMP"
|
||||
|
||||
- name: Verify Kit
|
||||
shell: bash
|
||||
run: kit --version
|
||||
|
||||
- name: Run Kit
|
||||
shell: bash
|
||||
env:
|
||||
MODEL: ${{ inputs.model }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
ARGS=()
|
||||
if [ -n "${MODEL:-}" ]; then
|
||||
ARGS+=(--model "$MODEL")
|
||||
fi
|
||||
kit github run ${ARGS[@]+"${ARGS[@]}"}
|
||||
+1
-1
@@ -173,7 +173,7 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: mark3labs/kit-action@v1
|
||||
- uses: mark3labs/kit@v0
|
||||
with:
|
||||
model: %s
|
||||
env:
|
||||
|
||||
@@ -1,30 +1,4 @@
|
||||
//go:build ignore
|
||||
|
||||
// Package main implements the Kit GitHub handler extension.
|
||||
//
|
||||
// This is the Phase 2b "GitHub handler" piece of Kit's GitHub integration
|
||||
// (issue #60). It is designed to run *inside a GitHub Actions runner*, driven
|
||||
// by the workflow scaffolded by `kit github install`. When a collaborator
|
||||
// comments `/kit <request>` on an issue or pull request, the workflow boots Kit
|
||||
// headlessly with this extension loaded; the extension then:
|
||||
//
|
||||
// - parses the triggering GitHub event from GITHUB_EVENT_PATH,
|
||||
// - enforces that the comment author has write/admin access
|
||||
// (author_association in OWNER / MEMBER / COLLABORATOR),
|
||||
// - reacts with 👀 on the trigger comment while it works,
|
||||
// - gathers context (issue thread or PR diff) and drives the agent with it,
|
||||
// - posts the agent's response back as a comment, and
|
||||
// - if the agent left uncommitted changes, pushes a branch as the
|
||||
// `kit-agent[bot]` identity and opens a pull request.
|
||||
//
|
||||
// Outside of GitHub Actions (i.e. when GITHUB_ACTIONS != "true") the extension
|
||||
// is inert, so it is safe to keep loaded during normal local use.
|
||||
//
|
||||
// Set KIT_GITHUB_DRY_RUN=1 (or the `github.dry-run` option) to exercise the
|
||||
// parsing / permission / prompt-building logic without shelling out to `gh` or
|
||||
// `git` — every side effect is logged instead of executed. This is what the
|
||||
// unit tests use.
|
||||
package main
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
@@ -35,7 +9,8 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"kit/ext"
|
||||
"github.com/charmbracelet/log"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// commandToken is the mention that triggers Kit from a comment, mirroring the
|
||||
@@ -46,6 +21,11 @@ const commandToken = "/kit"
|
||||
// an unexpected auth prompt cannot hang the Actions job indefinitely.
|
||||
const subprocessTimeout = 30 * time.Second
|
||||
|
||||
// agentTimeout bounds the headless agent run so a runaway turn cannot block the
|
||||
// job forever. GitHub Actions jobs have their own ceiling, but a tighter bound
|
||||
// keeps feedback fast and costs predictable.
|
||||
const agentTimeout = 20 * time.Minute
|
||||
|
||||
// botName / botEmail are the dedicated identity commits are attributed to, so
|
||||
// Kit's changes are clearly distinguishable from human authors in history.
|
||||
const (
|
||||
@@ -61,12 +41,47 @@ var writeAssociations = map[string]bool{
|
||||
"COLLABORATOR": true,
|
||||
}
|
||||
|
||||
// ghUser is a GitHub user as embedded in event payloads.
|
||||
var (
|
||||
githubRunModel string
|
||||
githubRunDryRun bool
|
||||
)
|
||||
|
||||
// githubRunCmd is the runtime half of the GitHub integration. It is invoked by
|
||||
// the bundled composite action (action.yml) inside a GitHub Actions runner once
|
||||
// a collaborator comments '/kit <request>' on an issue or pull request. It reads
|
||||
// the triggering event, enforces permissions, runs the agent headlessly against
|
||||
// the comment/PR context, and responds by posting a comment and — when the agent
|
||||
// leaves changes — opening a pull request.
|
||||
var githubRunCmd = &cobra.Command{
|
||||
Use: "run",
|
||||
Short: "Run Kit against the current GitHub Actions event (used by the kit action)",
|
||||
Long: `Run Kit against the current GitHub Actions event.
|
||||
|
||||
This command is normally invoked by the bundled composite action inside a
|
||||
GitHub Actions runner; you rarely run it by hand. It reads the triggering
|
||||
event from GITHUB_EVENT_PATH, verifies the commenter has write/admin access,
|
||||
reacts with an emoji while it works, runs the agent non-interactively against
|
||||
the issue thread or pull request, posts the response as a comment, and — if the
|
||||
agent modified files — pushes a kit-agent[bot] branch and opens a pull request.
|
||||
|
||||
Set --dry-run (or KIT_GITHUB_DRY_RUN=1) to log every git/gh side effect and
|
||||
skip the agent run instead of executing them.`,
|
||||
Args: cobra.NoArgs,
|
||||
RunE: runGitHubRun,
|
||||
}
|
||||
|
||||
func init() {
|
||||
githubRunCmd.Flags().StringVarP(&githubRunModel, "model", "m", "", "provider/model the agent should use (falls back to $MODEL, then a default)")
|
||||
githubRunCmd.Flags().BoolVar(&githubRunDryRun, "dry-run", false, "log git/gh side effects and skip the agent run instead of executing them")
|
||||
githubCmd.AddCommand(githubRunCmd)
|
||||
}
|
||||
|
||||
// --- GitHub event types ------------------------------------------------------
|
||||
|
||||
type ghUser struct {
|
||||
Login string `json:"login"`
|
||||
}
|
||||
|
||||
// ghComment is the triggering comment.
|
||||
type ghComment struct {
|
||||
ID int64 `json:"id"`
|
||||
Body string `json:"body"`
|
||||
@@ -74,8 +89,6 @@ type ghComment struct {
|
||||
User ghUser `json:"user"`
|
||||
}
|
||||
|
||||
// ghIssue is the issue (or PR, since GitHub models PRs as issues) the comment
|
||||
// was posted on. PullRequest is non-nil when the issue is actually a PR.
|
||||
type ghIssue struct {
|
||||
Number int `json:"number"`
|
||||
Title string `json:"title"`
|
||||
@@ -83,20 +96,17 @@ type ghIssue struct {
|
||||
PullRequest json.RawMessage `json:"pull_request"`
|
||||
}
|
||||
|
||||
// ghPull is the pull request for pull_request_review_comment events.
|
||||
type ghPull struct {
|
||||
Number int `json:"number"`
|
||||
Title string `json:"title"`
|
||||
Body string `json:"body"`
|
||||
}
|
||||
|
||||
// ghRepo identifies the repository the event originated from.
|
||||
type ghRepo struct {
|
||||
FullName string `json:"full_name"`
|
||||
DefaultBranch string `json:"default_branch"`
|
||||
}
|
||||
|
||||
// ghEvent is the subset of the GitHub Actions event payload the handler reads.
|
||||
type ghEvent struct {
|
||||
Action string `json:"action"`
|
||||
Comment *ghComment `json:"comment"`
|
||||
@@ -105,8 +115,8 @@ type ghEvent struct {
|
||||
Repository ghRepo `json:"repository"`
|
||||
}
|
||||
|
||||
// trigger captures everything the handler needs about a single invocation,
|
||||
// normalised across issue_comment and pull_request_review_comment events.
|
||||
// trigger normalises a single invocation across issue_comment and
|
||||
// pull_request_review_comment events.
|
||||
type trigger struct {
|
||||
repo string
|
||||
defaultBranch string
|
||||
@@ -121,83 +131,90 @@ type trigger struct {
|
||||
body string
|
||||
}
|
||||
|
||||
func Init(api ext.API) {
|
||||
api.RegisterOption(ext.OptionDef{
|
||||
Name: "github.dry-run",
|
||||
Description: "Log GitHub/git side effects instead of executing them",
|
||||
Default: "false",
|
||||
})
|
||||
// runGitHubRun is the entry point wired to `kit github run`.
|
||||
func runGitHubRun(cmd *cobra.Command, _ []string) error {
|
||||
ctx := cmd.Context()
|
||||
|
||||
api.OnSessionStart(func(_ ext.SessionStartEvent, ctx ext.Context) {
|
||||
if !inGitHubActions() {
|
||||
return
|
||||
}
|
||||
handleSessionStart(ctx)
|
||||
})
|
||||
if !inGitHubActions() && !githubDryRun() {
|
||||
return fmt.Errorf("kit github run is meant to run inside GitHub Actions (set GITHUB_ACTIONS=true or pass --dry-run)")
|
||||
}
|
||||
|
||||
api.OnAgentEnd(func(e ext.AgentEndEvent, ctx ext.Context) {
|
||||
if !inGitHubActions() || activeTrigger == nil {
|
||||
return
|
||||
}
|
||||
handleAgentEnd(e, ctx)
|
||||
})
|
||||
event, err := loadGitHubEvent()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tr, err := buildTrigger(event)
|
||||
if err != nil {
|
||||
// Not an actionable trigger (the workflow `if:` normally prevents this).
|
||||
log.Info("github run: nothing to do", "reason", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
if !writeAssociations[strings.ToUpper(tr.association)] {
|
||||
log.Warn("github run: ignoring /kit from unauthorized author",
|
||||
"author", tr.author, "association", tr.association)
|
||||
return nil
|
||||
}
|
||||
|
||||
model := resolveRunModel()
|
||||
log.Info("github run: handling trigger",
|
||||
"repo", tr.repo, "number", tr.number, "pr", tr.isPR, "author", tr.author, "model", model)
|
||||
|
||||
// React with 👀 so the human sees Kit picked up the request.
|
||||
addReaction(ctx, tr, "eyes")
|
||||
|
||||
gathered := gatherContext(ctx, tr)
|
||||
prompt := buildPrompt(tr, gathered)
|
||||
|
||||
response, runErr := runAgent(ctx, model, prompt)
|
||||
if runErr != nil {
|
||||
postComment(ctx, tr, "⚠️ Kit hit an error while processing this request:\n\n```\n"+runErr.Error()+"\n```")
|
||||
addReaction(ctx, tr, "confused")
|
||||
return runErr
|
||||
}
|
||||
|
||||
response = strings.TrimSpace(response)
|
||||
if response == "" {
|
||||
response = "Kit finished without a textual response."
|
||||
}
|
||||
|
||||
prURL := ""
|
||||
if hasUncommittedChanges(ctx) {
|
||||
prURL = openPullRequest(ctx, tr, response)
|
||||
}
|
||||
|
||||
comment := response
|
||||
if prURL != "" {
|
||||
comment += "\n\n---\nOpened a pull request with the changes: " + prURL
|
||||
}
|
||||
postComment(ctx, tr, comment)
|
||||
addReaction(ctx, tr, "rocket")
|
||||
return nil
|
||||
}
|
||||
|
||||
// activeTrigger holds the parsed trigger between OnSessionStart and OnAgentEnd.
|
||||
// Yaegi supports package-level state captured by the handler closures.
|
||||
var activeTrigger *trigger
|
||||
// resolveRunModel picks the model: --model flag, then $MODEL, then the default.
|
||||
func resolveRunModel() string {
|
||||
if m := strings.TrimSpace(githubRunModel); m != "" {
|
||||
return m
|
||||
}
|
||||
if m := strings.TrimSpace(os.Getenv("MODEL")); m != "" {
|
||||
return m
|
||||
}
|
||||
return defaultGitHubModel
|
||||
}
|
||||
|
||||
func inGitHubActions() bool {
|
||||
return os.Getenv("GITHUB_ACTIONS") == "true"
|
||||
}
|
||||
|
||||
// dryRun reports whether side effects should be logged instead of executed.
|
||||
func dryRun(ctx ext.Context) bool {
|
||||
if os.Getenv("KIT_GITHUB_DRY_RUN") != "" {
|
||||
return true
|
||||
}
|
||||
return strings.EqualFold(ctx.GetOption("github.dry-run"), "true")
|
||||
// githubDryRun reports whether side effects should be logged instead of run.
|
||||
func githubDryRun() bool {
|
||||
return githubRunDryRun || os.Getenv("KIT_GITHUB_DRY_RUN") != ""
|
||||
}
|
||||
|
||||
// handleSessionStart parses the event, enforces permissions, reacts on the
|
||||
// trigger comment, builds the prompt, and drives the agent.
|
||||
func handleSessionStart(ctx ext.Context) {
|
||||
event, err := loadEvent()
|
||||
if err != nil {
|
||||
ctx.PrintError("kit-github: " + err.Error())
|
||||
ctx.Exit()
|
||||
return
|
||||
}
|
||||
|
||||
tr, err := buildTrigger(event)
|
||||
if err != nil {
|
||||
// Not an actionable trigger (e.g. a comment without /kit). Stay quiet
|
||||
// and let the run finish; the workflow `if:` normally prevents this.
|
||||
ctx.PrintInfo("kit-github: " + err.Error())
|
||||
ctx.Exit()
|
||||
return
|
||||
}
|
||||
|
||||
if !writeAssociations[strings.ToUpper(tr.association)] {
|
||||
ctx.PrintError(fmt.Sprintf(
|
||||
"kit-github: ignoring /kit from @%s — author_association %q lacks write access",
|
||||
tr.author, tr.association))
|
||||
ctx.Exit()
|
||||
return
|
||||
}
|
||||
|
||||
activeTrigger = tr
|
||||
|
||||
// React with 👀 so the human sees Kit picked up the request.
|
||||
addReaction(ctx, tr, "eyes")
|
||||
|
||||
context := gatherContext(ctx, tr)
|
||||
prompt := buildPrompt(tr, context)
|
||||
ctx.SendMessage(prompt)
|
||||
}
|
||||
|
||||
// loadEvent reads and decodes the GitHub Actions event payload.
|
||||
func loadEvent() (*ghEvent, error) {
|
||||
// loadGitHubEvent reads and decodes the GitHub Actions event payload.
|
||||
func loadGitHubEvent() (*ghEvent, error) {
|
||||
path := os.Getenv("GITHUB_EVENT_PATH")
|
||||
if path == "" {
|
||||
return nil, fmt.Errorf("GITHUB_EVENT_PATH is not set")
|
||||
@@ -243,15 +260,12 @@ func buildTrigger(event *ghEvent) (*trigger, error) {
|
||||
tr.title = event.Issue.Title
|
||||
tr.body = event.Issue.Body
|
||||
tr.isPR = len(event.Issue.PullRequest) > 0
|
||||
// issue_comment fires for both issues and PRs; reactions for PR
|
||||
// comments posted on the conversation tab still use the issues path.
|
||||
tr.commentKind = "issues"
|
||||
case event.PullRequest != nil:
|
||||
tr.number = event.PullRequest.Number
|
||||
tr.title = event.PullRequest.Title
|
||||
tr.body = event.PullRequest.Body
|
||||
tr.isPR = true
|
||||
// pull_request_review_comment reactions use the pulls path.
|
||||
tr.commentKind = "pulls"
|
||||
default:
|
||||
return nil, fmt.Errorf("event has no issue or pull_request target")
|
||||
@@ -269,7 +283,7 @@ func buildTrigger(event *ghEvent) (*trigger, error) {
|
||||
// mentions like "please review /kit behavior" do not trigger the handler. It
|
||||
// returns the remainder of the matching line as the request.
|
||||
func extractRequest(body string) (string, bool) {
|
||||
for _, line := range strings.Split(body, "\n") {
|
||||
for line := range strings.SplitSeq(body, "\n") {
|
||||
trimmed := strings.TrimSpace(line)
|
||||
var rest string
|
||||
switch {
|
||||
@@ -289,8 +303,8 @@ func extractRequest(body string) (string, bool) {
|
||||
|
||||
// gatherContext assembles the issue thread or PR diff to give the agent. It
|
||||
// always includes the title/body from the event payload, and — outside dry-run,
|
||||
// when `gh` is available — enriches with the full comment thread and PR diff.
|
||||
func gatherContext(ctx ext.Context, tr *trigger) string {
|
||||
// when `gh` is available — enriches with the comment thread and PR diff.
|
||||
func gatherContext(ctx context.Context, tr *trigger) string {
|
||||
var b strings.Builder
|
||||
target := "Issue"
|
||||
if tr.isPR {
|
||||
@@ -301,19 +315,20 @@ func gatherContext(ctx ext.Context, tr *trigger) string {
|
||||
fmt.Fprintf(&b, "\n%s\n", strings.TrimSpace(tr.body))
|
||||
}
|
||||
|
||||
if dryRun(ctx) || !commandExists("gh") {
|
||||
if githubDryRun() || !commandExists("gh") {
|
||||
return b.String()
|
||||
}
|
||||
|
||||
num := fmt.Sprint(tr.number)
|
||||
if tr.isPR {
|
||||
if diff := ghOutput(ctx, "pr", "diff", fmt.Sprint(tr.number), "--repo", tr.repo); diff != "" {
|
||||
if diff := ghOutput(ctx, "pr", "diff", num, "--repo", tr.repo); diff != "" {
|
||||
fmt.Fprintf(&b, "\n## Diff\n```diff\n%s\n```\n", strings.TrimSpace(diff))
|
||||
}
|
||||
if comments := ghOutput(ctx, "pr", "view", fmt.Sprint(tr.number), "--repo", tr.repo, "--json", "comments", "--jq", ".comments[] | \"@\\(.author.login): \\(.body)\""); comments != "" {
|
||||
if comments := ghOutput(ctx, "pr", "view", num, "--repo", tr.repo, "--json", "comments", "--jq", ".comments[] | \"@\\(.author.login): \\(.body)\""); comments != "" {
|
||||
fmt.Fprintf(&b, "\n## Comments\n%s\n", strings.TrimSpace(comments))
|
||||
}
|
||||
} else {
|
||||
if comments := ghOutput(ctx, "issue", "view", fmt.Sprint(tr.number), "--repo", tr.repo, "--json", "comments", "--jq", ".comments[] | \"@\\(.author.login): \\(.body)\""); comments != "" {
|
||||
if comments := ghOutput(ctx, "issue", "view", num, "--repo", tr.repo, "--json", "comments", "--jq", ".comments[] | \"@\\(.author.login): \\(.body)\""); comments != "" {
|
||||
fmt.Fprintf(&b, "\n## Comments\n%s\n", strings.TrimSpace(comments))
|
||||
}
|
||||
}
|
||||
@@ -321,7 +336,7 @@ func gatherContext(ctx ext.Context, tr *trigger) string {
|
||||
}
|
||||
|
||||
// buildPrompt constructs the instruction sent to the agent.
|
||||
func buildPrompt(tr *trigger, context string) string {
|
||||
func buildPrompt(tr *trigger, gathered string) string {
|
||||
target := "issue"
|
||||
if tr.isPR {
|
||||
target = "pull request"
|
||||
@@ -335,96 +350,99 @@ func buildPrompt(tr *trigger, context string) string {
|
||||
fmt.Fprintf(&b, "You are Kit, operating as an automated collaborator on the GitHub repository %s.\n\n", tr.repo)
|
||||
fmt.Fprintf(&b, "@%s (access: %s) triggered you on %s #%d with this request:\n\n", tr.author, tr.association, target, tr.number)
|
||||
fmt.Fprintf(&b, "%s\n\n", request)
|
||||
fmt.Fprintf(&b, "## Context\n%s\n\n", strings.TrimSpace(context))
|
||||
fmt.Fprintf(&b, "## Context\n%s\n\n", strings.TrimSpace(gathered))
|
||||
b.WriteString("Carry out the request. If you modify files, they will be committed to a new ")
|
||||
b.WriteString("branch and a pull request will be opened automatically, so you do not need to ")
|
||||
b.WriteString("commit or push yourself. Finish with a concise summary of what you did.")
|
||||
return b.String()
|
||||
}
|
||||
|
||||
// handleAgentEnd posts the agent's response, opens a PR for any uncommitted
|
||||
// changes, and swaps the reaction to signal completion.
|
||||
func handleAgentEnd(e ext.AgentEndEvent, ctx ext.Context) {
|
||||
tr := activeTrigger
|
||||
response := strings.TrimSpace(e.Response)
|
||||
if response == "" {
|
||||
response = "Kit finished without a textual response."
|
||||
// runAgent drives the agent headlessly by invoking this same binary in quiet,
|
||||
// ephemeral mode against the constructed prompt, and returns its response. In
|
||||
// dry-run it returns a canned response without spawning anything.
|
||||
func runAgent(ctx context.Context, model, prompt string) (string, error) {
|
||||
if githubDryRun() {
|
||||
log.Info("github run: [dry-run] would run agent", "model", model, "promptChars", len(prompt))
|
||||
return "[dry-run] agent response", nil
|
||||
}
|
||||
|
||||
if e.StopReason == "error" {
|
||||
comment := "⚠️ Kit hit an error while processing this request:\n\n" + response
|
||||
postComment(ctx, tr, comment)
|
||||
addReaction(ctx, tr, "confused")
|
||||
ctx.Exit()
|
||||
return
|
||||
exe, err := os.Executable()
|
||||
if err != nil || exe == "" {
|
||||
exe = "kit"
|
||||
}
|
||||
|
||||
prURL := ""
|
||||
if hasUncommittedChanges(ctx) {
|
||||
prURL = openPullRequest(ctx, tr, response)
|
||||
}
|
||||
runCtx, cancel := context.WithTimeout(ctx, agentTimeout)
|
||||
defer cancel()
|
||||
|
||||
comment := response
|
||||
if prURL != "" {
|
||||
comment += "\n\n---\nOpened a pull request with the changes: " + prURL
|
||||
args := []string{"--quiet", "--no-session", "--no-extensions"}
|
||||
if model != "" {
|
||||
args = append(args, "--model", model)
|
||||
}
|
||||
postComment(ctx, tr, comment)
|
||||
addReaction(ctx, tr, "rocket")
|
||||
ctx.Exit()
|
||||
args = append(args, prompt)
|
||||
|
||||
cmd := exec.CommandContext(runCtx, exe, args...)
|
||||
cmd.Stderr = os.Stderr // surface agent progress/errors in the Actions log
|
||||
out, err := cmd.Output()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("agent run failed: %w", err)
|
||||
}
|
||||
return string(out), nil
|
||||
}
|
||||
|
||||
// hasUncommittedChanges reports whether the working tree has changes the agent
|
||||
// produced. In dry-run it reports the value of KIT_GITHUB_FAKE_DIRTY so tests
|
||||
// stay deterministic.
|
||||
func hasUncommittedChanges(ctx ext.Context) bool {
|
||||
if dryRun(ctx) {
|
||||
// hasUncommittedChanges reports whether the agent produced working-tree changes.
|
||||
func hasUncommittedChanges(ctx context.Context) bool {
|
||||
if githubDryRun() {
|
||||
return os.Getenv("KIT_GITHUB_FAKE_DIRTY") != ""
|
||||
}
|
||||
out := gitOutput(ctx, "status", "--porcelain")
|
||||
return strings.TrimSpace(out) != ""
|
||||
return strings.TrimSpace(gitOutput(ctx, "status", "--porcelain")) != ""
|
||||
}
|
||||
|
||||
// openPullRequest commits the working tree as kit-agent[bot], pushes a branch,
|
||||
// and opens a PR. It returns the PR URL, or "" on failure / dry-run.
|
||||
func openPullRequest(ctx ext.Context, tr *trigger, summary string) string {
|
||||
func openPullRequest(ctx context.Context, tr *trigger, summary string) string {
|
||||
branch := fmt.Sprintf("kit/issue-%d-%d", tr.number, time.Now().Unix())
|
||||
|
||||
runGit(ctx, "checkout", "-b", branch)
|
||||
runGit(ctx, "add", "-A")
|
||||
runGit(ctx, "-c", "user.name="+botName, "-c", "user.email="+botEmail,
|
||||
"commit", "-m", fmt.Sprintf("kit: address #%d", tr.number))
|
||||
|
||||
// `persist-credentials: false` in the workflow means the checkout left no
|
||||
// push credentials behind. Re-establish them from GITHUB_TOKEN via gh's git
|
||||
// credential helper, then push over the existing origin remote.
|
||||
if !githubDryRun() {
|
||||
runCmd(ctx, "gh", "auth", "setup-git")
|
||||
}
|
||||
runGit(ctx, "push", "origin", "HEAD:"+branch)
|
||||
|
||||
title := fmt.Sprintf("kit: changes for #%d", tr.number)
|
||||
body := fmt.Sprintf("Automated changes from Kit in response to #%d.\n\n%s", tr.number, summary)
|
||||
if dryRun(ctx) {
|
||||
ctx.Print(fmt.Sprintf("[dry-run] gh pr create --head %s --base %s", branch, tr.defaultBranch))
|
||||
if githubDryRun() {
|
||||
log.Info("github run: [dry-run] would open PR", "branch", branch, "base", tr.defaultBranch)
|
||||
return ""
|
||||
}
|
||||
url := ghOutput(ctx, "pr", "create", "--repo", tr.repo,
|
||||
"--head", branch, "--base", tr.defaultBranch,
|
||||
"--title", title, "--body", body)
|
||||
return strings.TrimSpace(url)
|
||||
return strings.TrimSpace(ghOutput(ctx, "pr", "create", "--repo", tr.repo,
|
||||
"--head", branch, "--base", tr.defaultBranch, "--title", title, "--body", body))
|
||||
}
|
||||
|
||||
// addReaction adds an emoji reaction to the trigger comment.
|
||||
func addReaction(ctx ext.Context, tr *trigger, content string) {
|
||||
func addReaction(ctx context.Context, tr *trigger, content string) {
|
||||
path := fmt.Sprintf("/repos/%s/%s/comments/%d/reactions", tr.repo, tr.commentKind, tr.commentID)
|
||||
if dryRun(ctx) || !commandExists("gh") {
|
||||
ctx.Print(fmt.Sprintf("[dry-run] react %q on %s", content, path))
|
||||
if githubDryRun() || !commandExists("gh") {
|
||||
log.Info("github run: [dry-run] react", "content", content, "path", path)
|
||||
return
|
||||
}
|
||||
runCmd(ctx, "gh", "api", "-X", "POST", path, "-f", "content="+content)
|
||||
}
|
||||
|
||||
// postComment posts a comment back on the triggering issue or pull request.
|
||||
func postComment(ctx ext.Context, tr *trigger, body string) {
|
||||
func postComment(ctx context.Context, tr *trigger, body string) {
|
||||
sub := "issue"
|
||||
if tr.isPR {
|
||||
sub = "pr"
|
||||
}
|
||||
if dryRun(ctx) || !commandExists("gh") {
|
||||
ctx.Print(fmt.Sprintf("[dry-run] gh %s comment %d --body <%d chars>", sub, tr.number, len(body)))
|
||||
if githubDryRun() || !commandExists("gh") {
|
||||
log.Info("github run: [dry-run] comment", "sub", sub, "number", tr.number, "chars", len(body))
|
||||
return
|
||||
}
|
||||
runCmd(ctx, "gh", sub, "comment", fmt.Sprint(tr.number), "--repo", tr.repo, "--body", body)
|
||||
@@ -438,46 +456,43 @@ func commandExists(name string) bool {
|
||||
}
|
||||
|
||||
// runGit runs a mutating git command, logging instead of executing in dry-run.
|
||||
func runGit(ctx ext.Context, args ...string) {
|
||||
if dryRun(ctx) {
|
||||
ctx.Print("[dry-run] git " + strings.Join(args, " "))
|
||||
func runGit(ctx context.Context, args ...string) {
|
||||
if githubDryRun() {
|
||||
log.Info("github run: [dry-run] git", "args", strings.Join(args, " "))
|
||||
return
|
||||
}
|
||||
runCmd(ctx, "git", args...)
|
||||
}
|
||||
|
||||
// gitOutput runs a read-only git command and returns its stdout.
|
||||
func gitOutput(ctx ext.Context, args ...string) string {
|
||||
cmdCtx, cancel := context.WithTimeout(context.Background(), subprocessTimeout)
|
||||
func gitOutput(ctx context.Context, args ...string) string {
|
||||
cmdCtx, cancel := context.WithTimeout(ctx, subprocessTimeout)
|
||||
defer cancel()
|
||||
cmd := exec.CommandContext(cmdCtx, "git", args...)
|
||||
out, err := cmd.Output()
|
||||
out, err := exec.CommandContext(cmdCtx, "git", args...).Output()
|
||||
if err != nil {
|
||||
ctx.PrintError(fmt.Sprintf("kit-github: git %s failed: %v", strings.Join(args, " "), err))
|
||||
log.Error("github run: git failed", "args", strings.Join(args, " "), "err", err)
|
||||
return ""
|
||||
}
|
||||
return string(out)
|
||||
}
|
||||
|
||||
// ghOutput runs a gh command and returns its stdout.
|
||||
func ghOutput(ctx ext.Context, args ...string) string {
|
||||
cmdCtx, cancel := context.WithTimeout(context.Background(), subprocessTimeout)
|
||||
func ghOutput(ctx context.Context, args ...string) string {
|
||||
cmdCtx, cancel := context.WithTimeout(ctx, subprocessTimeout)
|
||||
defer cancel()
|
||||
cmd := exec.CommandContext(cmdCtx, "gh", args...)
|
||||
out, err := cmd.Output()
|
||||
out, err := exec.CommandContext(cmdCtx, "gh", args...).Output()
|
||||
if err != nil {
|
||||
ctx.PrintError(fmt.Sprintf("kit-github: gh %s failed: %v", strings.Join(args, " "), err))
|
||||
log.Error("github run: gh failed", "args", strings.Join(args, " "), "err", err)
|
||||
return ""
|
||||
}
|
||||
return string(out)
|
||||
}
|
||||
|
||||
// runCmd runs a command for its side effects, surfacing failures via PrintError.
|
||||
func runCmd(ctx ext.Context, name string, args ...string) {
|
||||
cmdCtx, cancel := context.WithTimeout(context.Background(), subprocessTimeout)
|
||||
// runCmd runs a command for its side effects, surfacing failures in the log.
|
||||
func runCmd(ctx context.Context, name string, args ...string) {
|
||||
cmdCtx, cancel := context.WithTimeout(ctx, subprocessTimeout)
|
||||
defer cancel()
|
||||
cmd := exec.CommandContext(cmdCtx, name, args...)
|
||||
if out, err := cmd.CombinedOutput(); err != nil {
|
||||
ctx.PrintError(fmt.Sprintf("kit-github: %s failed: %v\n%s", name, err, strings.TrimSpace(string(out))))
|
||||
if out, err := exec.CommandContext(cmdCtx, name, args...).CombinedOutput(); err != nil {
|
||||
log.Error("github run: command failed", "cmd", name, "err", err, "output", strings.TrimSpace(string(out)))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// setupEvent writes a GitHub event payload to a temp file, points
|
||||
// GITHUB_EVENT_PATH at it, and forces dry-run + Actions mode. It also resets
|
||||
// the run command's package-level flag state so tests are independent.
|
||||
func setupEvent(t *testing.T, payload string) {
|
||||
t.Helper()
|
||||
path := filepath.Join(t.TempDir(), "event.json")
|
||||
if err := os.WriteFile(path, []byte(payload), 0o644); err != nil {
|
||||
t.Fatalf("write event: %v", err)
|
||||
}
|
||||
t.Setenv("GITHUB_ACTIONS", "true")
|
||||
t.Setenv("KIT_GITHUB_DRY_RUN", "1")
|
||||
t.Setenv("GITHUB_EVENT_PATH", path)
|
||||
t.Cleanup(func() {
|
||||
githubRunModel = ""
|
||||
githubRunDryRun = false
|
||||
})
|
||||
}
|
||||
|
||||
const issueCommentEvent = `{
|
||||
"action": "created",
|
||||
"comment": {
|
||||
"id": 555,
|
||||
"body": "/kit fix the broken parser",
|
||||
"author_association": "OWNER",
|
||||
"user": {"login": "alice"}
|
||||
},
|
||||
"issue": {"number": 42, "title": "Parser crashes on empty input", "body": "It panics."},
|
||||
"repository": {"full_name": "acme/widgets", "default_branch": "main"}
|
||||
}`
|
||||
|
||||
func TestExtractRequest(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
body string
|
||||
want string
|
||||
wantHit bool
|
||||
}{
|
||||
{"start with request", "/kit fix the bug", "fix the bug", true},
|
||||
{"bare token", "/kit", "", true},
|
||||
{"trailing token", "hey /kit", "", true},
|
||||
{"mid-sentence ignored", "please review /kit behavior in the docs", "", false},
|
||||
{"no token", "just a normal comment", "", false},
|
||||
{"token in second line", "thanks!\n/kit add tests", "add tests", true},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, hit := extractRequest(tt.body)
|
||||
if hit != tt.wantHit || got != tt.want {
|
||||
t.Errorf("extractRequest(%q) = (%q, %v), want (%q, %v)", tt.body, got, hit, tt.want, tt.wantHit)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildTrigger_IssueComment(t *testing.T) {
|
||||
event, err := func() (*ghEvent, error) {
|
||||
setupEvent(t, issueCommentEvent)
|
||||
return loadGitHubEvent()
|
||||
}()
|
||||
if err != nil {
|
||||
t.Fatalf("loadGitHubEvent: %v", err)
|
||||
}
|
||||
tr, err := buildTrigger(event)
|
||||
if err != nil {
|
||||
t.Fatalf("buildTrigger: %v", err)
|
||||
}
|
||||
if tr.repo != "acme/widgets" || tr.number != 42 || tr.isPR || tr.request != "fix the broken parser" {
|
||||
t.Errorf("unexpected trigger: %+v", tr)
|
||||
}
|
||||
if tr.commentKind != "issues" {
|
||||
t.Errorf("commentKind = %q, want issues", tr.commentKind)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildPrompt_ContainsContext(t *testing.T) {
|
||||
setupEvent(t, issueCommentEvent)
|
||||
event, _ := loadGitHubEvent()
|
||||
tr, _ := buildTrigger(event)
|
||||
|
||||
prompt := buildPrompt(tr, gatherContext(context.Background(), tr))
|
||||
for _, want := range []string{
|
||||
"fix the broken parser", // the request
|
||||
"acme/widgets", // the repo
|
||||
"issue #42", // the target
|
||||
"@alice", // the author
|
||||
"Parser crashes on empty input", // context: title
|
||||
"It panics.", // context: body
|
||||
} {
|
||||
if !strings.Contains(prompt, want) {
|
||||
t.Errorf("prompt missing %q\n---\n%s", want, prompt)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunGitHub_AuthorizedIssueComment(t *testing.T) {
|
||||
setupEvent(t, issueCommentEvent)
|
||||
if err := runGitHubRun(githubRunCmd, nil); err != nil {
|
||||
t.Fatalf("runGitHubRun: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunGitHub_UnauthorizedAssociation(t *testing.T) {
|
||||
setupEvent(t, strings.Replace(issueCommentEvent, `"OWNER"`, `"NONE"`, 1))
|
||||
// Should return nil (no-op) without attempting the agent run.
|
||||
if err := runGitHubRun(githubRunCmd, nil); err != nil {
|
||||
t.Fatalf("runGitHubRun should be a no-op for unauthorized authors, got: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunGitHub_CommentWithoutToken(t *testing.T) {
|
||||
setupEvent(t, strings.Replace(issueCommentEvent,
|
||||
`"/kit fix the broken parser"`, `"just a normal comment"`, 1))
|
||||
if err := runGitHubRun(githubRunCmd, nil); err != nil {
|
||||
t.Fatalf("runGitHubRun should be a no-op without /kit, got: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunGitHub_MidSentenceMentionIgnored(t *testing.T) {
|
||||
setupEvent(t, strings.Replace(issueCommentEvent,
|
||||
`"/kit fix the broken parser"`, `"please review /kit behavior in the docs"`, 1))
|
||||
if err := runGitHubRun(githubRunCmd, nil); err != nil {
|
||||
t.Fatalf("runGitHubRun should ignore mid-sentence mentions, got: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunGitHub_PullRequestReviewComment(t *testing.T) {
|
||||
setupEvent(t, `{
|
||||
"action": "created",
|
||||
"comment": {
|
||||
"id": 999,
|
||||
"body": "/kit review this change",
|
||||
"author_association": "COLLABORATOR",
|
||||
"user": {"login": "bob"}
|
||||
},
|
||||
"pull_request": {"number": 7, "title": "Add caching", "body": "Speeds things up."},
|
||||
"repository": {"full_name": "acme/widgets", "default_branch": "main"}
|
||||
}`)
|
||||
event, _ := loadGitHubEvent()
|
||||
tr, err := buildTrigger(event)
|
||||
if err != nil {
|
||||
t.Fatalf("buildTrigger: %v", err)
|
||||
}
|
||||
if !tr.isPR || tr.number != 7 || tr.commentKind != "pulls" {
|
||||
t.Errorf("unexpected PR trigger: %+v", tr)
|
||||
}
|
||||
if err := runGitHubRun(githubRunCmd, nil); err != nil {
|
||||
t.Fatalf("runGitHubRun (PR): %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunGitHub_RequiresActionsOrDryRun(t *testing.T) {
|
||||
// Neither GITHUB_ACTIONS nor dry-run set → must error rather than act.
|
||||
t.Setenv("GITHUB_ACTIONS", "")
|
||||
t.Setenv("KIT_GITHUB_DRY_RUN", "")
|
||||
githubRunDryRun = false
|
||||
t.Cleanup(func() { githubRunDryRun = false })
|
||||
if err := runGitHubRun(githubRunCmd, nil); err == nil {
|
||||
t.Fatal("expected an error when run outside Actions without --dry-run")
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveRunModel(t *testing.T) {
|
||||
t.Cleanup(func() { githubRunModel = "" })
|
||||
|
||||
t.Setenv("MODEL", "")
|
||||
githubRunModel = ""
|
||||
if got := resolveRunModel(); got != defaultGitHubModel {
|
||||
t.Errorf("default model = %q, want %q", got, defaultGitHubModel)
|
||||
}
|
||||
|
||||
t.Setenv("MODEL", "openai/gpt-5")
|
||||
if got := resolveRunModel(); got != "openai/gpt-5" {
|
||||
t.Errorf("MODEL env model = %q, want openai/gpt-5", got)
|
||||
}
|
||||
|
||||
githubRunModel = "anthropic/claude-sonnet-4-5"
|
||||
if got := resolveRunModel(); got != "anthropic/claude-sonnet-4-5" {
|
||||
t.Errorf("flag model = %q, want anthropic/claude-sonnet-4-5", got)
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -40,7 +40,7 @@ func TestRenderGitHubWorkflow(t *testing.T) {
|
||||
"github.event.comment.author_association == 'OWNER'",
|
||||
"github.event.comment.author_association == 'COLLABORATOR'",
|
||||
"persist-credentials: false",
|
||||
"uses: mark3labs/kit-action@v1",
|
||||
"uses: mark3labs/kit@v0",
|
||||
"model: anthropic/claude-sonnet-4-5-20250929",
|
||||
"GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}",
|
||||
"ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}",
|
||||
|
||||
@@ -83,7 +83,6 @@ kit install github.com/mark3labs/kit/examples/extensions --local
|
||||
| Extension | Description | Key API |
|
||||
|-----------|-------------|---------|
|
||||
| `kit-telegram/` | Telegram relay for remote monitoring & control | `RegisterCommand`, `OnAgentStart/End`, `SetStatus`, `SendMessage` |
|
||||
| `github-handler/` | Run Kit as a GitHub collaborator inside Actions (`/kit` comments → reviews & PRs) | `OnSessionStart`, `OnAgentEnd`, `SendMessage`, `RegisterOption` |
|
||||
|
||||
### Themes
|
||||
|
||||
@@ -147,15 +146,6 @@ Full-featured Telegram integration:
|
||||
- Status bar and widget updates
|
||||
- Config persistence with atomic writes
|
||||
|
||||
### github-handler/
|
||||
Run Kit as a GitHub collaborator inside GitHub Actions:
|
||||
- Parses the triggering event from `GITHUB_EVENT_PATH`
|
||||
- Permission gate on `author_association` (write/admin only)
|
||||
- 👀 reaction lifecycle on the trigger comment
|
||||
- Issue-thread / PR-diff context extraction via `gh`
|
||||
- Drives the agent, posts the response, and opens a PR for any changes
|
||||
- `KIT_GITHUB_DRY_RUN` mode for safe, deterministic testing
|
||||
|
||||
## Multi-File Extension Example
|
||||
|
||||
The `kit-kit-agents/` directory demonstrates the multi-file pattern:
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
# GitHub Handler Extension
|
||||
|
||||
The GitHub handler is the runtime half of Kit's GitHub integration (issue
|
||||
[#60](https://github.com/mark3labs/kit/issues/60), Phase 2b). It is designed to
|
||||
run **inside a GitHub Actions runner**, driven by the workflow that
|
||||
`kit github install` scaffolds.
|
||||
|
||||
When a collaborator comments `/kit <request>` on an issue or pull request, the
|
||||
workflow boots Kit headlessly with this extension loaded. The extension then:
|
||||
|
||||
1. **Parses** the triggering event from `GITHUB_EVENT_PATH`.
|
||||
2. **Enforces permissions** — only comments whose `author_association` is
|
||||
`OWNER`, `MEMBER`, or `COLLABORATOR` are acted on.
|
||||
3. **Reacts** with 👀 on the trigger comment so the human knows Kit is working.
|
||||
4. **Gathers context** — the issue thread, or the pull request diff and
|
||||
comments (via the `gh` CLI).
|
||||
5. **Drives the agent** with the request plus context.
|
||||
6. **Posts the response** back as a comment, and — if the agent left
|
||||
uncommitted changes — pushes a branch as the `kit-agent[bot]` identity and
|
||||
opens a pull request.
|
||||
7. **Swaps the reaction** to 🚀 (or 😕 on error) when finished.
|
||||
|
||||
Outside of GitHub Actions (i.e. when `GITHUB_ACTIONS != "true"`) the extension
|
||||
is inert, so it is safe to keep loaded during normal local use.
|
||||
|
||||
## Requirements
|
||||
|
||||
- The [`gh` CLI](https://cli.github.com/) on `PATH`, authenticated via
|
||||
`GITHUB_TOKEN` (GitHub Actions provides this automatically).
|
||||
- `git` on `PATH` with push access for opening pull requests.
|
||||
- A provider API key for the model Kit runs (e.g. `ANTHROPIC_API_KEY`).
|
||||
|
||||
## Usage in a workflow
|
||||
|
||||
`kit github install` writes `.github/workflows/kit.yml`. To wire in this
|
||||
handler, load it when invoking Kit headlessly inside the action, for example:
|
||||
|
||||
```bash
|
||||
kit --quiet --no-session \
|
||||
-e path/to/github-handler/main.go \
|
||||
--model "$KIT_MODEL"
|
||||
```
|
||||
|
||||
The extension reads the GitHub event itself, so no prompt argument is required —
|
||||
it constructs the prompt from the comment and repository context and drives the
|
||||
agent via the session lifecycle.
|
||||
|
||||
## Environment variables
|
||||
|
||||
| Variable | Purpose |
|
||||
|----------------------|---------------------------------------------------------------|
|
||||
| `GITHUB_ACTIONS` | Must be `true` for the handler to activate. |
|
||||
| `GITHUB_EVENT_PATH` | Path to the JSON event payload (set by Actions). |
|
||||
| `GITHUB_TOKEN` | Used by `gh`/`git` for API and push operations. |
|
||||
| `KIT_GITHUB_DRY_RUN` | When set, log `gh`/`git` side effects instead of running them. |
|
||||
|
||||
## Options
|
||||
|
||||
| Option | Default | Description |
|
||||
|-------------------|---------|------------------------------------------------------|
|
||||
| `github.dry-run` | `false` | Log GitHub/git side effects instead of executing. |
|
||||
|
||||
## Dry-run mode
|
||||
|
||||
Set `KIT_GITHUB_DRY_RUN=1` (or the `github.dry-run` option) to exercise the
|
||||
parsing, permission, and prompt-building logic without touching the network or
|
||||
the working tree. Every `gh`/`git` mutation is printed instead of executed.
|
||||
This is what the unit tests (`main_test.go`) use to stay deterministic.
|
||||
|
||||
## Security
|
||||
|
||||
- Triggers are gated to write/admin collaborators only.
|
||||
- The workflow uses `persist-credentials: false` and least-privilege
|
||||
`permissions`, mirroring established practice.
|
||||
- Commits are attributed to a dedicated `kit-agent[bot]` identity.
|
||||
@@ -1,209 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/mark3labs/kit/internal/extensions"
|
||||
"github.com/mark3labs/kit/pkg/extensions/test"
|
||||
)
|
||||
|
||||
// writeEvent writes a GitHub event payload to a temp file and points
|
||||
// GITHUB_EVENT_PATH at it. It also forces the extension into dry-run and
|
||||
// pretends we are running inside GitHub Actions.
|
||||
func writeEvent(t *testing.T, payload string) {
|
||||
t.Helper()
|
||||
path := filepath.Join(t.TempDir(), "event.json")
|
||||
if err := os.WriteFile(path, []byte(payload), 0o644); err != nil {
|
||||
t.Fatalf("write event: %v", err)
|
||||
}
|
||||
t.Setenv("GITHUB_ACTIONS", "true")
|
||||
t.Setenv("KIT_GITHUB_DRY_RUN", "1")
|
||||
t.Setenv("GITHUB_EVENT_PATH", path)
|
||||
}
|
||||
|
||||
const issueCommentEvent = `{
|
||||
"action": "created",
|
||||
"comment": {
|
||||
"id": 555,
|
||||
"body": "/kit fix the broken parser",
|
||||
"author_association": "OWNER",
|
||||
"user": {"login": "alice"}
|
||||
},
|
||||
"issue": {"number": 42, "title": "Parser crashes on empty input", "body": "It panics."},
|
||||
"repository": {"full_name": "acme/widgets", "default_branch": "main"}
|
||||
}`
|
||||
|
||||
func TestGitHubHandler_RegistersHandlers(t *testing.T) {
|
||||
harness := test.New(t)
|
||||
ext := harness.LoadFile("main.go")
|
||||
if ext == nil {
|
||||
t.Fatal("extension should not be nil")
|
||||
}
|
||||
test.AssertHasHandlers(t, harness, extensions.SessionStart)
|
||||
test.AssertHasHandlers(t, harness, extensions.AgentEnd)
|
||||
}
|
||||
|
||||
func TestGitHubHandler_InertOutsideActions(t *testing.T) {
|
||||
// No GITHUB_ACTIONS env → the handler must do nothing.
|
||||
t.Setenv("GITHUB_ACTIONS", "")
|
||||
harness := test.New(t)
|
||||
harness.LoadFile("main.go")
|
||||
|
||||
if _, err := harness.Emit(extensions.SessionStartEvent{SessionID: "s1"}); err != nil {
|
||||
t.Fatalf("emit: %v", err)
|
||||
}
|
||||
if msgs := harness.Context().Messages; len(msgs) != 0 {
|
||||
t.Errorf("expected no messages outside Actions, got %v", msgs)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGitHubHandler_AuthorizedIssueComment(t *testing.T) {
|
||||
writeEvent(t, issueCommentEvent)
|
||||
|
||||
harness := test.New(t)
|
||||
harness.LoadFile("main.go")
|
||||
if _, err := harness.Emit(extensions.SessionStartEvent{SessionID: "s1"}); err != nil {
|
||||
t.Fatalf("emit: %v", err)
|
||||
}
|
||||
|
||||
msgs := harness.Context().Messages
|
||||
if len(msgs) != 1 {
|
||||
t.Fatalf("expected exactly one driven prompt, got %d: %v", len(msgs), msgs)
|
||||
}
|
||||
prompt := msgs[0]
|
||||
for _, want := range []string{
|
||||
"fix the broken parser", // the request
|
||||
"acme/widgets", // the repo
|
||||
"issue #42", // the target
|
||||
"@alice", // the author
|
||||
"Parser crashes on empty input", // context: title
|
||||
"It panics.", // context: body
|
||||
} {
|
||||
if !strings.Contains(prompt, want) {
|
||||
t.Errorf("prompt missing %q\n---\n%s", want, prompt)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGitHubHandler_UnauthorizedAssociation(t *testing.T) {
|
||||
writeEvent(t, strings.Replace(issueCommentEvent, `"OWNER"`, `"NONE"`, 1))
|
||||
|
||||
harness := test.New(t)
|
||||
harness.LoadFile("main.go")
|
||||
if _, err := harness.Emit(extensions.SessionStartEvent{SessionID: "s1"}); err != nil {
|
||||
t.Fatalf("emit: %v", err)
|
||||
}
|
||||
|
||||
if msgs := harness.Context().Messages; len(msgs) != 0 {
|
||||
t.Fatalf("unauthorized author must not drive the agent, got %v", msgs)
|
||||
}
|
||||
if errs := harness.Context().GetPrintErrors(); len(errs) == 0 ||
|
||||
!strings.Contains(strings.Join(errs, "\n"), "lacks write access") {
|
||||
t.Errorf("expected a write-access error, got %v", errs)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGitHubHandler_CommentWithoutToken(t *testing.T) {
|
||||
writeEvent(t, strings.Replace(issueCommentEvent,
|
||||
`"/kit fix the broken parser"`, `"just a normal comment"`, 1))
|
||||
|
||||
harness := test.New(t)
|
||||
harness.LoadFile("main.go")
|
||||
if _, err := harness.Emit(extensions.SessionStartEvent{SessionID: "s1"}); err != nil {
|
||||
t.Fatalf("emit: %v", err)
|
||||
}
|
||||
if msgs := harness.Context().Messages; len(msgs) != 0 {
|
||||
t.Fatalf("non-/kit comment must not drive the agent, got %v", msgs)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGitHubHandler_MidSentenceMentionIgnored(t *testing.T) {
|
||||
// An incidental mid-sentence mention of the token must not trigger Kit.
|
||||
writeEvent(t, strings.Replace(issueCommentEvent,
|
||||
`"/kit fix the broken parser"`, `"please review /kit behavior in the docs"`, 1))
|
||||
|
||||
harness := test.New(t)
|
||||
harness.LoadFile("main.go")
|
||||
if _, err := harness.Emit(extensions.SessionStartEvent{SessionID: "s1"}); err != nil {
|
||||
t.Fatalf("emit: %v", err)
|
||||
}
|
||||
if msgs := harness.Context().Messages; len(msgs) != 0 {
|
||||
t.Fatalf("mid-sentence /kit mention must not drive the agent, got %v", msgs)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGitHubHandler_PullRequestReviewComment(t *testing.T) {
|
||||
writeEvent(t, `{
|
||||
"action": "created",
|
||||
"comment": {
|
||||
"id": 999,
|
||||
"body": "/kit review this change",
|
||||
"author_association": "COLLABORATOR",
|
||||
"user": {"login": "bob"}
|
||||
},
|
||||
"pull_request": {"number": 7, "title": "Add caching", "body": "Speeds things up."},
|
||||
"repository": {"full_name": "acme/widgets", "default_branch": "main"}
|
||||
}`)
|
||||
|
||||
harness := test.New(t)
|
||||
harness.LoadFile("main.go")
|
||||
if _, err := harness.Emit(extensions.SessionStartEvent{SessionID: "s1"}); err != nil {
|
||||
t.Fatalf("emit: %v", err)
|
||||
}
|
||||
msgs := harness.Context().Messages
|
||||
if len(msgs) != 1 {
|
||||
t.Fatalf("expected one driven prompt, got %v", msgs)
|
||||
}
|
||||
if !strings.Contains(msgs[0], "pull request #7") {
|
||||
t.Errorf("expected PR target in prompt:\n%s", msgs[0])
|
||||
}
|
||||
}
|
||||
|
||||
func TestGitHubHandler_AgentEndPostsComment(t *testing.T) {
|
||||
writeEvent(t, issueCommentEvent)
|
||||
|
||||
harness := test.New(t)
|
||||
harness.LoadFile("main.go")
|
||||
if _, err := harness.Emit(extensions.SessionStartEvent{SessionID: "s1"}); err != nil {
|
||||
t.Fatalf("emit session start: %v", err)
|
||||
}
|
||||
if _, err := harness.Emit(extensions.AgentEndEvent{
|
||||
Response: "Fixed the parser by guarding empty input.",
|
||||
StopReason: "completed",
|
||||
}); err != nil {
|
||||
t.Fatalf("emit agent end: %v", err)
|
||||
}
|
||||
|
||||
prints := strings.Join(harness.Context().GetPrints(), "\n")
|
||||
if !strings.Contains(prints, "gh issue comment 42") {
|
||||
t.Errorf("expected a dry-run comment post, got prints:\n%s", prints)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGitHubHandler_AgentEndOpensPRWhenDirty(t *testing.T) {
|
||||
writeEvent(t, issueCommentEvent)
|
||||
t.Setenv("KIT_GITHUB_FAKE_DIRTY", "1")
|
||||
|
||||
harness := test.New(t)
|
||||
harness.LoadFile("main.go")
|
||||
if _, err := harness.Emit(extensions.SessionStartEvent{SessionID: "s1"}); err != nil {
|
||||
t.Fatalf("emit session start: %v", err)
|
||||
}
|
||||
if _, err := harness.Emit(extensions.AgentEndEvent{
|
||||
Response: "Made changes.",
|
||||
StopReason: "completed",
|
||||
}); err != nil {
|
||||
t.Fatalf("emit agent end: %v", err)
|
||||
}
|
||||
|
||||
prints := strings.Join(harness.Context().GetPrints(), "\n")
|
||||
if !strings.Contains(prints, "gh pr create") {
|
||||
t.Errorf("expected a dry-run PR creation, got prints:\n%s", prints)
|
||||
}
|
||||
if !strings.Contains(prints, "git checkout -b kit/issue-42-") {
|
||||
t.Errorf("expected a dry-run branch checkout, got prints:\n%s", prints)
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,13 @@
|
||||
module github.com/mark3labs/kit
|
||||
|
||||
go 1.26.3
|
||||
go 1.26.4
|
||||
|
||||
require (
|
||||
charm.land/bubbles/v2 v2.1.0
|
||||
charm.land/bubbletea/v2 v2.0.7
|
||||
charm.land/fantasy v0.25.0
|
||||
charm.land/fantasy v0.31.0
|
||||
charm.land/huh/v2 v2.0.3
|
||||
charm.land/lipgloss/v2 v2.0.3
|
||||
charm.land/lipgloss/v2 v2.0.4
|
||||
github.com/alecthomas/chroma/v2 v2.26.1
|
||||
github.com/atotto/clipboard v0.1.4
|
||||
github.com/aymanbagabas/go-udiff v0.4.1
|
||||
@@ -15,7 +15,7 @@ require (
|
||||
github.com/charmbracelet/fang v1.0.0
|
||||
github.com/charmbracelet/log v1.0.0
|
||||
github.com/charmbracelet/openai-go v0.0.0-20260319145158-d0740cc34266
|
||||
github.com/charmbracelet/ultraviolet v0.0.0-20260601155805-6cf7526a1b3f
|
||||
github.com/charmbracelet/ultraviolet v0.0.0-20260615092913-2399af76d5b1
|
||||
github.com/charmbracelet/x/editor v0.2.0
|
||||
github.com/clipperhouse/displaywidth v0.11.0
|
||||
github.com/clipperhouse/uax29/v2 v2.7.0
|
||||
@@ -27,8 +27,8 @@ require (
|
||||
github.com/spf13/cobra v1.10.2
|
||||
github.com/spf13/viper v1.21.0
|
||||
github.com/traefik/yaegi v0.16.1
|
||||
golang.org/x/image v0.41.0
|
||||
golang.org/x/term v0.43.0
|
||||
golang.org/x/image v0.42.0
|
||||
golang.org/x/term v0.44.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
@@ -37,41 +37,41 @@ require (
|
||||
cloud.google.com/go/auth v0.20.0 // indirect
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.9.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.1 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.22.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.12.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2 v1.41.8 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.10 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.19 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.18 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.24 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.24 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.24 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.25 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.9 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.24 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/signin v1.1.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.18 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.36.1 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.42.2 // indirect
|
||||
github.com/aws/smithy-go v1.26.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2 v1.42.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.13 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.25 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.24 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.29 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.29 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.29 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.30 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.12 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.29 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/signin v1.2.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.31.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.36.6 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.43.3 // indirect
|
||||
github.com/aws/smithy-go v1.27.2 // indirect
|
||||
github.com/catppuccin/go v0.3.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/charmbracelet/anthropic-sdk-go v0.0.0-20260223140439-63879b0b8dab // indirect
|
||||
github.com/charmbracelet/harmonica v0.2.0 // indirect
|
||||
github.com/charmbracelet/lipgloss v1.1.1-0.20250404203927-76690c660834 // indirect
|
||||
github.com/charmbracelet/x/cellbuf v0.0.15 // indirect
|
||||
github.com/charmbracelet/x/exp/charmtone v0.0.0-20260602025833-85a30b5e440a // indirect
|
||||
github.com/charmbracelet/x/exp/charmtone v0.0.0-20260615092313-b57e5e6d29bb // indirect
|
||||
github.com/charmbracelet/x/exp/ordered v0.1.0 // indirect
|
||||
github.com/charmbracelet/x/exp/slice v0.0.0-20260527151214-009e6338d40d // indirect
|
||||
github.com/charmbracelet/x/exp/slice v0.0.0-20260615092313-b57e5e6d29bb // indirect
|
||||
github.com/charmbracelet/x/exp/strings v0.1.0 // indirect
|
||||
github.com/charmbracelet/x/json v0.2.0 // indirect
|
||||
github.com/charmbracelet/x/termios v0.1.1 // indirect
|
||||
github.com/charmbracelet/x/windows v0.2.2 // indirect
|
||||
github.com/dlclark/regexp2 v1.12.0 // indirect
|
||||
github.com/dlclark/regexp2/v2 v2.1.1 // indirect
|
||||
github.com/dlclark/regexp2/v2 v2.2.2 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/go-json-experiment/json v0.0.0-20260520185125-572e7c383686 // indirect
|
||||
github.com/felixge/httpsnoop v1.1.0 // indirect
|
||||
github.com/go-json-experiment/json v0.0.0-20260601182631-00ed12fed2a6 // indirect
|
||||
github.com/go-logfmt/logfmt v0.6.1 // indirect
|
||||
github.com/go-logr/logr v1.4.3 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
@@ -84,10 +84,8 @@ require (
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.16 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.22.0 // indirect
|
||||
github.com/gorilla/websocket v1.5.3 // indirect
|
||||
github.com/kaptinlin/go-i18n v0.4.5 // indirect
|
||||
github.com/kaptinlin/jsonpointer v0.4.25 // indirect
|
||||
github.com/kaptinlin/jsonschema v0.7.13 // indirect
|
||||
github.com/kaptinlin/messageformat-go v0.6.0 // indirect
|
||||
github.com/kaptinlin/jsonpointer v0.4.26 // indirect
|
||||
github.com/kaptinlin/jsonschema v0.8.0 // indirect
|
||||
github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect
|
||||
github.com/muesli/mango v0.2.0 // indirect
|
||||
github.com/muesli/mango-cobra v1.3.0 // indirect
|
||||
@@ -113,14 +111,14 @@ require (
|
||||
go.opentelemetry.io/otel/metric v1.44.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.44.0 // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||
golang.org/x/crypto v0.52.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20260603202125-055de637280b // indirect
|
||||
golang.org/x/net v0.55.0 // indirect
|
||||
golang.org/x/crypto v0.53.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20260611194520-c48552f49976 // indirect
|
||||
golang.org/x/net v0.56.0 // indirect
|
||||
golang.org/x/oauth2 v0.36.0 // indirect
|
||||
golang.org/x/time v0.15.0 // indirect
|
||||
google.golang.org/api v0.282.0 // indirect
|
||||
google.golang.org/genai v1.58.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa // indirect
|
||||
google.golang.org/api v0.284.0 // indirect
|
||||
google.golang.org/genai v1.60.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260615183401-62b3387ff324 // indirect
|
||||
google.golang.org/grpc v1.81.1 // indirect
|
||||
google.golang.org/protobuf v1.36.11 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
@@ -138,7 +136,7 @@ require (
|
||||
github.com/muesli/termenv v0.16.0 // indirect
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
github.com/spf13/pflag v1.0.10
|
||||
golang.org/x/sync v0.20.0 // indirect
|
||||
golang.org/x/sys v0.45.0 // indirect
|
||||
golang.org/x/text v0.37.0
|
||||
golang.org/x/sync v0.21.0 // indirect
|
||||
golang.org/x/sys v0.46.0 // indirect
|
||||
golang.org/x/text v0.38.0
|
||||
)
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
cel.dev/expr v0.25.2/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4=
|
||||
charm.land/bubbles/v2 v2.1.0 h1:YSnNh5cPYlYjPxRrzs5VEn3vwhtEn3jVGRBT3M7/I0g=
|
||||
charm.land/bubbles/v2 v2.1.0/go.mod h1:l97h4hym2hvWBVfmJDtrEHHCtkIKeTEb3TTJ4ZOB3wY=
|
||||
charm.land/bubbletea/v2 v2.0.7 h1:7qw2tTAVar7m7klOPBYfTB0mniv/RuexsYwMRNxSeL0=
|
||||
charm.land/bubbletea/v2 v2.0.7/go.mod h1:DGW2q8gvzHnOpMpZTORs0aySVHCox5C+2Svk0fci1qs=
|
||||
charm.land/fantasy v0.25.0 h1:oXOWY1ivmTSnhYGzAolscF8zKtavWZyBWv0LHRSwN5Q=
|
||||
charm.land/fantasy v0.25.0/go.mod h1:8QrWUzIcKwZQP+aAnC9vLu3iID6hu9/Jt+rPMiieBkc=
|
||||
charm.land/fantasy v0.31.0 h1:ioLVRi7A8lZXR8mrCIeseuCcq0KqAak46revmGumnpc=
|
||||
charm.land/fantasy v0.31.0/go.mod h1:lAE2gO68SrB1S5TrW5g0TRoxz9V+qJcg0Elx/uPWsDI=
|
||||
charm.land/huh/v2 v2.0.3 h1:2cJsMqEPwSywGHvdlKsJyQKPtSJLVnFKyFbsYZTlLkU=
|
||||
charm.land/huh/v2 v2.0.3/go.mod h1:93eEveeeqn47MwiC3tf+2atZ2l7Is88rAtmZNZ8x9Wc=
|
||||
charm.land/lipgloss/v2 v2.0.3 h1:yM2zJ4Cf5Y51b7RHIwioil4ApI/aypFXXVHSwlM6RzU=
|
||||
charm.land/lipgloss/v2 v2.0.3/go.mod h1:7myLU9iG/3xluAWzpY/fSxYYHCgoKTie7laxk6ATwXA=
|
||||
charm.land/x/vcr v0.1.1/go.mod h1:eByq2gqzWvcct/8XE2XO5KznoWEBiXH56+y2gphbltM=
|
||||
charm.land/lipgloss/v2 v2.0.4 h1:lcPeVtcp23SNra7lHy8iYE4UC2aIipVQ47sbGyyxR5Q=
|
||||
charm.land/lipgloss/v2 v2.0.4/go.mod h1:0653x8epbZSzdDfO/XPS1a/uYPOBeSsCssOpJOqDzik=
|
||||
cloud.google.com/go v0.123.0 h1:2NAUJwPR47q+E35uaJeYoNhuNEM9kM8SjgRgdeOJUSE=
|
||||
cloud.google.com/go v0.123.0/go.mod h1:xBoMV08QcqUGuPW65Qfm1o9Y4zKZBpGS+7bImXLTAZU=
|
||||
cloud.google.com/go/auth v0.20.0 h1:kXTssoVb4azsVDoUiF8KvxAqrsQcQtB53DcSgta74CA=
|
||||
@@ -18,81 +16,60 @@ cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIi
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c=
|
||||
cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs=
|
||||
cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10=
|
||||
cloud.google.com/go/iam v1.11.0/go.mod h1:KP+nKGugNJW4LcLx1uEZcq1ok5sQHFaQehQNl4QDgV4=
|
||||
cloud.google.com/go/longrunning v0.5.6/go.mod h1:vUaDrWYOMKRuhiv6JBnn49YxCPz2Ayn9GqyjaBT8/mA=
|
||||
cloud.google.com/go/monitoring v1.29.0/go.mod h1:72NOVjJXHY/HBfoLT0+qlCZBT059+9VXLeAnL2PeeVM=
|
||||
cloud.google.com/go/storage v1.62.1/go.mod h1:cpYz/kRVZ+UQAF1uHeea10/9ewcRbxGoGNKsS9daSXA=
|
||||
cloud.google.com/go/translate v1.10.3/go.mod h1:GW0vC1qvPtd3pgtypCv4k4U8B7EdgK9/QEF2aJEUovs=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.1 h1:jHb/wfvRikGdxMXYV3QG/SzUOPYN9KEUUuC0Yd0/vC0=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.1/go.mod h1:pzBXCYn05zvYIrwLgtK8Ap8QcjRg+0i76tMQdWN6wOk=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.22.0 h1:aokoqcHvaGjiM3VpjKDfMMnF/8epJ+Q1HLJ7CudztqE=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.22.0/go.mod h1:/WYEx9pcM9Y+Dd/APJaNlSvVSvzl54rrMdZT5+Oi2LM=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1 h1:Hk5QBxZQC1jb2Fwj6mpzme37xbCDdNTxU7O9eb5+LB4=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1/go.mod h1:IYus9qsFobWIc2YVwe/WPjcnyCkPKtnHAqUYeebc8z0=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.12.0 h1:fhqpLE3UEXi9lPaBRpQ6XuRW0nU7hgg4zlmZZa+a9q4=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.12.0/go.mod h1:7dCRMLwisfRH3dBupKeNCioWYUZ4SS09Z14H+7i8ZoY=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0 h1:XRzhVemXdgvJqCH0sFfrBUTnUJSBrBf7++ypk+twtRs=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0/go.mod h1:HKpQxkWaGLJ+D/5H8QRpyQXA1eKjxkFlOMwck5+33Jk=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.32.0/go.mod h1:RD2SsorTmYhF6HkTmDw7KmPYQk8OBYwTkuasChwv7R4=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.56.0/go.mod h1:hEpiGU18xf70qb3jbTcIggWAiEfX/cOIVc2OTe4OegA=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.56.0/go.mod h1:6ZZMQhZKDvUvkJw2rc+oDP90tMMzuU/J+5HG1ZmPOmE=
|
||||
github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ=
|
||||
github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE=
|
||||
github.com/Rhymond/go-money v1.0.15/go.mod h1:iHvCuIvitxu2JIlAlhF0g9jHqjRSr+rpdOs7Omqlupg=
|
||||
github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0=
|
||||
github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
|
||||
github.com/alecthomas/chroma/v2 v2.26.1 h1:2X21EdxGZNv5GF9mG5u+uzc02GCFyGxbcBm3Grd9A78=
|
||||
github.com/alecthomas/chroma/v2 v2.26.1/go.mod h1:lxhRRa9H4hPmRLOOdYga4zkQIQjq3dtrrdwQeCfu78Y=
|
||||
github.com/alecthomas/repr v0.5.2 h1:SU73FTI9D1P5UNtvseffFSGmdNci/O6RsqzeXJtP0Qs=
|
||||
github.com/alecthomas/repr v0.5.2/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
|
||||
github.com/ardanlabs/jinja v1.2.0/go.mod h1:aXXzlJfjA+T3XNKA/YT5ZtDq2VJxt5a5siZ8cl9B35Q=
|
||||
github.com/ardanlabs/kronk v1.25.2/go.mod h1:b5Gg4jDqvHDklkeHNB8+7treZRxUiCFsV65zphrTloY=
|
||||
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
|
||||
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
|
||||
github.com/aws/aws-sdk-go-v2 v1.41.8 h1:sRs7nG6/RiEBZ/K5UO2sNw0w40U02Nmz1VtARloTZXk=
|
||||
github.com/aws/aws-sdk-go-v2 v1.41.8/go.mod h1:4LAfZOPHNVNQEckOACQx60Y8pSRjIkNZQz1w92xpMJc=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.10 h1:gx1AwW1Iyk9Z9dD9F4akX5gnN3QZwUB20GGKH/I+Rho=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.10/go.mod h1:qqY157uZoqm5OXq/amuaBJyC9hgBCBQnsaWnPe905GY=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.19 h1:qRhIJMbevHUvIE7X4TK8N8zye5+5AhapcslPrvB+qKE=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.19/go.mod h1:RbJ24nfoya63+Mf5VI+CGCGk9vEdv28xPeii+gojRYs=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.18 h1:GcXQz2M/0ZvMo0v5DakUqbDBeBM1ZNaivkolEF4Esgw=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.18/go.mod h1:sHJ06tMGcD3ZpmMyJqV+VBsGilhSIZPIN+ZFy5Dg0C4=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.24 h1:FQm5ApnyzkuJdXLGskPce83CK1CQKC4RUnIHKVe4BU4=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.24/go.mod h1:JsC7dqQc55MlZ5mvNsDMMge71u8pVcSzU3RNz2h/5yQ=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.24 h1:u6kJU2i0va1AgtJsH3RdWKWqHULlTh7zHwb35Womf74=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.24/go.mod h1:7GY+xLcXOFUpCkNwDReft9qOAVg54A4/AnjHIU7sSAY=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.24 h1:Xhbcf3KugX6vX7SDyUK205Oicyfg7EGuvoVNyP5L6DM=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.24/go.mod h1:rwDgb2HNOGZsnTHylOUedM7Vnl+bCfnXDqUNPsFWYfk=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.25 h1:54CTMmlJ71Rk2dYvM9qZOob+39wjlVja2zDLxCu69Ew=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.25/go.mod h1:BZaHqxsS9vN1fvV5EfEl0OBLOk5+AajWsMu6MjqnZB4=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.9 h1:FLudkZLt5ci0ozzgkVo8BJGwvqNaZbTWb3UcucAateA=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.9/go.mod h1:w7wZ/s9qK7c8g4al+UyoF1Sp/Z45UwMGcqIzLWVQHWk=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.15/go.mod h1:e3IzZvQ3kAWNykvE0Tr0RDZCMFInMvhku3qNpcIQXhM=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.24 h1:CQW2FTrflfoslYWLf3fv7vG28Q219+v8YJS5QTQb2+Y=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.24/go.mod h1:Xfx13T+u3nH6EEzgl9fBSO6nDRmze1FvnZNYkctQ2zw=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.23/go.mod h1:M8l3mwgx5ToK7wot2sBBce/ojzgnPzZXUV445gTSyE8=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.101.0/go.mod h1:L2dcoOgS2VSgbPLvpak2NyUPsO1TBN7M45Z4H7DlRc4=
|
||||
github.com/aws/aws-sdk-go-v2/service/signin v1.1.0 h1:yQo3eZ5qFaL1sJWqs1nL6j3yPHA2/R7c6tQ4T+0IO10=
|
||||
github.com/aws/aws-sdk-go-v2/service/signin v1.1.0/go.mod h1:3Zzou41Qt/ueXfIzHvTEjDNuR5IjCUBVF01SNhrt1e8=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.18 h1:ApLTFdAZfDhZSiY5uskwECKHkSNNF83y2Ru2r7SezWA=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.18/go.mod h1:A9K9qx2l6nK89hp+a350FdGfRkrkH5HdiEjHbiy/Q/c=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.36.1 h1:4VD7TIZOGzehrgQ8vDE+1c6BQW4ErZPGY8ohZT5LXEE=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.36.1/go.mod h1:er0SFJfdV89Rit5hIJu/EXtv+qC2XMnxoksLmcUFkqM=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.42.2 h1:XKnxlM4KZH1gktcsh3zSWc7GW4KivEv/OkifmHOhCUY=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.42.2/go.mod h1:KJYmkQaFB3SUW2j3aBkPsxNmAb4ZsSOvbvCpuxzHJA0=
|
||||
github.com/aws/smithy-go v1.26.0 h1:9ouqbi+NyKP7fV3Te7UElCwdAb6Y8uk7LGwPE5tVe/s=
|
||||
github.com/aws/smithy-go v1.26.0/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc=
|
||||
github.com/aws/aws-sdk-go-v2 v1.42.0 h1:XvXMJTkFQtpBKIWZnmr9ZEOc2InWM2yldjXEJ/bymhA=
|
||||
github.com/aws/aws-sdk-go-v2 v1.42.0/go.mod h1:27+ACypSLljLAEKsCYOmrjKh83vuTRkuAe9Uv/3A4bg=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.13 h1:p1BBrg/Hhp6uK7zpejeI8QFXHJeC/mynzi04Sl03k9g=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.13/go.mod h1:8cIfkE9MDhkRZGpQ22aV6/lkYeYSozpz16Smrs5x4Ls=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.25 h1:ACCejvStYoilgwrfegSt5ZntCbPrk52qfwyNcnl3omM=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.25/go.mod h1:LJyU8sDRbXUxFn8xMJIGP+v9QYYwveNLI8a/giAOiAs=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.24 h1:2hQqYCV9yqyePQ9o6dCrZc/zO8U3TwPr9mIKlZnPu/I=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.24/go.mod h1:IDwpACtwqHLISdzfwUUNq4P9DsB/h5BLg4FwJPNfqFY=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.29 h1:r6qZHbT+wxgWO/e9vYNUEtg7lv5+UN3pRqKhLXvnArg=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.29/go.mod h1:QRnaRcTVGKPGRy8w78HMQtKUGRYcnMZAANATkeVA6Mo=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.29 h1:f3vKqSo13fhTYb+JEcXwXefZQE26I1FB5eTSniU67ko=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.29/go.mod h1:MzoLFUArKGpGD+ukmPiTPG1X5x4o6M2kq4v2dr1FiEc=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.29 h1:RdwIf/CuUsvJX3RgJagbOyotl/cxoLY4xviKuE7p2GY=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.29/go.mod h1:71wt8W2EgswdZy9Mf9KNnzxZ3TiZlv4caKghPktDOkA=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.30 h1:VTGy885W5DKBxWRUJbym9hytNaYzsyaPkCHGRRMAOhU=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.30/go.mod h1:AS0HycUvJRFvTt613AYDOgO2jzw+00cVSMny8XB3yMY=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.12 h1:ZD2+BSw9vFsNlKYIasSNt3uDbjqqXIBcM13UJv/Lx2k=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.12/go.mod h1:Ms4zlcVBbXbiP7EVLhl+lgjvA/a7YphqQ3Ih3174EmI=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.29 h1:DRebniUGZ2MqiiIVmQJ04vIXr918hubdHMnarSLEWyU=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.29/go.mod h1:LfRkPCD8YHDM2E5eTkos2UpwYeZnBcVarTa8L59bJHA=
|
||||
github.com/aws/aws-sdk-go-v2/service/signin v1.2.0 h1:3nXpRcFwRCW8n7HgO2QGy0Dc20eQNfBuUemGQhpF8m8=
|
||||
github.com/aws/aws-sdk-go-v2/service/signin v1.2.0/go.mod h1:LxYujSTLPRlp2vTtcUO/+1ilrew8ytt6SvQyOgejzFQ=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.31.3 h1:ey1XLTYXb9PcLt4535632o5kCGXNXEhNb620Dqwuylo=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.31.3/go.mod h1:Lk7PlmoTYryQmyBG0EXqj5BcUbj3whXdU2s3yGI3EAc=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.36.6 h1:yLr03zQE/5Eu5l3QU0Si+xMbLMbSDF2YXsigqXngs6g=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.36.6/go.mod h1:Q5N6icH+KJZDLh+ESNwzdv6cZ6vLFF/egy3IOxWhmz4=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.43.3 h1:VrIhKRCSK1umelSgB9RghvA9RTUYeQffyAS5ApXehNI=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.43.3/go.mod h1:r8wkDOuLaaMFqFiYAb8dGY2A3gJCOujMc6CFOVC4Zhc=
|
||||
github.com/aws/smithy-go v1.27.2 h1:y9NPmSE6am6LjEFPfqHqG/jJk7AauQvhCJONKh7kpzk=
|
||||
github.com/aws/smithy-go v1.27.2/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc=
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
|
||||
github.com/aymanbagabas/go-udiff v0.4.1 h1:OEIrQ8maEeDBXQDoGCbbTTXYJMYRCRO1fnodZ12Gv5o=
|
||||
github.com/aymanbagabas/go-udiff v0.4.1/go.mod h1:0L9PGwj20lrtmEMeyw4WKJ/TMyDtvAoK9bf2u/mNo3w=
|
||||
github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4=
|
||||
github.com/bits-and-blooms/bitset v1.24.4/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
||||
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
|
||||
github.com/catppuccin/go v0.3.0 h1:d+0/YicIq+hSTo5oPuRi5kOpqkVA5tAsU6dNhvRu+aY=
|
||||
github.com/catppuccin/go v0.3.0/go.mod h1:8IHJuMGaUUjQM82qBrGNBv7LFq6JI3NnQCF6MOlZjpc=
|
||||
github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/charmbracelet/anthropic-sdk-go v0.0.0-20260223140439-63879b0b8dab h1:J7XQLgl9sefgTnTGrmX3xqvp5o6MCiBzEjGv5igAlc4=
|
||||
@@ -109,8 +86,8 @@ github.com/charmbracelet/log v1.0.0 h1:HVVVMmfOorfj3BA9i8X8UL69Hoz9lI0PYwXfJvOdR
|
||||
github.com/charmbracelet/log v1.0.0/go.mod h1:uYgY3SmLpwJWxmlrPwXvzVYujxis1vAKRV/0VQB7yWA=
|
||||
github.com/charmbracelet/openai-go v0.0.0-20260319145158-d0740cc34266 h1:BW/sZtyd1JyYy0h5adMm3tzpNyL857LWjuTRET6OhpY=
|
||||
github.com/charmbracelet/openai-go v0.0.0-20260319145158-d0740cc34266/go.mod h1:1DahUaExbUZx/jD+FNT2PKP4L9rLE5+ZBRuI8mZjd/E=
|
||||
github.com/charmbracelet/ultraviolet v0.0.0-20260601155805-6cf7526a1b3f h1:vKsPSlO4g4jKfJ9enESgNZ45BkbHngTIq3UxNOzic74=
|
||||
github.com/charmbracelet/ultraviolet v0.0.0-20260601155805-6cf7526a1b3f/go.mod h1:hFpumms29Smx3LStRfku8vcCTBe1Kq8aCXtHUJa3mjY=
|
||||
github.com/charmbracelet/ultraviolet v0.0.0-20260615092913-2399af76d5b1 h1:4+r3uOJ69ueRBt4okgEfWZeXs3BD36HcDBmOIAUlETk=
|
||||
github.com/charmbracelet/ultraviolet v0.0.0-20260615092913-2399af76d5b1/go.mod h1:f/jRa757WUmaOZrbPspXymbg/GnbF+rwe4OLsG7aXYo=
|
||||
github.com/charmbracelet/x/ansi v0.11.7 h1:kzv1kJvjg2S3r9KHo8hDdHFQLEqn4RBCb39dAYC84jI=
|
||||
github.com/charmbracelet/x/ansi v0.11.7/go.mod h1:9qGpnAVYz+8ACONkZBUWPtL7lulP9No6p1epAihUZwQ=
|
||||
github.com/charmbracelet/x/cellbuf v0.0.15 h1:ur3pZy0o6z/R7EylET877CBxaiE1Sp1GMxoFPAIztPI=
|
||||
@@ -121,14 +98,14 @@ github.com/charmbracelet/x/editor v0.2.0 h1:7XLUKtaRaB8jN7bWU2p2UChiySyaAuIfYiIR
|
||||
github.com/charmbracelet/x/editor v0.2.0/go.mod h1:p3oQ28TSL3YPd+GKJ1fHWcp+7bVGpedHpXmo0D6t1dY=
|
||||
github.com/charmbracelet/x/errors v0.0.0-20240508181413-e8d8b6e2de86 h1:JSt3B+U9iqk37QUU2Rvb6DSBYRLtWqFqfxf8l5hOZUA=
|
||||
github.com/charmbracelet/x/errors v0.0.0-20240508181413-e8d8b6e2de86/go.mod h1:2P0UgXMEa6TsToMSuFqKFQR+fZTO9CNGUNokkPatT/0=
|
||||
github.com/charmbracelet/x/exp/charmtone v0.0.0-20260602025833-85a30b5e440a h1:aVvnksCVgxB2igk7jERL9ARIkbDXccp1gXCFqhGlamQ=
|
||||
github.com/charmbracelet/x/exp/charmtone v0.0.0-20260602025833-85a30b5e440a/go.mod h1:nsExn0DGyX0lh9LwLHTn2Gg+hafdzfSXnC+QmEJTZFY=
|
||||
github.com/charmbracelet/x/exp/charmtone v0.0.0-20260615092313-b57e5e6d29bb h1:hoqNT54vrpXamSaQe5GxupakGgvvqFmVgmLJjotpHco=
|
||||
github.com/charmbracelet/x/exp/charmtone v0.0.0-20260615092313-b57e5e6d29bb/go.mod h1:nsExn0DGyX0lh9LwLHTn2Gg+hafdzfSXnC+QmEJTZFY=
|
||||
github.com/charmbracelet/x/exp/golden v0.0.0-20250806222409-83e3a29d542f h1:pk6gmGpCE7F3FcjaOEKYriCvpmIN4+6OS/RD0vm4uIA=
|
||||
github.com/charmbracelet/x/exp/golden v0.0.0-20250806222409-83e3a29d542f/go.mod h1:IfZAMTHB6XkZSeXUqriemErjAWCCzT0LwjKFYCZyw0I=
|
||||
github.com/charmbracelet/x/exp/ordered v0.1.0 h1:55/qLwjIh0gL0Vni+QAWk7T/qRVP6sBf+2agPBgnOFE=
|
||||
github.com/charmbracelet/x/exp/ordered v0.1.0/go.mod h1:5UHwmG+is5THxMyCJHNPCn2/ecI07aKNrW+LcResjJ8=
|
||||
github.com/charmbracelet/x/exp/slice v0.0.0-20260527151214-009e6338d40d h1:RxcAR+vJCoD8QqT1cqLtkQKw+1cqvjqnu5IpPqYzPco=
|
||||
github.com/charmbracelet/x/exp/slice v0.0.0-20260527151214-009e6338d40d/go.mod h1:vqEfX6xzqW1pKKZUUiFOKg0OQ7bCh54Q2vR/tserrRA=
|
||||
github.com/charmbracelet/x/exp/slice v0.0.0-20260615092313-b57e5e6d29bb h1:fr6DwrfJB2XQ3zM2fCwumXPE5G+hegnkEpl1KUuPsQI=
|
||||
github.com/charmbracelet/x/exp/slice v0.0.0-20260615092313-b57e5e6d29bb/go.mod h1:vqEfX6xzqW1pKKZUUiFOKg0OQ7bCh54Q2vR/tserrRA=
|
||||
github.com/charmbracelet/x/exp/strings v0.1.0 h1:i69S2XI7uG1u4NLGeJPSYU++Nmjvpo9nwd6aoEm7gkA=
|
||||
github.com/charmbracelet/x/exp/strings v0.1.0/go.mod h1:/ehtMPNh9K4odGFkqYJKpIYyePhdp1hLBRvyY4bWkH8=
|
||||
github.com/charmbracelet/x/json v0.2.0 h1:DqB+ZGx2h+Z+1s98HOuOyli+i97wsFQIxP2ZQANTPrQ=
|
||||
@@ -143,7 +120,6 @@ github.com/charmbracelet/x/xpty v0.1.3 h1:eGSitii4suhzrISYH50ZfufV3v085BXQwIytcO
|
||||
github.com/charmbracelet/x/xpty v0.1.3/go.mod h1:poPYpWuLDBFCKmKLDnhBp51ATa0ooD8FhypRwEFtH3Y=
|
||||
github.com/clipperhouse/displaywidth v0.11.0 h1:lBc6kY44VFw+TDx4I8opi/EtL9m20WSEFgwIwO+UVM8=
|
||||
github.com/clipperhouse/displaywidth v0.11.0/go.mod h1:bkrFNkf81G8HyVqmKGxsPufD3JhNl3dSqnGhOoSD/o0=
|
||||
github.com/clipperhouse/stringish v0.1.1/go.mod h1:v/WhFtE1q0ovMta2+m+UbpZ+2/HEXNWYXQgCt4hdOzA=
|
||||
github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk=
|
||||
github.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM=
|
||||
github.com/cncf/xds/go v0.0.0-20260202195803-dba9d589def2 h1:aBangftG7EVZoUb69Os8IaYg++6uMOdKK83QtkkvJik=
|
||||
@@ -157,31 +133,25 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dlclark/regexp2 v1.12.0 h1:0j4c5qQmnC6XOWNjP3PIXURXN2gWx76rd3KvgdPkCz8=
|
||||
github.com/dlclark/regexp2 v1.12.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
||||
github.com/dlclark/regexp2/v2 v2.1.1 h1:LCUGyd9Wf+r+VVOl8Ny38JTpWJcAsdVnCIuhhtthmKw=
|
||||
github.com/dlclark/regexp2/v2 v2.1.1/go.mod h1:avUrQvPaLz2DrFNHJF0taWAFFX2C1GMSSoeiqFjcBmU=
|
||||
github.com/dlclark/regexp2/v2 v2.2.2 h1:MYWvNYw8okuqNhwTYO587EZMiDruVa2vhV6fsGpfya0=
|
||||
github.com/dlclark/regexp2/v2 v2.2.2/go.mod h1:avUrQvPaLz2DrFNHJF0taWAFFX2C1GMSSoeiqFjcBmU=
|
||||
github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI=
|
||||
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
|
||||
github.com/dromara/carbon/v2 v2.6.16/go.mod h1:NGo3reeV5vhWCYWcSqbJRZm46MEwyfYI5EJRdVFoLJo=
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/ebitengine/purego v0.10.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||
github.com/eliben/go-sentencepiece v0.6.0/go.mod h1:nNYk4aMzgBoI6QFp4LUG8Eu1uO9fHD9L5ZEre93o9+c=
|
||||
github.com/envoyproxy/go-control-plane v0.14.0 h1:hbG2kr4RuFj222B6+7T83thSPqLjwBIfQawTkC++2HA=
|
||||
github.com/envoyproxy/go-control-plane v0.14.0/go.mod h1:NcS5X47pLl/hfqxU70yPwL9ZMkUlwlKxtAohpi2wBEU=
|
||||
github.com/envoyproxy/go-control-plane/envoy v1.37.0 h1:u3riX6BoYRfF4Dr7dwSOroNfdSbEPe9Yyl09/B6wBrQ=
|
||||
github.com/envoyproxy/go-control-plane/envoy v1.37.0/go.mod h1:DReE9MMrmecPy+YvQOAOHNYMALuowAnbjjEMkkWOi6A=
|
||||
github.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod h1:Wk+tMFAFbCXaJPzVVHnPgRKdUdwW/KdbRt94AzgRee4=
|
||||
github.com/envoyproxy/protoc-gen-validate v1.3.3 h1:MVQghNeW+LZcmXe7SY1V36Z+WFMDjpqGAGacLe2T0ds=
|
||||
github.com/envoyproxy/protoc-gen-validate v1.3.3/go.mod h1:TsndJ/ngyIdQRhMcVVGDDHINPLWB7C82oDArY51KfB0=
|
||||
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/felixge/httpsnoop v1.1.0 h1:3YtUj32ZZkqZtt3sZZsClsymw/QDuVfpNhoA31zeORc=
|
||||
github.com/felixge/httpsnoop v1.1.0/go.mod h1:Zqxgdd+1Rkcz8euOqdr7lqgCRJztwr5hp9vDSi5UZCE=
|
||||
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/fsnotify/fsnotify v1.10.1 h1:b0/UzAf9yR5rhf3RPm9gf3ehBPpf0oZKIjtpKrx59Ho=
|
||||
github.com/fsnotify/fsnotify v1.10.1/go.mod h1:TLheqan6HD6GBK6PrDWyDPBaEV8LspOxvPSjC+bVfgo=
|
||||
github.com/go-jose/go-jose/v4 v4.1.4/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08=
|
||||
github.com/go-json-experiment/json v0.0.0-20260520185125-572e7c383686 h1:NZBJxCpbHS1gzS6xAmyxbJznosZIIPk9IB42v62UvKA=
|
||||
github.com/go-json-experiment/json v0.0.0-20260520185125-572e7c383686/go.mod h1:tphK2c80bpPhMOI4v6bIc2xWywPfbqi1Z06+RcrMkDg=
|
||||
github.com/go-json-experiment/json v0.0.0-20260601182631-00ed12fed2a6 h1:nxP4pPoyqOAgX8lYDFCfl3DyKeXErCvSvhcyzwGV9CE=
|
||||
github.com/go-json-experiment/json v0.0.0-20260601182631-00ed12fed2a6/go.mod h1:tphK2c80bpPhMOI4v6bIc2xWywPfbqi1Z06+RcrMkDg=
|
||||
github.com/go-logfmt/logfmt v0.6.1 h1:4hvbpePJKnIzH1B+8OR/JPbTx37NktoI9LE2QZBBkvE=
|
||||
github.com/go-logfmt/logfmt v0.6.1/go.mod h1:EV2pOAQoZaT1ZXZbqDl5hrymndi4SY9ED9/z6CO0XAk=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
@@ -195,17 +165,12 @@ github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM=
|
||||
github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
|
||||
github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo=
|
||||
github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
|
||||
github.com/golang/glog v1.2.5/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/go-pkcs11 v0.3.0/go.mod h1:6eQoGcuNJpa7jnd5pMGdkSaQpNDYvPlXWMcjXXThLlY=
|
||||
github.com/google/jsonschema-go v0.4.3 h1:/DBOLZTfDow7pe2GmaJNhltueGTtDKICi8V8p+DQPd0=
|
||||
github.com/google/jsonschema-go v0.4.3/go.mod h1:r5quNTdLOYEz95Ru18zA0ydNbBuYoo9tgaYcxEYhJVE=
|
||||
github.com/google/martian/v3 v3.3.3/go.mod h1:iEPrYcgCF7jA9OtScMFQyAlZZ4YXTKEtJ1E6RWzmBA0=
|
||||
github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0=
|
||||
github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
@@ -216,32 +181,18 @@ github.com/googleapis/gax-go/v2 v2.22.0 h1:PjIWBpgGIVKGoCXuiCoP64altEJCj3/Ei+kSU
|
||||
github.com/googleapis/gax-go/v2 v2.22.0/go.mod h1:irWBbALSr0Sk3qlqb9SyJ1h68WjgeFuiOzI4Rqw5+aY=
|
||||
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0/go.mod h1:Hyl3n6Twe1hvtd9XUXDec4pTvgMSEixRuQKPTMH2bNs=
|
||||
github.com/hashicorp/aws-sdk-go-base/v2 v2.0.0-beta.72/go.mod h1:Vn+BBgKQHVQYdVQ4NZDICE1Brb+JfaONyDHr3q07oQc=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
|
||||
github.com/hashicorp/go-getter v1.8.6/go.mod h1:nVH12eOV2P58dIiL3rsU6Fh3wLeJEKBOJzhMmzlSWoo=
|
||||
github.com/hashicorp/go-version v1.9.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
|
||||
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
|
||||
github.com/hybridgroup/yzma v1.13.0/go.mod h1:zrzMgv/KVQz23+s6l16b+vJ+9uJVBdWtGcGkwRTMeiQ=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/indaco/herald v0.13.0 h1:+xVG9Fx5NpuWhwku/9IlRL6I009NnX4VUGKvlZHTRxU=
|
||||
github.com/indaco/herald v0.13.0/go.mod h1:T5g1+XLYvpjouhzAGHnAHDCKizhESkoV6+QPZ3DhgWA=
|
||||
github.com/indaco/herald-md v0.3.0 h1:hN1cKyrexPPM9PeHBsKuaWvIizSi/iYvM9yzRgtdb8M=
|
||||
github.com/indaco/herald-md v0.3.0/go.mod h1:RUHVaDSG45ymJjKyxpDwBocLXrZo93FB4OeYMsw9B9s=
|
||||
github.com/invopop/jsonschema v0.13.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0=
|
||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||
github.com/jupiterrider/ffi v0.7.0/go.mod h1:9dauhpOfNqrqk28fxuu0kkdeFtT9Qr4vbfigiuIXN7c=
|
||||
github.com/kaptinlin/go-i18n v0.4.5 h1:9tIlo5A0RXth+yZJO2MG7Bhpu/X9PlzQnGz/qyYWNoY=
|
||||
github.com/kaptinlin/go-i18n v0.4.5/go.mod h1:mU/7BH4molY5lGZYBwBRKAaiJ70dWRHuqmQ0/pFLGno=
|
||||
github.com/kaptinlin/jsonpointer v0.4.25 h1:iJ197e8n+WwqaqBsa53FqG3rPJCg5oijyFXEXNWWC3E=
|
||||
github.com/kaptinlin/jsonpointer v0.4.25/go.mod h1:wVOBaXGGnP42YsMb6zev/3W5POTvspdNfh8DXzf8XS8=
|
||||
github.com/kaptinlin/jsonschema v0.7.13 h1:kahVXTy/rURL0XJjyQ9WELm59wEmXi6IY0TWswQEFvU=
|
||||
github.com/kaptinlin/jsonschema v0.7.13/go.mod h1:Uh0aUBusnhXDCEXJ2oimL/hx7YTo7F+sKniE+tM0ERc=
|
||||
github.com/kaptinlin/messageformat-go v0.6.0 h1:D6jiXFsKW4/JG2CMddv/F6Rev9KVbCRKEzzV5QOAcpc=
|
||||
github.com/kaptinlin/messageformat-go v0.6.0/go.mod h1:NKjwS6e9u7DRhAK+vydjDDwJ7UbdHhYjk/yk2WPuZPs=
|
||||
github.com/klauspost/compress v1.18.6/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
|
||||
github.com/kaptinlin/jsonpointer v0.4.26 h1:tw616yszHek+B3/GtDSia+uzBa3sLXGpmo4tYeMhBZw=
|
||||
github.com/kaptinlin/jsonpointer v0.4.26/go.mod h1:wVOBaXGGnP42YsMb6zev/3W5POTvspdNfh8DXzf8XS8=
|
||||
github.com/kaptinlin/jsonschema v0.8.0 h1:GhY966O2q3ZQsg1zkQj988KF2MADJ6EA7pKBMpGmb9A=
|
||||
github.com/kaptinlin/jsonschema v0.8.0/go.mod h1:dxt7s98W5NEuWEwCnAwGrhYGQdaRLqXZImR28DuxcMU=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
@@ -250,14 +201,12 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0
|
||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||
github.com/lucasb-eyer/go-colorful v1.4.0 h1:UtrWVfLdarDgc44HcS7pYloGHJUjHV/4FwW4TvVgFr4=
|
||||
github.com/lucasb-eyer/go-colorful v1.4.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/mark3labs/mcp-go v0.54.1 h1:Ap/ptEB9FtWzFKM8NDsTA7QDxerQOC06eZigrTldVj0=
|
||||
github.com/mark3labs/mcp-go v0.54.1/go.mod h1:+8WclSK1ZUweCP3hvktSji8n8ABG/95QaEkeVE/Uwas=
|
||||
github.com/mattn/go-isatty v0.0.22 h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw4=
|
||||
github.com/mattn/go-isatty v0.0.22/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4=
|
||||
github.com/mattn/go-runewidth v0.0.24 h1:cpokDiIn0MGnhdHwuWnJBITySJ20QyNGnY2kR/ay2DU=
|
||||
github.com/mattn/go-runewidth v0.0.24/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4=
|
||||
github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE=
|
||||
github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
|
||||
@@ -272,7 +221,6 @@ github.com/muesli/roff v0.1.0 h1:YD0lalCotmYuF5HhZliKWlIx7IEhiXeSfq7hNjFqGF8=
|
||||
github.com/muesli/roff v0.1.0/go.mod h1:pjAHQM9hdUUwm/krAfrLGgJkXJ+YuhtsfZ42kieB2Ig=
|
||||
github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc=
|
||||
github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/pelletier/go-toml/v2 v2.3.1 h1:MYEvvGnQjeNkRF1qUuGolNtNExTDwct51yp7olPtrEc=
|
||||
github.com/pelletier/go-toml/v2 v2.3.1/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
|
||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
|
||||
@@ -281,10 +229,6 @@ github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgm
|
||||
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
|
||||
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
|
||||
github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw=
|
||||
github.com/prometheus/procfs v0.20.1/go.mod h1:o9EMBZGRyvDrSPH1RqdxhojkuXstoe4UlK79eF5TGGo=
|
||||
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||
@@ -292,10 +236,8 @@ github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sagikazarmark/locafero v0.12.0 h1:/NQhBAkUb4+fH1jivKHWusDYFjMOOKU88eegjfxfHb4=
|
||||
github.com/sagikazarmark/locafero v0.12.0/go.mod h1:sZh36u/YSZ918v0Io+U9ogLYQJ9tLLBmM4eneO6WwsI=
|
||||
github.com/sahilm/fuzzy v0.1.1/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
|
||||
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ=
|
||||
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU=
|
||||
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U=
|
||||
github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I=
|
||||
github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg=
|
||||
github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY=
|
||||
@@ -307,7 +249,6 @@ github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
|
||||
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU=
|
||||
github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY=
|
||||
github.com/spiffe/go-spiffe/v2 v2.6.0/go.mod h1:gm2SeUoMZEtpnzPNs2Csc0D/gX33k1xIx7lEzqblHEs=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||
@@ -325,27 +266,20 @@ github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
|
||||
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
|
||||
github.com/traefik/yaegi v0.16.1 h1:f1De3DVJqIDKmnasUF6MwmWv1dSEEat0wcpXhD2On3E=
|
||||
github.com/traefik/yaegi v0.16.1/go.mod h1:4eVhbPb3LnD2VigQjhYbEJ69vDRFdT2HQNrXx8eEwUY=
|
||||
github.com/ulikunitz/xz v0.5.15/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||
github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw=
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
|
||||
github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4=
|
||||
github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4=
|
||||
github.com/yuin/goldmark v1.8.2 h1:kEGpgqJXdgbkhcOgBxkC0X0PmoPG1ZyoZ117rDVp4zE=
|
||||
github.com/yuin/goldmark v1.8.2/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg=
|
||||
github.com/zeebo/errs v1.4.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4=
|
||||
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.43.0/go.mod h1:RyaZMFY7yi1kAs45S6mbFGz8O8rqB0dTY14uzvG4LCs=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.69.0 h1:2yEATaop1/a1I4psnSLgWVPLWwCzkqWakgJy7xTDVy0=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.69.0/go.mod h1:D7J12YRapIekYyPWgGPlA/23pRmpSEZC5xJC/TTLI9U=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0 h1:8tvICD4vSTOOsNrsI4Ljf6C+6UKvpTEH5XY3JMoyPoo=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0/go.mod h1:z9+yiacE0IHRqM4qFfkbt/JYlmYXgss8GY/jXoNuPJI=
|
||||
go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU=
|
||||
go.opentelemetry.io/otel v1.44.0/go.mod h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0/go.mod h1:Vl1/iaggsuRlrHf/hfPJPvVag77kKyvrLeD10kpMl+A=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.43.0/go.mod h1:AGmbycVGEsRx9mXMZ75CsOyhSP6MFIcj/6dnG+vhVjk=
|
||||
go.opentelemetry.io/otel/metric v1.44.0 h1:1w0gILTcHdr3YI+ixLyjemwrVnsMURbTZFrSYCdDdmc=
|
||||
go.opentelemetry.io/otel/metric v1.44.0/go.mod h1:8O7hanEPBNgEMmybD3s2VBKcgWOCsA6tzHBPODAiquo=
|
||||
go.opentelemetry.io/otel/sdk v1.44.0 h1:nHYwb9lK+fJPU/dnT6s7W7Z8itMWyqrnVfbheVYrZ58=
|
||||
@@ -354,49 +288,40 @@ go.opentelemetry.io/otel/sdk/metric v1.44.0 h1:3LlKgI+VjbVsjNRFZJZAJ30WjXC5VkNRk
|
||||
go.opentelemetry.io/otel/sdk/metric v1.44.0/go.mod h1:5B5pMARnXxKhltooO4xUuCBorl65a4EpnTalObqOigA=
|
||||
go.opentelemetry.io/otel/trace v1.44.0 h1:jxF5CsGYCe74MCRx2X4g7WsY/VBKRqqpNvXlX/6gtIk=
|
||||
go.opentelemetry.io/otel/trace v1.44.0/go.mod h1:oLl1jrMQAVo6v3GAggN+1VH9VIz9iUSvW53sW1Q8PIE=
|
||||
go.opentelemetry.io/proto/otlp v1.10.0/go.mod h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk=
|
||||
go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ=
|
||||
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
|
||||
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
||||
go.yaml.in/yaml/v4 v4.0.0-rc.3/go.mod h1:aZqd9kCMsGL7AuUv/m/PvWLdg5sjJsZ4oHDEnfPPfY0=
|
||||
golang.org/x/crypto v0.52.0 h1:RMs7fP2rXdep0CftQlK8Uf+kibLm7qkCcradZWYz988=
|
||||
golang.org/x/crypto v0.52.0/go.mod h1:1QgfPxDqh0T2M/elOJtp9RvuR95kVjir0e6/BvEmGbc=
|
||||
golang.org/x/exp v0.0.0-20260603202125-055de637280b h1:v1uXiEBHo8QA0LiGCo7UgHMzHT4Kdfpl2zmtH5vaP1Q=
|
||||
golang.org/x/exp v0.0.0-20260603202125-055de637280b/go.mod h1:d2fgXJLVs4dYDHUk5lwMIfzRzSrWCfGZb0ZqeLa/Vcw=
|
||||
golang.org/x/image v0.41.0 h1:8wS72eGJMJaBxK6okTzd4WaXumUlTVlb753MlsSvTCo=
|
||||
golang.org/x/image v0.41.0/go.mod h1:uIc348UZMSvS5Z65CVZ7iDPaNobNFEPeJ4kbqTOszmA=
|
||||
golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ=
|
||||
golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8=
|
||||
golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww=
|
||||
golang.org/x/crypto v0.53.0 h1:QZ4Muo8THX6CizN2vPPd5fBGHyogrdK9fG4wLPFUsto=
|
||||
golang.org/x/crypto v0.53.0/go.mod h1:DNLU434OwVakk9PzuwV8w62mAJpRJL3vsgcfp4Qnsio=
|
||||
golang.org/x/exp v0.0.0-20260611194520-c48552f49976 h1:X8Hz2ImujgbmetVuW+w2YkyZChE3cBpZi2P158rTG9M=
|
||||
golang.org/x/exp v0.0.0-20260611194520-c48552f49976/go.mod h1:vnf4pv9iKZXY58sQE1L86zmNWJ4159e1RkcWiLCkeEY=
|
||||
golang.org/x/image v0.42.0 h1:1gSs6ehNWXLbkHBIPcWztk3D/6aIA/8hauiAYtlodVY=
|
||||
golang.org/x/image v0.42.0/go.mod h1:rrpelvGFt+kLPAjPM4HeWPgrl0FtafueU//e5N0qk/Q=
|
||||
golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o=
|
||||
golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec=
|
||||
golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs=
|
||||
golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q=
|
||||
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
|
||||
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
||||
golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY=
|
||||
golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/term v0.43.0 h1:S4RLU2sB31O/NCl+zFN9Aru9A/Cq2aqKpTZJ6B+DwT4=
|
||||
golang.org/x/term v0.43.0/go.mod h1:lrhlHNdQJHO+1qVYiHfFKVuVioJIheAc3fBSMFYEIsk=
|
||||
golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc=
|
||||
golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38=
|
||||
golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM=
|
||||
golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
||||
golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw=
|
||||
golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/term v0.44.0 h1:0rLvDRCtNj0gZkyIXhCyOb2OAzEhLVqc4B+hrsBhrmc=
|
||||
golang.org/x/term v0.44.0/go.mod h1:7ze4MdzUzLXpSAoFP1H0bOI9aXDqveSvatT5vKcFh2Y=
|
||||
golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE=
|
||||
golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4=
|
||||
golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
|
||||
golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
|
||||
golang.org/x/tools v0.45.0/go.mod h1:LuUGqqaXcXMEFEruIVJVm5mgDD8vww/z/SR1gQ4uE/0=
|
||||
golang.org/x/tools/go/expect v0.1.1-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY=
|
||||
golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated/go.mod h1:RVAQXBGNv1ib0J382/DPCRS/BPnsGebyM1Gj5VSDpG8=
|
||||
gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
|
||||
gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
|
||||
google.golang.org/api v0.282.0 h1:WmJiSVqUnKqJCpJOx7YADbXaC+9DDsnGSfllFSj7R2I=
|
||||
google.golang.org/api v0.282.0/go.mod h1:6Wssta4c5n9qHq5CBhmlai5h/PUa1djdDAIhYEHyvcM=
|
||||
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
|
||||
google.golang.org/genai v1.58.0 h1:MNA3ZkRyr7MnRwZ9RNZ60p4+UMKV3yYRw6pyHq4pp0U=
|
||||
google.golang.org/genai v1.58.0/go.mod h1:A3kkl0nyBjyFlNjgxIwKq70julKbIxpSxqKO5gw/gmk=
|
||||
google.golang.org/genproto v0.0.0-20260504160031-60b97b32f348 h1:JjVGDZYWkJWZcxveJGzfkXC5myDVWAd4dZdgbzrDUv8=
|
||||
google.golang.org/genproto v0.0.0-20260504160031-60b97b32f348/go.mod h1:95PqD4xM+AdOcBGsmgfaofXsiA37uXDtDufVbntT3TU=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20260504160031-60b97b32f348 h1:U8orV30l6KpDsi9dxU0CoJZGbjS8EEpw+6ba+XwGPQA=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20260504160031-60b97b32f348/go.mod h1:Yzdzr5OOZFgSsEV2D/Xi9NL3bszpXFAg0hFJiRohcD8=
|
||||
google.golang.org/genproto/googleapis/bytestream v0.0.0-20260523011958-0a33c5d7ca68/go.mod h1:6TABGosqSqU2l1+fJ3jdvOYPPVryeKybxYF0cCZkTBE=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa h1:mZHHdPZl0dbGHCflZgAq/Q468DWVFcU2whhB2KAo8fk=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
||||
google.golang.org/api v0.284.0 h1:i+cKTgeQRcRySkP7QTl5PDO7/pAm8EcMFIUMlNbk4Vc=
|
||||
google.golang.org/api v0.284.0/go.mod h1:AU44fU+XVZOCcd8uLaBIa/ZgzgPf/0qqY3+m7lQaado=
|
||||
google.golang.org/genai v1.60.0 h1:uAkea4tYhCz1LlUmxdiOFAmlrLFaLs8PbXucgZHqHVo=
|
||||
google.golang.org/genai v1.60.0/go.mod h1:mDdPDFXo1Ats7f1WXVyZgWb/CkMzFWTWJruIMy7hGIU=
|
||||
google.golang.org/genproto v0.0.0-20260526163538-3dc84a4a5aaa h1:mfj8IS4EA4VAR9a6QDVxTQkLY64iBybb5QI1B4pXrpE=
|
||||
google.golang.org/genproto v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:fuT7yonGw1Iq2oa+YC0fyqPPQJkgo/54gPNC6VitOkI=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa h1:Kjn0N0tCrDgiAFW+lGO4JZ3ck44CehvJQMAwj9QF0G8=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:q4lMZS6kskjT5HvCPrnnypcDPVJqT/f4nfxmkE7gryY=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260615183401-62b3387ff324 h1:9HZDLIdYBJXAnaFOr9WHrKVycfpY+75s9HGadC0305A=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260615183401-62b3387ff324/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
||||
google.golang.org/grpc v1.81.1 h1:VnnIIZ88UzOOKLukQi+ImGz8O1Wdp8nAGGnvOfEIWQQ=
|
||||
google.golang.org/grpc v1.81.1/go.mod h1:xGH9GfzOyMTGIOXBJmXt+BX/V0kcdQbdcuwQ/zNw42I=
|
||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||
@@ -404,8 +329,6 @@ google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/dnaeon/go-vcr.v4 v4.0.6-0.20251110073552-01de4eb40290/go.mod h1:sbq5oMEcM4PXngbcNbHhzfCP9OdZodLhrbRYoyg09HY=
|
||||
gopkg.in/ini.v1 v1.67.1/go.mod h1:x/cyOwCgZqOkJoDIJ3c1KNHMo10+nLGAhh+kn3Zizss=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -99,7 +99,7 @@ The generated workflow:
|
||||
|
||||
After committing the workflow and setting the provider secret, comment `/kit <your request>` on any issue or pull request to trigger Kit.
|
||||
|
||||
The runtime that reads the event context, enforces permissions, drives the agent, and posts the response back is the [`github-handler`](/extensions/examples) example extension.
|
||||
The generated workflow uses the bundled [`mark3labs/kit`](https://github.com/mark3labs/kit/blob/master/action.yml) composite action, which installs the Kit binary and runs `kit github run`. That command reads the triggering event, enforces permissions, reacts with an emoji, runs the agent against the issue thread or PR, posts the response as a comment, and — if the agent changed files — pushes a `kit-agent[bot]` branch and opens a pull request.
|
||||
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
|
||||
@@ -90,7 +90,6 @@ These examples demonstrate the new bridged SDK APIs that give extensions access
|
||||
|-----------|-------------|
|
||||
| [`kit-kit-agents/`](https://github.com/mark3labs/kit/tree/master/examples/extensions/kit-kit-agents) | Multi-agent orchestration example |
|
||||
| [`kit-telegram/`](https://github.com/mark3labs/kit/tree/master/examples/extensions/kit-telegram) | Telegram bot integration |
|
||||
| [`github-handler/`](https://github.com/mark3labs/kit/tree/master/examples/extensions/github-handler) | Run Kit as a GitHub collaborator inside Actions — parses the event, gates on `author_association`, drives the agent, posts comments, and opens PRs |
|
||||
| [`status-tools/`](https://github.com/mark3labs/kit/tree/master/examples/extensions/status-tools) | Status bar tool examples |
|
||||
|
||||
## Project-local example
|
||||
|
||||
Reference in New Issue
Block a user