Help us shape the future of Go! Take the 2026 Go Developer Survey

vcs

package
v0.4.5 Latest Latest
Warning

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

Go to latest
Published: Oct 16, 2026 License: MIT Imports: 21 Imported by: 0

Documentation

Overview

Boundary-aware upward VCS auto-detection: innermost-match selection across built-in and user detectors.

Marker-based VCS detection: marker-name validation and single-directory probing.

VCS action invocation: placeholder substitution, cwd containment, launch-failure synthesis, and paired tool_exec_* emission.

Hard override vcs.preferred: cross-reference validation and single-detector upward walk.

VCS detection tie-breaking by configured vcs.priority and the ambiguity warning helper.

Loads and validates per-source VCS template files.

tools.Tool wrapper for a single VCS action, its effective-cwd exposure, and the per-template registration of vcs_<action> tools (step 6c).

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AmbiguityWarning

func AmbiguityWarning(matches []string, winner string, preferredApplied bool) string

AmbiguityWarning returns a single-line warning when more than one detector matched at the same depth and no vcs.preferred override was applied; otherwise it returns an empty string. The warning names the chosen winner and points the user at vcs.priority and vcs.preferred. It is side-effect-free: the caller prints it. (The vcs.preferred override path bypasses tie-breaking and sets preferredApplied.)

func AutoDetect

func AutoDetect(cwd string, boundary string, projectRoot string, templates map[string]*Template) (matches []string, depth int, warnings []string, err error)

AutoDetect walks upward from cwd, bounded by boundary, and returns the VCS names whose markers succeed at the innermost level. matches holds every name that matched at that level so the caller can tie-break; depth is 0 for cwd and increases by one per parent level, and is -1 when no marker is found anywhere within the boundary. warnings carries one collapsed line per skipped unreadable non-anchor directory for the caller to print; AutoDetect never writes to stderr. An unreadable walk anchor (the cwd itself) is not a skippable directory: AutoDetect returns a *AnchorReadError before probing for matches or walking to parents, so the caller can render the OP_FAIL walk-anchor failure and exit before the TUI starts.

boundary is "launch-dir-only" (probe cwd only, projectRoot ignored) or "project-root" (walk from cwd up through projectRoot inclusive). Any other boundary value, or a cwd that is not within projectRoot in project-root mode, returns an error without reporting a match. Detection is a pure filesystem marker probe and never shells out, so a matched VCS's binary need not be installed; a missing binary surfaces only on first action invocation.

func ConfinementMode

func ConfinementMode(ctx context.Context) (string, bool)

func DetectInDir

func DetectInDir(dir, marker string) (bool, error)

DetectInDir reports whether dir directly contains an entry named marker. It validates marker before joining paths so an invalid marker can never become a path-traversal or nested-path probe. The probe is an lstat (no symlink follow): any entry type counts as present. A missing entry yields (false, nil); any other filesystem error is returned.

func Invoke

func Invoke(ctx context.Context, actionName string, action *ActionSpec, params map[string]string, repoRoot string, runner cmdrunner.Runner, emit EventAppender, cap int) (tools.Result, error)

Invoke runs a single non-detect VCS action and returns its raw tools.Result. It substitutes placeholders into argv, resolves and contains the cwd, mints the invocation id via the runner (— the runner owns the id), emits the paired tool_exec_start/tool_exec_end events, and synthesizes the launch-failure surface for a cwd escape or a failed process launch. cap is the registration-supplied sessions.max_tool_output_bytes: the persisted tool_exec_end stdout/stderr are capped through the shared truncation helper, while the returned tools.Result keeps the raw streams unchanged.

A non-nil error is reserved for invalid input or an internal failure with no reliable result (mirroring the runner contract); the three failure modes — cwd escape, repo-root disappearance ("active repo root binding"), and process-launch failure — are carried on the returned Result, not as errors.

func LoadBuiltinTemplates

func LoadBuiltinTemplates() (map[string]*Template, error)

LoadBuiltinTemplates parses every embedded built-in template (git, hg, jj) into validated *Template values keyed by name. It is the in-memory base map a caller overlays the global and per-project template directories onto at bootstrap step 4, so the built-ins are always present even when their first-run reference copies under ~/.codemeld/global/vcs/ have been deleted — the union of names this base provides is part (a) of the vcs.preferred cross-reference set. Each Template.Source is the synthetic token "built-in:<name>" because the bytes come from the binary, not a file on disk.

func LoadTemplateFiles

func LoadTemplateFiles(files []TemplateFile) (map[string]*Template, error)

LoadTemplateFiles loads templates from bytes a caller already holds, under the same filename, duplicate-name and validation rules as LoadTemplates. It exists for a caller that must load exactly the bytes it inspected earlier and may not reopen the paths.

func LoadTemplates

func LoadTemplates(dir string) (map[string]*Template, error)

LoadTemplates scans a single source directory for `*.yaml` VCS templates and returns them keyed by derived name. A missing directory is not an error and contributes no templates; any other enumeration failure is returned to the caller. Each file is validated; the first validation failure is returned.

func Rank

func Rank(name string, priority []string, builtinNames map[string]bool) (rank int)

Rank returns the primary order bucket for name under priority. Lower ranks win. A name listed in priority ranks at its first position in that list. A name not listed ranks after every listed entry: unlisted built-ins (builtinNames[name] true) sort ahead of unlisted user-defined names. Rank only establishes the bucket; names sharing an unlisted bucket are equal here and broken alphabetically by TieBreak.

func RegisterActions

func RegisterActions(reg *tools.Registry, tmpl *Template, repoRoot string, runner cmdrunner.Runner, emit EventAppender, cap int) error

RegisterActions registers one ActionTool per non-detect action of tmpl in reg under its vcs_<action> name, using tmpl.Source as the registry source. Explicit action class declarations are ignored by this untrusted entry point; callers that have already verified template trust should use RegisterActionsWithTrustedClasses. Registration order follows the canonical action order so any same-name replacement warning is deterministic. A nil tmpl (no active template, e.g. detection found no match) registers nothing. cap is sessions.max_tool_output_bytes (config.Cache.MaxToolOutputBytes()), threaded onto each tool so the persisted tool_exec_end output is capped.

func RegisterActionsWithTrustedClasses

func RegisterActionsWithTrustedClasses(reg *tools.Registry, tmpl *Template, repoRoot string, runner cmdrunner.Runner, emit EventAppender, cap int) error

RegisterActionsWithTrustedClasses registers VCS actions like RegisterActions, but treats explicit per-action class declarations in tmpl as trusted registration metadata.

func ResolveActionCWD

func ResolveActionCWD(action *ActionSpec, repoRoot string) (string, error)

ResolveActionCWD resolves the effective working directory for action under repoRoot, applying the VCS action cwd rule: an omitted cwd uses repoRoot; an absolute cwd is used as-is; a relative cwd is joined to repoRoot. Both the candidate and the repo root are symlink-resolved and cleaned, then compared with the same descendant/equal rule permissions path-scope matching uses, so a symlink alias cannot make authorization and execution disagree. A resolved cwd outside repoRoot returns a *CWDEscapeError carrying the resolved path. A repo root that no longer resolves (removed or inaccessible after bootstrap bound it "active repo root binding") returns a *RepoRootResolveError carrying the would-be effective cwd and error category, so the caller can take the launch-failure path; any other resolution failure (e.g. an explicit cwd target that vanished while the root survives) is returned wrapped. It is the single source of an action's cwd: both Invoke and the tool wrapper's EffectiveCWD call it, so the authorized path and the executed path cannot drift.

func RunPreferred

func RunPreferred(name string, cwd string, boundary string, projectRoot string, sourceFile string, builtinDetect map[string]string, templates map[string]*Template) (matchedDir string, err error)

RunPreferred performs the hard-override detection walk for an effective vcs.preferred value: only the named VCS's detect marker is probed up the tree, skipping vcs.priority tie-breaking entirely. It mirrors AutoDetect's boundary semantics — "launch-dir-only" probes only cwd; "project-root" walks from cwd through projectRoot inclusive and rejects a cwd outside projectRoot; any other boundary errors before walking; an unreadable walk anchor is fatal (returns *AnchorReadError) while unreadable non-anchor directories are skipped. The innermost directory whose marker matches is returned as the active VCS template's repo root. When the marker matches nowhere on the walk, it returns the prescribed detect-fails-everywhere error naming sourceFile so the caller can exit.

Built-in names probe builtinDetect[name] even when templates carries a built-in-name override, matching the auto-detect contract; non-built-in names probe templates[name].Detect.Marker.

func TieBreak

func TieBreak(matches []string, priority []string, builtinNames map[string]bool) string

TieBreak returns the winning name among same-depth detector matches under priority. It picks the lowest Rank; among names sharing an unlisted bucket it picks the alphabetically smallest. It returns an empty string when matches is empty.

func ValidateMarker

func ValidateMarker(marker string) error

ValidateMarker reports whether marker names a single filesystem entry rather than a path. A valid marker is non-empty; contains no '/', '\', or NUL; is at most 255 UTF-8 bytes; is neither "." nor ".."; and has no leading or trailing ASCII whitespace. The returned error describes the violation.

func ValidatePreferred

func ValidatePreferred(name string, builtins []string, userTemplates []string, sourceFile string) error

ValidatePreferred cross-reference-checks an effective vcs.preferred value against the loaded-template name set. An unset or empty value disables the override and returns nil. The accepted set is the union of the built-in names (always, regardless of filesystem-resident reference copies) and the user-defined template names that loaded successfully. An unrecognized value yields a schema-validation-shaped load-time error naming sourceFile, the vcs.preferred key, and the offending value, so the caller renders it the same way it renders settings schema-validation failures and exits before the TUI.

func WithChildInvocationID

func WithChildInvocationID(ctx context.Context, id string) context.Context

WithChildInvocationID marks ctx as running inside the child agent identified by id, so the action's tool_exec_* payloads carry it. The registry — and with it every ActionTool and the EventAppender bound to it — is shared between the parent and its children, so the id cannot be held on the tool and has to arrive with the call.

func WithConfinementMode

func WithConfinementMode(ctx context.Context, mode string) context.Context

Types

type ActionClass

type ActionClass string

ActionClass is an optional per-action trust declaration. The zero value ClassUnset means the action omitted the class key and is distinct from an explicit ClassMutating, so later trust logic can tell default disk behavior from a user declaration.

const (
	// ClassUnset is the absent-class state (the class key was omitted).
	ClassUnset ActionClass = ""
	// ClassReadOnly declares the action does not mutate the repository.
	ClassReadOnly ActionClass = "read_only"
	// ClassMutating declares the action mutates the repository.
	ClassMutating ActionClass = "mutating"
)

type ActionSpec

type ActionSpec struct {
	Argv  []string
	Cwd   string
	Class ActionClass
}

ActionSpec is a non-detect action body: the argv to run directly (no shell) and an optional working directory. An empty Cwd means the cwd key was absent; a present-but-empty cwd is rejected at load time. Class is the optional per-action trust declaration; ClassUnset means the class key was absent.

type ActionTool

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

ActionTool is the tools.Tool for one non-detect VCS action. It dispatches under the name vcs_<action> and routes Invoke to the package's action invoker with the action spec, repo root, runner, and event seam it was built with.

func (*ActionTool) Advertise

func (t *ActionTool) Advertise() tools.Metadata

Advertise returns this action tool's product-authored advertising metadata and its source-sensitive read-only classification. The parameter JSON-Schema is keyed by action name — viable because template validation rejects unknown action keys, so the action-name set is closed even for user-supplied templates. ReadOnly reflects the classification bound at registration from the template source, and only an action running the product's own read-only argv is noncredential — a template author cannot declare that classification for itself.

func (*ActionTool) EffectiveCWD

func (t *ActionTool) EffectiveCWD() (string, error)

EffectiveCWD returns the resolved cwd (or the same cwd error) the action will use at invocation, by delegating to ResolveActionCWD. The tool-dispatch layer reads this before authorizing so the path scope it authorizes is the exact path the action executes in.

func (*ActionTool) Invoke

func (t *ActionTool) Invoke(ctx context.Context, args map[string]any) (tools.Result, error)

Invoke decodes args into the action's placeholder params and runs the action.

func (*ActionTool) InvokeWithEffectiveCWD

func (t *ActionTool) InvokeWithEffectiveCWD(ctx context.Context, args map[string]any, resolvedCwd string, cwdErr error) (tools.Result, error)

InvokeWithEffectiveCWD runs the action using a cwd result that was already resolved by EffectiveCWD. Structured dispatch uses this after authorizing that same cwd so authorization and execution cannot drift if symlinks change between the two steps.

func (*ActionTool) Name

func (t *ActionTool) Name() string

Name returns the exact dispatch name vcs_<action>.

func (*ActionTool) ProtectedStateRisk

func (t *ActionTool) ProtectedStateRisk(ctx context.Context, args map[string]any, protectedIn func(root string) ([]string, error)) bool

ProtectedStateRisk reports whether running this action could rewrite one of the run's protected settings identities. It answers before the action launches, using only non-mutating backend queries that emit no execution events, and reports risk for anything it cannot prove safe. protectedIn supplies the protected identities inside this repository, and is called only for an action whose verdict needs them.

func (*ActionTool) SubjectKind

func (t *ActionTool) SubjectKind() string

SubjectKind returns the permission subject kind for a structured tool, always "tool".

type AnchorReadError

type AnchorReadError struct {
	Operation string
	Anchor    string
	Category  fserrors.Category
	Err       error
}

AnchorReadError reports that the VCS auto-detection walk anchor (the launch CWD) could not be listed, so the walk never started. The caller renders it with the OP_FAIL template (operation read-walk-anchor) and exits before the TUI starts, rather than treating the anchor as a skippable unreadable directory.

func (*AnchorReadError) Error

func (e *AnchorReadError) Error() string

func (*AnchorReadError) Unwrap

func (e *AnchorReadError) Unwrap() error

type CWDEscapeError

type CWDEscapeError struct {
	ResolvedCwd string
}

CWDEscapeError reports that an action's resolved cwd lies outside the active repo root. It carries the cleaned, symlink-resolved cwd so callers can build the exact launch-failure stderr and record the attempted path scope.

func (*CWDEscapeError) Error

func (e *CWDEscapeError) Error() string

type DetectSpec

type DetectSpec struct {
	Marker string
}

DetectSpec is the marker-based detect action body: a single filesystem entry name to probe for.

type EventAppender

type EventAppender func(events.EventPayload) error

EventAppender is the narrow event-write seam this package needs: it accepts an events.EventPayload and returns an error. Production adapts it to events.Append bound to the active *sessions.Store; tests pass a capturing function. Keeping the seam local (rather than importing the store into invocation) follows the callback-seam style that avoids package cycles.

type RepoRootResolveError

type RepoRootResolveError struct {
	// PathScope is the cleaned, absolute effective cwd the action would have used,
	// derived from the bootstrap-resolved repo root per the cwd rule. It is
	// not symlink-resolved a second time because the target no longer resolves on
	// disk; the bootstrap-resolved root it is built from was resolved when present.
	PathScope string
	// Category is the error category classified from the resolution failure
	// (e.g. not_found when the root was removed, permission_denied when unreadable).
	Category fserrors.Category
	// contains filtered or unexported fields
}

RepoRootResolveError reports that the active repo root could not be resolved at invocation time — e.g. it was removed or became inaccessible after bootstrap step 6 bound it ("active repo root binding"). It carries the error category (for the launch-failure stderr) and the cleaned, absolute would-be effective cwd (the path scope recorded on the paired events), so Invoke can synthesize the launch-failure surface instead of surfacing a bare Go error with no result and no events.

func (*RepoRootResolveError) Error

func (e *RepoRootResolveError) Error() string

func (*RepoRootResolveError) Unwrap

func (e *RepoRootResolveError) Unwrap() error

type Template

type Template struct {
	Name                 string
	Detect               *DetectSpec
	Actions              map[string]ActionSpec
	Source               string
	BuiltinReferenceCopy bool
}

Template is one loaded VCS template. Detect is nil when the file omits it (permitted only for built-in-name overrides). BuiltinReferenceCopy reports that the raw bytes are byte-identical to the embedded built-in of the same name (an unchanged first-run reference copy); it is a path-free property of the bytes, and trust wiring that combines it with source location lives outside this package.

type TemplateFile

type TemplateFile struct {
	Path  string
	Bytes []byte
}

TemplateFile is one template supplied as bytes already read from Path, which is used for the derived name and for validation-failure attribution.

type ValidationError

type ValidationError struct {
	File string
	Msg  string
}

ValidationError is a load-time template validation failure. It names the offending file when known.

func (*ValidationError) Error

func (e *ValidationError) Error() string

Directories

Path Synopsis
Package builtin embeds codemeld's built-in VCS templates (git, hg, jj) as copy-and-modify reference bytes.
Package builtin embeds codemeld's built-in VCS templates (git, hg, jj) as copy-and-modify reference bytes.

Jump to

Keyboard shortcuts

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