pluginstate

package
v0.8.0 Latest Latest
Warning

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

Go to latest
Published: May 11, 2026 License: Apache-2.0 Imports: 6 Imported by: 0

Documentation

Overview

Package pluginstate is a read-only view of Claude Code's installed-plugin index (`~/.claude/plugins/installed_plugins.json`). It exists so `aiwf doctor` can answer the question "is plugin X installed for this consumer's project scope?" without re-deriving the JSON shape at every call site.

The package is deliberately narrow: it loads the index, exposes a typed match function, and treats a missing file as an empty index (the M-070 spec's "Claude Code never run on this machine" case). Other fields on the on-disk JSON (installPath, version, installedAt, lastUpdated, gitCommitSha) are ignored — the matcher only needs scope and projectPath.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Index

type Index struct {
	Plugins map[string][]InstallEntry `json:"plugins"`
}

Index is the parsed shape of installed_plugins.json. The map key is `<name>@<marketplace>` (the same string a user types into `claude /plugin install`); the value is the list of scope entries recorded for that plugin.

func Load

func Load(home string) (*Index, error)

Load reads installed_plugins.json from `<home>/.claude/plugins/` and returns a typed view. A missing file is treated as an empty index (no error) — see package doc. Read errors and JSON parse errors are returned to the caller so a corrupted state does not silently degrade to "no plugins."

func (*Index) HasProjectScope

func (i *Index) HasProjectScope(plugin, projectRoot string) (bool, error)

HasProjectScope reports whether the index contains an installed entry for `plugin` (e.g. `aiwf-extensions@ai-workflow-rituals`) with scope `project` and a `projectPath` that resolves to the same absolute path as `projectRoot`.

Both paths are normalized via filepath.Abs before comparison so an already-absolute argument is a no-op and a relative argument resolves against the caller's current working directory. Exact string equality after normalization — no case folding, no symlink resolution. Per AC-2 of M-070.

User-scope installs are intentionally NOT considered a match: the kernel's recommendation surface is per-project ("the consumer declared this plugin in *this* repo's aiwf.yaml"), so a plugin installed only for the user must still warn until the operator installs it for the project too.

type InstallEntry

type InstallEntry struct {
	Scope       string `json:"scope"`
	ProjectPath string `json:"projectPath,omitempty"`
}

InstallEntry captures the scope-level fields the matcher consumes. Only Scope and ProjectPath are read; other fields on the on-disk JSON are silently dropped on unmarshal.

Scope is one of "project", "user". For "project" entries ProjectPath is the absolute path of the consumer repo the install is bound to; for "user" entries it is empty.

Jump to

Keyboard shortcuts

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