candywalk

package
v0.2026287.2235 Latest Latest
Warning

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

Go to latest
Published: Oct 14, 2026 License: MIT Imports: 8 Imported by: 1

Documentation

Overview

Package candywalk is the SHARED entity-discovery walk over a charly repo: the superproject plus every box/<distro> submodule, reading every candy/ + box/ charly.yml and returning one Entity per top-level node. It is the ONE discovery abstraction (R3) both out-of-process generator plugins use — candy/plugin-docs (the docs site generator) and candy/plugin-marketplace (the harness/marketplace generator) — so the two never fork their own directory conventions.

Discovery is PURE FILESYSTEM walking + os.ReadFile — it never shells out to git, never runs charly commands. "Defined, not default-active": it returns every DEFINED entity (what an author wrote down), never the resolved/enabled set (the resolver's surfaces are wrong for a catalog — `charly box list boxes` resolves through main's import: closure and omits every debian.* and ubuntu.* box). Each repo (the superproject + each checked-out box/<distro> submodule) is walked as its own root and the results unioned; an uninitialised submodule (no charly.yml) is skipped.

The candy de-submodule cutover (Phases 1-2) moved every candy to a standalone kind-prefixed repo (layer-*, pod-*, vm-*, plugin-*). Phase 4 deletes the in-repo candy/ dirs, after which the local FS walk alone finds only the residual fixtures. CollectEntitiesRemote extends discovery with a REMOTE-REF-AWARE mode: it also collects every @github.com/opencharly/... ref from the walked files' require:/candy: lists, resolves each repo+tag via a CALLER-SUPPLIED resolver seam (out-of-process generators use spec/refs.DownloadRepo; an in-proc caller could supply the loader's EnsureRepoDownloaded), and walks each fetched repo's candy dir (or repo-root charly.yml for config candies) — fix-pointing until no new refs surface, the same transitive closure the runtime scan materialises. The seam keeps this kit import-free: candywalk itself still carries NO charly or sdk import — only the stdlib + yaml.v3.

The package carries only the CONTRACT module + the pure kit (github.com/opencharly/spec for ParseRemoteRef (F4.3), github.com/opencharly/sdk/kit for RepoLayoutDirs (F4.4)) — never charly, never a mechanism kit with registry/host coupling. It returns the raw per-node kind discriminator + value node; the caller owns the projection into its own types (the docs plugin decodes `candy:` into its candyView/boxView; the marketplace plugin decodes `skill:`/`hook:`/ `marketplace:` into the generated spec types).

Index

Constants

View Source
const UnifiedFileName = "charly.yml"

UnifiedFileName is the one entity filename (the project rulebook's "one filename charly.yml").

Variables

This section is empty.

Functions

This section is empty.

Types

type Entity

type Entity struct {
	Name       string    // the top-level node name (as authored)
	Namespace  string    // "" for the superproject, else the box/<distro> submodule name
	Dir        string    // directory holding this charly.yml, relative to the repo root
	Kind       string    // the node's kind discriminator ("candy", "skill", "hook", "marketplace", …)
	Value      yaml.Node // the kind value body
	SourceRoot string    // absolute repo root ("" = local root; else the fetched remote cache dir)
}

Entity is one top-level node of a discovered charly.yml, regardless of kind. The value node is the node's kind value (the body under `<name>: {<kind>: …}`).

Value is a VALUE yaml.Node, not a pointer: yaml.v3's decode into `map[string]map[string]*yaml.Node` silently drops nested structs when the caller then Decodes the leaf (a plugin-fleet candy's `plugin:` block came back nil), while the value-node decode round-trips faithfully. The value-node form is what the original plugin-docs walk used.

SourceRoot is the ABSOLUTE path of the repo root this entity was read from: "" for a local superproject/box root (the caller knows the local root it passed in), or the fetched repo cache dir for a REMOTE entity from CollectEntitiesRemote. Schema reads and other per-entity file lookups must resolve relative to SourceRoot (when non-empty) rather than the local project root.

func CollectEntities

func CollectEntities(roots []Root) ([]Entity, error)

CollectEntities reads every entity node across every repo root, for the two discovery directories the loader uses (candy/ and box/). Discovery is by directory convention (candy/<name>/charly.yml, box/<name>/charly.yml) — the same two the loader uses — so the result is exactly what an author has written down.

func CollectEntitiesRemote added in v0.2026237.1646

func CollectEntitiesRemote(roots []Root, resolve RemoteResolver) ([]Entity, error)

CollectEntitiesRemote extends CollectEntities with the candy de-submodule cutover's remote-ref-aware discovery (Phase 3): every @github.com/opencharly/... ref found in the walked files' require:/candy: lists is resolved through the caller-supplied seam and the fetched repo's own candy entities (candy/<name>/charly.yml or the repo-root charly.yml for config candies) are unioned into the result, TRANSITIVELY — a fetched repo's own require:/candy: lists may surface new refs, which are fetched in turn, until closure (the same fix-point the runtime scan materialises). Entity.SourceRoot carries the fetched repo dir for remote entities so schema reads resolve against the fetched tree, not the local project root.

func ReadEntityFile

func ReadEntityFile(path string, r Root, relDir string) ([]Entity, error)

ReadEntityFile decodes one charly.yml into its top-level nodes. The file is a map of entity NAME to a single kind key (name-first shape); each (name, kind, value) triple is one Entity. A charly.yml that does not fit the name-first shape (a multi-doc bed, a template) is skipped rather than failing the whole discovery. Scalar top-level keys (the standalone repos' prepended `version: <calver>` schema header) are tolerated and ignored — they are not entities.

type RemoteResolver added in v0.2026237.1646

type RemoteResolver func(repoPath, version string) (fetchedDir string, err error)

RemoteResolver resolves one remote candy ref to a LOCALLY FETCHED repo directory. It is the caller-supplied seam that keeps this kit import-free: an out-of-process generator supplies spec/refs.DownloadRepo (or a wrapper), an in-proc caller supplies the loader's EnsureRepoDownloaded. The returned dir must hold the fetched repo export (the same shape the runtime's repo cache produces) so the walker can read its candy/ + root charly.yml.

type Root

type Root struct {
	Namespace string // "" for the superproject, else the box/<distro> submodule name
	Dir       string // absolute path
}

Root is one project tree to walk: the superproject, or a box/<distro> submodule.

func RepoRoots

func RepoRoots(root string) ([]Root, error)

RepoRoots enumerates the superproject plus every box/<distro> submodule that is actually checked out. A submodule with no charly.yml is an uninitialised gitlink — skipped rather than failed, so discovery still runs in a partially-initialised clone.

Jump to

Keyboard shortcuts

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