plugins

package
v0.0.0-...-7bc539a Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 14, 2026 License: AGPL-3.0 Imports: 48 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ClaudeObservabilityHookEvents = []string{
	"PreToolUse",
	"PostToolUse",
	"PostToolUseFailure",
	"SessionStart",
	"SessionEnd",
	"UserPromptSubmit",
	"Stop",
	"Notification",
}

ClaudeObservabilityHookEvents are the Claude Code hook events the observability plugin registers against. Names match Claude's hooks.json schema. Claude only invokes hook.sh for events listed here, so any event the Claude() handler in server/internal/hooks/claude_hooks.go expects to record must appear in this list — otherwise it is silently dropped on the client side.

View Source
var CodexObservabilityHookEvents = []string{
	"SessionStart",
	"PreToolUse",
	"PermissionRequest",
	"PostToolUse",
	"UserPromptSubmit",
	"Stop",
}

CodexObservabilityHookEvents are Codex's hook event names. Codex uses PascalCase names and has a PermissionRequest event that Claude/Cursor lack.

View Source
var CursorObservabilityHookEvents = []string{
	"beforeSubmitPrompt",
	"stop",
	"afterAgentResponse",
	"afterAgentThought",
	"preToolUse",
	"postToolUse",
	"postToolUseFailure",
	"beforeMCPExecution",
	"afterMCPExecution",
}

CursorObservabilityHookEvents are Cursor's native hook event names (per server/design/hooks/design.go:58). Cursor uses different event names than Claude, not a lowercased mirror, so the two lists are maintained separately.

Functions

func Attach

func Attach(mux goahttp.Muxer, service *Service)

func ClaudeObservabilitySlug

func ClaudeObservabilitySlug(cfg GenerateConfig) string

ClaudeObservabilitySlug / CursorObservabilitySlug derive the observability plugin's directory name and marketplace identifier from the org slug. Namespacing per-org avoids collisions with user plugins that legitimately use slug "observability". Exported because tests need to predict the published path.

func CodexObservabilitySlug

func CodexObservabilitySlug(cfg GenerateConfig) string

func CursorObservabilitySlug

func CursorObservabilitySlug(cfg GenerateConfig) string

func GenerateCodexInstallScript

func GenerateCodexInstallScript(marketplaceURL string, cfg GenerateConfig) ([]byte, error)

GenerateCodexInstallScript produces a bash install script that:

  • Registers the Gram marketplace with the Codex CLI
  • Patches ~/.codex/config.toml with feature flags and plugin entry
  • Pre-approves all hook events so users skip the manual Settings → Hooks step

When marketplaceURL is empty the script uses the directory it was run from as the marketplace source (suitable for the ZIP-bundled install.sh). When marketplaceURL is non-empty the script registers the remote URL instead.

func GenerateObservabilityPluginPackage

func GenerateObservabilityPluginPackage(cfg GenerateConfig, platform string) (map[string][]byte, error)

GenerateObservabilityPluginPackage produces the file map for a single observability plugin for direct ZIP installation (no <org>-observability/ subdir). Minting a fresh hooks key is the caller's responsibility — this just renders files using cfg.HooksAPIKey.

func GeneratePluginPackages

func GeneratePluginPackages(plugins []PluginInfo, cfg GenerateConfig) (map[string][]byte, error)

GeneratePluginPackages produces the complete file map for a plugin distribution repository containing Claude Code, Cursor, and Codex plugins. Used for GitHub push.

func GenerateSinglePluginPackage

func GenerateSinglePluginPackage(plugin PluginInfo, cfg GenerateConfig, platform string) (map[string][]byte, error)

GenerateSinglePluginPackage produces files for a single plugin with files at the root level (no subdirectory prefix). Used for per-plugin ZIP downloads that can be installed directly via `claude --plugin-dir`.

Types

type GenerateConfig

type GenerateConfig struct {
	OrgName  string
	OrgEmail string
	// Base server URL (e.g. https://app.getgram.ai).
	ServerURL string
	// APIKey is the plaintext consumer-scoped Gram API key to inject into
	// MCP server configs. If empty, configs will use placeholder variables.
	APIKey string
	// HooksAPIKey is the plaintext hooks-scoped Gram API key embedded in the
	// observability plugin's hook script. If empty, the observability plugin
	// is omitted.
	HooksAPIKey string
	// ProjectSlug is the publishing project's slug. The Cursor hooks endpoint
	// requires it via the Gram-Project header (Claude's does not).
	ProjectSlug string
	// Version is stamped into every plugin.json. Callers should bump this on
	// every publish so platform marketplaces (Claude Code, Cursor, Codex) treat
	// the manifest as new and refresh installed copies. Empty falls back to
	// the static default, preserving test ergonomics.
	Version string
}

GenerateConfig holds org-level configuration for package generation.

type GitHubConfig

type GitHubConfig struct {
	Client         GitHubPublisher
	Org            string
	InstallationID int64
}

GitHubConfig holds the configured GitHub client and the Gram-owned org where plugin repos are created. Nil means GitHub publishing is disabled.

func NewGitHubConfig

func NewGitHubConfig(in GitHubConfigInput) (*GitHubConfig, error)

NewGitHubConfig validates a GitHubConfigInput holistically and returns:

  • (nil, nil) when no fields are set: feature is disabled
  • (config, nil) when all fields are set: feature is enabled
  • (nil, error) when only some fields are set: deployment is misconfigured

The all-or-nothing check prevents the silent-disable footgun where setting two of three inputs (e.g. forgetting GRAM_PLUGINS_GITHUB_ORG) leaves the deployment running with publishing inexplicably off.

type GitHubConfigInput

type GitHubConfigInput struct {
	Client         *ghclient.Client
	Org            string
	InstallationID int64
}

GitHubConfigInput is the deployment-time configuration for plugin GitHub publishing. All fields must be set together (the feature is on) or all must be unset (the feature is off). Pass to NewGitHubConfig.

Client is constructed by the caller (typically once in cmd/gram, then shared with other consumers like the marketplace proxy that need to mint installation tokens against the same App).

type GitHubPublisher

type GitHubPublisher interface {
	CreateRepo(ctx context.Context, installationID int64, org, name string, private bool) error
	PushFiles(ctx context.Context, installationID int64, owner, repo, branch, commitMsg string, files map[string][]byte) (string, error)
	AddCollaborator(ctx context.Context, installationID int64, owner, repo, username, permission string) error
}

GitHubPublisher is the interface for creating repos and pushing files to GitHub.

type PluginInfo

type PluginInfo struct {
	Name        string
	Slug        string
	Description string
	Servers     []PluginServerInfo
}

PluginInfo contains the data needed to generate packages for a single plugin.

type PluginServerInfo

type PluginServerInfo struct {
	DisplayName string
	Policy      string
	// Resolved MCP URL (e.g. https://app.getgram.ai/mcp/{slug}).
	MCPURL string
	// IsPublic indicates whether the toolset is publicly accessible (no Gram API key needed).
	IsPublic bool
	// EnvConfigs are user-facing environment variables for public servers.
	EnvConfigs []ServerEnvConfig
}

PluginServerInfo contains the resolved information for a single MCP server.

type ServerEnvConfig

type ServerEnvConfig struct {
	VariableName string
	DisplayName  string // Shown to the user in Claude's userConfig prompt
}

ServerEnvConfig represents a user-facing environment variable required by a server.

type Service

type Service struct {
	// contains filtered or unexported fields
}

func NewService

func NewService(
	logger *slog.Logger,
	tracerProvider trace.TracerProvider,
	db *pgxpool.Pool,
	sessions *sessions.Manager,
	authzEngine *authz.Engine,
	auditLogger *audit.Logger,
	github *GitHubConfig,
	env string,
	serverURL string,
) *Service

func (*Service) APIKeyAuth

func (s *Service) APIKeyAuth(ctx context.Context, key string, schema *security.APIKeyScheme) (context.Context, error)

func (*Service) AddPluginServer

func (s *Service) AddPluginServer(ctx context.Context, payload *gen.AddPluginServerPayload) (*gen.PluginServer, error)

func (*Service) CreatePlugin

func (s *Service) CreatePlugin(ctx context.Context, payload *gen.CreatePluginPayload) (*gen.Plugin, error)

func (*Service) DeletePlugin

func (s *Service) DeletePlugin(ctx context.Context, payload *gen.DeletePluginPayload) error

func (*Service) DownloadObservabilityPlugin

DownloadObservabilityPlugin returns a ZIP of the per-org observability plugin for direct installation. Mints a fresh hooks-scoped API key per download and embeds it in the script — the org's API Keys page will accumulate one row per download, which admins can audit and revoke independently of the publish-bundled key. The plugin contents are otherwise identical to what PublishPlugins ships in the GitHub marketplace.

func (*Service) GetPlugin

func (s *Service) GetPlugin(ctx context.Context, payload *gen.GetPluginPayload) (*gen.Plugin, error)

func (*Service) GetPublishStatus

func (s *Service) GetPublishStatus(ctx context.Context, payload *gen.GetPublishStatusPayload) (*gen.PublishStatusResult, error)

func (*Service) ListPlugins

func (s *Service) ListPlugins(ctx context.Context, payload *gen.ListPluginsPayload) (*gen.ListPluginsResult, error)

func (*Service) PublishPlugins

func (s *Service) PublishPlugins(ctx context.Context, payload *gen.PublishPluginsPayload) (*gen.PublishPluginsResult, error)

func (*Service) RemovePluginServer

func (s *Service) RemovePluginServer(ctx context.Context, payload *gen.RemovePluginServerPayload) error

func (*Service) SetPluginAssignments

func (s *Service) SetPluginAssignments(ctx context.Context, payload *gen.SetPluginAssignmentsPayload) (*gen.SetPluginAssignmentsResult, error)

func (*Service) UpdatePlugin

func (s *Service) UpdatePlugin(ctx context.Context, payload *gen.UpdatePluginPayload) (*gen.Plugin, error)

func (*Service) UpdatePluginServer

func (s *Service) UpdatePluginServer(ctx context.Context, payload *gen.UpdatePluginServerPayload) (*gen.PluginServer, error)

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL