From dfea2cfda048a57d8c5c4c6906a9683f61b97b7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nikola=20Milojevi=C4=87?= Date: Tue, 25 Nov 2025 12:25:53 +0100 Subject: [PATCH 1/4] added restic plugin --- plugins/restic/credentials.go | 225 +++++++++++++++++++++++++++++ plugins/restic/credentials_test.go | 101 +++++++++++++ plugins/restic/plugin.go | 22 +++ plugins/restic/restic.go | 22 +++ 4 files changed, 370 insertions(+) create mode 100644 plugins/restic/credentials.go create mode 100644 plugins/restic/credentials_test.go create mode 100644 plugins/restic/plugin.go create mode 100644 plugins/restic/restic.go diff --git a/plugins/restic/credentials.go b/plugins/restic/credentials.go new file mode 100644 index 00000000..77887eb8 --- /dev/null +++ b/plugins/restic/credentials.go @@ -0,0 +1,225 @@ +package restic + +import ( + "github.com/1Password/shell-plugins/sdk" + "github.com/1Password/shell-plugins/sdk/importer" + "github.com/1Password/shell-plugins/sdk/provision" + "github.com/1Password/shell-plugins/sdk/schema" + "github.com/1Password/shell-plugins/sdk/schema/credname" + "github.com/1Password/shell-plugins/sdk/schema/fieldname" +) + +// Custom field names for restic-specific fields +const ( + AzureAccountName sdk.FieldName = "Azure Account Name" + AzureAccountKey sdk.FieldName = "Azure Account Key" + AzureAccountSAS sdk.FieldName = "Azure Account SAS" + B2AccountID sdk.FieldName = "B2 Account ID" + B2AccountKey sdk.FieldName = "B2 Account Key" + RESTUsername sdk.FieldName = "REST Username" + RESTPassword sdk.FieldName = "REST Password" + SessionToken sdk.FieldName = "Session Token" +) + +func Credentials() schema.CredentialType { + return schema.CredentialType{ + Name: credname.Credentials, + DocsURL: sdk.URL("https://restic.readthedocs.io/en/latest/040_backup.html"), + ManagementURL: nil, + Fields: []schema.CredentialField{ + // Core - Required + { + Name: fieldname.Password, + MarkdownDescription: "The password used to encrypt/decrypt the restic repository.", + Secret: true, + Composition: &schema.ValueComposition{ + Length: 32, + Charset: schema.Charset{ + Uppercase: true, + Lowercase: true, + Digits: true, + }, + }, + }, + // AWS S3 / Cloudflare R2 / MinIO - Optional + { + Name: fieldname.AccessKeyID, + MarkdownDescription: "The AWS Access Key ID for S3-compatible backends (AWS S3, Cloudflare R2, MinIO).", + Optional: true, + Composition: &schema.ValueComposition{ + Length: 20, + Prefix: "AKIA", + Charset: schema.Charset{ + Uppercase: true, + Digits: true, + }, + }, + }, + { + Name: fieldname.SecretAccessKey, + MarkdownDescription: "The AWS Secret Access Key for S3-compatible backends.", + Secret: true, + Optional: true, + Composition: &schema.ValueComposition{ + Length: 40, + Charset: schema.Charset{ + Uppercase: true, + Lowercase: true, + Digits: true, + }, + }, + }, + { + Name: SessionToken, + MarkdownDescription: "The AWS Session Token for temporary credentials.", + Secret: true, + Optional: true, + Composition: &schema.ValueComposition{ + Length: 64, + Charset: schema.Charset{ + Uppercase: true, + Lowercase: true, + Digits: true, + }, + }, + }, + // Azure Blob Storage - Optional + { + Name: AzureAccountName, + MarkdownDescription: "The Azure Storage account name.", + Optional: true, + Composition: &schema.ValueComposition{ + Length: 24, + Charset: schema.Charset{ + Lowercase: true, + Digits: true, + }, + }, + }, + { + Name: AzureAccountKey, + MarkdownDescription: "The Azure Storage account key.", + Secret: true, + Optional: true, + Composition: &schema.ValueComposition{ + Length: 88, + Charset: schema.Charset{ + Uppercase: true, + Lowercase: true, + Digits: true, + }, + }, + }, + { + Name: AzureAccountSAS, + MarkdownDescription: "The Azure Storage SAS token.", + Secret: true, + Optional: true, + Composition: &schema.ValueComposition{ + Length: 64, + Charset: schema.Charset{ + Uppercase: true, + Lowercase: true, + Digits: true, + }, + }, + }, + // Backblaze B2 - Optional + { + Name: B2AccountID, + MarkdownDescription: "The Backblaze B2 Account ID.", + Optional: true, + Composition: &schema.ValueComposition{ + Length: 12, + Charset: schema.Charset{ + Lowercase: true, + Digits: true, + }, + }, + }, + { + Name: B2AccountKey, + MarkdownDescription: "The Backblaze B2 Application Key.", + Secret: true, + Optional: true, + Composition: &schema.ValueComposition{ + Length: 31, + Charset: schema.Charset{ + Uppercase: true, + Lowercase: true, + Digits: true, + }, + }, + }, + // Google Cloud Storage - Optional + { + Name: fieldname.ProjectID, + MarkdownDescription: "The Google Cloud project ID.", + Optional: true, + Composition: &schema.ValueComposition{ + Length: 20, + Charset: schema.Charset{ + Lowercase: true, + Digits: true, + }, + }, + }, + { + Name: fieldname.Credentials, + MarkdownDescription: "The path to Google Cloud application credentials JSON file.", + Optional: true, + }, + // REST Server - Optional + { + Name: RESTUsername, + MarkdownDescription: "The username for REST server authentication.", + Optional: true, + Composition: &schema.ValueComposition{ + Length: 12, + Charset: schema.Charset{ + Lowercase: true, + Digits: true, + }, + }, + }, + { + Name: RESTPassword, + MarkdownDescription: "The password for REST server authentication.", + Secret: true, + Optional: true, + Composition: &schema.ValueComposition{ + Length: 24, + Charset: schema.Charset{ + Uppercase: true, + Lowercase: true, + Digits: true, + }, + }, + }, + }, + DefaultProvisioner: provision.EnvVars(defaultEnvVarMapping), + Importer: importer.TryEnvVarPair(defaultEnvVarMapping), + } +} + +var defaultEnvVarMapping = map[string]sdk.FieldName{ + // Core + "RESTIC_PASSWORD": fieldname.Password, + // AWS S3 / Cloudflare R2 / MinIO + "AWS_ACCESS_KEY_ID": fieldname.AccessKeyID, + "AWS_SECRET_ACCESS_KEY": fieldname.SecretAccessKey, + "AWS_SESSION_TOKEN": SessionToken, + // Azure + "AZURE_ACCOUNT_NAME": AzureAccountName, + "AZURE_ACCOUNT_KEY": AzureAccountKey, + "AZURE_ACCOUNT_SAS": AzureAccountSAS, + // Backblaze B2 + "B2_ACCOUNT_ID": B2AccountID, + "B2_ACCOUNT_KEY": B2AccountKey, + // Google Cloud + "GOOGLE_PROJECT_ID": fieldname.ProjectID, + "GOOGLE_APPLICATION_CREDENTIALS": fieldname.Credentials, + // REST Server + "RESTIC_REST_USERNAME": RESTUsername, + "RESTIC_REST_PASSWORD": RESTPassword, +} diff --git a/plugins/restic/credentials_test.go b/plugins/restic/credentials_test.go new file mode 100644 index 00000000..17e77985 --- /dev/null +++ b/plugins/restic/credentials_test.go @@ -0,0 +1,101 @@ +package restic + +import ( + "testing" + + "github.com/1Password/shell-plugins/sdk" + "github.com/1Password/shell-plugins/sdk/plugintest" + "github.com/1Password/shell-plugins/sdk/schema/fieldname" +) + +func TestCredentialsProvisioner(t *testing.T) { + plugintest.TestProvisioner(t, Credentials().DefaultProvisioner, map[string]plugintest.ProvisionCase{ + "default with AWS S3": { + ItemFields: map[sdk.FieldName]string{ + fieldname.Password: "mysecretpassword", + fieldname.AccessKeyID: "AKIAIOSFODNN7EXAMPLE", + fieldname.SecretAccessKey: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + }, + ExpectedOutput: sdk.ProvisionOutput{ + Environment: map[string]string{ + "RESTIC_PASSWORD": "mysecretpassword", + "AWS_ACCESS_KEY_ID": "AKIAIOSFODNN7EXAMPLE", + "AWS_SECRET_ACCESS_KEY": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + }, + }, + }, + "with Azure": { + ItemFields: map[sdk.FieldName]string{ + fieldname.Password: "mysecretpassword", + AzureAccountName: "myaccount", + AzureAccountKey: "myaccountkey", + }, + ExpectedOutput: sdk.ProvisionOutput{ + Environment: map[string]string{ + "RESTIC_PASSWORD": "mysecretpassword", + "AZURE_ACCOUNT_NAME": "myaccount", + "AZURE_ACCOUNT_KEY": "myaccountkey", + }, + }, + }, + "with B2": { + ItemFields: map[sdk.FieldName]string{ + fieldname.Password: "mysecretpassword", + B2AccountID: "myaccountid", + B2AccountKey: "myaccountkey", + }, + ExpectedOutput: sdk.ProvisionOutput{ + Environment: map[string]string{ + "RESTIC_PASSWORD": "mysecretpassword", + "B2_ACCOUNT_ID": "myaccountid", + "B2_ACCOUNT_KEY": "myaccountkey", + }, + }, + }, + "with REST server": { + ItemFields: map[sdk.FieldName]string{ + fieldname.Password: "mysecretpassword", + RESTUsername: "myuser", + RESTPassword: "myrestpassword", + }, + ExpectedOutput: sdk.ProvisionOutput{ + Environment: map[string]string{ + "RESTIC_PASSWORD": "mysecretpassword", + "RESTIC_REST_USERNAME": "myuser", + "RESTIC_REST_PASSWORD": "myrestpassword", + }, + }, + }, + "password only": { + ItemFields: map[sdk.FieldName]string{ + fieldname.Password: "mysecretpassword", + }, + ExpectedOutput: sdk.ProvisionOutput{ + Environment: map[string]string{ + "RESTIC_PASSWORD": "mysecretpassword", + }, + }, + }, + }) +} + +func TestCredentialsImporter(t *testing.T) { + plugintest.TestImporter(t, Credentials().Importer, map[string]plugintest.ImportCase{ + "environment": { + Environment: map[string]string{ + "RESTIC_PASSWORD": "mysecretpassword", + "AWS_ACCESS_KEY_ID": "AKIAIOSFODNN7EXAMPLE", + "AWS_SECRET_ACCESS_KEY": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + }, + ExpectedCandidates: []sdk.ImportCandidate{ + { + Fields: map[sdk.FieldName]string{ + fieldname.Password: "mysecretpassword", + fieldname.AccessKeyID: "AKIAIOSFODNN7EXAMPLE", + fieldname.SecretAccessKey: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + }, + }, + }, + }, + }) +} diff --git a/plugins/restic/plugin.go b/plugins/restic/plugin.go new file mode 100644 index 00000000..68f18071 --- /dev/null +++ b/plugins/restic/plugin.go @@ -0,0 +1,22 @@ +package restic + +import ( + "github.com/1Password/shell-plugins/sdk" + "github.com/1Password/shell-plugins/sdk/schema" +) + +func New() schema.Plugin { + return schema.Plugin{ + Name: "restic", + Platform: schema.PlatformInfo{ + Name: "Restic", + Homepage: sdk.URL("https://restic.net"), + }, + Credentials: []schema.CredentialType{ + Credentials(), + }, + Executables: []schema.Executable{ + ResticCLI(), + }, + } +} diff --git a/plugins/restic/restic.go b/plugins/restic/restic.go new file mode 100644 index 00000000..933757b9 --- /dev/null +++ b/plugins/restic/restic.go @@ -0,0 +1,22 @@ +package restic + +import ( + "github.com/1Password/shell-plugins/sdk" + "github.com/1Password/shell-plugins/sdk/needsauth" + "github.com/1Password/shell-plugins/sdk/schema" + "github.com/1Password/shell-plugins/sdk/schema/credname" +) + +func ResticCLI() schema.Executable { + return schema.Executable{ + Name: "Restic CLI", + Runs: []string{"restic"}, + DocsURL: sdk.URL("https://restic.readthedocs.io"), + NeedsAuth: needsauth.NotForHelpOrVersion(), + Uses: []schema.CredentialUsage{ + { + Name: credname.Credentials, + }, + }, + } +} From 1028a0b3d62c9b1ae0041fcc81a54606801f16b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nikola=20Milojevi=C4=87?= Date: Tue, 25 Nov 2025 12:45:24 +0100 Subject: [PATCH 2/4] add llm plugin --- .github/workflows/release.yml | 91 +++++++++++++++++++++++++++++++++ plugins/llm/credentials.go | 62 ++++++++++++++++++++++ plugins/llm/credentials_test.go | 64 +++++++++++++++++++++++ plugins/llm/llm.go | 22 ++++++++ plugins/llm/plugin.go | 22 ++++++++ 5 files changed, 261 insertions(+) create mode 100644 .github/workflows/release.yml create mode 100644 plugins/llm/credentials.go create mode 100644 plugins/llm/credentials_test.go create mode 100644 plugins/llm/llm.go create mode 100644 plugins/llm/plugin.go diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..23783eee --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,91 @@ +name: Build and Release Custom Plugins + +on: + push: + branches: + - main + paths: + - 'plugins/restic/**' + - 'plugins/llm/**' + - '.github/workflows/release.yml' + +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + plugin: [restic, llm] + goos: [linux, darwin] + goarch: [amd64, arm64] + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: '1.21' + + - name: Generate registry + run: go run cmd/contrib/main.go registry + + - name: Build plugin + env: + GOOS: ${{ matrix.goos }} + GOARCH: ${{ matrix.goarch }} + run: | + mkdir -p dist + go build -o dist/${{ matrix.plugin }}-${{ matrix.goos }}-${{ matrix.goarch }} \ + -ldflags="-X 'main.PluginName=${{ matrix.plugin }}'" \ + ./cmd/contrib/build/ + + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: ${{ matrix.plugin }}-${{ matrix.goos }}-${{ matrix.goarch }} + path: dist/${{ matrix.plugin }}-${{ matrix.goos }}-${{ matrix.goarch }} + + release: + needs: build + runs-on: ubuntu-latest + permissions: + contents: write + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Download all artifacts + uses: actions/download-artifact@v4 + with: + path: dist + merge-multiple: true + + - name: Generate release tag + id: tag + run: echo "tag=v$(date +'%Y%m%d.%H%M%S')" >> $GITHUB_OUTPUT + + - name: Create Release + uses: softprops/action-gh-release@v1 + with: + tag_name: ${{ steps.tag.outputs.tag }} + name: Custom Plugins ${{ steps.tag.outputs.tag }} + body: | + Custom 1Password shell plugins build. + + ## Included Plugins + - **restic** - Backup tool with support for S3, Azure, B2, GCS, and REST backends + - **llm** - Simon Willison's LLM CLI with OpenAI and OpenRouter support + + ## Installation + Download the appropriate binary for your platform and place it in `~/.config/op/plugins/local/` + + ```bash + mkdir -p ~/.config/op/plugins/local + chmod 700 ~/.config/op/plugins/local + # Download and rename to just the plugin name (e.g., 'restic' or 'llm') + ``` + files: dist/* + draft: false + prerelease: false diff --git a/plugins/llm/credentials.go b/plugins/llm/credentials.go new file mode 100644 index 00000000..738b7acc --- /dev/null +++ b/plugins/llm/credentials.go @@ -0,0 +1,62 @@ +package llm + +import ( + "github.com/1Password/shell-plugins/sdk" + "github.com/1Password/shell-plugins/sdk/importer" + "github.com/1Password/shell-plugins/sdk/provision" + "github.com/1Password/shell-plugins/sdk/schema" + "github.com/1Password/shell-plugins/sdk/schema/credname" +) + +// Custom field names for llm-specific fields +const ( + OpenAIAPIKey sdk.FieldName = "OpenAI API Key" + OpenRouterAPIKey sdk.FieldName = "OpenRouter API Key" +) + +func Credentials() schema.CredentialType { + return schema.CredentialType{ + Name: credname.Credentials, + DocsURL: sdk.URL("https://llm.datasette.io/en/stable/setup.html"), + ManagementURL: nil, + Fields: []schema.CredentialField{ + { + Name: OpenAIAPIKey, + MarkdownDescription: "The OpenAI API key used to authenticate to OpenAI models.", + Secret: true, + Optional: true, + Composition: &schema.ValueComposition{ + Length: 51, + Prefix: "sk-", + Charset: schema.Charset{ + Uppercase: true, + Lowercase: true, + Digits: true, + }, + }, + }, + { + Name: OpenRouterAPIKey, + MarkdownDescription: "The OpenRouter API key used to authenticate to OpenRouter models.", + Secret: true, + Optional: true, + Composition: &schema.ValueComposition{ + Length: 51, + Prefix: "sk-or-", + Charset: schema.Charset{ + Uppercase: true, + Lowercase: true, + Digits: true, + }, + }, + }, + }, + DefaultProvisioner: provision.EnvVars(defaultEnvVarMapping), + Importer: importer.TryEnvVarPair(defaultEnvVarMapping), + } +} + +var defaultEnvVarMapping = map[string]sdk.FieldName{ + "OPENAI_API_KEY": OpenAIAPIKey, + "OPENROUTER_API_KEY": OpenRouterAPIKey, +} diff --git a/plugins/llm/credentials_test.go b/plugins/llm/credentials_test.go new file mode 100644 index 00000000..c6f58c89 --- /dev/null +++ b/plugins/llm/credentials_test.go @@ -0,0 +1,64 @@ +package llm + +import ( + "testing" + + "github.com/1Password/shell-plugins/sdk" + "github.com/1Password/shell-plugins/sdk/plugintest" +) + +func TestCredentialsProvisioner(t *testing.T) { + plugintest.TestProvisioner(t, Credentials().DefaultProvisioner, map[string]plugintest.ProvisionCase{ + "with OpenAI": { + ItemFields: map[sdk.FieldName]string{ + OpenAIAPIKey: "sk-1234567890abcdefghijklmnopqrstuvwxyzEXAMPLEKEY", + }, + ExpectedOutput: sdk.ProvisionOutput{ + Environment: map[string]string{ + "OPENAI_API_KEY": "sk-1234567890abcdefghijklmnopqrstuvwxyzEXAMPLEKEY", + }, + }, + }, + "with OpenRouter": { + ItemFields: map[sdk.FieldName]string{ + OpenRouterAPIKey: "sk-or-1234567890abcdefghijklmnopqrstuvwxEXAMPLE", + }, + ExpectedOutput: sdk.ProvisionOutput{ + Environment: map[string]string{ + "OPENROUTER_API_KEY": "sk-or-1234567890abcdefghijklmnopqrstuvwxEXAMPLE", + }, + }, + }, + "with both": { + ItemFields: map[sdk.FieldName]string{ + OpenAIAPIKey: "sk-1234567890abcdefghijklmnopqrstuvwxyzEXAMPLEKEY", + OpenRouterAPIKey: "sk-or-1234567890abcdefghijklmnopqrstuvwxEXAMPLE", + }, + ExpectedOutput: sdk.ProvisionOutput{ + Environment: map[string]string{ + "OPENAI_API_KEY": "sk-1234567890abcdefghijklmnopqrstuvwxyzEXAMPLEKEY", + "OPENROUTER_API_KEY": "sk-or-1234567890abcdefghijklmnopqrstuvwxEXAMPLE", + }, + }, + }, + }) +} + +func TestCredentialsImporter(t *testing.T) { + plugintest.TestImporter(t, Credentials().Importer, map[string]plugintest.ImportCase{ + "environment": { + Environment: map[string]string{ + "OPENAI_API_KEY": "sk-1234567890abcdefghijklmnopqrstuvwxyzEXAMPLEKEY", + "OPENROUTER_API_KEY": "sk-or-1234567890abcdefghijklmnopqrstuvwxEXAMPLE", + }, + ExpectedCandidates: []sdk.ImportCandidate{ + { + Fields: map[sdk.FieldName]string{ + OpenAIAPIKey: "sk-1234567890abcdefghijklmnopqrstuvwxyzEXAMPLEKEY", + OpenRouterAPIKey: "sk-or-1234567890abcdefghijklmnopqrstuvwxEXAMPLE", + }, + }, + }, + }, + }) +} diff --git a/plugins/llm/llm.go b/plugins/llm/llm.go new file mode 100644 index 00000000..26154930 --- /dev/null +++ b/plugins/llm/llm.go @@ -0,0 +1,22 @@ +package llm + +import ( + "github.com/1Password/shell-plugins/sdk" + "github.com/1Password/shell-plugins/sdk/needsauth" + "github.com/1Password/shell-plugins/sdk/schema" + "github.com/1Password/shell-plugins/sdk/schema/credname" +) + +func LLMCLI() schema.Executable { + return schema.Executable{ + Name: "LLM CLI", + Runs: []string{"llm"}, + DocsURL: sdk.URL("https://llm.datasette.io/en/stable/"), + NeedsAuth: needsauth.NotForHelpOrVersion(), + Uses: []schema.CredentialUsage{ + { + Name: credname.Credentials, + }, + }, + } +} diff --git a/plugins/llm/plugin.go b/plugins/llm/plugin.go new file mode 100644 index 00000000..b38eb2fb --- /dev/null +++ b/plugins/llm/plugin.go @@ -0,0 +1,22 @@ +package llm + +import ( + "github.com/1Password/shell-plugins/sdk" + "github.com/1Password/shell-plugins/sdk/schema" +) + +func New() schema.Plugin { + return schema.Plugin{ + Name: "llm", + Platform: schema.PlatformInfo{ + Name: "LLM", + Homepage: sdk.URL("https://llm.datasette.io"), + }, + Credentials: []schema.CredentialType{ + Credentials(), + }, + Executables: []schema.Executable{ + LLMCLI(), + }, + } +} From 7f29615ef4f336061f0adfcdc18c09d542b11c5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nikola=20Milojevi=C4=87?= Date: Tue, 25 Nov 2025 12:47:41 +0100 Subject: [PATCH 3/4] try new release --- .github/workflows/release.yml | 36 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 23783eee..1f51b3d3 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -67,25 +67,23 @@ jobs: run: echo "tag=v$(date +'%Y%m%d.%H%M%S')" >> $GITHUB_OUTPUT - name: Create Release - uses: softprops/action-gh-release@v1 - with: - tag_name: ${{ steps.tag.outputs.tag }} - name: Custom Plugins ${{ steps.tag.outputs.tag }} - body: | - Custom 1Password shell plugins build. + env: + GH_TOKEN: ${{ github.token }} + run: | + gh release create ${{ steps.tag.outputs.tag }} \ + --title "Custom Plugins ${{ steps.tag.outputs.tag }}" \ + --notes "Custom 1Password shell plugins build. - ## Included Plugins - - **restic** - Backup tool with support for S3, Azure, B2, GCS, and REST backends - - **llm** - Simon Willison's LLM CLI with OpenAI and OpenRouter support + ## Included Plugins + - **restic** - Backup tool with support for S3, Azure, B2, GCS, and REST backends + - **llm** - Simon Willison's LLM CLI with OpenAI and OpenRouter support - ## Installation - Download the appropriate binary for your platform and place it in `~/.config/op/plugins/local/` + ## Installation + Download the appropriate binary for your platform and place it in \`~/.config/op/plugins/local/\` - ```bash - mkdir -p ~/.config/op/plugins/local - chmod 700 ~/.config/op/plugins/local - # Download and rename to just the plugin name (e.g., 'restic' or 'llm') - ``` - files: dist/* - draft: false - prerelease: false + \`\`\`bash + mkdir -p ~/.config/op/plugins/local + chmod 700 ~/.config/op/plugins/local + # Download and rename to just the plugin name (e.g., 'restic' or 'llm') + \`\`\`" \ + dist/* From bddb47d999876b340900cd3f6b4388e9eb02b250 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nikola=20Milojevi=C4=87?= <9573356+nklmilojevic@users.noreply.github.com> Date: Tue, 25 Nov 2025 13:16:47 +0100 Subject: [PATCH 4/4] Update release.yml --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1f51b3d3..da0a80c0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -68,7 +68,7 @@ jobs: - name: Create Release env: - GH_TOKEN: ${{ github.token }} + GITHUB_TOKEN: ${{ github.token }} run: | gh release create ${{ steps.tag.outputs.tag }} \ --title "Custom Plugins ${{ steps.tag.outputs.tag }}" \