Documentation
¶
Index ¶
- Constants
- Variables
- func CanonicalBucketPath(bucket CanonicalBucket, parts ...string) string
- func CanonicalBucketRoot(agentsHome string, bucket CanonicalBucket) string
- func CanonicalBucketScopePath(bucket CanonicalBucket, scope string, parts ...string) string
- func CanonicalBucketScopeRoot(agentsHome string, bucket CanonicalBucket, scope string) string
- func CollectAndExecuteSharedTargetPlan(project, repoPath string, platforms []Platform) error
- func DryRunSharedTargetPlanLines(project, repoPath string, platforms []Platform) ([]string, error)
- func EnsureUnderMCPScopeTree(agentsHome, scope, target string) error
- func EnsureUnderRulesScopeTree(agentsHome, scope, target string) error
- func EnsureUnderSettingsScopeTree(agentsHome, scope, target string) error
- func ExecuteSharedSkillMirrorPlan(project, repoPath string, targetRoots ...string) error
- func HasMultipleHardLinks(path string) bool
- func ListScopedResourceDirsForBucket(agentsHome string, bucket CanonicalBucket, scope, marker string) ([]resourceDir, error)
- func RemoveSharedTargetPlan(project, repoPath string, platforms []Platform) error
- func ResolveHookCommand(spec HookSpec) string
- func RunSharedTargetProjection(project, repoPath string, platforms []Platform, dryRun bool) ([]string, error)
- func RunSharedTargetProjectionExact(project, repoPath string, platforms []Platform, dryRun, exact bool) ([]string, error)
- func SortedUniqueStrings(values []string) []string
- type AuditPrinter
- type BranchSessionFinder
- type BranchSessionInfo
- type BrokenLink
- type BrokenLinkReporter
- type CanonicalBucket
- type CanonicalBucketSpec
- type CommitAttribution
- type DailyUsage
- type HookEmissionMode
- type HookPlatformOverride
- type HookShape
- type HookSourceKind
- type HookSpec
- type HookTransport
- type LinkCounter
- type MCPFileSpec
- type ModelTokenUsage
- type OrphanCanonical
- type OrphanCanonicalReporter
- type Platform
- func All() []Platform
- func ByID(id string) Platform
- func Filter(all []Platform, agentFilter string) []Platform
- func InstalledEnabledPlatforms(cfg *config.Config) []Platform
- func NewClaude() Platform
- func NewCodex() Platform
- func NewCopilot() Platform
- func NewCursor() Platform
- func NewOpenCode() Platform
- type PlatformBadge
- type PlatformUsageStats
- type PluginKind
- type PluginMarketplace
- type PluginResources
- type PluginSpec
- type ResourceIntent
- func BuildSharedAgentFileSymlinkIntents(project, targetRoot, destFileSuffix string) ([]ResourceIntent, error)
- func BuildSharedAgentMirrorIntents(project string, targetRoots ...string) ([]ResourceIntent, error)
- func BuildSharedCodexAgentTomlIntents(project string) ([]ResourceIntent, error)
- func BuildSharedPluginBundleIntents(project string, targetRoots ...string) ([]ResourceIntent, error)
- func BuildSharedSkillMirrorIntents(project string, targetRoots ...string) ([]ResourceIntent, error)
- type ResourceOwnership
- type ResourcePlan
- type ResourceProvenance
- type ResourcePrunePolicy
- type ResourceReplacePolicy
- type ResourceShape
- type ResourceSourceKind
- type ResourceSourceRef
- type ResourceTransport
- type RuleFileSpec
- type SessionReader
- type SessionSummary
- type SessionTokenMetrics
- type SessionTokenScanner
- type SettingsFileSpec
- type SingleFileLinkSpec
- type StatsReader
- type StatusBadger
- type UserConfigReporter
Constants ¶
const PluginManifestName = "PLUGIN.yaml"
Variables ¶
var BackupBeforeOverwrite = func(dst string) error { return sidecarBackup(stdPlatformIO{}, dst) }
BackupBeforeOverwrite preserves an existing managed-file destination before writeManagedFile replaces it with freshly rendered content. The default writes a sibling <dst>.dot-agents-backup (the existing repo backup convention, headless-safe, no layering inversion). The future config-distribution / lock-file model can wire a richer mirror-backup adapter through this seam without touching internal/platform.
This is a deliberate forward-compat extension point (NOT a test seam) — see the docstring above. Tests swap it via the legacy func-var pattern because that pattern matches its intended runtime-swap contract; the seam-interface-di-migration plan does not target this var.
var PluginManifestSchema = schemas.Plugin
PluginManifestSchema is the embedded compiled schema for PLUGIN.yaml.
Functions ¶
func CanonicalBucketPath ¶
func CanonicalBucketPath(bucket CanonicalBucket, parts ...string) string
CanonicalBucketPath returns a slash-normalized canonical registry key (not a filesystem path). Keys are stored and compared in POSIX form on every OS, so the join is forced to forward slashes.
func CanonicalBucketRoot ¶
func CanonicalBucketRoot(agentsHome string, bucket CanonicalBucket) string
func CanonicalBucketScopePath ¶
func CanonicalBucketScopePath(bucket CanonicalBucket, scope string, parts ...string) string
CanonicalBucketScopePath returns a slash-normalized canonical registry key (not a filesystem path). See CanonicalBucketPath.
func CanonicalBucketScopeRoot ¶
func CanonicalBucketScopeRoot(agentsHome string, bucket CanonicalBucket, scope string) string
func CollectAndExecuteSharedTargetPlan ¶
CollectAndExecuteSharedTargetPlan runs BuildSharedTargetPlan then executes it against the repo and agents home. This is the command-layer entry point for centralized shared-target writes.
func DryRunSharedTargetPlanLines ¶
DryRunSharedTargetPlanLines describes what CollectAndExecuteSharedTargetPlan would write (merged shared-target rows, duplicate-intent counts) without touching the filesystem.
func EnsureUnderMCPScopeTree ¶
EnsureUnderMCPScopeTree checks that target is under agentsHome/mcp/scope.
func EnsureUnderRulesScopeTree ¶
EnsureUnderRulesScopeTree checks that target is under agentsHome/rules/scope (after clean).
func EnsureUnderSettingsScopeTree ¶
EnsureUnderSettingsScopeTree checks that target is under agentsHome/settings/scope.
func HasMultipleHardLinks ¶
HasMultipleHardLinks is the exported entry point that the commands/internal/lifecycle HasMultipleHardLinks func-var seam now delegates to. Exported (not package-private) because lifecycle's backup.go and status.go need to read it across the package boundary, and because backup_test.go overrides the lifecycle-side seam directly — both callers are within the dot-agents binary so the surface stays internal.
func ListScopedResourceDirsForBucket ¶
func ListScopedResourceDirsForBucket(agentsHome string, bucket CanonicalBucket, scope, marker string) ([]resourceDir, error)
func RemoveSharedTargetPlan ¶
RemoveSharedTargetPlan removes repo-local shared targets implied by the merged plan for the given platforms (same aggregation as CollectAndExecuteSharedTargetPlan). Symlinks are removed only when they point into agentsHome; rendered files are removed for known materializers (e.g. codex-agent-toml).
func ResolveHookCommand ¶
ResolveHookCommand returns the hook command with relative paths resolved against the HOOK.yaml location.
func RunSharedTargetProjection ¶
func RunSharedTargetProjection(project, repoPath string, platforms []Platform, dryRun bool) ([]string, error)
RunSharedTargetProjection is the command-layer entry point for shared-target projection: it builds the merged ResourcePlan (BuildSharedTargetPlan) and either returns dry-run preview lines or executes writes. This keeps refresh/install/add on one code path for "build intents → plan → dry-run or apply".
Callers must set config.SetWindowsMirrorContext(repoPath) before calling when the repo needs Windows-specific path behavior for intent resolution.
func RunSharedTargetProjectionExact ¶ added in v0.4.0
func RunSharedTargetProjectionExact(project, repoPath string, platforms []Platform, dryRun, exact bool) ([]string, error)
RunSharedTargetProjectionExact is the EXACT/PRUNE command-layer entry point (config-v2-coherence §7A.5 / D10 "outputs half"): it projects the resolved asset-store union AND prunes managed outputs that are no longer in the resolved set, so the repo tree converges to exactly what the plan declares. It is the projection refresh/install drive by default; pass exact=false (`--inexact`) to keep the additive RunSharedTargetProjection behavior (write the wanted set, leave stale managed outputs in place).
Dry-run returns the same preview lines as RunSharedTargetProjection plus a "prune" line for every managed output the apply path would delete, so the preview is a faithful diff of the exact projection. Apply executes the plan then prunes; prune is best-effort relative to the write — a prune failure is returned so the caller can withhold a clean-success stamp.
Callers must set config.SetWindowsMirrorContext(repoPath) before calling when the repo needs Windows-specific path behavior for intent resolution.
func SortedUniqueStrings ¶
SortedUniqueStrings trims whitespace, drops empties + duplicates, and returns values sorted. Exported so commands/import_plugins.go can share the implementation instead of duplicating it.
Types ¶
type AuditPrinter ¶
AuditPrinter is implemented by platforms that render the per-platform audit block shown by `da status --audit`. Resolved in Phase 5 (Q2): the printer takes an io.Writer rather than a *ui.Sink — the platform layer only needs the ANSI colour constants from internal/ui (plain strings), so io.Writer keeps the dependency surface minimal while the lifecycle layer supplies os.Stdout at the call site.
type BranchSessionFinder ¶
type BranchSessionFinder interface {
FindSessionsOnBranch(home, projectPath, branch string, maxResults int) []BranchSessionInfo
}
BranchSessionFinder is implemented by platforms that embed git branch metadata in their session files, allowing orient to surface recent sessions on the current branch.
type BranchSessionInfo ¶
BranchSessionInfo holds brief info about a session that was active on a specific git branch. Used by BranchSessionFinder.
type BrokenLink ¶
type BrokenLink struct {
// PlatformID identifies which platform owns this link (e.g. "cursor").
PlatformID string
// LinkPath is the display-friendly path to the broken link — typically
// repo-relative for project links or home-relative for user-config links.
LinkPath string
// Dest is the raw target string returned by the OS (os.Readlink output
// for symlinks/junctions; empty for hard links whose canonical source
// could not be matched).
Dest string
// DisplayDest is Dest after path resolution and ~/-prefix formatting,
// suitable for direct rendering by doctor/status.
DisplayDest string
}
BrokenLink describes a single managed link that exists but does not resolve to the expected canonical source. PlatformID is intentionally carried on the value so JSON reports can self-describe per-entry (Q1 in the proposal — kept).
func ScanSingleFileLinks ¶
func ScanSingleFileLinks(specs []SingleFileLinkSpec) []BrokenLink
ScanSingleFileLinks evaluates each spec and returns a BrokenLink for every entry that exists at LinkPath but does not satisfy any CanonicalPaths match. The rules mirror what cursor + the single-file managed paths in doctor.go already encode:
- If LinkPath does not exist on disk, nothing is reported — an absent link is "not present" rather than "broken".
- If LinkPath is hard-linked to ANY of CanonicalPaths, it is healthy and nothing is reported.
- If LinkPath is a resolvable managed link (POSIX symlink / Windows junction) and its target is missing, it is reported broken with the raw target in Dest.
- If LinkPath is a resolvable managed link and its target exists but does not match any canonical (mis-pointed), it is also reported broken — the canonical contract is "link matches a known source", not "link resolves to anything".
Note that platforms supply the PlatformID at the call site by post- processing the returned slice (this keeps the helper platform-agnostic and avoids threading platform identity through every spec).
func ScanSymlinkDir ¶
func ScanSymlinkDir(dir string) (ok, broken int, brokenLinks []BrokenLink)
ScanSymlinkDir reads dir and classifies each entry as healthy or broken via the managed-link semantics used by status/doctor today. Returns the healthy count, the broken count, and the broken entries with raw + display target populated. Hidden files and subdirectories are skipped (the existing per-platform dirs are flat — rules/, agents/, skills/, agent/).
dir may not exist; in that case (0, 0, nil) is returned without error — "absent dir" is "not present" rather than "broken", matching the existing doctor/status behavior. Symlinks to directories (which on Windows show up as junctions and on POSIX as plain symlinks) are classified using managedLinkBroken so their broken state is reported even though they are not files.
type BrokenLinkReporter ¶
type BrokenLinkReporter interface {
BrokenLinks(project, repoPath, agentsHome string) []BrokenLink
}
BrokenLinkReporter is implemented by platforms that can enumerate their own broken project-scope links. Consumer: doctor.collectBrokenLinks.
type CanonicalBucket ¶
type CanonicalBucket string
const ( CanonicalBucketRules CanonicalBucket = "rules" CanonicalBucketSettings CanonicalBucket = "settings" CanonicalBucketMCP CanonicalBucket = "mcp" CanonicalBucketSkills CanonicalBucket = "skills" CanonicalBucketAgents CanonicalBucket = "agents" CanonicalBucketHooks CanonicalBucket = "hooks" CanonicalBucketCommands CanonicalBucket = "commands" CanonicalBucketOutputStyles CanonicalBucket = "output-styles" CanonicalBucketIgnore CanonicalBucket = "ignore" CanonicalBucketModes CanonicalBucket = "modes" CanonicalBucketPlugins CanonicalBucket = "plugins" CanonicalBucketThemes CanonicalBucket = "themes" CanonicalBucketPrompts CanonicalBucket = "prompts" )
type CanonicalBucketSpec ¶
type CanonicalBucketSpec struct {
Name CanonicalBucket
Stage int
CountDirs bool
MarkerFile string
Description string
}
func CanonicalStoreBucketSpecs ¶
func CanonicalStoreBucketSpecs() []CanonicalBucketSpec
func CanonicalStoreStage1BucketSpecs ¶
func CanonicalStoreStage1BucketSpecs() []CanonicalBucketSpec
func CanonicalStoreStage2BucketSpecs ¶
func CanonicalStoreStage2BucketSpecs() []CanonicalBucketSpec
type CommitAttribution ¶
type CommitAttribution struct {
CommitHash string
BranchName string
ScoredAt string
LinesAdded int
LinesDeleted int
ComposerLinesAdded int
ComposerLinesDeleted int
HumanLinesAdded int
V2AIPercentage float64
}
CommitAttribution holds AI vs human code attribution for a single commit. Sourced from Cursor's scored_commits table.
type DailyUsage ¶
DailyUsage holds activity counts for a single day.
type HookEmissionMode ¶
type HookEmissionMode struct {
Shape HookShape
Transport HookTransport
}
type HookPlatformOverride ¶
type HookSourceKind ¶
type HookSourceKind string
const ( HookSourceLegacyFile HookSourceKind = "legacy_file" HookSourceCanonicalBundle HookSourceKind = "canonical_bundle" )
type HookSpec ¶
type HookSpec struct {
Name string
Scope string
SourcePath string
SourceBucket string
SourceKind HookSourceKind
Description string
When string
// WhenEvents, when non-empty, declares a multi-event hook. The
// loader rejects manifests that set both `when` and `when_events`
// (mutual exclusion) and manifests with duplicate or unknown
// canonical events (P1c contract `when_events` rules). At render
// time the spec is expanded into one rendered action per canonical
// event the target platform documents.
WhenEvents []string
MatchTools []string
MatchExpression string
Command string
TimeoutMS int
EnabledOn []string
RequiredOn []string
PlatformOverrides map[string]HookPlatformOverride
}
func ListHookSpecs ¶
ListHookSpecs returns hook entries under ~/.agents/hooks/<scope>/: canonical bundles (…/<name>/HOOK.yaml) and legacy single-file JSON hooks. The hooks directory must exist; if it is missing, ReadDir fails with an error satisfying os.IsNotExist.
type HookTransport ¶
type HookTransport string
const ( HookTransportSymlink HookTransport = "symlink" HookTransportHardlink HookTransport = "hardlink" HookTransportWrite HookTransport = "write" )
type LinkCounter ¶
LinkCounter is implemented by platforms that can count their healthy and broken managed links for a project. Consumer: doctor.countProjectLinks and the badge-math feeding status.
type MCPFileSpec ¶
MCPFileSpec describes one canonical MCP config file under ~/.agents/mcp/<scope>/.
func ListCanonicalMCPFiles ¶
func ListCanonicalMCPFiles(agentsHome, scope string) ([]MCPFileSpec, error)
ListCanonicalMCPFiles returns non-directory MCP config files under ~/.agents/mcp/<scope>/, sorted by basename. If the scope directory is missing, the error satisfies os.IsNotExist.
func ResolveCanonicalMCPFile ¶
func ResolveCanonicalMCPFile(agentsHome, scope, name string) (*MCPFileSpec, error)
ResolveCanonicalMCPFile finds an MCP file by scope and name (basename or stem).
type ModelTokenUsage ¶
type ModelTokenUsage struct {
InputTokens int
OutputTokens int
CacheReadInputTokens int
CacheCreationInputTokens int
}
ModelTokenUsage holds cumulative token counts for a single model.
type OrphanCanonical ¶
type OrphanCanonical struct {
// Name is the entry basename as it appears under ~/.agents/<bucket>/.
Name string
// DisplayNote is either "" (plain orphan) or a pre-formatted suffix
// describing the mis-pointed target. Callers concatenate it directly
// when rendering.
DisplayNote string
}
OrphanCanonical describes a canonical entry under ~/.agents/ that has no corresponding managed link in the project (orphan from the project's perspective). DisplayNote is empty for plain orphans; a mis-pointed link surfaces as a non-empty note formatted as " (mis-pointed: <target>)".
type OrphanCanonicalReporter ¶
type OrphanCanonicalReporter interface {
OrphanCanonicals(project, projectPath, agentsHome, bucket string) []OrphanCanonical
}
OrphanCanonicalReporter is implemented by platforms that maintain a canonical store under ~/.agents/<bucket>/ that can be inspected for orphans (entries with no matching project link). Consumer: doctor.collectOrphanCanonicals.
type Platform ¶
type Platform interface {
// ID returns the platform identifier (e.g. "cursor", "claude").
ID() string
// DisplayName returns the human-readable name.
DisplayName() string
// IsInstalled checks if this platform is installed on the system.
IsInstalled() bool
// Version returns the detected version string, or empty string.
Version() string
// CreateLinks creates all managed links for a project in repoPath.
CreateLinks(project, repoPath string) error
// RemoveLinks removes all managed links for a project from repoPath.
RemoveLinks(project, repoPath string) error
// HasDeprecatedFormat checks if the project has deprecated config files.
HasDeprecatedFormat(repoPath string) bool
// DeprecatedDetails returns a description of the deprecated format.
DeprecatedDetails(repoPath string) string
// to shared (cross-platform) repo-local targets such as .agents/skills/*.
// These intents are aggregated by the command layer into a single
// ResourcePlan so compatible targets are deduped and conflicts are caught
// before any filesystem writes occur.
SharedTargetIntents(project string) ([]ResourceIntent, error)
}
Platform defines the interface all AI agent platforms must implement.
func Filter ¶ added in v0.4.1
Filter returns the subset of all whose ID() matches agentFilter, in the original order. An empty agentFilter selects every platform (the unfiltered `da status`/`da doctor --verbose` audit). This is the single platform-selection primitive the lifecycle audit loop dispatches over, replacing the per-platform `agentFilter == "" || agentFilter == "<id>"` chain that previously lived in status.go's printAudit.
func InstalledEnabledPlatforms ¶
InstalledEnabledPlatforms returns platforms that are enabled in cfg and detected as installed on this machine. Order matches All().
func NewCopilot ¶
func NewCopilot() Platform
func NewOpenCode ¶
func NewOpenCode() Platform
type PlatformBadge ¶
type PlatformBadge struct {
// Name is the human-readable platform name shown in the badge row
// (e.g. "Cursor", "Claude Code").
Name string
// Present is true when this platform has any managed state for the
// inspected scope (project or user-home).
Present bool
// Broken is true when any of the platform's managed links are broken.
Broken bool
}
PlatformBadge is the per-platform summary consumed by both the text (badge row) and JSON (statusJSONPlatform) status output. Per D5 of the proposal, this is the single source of truth that replaces the parallel `*TextBadge` and `collectProjectPlatforms` paths.
type PlatformUsageStats ¶
type PlatformUsageStats struct {
PlatformID string
TotalSessions int
TotalMessages int
TokensByModel map[string]ModelTokenUsage
DailyActivity []DailyUsage
RecentSessions []SessionSummary
CommitAttribution []CommitAttribution
}
PlatformUsageStats holds pre-aggregated usage data from a platform's native store. Used by StatsReader.ReadUsageStats.
type PluginKind ¶
type PluginKind string
const ( PluginKindNative PluginKind = "native" PluginKindPackage PluginKind = "package" )
type PluginMarketplace ¶
type PluginResources ¶
type PluginSpec ¶
type PluginSpec struct {
SchemaVersion int `yaml:"schema_version"`
Kind PluginKind `yaml:"kind"`
Name string `yaml:"name"`
Version string `yaml:"version,omitempty"`
DisplayName string `yaml:"display_name,omitempty"`
Description string `yaml:"description,omitempty"`
Authors []string `yaml:"authors,omitempty"`
Homepage string `yaml:"homepage,omitempty"`
License string `yaml:"license,omitempty"`
Platforms []string `yaml:"platforms"`
Resources PluginResources `yaml:"resources,omitempty"`
Marketplace PluginMarketplace `yaml:"marketplace,omitempty"`
Dependencies map[string]any `yaml:"dependencies,omitempty"`
PlatformOverrides map[string]map[string]any `yaml:"platform_overrides,omitempty"`
Dir string `yaml:"-"`
ManifestPath string `yaml:"-"`
Scope string `yaml:"-"`
}
PluginSpec is the canonical dot-agents plugin bundle manifest. Schema contract: schemas/plugin.schema.json - keep this struct aligned with the manifest contract and validate raw YAML bytes via PluginManifestSchema before trusting the typed fields.
func ListPluginSpecs ¶
func ListPluginSpecs(agentsHome, scope string) ([]PluginSpec, error)
ListPluginSpecs returns canonical plugin specs for a scope. An empty scope scans all scopes under ~/.agents/plugins/.
func LoadPluginSpec ¶
func LoadPluginSpec(pluginDir string) (PluginSpec, error)
LoadPluginSpec parses and validates a canonical plugin manifest from pluginDir.
type ResourceIntent ¶
type ResourceIntent struct {
IntentID string `json:"intent_id"`
Project string `json:"project"`
Bucket string `json:"bucket"`
LogicalName string `json:"logical_name"`
TargetPath string `json:"target_path"`
Ownership ResourceOwnership `json:"ownership"`
SourceRef ResourceSourceRef `json:"source_ref"`
Shape ResourceShape `json:"shape"`
Transport ResourceTransport `json:"transport"`
Materializer string `json:"materializer"`
ReplacePolicy ResourceReplacePolicy `json:"replace_policy"`
PrunePolicy ResourcePrunePolicy `json:"prune_policy"`
Provenance ResourceProvenance `json:"provenance"`
Precedence int `json:"precedence,omitempty"`
ConflictKey string `json:"conflict_key,omitempty"`
MarkerFiles []string `json:"marker_files,omitempty"`
EnabledOn []string `json:"enabled_on,omitempty"`
ReviewHint string `json:"review_hint,omitempty"`
}
func BuildSharedAgentFileSymlinkIntents ¶
func BuildSharedAgentFileSymlinkIntents(project, targetRoot, destFileSuffix string) ([]ResourceIntent, error)
BuildSharedAgentFileSymlinkIntents builds symlink intents from each canonical AGENT.md file to a repo-local file path (OpenCode `.md`, Copilot `.agent.md`).
A missing canonical agents bucket (ENOENT) is treated as an empty resource set — projects without any agents yet are legitimate and should yield no intents, not a hard failure. Other errors (permission denied, IO) propagate so callers can surface them instead of silently producing an empty plan.
func BuildSharedAgentMirrorIntents ¶
func BuildSharedAgentMirrorIntents(project string, targetRoots ...string) ([]ResourceIntent, error)
BuildSharedAgentMirrorIntents builds symlink intents for canonical agents/ buckets (per-entry directories with AGENT.md) into the given repo-relative target roots.
func BuildSharedCodexAgentTomlIntents ¶
func BuildSharedCodexAgentTomlIntents(project string) ([]ResourceIntent, error)
BuildSharedCodexAgentTomlIntents builds render intents for `.codex/agents/*.toml` from canonical project agent directories.
A missing canonical agents bucket (ENOENT) is treated as an empty resource set — projects without any agents yet are legitimate and should yield no intents, not a hard failure. Other errors (permission denied, IO) propagate so callers can surface them instead of silently producing an empty plan.
func BuildSharedPluginBundleIntents ¶
func BuildSharedPluginBundleIntents(project string, targetRoots ...string) ([]ResourceIntent, error)
BuildSharedPluginBundleIntents returns ResourceIntents for each canonical plugin bundle under ~/.agents/plugins/{scope}/ pointing at the given target roots. Each platform's SharedTargetIntents calls this with its own native plugin target path (e.g. OpenCode uses .opencode/plugins/, Cursor uses .cursor-plugin/, Claude uses .claude-plugin/, etc.). Platforms that do not yet have an emitter for their native plugin format simply omit this call from their SharedTargetIntents implementation — add it there when the emitter lands.
func BuildSharedSkillMirrorIntents ¶
func BuildSharedSkillMirrorIntents(project string, targetRoots ...string) ([]ResourceIntent, error)
func (ResourceIntent) EffectiveConflictKey ¶
func (i ResourceIntent) EffectiveConflictKey() string
func (ResourceIntent) Validate ¶
func (i ResourceIntent) Validate() error
type ResourceOwnership ¶
type ResourceOwnership string
const ( ResourceOwnershipPlatformRepo ResourceOwnership = "platform_repo" ResourceOwnershipUserHome ResourceOwnership = "user_home" )
type ResourcePlan ¶
type ResourcePlan struct {
Resources []plannedResource
}
func BuildResourcePlan ¶
func BuildResourcePlan(intents []ResourceIntent) (ResourcePlan, error)
func BuildSharedTargetPlan ¶
func BuildSharedTargetPlan(project string, platforms []Platform) (ResourcePlan, error)
BuildSharedTargetPlan aggregates SharedTargetIntents from all provided platforms and builds a single merged ResourcePlan (dedupe, conflict detection). Dry-run and execute paths both use this so intent collection and planning happen once per operation.
func (ResourcePlan) Execute ¶
func (p ResourcePlan) Execute(repoPath, agentsHome string) error
func (ResourcePlan) PruneStaleSharedTargets ¶ added in v0.4.0
func (p ResourcePlan) PruneStaleSharedTargets(repoPath, agentsHome string) ([]string, error)
PruneStaleSharedTargets deletes managed outputs that are no longer in the resolved plan (the EXACT/PRUNE projection, config-v2-coherence §7A.5). It scans only the parent directories that own at least one ResourcePruneTarget intent — the directories da actively projects into — and removes any entry there that (a) is not a wanted plan target and (b) is a managed link under agentsHome. User-authored files and links pointing outside agentsHome are never touched, so the prune cannot delete content da does not own.
Returns the list of pruned absolute paths and an aggregated error: a single stuck removal is reported (errors.Join) rather than short-circuiting, so one failure cannot hide the prune status of the rest and the caller never reports a converged tree while a stale managed output is still live.
func (ResourcePlan) RemoveSharedTargets ¶
func (p ResourcePlan) RemoveSharedTargets(repoPath, agentsHome string) error
RemoveSharedTargets deletes managed outputs for each resource in the plan. Per-resource removal failures are aggregated (errors.Join) rather than short-circuiting so that one stuck target cannot hide the removal status of the rest, and so the caller (da remove) never reports a clean unlink while a managed output is still live on disk.
type ResourceProvenance ¶
type ResourcePrunePolicy ¶
type ResourcePrunePolicy string
const ( ResourcePruneNone ResourcePrunePolicy = "none" ResourcePruneTarget ResourcePrunePolicy = "target_only" ResourcePruneGeneratedChildren ResourcePrunePolicy = "generated_children" )
type ResourceReplacePolicy ¶
type ResourceReplacePolicy string
const ( ResourceReplaceNever ResourceReplacePolicy = "never" ResourceReplaceIfManaged ResourceReplacePolicy = "if_managed" ResourceReplaceAllowlistedImportedDirOnly ResourceReplacePolicy = "allowlisted_imported_dir_only" )
type ResourceShape ¶
type ResourceShape string
const ( ResourceShapeDirectDir ResourceShape = "direct_dir" ResourceShapeDirectFile ResourceShape = "direct_file" ResourceShapeRenderSingle ResourceShape = "render_single" ResourceShapeRenderFanout ResourceShape = "render_fanout" )
type ResourceSourceKind ¶
type ResourceSourceKind string
const ( ResourceSourceCanonicalFile ResourceSourceKind = "canonical_file" ResourceSourceCanonicalDir ResourceSourceKind = "canonical_dir" ResourceSourceCanonicalBundle ResourceSourceKind = "canonical_bundle" )
type ResourceSourceRef ¶
type ResourceSourceRef struct {
Scope string `json:"scope"`
Bucket string `json:"bucket"`
RelativePath string `json:"relative_path"`
Kind ResourceSourceKind `json:"kind"`
Origin string `json:"origin,omitempty"`
}
func (ResourceSourceRef) CanonicalPath ¶
func (r ResourceSourceRef) CanonicalPath(agentsHome string) string
func (ResourceSourceRef) Validate ¶
func (r ResourceSourceRef) Validate() error
type ResourceTransport ¶
type ResourceTransport string
const ( ResourceTransportSymlink ResourceTransport = "symlink" ResourceTransportHardlink ResourceTransport = "hardlink" ResourceTransportWrite ResourceTransport = "write" )
type RuleFileSpec ¶
type RuleFileSpec struct {
Scope string
BaseName string // full file name, e.g. rules.mdc
SourcePath string
}
RuleFileSpec describes one canonical rule file under ~/.agents/rules/<scope>/.
func ListCanonicalRuleFiles ¶
func ListCanonicalRuleFiles(agentsHome, scope string) ([]RuleFileSpec, error)
ListCanonicalRuleFiles returns non-directory rule files under ~/.agents/rules/<scope>/, sorted by basename. Subdirectories are ignored. If the scope directory is missing, the error satisfies os.IsNotExist.
func ResolveCanonicalRuleFile ¶
func ResolveCanonicalRuleFile(agentsHome, scope, name string) (*RuleFileSpec, error)
ResolveCanonicalRuleFile finds a rule file by scope and name. Name may be a full basename (e.g. rules.mdc) or a stem; stems try .mdc, .md, .txt in order.
type SessionReader ¶
type SessionReader interface {
// AIAgentPrefix returns the harness prefix used in the AI_AGENT env var
// convention (e.g. "claude-code" for AI_AGENT=claude-code_2-1-138_agent).
// Returns "" if this platform does not follow the AI_AGENT convention.
AIAgentPrefix() string
// SessionEnvs lists env var names (in preference order) that carry the
// active session ID. First non-empty value wins.
SessionEnvs() []string
// EntrypointEnvs lists env var names for the session launch entrypoint.
EntrypointEnvs() []string
// ResolveModel scans the platform's session store for the model active in
// the given session. Returns "" when unavailable or not yet implemented.
ResolveModel(home, projectPath, sessionID string) string
}
SessionReader is implemented by platforms that expose structured runtime session data. It is the read-side complement to the write-side Platform interface and is kept separate to avoid burdening platforms that do not yet have confirmed session env var contracts.
Implement on a platform struct to make it participate in agent identity detection at `da workflow checkpoint` time. Stubs that return "" / nil are valid until the env var contract for that platform is confirmed.
type SessionSummary ¶
SessionSummary holds a brief description of a session.
type SessionTokenMetrics ¶
type SessionTokenMetrics struct {
InputTokens int
OutputTokens int
CacheReadTokens int
CacheCreationTokens int
ReasoningTokens int // Codex o-series reasoning tokens; 0 for Claude Code
CacheHitRate float64 // CacheReadTokens/(CacheReadTokens+CacheCreationTokens); 0 = unavailable
MessageCount int
}
SessionTokenMetrics holds per-iteration token usage aggregated from a session's JSONL, time-windowed by checkpoint_at. Used by SessionTokenScanner.
type SessionTokenScanner ¶
type SessionTokenScanner interface {
ScanSessionTokens(home, projectPath, sessionID, afterTimestamp string) SessionTokenMetrics
}
SessionTokenScanner is implemented by platforms that support per-iteration token usage scanning from their session JSONL. Returns a zero SessionTokenMetrics when no matching entries exist or the session file is absent.
type SettingsFileSpec ¶
SettingsFileSpec describes one canonical settings file under ~/.agents/settings/<scope>/.
func ListCanonicalSettingsFiles ¶
func ListCanonicalSettingsFiles(agentsHome, scope string) ([]SettingsFileSpec, error)
ListCanonicalSettingsFiles returns non-directory settings files under ~/.agents/settings/<scope>/.
func ResolveCanonicalSettingsFile ¶
func ResolveCanonicalSettingsFile(agentsHome, scope, name string) (*SettingsFileSpec, error)
ResolveCanonicalSettingsFile finds a settings file by scope and name (basename or stem).
type SingleFileLinkSpec ¶
type SingleFileLinkSpec struct {
// LinkPath is the absolute path to the managed file link.
LinkPath string
// CanonicalPaths is the ordered list of acceptable sources. The first
// hard-linked match wins; if none match and the link exists, the link
// is reported as broken.
CanonicalPaths []string
}
SingleFileLinkSpec describes one managed file link a platform owns: a fixed link path and the ordered list of canonical source files any of which would satisfy the link (the ordered list supports the .mdc → .md fallback already used by cursor rules).
type StatsReader ¶
type StatsReader interface {
ReadUsageStats(home string) *PlatformUsageStats
}
StatsReader is implemented by platforms that expose pre-aggregated usage statistics. ReadUsageStats returns nil when the platform's stats file is absent or not yet implemented.
type StatusBadger ¶
type StatusBadger interface {
Badge(project, repoPath, agentsHome string) PlatformBadge
}
StatusBadger is implemented by platforms that can produce a one-line status badge for the project. Consumer: status.collectProjectTextBadges and status.collectProjectPlatforms (text + JSON share the same value per D5).
type UserConfigReporter ¶
type UserConfigReporter interface {
// UserBrokenLinks returns broken managed links under the user's home
// directory for this platform. Consumer: doctor.collectBrokenUserLinks.
UserBrokenLinks(home string) []BrokenLink
// UserBadge returns the user-config badge for the platform. Consumer:
// status.collectUserConfigPlatforms.
UserBadge(home string) PlatformBadge
}
UserConfigReporter is implemented by every platform that participates in the user-home diagnostics path. claude/codex/opencode/cursor report real managed user-home links; copilot implements it too but reports an empty/clean surface because its documented user-config layer is not yet wired by dot-agents (the user-scope wiring gap is tracked in PLATFORM_DIRS_DOCS). No platform lacks a user-config layer — the distinction is whether dot-agents wires it yet.