Compare commits

...

15 Commits

Author SHA1 Message Date
github-actions[bot]
8475051a7c chore(release): Update version to v1.4.351 2025-12-18 18:37:22 +00:00
Kayvan Sylvan
9f3122ba35 Merge pull request #1882 from bvandevliet/fix/include-yt-dlp-in-docker-image
Added yt-dlp package to docker image.
2025-12-18 10:34:54 -08:00
Changelog Bot
f61db2cdce chore: incoming 1882 changelog entry 2025-12-18 10:30:23 -08:00
github-actions[bot]
8a2d5f82f1 chore(release): Update version to v1.4.350 2025-12-18 18:29:51 +00:00
Kayvan Sylvan
edaf1a0110 Merge pull request #1884 from ksylvan/kayvan/add-swagger-ui-to-server
Implement interactive Swagger API documentation and automated OpenAPI specification generation.
2025-12-18 10:27:06 -08:00
Changelog Bot
3a4468b970 chore: incoming 1884 changelog entry 2025-12-18 10:05:33 -08:00
Kayvan Sylvan
645190be3a feat: update REST API docs with new fields and examples
### CHANGES

- Add detailed prompt fields table with defaults
- Introduce chat options table with new parameters
- Include complete workflow examples for YouTube summary
- Provide alternative script and CLI comparison for flexibility
2025-12-18 07:30:34 -08:00
Kayvan Sylvan
c06c94f8b8 # CHANGES
- Add Swagger UI at `/swagger/index.html` endpoint
- Generate OpenAPI spec files (JSON and YAML)
- Document chat, patterns, and models endpoints
- Update contributing guide with Swagger annotation instructions
- Add swaggo dependencies to project
- Configure authentication bypass for Swagger documentation
- Add custom YAML handler for OpenAPI spec
- Update REST API documentation with Swagger links
- Add dictionary entries for new tools
2025-12-18 07:12:08 -08:00
Bob Vandevliet
d84bd6f989 Added yt-dlp package to docker image. 2025-12-18 11:16:39 +01:00
Kayvan Sylvan
7ab5e8956c Merge pull request #1880 from ksylvan/kayvan/rest-api-docs 2025-12-17 19:29:28 -08:00
Kayvan Sylvan
99b8b6a972 - Add README table-of-contents link for REST API.
- Document REST API server startup and capabilities.
- Add endpoint overview for chat, patterns, contexts.
- Describe sessions management and model listing endpoints.
- Provide curl examples for key API workflows.
- Explain Ollama compatibility mode endpoints and port.
2025-12-17 19:11:57 -08:00
github-actions[bot]
833b09081e chore(release): Update version to v1.4.349 2025-12-16 08:12:11 +00:00
Kayvan Sylvan
201d1fb791 Merge pull request #1877 from ksylvan/kayvan/modernize-part4-string-and-slice-syntax
modernize: update GitHub Actions and modernize Go code
2025-12-16 00:09:43 -08:00
Changelog Bot
6ecbd044e6 chore: incoming 1877 changelog entry 2025-12-16 00:06:39 -08:00
Kayvan Sylvan
fdadeae1e7 modernize: update GitHub Actions and modernize Go code with latest stdlib features
## CHANGES

- Upgrade GitHub Actions to latest versions (v6, v21)
- Add modernization check step in CI workflow
- Replace strings manipulation with `strings.CutPrefix` and `strings.CutSuffix`
- Replace manual loops with `slices.Contains` for validation
- Use `strings.SplitSeq` for iterator-based string splitting
- Replace `bytes.TrimPrefix` with `bytes.CutPrefix` for clarity
- Use `strings.Builder` instead of string concatenation
- Replace `fmt.Sprintf` with `fmt.Appendf` for efficiency
- Simplify padding calculation with `max` builtin
2025-12-15 23:55:37 -08:00
36 changed files with 2122 additions and 196 deletions

View File

@@ -20,18 +20,22 @@ jobs:
contents: read
steps:
- name: Checkout code
uses: actions/checkout@v5
- name: Install Nix
uses: DeterminateSystems/nix-installer-action@main
uses: actions/checkout@v6
- name: Set up Go
uses: actions/setup-go@v5
uses: actions/setup-go@v6
with:
go-version-file: ./go.mod
- name: Run tests
run: go test -v ./...
- name: Check for modernization opportunities
run: |
go run golang.org/x/tools/go/analysis/passes/modernize/cmd/modernize@latest ./...
- name: Install Nix
uses: DeterminateSystems/nix-installer-action@v21
- name: Check Formatting
run: nix flake check

View File

@@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v5
uses: actions/checkout@v6
with:
fetch-depth: 0
@@ -32,7 +32,7 @@ jobs:
- name: Upload Patterns Artifact
if: steps.check-changes.outputs.changes == 'true'
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: patterns
path: patterns.zip

View File

@@ -15,12 +15,12 @@ jobs:
contents: read
steps:
- name: Checkout code
uses: actions/checkout@v5
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Set up Go
uses: actions/setup-go@v5
uses: actions/setup-go@v6
with:
go-version-file: ./go.mod
@@ -37,11 +37,11 @@ jobs:
contents: write
steps:
- name: Checkout code
uses: actions/checkout@v5
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Set up Go
uses: actions/setup-go@v5
uses: actions/setup-go@v6
with:
go-version-file: ./go.mod
- name: Run GoReleaser

View File

@@ -24,17 +24,17 @@ concurrency:
jobs:
update-version:
if: >
${{ github.repository_owner == 'danielmiessler' }} &&
github.repository_owner == 'danielmiessler' &&
github.event_name == 'push' && github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Install Nix
uses: DeterminateSystems/nix-installer-action@main
uses: DeterminateSystems/nix-installer-action@v21
- name: Set up Git
run: |

View File

@@ -7,6 +7,7 @@
"Anki",
"anthropics",
"Aoede",
"apikey",
"aplicar",
"atotto",
"Autonoe",
@@ -63,6 +64,7 @@
"gjson",
"GOARCH",
"GODEBUG",
"godoc",
"godotenv",
"GOEXPERIMENT",
"gofmt",
@@ -173,6 +175,7 @@
"stretchr",
"subchunk",
"Sulafat",
"swaggo",
"synctest",
"talkpanel",
"Telos",
@@ -188,6 +191,7 @@
"updatepatterns",
"useb",
"USERPROFILE",
"varnames",
"videoid",
"webp",
"WEBVTT",

View File

@@ -1,5 +1,39 @@
# Changelog
## v1.4.351 (2025-12-18)
### PR [#1882](https://github.com/danielmiessler/Fabric/pull/1882) by [bvandevliet](https://github.com/bvandevliet): Added yt-dlp package to docker image
- Added yt-dlp package to docker image.
## v1.4.350 (2025-12-18)
### PR [#1880](https://github.com/danielmiessler/Fabric/pull/1880) by [ksylvan](https://github.com/ksylvan): docs: add REST API server section and new endpoint reference
- Add README table-of-contents link for REST API
- Document REST API server startup and capabilities
- Add endpoint overview for chat, patterns, contexts
- Describe sessions management and model listing endpoints
- Provide curl examples for key API workflows
### PR [#1884](https://github.com/danielmiessler/Fabric/pull/1884) by [ksylvan](https://github.com/ksylvan): Implement interactive Swagger API documentation and automated OpenAPI specification generation
- Add Swagger UI at `/swagger/index.html` endpoint
- Generate OpenAPI spec files (JSON and YAML)
- Document chat, patterns, and models endpoints
- Update contributing guide with Swagger annotation instructions
- Configure authentication bypass for Swagger documentation
## v1.4.349 (2025-12-16)
### PR [#1877](https://github.com/danielmiessler/Fabric/pull/1877) by [ksylvan](https://github.com/ksylvan): modernize: update GitHub Actions and modernize Go code
- Modernize GitHub Actions and Go code with latest stdlib features
- Upgrade GitHub Actions to latest versions (v6, v21) and add modernization check step
- Replace strings manipulation with `strings.CutPrefix` and `strings.CutSuffix`
- Replace manual loops with `slices.Contains` for validation and use `strings.SplitSeq` for iterator-based splitting
- Replace `fmt.Sprintf` with `fmt.Appendf` for efficiency and simplify padding calculation with `max` builtin
## v1.4.348 (2025-12-16)
### PR [#1876](https://github.com/danielmiessler/Fabric/pull/1876) by [ksylvan](https://github.com/ksylvan): modernize Go code with TypeFor and range loops

View File

@@ -38,6 +38,7 @@
[Philosophy](#philosophy) •
[Installation](#installation) •
[Usage](#usage) •
[REST API](#rest-api-server) •
[Examples](#examples) •
[Just Use the Patterns](#just-use-the-patterns) •
[Custom Patterns](#custom-patterns) •
@@ -170,6 +171,7 @@ Keep in mind that many of these were recorded when Fabric was Python-based, so r
- [Usage](#usage)
- [Debug Levels](#debug-levels)
- [Extensions](#extensions)
- [REST API Server](#rest-api-server)
- [Our approach to prompting](#our-approach-to-prompting)
- [Examples](#examples)
- [Just use the Patterns](#just-use-the-patterns)
@@ -299,7 +301,7 @@ docker run --rm -it -v $HOME/.fabric-config:/root/.config/fabric kayvan/fabric:l
# Use Fabric with your patterns
docker run --rm -it -v $HOME/.fabric-config:/root/.config/fabric kayvan/fabric:latest -p summarize
# Run the REST API server
# Run the REST API server (see REST API Server section)
docker run --rm -it -p 8080:8080 -v $HOME/.fabric-config:/root/.config/fabric kayvan/fabric:latest --serve
```
@@ -721,6 +723,25 @@ Fabric supports extensions that can be called within patterns. See the [Extensio
**Important:** Extensions only work within pattern files, not via direct stdin. See the guide for details and examples.
## REST API Server
Fabric includes a built-in REST API server that exposes all core functionality over HTTP. Start the server with:
```bash
fabric --serve
```
The server provides endpoints for:
- Chat completions with streaming responses
- Pattern management (create, read, update, delete)
- Context and session management
- Model and vendor listing
- YouTube transcript extraction
- Configuration management
For complete endpoint documentation, authentication setup, and usage examples, see [REST API Documentation](docs/rest-api.md).
## Our approach to prompting
Fabric _Patterns_ are different than most prompts you'll see.

View File

@@ -1,3 +1,3 @@
package main
var version = "v1.4.348"
var version = "v1.4.351"

Binary file not shown.

View File

@@ -574,8 +574,8 @@ func (g *Generator) extractChanges(pr *github.PR) []string {
}
if len(changes) == 0 && pr.Body != "" {
lines := strings.Split(pr.Body, "\n")
for _, line := range lines {
lines := strings.SplitSeq(pr.Body, "\n")
for line := range lines {
line = strings.TrimSpace(line)
if strings.HasPrefix(line, "- ") || strings.HasPrefix(line, "* ") {
change := strings.TrimPrefix(strings.TrimPrefix(line, "- "), "* ")

View File

@@ -159,7 +159,7 @@ func (g *Generator) CreateNewChangelogEntry(version string) error {
for _, file := range files {
// Extract PR number from filename (e.g., "1640.txt" -> 1640)
filename := filepath.Base(file)
if prNumStr := strings.TrimSuffix(filename, ".txt"); prNumStr != filename {
if prNumStr, ok := strings.CutSuffix(filename, ".txt"); ok {
if prNum, err := strconv.Atoi(prNumStr); err == nil {
processedPRs[prNum] = true
prNumbers = append(prNumbers, prNum)

View File

@@ -165,6 +165,79 @@ Example output here
- Include usage examples
- Keep documentation current
### REST API Documentation
When adding or modifying REST API endpoints, you must update the Swagger documentation:
**1. Add Swagger annotations to your handler:**
```go
// HandlerName godoc
// @Summary Short description of what this endpoint does
// @Description Detailed description of the endpoint's functionality
// @Tags category-name
// @Accept json
// @Produce json
// @Param name path string true "Parameter description"
// @Param body body RequestType true "Request body description"
// @Success 200 {object} ResponseType "Success description"
// @Failure 400 {object} map[string]string "Bad request"
// @Failure 500 {object} map[string]string "Server error"
// @Security ApiKeyAuth
// @Router /endpoint/path [get]
func (h *Handler) HandlerName(c *gin.Context) {
// Implementation
}
```
**2. Regenerate Swagger documentation:**
```bash
# Install swag CLI if you haven't already
go install github.com/swaggo/swag/cmd/swag@latest
# Generate updated documentation
swag init -g internal/server/serve.go -o docs
```
**3. Commit the generated files:**
The following files will be updated and should be committed:
- `docs/swagger.json`
- `docs/swagger.yaml`
- `docs/docs.go`
**4. Test your changes:**
Start the server and verify your endpoint appears in Swagger UI:
```bash
go run ./cmd/fabric --serve
# Open http://localhost:8080/swagger/index.html
```
**Examples to follow:**
- Chat endpoint: `internal/server/chat.go:58-68`
- Patterns endpoint: `internal/server/patterns.go:36-45`
- Models endpoint: `internal/server/models.go:20-28`
**Common annotation tags:**
- `@Summary` - One-line description (required)
- `@Description` - Detailed explanation
- `@Tags` - Logical grouping (e.g., "patterns", "chat", "models")
- `@Accept` - Input content type (e.g., "json")
- `@Produce` - Output content type (e.g., "json", "text/event-stream")
- `@Param` - Request parameters (path, query, body)
- `@Success` - Successful response (include status code and type)
- `@Failure` - Error responses
- `@Security` - Authentication requirement (use "ApiKeyAuth" for API key)
- `@Router` - Endpoint path and HTTP method
For complete Swagger annotation syntax, see the [swaggo documentation](https://github.com/swaggo/swag#declarative-comments-format)
## Getting Help
- Check existing issues first

431
docs/docs.go Normal file
View File

@@ -0,0 +1,431 @@
// Package docs Code generated by swaggo/swag. DO NOT EDIT
package docs
import "github.com/swaggo/swag"
const docTemplate = `{
"schemes": {{ marshal .Schemes }},
"swagger": "2.0",
"info": {
"description": "{{escape .Description}}",
"title": "{{.Title}}",
"contact": {
"name": "Fabric Support",
"url": "https://github.com/danielmiessler/fabric"
},
"license": {
"name": "MIT",
"url": "https://opensource.org/licenses/MIT"
},
"version": "{{.Version}}"
},
"host": "{{.Host}}",
"basePath": "{{.BasePath}}",
"paths": {
"/chat": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "Stream AI responses using Server-Sent Events (SSE)",
"consumes": [
"application/json"
],
"produces": [
"text/event-stream"
],
"tags": [
"chat"
],
"summary": "Stream chat completions",
"parameters": [
{
"description": "Chat request with prompts and options",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/restapi.ChatRequest"
}
}
],
"responses": {
"200": {
"description": "Streaming response",
"schema": {
"$ref": "#/definitions/restapi.StreamResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
}
}
}
},
"/models/names": {
"get": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "Get a list of all available AI models grouped by vendor",
"produces": [
"application/json"
],
"tags": [
"models"
],
"summary": "List all available models",
"responses": {
"200": {
"description": "Returns models (array) and vendors (map)",
"schema": {
"type": "object",
"additionalProperties": true
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
}
}
}
},
"/patterns/{name}": {
"get": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "Retrieve a pattern by name",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"patterns"
],
"summary": "Get a pattern",
"parameters": [
{
"type": "string",
"description": "Pattern name",
"name": "name",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/fsdb.Pattern"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
}
}
}
},
"/patterns/{name}/apply": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "Apply a pattern with variable substitution",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"patterns"
],
"summary": "Apply pattern with variables",
"parameters": [
{
"type": "string",
"description": "Pattern name",
"name": "name",
"in": "path",
"required": true
},
{
"description": "Pattern application request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/restapi.PatternApplyRequest"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/fsdb.Pattern"
}
},
"400": {
"description": "Bad Request",
"schema": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
}
}
}
}
},
"definitions": {
"domain.ThinkingLevel": {
"type": "string",
"enum": [
"off",
"low",
"medium",
"high"
],
"x-enum-varnames": [
"ThinkingOff",
"ThinkingLow",
"ThinkingMedium",
"ThinkingHigh"
]
},
"fsdb.Pattern": {
"type": "object",
"properties": {
"description": {
"type": "string"
},
"name": {
"type": "string"
},
"pattern": {
"type": "string"
}
}
},
"restapi.ChatRequest": {
"type": "object",
"properties": {
"audioFormat": {
"type": "string"
},
"audioOutput": {
"type": "boolean"
},
"frequencyPenalty": {
"type": "number",
"format": "float64"
},
"imageBackground": {
"type": "string"
},
"imageCompression": {
"type": "integer"
},
"imageFile": {
"type": "string"
},
"imageQuality": {
"type": "string"
},
"imageSize": {
"type": "string"
},
"language": {
"description": "Add Language field to bind from request",
"type": "string"
},
"maxTokens": {
"type": "integer"
},
"model": {
"type": "string"
},
"modelContextLength": {
"type": "integer"
},
"notification": {
"type": "boolean"
},
"notificationCommand": {
"type": "string"
},
"presencePenalty": {
"type": "number",
"format": "float64"
},
"prompts": {
"type": "array",
"items": {
"$ref": "#/definitions/restapi.PromptRequest"
}
},
"raw": {
"type": "boolean"
},
"search": {
"type": "boolean"
},
"searchLocation": {
"type": "string"
},
"seed": {
"type": "integer"
},
"suppressThink": {
"type": "boolean"
},
"temperature": {
"type": "number",
"format": "float64"
},
"thinkEndTag": {
"type": "string"
},
"thinkStartTag": {
"type": "string"
},
"thinking": {
"$ref": "#/definitions/domain.ThinkingLevel"
},
"topP": {
"type": "number",
"format": "float64"
},
"voice": {
"type": "string"
}
}
},
"restapi.PatternApplyRequest": {
"type": "object",
"properties": {
"input": {
"type": "string"
},
"variables": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
}
},
"restapi.PromptRequest": {
"type": "object",
"properties": {
"contextName": {
"type": "string"
},
"model": {
"type": "string"
},
"patternName": {
"type": "string"
},
"strategyName": {
"description": "Optional strategy name",
"type": "string"
},
"userInput": {
"type": "string"
},
"variables": {
"description": "Pattern variables",
"type": "object",
"additionalProperties": {
"type": "string"
}
},
"vendor": {
"type": "string"
}
}
},
"restapi.StreamResponse": {
"type": "object",
"properties": {
"content": {
"description": "The actual content",
"type": "string"
},
"format": {
"description": "\"markdown\", \"mermaid\", \"plain\"",
"type": "string"
},
"type": {
"description": "\"content\", \"error\", \"complete\"",
"type": "string"
}
}
}
},
"securityDefinitions": {
"ApiKeyAuth": {
"type": "apiKey",
"name": "X-API-Key",
"in": "header"
}
}
}`
// SwaggerInfo holds exported Swagger Info so clients can modify it
var SwaggerInfo = &swag.Spec{
Version: "1.0",
Host: "localhost:8080",
BasePath: "/",
Schemes: []string{},
Title: "Fabric REST API",
Description: "REST API for Fabric AI augmentation framework. Provides endpoints for chat completions, pattern management, contexts, sessions, and more.",
InfoInstanceName: "swagger",
SwaggerTemplate: docTemplate,
LeftDelim: "{{",
RightDelim: "}}",
}
func init() {
swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo)
}

487
docs/rest-api.md Normal file
View File

@@ -0,0 +1,487 @@
# Fabric REST API
Fabric's REST API provides HTTP access to all core functionality: chat completions, pattern management, contexts, sessions, and more.
## Quick Start
Start the server:
```bash
fabric --serve
```
The server runs on `http://localhost:8080` by default.
Test it:
```bash
curl http://localhost:8080/patterns/names
```
## Interactive API Documentation
Fabric includes Swagger/OpenAPI documentation with an interactive UI:
- **Swagger UI**: [http://localhost:8080/swagger/index.html](http://localhost:8080/swagger/index.html)
- **OpenAPI JSON**: [http://localhost:8080/swagger/doc.json](http://localhost:8080/swagger/doc.json)
- **OpenAPI YAML**: [http://localhost:8080/swagger/swagger.yaml](http://localhost:8080/swagger/swagger.yaml)
The Swagger UI lets you:
- Browse all available endpoints
- View request/response schemas
- Test API calls directly in your browser
- See authentication requirements
**Note:** Swagger documentation endpoints are publicly accessible even when API key authentication is enabled. Only the actual API endpoints require authentication
## Server Options
| Flag | Description | Default |
| ------ | ------------- | --------- |
| `--serve` | Start the REST API server | - |
| `--address` | Server address and port | `:8080` |
| `--api-key` | Enable API key authentication | (none) |
Example with custom configuration:
```bash
fabric --serve --address :9090 --api-key my_secret_key
```
## Authentication
When you set an API key with `--api-key`, all requests must include:
```http
X-API-Key: your-api-key-here
```
Example:
```bash
curl -H "X-API-Key: my_secret_key" http://localhost:8080/patterns/names
```
Without an API key, the server accepts all requests and logs a warning.
## Endpoints
### Chat Completions
Stream AI responses using Server-Sent Events (SSE).
**Endpoint:** `POST /chat`
**Request:**
```json
{
"prompts": [
{
"userInput": "Explain quantum computing",
"vendor": "openai",
"model": "gpt-4o",
"patternName": "explain",
"contextName": "",
"strategyName": "",
"variables": {}
}
],
"language": "en",
"temperature": 0.7,
"topP": 0.9,
"frequencyPenalty": 0,
"presencePenalty": 0,
"thinking": 0
}
```
**Prompt Fields:**
| Field | Required | Default | Description |
| ------- | ---------- | --------- | ------------- |
| `userInput` | **Yes** | - | Your message or question |
| `vendor` | **Yes** | - | AI provider: `openai`, `anthropic`, `gemini`, `ollama`, etc. |
| `model` | **Yes** | - | Model name: `gpt-4o`, `claude-sonnet-4.5`, `gemini-2.0-flash-exp`, etc. |
| `patternName` | No | `""` | Pattern to apply (from `~/.config/fabric/patterns/`) |
| `contextName` | No | `""` | Context to prepend (from `~/.config/fabric/contexts/`) |
| `strategyName` | No | `""` | Strategy to use (from `~/.config/fabric/strategies/`) |
| `variables` | No | `{}` | Variable substitutions for patterns (e.g., `{"role": "expert"}`) |
**Chat Options:**
| Field | Required | Default | Description |
| ------- | ---------- | --------- | ------------- |
| `language` | No | `"en"` | Language code for responses |
| `temperature` | No | `0.7` | Randomness (0.0-1.0) |
| `topP` | No | `0.9` | Nucleus sampling (0.0-1.0) |
| `frequencyPenalty` | No | `0.0` | Reduce repetition (-2.0 to 2.0) |
| `presencePenalty` | No | `0.0` | Encourage new topics (-2.0 to 2.0) |
| `thinking` | No | `0` | Reasoning level (0=off, or numeric for tokens) |
**Response:**
Server-Sent Events stream with `Content-Type: text/readystream`. Each line contains JSON:
```json
{"type": "content", "format": "markdown", "content": "Quantum computing uses..."}
{"type": "content", "format": "markdown", "content": " quantum mechanics..."}
{"type": "complete", "format": "markdown", "content": ""}
```
**Types:**
- `content` - Response chunk
- `error` - Error message
- `complete` - Stream finished
**Formats:**
- `markdown` - Standard text
- `mermaid` - Mermaid diagram
- `plain` - Plain text
**Example:**
```bash
curl -X POST http://localhost:8080/chat \
-H "Content-Type: application/json" \
-d '{
"prompts": [{
"userInput": "What is Fabric?",
"vendor": "openai",
"model": "gpt-4o",
"patternName": "explain"
}]
}'
```
### Patterns
Manage reusable AI prompts.
| Method | Endpoint | Description |
| -------- | ---------- | ------------- |
| `GET` | `/patterns/names` | List all pattern names |
| `GET` | `/patterns/:name` | Get pattern content |
| `GET` | `/patterns/exists/:name` | Check if pattern exists |
| `POST` | `/patterns/:name` | Create or update pattern |
| `DELETE` | `/patterns/:name` | Delete pattern |
| `PUT` | `/patterns/rename/:oldName/:newName` | Rename pattern |
| `POST` | `/patterns/:name/apply` | Apply pattern with variables |
**Example - Get pattern:**
```bash
curl http://localhost:8080/patterns/summarize
```
**Example - Apply pattern with variables:**
```bash
curl -X POST http://localhost:8080/patterns/translate/apply \
-H "Content-Type: application/json" \
-d '{
"input": "Hello world",
"variables": {"lang_code": "es"}
}'
```
**Example - Create pattern:**
```bash
curl -X POST http://localhost:8080/patterns/my_custom_pattern \
-H "Content-Type: text/plain" \
-d "You are an expert in explaining complex topics simply..."
```
### Contexts
Manage context snippets that prepend to prompts.
| Method | Endpoint | Description |
| -------- | ---------- | ------------- |
| `GET` | `/contexts/names` | List all context names |
| `GET` | `/contexts/:name` | Get context content |
| `GET` | `/contexts/exists/:name` | Check if context exists |
| `POST` | `/contexts/:name` | Create or update context |
| `DELETE` | `/contexts/:name` | Delete context |
| `PUT` | `/contexts/rename/:oldName/:newName` | Rename context |
### Sessions
Manage chat conversation history.
| Method | Endpoint | Description |
| -------- | ---------- | ------------- |
| `GET` | `/sessions/names` | List all session names |
| `GET` | `/sessions/:name` | Get session messages (JSON array) |
| `GET` | `/sessions/exists/:name` | Check if session exists |
| `POST` | `/sessions/:name` | Save session messages |
| `DELETE` | `/sessions/:name` | Delete session |
| `PUT` | `/sessions/rename/:oldName/:newName` | Rename session |
### Models
List available AI models.
**Endpoint:** `GET /models/names`
**Response:**
```json
{
"models": ["gpt-4o", "gpt-4o-mini", "claude-sonnet-4.5", "gemini-2.0-flash-exp"],
"vendors": {
"openai": ["gpt-4o", "gpt-4o-mini"],
"anthropic": ["claude-sonnet-4.5", "claude-opus-4.5"],
"gemini": ["gemini-2.0-flash-exp", "gemini-2.0-flash-thinking-exp"]
}
}
```
### Strategies
List available prompt strategies (Chain of Thought, etc.).
**Endpoint:** `GET /strategies`
**Response:**
```json
[
{
"name": "chain_of_thought",
"description": "Think step by step",
"prompt": "Let's think through this step by step..."
}
]
```
### YouTube Transcripts
Extract transcripts from YouTube videos.
**Endpoint:** `POST /youtube/transcript`
**Request:**
```json
{
"url": "https://youtube.com/watch?v=dQw4w9WgXcQ",
"timestamps": false
}
```
**Response:**
```json
{
"title": "Video Title",
"transcript": "Full transcript text..."
}
```
**Example:**
```bash
curl -X POST http://localhost:8080/youtube/transcript \
-H "Content-Type: application/json" \
-d '{"url": "https://youtube.com/watch?v=dQw4w9WgXcQ", "timestamps": true}'
```
### Configuration
Manage API keys and environment settings.
**Get configuration:**
`GET /config`
Returns API keys and URLs for all configured vendors.
**Update configuration:**
`POST /config/update`
```json
{
"OPENAI_API_KEY": "sk-...",
"ANTHROPIC_API_KEY": "sk-ant-..."
}
```
Updates `~/.config/fabric/.env` with new values.
## Complete Workflow Examples
### Example: Summarize a YouTube Video
This example shows how to extract a YouTube transcript and summarize it using the `youtube_summary` pattern. This requires two API calls:
#### Step 1: Extract the transcript
```bash
curl -X POST http://localhost:8080/youtube/transcript \
-H "Content-Type: application/json" \
-d '{
"url": "https://youtube.com/watch?v=dQw4w9WgXcQ",
"timestamps": false
}' > transcript.json
```
Response:
```json
{
"title": "Rick Astley - Never Gonna Give You Up (Official Video)",
"transcript": "We're no strangers to love. You know the rules and so do I..."
}
```
#### Step 2: Summarize the transcript
Extract the transcript text and send it to the chat endpoint with the `youtube_summary` pattern:
```bash
# Extract transcript text from JSON
TRANSCRIPT=$(cat transcript.json | jq -r '.transcript')
# Send to chat endpoint with pattern
curl -X POST http://localhost:8080/chat \
-H "Content-Type: application/json" \
-d "{
\"prompts\": [{
\"userInput\": \"$TRANSCRIPT\",
\"vendor\": \"openai\",
\"model\": \"gpt-4o\",
\"patternName\": \"youtube_summary\"
}]
}"
```
#### Combined one-liner (using jq)
```bash
curl -s -X POST http://localhost:8080/youtube/transcript \
-H "Content-Type: application/json" \
-d '{"url": "https://youtube.com/watch?v=dQw4w9WgXcQ", "timestamps": false}' | \
jq -r '.transcript' | \
xargs -I {} curl -X POST http://localhost:8080/chat \
-H "Content-Type: application/json" \
-d "{\"prompts\":[{\"userInput\":\"{}\",\"vendor\":\"openai\",\"model\":\"gpt-4o\",\"patternName\":\"youtube_summary\"}]}"
```
#### Alternative: Using a script
```bash
#!/bin/bash
YOUTUBE_URL="https://youtube.com/watch?v=dQw4w9WgXcQ"
API_BASE="http://localhost:8080"
# Step 1: Get transcript
echo "Extracting transcript..."
TRANSCRIPT=$(curl -s -X POST "$API_BASE/youtube/transcript" \
-H "Content-Type: application/json" \
-d "{\"url\":\"$YOUTUBE_URL\",\"timestamps\":false}" | jq -r '.transcript')
# Step 2: Summarize with pattern
echo "Generating summary..."
curl -X POST "$API_BASE/chat" \
-H "Content-Type: application/json" \
-d "{
\"prompts\": [{
\"userInput\": $(echo "$TRANSCRIPT" | jq -Rs .),
\"vendor\": \"openai\",
\"model\": \"gpt-4o\",
\"patternName\": \"youtube_summary\"
}]
}"
```
#### Comparison with CLI
The CLI combines these steps automatically:
```bash
# CLI version (single command)
fabric -y "https://youtube.com/watch?v=dQw4w9WgXcQ" --pattern youtube_summary
```
The API provides more flexibility by separating transcript extraction and summarization, allowing you to:
- Extract the transcript once and process it multiple ways
- Apply different patterns to the same transcript
- Store the transcript for later use
- Use different models or vendors for summarization
## Docker Usage
Run the server in Docker:
```bash
# Setup (first time)
mkdir -p $HOME/.fabric-config
docker run --rm -it \
-v $HOME/.fabric-config:/root/.config/fabric \
kayvan/fabric:latest --setup
# Start server
docker run --rm -it \
-p 8080:8080 \
-v $HOME/.fabric-config:/root/.config/fabric \
kayvan/fabric:latest --serve
# With authentication
docker run --rm -it \
-p 8080:8080 \
-v $HOME/.fabric-config:/root/.config/fabric \
kayvan/fabric:latest --serve --api-key my_secret_key
```
## Ollama Compatibility Mode
Fabric can emulate Ollama's API endpoints:
```bash
fabric --serveOllama --address :11434
```
This mode provides:
- `GET /api/tags` - Lists patterns as models
- `GET /api/version` - Server version
- `POST /api/chat` - Ollama-compatible chat endpoint
## Error Handling
All endpoints return standard HTTP status codes:
- `200 OK` - Success
- `400 Bad Request` - Invalid input
- `401 Unauthorized` - Missing or invalid API key
- `404 Not Found` - Resource not found
- `500 Internal Server Error` - Server error
Error responses include JSON with details:
```json
{
"error": "Pattern not found: nonexistent"
}
```
## Rate Limiting
The server does not implement rate limiting. When deploying publicly, use a reverse proxy (nginx, Caddy) with rate limiting enabled.
## CORS
The server sets CORS headers for local development:
```http
Access-Control-Allow-Origin: http://localhost:5173
```
For production, configure CORS through a reverse proxy.

407
docs/swagger.json Normal file
View File

@@ -0,0 +1,407 @@
{
"swagger": "2.0",
"info": {
"description": "REST API for Fabric AI augmentation framework. Provides endpoints for chat completions, pattern management, contexts, sessions, and more.",
"title": "Fabric REST API",
"contact": {
"name": "Fabric Support",
"url": "https://github.com/danielmiessler/fabric"
},
"license": {
"name": "MIT",
"url": "https://opensource.org/licenses/MIT"
},
"version": "1.0"
},
"host": "localhost:8080",
"basePath": "/",
"paths": {
"/chat": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "Stream AI responses using Server-Sent Events (SSE)",
"consumes": [
"application/json"
],
"produces": [
"text/event-stream"
],
"tags": [
"chat"
],
"summary": "Stream chat completions",
"parameters": [
{
"description": "Chat request with prompts and options",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/restapi.ChatRequest"
}
}
],
"responses": {
"200": {
"description": "Streaming response",
"schema": {
"$ref": "#/definitions/restapi.StreamResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
}
}
}
},
"/models/names": {
"get": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "Get a list of all available AI models grouped by vendor",
"produces": [
"application/json"
],
"tags": [
"models"
],
"summary": "List all available models",
"responses": {
"200": {
"description": "Returns models (array) and vendors (map)",
"schema": {
"type": "object",
"additionalProperties": true
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
}
}
}
},
"/patterns/{name}": {
"get": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "Retrieve a pattern by name",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"patterns"
],
"summary": "Get a pattern",
"parameters": [
{
"type": "string",
"description": "Pattern name",
"name": "name",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/fsdb.Pattern"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
}
}
}
},
"/patterns/{name}/apply": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "Apply a pattern with variable substitution",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"patterns"
],
"summary": "Apply pattern with variables",
"parameters": [
{
"type": "string",
"description": "Pattern name",
"name": "name",
"in": "path",
"required": true
},
{
"description": "Pattern application request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/restapi.PatternApplyRequest"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/fsdb.Pattern"
}
},
"400": {
"description": "Bad Request",
"schema": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
}
}
}
}
},
"definitions": {
"domain.ThinkingLevel": {
"type": "string",
"enum": [
"off",
"low",
"medium",
"high"
],
"x-enum-varnames": [
"ThinkingOff",
"ThinkingLow",
"ThinkingMedium",
"ThinkingHigh"
]
},
"fsdb.Pattern": {
"type": "object",
"properties": {
"description": {
"type": "string"
},
"name": {
"type": "string"
},
"pattern": {
"type": "string"
}
}
},
"restapi.ChatRequest": {
"type": "object",
"properties": {
"audioFormat": {
"type": "string"
},
"audioOutput": {
"type": "boolean"
},
"frequencyPenalty": {
"type": "number",
"format": "float64"
},
"imageBackground": {
"type": "string"
},
"imageCompression": {
"type": "integer"
},
"imageFile": {
"type": "string"
},
"imageQuality": {
"type": "string"
},
"imageSize": {
"type": "string"
},
"language": {
"description": "Add Language field to bind from request",
"type": "string"
},
"maxTokens": {
"type": "integer"
},
"model": {
"type": "string"
},
"modelContextLength": {
"type": "integer"
},
"notification": {
"type": "boolean"
},
"notificationCommand": {
"type": "string"
},
"presencePenalty": {
"type": "number",
"format": "float64"
},
"prompts": {
"type": "array",
"items": {
"$ref": "#/definitions/restapi.PromptRequest"
}
},
"raw": {
"type": "boolean"
},
"search": {
"type": "boolean"
},
"searchLocation": {
"type": "string"
},
"seed": {
"type": "integer"
},
"suppressThink": {
"type": "boolean"
},
"temperature": {
"type": "number",
"format": "float64"
},
"thinkEndTag": {
"type": "string"
},
"thinkStartTag": {
"type": "string"
},
"thinking": {
"$ref": "#/definitions/domain.ThinkingLevel"
},
"topP": {
"type": "number",
"format": "float64"
},
"voice": {
"type": "string"
}
}
},
"restapi.PatternApplyRequest": {
"type": "object",
"properties": {
"input": {
"type": "string"
},
"variables": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
}
},
"restapi.PromptRequest": {
"type": "object",
"properties": {
"contextName": {
"type": "string"
},
"model": {
"type": "string"
},
"patternName": {
"type": "string"
},
"strategyName": {
"description": "Optional strategy name",
"type": "string"
},
"userInput": {
"type": "string"
},
"variables": {
"description": "Pattern variables",
"type": "object",
"additionalProperties": {
"type": "string"
}
},
"vendor": {
"type": "string"
}
}
},
"restapi.StreamResponse": {
"type": "object",
"properties": {
"content": {
"description": "The actual content",
"type": "string"
},
"format": {
"description": "\"markdown\", \"mermaid\", \"plain\"",
"type": "string"
},
"type": {
"description": "\"content\", \"error\", \"complete\"",
"type": "string"
}
}
}
},
"securityDefinitions": {
"ApiKeyAuth": {
"type": "apiKey",
"name": "X-API-Key",
"in": "header"
}
}
}

270
docs/swagger.yaml Normal file
View File

@@ -0,0 +1,270 @@
basePath: /
definitions:
domain.ThinkingLevel:
enum:
- "off"
- low
- medium
- high
type: string
x-enum-varnames:
- ThinkingOff
- ThinkingLow
- ThinkingMedium
- ThinkingHigh
fsdb.Pattern:
properties:
description:
type: string
name:
type: string
pattern:
type: string
type: object
restapi.ChatRequest:
properties:
audioFormat:
type: string
audioOutput:
type: boolean
frequencyPenalty:
format: float64
type: number
imageBackground:
type: string
imageCompression:
type: integer
imageFile:
type: string
imageQuality:
type: string
imageSize:
type: string
language:
description: Add Language field to bind from request
type: string
maxTokens:
type: integer
model:
type: string
modelContextLength:
type: integer
notification:
type: boolean
notificationCommand:
type: string
presencePenalty:
format: float64
type: number
prompts:
items:
$ref: '#/definitions/restapi.PromptRequest'
type: array
raw:
type: boolean
search:
type: boolean
searchLocation:
type: string
seed:
type: integer
suppressThink:
type: boolean
temperature:
format: float64
type: number
thinkEndTag:
type: string
thinkStartTag:
type: string
thinking:
$ref: '#/definitions/domain.ThinkingLevel'
topP:
format: float64
type: number
voice:
type: string
type: object
restapi.PatternApplyRequest:
properties:
input:
type: string
variables:
additionalProperties:
type: string
type: object
type: object
restapi.PromptRequest:
properties:
contextName:
type: string
model:
type: string
patternName:
type: string
strategyName:
description: Optional strategy name
type: string
userInput:
type: string
variables:
additionalProperties:
type: string
description: Pattern variables
type: object
vendor:
type: string
type: object
restapi.StreamResponse:
properties:
content:
description: The actual content
type: string
format:
description: '"markdown", "mermaid", "plain"'
type: string
type:
description: '"content", "error", "complete"'
type: string
type: object
host: localhost:8080
info:
contact:
name: Fabric Support
url: https://github.com/danielmiessler/fabric
description: REST API for Fabric AI augmentation framework. Provides endpoints for
chat completions, pattern management, contexts, sessions, and more.
license:
name: MIT
url: https://opensource.org/licenses/MIT
title: Fabric REST API
version: "1.0"
paths:
/chat:
post:
consumes:
- application/json
description: Stream AI responses using Server-Sent Events (SSE)
parameters:
- description: Chat request with prompts and options
in: body
name: request
required: true
schema:
$ref: '#/definitions/restapi.ChatRequest'
produces:
- text/event-stream
responses:
"200":
description: Streaming response
schema:
$ref: '#/definitions/restapi.StreamResponse'
"400":
description: Bad Request
schema:
additionalProperties:
type: string
type: object
security:
- ApiKeyAuth: []
summary: Stream chat completions
tags:
- chat
/models/names:
get:
description: Get a list of all available AI models grouped by vendor
produces:
- application/json
responses:
"200":
description: Returns models (array) and vendors (map)
schema:
additionalProperties: true
type: object
"500":
description: Internal Server Error
schema:
additionalProperties:
type: string
type: object
security:
- ApiKeyAuth: []
summary: List all available models
tags:
- models
/patterns/{name}:
get:
consumes:
- application/json
description: Retrieve a pattern by name
parameters:
- description: Pattern name
in: path
name: name
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/fsdb.Pattern'
"500":
description: Internal Server Error
schema:
additionalProperties:
type: string
type: object
security:
- ApiKeyAuth: []
summary: Get a pattern
tags:
- patterns
/patterns/{name}/apply:
post:
consumes:
- application/json
description: Apply a pattern with variable substitution
parameters:
- description: Pattern name
in: path
name: name
required: true
type: string
- description: Pattern application request
in: body
name: request
required: true
schema:
$ref: '#/definitions/restapi.PatternApplyRequest'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/fsdb.Pattern'
"400":
description: Bad Request
schema:
additionalProperties:
type: string
type: object
"500":
description: Internal Server Error
schema:
additionalProperties:
type: string
type: object
security:
- ApiKeyAuth: []
summary: Apply pattern with variables
tags:
- patterns
securityDefinitions:
ApiKeyAuth:
in: header
name: X-API-Key
type: apiKey
swagger: "2.0"

52
go.mod
View File

@@ -9,8 +9,8 @@ require (
github.com/aws/aws-sdk-go-v2/config v1.31.8
github.com/aws/aws-sdk-go-v2/service/bedrock v1.46.1
github.com/aws/aws-sdk-go-v2/service/bedrockruntime v1.40.1
github.com/gabriel-vasile/mimetype v1.4.9
github.com/gin-gonic/gin v1.10.1
github.com/gabriel-vasile/mimetype v1.4.12
github.com/gin-gonic/gin v1.11.0
github.com/go-git/go-git/v5 v5.16.2
github.com/go-shiori/go-readability v0.0.0-20250217085726-9f5bf5ca7612
github.com/google/go-github/v66 v66.0.0
@@ -28,8 +28,11 @@ require (
github.com/sgaunet/perplexity-go/v2 v2.8.0
github.com/spf13/cobra v1.9.1
github.com/stretchr/testify v1.11.1
github.com/swaggo/files v1.0.1
github.com/swaggo/gin-swagger v1.6.1
github.com/swaggo/swag v1.16.6
golang.org/x/oauth2 v0.30.0
golang.org/x/text v0.31.0
golang.org/x/text v0.32.0
google.golang.org/api v0.247.0
gopkg.in/yaml.v3 v3.0.1
)
@@ -37,8 +40,27 @@ require (
require (
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.19.1 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 // indirect
github.com/KyleBanks/depth v1.2.1 // indirect
github.com/bytedance/gopkg v0.1.3 // indirect
github.com/go-openapi/jsonpointer v0.22.4 // indirect
github.com/go-openapi/jsonreference v0.21.4 // indirect
github.com/go-openapi/spec v0.22.2 // indirect
github.com/go-openapi/swag/conv v0.25.4 // indirect
github.com/go-openapi/swag/jsonname v0.25.4 // indirect
github.com/go-openapi/swag/jsonutils v0.25.4 // indirect
github.com/go-openapi/swag/loading v0.25.4 // indirect
github.com/go-openapi/swag/stringutils v0.25.4 // indirect
github.com/go-openapi/swag/typeutils v0.25.4 // indirect
github.com/go-openapi/swag/yamlutils v0.25.4 // indirect
github.com/goccy/go-yaml v1.19.1 // indirect
github.com/google/go-cmp v0.7.0 // indirect
github.com/gorilla/websocket v1.5.3 // indirect
github.com/quic-go/qpack v0.6.0 // indirect
github.com/quic-go/quic-go v0.57.1 // indirect
go.uber.org/mock v0.6.0 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/mod v0.31.0 // indirect
golang.org/x/tools v0.40.0 // indirect
)
require (
@@ -63,10 +85,10 @@ require (
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.34.4 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.38.4 // indirect
github.com/aws/smithy-go v1.23.0 // indirect
github.com/bytedance/sonic v1.13.3 // indirect
github.com/bytedance/sonic/loader v0.2.4 // indirect
github.com/bytedance/sonic v1.14.2 // indirect
github.com/bytedance/sonic/loader v0.4.0 // indirect
github.com/cloudflare/circl v1.6.1 // indirect
github.com/cloudwego/base64x v0.1.5 // indirect
github.com/cloudwego/base64x v0.1.6 // indirect
github.com/coder/websocket v1.8.13 // indirect
github.com/cyphar/filepath-securejoin v0.4.1 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
@@ -79,7 +101,7 @@ require (
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.26.0 // indirect
github.com/go-playground/validator/v10 v10.29.0 // indirect
github.com/go-shiori/dom v0.0.0-20230515143342-73569d674e1c // indirect
github.com/goccy/go-json v0.10.5 // indirect
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f // indirect
@@ -93,7 +115,7 @@ require (
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/kevinburke/ssh_config v1.2.0 // indirect
github.com/klauspost/cpuid/v2 v2.2.10 // indirect
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
@@ -110,23 +132,23 @@ require (
github.com/tidwall/pretty v1.2.1 // indirect
github.com/tidwall/sjson v1.2.5 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.14 // indirect
github.com/ugorji/go/codec v1.3.1 // indirect
github.com/xanzy/ssh-agent v0.3.3 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect
go.opentelemetry.io/otel v1.36.0 // indirect
go.opentelemetry.io/otel/metric v1.36.0 // indirect
go.opentelemetry.io/otel/trace v1.36.0 // indirect
golang.org/x/arch v0.18.0 // indirect
golang.org/x/crypto v0.45.0 // indirect
golang.org/x/arch v0.23.0 // indirect
golang.org/x/crypto v0.46.0 // indirect
golang.org/x/exp v0.0.0-20250531010427-b6e5de432a8b // indirect
golang.org/x/net v0.47.0 // indirect
golang.org/x/sync v0.18.0 // indirect
golang.org/x/sys v0.38.0 // indirect
golang.org/x/net v0.48.0 // indirect
golang.org/x/sync v0.19.0 // indirect
golang.org/x/sys v0.39.0 // indirect
google.golang.org/genai v1.17.0
google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c // indirect
google.golang.org/grpc v1.74.2 // indirect
google.golang.org/protobuf v1.36.7 // indirect
google.golang.org/protobuf v1.36.11 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
)

142
go.sum
View File

@@ -18,6 +18,8 @@ github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 h1:oygO0locgZJ
github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
@@ -27,8 +29,6 @@ github.com/andybalholm/cascadia v1.3.3 h1:AG2YHrzJIm4BZ19iwJ/DAua6Btl3IwJX+VI4kk
github.com/andybalholm/cascadia v1.3.3/go.mod h1:xNd9bqTn98Ln4DwST8/nG+H0yuB8Hmgu1YHNnWw0GeA=
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
github.com/anthropics/anthropic-sdk-go v1.16.0 h1:nRkOFDqYXsHteoIhjdJr/5dsiKbFF3rflSv8ax50y8o=
github.com/anthropics/anthropic-sdk-go v1.16.0/go.mod h1:WTz31rIUHUHqai2UslPpw5CwXrQP3geYBioRV4WOLvE=
github.com/anthropics/anthropic-sdk-go v1.19.0 h1:mO6E+ffSzLRvR/YUH9KJC0uGw0uV8GjISIuzem//3KE=
github.com/anthropics/anthropic-sdk-go v1.19.0/go.mod h1:WTz31rIUHUHqai2UslPpw5CwXrQP3geYBioRV4WOLvE=
github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de h1:FxWPpzIjnTlhPwqqXc4/vE0f7GvRjuAsbW+HOIe8KnA=
@@ -69,16 +69,16 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.38.4 h1:PR00NXRYgY4FWHqOGx3fC3lhVKjs
github.com/aws/aws-sdk-go-v2/service/sts v1.38.4/go.mod h1:Z+Gd23v97pX9zK97+tX4ppAgqCt3Z2dIXB02CtBncK8=
github.com/aws/smithy-go v1.23.0 h1:8n6I3gXzWJB2DxBDnfxgBaSX6oe0d/t10qGz7OKqMCE=
github.com/aws/smithy-go v1.23.0/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI=
github.com/bytedance/sonic v1.13.3 h1:MS8gmaH16Gtirygw7jV91pDCN33NyMrPbN7qiYhEsF0=
github.com/bytedance/sonic v1.13.3/go.mod h1:o68xyaF9u2gvVBuGHPlUVCy+ZfmNNO5ETf1+KgkJhz4=
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
github.com/bytedance/sonic/loader v0.2.4 h1:ZWCw4stuXUsn1/+zQDqeE7JKP+QO47tz7QCNan80NzY=
github.com/bytedance/sonic/loader v0.2.4/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI=
github.com/bytedance/gopkg v0.1.3 h1:TPBSwH8RsouGCBcMBktLt1AymVo2TVsBVCY4b6TnZ/M=
github.com/bytedance/gopkg v0.1.3/go.mod h1:576VvJ+eJgyCzdjS+c4+77QF3p7ubbtiKARP3TxducM=
github.com/bytedance/sonic v1.14.2 h1:k1twIoe97C1DtYUo+fZQy865IuHia4PR5RPiuGPPIIE=
github.com/bytedance/sonic v1.14.2/go.mod h1:T80iDELeHiHKSc0C9tubFygiuXoGzrkjKzX2quAx980=
github.com/bytedance/sonic/loader v0.4.0 h1:olZ7lEqcxtZygCK9EKYKADnpQoYkRQxaeY2NYzevs+o=
github.com/bytedance/sonic/loader v0.4.0/go.mod h1:AR4NYCk5DdzZizZ5djGqQ92eEhCCcdf5x77udYiSJRo=
github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
github.com/cloudwego/base64x v0.1.5 h1:XPciSp1xaq2VCSt6lF0phncD4koWyULpl5bUxbfCyP4=
github.com/cloudwego/base64x v0.1.5/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M=
github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU=
github.com/coder/websocket v1.8.13 h1:f3QZdXy7uGVz+4uCJy2nTZyM0yTBj8yANEHhqlXZ9FE=
github.com/coder/websocket v1.8.13/go.mod h1:LNVeNrXQZfe5qhS9ALED3uA+l5pPqvwXg3CKoDBB2gs=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
@@ -94,12 +94,14 @@ github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/gabriel-vasile/mimetype v1.4.9 h1:5k+WDwEsD9eTLL8Tz3L0VnmVh9QxGjRmjBvAG7U/oYY=
github.com/gabriel-vasile/mimetype v1.4.9/go.mod h1:WnSQhFKJuBlRyLiKohA/2DtIlPFAbguNaG7QCHcyGok=
github.com/gabriel-vasile/mimetype v1.4.12 h1:e9hWvmLYvtp846tLHam2o++qitpguFiYCKbn0w9jyqw=
github.com/gabriel-vasile/mimetype v1.4.12/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4=
github.com/gin-contrib/gzip v0.0.6/go.mod h1:QOJlmV2xmayAjkNS2Y8NQsMneuRShOU/kjovCXNuzzk=
github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w=
github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM=
github.com/gin-gonic/gin v1.10.1 h1:T0ujvqyCSqRopADpgPgiTT63DUQVSfojyME59Ei63pQ=
github.com/gin-gonic/gin v1.10.1/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
github.com/gin-gonic/gin v1.11.0 h1:OW/6PLjyusp2PPXtyxKHU0RbX6I/l28FTdDlae5ueWk=
github.com/gin-gonic/gin v1.11.0/go.mod h1:+iq/FyxlGzII0KHiBGjuNn4UNENUlKbGlNmc+W50Dls=
github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c=
github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU=
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
@@ -115,20 +117,49 @@ github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-openapi/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4=
github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80=
github.com/go-openapi/jsonreference v0.21.4 h1:24qaE2y9bx/q3uRK/qN+TDwbok1NhbSmGjjySRCHtC8=
github.com/go-openapi/jsonreference v0.21.4/go.mod h1:rIENPTjDbLpzQmQWCj5kKj3ZlmEh+EFVbz3RTUh30/4=
github.com/go-openapi/spec v0.22.2 h1:KEU4Fb+Lp1qg0V4MxrSCPv403ZjBl8Lx1a83gIPU8Qc=
github.com/go-openapi/spec v0.22.2/go.mod h1:iIImLODL2loCh3Vnox8TY2YWYJZjMAKYyLH2Mu8lOZs=
github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM=
github.com/go-openapi/swag/conv v0.25.4 h1:/Dd7p0LZXczgUcC/Ikm1+YqVzkEeCc9LnOWjfkpkfe4=
github.com/go-openapi/swag/conv v0.25.4/go.mod h1:3LXfie/lwoAv0NHoEuY1hjoFAYkvlqI/Bn5EQDD3PPU=
github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI=
github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag=
github.com/go-openapi/swag/jsonutils v0.25.4 h1:VSchfbGhD4UTf4vCdR2F4TLBdLwHyUDTd1/q4i+jGZA=
github.com/go-openapi/swag/jsonutils v0.25.4/go.mod h1:7OYGXpvVFPn4PpaSdPHJBtF0iGnbEaTk8AvBkoWnaAY=
github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4 h1:IACsSvBhiNJwlDix7wq39SS2Fh7lUOCJRmx/4SN4sVo=
github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4/go.mod h1:Mt0Ost9l3cUzVv4OEZG+WSeoHwjWLnarzMePNDAOBiM=
github.com/go-openapi/swag/loading v0.25.4 h1:jN4MvLj0X6yhCDduRsxDDw1aHe+ZWoLjW+9ZQWIKn2s=
github.com/go-openapi/swag/loading v0.25.4/go.mod h1:rpUM1ZiyEP9+mNLIQUdMiD7dCETXvkkC30z53i+ftTE=
github.com/go-openapi/swag/stringutils v0.25.4 h1:O6dU1Rd8bej4HPA3/CLPciNBBDwZj9HiEpdVsb8B5A8=
github.com/go-openapi/swag/stringutils v0.25.4/go.mod h1:GTsRvhJW5xM5gkgiFe0fV3PUlFm0dr8vki6/VSRaZK0=
github.com/go-openapi/swag/typeutils v0.25.4 h1:1/fbZOUN472NTc39zpa+YGHn3jzHWhv42wAJSN91wRw=
github.com/go-openapi/swag/typeutils v0.25.4/go.mod h1:Ou7g//Wx8tTLS9vG0UmzfCsjZjKhpjxayRKTHXf2pTE=
github.com/go-openapi/swag/yamlutils v0.25.4 h1:6jdaeSItEUb7ioS9lFoCZ65Cne1/RZtPBZ9A56h92Sw=
github.com/go-openapi/swag/yamlutils v0.25.4/go.mod h1:MNzq1ulQu+yd8Kl7wPOut/YHAAU/H6hL91fF+E2RFwc=
github.com/go-openapi/testify/enable/yaml/v2 v2.0.2 h1:0+Y41Pz1NkbTHz8NngxTuAXxEodtNSI1WG1c/m5Akw4=
github.com/go-openapi/testify/enable/yaml/v2 v2.0.2/go.mod h1:kme83333GCtJQHXQ8UKX3IBZu6z8T5Dvy5+CW3NLUUg=
github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls=
github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc/iMaVtFbr3Sw2k=
github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo=
github.com/go-playground/validator/v10 v10.29.0 h1:lQlF5VNJWNlRbRZNeOIkWElR+1LL/OuHcc0Kp14w1xk=
github.com/go-playground/validator/v10 v10.29.0/go.mod h1:D6QxqeMlgIPuT02L66f2ccrZ7AGgHkzKmmTMZhk/Kc4=
github.com/go-shiori/dom v0.0.0-20230515143342-73569d674e1c h1:wpkoddUomPfHiOziHZixGO5ZBS73cKqVzZipfrLmO1w=
github.com/go-shiori/dom v0.0.0-20230515143342-73569d674e1c/go.mod h1:oVDCh3qjJMLVUSILBRwrm+Bc6RNXGZYtoh9xdvf1ffM=
github.com/go-shiori/go-readability v0.0.0-20250217085726-9f5bf5ca7612 h1:BYLNYdZaepitbZreRIa9xeCQZocWmy/wj4cGIH0qyw0=
github.com/go-shiori/go-readability v0.0.0-20250217085726-9f5bf5ca7612/go.mod h1:wgqthQa8SAYs0yyljVeCOQlZ027VW5CmLsbi9jWC08c=
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/goccy/go-yaml v1.19.1 h1:3rG3+v8pkhRqoQ/88NYNMHYVGYztCOCIZ7UQhu7H+NE=
github.com/goccy/go-yaml v1.19.1/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f h1:3BSP1Tbs2djlpprl7wCLuiqMaUh5SJkkzI2gDs+FgLs=
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f/go.mod h1:Pcatq5tYkCW2Q6yrR2VRHlbHpZ/R4/7qyL1TCF7vl14=
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
@@ -172,10 +203,8 @@ github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNU
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE=
github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
@@ -220,6 +249,10 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
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/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8=
github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII=
github.com/quic-go/quic-go v0.57.1 h1:25KAAR9QR8KZrCZRThWMKVAwGoiHIrNbT72ULHTuI10=
github.com/quic-go/quic-go v0.57.1/go.mod h1:ly4QBAjHA2VhdnxhojRsCUOeJwKYg+taDlos92xb1+s=
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
@@ -241,15 +274,23 @@ github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
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/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE=
github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg=
github.com/swaggo/gin-swagger v1.6.1 h1:Ri06G4gc9N4t4k8hekMigJ9zKTFSlqj/9paAQCQs7cY=
github.com/swaggo/gin-swagger v1.6.1/go.mod h1:LQ+hJStHakCWRiK/YNYtJOu4mR2FP+pxLnILT/qNiTw=
github.com/swaggo/swag v1.16.6 h1:qBNcx53ZaX+M5dxVyTrgQ0PJ/ACK+NzhwcbieTt+9yI=
github.com/swaggo/swag v1.16.6/go.mod h1:ngP2etMK5a0P3QBizic5MEwpRmluJZPHjXcMoj4Xesg=
github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=
github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
@@ -262,8 +303,8 @@ 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/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go/codec v1.2.14 h1:yOQvXCBc3Ij46LRkRoh4Yd5qK6LVOgi0bYOXfb7ifjw=
github.com/ugorji/go/codec v1.2.14/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/ugorji/go/codec v1.3.1 h1:waO7eEiFDwidsBN6agj1vJQ4AG7lh2yqXyOXqhgQuyY=
github.com/ugorji/go/codec v1.3.1/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4=
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
@@ -281,8 +322,12 @@ go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFw
go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4=
go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w=
go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA=
golang.org/x/arch v0.18.0 h1:WN9poc33zL4AzGxqf8VtpKUnGvMi8O9lhNyBMF/85qc=
golang.org/x/arch v0.18.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk=
go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y=
go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
golang.org/x/arch v0.23.0 h1:lKF64A2jF6Zd8L0knGltUnegD62JMFBiCPBmQpToHhg=
golang.org/x/arch v0.23.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
@@ -290,10 +335,8 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliY
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4=
golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc=
golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
golang.org/x/exp v0.0.0-20250531010427-b6e5de432a8b h1:QoALfVG9rhQ/M7vYDScfPdWjGL9dlsVVM5VGh7aKoAA=
golang.org/x/exp v0.0.0-20250531010427-b6e5de432a8b/go.mod h1:U6Lno4MTRCDY+Ba7aCcauB9T60gsv5s4ralQzP72ZoQ=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
@@ -301,20 +344,21 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI=
golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU=
golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY=
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -324,10 +368,8 @@ golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -344,10 +386,8 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@@ -357,9 +397,8 @@ golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4=
golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw=
golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU=
golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q=
golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
@@ -370,16 +409,18 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA=
golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.247.0 h1:tSd/e0QrUlLsrwMKmkbQhYVa109qIintOls2Wh6bngc=
@@ -394,8 +435,8 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c h1:
google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c/go.mod h1:gw1tLEfykwDz2ET4a12jcXt4couGAm7IwsVaTy0Sflo=
google.golang.org/grpc v1.74.2 h1:WoosgB65DlWVC9FqI82dGsZhWFNBSLjQ84bjROOpMu4=
google.golang.org/grpc v1.74.2/go.mod h1:CtQ+BGjaAIXHs/5YS3i473GqwBBa1zGQNevxdeBEXrM=
google.golang.org/protobuf v1.36.7 h1:IgrO7UwFQGJdRNXH/sQux4R1Dj1WAKcLElzeeRaXV2A=
google.golang.org/protobuf v1.36.7/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
@@ -407,4 +448,3 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=

View File

@@ -8,6 +8,7 @@ import (
"os"
"path/filepath"
"reflect"
"slices"
"strconv"
"strings"
@@ -230,8 +231,8 @@ func parseDebugLevel(args []string) int {
if lvl, err := strconv.Atoi(args[i+1]); err == nil {
return lvl
}
} else if strings.HasPrefix(arg, "--debug=") {
if lvl, err := strconv.Atoi(strings.TrimPrefix(arg, "--debug=")); err == nil {
} else if after, ok := strings.CutPrefix(arg, "--debug="); ok {
if lvl, err := strconv.Atoi(after); err == nil {
return lvl
}
}
@@ -241,8 +242,8 @@ func parseDebugLevel(args []string) int {
func extractFlag(arg string) string {
var flag string
if strings.HasPrefix(arg, "--") {
flag = strings.TrimPrefix(arg, "--")
if after, ok := strings.CutPrefix(arg, "--"); ok {
flag = after
if i := strings.Index(flag, "="); i > 0 {
flag = flag[:i]
}
@@ -348,10 +349,8 @@ func validateImageFile(imagePath string) error {
ext := strings.ToLower(filepath.Ext(imagePath))
validExtensions := []string{".png", ".jpeg", ".jpg", ".webp"}
for _, validExt := range validExtensions {
if ext == validExt {
return nil // Valid extension found
}
if slices.Contains(validExtensions, ext) {
return nil // Valid extension found
}
return fmt.Errorf("%s", fmt.Sprintf(i18n.T("invalid_image_file_extension"), ext))
@@ -370,13 +369,7 @@ func validateImageParameters(imagePath, size, quality, background string, compre
// Validate size
if size != "" {
validSizes := []string{"1024x1024", "1536x1024", "1024x1536", "auto"}
valid := false
for _, validSize := range validSizes {
if size == validSize {
valid = true
break
}
}
valid := slices.Contains(validSizes, size)
if !valid {
return fmt.Errorf("%s", fmt.Sprintf(i18n.T("invalid_image_size"), size))
}
@@ -385,13 +378,7 @@ func validateImageParameters(imagePath, size, quality, background string, compre
// Validate quality
if quality != "" {
validQualities := []string{"low", "medium", "high", "auto"}
valid := false
for _, validQuality := range validQualities {
if quality == validQuality {
valid = true
break
}
}
valid := slices.Contains(validQualities, quality)
if !valid {
return fmt.Errorf("%s", fmt.Sprintf(i18n.T("invalid_image_quality"), quality))
}
@@ -400,13 +387,7 @@ func validateImageParameters(imagePath, size, quality, background string, compre
// Validate background
if background != "" {
validBackgrounds := []string{"opaque", "transparent"}
valid := false
for _, validBackground := range validBackgrounds {
if background == validBackground {
valid = true
break
}
}
valid := slices.Contains(validBackgrounds, background)
if !valid {
return fmt.Errorf("%s", fmt.Sprintf(i18n.T("invalid_image_background"), background))
}

View File

@@ -183,10 +183,10 @@ func detectLanguageFromArgs() string {
if i+1 < len(args) {
return args[i+1]
}
} else if strings.HasPrefix(arg, "--language=") {
return strings.TrimPrefix(arg, "--language=")
} else if strings.HasPrefix(arg, "-g=") {
return strings.TrimPrefix(arg, "-g=")
} else if after, ok := strings.CutPrefix(arg, "--language="); ok {
return after
} else if after, ok := strings.CutPrefix(arg, "-g="); ok {
return after
} else if runtime.GOOS == "windows" && strings.HasPrefix(arg, "/g:") {
return strings.TrimPrefix(arg, "/g:")
} else if runtime.GOOS == "windows" && strings.HasPrefix(arg, "/g=") {
@@ -272,10 +272,7 @@ func (h *TranslatedHelpWriter) writeAllFlags() {
// Pad to align descriptions
flagStr := flagLine.String()
padding := 34 - len(flagStr)
if padding < 2 {
padding = 2
}
padding := max(34-len(flagStr), 2)
fmt.Fprintf(h.writer, "%s%s%s", flagStr, strings.Repeat(" ", padding), description)

View File

@@ -4,6 +4,7 @@ import (
"fmt"
"os"
"path/filepath"
"slices"
"strings"
"github.com/atotto/clipboard"
@@ -66,10 +67,5 @@ func CreateAudioOutputFile(audioData []byte, fileName string) (err error) {
func IsAudioFormat(fileName string) bool {
ext := strings.ToLower(filepath.Ext(fileName))
audioExts := []string{".wav", ".mp3", ".m4a", ".aac", ".ogg", ".flac"}
for _, audioExt := range audioExts {
if ext == audioExt {
return true
}
}
return false
return slices.Contains(audioExts, ext)
}

View File

@@ -5,6 +5,7 @@ import (
"fmt"
"os"
"path/filepath"
"slices"
"strings"
)
@@ -146,14 +147,7 @@ func fixInvalidEscapes(jsonStr string) string {
// Check for escape sequences only inside strings
if inQuotes && ch == '\\' && i+1 < len(jsonStr) {
nextChar := jsonStr[i+1]
isValid := false
for _, validEscape := range validEscapes {
if nextChar == validEscape {
isValid = true
break
}
}
isValid := slices.Contains(validEscapes, nextChar)
if !isValid {
// Invalid escape sequence - add an extra backslash

View File

@@ -3,6 +3,7 @@ package gemini
import (
"fmt"
"sort"
"strings"
)
// GeminiVoice represents a Gemini TTS voice with its characteristics
@@ -126,16 +127,17 @@ func ListGeminiVoices(shellCompleteMode bool) string {
if shellCompleteMode {
// For shell completion, just return voice names
names := GetGeminiVoiceNames()
result := ""
var result strings.Builder
for _, name := range names {
result += name + "\n"
result.WriteString(name + "\n")
}
return result
return result.String()
}
// For human-readable output
voices := GetGeminiVoices()
result := "Available Gemini Text-to-Speech voices:\n\n"
var result strings.Builder
result.WriteString("Available Gemini Text-to-Speech voices:\n\n")
// Group by characteristics for better readability
groups := map[string][]GeminiVoice{
@@ -186,22 +188,22 @@ func ListGeminiVoices(shellCompleteMode bool) string {
// Output grouped voices
for groupName, groupVoices := range groups {
if len(groupVoices) > 0 {
result += fmt.Sprintf("%s:\n", groupName)
result.WriteString(fmt.Sprintf("%s:\n", groupName))
for _, voice := range groupVoices {
defaultStr := ""
if voice.Name == "Kore" {
defaultStr = " (default)"
}
result += fmt.Sprintf(" %-15s - %s%s\n", voice.Name, voice.Description, defaultStr)
result.WriteString(fmt.Sprintf(" %-15s - %s%s\n", voice.Name, voice.Description, defaultStr))
}
result += "\n"
result.WriteString("\n")
}
}
result += "Use --voice <voice_name> to select a specific voice.\n"
result += "Example: fabric --voice Charon -m gemini-2.5-flash-preview-tts -o output.wav \"Hello world\"\n"
result.WriteString("Use --voice <voice_name> to select a specific voice.\n")
result.WriteString("Example: fabric --voice Charon -m gemini-2.5-flash-preview-tts -o output.wav \"Hello world\"\n")
return result
return result.String()
}
// NOTE: This implementation maintains a curated list based on official Google documentation.

View File

@@ -140,8 +140,8 @@ func (c *Client) SendStream(msgs []*chat.ChatCompletionMessage, opts *domain.Cha
continue
}
if bytes.HasPrefix(line, []byte("data: ")) {
line = bytes.TrimPrefix(line, []byte("data: "))
if after, ok := bytes.CutPrefix(line, []byte("data: ")); ok {
line = after
}
if string(line) == "[DONE]" {

View File

@@ -8,6 +8,7 @@ import (
"fmt"
"os"
"path/filepath"
"slices"
"strings"
"github.com/danielmiessler/fabric/internal/domain"
@@ -31,12 +32,7 @@ var ImageGenerationSupportedModels = []string{
// supportsImageGeneration checks if the given model supports the image_generation tool
func supportsImageGeneration(model string) bool {
for _, supportedModel := range ImageGenerationSupportedModels {
if model == supportedModel {
return true
}
}
return false
return slices.Contains(ImageGenerationSupportedModels, model)
}
// getOutputFormatFromExtension determines the API output format based on file extension

View File

@@ -4,6 +4,7 @@ import (
"context"
"fmt"
"os"
"strings"
"sync"
"github.com/danielmiessler/fabric/internal/domain"
@@ -107,18 +108,19 @@ func (c *Client) Send(ctx context.Context, msgs []*chat.ChatCompletionMessage, o
return "", fmt.Errorf("perplexity API request failed: %w", err) // Corrected capitalization
}
content := resp.GetLastContent()
var content strings.Builder
content.WriteString(resp.GetLastContent())
// Append citations if available
citations := resp.GetCitations()
if len(citations) > 0 {
content += "\n\n# CITATIONS\n\n"
content.WriteString("\n\n# CITATIONS\n\n")
for i, citation := range citations {
content += fmt.Sprintf("- [%d] %s\n", i+1, citation)
content.WriteString(fmt.Sprintf("- [%d] %s\n", i+1, citation))
}
}
return content, nil
return content.String(), nil
}
func (c *Client) SendStream(msgs []*chat.ChatCompletionMessage, opts *domain.ChatOptions, channel chan string) error {

View File

@@ -189,7 +189,8 @@ esac`
// Helper function to create and register extension
createExtension := func(name, opName, cmdTemplate string, config map[string]any) error {
configPath := filepath.Join(tmpDir, name+".yaml")
configContent := `name: ` + name + `
var configContent strings.Builder
configContent.WriteString(`name: ` + name + `
executable: ` + testScript + `
type: executable
timeout: 30s
@@ -199,14 +200,14 @@ operations:
config:
output:
method: file
file_config:`
file_config:`)
// Add config options
for k, v := range config {
configContent += "\n " + k + ": " + strings.TrimSpace(v.(string))
configContent.WriteString("\n " + k + ": " + strings.TrimSpace(v.(string)))
}
if err := os.WriteFile(configPath, []byte(configContent), 0644); err != nil {
if err := os.WriteFile(configPath, []byte(configContent.String()), 0644); err != nil {
return err
}

View File

@@ -2,14 +2,25 @@ package restapi
import (
"net/http"
"strings"
"github.com/gin-gonic/gin"
)
const APIKeyHeader = "X-API-Key"
// APIKeyMiddleware validates API key for protected endpoints.
// Swagger documentation endpoints (/swagger/*) are exempt from authentication
// to allow users to browse and test the API documentation freely.
func APIKeyMiddleware(apiKey string) gin.HandlerFunc {
return func(c *gin.Context) {
// Skip authentication for Swagger documentation endpoints
// This allows public access to API docs even when authentication is enabled
if strings.HasPrefix(c.Request.URL.Path, "/swagger/") {
c.Next()
return
}
headerApiKey := c.GetHeader(APIKeyHeader)
if headerApiKey == "" {

View File

@@ -55,6 +55,17 @@ func NewChatHandler(r *gin.Engine, registry *core.PluginRegistry, db *fsdb.Db) *
return handler
}
// HandleChat godoc
// @Summary Stream chat completions
// @Description Stream AI responses using Server-Sent Events (SSE)
// @Tags chat
// @Accept json
// @Produce text/event-stream
// @Param request body ChatRequest true "Chat request with prompts and options"
// @Success 200 {object} StreamResponse "Streaming response"
// @Failure 400 {object} map[string]string
// @Security ApiKeyAuth
// @Router /chat [post]
func (h *ChatHandler) HandleChat(c *gin.Context) {
var request ChatRequest

View File

@@ -17,6 +17,15 @@ func NewModelsHandler(r *gin.Engine, vendorManager *ai.VendorsManager) {
r.GET("/models/names", handler.GetModelNames)
}
// GetModelNames godoc
// @Summary List all available models
// @Description Get a list of all available AI models grouped by vendor
// @Tags models
// @Produce json
// @Success 200 {object} map[string]interface{} "Returns models (array) and vendors (map)"
// @Failure 500 {object} map[string]string
// @Security ApiKeyAuth
// @Router /models/names [get]
func (h *ModelsHandler) GetModelNames(c *gin.Context) {
vendorsModels, err := h.vendorManager.GetModels()
if err != nil {

View File

@@ -102,7 +102,7 @@ func ServeOllama(registry *core.PluginRegistry, address string, version string)
// Ollama Endpoints
r.GET("/api/tags", typeConversion.ollamaTags)
r.GET("/api/version", func(c *gin.Context) {
c.Data(200, "application/json", []byte(fmt.Sprintf("{\"%s\"}", version)))
c.Data(200, "application/json", fmt.Appendf(nil, "{\"%s\"}", version))
})
r.POST("/api/chat", typeConversion.ollamaChat)
@@ -224,7 +224,7 @@ func (f APIConvert) ollamaChat(c *gin.Context) {
c.JSON(http.StatusInternalServerError, gin.H{"error": "testing endpoint"})
return
}
for _, word := range strings.Split(fabricResponse.Content, " ") {
for word := range strings.SplitSeq(fabricResponse.Content, " ") {
forwardedResponse = OllamaResponse{
Model: "",
CreatedAt: "",

View File

@@ -33,6 +33,16 @@ func NewPatternsHandler(r *gin.Engine, patterns *fsdb.PatternsEntity) (ret *Patt
}
// Get handles the GET /patterns/:name route - returns raw pattern without variable processing
// @Summary Get a pattern
// @Description Retrieve a pattern by name
// @Tags patterns
// @Accept json
// @Produce json
// @Param name path string true "Pattern name"
// @Success 200 {object} fsdb.Pattern
// @Failure 500 {object} map[string]string
// @Security ApiKeyAuth
// @Router /patterns/{name} [get]
func (h *PatternsHandler) Get(c *gin.Context) {
name := c.Param("name")
@@ -59,6 +69,18 @@ type PatternApplyRequest struct {
}
// ApplyPattern handles the POST /patterns/:name/apply route
// @Summary Apply pattern with variables
// @Description Apply a pattern with variable substitution
// @Tags patterns
// @Accept json
// @Produce json
// @Param name path string true "Pattern name"
// @Param request body PatternApplyRequest true "Pattern application request"
// @Success 200 {object} fsdb.Pattern
// @Failure 400 {object} map[string]string
// @Failure 500 {object} map[string]string
// @Security ApiKeyAuth
// @Router /patterns/{name}/apply [post]
func (h *PatternsHandler) ApplyPattern(c *gin.Context) {
name := c.Param("name")

View File

@@ -2,11 +2,30 @@ package restapi
import (
"log/slog"
"net/http"
"os"
"path/filepath"
"github.com/danielmiessler/fabric/internal/core"
"github.com/gin-gonic/gin"
swaggerFiles "github.com/swaggo/files"
ginSwagger "github.com/swaggo/gin-swagger"
_ "github.com/danielmiessler/fabric/docs" // swagger docs
)
// @title Fabric REST API
// @version 1.0
// @description REST API for Fabric AI augmentation framework. Provides endpoints for chat completions, pattern management, contexts, sessions, and more.
// @contact.name Fabric Support
// @contact.url https://github.com/danielmiessler/fabric
// @license.name MIT
// @license.url https://opensource.org/licenses/MIT
// @host localhost:8080
// @BasePath /
// @securityDefinitions.apikey ApiKeyAuth
// @in header
// @name X-API-Key
func Serve(registry *core.PluginRegistry, address string, apiKey string) (err error) {
r := gin.New()
@@ -20,6 +39,32 @@ func Serve(registry *core.PluginRegistry, address string, apiKey string) (err er
slog.Warn("Starting REST API server without API key authentication. This may pose security risks.")
}
// Swagger UI and documentation endpoint with custom YAML handler
r.GET("/swagger/*any", func(c *gin.Context) {
// Check if request is for swagger.yaml
if c.Param("any") == "/swagger.yaml" {
// Try to find swagger.yaml relative to current directory or executable
yamlPath := "docs/swagger.yaml"
if _, err := os.Stat(yamlPath); os.IsNotExist(err) {
// Try relative to executable
if exePath, err := os.Executable(); err == nil {
yamlPath = filepath.Join(filepath.Dir(exePath), "docs", "swagger.yaml")
}
}
if _, err := os.Stat(yamlPath); err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "swagger.yaml not found - generate it with: swag init -g internal/server/serve.go -o docs"})
return
}
c.File(yamlPath)
return
}
// For all other swagger paths, use the default handler
ginSwagger.WrapHandler(swaggerFiles.Handler)(c)
})
// Register routes
fabricDb := registry.Db
NewPatternsHandler(r, fabricDb.Patterns)

View File

@@ -22,6 +22,9 @@ schema = 3
[mod."github.com/Azure/azure-sdk-for-go/sdk/internal"]
version = "v1.11.2"
hash = "sha256-O4Vo6D/fus3Qhs/Te644+jh2LfiG5PpiMkW0YWIbLCs="
[mod."github.com/KyleBanks/depth"]
version = "v1.2.1"
hash = "sha256-czR52MfeKA2FdStXCebTMQRKT8jaWQcbV214O3j49qU="
[mod."github.com/Microsoft/go-winio"]
version = "v0.6.2"
hash = "sha256-tVNWDUMILZbJvarcl/E7tpSnkn7urqgSHa2Eaka5vSU="
@@ -88,18 +91,21 @@ schema = 3
[mod."github.com/aws/smithy-go"]
version = "v1.23.0"
hash = "sha256-75k+gn1lbQB1TzjV3HeEJeuyPPfX2huKhONXo98SUKg="
[mod."github.com/bytedance/gopkg"]
version = "v0.1.3"
hash = "sha256-GyUbPfn41y/mgj0cQOa4tm+aj70C2K50VBZxZc/tcZE="
[mod."github.com/bytedance/sonic"]
version = "v1.13.3"
hash = "sha256-Nnt5b2NkIvSXhGERQmyI0ka28hbWi7A7Zn3dsAjPcEA="
version = "v1.14.2"
hash = "sha256-S6EGwzt3TaTUjU1SdtorTdAq3xwROzSGZT6ynfLNq8o="
[mod."github.com/bytedance/sonic/loader"]
version = "v0.2.4"
hash = "sha256-rv9LnePpm4OspSVbfSoVbohXzhu+dxE1BH1gm3mTmTc="
version = "v0.4.0"
hash = "sha256-Hc2bB9nLEFhyipIVHKnJmi6WMoWPCe0REK3bmQThO4A="
[mod."github.com/cloudflare/circl"]
version = "v1.6.1"
hash = "sha256-Dc69V12eIFnJoUNmwg6VKXHfAMijbAeEVSDe8AiOaLo="
[mod."github.com/cloudwego/base64x"]
version = "v0.1.5"
hash = "sha256-MyUYTveN48DhnL8mwAgCRuMExLct98uzSPsmYlfaa4I="
version = "v0.1.6"
hash = "sha256-VzYJsGubsDk3FAMH6e0Xk0Cl4HtUFHHmWkVASUYidsI="
[mod."github.com/coder/websocket"]
version = "v1.8.13"
hash = "sha256-NbF0aPhy8YR3jRM6LMMQTtkeGTFba0eIBPAUsqI9KOk="
@@ -116,14 +122,14 @@ schema = 3
version = "v1.0.4"
hash = "sha256-c1JKoRSndwwOyOxq9ddCe+8qn7mG9uRq2o/822x5O/c="
[mod."github.com/gabriel-vasile/mimetype"]
version = "v1.4.9"
hash = "sha256-75uELLqb01djHTe7KdXvUidBK7SuejarYouEUuxaj8Q="
version = "v1.4.12"
hash = "sha256-vY2g58yUrkT//8fttRKhS9rbg89YSae/BzOARS5uH30="
[mod."github.com/gin-contrib/sse"]
version = "v1.1.0"
hash = "sha256-2VP6zHEsPi0u2ZYpOTcLulwj1Gsmb6oA19qcP2/AzVM="
[mod."github.com/gin-gonic/gin"]
version = "v1.10.1"
hash = "sha256-D98+chAdjb6JcLPkscOr8TgTW87UqA4h3cnY0XIr16c="
version = "v1.11.0"
hash = "sha256-tFP0u7TZyB1V8b1mdnTWMrfdcwzf9yO86RZr026K8Ao="
[mod."github.com/go-git/gcfg"]
version = "v1.5.1-0.20230307220236-3a3c6141e376"
hash = "sha256-f4k0gSYuo0/q3WOoTxl2eFaj7WZpdz29ih6CKc8Ude8="
@@ -139,6 +145,36 @@ schema = 3
[mod."github.com/go-logr/stdr"]
version = "v1.2.2"
hash = "sha256-rRweAP7XIb4egtT1f2gkz4sYOu7LDHmcJ5iNsJUd0sE="
[mod."github.com/go-openapi/jsonpointer"]
version = "v0.22.4"
hash = "sha256-V76k+oQUyqkWcpa64bOirteoCfdn1Xm9TLH0/7W4Uxc="
[mod."github.com/go-openapi/jsonreference"]
version = "v0.21.4"
hash = "sha256-R+Q/MOSRTMiOaZutRmjv/qwbU9/cUWN59Hwr2LgDz2U="
[mod."github.com/go-openapi/spec"]
version = "v0.22.2"
hash = "sha256-o9A6ZVaVPUVP2ssO0I4CDTuGyRuhL/VCM28jU0l32ps="
[mod."github.com/go-openapi/swag/conv"]
version = "v0.25.4"
hash = "sha256-uHgTdZC76LMSsq+x+RyeclnOgBsS0ID2cLgfjzFk0KQ="
[mod."github.com/go-openapi/swag/jsonname"]
version = "v0.25.4"
hash = "sha256-Z6uETeudh8W+/SGxFBnOB/VlJeRPRkFgCyJmntpz7bc="
[mod."github.com/go-openapi/swag/jsonutils"]
version = "v0.25.4"
hash = "sha256-TQGeMImUuL5BWDoBHKAjZ1BvvxPXkFrV3TMgb82IrLk="
[mod."github.com/go-openapi/swag/loading"]
version = "v0.25.4"
hash = "sha256-xr8OnFqB/kwBj3yf9HiLJwDcpL7I3/qJYlKb6VWbVFA="
[mod."github.com/go-openapi/swag/stringutils"]
version = "v0.25.4"
hash = "sha256-rVo5NBH+oLLX9kaemUYWILd+TKw/TDTB8UdSz+mn3m8="
[mod."github.com/go-openapi/swag/typeutils"]
version = "v0.25.4"
hash = "sha256-59RHnK6ugsAUc+A8DZCj7gZ3bJnt01Al7T/1kzM9PpA="
[mod."github.com/go-openapi/swag/yamlutils"]
version = "v0.25.4"
hash = "sha256-zba7QX7Ds05oZq1opP/vwRSBEDaJ1pKm+9DgrsOuR9w="
[mod."github.com/go-playground/locales"]
version = "v0.14.1"
hash = "sha256-BMJGAexq96waZn60DJXZfByRHb8zA/JP/i6f/YrW9oQ="
@@ -146,8 +182,8 @@ schema = 3
version = "v0.18.1"
hash = "sha256-2/B2qP51zfiY+k8G0w0D03KXUc7XpWj6wKY7NjNP/9E="
[mod."github.com/go-playground/validator/v10"]
version = "v10.26.0"
hash = "sha256-/jMKICp8LTcJVt+b4YRTnJM84r7HK6aT0oqO7Q8SRs8="
version = "v10.29.0"
hash = "sha256-HFiWBwxNlzoyMlRwA92rAiEGjBy9Dz/ZUKSRp8pXB2Y="
[mod."github.com/go-shiori/dom"]
version = "v0.0.0-20230515143342-73569d674e1c"
hash = "sha256-4lm9KZfR2XnfZU9KTG+4jqLYZqbfL74AMO4y3dKpIbg="
@@ -157,6 +193,9 @@ schema = 3
[mod."github.com/goccy/go-json"]
version = "v0.10.5"
hash = "sha256-/EtlGihP0/7oInzMC5E0InZ4b5Ad3s4xOpqotloi3xw="
[mod."github.com/goccy/go-yaml"]
version = "v1.19.1"
hash = "sha256-zlT9y4wkvyv7RBv48jdJqOM2lrDMLrC6Z6hCl90c5hQ="
[mod."github.com/gogs/chardet"]
version = "v0.0.0-20211120154057-b7413eaefb8f"
hash = "sha256-4MeqBJsh4U+ZEbfdDwdciTYMlQWkCil2KJbUxHjBSIo="
@@ -212,8 +251,8 @@ schema = 3
version = "v1.2.0"
hash = "sha256-Ta7ZOmyX8gG5tzWbY2oES70EJPfI90U7CIJS9EAce0s="
[mod."github.com/klauspost/cpuid/v2"]
version = "v2.2.10"
hash = "sha256-o21Tk5sD7WhhLUoqSkymnjLbzxl0mDJCTC1ApfZJrC0="
version = "v2.3.0"
hash = "sha256-50JhbQyT67BK38HIdJihPtjV7orYp96HknI2VP7A9Yc="
[mod."github.com/leodido/go-urn"]
version = "v1.4.0"
hash = "sha256-Q6kplWkY37Tzy6GOme3Wut40jFK4Izun+ij/BJvcEu0="
@@ -256,6 +295,12 @@ schema = 3
[mod."github.com/pmezard/go-difflib"]
version = "v1.0.1-0.20181226105442-5d4384ee4fb2"
hash = "sha256-XA4Oj1gdmdV/F/+8kMI+DBxKPthZ768hbKsO3d9Gx90="
[mod."github.com/quic-go/qpack"]
version = "v0.6.0"
hash = "sha256-xaxHnTKIZt1cHK5ZqTuSTOt5RNSjQB37GlrIgEGBskM="
[mod."github.com/quic-go/quic-go"]
version = "v0.57.1"
hash = "sha256-MdXc0GRVp3YuN9XFoGFOjgIcIMp7yoLqwfEikZp1i4w="
[mod."github.com/samber/lo"]
version = "v1.50.0"
hash = "sha256-KDFks82BKu39sGt0f972IyOkohV2U0r1YvsnlNLdugY="
@@ -277,6 +322,15 @@ schema = 3
[mod."github.com/stretchr/testify"]
version = "v1.11.1"
hash = "sha256-sWfjkuKJyDllDEtnM8sb/pdLzPQmUYWYtmeWz/5suUc="
[mod."github.com/swaggo/files"]
version = "v1.0.1"
hash = "sha256-bNBmpJaM7g1BNwd7VxNIRSdY35NKSXhYHGfnZsSEUZ8="
[mod."github.com/swaggo/gin-swagger"]
version = "v1.6.1"
hash = "sha256-9TQuEmPpDO2QL0c9VwjK9uwB1jka08Ox6fje2RwVpUc="
[mod."github.com/swaggo/swag"]
version = "v1.16.6"
hash = "sha256-na5+ZylxPFKoMJcgx8nmSJXMMkKFCyuh1qSkb7Qth/I="
[mod."github.com/tidwall/gjson"]
version = "v1.18.0"
hash = "sha256-CO6hqDu8Y58Po6A01e5iTpwiUBQ5khUZsw7czaJHw0I="
@@ -293,8 +347,8 @@ schema = 3
version = "v0.15.1"
hash = "sha256-HLk6oUe7EoITrNvP0y8D6BtIgIcmDZYtb/xl/dufIoY="
[mod."github.com/ugorji/go/codec"]
version = "v1.2.14"
hash = "sha256-PoVXlCBE8SvMWpXx9FRsQOSAmE/+5SnPGr4m5BGoyIo="
version = "v1.3.1"
hash = "sha256-VQtXVaKxXjm5Q60hCgVKZxNywl6SJFPqju6JNjADp4w="
[mod."github.com/xanzy/ssh-agent"]
version = "v0.3.3"
hash = "sha256-l3pGB6IdzcPA/HLk93sSN6NM2pKPy+bVOoacR5RC2+c="
@@ -313,30 +367,42 @@ schema = 3
[mod."go.opentelemetry.io/otel/trace"]
version = "v1.36.0"
hash = "sha256-owWD9x1lp8aIJqYt058BXPUsIMHdk3RI0escso0BxwA="
[mod."go.uber.org/mock"]
version = "v0.6.0"
hash = "sha256-m11cxIbrvOowa6xj11AztzfFk86DwR6SNO1lStcKzvo="
[mod."go.yaml.in/yaml/v3"]
version = "v3.0.4"
hash = "sha256-NkGFiDPoCxbr3LFsI6OCygjjkY0rdmg5ggvVVwpyDQ4="
[mod."golang.org/x/arch"]
version = "v0.18.0"
hash = "sha256-tUpUPERjmRi7zldj0oPlnbnBhEkcI9iQGvP1HqlsK10="
version = "v0.23.0"
hash = "sha256-ynvhsw8ZYgKTzFn1wnIj3/p+1O/Ty5PX1Lnj+NMTAQQ="
[mod."golang.org/x/crypto"]
version = "v0.45.0"
hash = "sha256-IpNesJYxFcs2jGvagwJrUD/gsJfA3UiETjQwYByXxSY="
version = "v0.46.0"
hash = "sha256-I8N/spcw3/h0DFA+V1WK38HctckWIB9ep93DEVCALxU="
[mod."golang.org/x/exp"]
version = "v0.0.0-20250531010427-b6e5de432a8b"
hash = "sha256-QaFfjyB+pogCkUkJskR9xnXwkCOU828XJRrzwwLm6Ms="
[mod."golang.org/x/mod"]
version = "v0.31.0"
hash = "sha256-ZVNmaZADgM3+30q9rW8q4gP6ySkT7r1eb4vrHIlpCjM="
[mod."golang.org/x/net"]
version = "v0.47.0"
hash = "sha256-2qFgCd0YfNCGkLrf+xvnhQtKjSe8CymMdLlN3svUYTg="
version = "v0.48.0"
hash = "sha256-oZpddsiJwWCH3Aipa+XXpy7G/xHY5fEagUSok7T0bXE="
[mod."golang.org/x/oauth2"]
version = "v0.30.0"
hash = "sha256-btD7BUtQpOswusZY5qIU90uDo38buVrQ0tmmQ8qNHDg="
[mod."golang.org/x/sync"]
version = "v0.18.0"
hash = "sha256-S8o6y7GOaYWeq+TzT8BB6T+1mg82Mu08V0TL3ukJprg="
version = "v0.19.0"
hash = "sha256-RbRZ+sKZUurOczGhhzOoY/sojTlta3H9XjL4PXX/cno="
[mod."golang.org/x/sys"]
version = "v0.38.0"
hash = "sha256-1+i5EaG3JwH3KMtefzJLG5R6jbOeJM4GK3/LHBVnSy0="
version = "v0.39.0"
hash = "sha256-dxTBu/JAWUkPbjFIXXRFdhQWyn+YyEpIC+tWqGo0Y6U="
[mod."golang.org/x/text"]
version = "v0.31.0"
hash = "sha256-AT46RrSmV6+/d5FDhs9fPwYzmQ7WSo+YL9tPfhREwLw="
version = "v0.32.0"
hash = "sha256-9PXtWBKKY9rG4AgjSP4N+I1DhepXhy8SF/vWSIDIoWs="
[mod."golang.org/x/tools"]
version = "v0.40.0"
hash = "sha256-ksmhTnH9btXKiRbbE0KGh02nbeNqNBQKcfwvx9dE7t0="
[mod."google.golang.org/api"]
version = "v0.247.0"
hash = "sha256-UzTtydHmNqh1OXbxcN5qNKQxb5dV6h2Mo6DH4P219Ec="
@@ -353,8 +419,8 @@ schema = 3
version = "v1.74.2"
hash = "sha256-tvYMdfu/ZQZRPZNmnQI4CZpg46CM8+mD49hw0gFheGs="
[mod."google.golang.org/protobuf"]
version = "v1.36.7"
hash = "sha256-6xCU+t2AVPcscMKenVs4etGqutYGPDXCQ3DCD3PpTq4="
version = "v1.36.11"
hash = "sha256-7W+6jntfI/awWL3JP6yQedxqP5S9o3XvPgJ2XxxsIeE="
[mod."gopkg.in/warnings.v0"]
version = "v0.1.2"
hash = "sha256-ATVL9yEmgYbkJ1DkltDGRn/auGAjqGOfjQyBYyUo8s8="

View File

@@ -1 +1 @@
"1.4.348"
"1.4.351"

View File

@@ -18,7 +18,7 @@ FROM alpine:latest
LABEL org.opencontainers.image.description="A Docker image for running the Fabric CLI. See https://github.com/danielmiessler/Fabric/tree/main/scripts/docker for details."
RUN apk add --no-cache ca-certificates \
RUN apk add --no-cache ca-certificates yt-dlp \
&& mkdir -p /root/.config/fabric
COPY --from=builder /fabric /usr/local/bin/fabric