{"content":"# aux4/lint\n\nLinter for .aux4 configuration files. Validates JSON structure, naming conventions, reference integrity, parameter functions, encrypted variables, and best practices.\n\n## Installation\n\n``bash\naux4 aux4 pkger install aux4/lint\n`\n\n## Quick Start\n\n`bash\naux4 lint run\n`\n\nLint a specific directory:\n\n`bash\naux4 lint run --dir ./my-package\n`\n\n## Options\n\n| Flag | Description | Default |\n|------|-------------|---------|\n| --dir | Directory to scan for .aux4 files | . |\n| --format | Output format: text or json | text |\n| --strict | Treat -local versions as errors (for CI/production) | false |\n| --resolve | Resolve aux4 command calls to validate flags and parameters | false |\n\n## Output\n\n### Text (default)\n\nOutput includes ANSI colors, line numbers, and a summary:\n\n`text\n/path/to/package/.aux4\n 2: ERROR [metadata-scope] Invalid 'scope' value '<scope>' — must be lowercase alphanumeric with optional dashes\n 3: ERROR [metadata-name] Invalid 'name' value '<name>' — must be lowercase alphanumeric with optional dashes\n 14: WARN [missing-help] Command 'build' in profile 'main' missing 'help' field\n\n2 errors, 1 warning\n`\n\n### JSON\n\n`bash\naux4 lint run --format json\n`\n\n`json\n{\n \"results\": [\n {\n \"file\": \"/path/to/package/.aux4\",\n \"issues\": [\n {\n \"rule\": \"main-profile\",\n \"severity\": \"error\",\n \"message\": \"Missing required 'main' profile\",\n \"file\": \"/path/to/package/.aux4\",\n \"line\": 7\n }\n ]\n }\n ],\n \"summary\": {\n \"files\": 1,\n \"errors\": 1,\n \"warnings\": 0\n }\n}\n`\n\n## Strict Mode\n\nUse --strict true in CI/production to treat -local version suffixes as errors instead of warnings:\n\n`bash\naux4 lint run --strict true\n`\n\n## Resolve Mode\n\nUse --resolve true to validate aux4 command calls in execute arrays against the installed command signatures via aux4 <cmd> --help --json:\n\n`bash\naux4 lint run --resolve true\n`\n\nThis checks that --flag names passed to aux4 commands match declared parameters. Requires aux4 and target packages to be installed.\n\n## Validation Rules\n\n### Structure\n\n| Rule | Severity | Description |\n|------|----------|-------------|\n| json-valid | error | File contains valid JSON |\n| profiles-required | error | profiles array must exist |\n| main-profile | error | main profile must be defined (skipped for extension packages with colon-notation profiles) |\n| profile-name | error | Every profile must have a name field |\n| profile-commands | error | Every profile must have a commands array |\n| command-name | error | Every command must have a name field |\n| command-execute | error | Every command must have an execute array |\n| command-private | error | private field must be a boolean |\n| duplicate-profile | error | Profile names must be unique |\n| duplicate-command | error | Command names must be unique within a profile |\n| duplicate-variable | error | Variable names must be unique within a command |\n| circular-profile | error | Profile references must not form cycles |\n\n### References\n\n| Rule | Severity | Description |\n|------|----------|-------------|\n| profile-reference | error/warn | profile:x executors must reference existing profiles (warns for cross-package references) |\n| variable-reference | warn | ${var} in execute arrays should reference declared variables (skipped for config-bound commands). Supports dot notation and array indexing (${obj.items[0].name}); shell expansions like ${HOME:-/tmp} are ignored |\n| condition-variable | warn | Variables in if() conditions must be declared |\n\n### Executors\n\n| Rule | Severity | Description |\n|------|----------|-------------|\n| executor-profile | error | profile: must be followed by a profile name |\n| executor-set | error | set: must follow set:varName=value or set:varName=!command format (multiple ;-separated assignments allowed) |\n| executor-each | error | each: must have a command to run for each item in ${response} (e.g. each:echo ${item}) |\n| executor-range | warn | range: must follow range:N or range:start-end format |\n| executor-when | warn | when: must follow when:condition:command format (a missing command silently does nothing) |\n| unknown-executor | warn | Instruction starts with an unrecognized executor prefix |\n| misplaced-executor | warn | Known executor prefix appears mid-instruction instead of at the beginning |\n\nRecognized executor prefixes: profile, set, log, nout, json, each, confirm, stdin, alias, debug, when, range, file, aux4.\n\nExecutor rules apply both to command execute arrays and to hook before/after/error steps.\n\n### Hooks\n\nThe top-level hooks array is validated for structure, and each hook's before/after/error steps are run through the same executor checks as command execute arrays.\n\n| Rule | Severity | Description |\n|------|----------|-------------|\n| hooks-structure | error | hooks must be an array |\n| hook-structure | error | Each hook must be an object |\n| hook-command | error/warn | Hook requires a non-empty command (error); pattern should be profile/command with wildcards (warn) |\n| hook-order | error | order must be an integer |\n| hook-params | error | params must be an object of string values |\n| hook-steps | error | before, after, error must be arrays of strings |\n| hook-empty | warn | Hook should define at least one of before, after, or error |\n| hook-executor | error | profile: and stdin: executors are not allowed in hook steps |\n\n### Parameter Functions\n\n| Rule | Severity | Description |\n|------|----------|-------------|\n| param-function | warn | Variables in value(), values(), param(), params(), object() must be declared |\n| param-multiple | warn | var or var* suffix requires multiple: true on the variable |\n\nSupports value() (all params as JSON), param(name:alias) (flag aliasing), param(name**) (multi-value expansion), and $ prefix stripping.\n\n### Encrypted Variables\n\n| Rule | Severity | Description |\n|------|----------|-------------|\n| encrypted-variable | warn | ${encryptedX} or --encryptedX must have a matching variable x with encrypt: true |\n| encrypt-dependency | warn | Variables with encrypt: true require aux4/encrypter in dependencies |\n\n### Variable Properties\n\n| Rule | Severity | Description |\n|------|----------|-------------|\n| variable-type | error | arg, multiple, hide, encrypt must be boolean; options must be string array; env and default must be strings |\n| multiple-args | warn | Only one variable per command should have arg: true |\n\n### Naming Conventions\n\n| Rule | Severity | Description |\n|------|----------|-------------|\n| naming-profile | warn | Profile names should use dashes, not camelCase |\n| naming-command | warn | Command names should use dashes, not camelCase |\n| naming-variable | warn | Variable names should use camelCase, not dashes (dot notation allowed for nested objects, e.g. setting.timezone) |\n| file-naming | error | Man/test files must use __ for command hierarchy and _ for special characters |\n\n### Metadata\n\n| Rule | Severity | Description |\n|------|----------|-------------|\n| metadata-scope | error | Required when any package field is present; must be lowercase alphanumeric with optional dashes (may start with a digit) |\n| metadata-name | error | Required when any package field is present; must be lowercase alphanumeric with optional dashes (may start with a digit, e.g. 2table) |\n| metadata-version | error | Required when any package field is present; must follow semver |\n| version-local | warn/error | -local version suffix (error with --strict) |\n| metadata-description | error | Must be a string if present |\n| metadata-license | error | Must be a string if present |\n| metadata-git | warn | Should be an HTTPS or git+ssh URL |\n| metadata-tags | error | Must be an array of strings |\n| metadata-dependencies | warn | Should follow scope/name format |\n| metadata-system | error | Must be array of arrays; entries must follow prefix:package format; first entry should be test: |\n| metadata-unknown | warn | Unknown top-level fields |\n\n### Resolve Mode (--resolve)\n\n| Rule | Severity | Description |\n|------|----------|-------------|\n| resolve-flag | warn | --flag passed to an aux4 command must match a declared parameter |\n| resolve-subcommand | warn | Calling a command group without specifying a subcommand |\n\n### Best Practices\n\n| Rule | Severity | Description |\n|------|----------|-------------|\n| unused-profile | warn | Profiles should be referenced by at least one profile:x executor |\n| missing-help | warn | Commands should have a help field |\n| missing-help-text | warn | Help objects should have a text field |\n| missing-variable-text | warn | Variables should have a text field |\n| missing-description | warn | Package metadata should have a description field |\n\n## Config Integration\n\nCommands that declare a config or configFile variable use --config binding, which auto-populates variables from config.yaml at runtime. The linter skips variable-reference and param-function checks for these commands since the variable values come from the config file.\n\n## Extension Packages\n\nPackages that extend a parent package's profile tree (e.g., db:mysql, aux4:releaser) are detected by colon-notation in profile names. For these packages:\n\n- The main-profile check is skipped\n- The first profile is treated as the entry point for unused-profile detection\n- Profile references that look like cross-package references are downgraded to warnings\n\n## Exit Codes\n\n| Code | Meaning |\n|------|---------|\n| 0 | No errors found (warnings may be present) |\n| 1 | One or more errors found |\n\n## Commands\n\n| Command | Description |\n|---------|-------------|\n| aux4 lint run | Run the linter on .aux4` files |\n"}