Documentation
¶
Overview ¶
Package config loads and merges nexss.srcpack.yml files. It owns every srcpack-specific type, default, and merge rule; file discovery and YAML decoding are delegated to github.com/nexssp/flow/config.
Index ¶
- Constants
- Variables
- func CanonicalProfileName(name string) string
- func EmbeddedIgnore() []byte
- func FindInDir(dir string) string
- func FindRoot(startDir string) (root, configPath string)
- func FormatSnippet(s string, maxLen int) string
- func MergeConfigOptions(dst *ConfigOptions, src ConfigOptions)
- func MergeProfile(dst *Profile, src Profile)
- func MergeStringSlices(dst, src []string) []string
- func ParseProfileRef(ref, currentDir string) (configPath, profileName string)
- func ResolveTreeDepth(depth int) int
- func SortedProfileNames(cfg Config) []string
- func TargetHasCycle(start string, targets map[string]TargetGroup) bool
- type ChangeDetector
- type Config
- type ConfigOptions
- type ConfigRes
- type ConfigStore
- type DirEntry
- type EditorFormat
- type EditorInfo
- type FlexibleText
- type Guardrails
- type IssueSeverity
- type OptionMutator
- type Options
- type Profile
- type ProfileInfo
- type ProfileMeta
- type TargetGroup
- type TargetInfo
- type UserConfig
- type ValidationIssue
- type ValidationReport
Constants ¶
const ConfigFileName = "nexss.srcpack.yml"
ConfigFileName is the name srcpack looks for when walking up from a project root.
const DefaultTreeDepth = 1
DefaultTreeDepth is the single source of truth for omitted tree depth.
Variables ¶
var BuiltinProfiles = []ProfileMeta{ { Name: "arch", Aliases: []string{"no-comments", "nocomments", "skeleton", "api-map", "arch-clean"}, Description: "Architecture map: signatures only (NO bodies, NO comments)", Options: ConfigOptions{ ExportedOnly: new(true), RemoveBodyFunc: new(true), StripComments: new(true), NoTests: new(true), NoGenerated: new(true), NoDeps: new(true), }, }, { Name: "api", Aliases: []string{"with-comments", "withcomments", "docs", "contracts", "arch-docs"}, Description: "Public API declarations: signatures + doc comments (NO bodies, WITH comments)", Options: ConfigOptions{ ExportedOnly: new(true), RemoveBodyFunc: new(true), StripComments: new(false), NoTests: new(true), NoGenerated: new(true), NoDeps: new(true), }, }, { Name: "impl", Aliases: []string{"review", "logic"}, Description: "Implementation logic (bodies preserved, comments stripped)", Options: ConfigOptions{ ExportedOnly: new(false), RemoveBodyFunc: new(false), StripComments: new(true), NoTests: new(true), NoGenerated: new(true), NoDeps: new(true), }, }, { Name: "source", Aliases: []string{"full", "src", "sources"}, Description: "Full code context for AI (bodies & comments, no tests/deps)", Options: ConfigOptions{ ExportedOnly: new(false), RemoveBodyFunc: new(false), StripComments: new(false), NoTests: new(true), NoGenerated: new(true), NoDeps: new(true), }, }, { Name: "with-tests", Aliases: []string{"test", "tests"}, Description: "Source code plus unit tests and test helpers", Options: ConfigOptions{ ExportedOnly: new(false), RemoveBodyFunc: new(false), StripComments: new(false), NoTests: new(false), }, }, { Name: "compact", Aliases: []string{"min", "tiny"}, Description: "Aggressively reduced context for small token budgets", Options: ConfigOptions{ ExportedOnly: new(true), RemoveBodyFunc: new(true), StripComments: new(true), TrimBlankLines: new(true), TrimIndent: new(true), MaxLines: new(100), NoTests: new(true), NoGenerated: new(true), NoDeps: new(true), }, }, { Name: "dense", Aliases: []string{"ai-dense", "idl", "ultra", "signatures"}, Description: "Ultra-compact IDL for AI reasoning (signatures only, max token savings)", Options: ConfigOptions{ ExportedOnly: new(true), RemoveBodyFunc: new(true), StripComments: new(true), NoTests: new(true), NoGenerated: new(true), NoDeps: new(true), TrimBlankLines: new(true), TrimIndent: new(true), Dense: new(true), }, }, }
BuiltinProfiles is the ordered list of profiles every srcpack run starts from. User profiles with the same name override fields on top; user profiles with a new name are added alongside.
var ConfigFileNames = []string{
"nexss.srcpack.yml",
"nexss.srcpack.yaml",
"_nexss.yml",
"_nexss.yaml",
}
ConfigFileNames is the ordered list of names srcpack recognizes as a configuration file when looking inside a specific directory. The first entry is the canonical name written by `srcpack init`; the rest are accepted for compatibility.
var DefaultExampleFolders = []string{
"examples", "example",
"samples", "sample",
"demo", "demos",
}
DefaultExampleFolders is the built-in set of directory names treated as "examples" and excluded when NoExamples is on.
Functions ¶
func CanonicalProfileName ¶
CanonicalProfileName resolves a case-insensitive name or alias to a built-in profile's canonical name. Unknown names are returned trimmed but otherwise unchanged, so user-defined profile names pass through.
func EmbeddedIgnore ¶
func EmbeddedIgnore() []byte
EmbeddedIgnore returns the shipped content of nexss.srcpack.ignore. Used by `srcpack init` to seed the file when one is not present.
func FindInDir ¶
FindInDir returns the config file present in dir, or "" when none is found. Unlike FindRoot, this does not walk upward — it only checks the given directory.
Used by `srcpack init` to detect "a config already exists HERE", which is what decides whether --force is required. The distinction matters: init creates a config in the current directory, so a walk-up would find the parent project's config and overwrite it.
func FindRoot ¶
FindRoot returns the project root for startDir, plus the path of the config file found there (empty when the root was determined by .git/ only).
The project root is the first ancestor of startDir that contains either a recognized config file or a .git/ directory. When neither is found before the filesystem root, startDir is returned with an empty configPath.
This is the single source of truth for "where is the project". Both config discovery and default output placement use it, so a run from a subdirectory never produces a stray _srcpack/ under the subdirectory.
func FormatSnippet ¶
FormatSnippet renders a short preview of multi-line text: the first few words, then an ellipsis, then the last few words.
func MergeConfigOptions ¶
func MergeConfigOptions(dst *ConfigOptions, src ConfigOptions)
MergeConfigOptions overlays every non-nil field of src onto dst.
func MergeProfile ¶
MergeProfile overlays src on dst. Fields that src leaves unset are preserved. Includes are unioned; Options merge recursively.
func MergeStringSlices ¶
MergeStringSlices appends src items to dst, skipping duplicates.
func ParseProfileRef ¶
ParseProfileRef splits a selector into an optional external config file and a profile name. When ref does not name a config file, the returned path is empty and the whole ref is the profile name.
Supported forms:
"path/to/file.yml:profile" "path/to/file.yml#profile" "path/to/dir:profile" (dir must contain a config file) "path/to/dir#profile" "path/to/dir/profile" (dir must contain a config file) "profile" (bare profile name)
func ResolveTreeDepth ¶
ResolveTreeDepth preserves positive overrides and defaults unset/invalid values.
func SortedProfileNames ¶
SortedProfileNames returns every profile name in cfg.Profiles in stable order. Used for error messages and CLI listings.
func TargetHasCycle ¶
func TargetHasCycle(start string, targets map[string]TargetGroup) bool
TargetHasCycle reports whether a target's reachable dependency graph cycles. It performs no filesystem access and leaves reporting policy to its caller.
Types ¶
type ChangeDetector ¶
type ChangeDetector interface {
IsActive() bool
IsFileChanged(absPath, relPath string, modTime time.Time) (bool, error)
}
ChangeDetector reports whether a file should be included under an incremental or git-filtered run. Implementations live in the operators package; the config layer only needs the contract.
type Config ¶
type Config struct {
Prompts map[string]string `yaml:"prompts,omitempty" json:"prompts,omitempty"`
Editors map[string]EditorFormat `yaml:"editors,omitempty" json:"editors,omitempty"`
TargetsMap map[string]TargetGroup `yaml:"targets,omitempty" json:"targets,omitempty"`
Views map[string][]string `yaml:"views,omitempty" json:"views,omitempty"`
Profile `yaml:",inline"`
Profiles map[string]Profile `yaml:"profiles,omitempty" json:"profiles,omitempty"`
}
Config is the top-level structure of nexss.srcpack.yml. Profile is embedded so top-level keys such as `editor:` and `options:` bind directly to the default profile without an intermediate `profile:` wrapper.
func Load ¶
Load returns the effective Config for a run. When no user file is found under rootDir the embedded defaults plus built-in profiles are returned. When a user file is present it is overlaid on the defaults; built-in profile fields are preserved unless the user file explicitly overrides them.
explicitPath, when non-empty, bypasses discovery and loads that file instead. A missing explicit path is an error, unlike a missing discovered path.
func LoadOptional ¶
LoadOptional behaves like Load but treats a missing explicit path as "no file present" rather than an error. Used by callers that want the defaults-plus-discovery behavior only.
type ConfigOptions ¶
type ConfigOptions struct {
StripComments *bool `yaml:"strip_comments,omitempty"`
RemoveBodyFunc *bool `yaml:"remove_body_func,omitempty"`
MaxLines *int `yaml:"max_lines,omitempty"`
MaxLinesHead *int `yaml:"max_lines_head,omitempty"`
MaxLinesTail *int `yaml:"max_lines_tail,omitempty"`
NoTests *bool `yaml:"no_tests,omitempty"`
NoGenerated *bool `yaml:"no_generated,omitempty"`
TrimBlankLines *bool `yaml:"trim_blank_lines,omitempty"`
TrimIndent *bool `yaml:"trim_indent,omitempty"`
NoDeps *bool `yaml:"no_deps,omitempty"`
ExtFilter *string `yaml:"ext_filter,omitempty"`
ExportedOnly *bool `yaml:"exported_only,omitempty"`
NoHeader *bool `yaml:"no_header,omitempty"`
NoPrompt *bool `yaml:"no_prompt,omitempty"`
NoStart *bool `yaml:"no_start,omitempty"`
NoEnd *bool `yaml:"no_end,omitempty"`
Since *string `yaml:"since,omitempty"`
Modified *bool `yaml:"modified,omitempty"`
Staged *bool `yaml:"staged,omitempty"`
Changed *bool `yaml:"changed,omitempty"`
MaskSecrets *bool `yaml:"mask_secrets,omitempty"`
DiffOnly *bool `yaml:"diff_only,omitempty"`
Tree *bool `yaml:"tree,omitempty"`
TreeOnly *bool `yaml:"tree_only,omitempty"`
TreeFiles *bool `yaml:"tree_files,omitempty"`
TreeDepth *int `yaml:"tree_depth,omitempty"`
FullTree *bool `yaml:"full_tree,omitempty"`
CostROI *bool `yaml:"cost,omitempty"`
IncludeDirPrefix *bool `yaml:"include_dir_prefix,omitempty"`
Dense *bool `yaml:"dense,omitempty"`
Examples []string `yaml:"examples,omitempty"`
NoExamples *bool `yaml:"no_examples,omitempty"`
}
ConfigOptions is the sparse, YAML-facing form of Options. A nil pointer means "not specified"; overlay skips those fields.
func (ConfigOptions) Mutator ¶
func (c ConfigOptions) Mutator() OptionMutator
Mutator returns an OptionMutator that overlays every non-nil field of c onto the target Options.
func (ConfigOptions) ToOptions ¶
func (c ConfigOptions) ToOptions() Options
ToOptions materializes a fresh Options with the srcpack defaults and then overlays c on top.
type ConfigRes ¶
type ConfigRes struct {
Profiles []ProfileInfo `json:"profiles"`
Targets []TargetInfo `json:"targets"`
Prompts map[string]string `json:"prompts"`
Editors []EditorInfo `json:"editors"`
}
ConfigRes is the structured response for `srcpack list`.
type ConfigStore ¶
type ConfigStore struct {
Path string
}
ConfigStore reads and writes nexss.srcpack.yml. Every write goes through xfs.WriteFileAtomic so a crash mid-write never leaves a partial file.
func NewConfigStore ¶
func NewConfigStore(path string) *ConfigStore
func (*ConfigStore) LoadRaw ¶
func (s *ConfigStore) LoadRaw() (UserConfig, error)
LoadRaw reads the user config without overlaying built-in defaults. A missing file is not an error — it returns an empty config.
func (*ConfigStore) Mutate ¶
func (s *ConfigStore) Mutate(dryRun bool, fn func(*UserConfig) error) (string, error)
Mutate loads the raw config, applies fn, then atomically writes the result. A failed fn aborts the write. When dryRun is true the serialized YAML is returned without touching disk.
type DirEntry ¶
type DirEntry struct {
Path string `yaml:"path" json:"path"`
Full []string `yaml:"full,omitempty" json:"full,omitempty"`
Omit []string `yaml:"omit,omitempty" json:"omit,omitempty"`
Signatures []string `yaml:"signatures,omitempty" json:"signatures,omitempty"`
}
DirEntry is one entry in a target's `dir:` list. When no per-entry rule is present it may be written as a bare string; otherwise it is an object with optional full/omit/signatures sub-lists.
func (DirEntry) MarshalYAML ¶
type EditorFormat ¶
type EditorFormat struct {
Description string `yaml:"description,omitempty" json:"description,omitempty"`
Start string `yaml:"start,omitempty" json:"start,omitempty"`
End string `yaml:"end,omitempty" json:"end,omitempty"`
FileStart string `yaml:"file_start,omitempty" json:"file_start,omitempty"`
FileEnd string `yaml:"file_end,omitempty" json:"file_end,omitempty"`
}
EditorFormat defines layout rules for one output format.
type EditorInfo ¶
type FlexibleText ¶
FlexibleText accepts a string, a YAML block scalar, or the boolean false (meaning "explicitly disabled"). Set records whether the field was present at all, so overlay merge can distinguish "not specified" from "specified as disabled".
func (FlexibleText) MarshalYAML ¶
func (f FlexibleText) MarshalYAML() (any, error)
func (*FlexibleText) UnmarshalYAML ¶
func (f *FlexibleText) UnmarshalYAML(value *yaml.Node) error
type Guardrails ¶
Guardrails enforces per-scan safety limits.
type IssueSeverity ¶
type IssueSeverity string
IssueSeverity classifies one validation finding.
const ( SeverityOK IssueSeverity = "OK" SeverityWarning IssueSeverity = "WARN" SeverityError IssueSeverity = "ERROR" )
type OptionMutator ¶
type OptionMutator func(*Options)
OptionMutator is one step in a chain of option overlays.
type Options ¶
type Options struct {
StripComments bool
RemoveBodyFunc bool
MaxLines int
MaxLinesHead int
MaxLinesTail int
NoTests bool
NoGenerated bool
TrimBlankLines bool
TrimIndent bool
ExtFilter string
NoDeps bool
OutputFile string
ExportedOnly bool
NoHeader bool
NoPrompt bool
NoStart bool
NoEnd bool
Since string
Modified bool
Staged bool
Changed bool
MaskSecrets bool
DiffOnly bool
Tree bool
TreeOnly bool
TreeFiles bool
TreeDepth int
FullTree bool
CostROI bool
IncludeDirPrefix bool
Dense bool
Examples []string
NoExamples bool
Detector ChangeDetector
Guardrails Guardrails
}
Options is the fully resolved configuration for one pipeline run. Every field is concrete; overlay of ConfigOptions on top of it happens once, before scanning starts.
func ResolveOptions ¶
ResolveOptions applies every profile's option overlay to base in chain order — earliest first, latest last — and returns the result. Callers pass cfg.Options.ToOptions() as base.
func (*Options) Apply ¶
func (o *Options) Apply(mutators ...OptionMutator) *Options
Apply runs every non-nil mutator in order and returns the receiver for chaining.
type Profile ¶
type Profile struct {
Name string `yaml:"-" json:"name,omitempty"`
BaseDir string `yaml:"-" json:"base_dir,omitempty"`
Description string `yaml:"description,omitempty" json:"description,omitempty"`
Example string `yaml:"example,omitempty" json:"example,omitempty"`
Prompt FlexibleText `yaml:"prompt,omitempty" json:"prompt,omitzero"`
Start FlexibleText `yaml:"start,omitempty" json:"start,omitzero"`
End FlexibleText `yaml:"end,omitempty" json:"end,omitzero"`
Summary FlexibleText `yaml:"summary,omitempty" json:"summary,omitzero"`
FileStart string `yaml:"file_start,omitempty" json:"file_start,omitempty"`
FileEnd string `yaml:"file_end,omitempty" json:"file_end,omitempty"`
Editor string `yaml:"editor,omitempty" json:"editor,omitempty"`
Output string `yaml:"output,omitempty" json:"output,omitempty"`
OutputFile string `yaml:"output_file,omitempty" json:"output_file,omitempty"`
Options ConfigOptions `yaml:"options,omitempty" json:"options,omitzero"`
Dir []DirEntry `yaml:"dir,omitempty" json:"dir,omitempty"`
Files []string `yaml:"files,omitempty" json:"files,omitempty"`
Includes []string `yaml:"includes,omitempty" json:"includes,omitempty"`
IncludeProfiles []string `yaml:"include_profiles,omitempty" json:"include_profiles,omitempty"`
IncludeProfile string `yaml:"include_profile,omitempty" json:"include_profile,omitempty"`
IncludedProfiles []string `yaml:"-" json:"included_profiles,omitempty"`
}
Profile defines transformation rules, prompt bindings, and file or directory scopes for a named content mode.
func ResolveProfileChain ¶
ResolveProfileChain resolves ref to a list of profiles whose option overlays are applied in order — earliest first, latest last — to produce the effective options for a run. The last profile in the chain is the target profile; profiles before it are its transitive includes.
ref may be a bare profile name, "path:profile", "path#profile", or "path/to/dir/profile" when the directory contains a config file. When ref names an external config, that file is loaded and its profiles are used; otherwise cfg is used.
Cycles in the include graph are reported as xerr.Conflict. Missing profiles are reported as xerr.NotFound with the available names.
func (Profile) GetIncludeProfiles ¶
GetIncludeProfiles returns IncludeProfile followed by IncludeProfiles, with empty entries dropped.
func (Profile) GetOutputFile ¶
GetOutputFile returns OutputFile, falling back to the legacy Output key.
type ProfileInfo ¶
type ProfileMeta ¶
type ProfileMeta struct {
Name string
Aliases []string
Description string
PromptKey string
Options ConfigOptions
}
ProfileMeta describes one shipped built-in profile. The Options field carries the profile's default overlay; a user override in nexss.srcpack.yml merges on top of it.
func FindBuiltinProfile ¶
func FindBuiltinProfile(name string) (ProfileMeta, bool)
FindBuiltinProfile returns the built-in profile matching name or one of its aliases.
type TargetGroup ¶
type TargetGroup struct {
Name string `yaml:"-" json:"name,omitempty"`
Description string `yaml:"description,omitempty" json:"description,omitempty"`
Paths []string `yaml:"paths,omitempty" json:"paths,omitempty"`
Dir []DirEntry `yaml:"dir,omitempty" json:"dir,omitempty"`
Files []string `yaml:"files,omitempty" json:"files,omitempty"`
Targets []string `yaml:"targets,omitempty" json:"targets,omitempty"`
Prompt FlexibleText `yaml:"prompt,omitempty" json:"prompt,omitzero"`
Header FlexibleText `yaml:"header,omitempty" json:"header,omitzero"`
Options ConfigOptions `yaml:"options,omitempty" json:"options,omitzero"`
}
TargetGroup specifies a named subsystem of directories and explicit files.
type TargetInfo ¶
type UserConfig ¶
type UserConfig struct {
Prompts map[string]string `yaml:"prompts,omitempty"`
Prompt *FlexibleText `yaml:"prompt,omitempty"`
Options *ConfigOptions `yaml:"options,omitempty"`
Editor string `yaml:"editor,omitempty"`
Dir []DirEntry `yaml:"dir,omitempty"`
Targets map[string]TargetGroup `yaml:"targets,omitempty"`
Profiles map[string]Profile `yaml:"profiles,omitempty"`
Editors map[string]EditorFormat `yaml:"editors,omitempty"`
Views map[string][]string `yaml:"views,omitempty"`
}
UserConfig is the raw YAML structure of nexss.srcpack.yml as written by a user. It contains only fields the user actually wrote — no defaults, no built-in profiles. Used exclusively for read-modify- write operations; runtime consumers use Config.
type ValidationIssue ¶
type ValidationIssue struct {
Severity IssueSeverity
Category string
Message string
}
ValidationIssue is one finding from Validate.
type ValidationReport ¶
type ValidationReport struct {
ConfigFile string
Issues []ValidationIssue
Passed bool
}
ValidationReport is the structured result of a config audit.
func Validate ¶
func Validate(cwd, configPath string) ValidationReport
Validate audits a workspace configuration: missing target paths, cycles in target sub-targets, references into _srcpack, and profile prompts that name an undefined prompt. It never fails — problems are reported in the returned report with Passed=false.
func (ValidationReport) String ¶
func (r ValidationReport) String() string