@sous-io/sous 0.2.36 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -256
- package/dist/bin.js +11 -0
- package/dist/sous.js +1093 -0
- package/docs/markdown/README.md +5 -4
- package/docs/markdown/_sidebar.md +21 -1
- package/docs/markdown/commands.md +294 -431
- package/docs/markdown/config-discovery.md +25 -14
- package/docs/markdown/config-inspection.md +53 -31
- package/docs/markdown/config-layers.md +168 -66
- package/docs/markdown/config-variables.md +44 -11
- package/docs/markdown/configuration.md +104 -17
- package/docs/markdown/design-principles.md +4 -1
- package/docs/markdown/repositories-authoring.md +30 -0
- package/docs/markdown/repositories-consuming.md +72 -14
- package/docs/markdown/repositories-file-formats.md +31 -13
- package/docs/markdown/repositories-providers.md +48 -57
- package/docs/markdown/repositories-quickstart.md +3 -2
- package/docs/markdown/repositories-troubleshooting.md +27 -1
- package/docs/markdown/repositories-variables.md +6 -1
- package/docs/markdown/repositories.md +18 -8
- package/package.json +48 -107
- package/recipes/core/sous-skills/skills/about-liquid-templates/SKILL.tpl.md +4 -6
- package/recipes/core/sous-skills/skills/about-liquid-templates/references/liquid-filters.tpl.md +2 -0
- package/recipes/core/sous-skills/skills/about-sous/SKILL.tpl.md +10 -9
- package/recipes/core/sous-skills/skills/about-sous-configuration/SKILL.tpl.md +35 -14
- package/recipes/core/sous-skills/skills/about-sous-recipes/SKILL.tpl.md +51 -20
- package/recipes/core/sous-skills/sous.recipe.yaml +1 -1
- package/sous.config.schema.json +351 -132
- package/bin/run.js +0 -51
- package/src/base-command.ts +0 -457
- package/src/commands/build.ts +0 -181
- package/src/commands/clear.ts +0 -79
- package/src/commands/compile.ts +0 -155
- package/src/commands/config/get.ts +0 -110
- package/src/commands/config/show.ts +0 -32
- package/src/commands/config/validate.ts +0 -53
- package/src/commands/help.ts +0 -46
- package/src/commands/init.ts +0 -289
- package/src/commands/launch.ts +0 -139
- package/src/commands/lock/rebuild.ts +0 -239
- package/src/commands/lock/show.ts +0 -115
- package/src/commands/namespace/list.ts +0 -138
- package/src/commands/namespace/show.ts +0 -130
- package/src/commands/prune.ts +0 -43
- package/src/commands/recipe/list.ts +0 -112
- package/src/commands/recipe/show.ts +0 -439
- package/src/commands/repo/add.ts +0 -145
- package/src/commands/repo/contribute.ts +0 -604
- package/src/commands/repo/gc.ts +0 -173
- package/src/commands/repo/init.ts +0 -136
- package/src/commands/repo/link.ts +0 -899
- package/src/commands/repo/list.ts +0 -236
- package/src/commands/repo/release.ts +0 -685
- package/src/commands/repo/remove.ts +0 -194
- package/src/commands/repo/search.ts +0 -243
- package/src/commands/repo/submit.ts +0 -341
- package/src/commands/repo/unlink.ts +0 -461
- package/src/commands/subscription/add.ts +0 -286
- package/src/commands/subscription/list.ts +0 -208
- package/src/commands/subscription/remove.ts +0 -182
- package/src/commands/subscription/update.ts +0 -216
- package/src/commands/update.ts +0 -178
- package/src/commands/vars/ask.ts +0 -417
- package/src/commands/vars/index.ts +0 -79
- package/src/commands/vars/list.ts +0 -67
- package/src/commands/vars/show.ts +0 -77
- package/src/config-command.ts +0 -30
- package/src/lib/build-preparation.ts +0 -128
- package/src/lib/build-service.ts +0 -580
- package/src/lib/config-discovery.ts +0 -378
- package/src/lib/config-inspect.ts +0 -145
- package/src/lib/config-kernel.mjs +0 -379
- package/src/lib/config-schema.ts +0 -401
- package/src/lib/env-file.ts +0 -328
- package/src/lib/env-local.ts +0 -212
- package/src/lib/errors.ts +0 -32
- package/src/lib/glob-pattern.ts +0 -24
- package/src/lib/include-resolver.ts +0 -523
- package/src/lib/interactive.ts +0 -165
- package/src/lib/markdown-compiler.ts +0 -947
- package/src/lib/package-info.ts +0 -25
- package/src/lib/pid-service.ts +0 -99
- package/src/lib/project-install.d.mts +0 -44
- package/src/lib/project-install.mjs +0 -234
- package/src/lib/project-scaffold/index.ts +0 -332
- package/src/lib/project-scaffold/templates.ts +0 -240
- package/src/lib/repos/catalog-display.ts +0 -215
- package/src/lib/repos/catalog-inputs.ts +0 -288
- package/src/lib/repos/catalog.ts +0 -842
- package/src/lib/repos/contribute.ts +0 -452
- package/src/lib/repos/core-recipe.ts +0 -105
- package/src/lib/repos/declarations.ts +0 -187
- package/src/lib/repos/defaults.ts +0 -175
- package/src/lib/repos/formats/common.ts +0 -440
- package/src/lib/repos/formats/index-file.ts +0 -253
- package/src/lib/repos/formats/links-map.ts +0 -98
- package/src/lib/repos/formats/lockfile.ts +0 -169
- package/src/lib/repos/formats/patterns.ts +0 -57
- package/src/lib/repos/formats/recipe-manifest.ts +0 -205
- package/src/lib/repos/formats/repo-manifest.ts +0 -97
- package/src/lib/repos/formats/store-entry.ts +0 -84
- package/src/lib/repos/formats/variable-definition.ts +0 -268
- package/src/lib/repos/freshness.ts +0 -264
- package/src/lib/repos/git-clone.ts +0 -850
- package/src/lib/repos/identity.ts +0 -89
- package/src/lib/repos/index.ts +0 -57
- package/src/lib/repos/links.ts +0 -356
- package/src/lib/repos/load-manifest.ts +0 -237
- package/src/lib/repos/lock-service.ts +0 -454
- package/src/lib/repos/locked-namespace-resolver.ts +0 -232
- package/src/lib/repos/locked-recipe-lookup.ts +0 -123
- package/src/lib/repos/locked-recipes.ts +0 -254
- package/src/lib/repos/managed-layer.ts +0 -422
- package/src/lib/repos/memories-hash-name.ts +0 -33
- package/src/lib/repos/namespace-resolver.ts +0 -527
- package/src/lib/repos/providers/base.ts +0 -268
- package/src/lib/repos/providers/git.ts +0 -237
- package/src/lib/repos/providers/github.ts +0 -589
- package/src/lib/repos/providers/gitlab.ts +0 -332
- package/src/lib/repos/providers/http.ts +0 -128
- package/src/lib/repos/providers/index-cache.ts +0 -421
- package/src/lib/repos/providers/index.ts +0 -106
- package/src/lib/repos/providers/local.ts +0 -391
- package/src/lib/repos/providers/provider.ts +0 -615
- package/src/lib/repos/recipe-config-layers.ts +0 -316
- package/src/lib/repos/recipe-key-matcher.ts +0 -62
- package/src/lib/repos/recipe-memories.ts +0 -178
- package/src/lib/repos/recipe-targets.ts +0 -236
- package/src/lib/repos/ref-search.ts +0 -46
- package/src/lib/repos/release/bump.ts +0 -161
- package/src/lib/repos/release/changelog.ts +0 -461
- package/src/lib/repos/release/git-state.ts +0 -460
- package/src/lib/repos/release/index-builder.ts +0 -1108
- package/src/lib/repos/release/index.ts +0 -19
- package/src/lib/repos/release/plan.ts +0 -521
- package/src/lib/repos/release/settle.ts +0 -154
- package/src/lib/repos/release/submissions.ts +0 -214
- package/src/lib/repos/release/submit-checkout.ts +0 -290
- package/src/lib/repos/release/submit-questions.ts +0 -153
- package/src/lib/repos/release/submit-service.ts +0 -898
- package/src/lib/repos/release/tags.ts +0 -239
- package/src/lib/repos/release/validate.ts +0 -463
- package/src/lib/repos/resolver.ts +0 -1028
- package/src/lib/repos/scaffold/index.ts +0 -245
- package/src/lib/repos/scaffold/templates.ts +0 -517
- package/src/lib/repos/seed.ts +0 -473
- package/src/lib/repos/store/contract.ts +0 -64
- package/src/lib/repos/store/hash.ts +0 -191
- package/src/lib/repos/store/recipe-store.ts +0 -599
- package/src/lib/repos/store/settings.ts +0 -58
- package/src/lib/repos/subscription-service.ts +0 -3859
- package/src/lib/repos/trust.ts +0 -447
- package/src/lib/repos/update-plan.ts +0 -235
- package/src/lib/self-update/index.ts +0 -14
- package/src/lib/self-update/installs.ts +0 -412
- package/src/lib/self-update/managers.ts +0 -126
- package/src/lib/self-update/plan.ts +0 -315
- package/src/lib/self-update/registry.ts +0 -99
- package/src/lib/self-update/run.ts +0 -506
- package/src/lib/self-update/versions.ts +0 -243
- package/src/lib/settings.ts +0 -1105
- package/src/lib/sous-home.ts +0 -104
- package/src/lib/state.ts +0 -167
- package/src/lib/vars/answers.ts +0 -192
- package/src/lib/vars/ask.ts +0 -1152
- package/src/lib/vars/definition-source.ts +0 -261
- package/src/lib/vars/display.ts +0 -231
- package/src/lib/vars/index.ts +0 -20
- package/src/lib/vars/ladder.ts +0 -282
- package/src/lib/vars/mappings.ts +0 -260
- package/src/lib/vars/names.ts +0 -94
- package/src/lib/vars/preanswers.ts +0 -395
- package/src/lib/vars/question-plan.ts +0 -241
- package/src/lib/vars/report.ts +0 -228
- package/src/lib/vars/safe-regex.ts +0 -235
- package/src/lib/vars/secrets.ts +0 -131
- package/src/lib/vars/validate.ts +0 -312
- package/src/lib/version-report.ts +0 -90
- package/src/lib/watch-loop.ts +0 -148
- package/src/lib/watch-service.ts +0 -116
- package/src/services/ref-resolver/container.ts +0 -107
- package/src/services/ref-resolver/dependency.ts +0 -60
- package/src/services/ref-resolver/format.ts +0 -197
- package/src/services/ref-resolver/glob.ts +0 -115
- package/src/services/ref-resolver/hash-names.ts +0 -155
- package/src/services/ref-resolver/index.ts +0 -55
- package/src/services/ref-resolver/injectable.ts +0 -36
- package/src/services/ref-resolver/location.ts +0 -62
- package/src/services/ref-resolver/lookups/cached-index-lookup.ts +0 -53
- package/src/services/ref-resolver/lookups/catalog-lookup.ts +0 -23
- package/src/services/ref-resolver/lookups/catalog-matcher.ts +0 -261
- package/src/services/ref-resolver/lookups/chained-lookup.ts +0 -27
- package/src/services/ref-resolver/lookups/env-var-lookup.ts +0 -65
- package/src/services/ref-resolver/lookups/fetched-index-lookup.ts +0 -150
- package/src/services/ref-resolver/lookups/recorded-dependency-lookup.ts +0 -62
- package/src/services/ref-resolver/lookups/ref-lookup.ts +0 -54
- package/src/services/ref-resolver/lookups/variable-lookup.ts +0 -123
- package/src/services/ref-resolver/named-refs.ts +0 -144
- package/src/services/ref-resolver/parser/env-var-splitter.ts +0 -27
- package/src/services/ref-resolver/parser/location-splitter.ts +0 -239
- package/src/services/ref-resolver/parser/name-path-splitter.ts +0 -200
- package/src/services/ref-resolver/parser/partial-ref.ts +0 -84
- package/src/services/ref-resolver/parser/query-splitter.ts +0 -61
- package/src/services/ref-resolver/parser/range-splitter.ts +0 -52
- package/src/services/ref-resolver/parser/ref-parser.ts +0 -115
- package/src/services/ref-resolver/parser/repo-qualifier-splitter.ts +0 -51
- package/src/services/ref-resolver/parts.ts +0 -115
- package/src/services/ref-resolver/pruners/command-line-pruner.ts +0 -47
- package/src/services/ref-resolver/pruners/include-pruner.ts +0 -66
- package/src/services/ref-resolver/pruners/manifest-pruner.ts +0 -130
- package/src/services/ref-resolver/pruners/ref-pruner.ts +0 -135
- package/src/services/ref-resolver/pruners/rule-helpers.ts +0 -44
- package/src/services/ref-resolver/pruners/stored-key-pruner.ts +0 -136
- package/src/services/ref-resolver/ref-helpers.ts +0 -62
- package/src/services/ref-resolver/ref-picker-service.ts +0 -204
- package/src/services/ref-resolver/ref-report.ts +0 -84
- package/src/services/ref-resolver/ref-resolve-arguments.ts +0 -47
- package/src/services/ref-resolver/ref-resolve-result.ts +0 -36
- package/src/services/ref-resolver/ref-resolver-service.ts +0 -323
- package/src/services/ref-resolver/source.ts +0 -48
- package/src/services/ref-resolver/tokens.ts +0 -25
- package/src/services/ref-resolver/types.ts +0 -155
- package/src/templating/filters/bullet-list.ts +0 -9
- package/src/templating/filters/index.ts +0 -8
- package/src/templating/init-liquid-engine.ts +0 -139
- package/src/templating/lib/glob-files.ts +0 -74
- package/src/templating/lib/import-export.ts +0 -32
- package/src/templating/lib/secret-scope.ts +0 -41
- package/src/templating/lib/tag-args.ts +0 -19
- package/src/templating/tags/exportScalarVarsJs.ts +0 -46
- package/src/templating/tags/getFiles.ts +0 -89
- package/src/templating/tags/index.ts +0 -14
- package/src/templating/tags/listFiles.ts +0 -54
- package/src/templating/tags/showVars.ts +0 -28
- package/src/utils/choice-prompt.ts +0 -143
- package/src/utils/command-errors.ts +0 -186
- package/src/utils/command-help.ts +0 -45
- package/src/utils/confirm-prompt.ts +0 -110
- package/src/utils/flags.ts +0 -177
- package/src/utils/formatting.ts +0 -849
- package/src/utils/prompts.ts +0 -53
- package/src/utils/sous-directory.ts +0 -245
- package/src/utils/table.ts +0 -603
- package/src/utils/value-prompt.ts +0 -119
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
# Discovery and Overrides
|
|
2
2
|
|
|
3
3
|
How sous locates a project's configuration, and every way to override it. Discovery runs on
|
|
4
|
-
every command; there is no opt-out.
|
|
4
|
+
every command; there is no opt-out. It runs once, when sous starts, and finds exactly one project:
|
|
5
|
+
every sous process (a CLI run, watch mode, or `sous mcp` for its whole life) serves the project it
|
|
6
|
+
started in.
|
|
5
7
|
|
|
6
8
|
## Locating the primary config
|
|
7
9
|
|
|
@@ -14,10 +16,19 @@ Precedence, highest first. Flags beat env vars; both beat walk-up discovery:
|
|
|
14
16
|
5. Walk UP from the working directory to the filesystem root, taking the first `.sous/`
|
|
15
17
|
directory that holds a primary config. A `.sous/` without one does not stop the walk.
|
|
16
18
|
|
|
17
|
-
A primary config is named `sous.config.js`, `sous.config.mjs`, `sous.config.
|
|
18
|
-
`sous.config.jsonc` or `sous.config.yaml`. The `.jsonc` form is JSON with comments: line comments,
|
|
19
|
+
A primary config is named `sous.config.js`, `sous.config.mjs`, `sous.config.ts`,
|
|
20
|
+
`sous.config.json`, `sous.config.jsonc` or `sous.config.yaml`. The `.jsonc` form is JSON with comments: line comments,
|
|
19
21
|
block comments and trailing commas are all allowed in it.
|
|
20
22
|
|
|
23
|
+
## The project root
|
|
24
|
+
|
|
25
|
+
The project root is the directory that holds the `.sous/` directory the config was found in. When
|
|
26
|
+
`--config` names a file outside any `.sous/`, the root is the parent of the directory holding that
|
|
27
|
+
file. A project cannot set its root anywhere else: sous publishes it as the auto-variable
|
|
28
|
+
`${projectRoot}`, and setting `projectRoot` in any `_vars` block is an error.
|
|
29
|
+
|
|
30
|
+
## How a location value is read
|
|
31
|
+
|
|
21
32
|
Every flag or env value resolves with the same rules. It may point at:
|
|
22
33
|
|
|
23
34
|
- a config file directly,
|
|
@@ -29,22 +40,22 @@ bare `export SOUS_CONFIG=`) is treated as unset and falls through to the next ti
|
|
|
29
40
|
hijacks resolution. Error messages name the source that was actually set (`--sous-dir`,
|
|
30
41
|
`SOUS_CONFIG`, and so on), not a generic flag.
|
|
31
42
|
|
|
32
|
-
## Locating the conf.d
|
|
43
|
+
## Locating the conf.d directory
|
|
33
44
|
|
|
34
45
|
Precedence: `--sous-confd <path>` flag, then `SOUS_CONFD` env var, then the default
|
|
35
|
-
`<sousDir>/conf.d`. An override
|
|
36
|
-
|
|
46
|
+
`<sousDir>/conf.d`. An override applies everywhere the default would: finding the `conf.d` files,
|
|
47
|
+
the check for file names that differ only by extension (below), and reloading in watch mode.
|
|
37
48
|
|
|
38
49
|
## Env file layering
|
|
39
50
|
|
|
40
|
-
After discovery, sous
|
|
41
|
-
|
|
51
|
+
After discovery, sous reads two optional files from the discovered `.sous/` into the environment
|
|
52
|
+
every plugin sees:
|
|
42
53
|
|
|
43
54
|
- `.env.local`: gitignored; machine-specific values and secrets
|
|
44
55
|
- `.env`: committed; team-shared defaults
|
|
45
56
|
|
|
46
57
|
Load order is `.env.local` first, then `.env`, and no load ever overwrites a value that is
|
|
47
|
-
already set. Effective precedence is therefore: real shell environment, then `.env.local`, then
|
|
58
|
+
already set. Config expressions read the result as `env.<NAME>`. Effective precedence is therefore: real shell environment, then `.env.local`, then
|
|
48
59
|
`.env`. The syntax is deliberately small (not a shell): `KEY=value` lines, `#` comments, an
|
|
49
60
|
optional `export ` prefix, single or double quoted values (`\n` and `\t` expand inside double
|
|
50
61
|
quotes), and inline `# comment` stripped from unquoted values. Lines without `=` are ignored.
|
|
@@ -60,12 +71,12 @@ All are hard `ConfigError`s; sous never guesses:
|
|
|
60
71
|
- **No config found**: the error lists every directory checked during the walk and names the two
|
|
61
72
|
fixes: run `sous init` in the project's root directory, which writes the config and everything
|
|
62
73
|
else a first build needs, or pass `--config <path>`.
|
|
63
|
-
- **Multiple primary configs**: two or more of `sous.config.js|mjs|json|jsonc|yaml` in the same
|
|
74
|
+
- **Multiple primary configs**: two or more of `sous.config.js|mjs|ts|json|jsonc|yaml` in the same
|
|
64
75
|
`.sous/` is an error naming every candidate.
|
|
65
|
-
- **
|
|
66
|
-
only by extension is an error naming both files, because their merge order would
|
|
67
|
-
depend on extension. `500-repos.json` and `500-repos.jsonc` collide for the same reason, which
|
|
68
|
-
is what keeps a
|
|
76
|
+
- **Names that differ only by extension**: any two loaded files (primary or conf.d) whose names
|
|
77
|
+
differ only by extension is an error naming both files, because their merge order would
|
|
78
|
+
otherwise depend on the extension. `500-repos.json` and `500-repos.jsonc` collide for the same reason, which
|
|
79
|
+
is what keeps a file sous is migrating to `.jsonc` from being loaded twice.
|
|
69
80
|
|
|
70
81
|
## Interaction with `sous launch` pass-through
|
|
71
82
|
|
|
@@ -2,42 +2,60 @@
|
|
|
2
2
|
|
|
3
3
|
## The validation pipeline
|
|
4
4
|
|
|
5
|
-
Every command validates the config
|
|
5
|
+
Every command builds and validates the config before it does its work, in this order:
|
|
6
6
|
|
|
7
|
-
1.
|
|
8
|
-
|
|
7
|
+
1. Sous builds the config from every file, recipe and plugin (any config file failure names the
|
|
8
|
+
file; see [Layers and merging](config-layers.md)). Config expressions are evaluated as each file
|
|
9
|
+
is applied.
|
|
10
|
+
2. A check for the old config format rejects the removed multi-project keys (`projects`,
|
|
9
11
|
`defaultProject`) with a migration message.
|
|
10
|
-
3.
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
version
|
|
12
|
+
3. The built config is checked against the schema of every config key. Each plugin declares the
|
|
13
|
+
keys it reads, with their schema and defaults, so a key no loaded plugin declares is unknown.
|
|
14
|
+
Unknown keys at ANY level are rejected with the full path and a typo hint; a target must have
|
|
15
|
+
exactly one of `entryPoint`, `entryGlob` or `content`; `version`, when present, must be `1`
|
|
16
|
+
(anything else fails as unsupported by this sous version). Validation runs after values
|
|
17
|
+
resolve, so a value built from a variable is checked.
|
|
14
18
|
4. Variable resolution and substitution run as values are used; `sous config validate` runs them
|
|
15
19
|
eagerly (below).
|
|
16
20
|
|
|
17
|
-
Validation applies to the
|
|
18
|
-
|
|
21
|
+
Validation applies to the BUILT config only. A `conf.d/` file on its own does not need to be a
|
|
22
|
+
complete config; it only needs to use known keys.
|
|
19
23
|
|
|
20
24
|
## The JSON Schema artifact
|
|
21
25
|
|
|
22
|
-
Sous ships `sous.config.schema.json` at the package root
|
|
23
|
-
|
|
24
|
-
tooling:
|
|
26
|
+
Sous ships `sous.config.schema.json` at the package root, for editor autocompletion and external
|
|
27
|
+
tooling. A JSON config can bind it:
|
|
25
28
|
|
|
26
29
|
```json
|
|
27
30
|
{ "$schema": "./path/to/sous.config.schema.json" }
|
|
28
31
|
```
|
|
29
32
|
|
|
30
|
-
The `$schema` key is accepted at the top level and ignored by sous itself.
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
33
|
+
The `$schema` key is accepted at the top level and ignored by sous itself. Point it at the
|
|
34
|
+
package-local copy, or at the artifact published on GitHub for the version you run.
|
|
35
|
+
|
|
36
|
+
?> Because each plugin declares its own config keys, the published schema file may not know a key
|
|
37
|
+
that a plugin adds. An editor may flag such a key even though sous accepts it; `sous config validate`
|
|
38
|
+
is the check that counts.
|
|
34
39
|
|
|
35
40
|
## sous config show
|
|
36
41
|
|
|
37
|
-
Prints the full
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
42
|
+
Prints the full built config as pretty JSON, with config expressions evaluated: what sous will do on
|
|
43
|
+
this machine. Output is machine-readable by contract: the decorative header and any error text go to
|
|
44
|
+
stderr, so `sous config show | jq .` always receives either valid JSON or nothing. Colorized only
|
|
45
|
+
when stdout is a TTY.
|
|
46
|
+
|
|
47
|
+
- `--layers` shows each change, in order, and what made it (a file, a recipe or a plugin): for a
|
|
48
|
+
config file, the expression as written, what it evaluated to and the values it read; for code,
|
|
49
|
+
each builder operation it ran and the primitive patches it made
|
|
50
|
+
([Patches](config-layers.md#patches) explains both). It ends with the result and the number of passes the config took to
|
|
51
|
+
settle.
|
|
52
|
+
- `--raw` prints each config file as written, in order.
|
|
53
|
+
|
|
54
|
+
```text
|
|
55
|
+
confd/620-no-diagrams.js
|
|
56
|
+
removeWhere compilation.targets ← a builder operation
|
|
57
|
+
removeIndex compilation.targets[7] ← a primitive patch
|
|
58
|
+
```
|
|
41
59
|
|
|
42
60
|
## sous config get
|
|
43
61
|
|
|
@@ -51,22 +69,26 @@ sous config get compilation.targets[0].entryPoint
|
|
|
51
69
|
Scalars print raw (no quotes); objects and arrays print as pretty JSON. A missing path exits
|
|
52
70
|
non-zero with a message on stderr.
|
|
53
71
|
|
|
54
|
-
`--layers` adds
|
|
55
|
-
that path,
|
|
56
|
-
This answers "which file set this?" directly:
|
|
72
|
+
`--layers` adds where the value came from: every file, recipe or plugin that changed the value at
|
|
73
|
+
that path, in order, with its change. This answers "which file or plugin set this?" directly:
|
|
57
74
|
|
|
58
|
-
```
|
|
59
|
-
sous config get
|
|
75
|
+
```text
|
|
76
|
+
$ sous config get subscriptions."tool-usage/automated-browser-tasks".enabled --layers
|
|
77
|
+
conf.d/510-subscriptions.jsonc (not set)
|
|
78
|
+
conf.d/610-mac.jsonc { "$if": { "expr": "host.platform == 'darwin'", "then": false } }
|
|
79
|
+
→ false (host.platform = "darwin")
|
|
80
|
+
result false (settled after 1 pass)
|
|
60
81
|
```
|
|
61
82
|
|
|
83
|
+
`sous plugins show` lists every plugin and what it adds or replaces, and `--timings` on any command
|
|
84
|
+
prints how long each step took, each config file included.
|
|
85
|
+
|
|
62
86
|
## sous config validate
|
|
63
87
|
|
|
64
|
-
Runs
|
|
88
|
+
Runs every check above at once: discovery, the config build, the old-format check, schema, then FULL
|
|
65
89
|
variable resolution including compilation, tools and watch config. This surfaces the errors
|
|
66
90
|
schema validation alone cannot: variable cycles, undefined `${refs}`, and bad substitutions in
|
|
67
|
-
entry points and destinations. On success it prints a short summary
|
|
68
|
-
target count, tools) and exits 0; on failure it prints the `ConfigError` and exits non-zero.
|
|
91
|
+
entry points and destinations. On success it prints a short summary of the config and exits 0; on failure it prints the `ConfigError` and exits non-zero.
|
|
69
92
|
|
|
70
|
-
All three commands honor the same config-locating flags and env vars as every other command
|
|
71
|
-
(
|
|
72
|
-
`SOUS_CONFD`); see [Discovery and overrides](config-discovery.md).
|
|
93
|
+
All three commands honor the same config-locating flags and env vars as every other command; see
|
|
94
|
+
[Discovery and overrides](config-discovery.md).
|
|
@@ -1,92 +1,194 @@
|
|
|
1
1
|
# Layers and Merging
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
Sous builds one config for a project from many sources: the primary `sous.config.*` file, each
|
|
4
|
+
file in `conf.d/`, the config files recipes ship, the entries sous adds itself (the official
|
|
5
|
+
repository and the `core` subscription), and any plugin that changes the config. Sous combines
|
|
6
|
+
them all before any command does its work, and again after a command that changed the config.
|
|
6
7
|
|
|
7
|
-
##
|
|
8
|
+
## Which files are read
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
by filename. The sort is locale-independent and per-machine stable, but it is not numeric:
|
|
12
|
-
`10-a.json` sorts before `2-b.json` because the character `1` precedes `2`. Zero-pad numeric
|
|
13
|
-
prefixes (`02-`, `10-`) when ordering matters.
|
|
10
|
+
- The primary `sous.config.*` file in `.sous/`.
|
|
11
|
+
- Every file directly inside `conf.d/` (not its subdirectories).
|
|
14
12
|
|
|
15
|
-
A `.jsonc`
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
A `.json`, `.jsonc` or `.yaml` file is parsed; a `.js`, `.mjs` or `.ts` file is imported in
|
|
14
|
+
the sous process itself. A `.jsonc` file is JSON with comments: line comments, block comments and
|
|
15
|
+
trailing commas are all allowed in it. A file is read from disk once per build.
|
|
18
16
|
|
|
19
|
-
##
|
|
17
|
+
## Load order, and why your files win
|
|
20
18
|
|
|
21
|
-
|
|
19
|
+
The `conf.d/` files are applied after the primary config, in the order of the number each name
|
|
20
|
+
starts with. Files with the same number are applied in filename order (bytewise, the same on every
|
|
21
|
+
machine), and a file whose name starts with no number is applied as if it were numbered 500; a number above 9999 counts as 9999:
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
```text
|
|
24
|
+
plugins and recipes → sous.config.* → conf.d/500-repos → conf.d/510-subscriptions → conf.d/610-mac
|
|
25
|
+
```
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
Give every file a number of the same length (three digits, as the files sous writes have) so the
|
|
28
|
+
order is obvious from a directory listing.
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
Your files are applied last, after every plugin and recipe. Whenever a plugin or a recipe's config
|
|
31
|
+
file changes the config, sous applies your `sous.config.*` and `conf.d` files again after it. So
|
|
32
|
+
when a plugin or a recipe sets a key that one of your files also sets, your value wins:
|
|
31
33
|
|
|
32
|
-
|
|
34
|
+
```js
|
|
35
|
+
// .sous/sous.config.js (excerpt)
|
|
36
|
+
export const config = {
|
|
37
|
+
compilation: {
|
|
38
|
+
includeSourceComments: false,
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
If a plugin sets `compilation.includeSourceComments` to `true`, the result is still `false`. In a
|
|
44
|
+
project whose files do not set it, the result is `true`.
|
|
45
|
+
|
|
46
|
+
Sous repeats this until nothing changes. A file that is applied again never doubles its own array
|
|
47
|
+
items. A config that never settles (two files that keep changing a value the other reads, for
|
|
48
|
+
example) stops sous with a `ConfigError` naming the values that kept changing and where each change
|
|
49
|
+
came from. Validation runs last, after variables resolve.
|
|
50
|
+
|
|
51
|
+
## Merge semantics
|
|
52
|
+
|
|
53
|
+
A config file is merged key by key into the config built so far:
|
|
33
54
|
|
|
34
55
|
- plain object + plain object: recurse
|
|
35
|
-
- array + array: CONCATENATE,
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
56
|
+
- array + array: CONCATENATE, existing items first, the file's second. Duplicates are kept.
|
|
57
|
+
- anything else (scalar, mixed types, null): the later file replaces
|
|
58
|
+
- an own `__proto__`, `constructor`, or `prototype` key in file data is skipped
|
|
59
|
+
|
|
60
|
+
To remove or replace an array item without code, write a [patch file](#patch-files).
|
|
61
|
+
|
|
62
|
+
## Plain JSON data
|
|
63
|
+
|
|
64
|
+
The config is always plain JSON data, so `sous config show` can print it exactly. Every value passes
|
|
65
|
+
through a JSON round-trip: functions and `undefined` values are dropped, and a regular expression is
|
|
66
|
+
written as a string `/.../`. [Config expressions](configuration.md#config-expressions) rely on
|
|
67
|
+
`undefined` values being dropped.
|
|
68
|
+
|
|
69
|
+
## JavaScript and TypeScript files
|
|
70
|
+
|
|
71
|
+
A `.js`, `.mjs` or `.ts` config file may export plain data (`export const config = {...}`, or a
|
|
72
|
+
default export that is an object), which is merged like a JSON file. It may also export
|
|
73
|
+
`configure(config)`, which is given a builder object for changing the config:
|
|
74
|
+
|
|
75
|
+
```js
|
|
76
|
+
// .sous/conf.d/620-no-diagrams.js
|
|
77
|
+
export function configure(config) {
|
|
78
|
+
config.atPath("compilation.targets").removeWhere((target) => target.id === "diagrams");
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
`configure` runs again whenever sous applies the file again, so it must give the same result for
|
|
83
|
+
the same input. When a `.js` file changes on disk during watch mode, it is imported again.
|
|
84
|
+
|
|
85
|
+
Some of the builder's operations (the full list, with each one's documentation, is the `DocumentNode`
|
|
86
|
+
type in `packages/plugin-api/src/node.ts`):
|
|
87
|
+
|
|
88
|
+
```js
|
|
89
|
+
const node = config.atPath("compilation.targets");
|
|
90
|
+
|
|
91
|
+
// Inspecting
|
|
92
|
+
node.exists();
|
|
93
|
+
node.type(); // "object" | "array" | "string" | "number" | "boolean" | "null"
|
|
94
|
+
node.isArray();
|
|
95
|
+
node.isObject();
|
|
96
|
+
node.get();
|
|
97
|
+
node.valueOr(fallback);
|
|
98
|
+
|
|
99
|
+
// Objects and values
|
|
100
|
+
node.set(value);
|
|
101
|
+
node.delete();
|
|
102
|
+
node.rename("newKey");
|
|
103
|
+
node.merge(object); // key by key; arrays joined
|
|
104
|
+
node.replace(object); // whole
|
|
105
|
+
config.atPath("tools").keys();
|
|
106
|
+
|
|
107
|
+
// Arrays
|
|
108
|
+
node.append(item);
|
|
109
|
+
node.prepend(item);
|
|
110
|
+
node.insertAt(2, item);
|
|
111
|
+
node.removeAt(2);
|
|
112
|
+
node.removeWhere((target) => target.id === "diagrams");
|
|
113
|
+
node.upsertWhere((target) => target.id === "diagrams", item); // replace the match, or append
|
|
114
|
+
node.findWhere((target) => target.id === "diagrams"); // a node for the match, to edit in place
|
|
115
|
+
node.atIndex(0);
|
|
116
|
+
node.move(from, to);
|
|
117
|
+
node.dedupe();
|
|
118
|
+
|
|
119
|
+
// The whole config
|
|
120
|
+
config.root().merge(data);
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
?> A `configure(currentConfig, builder)` written for sous 0.2.x, which changes `currentConfig` in
|
|
124
|
+
place and calls the old builder (`builder.merge`, `builder.loadConfig`, `builder.loadConfigs`,
|
|
125
|
+
`builder.env`), keeps working. Sous records what it changed like any other change.
|
|
126
|
+
|
|
127
|
+
## Patches
|
|
128
|
+
|
|
129
|
+
Every change to the config, from a file, a recipe or a plugin, ends up as primitive operations,
|
|
130
|
+
each called a patch:
|
|
131
|
+
|
|
132
|
+
| `op` | What it does |
|
|
133
|
+
| --- | --- |
|
|
134
|
+
| `setKey` | sets one key of an object |
|
|
135
|
+
| `deleteKey` | deletes one key of an object |
|
|
136
|
+
| `renameKey` | renames one key of an object |
|
|
137
|
+
| `setIndex` | sets one item of an array |
|
|
138
|
+
| `insertAt` | inserts one item into an array |
|
|
139
|
+
| `removeIndex` | removes one item from an array |
|
|
140
|
+
|
|
141
|
+
Every other builder operation is built from these. `removeWhere` above, for example, records one
|
|
142
|
+
`removeIndex` per matching item. `sous config show --layers` shows both: each operation a file or
|
|
143
|
+
plugin ran, and the patches it made.
|
|
144
|
+
|
|
145
|
+
### Patch files
|
|
146
|
+
|
|
147
|
+
A file of raw patches can sit in `conf.d/` or beside `sous.config.*`:
|
|
148
|
+
|
|
149
|
+
- A `.patch.json` file holds one patch, unless its top-level object has a single key, `$patches`,
|
|
150
|
+
holding an array: then each item is a patch.
|
|
151
|
+
- A `.patch.jsonl` file holds one patch per line, so a tool or an agent can add a line without
|
|
152
|
+
parsing the file.
|
|
153
|
+
|
|
154
|
+
```jsonc
|
|
155
|
+
// .sous/conf.d/720-my-special-thing.patch.json: several patches, so a single $patches key
|
|
156
|
+
{
|
|
157
|
+
"$patches": [
|
|
158
|
+
{ "op": "setKey", "path": "compilation", "key": "overwriteUntracked", "value": false },
|
|
159
|
+
{ "op": "deleteKey", "path": "tools", "key": "codex" }
|
|
160
|
+
]
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
```jsonl
|
|
165
|
+
// .sous/conf.d/721-my-list-of-things.patch.jsonl: one patch per line
|
|
166
|
+
{"op": "insertAt", "path": "compilation.targets", "index": 0, "value": {"id": "first", "entryPoint": "a.tpl.md"}}
|
|
167
|
+
{"op": "setKey", "path": "_vars", "key": "machineRole", "value": "laptop"}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
!> An index written in a patch file is never recomputed: `removeIndex 7` removes whatever is at
|
|
171
|
+
index 7 at that point. Use patch files for arrays only when you know the order the files, recipes and
|
|
172
|
+
plugins before it apply in. Key and path operations have no such catch.
|
|
73
173
|
|
|
74
174
|
## Failure behavior
|
|
75
175
|
|
|
76
|
-
Any
|
|
77
|
-
|
|
78
|
-
|
|
176
|
+
Any config file failure (a JSON/YAML parse error, an import error, a `configure` throw) halts sous
|
|
177
|
+
with a `ConfigError` naming the file. There is no warn-and-skip; a broken file never silently drops
|
|
178
|
+
out of the config.
|
|
79
179
|
|
|
80
180
|
## The managed 5xx layer band
|
|
81
181
|
|
|
82
|
-
`conf.d/500-*` through `conf.d/599-*` is reserved for
|
|
83
|
-
They are `.jsonc`, and each one opens with a header comment saying what it holds.
|
|
182
|
+
`conf.d/500-*` through `conf.d/599-*` is reserved for files the sous CLI writes on your behalf.
|
|
183
|
+
They are `.jsonc`, and each one opens with a header comment saying what it holds. They are ordinary
|
|
184
|
+
config files, merged like any other: sous always reads the built config, never one file on its own.
|
|
84
185
|
|
|
85
186
|
**Sous edits these files by key; you may edit them too.** A write rewrites only the bytes of the
|
|
86
187
|
entry that changes, so your comments, your key order and your formatting survive it, and repeated
|
|
87
188
|
edits produce minimal version-control diffs. Sous never edits a hand-written primary config or a
|
|
88
|
-
|
|
89
|
-
higher-sorting
|
|
189
|
+
file outside the 5xx band. To override a managed value rather than change it in place, add a
|
|
190
|
+
higher-sorting file (for example `conf.d/600-overrides.json`), or a
|
|
191
|
+
[config expression](configuration.md#config-expressions) that switches it on some machines only.
|
|
90
192
|
|
|
91
193
|
Where a comment is impossible because a format really is strict JSON, the convention is a `//`
|
|
92
194
|
key, which sous ignores wherever it appears.
|
|
@@ -10,12 +10,23 @@ This page is about the config side only.
|
|
|
10
10
|
Later scopes override earlier ones:
|
|
11
11
|
|
|
12
12
|
```
|
|
13
|
-
auto-vars -> _env scope -> _vars -> compilation._vars -> target._vars -> output._vars
|
|
13
|
+
auto-vars -> recipe answers -> _env scope -> _vars -> compilation._vars -> target._vars -> output._vars
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
`_vars` may be set at four levels, each inheriting the levels above it, inner values winning:
|
|
17
|
+
|
|
18
|
+
```text
|
|
19
|
+
root _vars
|
|
20
|
+
└── compilation._vars
|
|
21
|
+
└── compilation.targets[]._vars
|
|
22
|
+
└── targets[].outputs[]._vars
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
So a target var may reference a top-level var, and an output var may override both for that output
|
|
26
|
+
only. A [config expression](configuration.md#config-expressions) sees the `_vars` of every level
|
|
27
|
+
that contains it, and no others; an expression under `subscriptions`, `repos` or any other top-level
|
|
28
|
+
key sees only the root `_vars`. Recipe outputs also get a scope per recipe, holding that recipe's
|
|
29
|
+
answers (see [Recipe variables](repositories-variables.md)).
|
|
19
30
|
|
|
20
31
|
## Auto-vars
|
|
21
32
|
|
|
@@ -23,6 +34,7 @@ Always injected first, before `_env` and `_vars`:
|
|
|
23
34
|
|
|
24
35
|
| Variable | Value |
|
|
25
36
|
|----------|-------|
|
|
37
|
+
| `projectRoot` | the project root: the directory that holds `.sous/` (see [The project root](config-discovery.md#the-project-root)) |
|
|
26
38
|
| `sousDir` | the discovered `.sous/` directory holding the active config |
|
|
27
39
|
| `sousConfDir` | the `conf.d/` drop-in directory for the active config |
|
|
28
40
|
| `sousConfigPath` | absolute path of the active primary config file |
|
|
@@ -31,6 +43,10 @@ Always injected first, before `_env` and `_vars`:
|
|
|
31
43
|
| `sousTemplatePath` | absolute path of the `.tpl.` file being rendered (render time only) |
|
|
32
44
|
| `sousTemplateDir` | directory of the `.tpl.` file being rendered (render time only) |
|
|
33
45
|
|
|
46
|
+
!> Sous sets `projectRoot`. Setting it in any `_vars` block is an error saying so. A config that
|
|
47
|
+
wrote `projectRoot: "${sousDir}/.."` before 1.0 drops that line; every `${projectRoot}` keeps
|
|
48
|
+
working.
|
|
49
|
+
|
|
34
50
|
The `sous*` namespace is reserved: defining any var whose name starts with `sous` earns a
|
|
35
51
|
warning and risks colliding with a future auto-var.
|
|
36
52
|
|
|
@@ -42,14 +58,31 @@ shell environment, `.sous/.env.local`, or `.sous/.env` (first writer wins, in th
|
|
|
42
58
|
mapped env var that is not set anywhere is a hard `ConfigError` telling you which file to define
|
|
43
59
|
it in.
|
|
44
60
|
|
|
45
|
-
##
|
|
61
|
+
## Variables set in a later file
|
|
62
|
+
|
|
63
|
+
A [config expression](configuration.md#config-expressions) always sees a variable's final value,
|
|
64
|
+
even when a later file sets it. Sous notes every variable an expression reads, and when that
|
|
65
|
+
variable's value changes, it applies the file again
|
|
66
|
+
([Layers and merging](config-layers.md#load-order-and-why-your-files-win)):
|
|
67
|
+
|
|
68
|
+
```text
|
|
69
|
+
Files: sous.config (machineRole: laptop) → 610-browser ($if machineRole == 'laptop') → 700-ci (machineRole: ci)
|
|
70
|
+
|
|
71
|
+
610-browser reads machineRole → "laptop" → enabled: true; 700-ci then sets "ci"
|
|
72
|
+
610-browser is applied again: machineRole is now "ci" → enabled: false
|
|
73
|
+
nothing it read changed → done
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
A variable still unknown when the config settles is an error naming it.
|
|
77
|
+
|
|
78
|
+
## Variables that refer to other variables
|
|
46
79
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
80
|
+
A variable may refer to others in the same `_vars` block, in any order. Sous resolves every entry
|
|
81
|
+
whose `${refs}` are all known, then tries the rest again, until nothing more resolves. Declaration
|
|
82
|
+
order therefore never matters; `{ file: "${root}/x", root:
|
|
50
83
|
"/data" }` resolves as readily as the reverse.
|
|
51
84
|
|
|
52
|
-
If entries remain unresolved
|
|
85
|
+
If entries remain unresolved at the end, that is a hard `ConfigError`. The message
|
|
53
86
|
separates:
|
|
54
87
|
|
|
55
88
|
- **Cycles**: entries that reference each other (members are named), and
|
|
@@ -64,8 +97,8 @@ reference.
|
|
|
64
97
|
## Path normalization
|
|
65
98
|
|
|
66
99
|
Absolute `entryPoint`, `entryGlob`, `globBase`, `destinationFile` and `destinationDir` values
|
|
67
|
-
are normalized after substitution, so
|
|
68
|
-
|
|
100
|
+
are normalized after substitution, so a path such as `${sousDir}/../docs` collapses to the real
|
|
101
|
+
directory. This matters: prune compares tracked outputs against `destinationDir` by
|
|
69
102
|
string prefix, and watch mode matches event paths against watched entries; both need the
|
|
70
103
|
normalized form.
|
|
71
104
|
|