@sous-io/sous 1.0.13 → 1.0.14
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/dist/sous.js +39 -39
- package/docs/markdown/_sidebar.md +1 -0
- package/docs/markdown/repositories-authoring.md +17 -11
- package/docs/markdown/repositories-consuming.md +14 -8
- package/docs/markdown/repositories-file-formats.md +38 -14
- package/docs/markdown/repositories-quickstart.md +2 -2
- package/docs/markdown/repositories-variables.md +31 -0
- package/docs/markdown/repositories.md +2 -2
- package/package.json +33 -33
- package/recipes/core/sous-skills/skills/about-sous-recipes/SKILL.tpl.md +15 -6
- package/recipes/core/sous-skills/skills/about-sous-repos/SKILL.tpl.md +3 -2
- package/recipes/core/sous-skills/sous.recipe.yaml +1 -1
|
@@ -52,3 +52,4 @@
|
|
|
52
52
|
- [0020: Config expressions](adrs/0020-config-expressions.md)
|
|
53
53
|
- [0021: Reporting as levels and styles](adrs/0021-reporting-levels-and-styles.md)
|
|
54
54
|
- [0022: Intents return outputs](adrs/0022-intents-return-outputs.md)
|
|
55
|
+
- [0023: The project's lockfile is the only lock](adrs/0023-the-project-lockfile-is-the-only-lock.md)
|
|
@@ -132,7 +132,7 @@ A subscriber is offered the missing plugin when they subscribe; see
|
|
|
132
132
|
## Declare the variables a recipe needs
|
|
133
133
|
|
|
134
134
|
A recipe that needs a value from the project asks through a **definition**: a published specification, never a
|
|
135
|
-
value. Sous asks the question only when a
|
|
135
|
+
value. Sous asks the question only when a recipe the project holds needs the variable and no valid answer is in scope.
|
|
136
136
|
|
|
137
137
|
```yaml
|
|
138
138
|
variables:
|
|
@@ -177,7 +177,7 @@ variables:
|
|
|
177
177
|
a value the environment already carries, such as `GITHUB_TOKEN`; `x-intentional: true` then silences the
|
|
178
178
|
release warning about claiming a well-known name (`PATH`, `HOME`, `USER`, `SHELL`, `GITHUB_TOKEN`,
|
|
179
179
|
`GITLAB_TOKEN`, `NPM_TOKEN`, or anything starting `AWS_` or `SOUS_`, except the `SOUS_VAR_` names sous
|
|
180
|
-
derives itself). Two definitions of the same name
|
|
180
|
+
derives itself). Two definitions of the same name share one variable; two of **different** names
|
|
181
181
|
claiming the same one is an error.
|
|
182
182
|
- **`secret: true`** hides the value everywhere sous prints it, and **`scope`** picks the file the answer is
|
|
183
183
|
written to: `shared` for the committed `.sous/.env`, `local` for the gitignored `.sous/.env.local`. A secret
|
|
@@ -187,19 +187,23 @@ variables:
|
|
|
187
187
|
answering, and the message names your pattern. Within a major version a schema may only LOOSEN: tightening a
|
|
188
188
|
constraint is a major bump, and an upgrade re-validates stored answers, re-prompting only where an old one no
|
|
189
189
|
longer fits.
|
|
190
|
+
- **Reading another recipe's variable** needs no definition: list that recipe under `depends` and use the name in
|
|
191
|
+
your templates. Redefining it makes a second definition, which sous combines with the first; see
|
|
192
|
+
[Two recipes, one name](repositories-variables.md#two-recipes-one-name).
|
|
190
193
|
- **Further reading:** [Recipe variables](repositories-variables.md) covers how an answer is found at build
|
|
191
194
|
time; [Variable definitions](repositories-file-formats.md#variable-definitions) is the full field table.
|
|
192
195
|
|
|
193
196
|
## Declare dependencies and co-subscriptions
|
|
194
197
|
|
|
195
198
|
`depends` fetches and pins a recipe whose files stay OUT of a subscriber's output but are addressable from your
|
|
196
|
-
own templates, and from the templates of any project whose lockfile pins it. `subscribes` is a co-subscription: its
|
|
197
|
-
how a curated bundle is built.
|
|
199
|
+
own templates, and from the templates of any project whose lockfile pins it. `subscribes` is a co-subscription: its
|
|
200
|
+
files DO enter the output, which is how a curated bundle is built. Under either list, the other recipe's questions
|
|
201
|
+
are asked and its answers reach your templates. Both hold plain strings naming their target by where it lives.
|
|
198
202
|
|
|
199
203
|
```yaml
|
|
200
204
|
depends:
|
|
201
|
-
- workflow/qa-helper # a sibling
|
|
202
|
-
- workflow/qa-helper
|
|
205
|
+
- workflow/qa-helper # a sibling: ^ its version at release
|
|
206
|
+
- workflow/qa-helper@1.1.4 # a sibling at exactly one version
|
|
203
207
|
- github://sous-io/sous-recipes/workflow/sat@^1.0 # another repository
|
|
204
208
|
- gitlab://gitlab.example.com/group/subgroup/proj/-/qa/lint # a self-hosted host, with subgroups
|
|
205
209
|
- https://github.com/acme/recipes/tree/main/recipes/lint # a URL copied from the browser
|
|
@@ -207,14 +211,15 @@ subscribes:
|
|
|
207
211
|
- quality/code-review # co-subscribed: its files land too
|
|
208
212
|
```
|
|
209
213
|
|
|
210
|
-
A **bare ref** is a sibling in this repository; with no range it means
|
|
211
|
-
|
|
214
|
+
A **bare ref** is a sibling in this repository; with no range it means `^<the sibling's version at release>`, any
|
|
215
|
+
later version with the same major. A location names another repository: a
|
|
212
216
|
locator, an HTTPS or SSH URL, or a URL copied from the browser. A ref is stored and printed as its published
|
|
213
217
|
**identity** (namespace and recipe), never as a folder path. Any spelling that settles to one identity is
|
|
214
218
|
accepted, including a folder path or a pasted browser URL: a recipe stored at `recipes/shared/sat/` and
|
|
215
219
|
published as `workflow/sat` may be written `github://owner/repo/workflow/sat` or
|
|
216
220
|
`https://github.com/owner/repo/tree/main/recipes/shared/sat`, and the release settles the second through the
|
|
217
|
-
other repository's index. The optional range after `@` follows npm's rules
|
|
221
|
+
other repository's index. The optional range after `@` follows npm's rules, and may be exact when your recipe needs
|
|
222
|
+
certainty; nothing else pins a dependency to one version except the subscribing project's lockfile. `local://` locators and `repo:`
|
|
218
223
|
short names are refused: a local repository is a consumer's convenience, and a short name is one project's
|
|
219
224
|
private label. See [Dependencies named by location](repositories-file-formats.md#dependencies-named-by-location)
|
|
220
225
|
and every accepted spelling in [Ref forms](repositories-file-formats.md#ref-forms).
|
|
@@ -292,8 +297,9 @@ this release's scope** is fine: the release depends on the last published versio
|
|
|
292
297
|
release's scope; 'workflow/qa-variables@0.1.1' will depend on 'workflow/qa-helper@0.1.0'.
|
|
293
298
|
```
|
|
294
299
|
|
|
295
|
-
Each version's
|
|
296
|
-
|
|
300
|
+
Each version's dependencies are written into the index as ranges: the range the manifest declares, or
|
|
301
|
+
`^<the sibling's version at release>` for a sibling named with no range. A consumer resolves those ranges, and
|
|
302
|
+
its own lockfile pins what it got; that lockfile is the only lock. Each dependency also records the manifest
|
|
297
303
|
entry that brought it in and whether it is a co-subscription or a build dependency, and each version records the
|
|
298
304
|
variable definitions its manifest publishes, so `sous recipe show` and `sous subscription add --dry-run` can say
|
|
299
305
|
what a recipe installs and asks before anything is fetched. A published version never changes: its content
|
|
@@ -67,8 +67,8 @@ upstream's newest version beside the installed one.
|
|
|
67
67
|
|
|
68
68
|
Read `sous recipe show` before subscribing. It works offline, from the index alone: every published
|
|
69
69
|
version, what the version depends on (the manifest entry that brings each dependency in, whether it
|
|
70
|
-
is a co-subscription whose files land here or a build dependency, and the
|
|
71
|
-
|
|
70
|
+
is a co-subscription whose files land here or a build dependency, and the range of versions it
|
|
71
|
+
may take), every recipe a subscription would install, and every question that would ask. Only the
|
|
72
72
|
files it publishes wait until it is installed. A preset set, a recipe that only bundles others,
|
|
73
73
|
reads like this:
|
|
74
74
|
|
|
@@ -77,11 +77,11 @@ $ sous recipe show omakase/house
|
|
|
77
77
|
Latest version : 1.0.0
|
|
78
78
|
Pinned version : this project pins none
|
|
79
79
|
Subscribed : no
|
|
80
|
-
Dependency Declared as Resolved to
|
|
81
|
-
--------------- ------------------------------
|
|
82
|
-
tools/lint tools/lint 1.0.0
|
|
83
|
-
workflow/notes the whole 'workflow' namespace 1.0.0
|
|
84
|
-
workflow/review the whole 'workflow' namespace 1.0.0
|
|
80
|
+
Dependency Declared as Resolved to Repository Kind
|
|
81
|
+
--------------- ------------------------------ ---------------- --------------- ----------------
|
|
82
|
+
tools/lint tools/lint the range ^1.0.0 this repository build dependency
|
|
83
|
+
workflow/notes the whole 'workflow' namespace the range ^1.0.0 this repository co-subscription
|
|
84
|
+
workflow/review the whole 'workflow' namespace the range ^1.0.0 this repository co-subscription
|
|
85
85
|
➔ What subscribing asks you:
|
|
86
86
|
These recipes ask 3 questions, 3 of which nothing answers yet.
|
|
87
87
|
workflow/notes asks 1 question:
|
|
@@ -168,7 +168,8 @@ change when you say yes: `.sous/conf.d/510-subscriptions.jsonc` records the subs
|
|
|
168
168
|
the new skills are on disk when it returns; `--no-build` defers that, and a failed build keeps it.
|
|
169
169
|
|
|
170
170
|
?> Only a recipe a manifest lists under `subscribes` contributes files; one listed under `depends`,
|
|
171
|
-
like `workflow/qa-helper` above, is fetched and pinned but stays out of your output.
|
|
171
|
+
like `workflow/qa-helper` above, is fetched and pinned but stays out of your output. Recipes under both
|
|
172
|
+
lists have their questions asked. See
|
|
172
173
|
[Dependencies](repositories.md#dependencies).
|
|
173
174
|
|
|
174
175
|
## Choose where the files land
|
|
@@ -312,6 +313,11 @@ What it will and will not do:
|
|
|
312
313
|
- A pin moves only within the range its subscription declares, or the range the recipe depending
|
|
313
314
|
on it declares; a range is never widened. Prereleases count only for a subscription that opted
|
|
314
315
|
into them.
|
|
316
|
+
- Every subscription in scope resolves together, so a recipe several of them need takes one version
|
|
317
|
+
that every holder's range allows: the pinned one while it still fits, otherwise the newest that
|
|
318
|
+
does. When no version fits every holder, the subscription that cannot join is refused, naming each
|
|
319
|
+
holder and its range. A library held only through `depends` that its holders need at
|
|
320
|
+
incompatible versions is instead pinned once per holder.
|
|
315
321
|
- Dependencies move with the closure: a dependency a newer version adds is pinned, and one it
|
|
316
322
|
dropped leaves the lockfile unless something else still holds it.
|
|
317
323
|
- Only the lockfile changes. Your subscriptions stay exactly as they are written.
|
|
@@ -217,7 +217,7 @@ fetches only this file; nothing more is downloaded until a project subscribes.
|
|
|
217
217
|
"recipes": { "quality/qa-remote-dep": { "path": "recipes/quality/qa-remote-dep",
|
|
218
218
|
"versions": { "0.1.0": {
|
|
219
219
|
"dependencies": {
|
|
220
|
-
"workflow/qa-helper": { "
|
|
220
|
+
"workflow/qa-helper": { "range": "^0.1.0", "declared": "workflow", "kind": "subscribes" },
|
|
221
221
|
"workflow/sub-agent-delegation": { "range": "^1.0", "repo": "github.com/sous-io/sous-recipes",
|
|
222
222
|
"declared": "github://sous-io/sous-recipes/workflow/sub-agent-delegation@^1.0",
|
|
223
223
|
"kind": "depends" } },
|
|
@@ -239,20 +239,26 @@ fetches only this file; nothing more is downloaded until a project subscribes.
|
|
|
239
239
|
| `recipes` | top level | Keyed `namespace/recipe`; a recipe whose namespace is not declared is an error. Each entry carries `path` (the recipe folder), `description`, and `versions`, keyed by exact version |
|
|
240
240
|
| `hash`, `tag` | per version | The content hash verified after every fetch, and the tag, which must be exactly `namespace/recipe@version` so a version can never point at a branch |
|
|
241
241
|
| `prerelease`, `releasedAt`, `seeded` | per version | Whether ranges skip it unless a subscription opts in, when it was released, and whether it is the copy sous folds in from its own package |
|
|
242
|
-
| `dependencies` | per version |
|
|
242
|
+
| `dependencies` | per version | The range each dependency may take, keyed `namespace/recipe`; see below |
|
|
243
243
|
| `variables` | per version | The version's variable definitions, exactly as its manifest publishes them (see [Variable definitions](#variable-definitions)), with `required`, `secret` and `scope` filled in; `[]` when it asks nothing |
|
|
244
244
|
| `depends`, `subscribes` | per version | The version's manifest lists, exactly as written; `[]` when empty |
|
|
245
245
|
|
|
246
|
-
Dependencies are
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
246
|
+
Dependencies are recorded at release time and keyed `namespace/recipe`. Each entry carries `range`: the range
|
|
247
|
+
the manifest declares, or `^<the sibling's version at release>` for a sibling named with no range (`*` when the
|
|
248
|
+
sibling has no version yet). A dependency in another repository also carries `repo`, the identity of the
|
|
249
|
+
repository publishing it, whose own index resolves the range. The index never pins a dependency to one version;
|
|
250
|
+
the consuming project resolves every range and its lockfile is the only lock.
|
|
251
|
+
|
|
252
|
+
An entry written by an older release carries `version`, the exact version that release resolved, instead of
|
|
253
|
+
`range`. Sous reads it as `^<version>`, further limited by the range in the entry's `declared` field when it
|
|
254
|
+
holds one, so `{ "version": "1.1.1", "declared": "workflow/sub-agent-delegation@~1.1" }` allows any `1.1.x`
|
|
255
|
+
from `1.1.1` up. Nothing is republished to change it.
|
|
250
256
|
|
|
251
257
|
**Each version describes itself.** So that a recipe can be described before anything is fetched, every
|
|
252
258
|
version a release records carries more than its dependencies. Each dependency records `declared`, the
|
|
253
259
|
manifest entry that brings it in exactly as written (a recipe such as `workflow/qa-helper@^1.0`, a whole
|
|
254
260
|
namespace such as `workflow`, or a locator), and `kind`: `subscribes` for a co-subscription, whose files
|
|
255
|
-
land
|
|
261
|
+
land, or `depends` for a build dependency, whose files stay out; the questions of both are asked. When several entries cover one
|
|
256
262
|
recipe, an entry naming it wins over a namespace, and it is a co-subscription when any entry covering it is
|
|
257
263
|
one. The version records `variables`, its manifest's definitions, and `depends` and `subscribes`, its
|
|
258
264
|
manifest's lists as written; the lists are what a consumer walks, because a namespace of another repository
|
|
@@ -263,15 +269,16 @@ the resolver walks a recipe whose files are not on the machine from its index en
|
|
|
263
269
|
its manifest. A version recorded before a release wrote these fields keeps its entry as it is; its questions
|
|
264
270
|
are known only once its files are fetched, and the dry run names it as such.
|
|
265
271
|
|
|
266
|
-
**A published version's entry is frozen.** Its dependencies are
|
|
267
|
-
|
|
272
|
+
**A published version's entry is frozen.** Its dependencies are recorded once, when the version is first
|
|
273
|
+
published, and every later release carries the entry forward exactly as published, like its hash; releasing
|
|
268
274
|
other recipes, adding a recipe to a namespace it subscribes to, or raising a sibling it names changes nothing
|
|
269
275
|
in it. A release still checks the recorded list against the version's manifest: a recipe the manifest names
|
|
270
|
-
that the list lacks, a recipe in the list the manifest does not declare, a
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
276
|
+
that the list lacks, a recipe in the list the manifest does not declare, a recorded range that is not the
|
|
277
|
+
declared one (for a sibling named with no range, not a `^<version>` range or `*`), an older entry's `version`
|
|
278
|
+
outside its declared range, or another repository's entry with a different repository is an error naming the
|
|
279
|
+
recipe, the version and each difference; restore the entry if the index was edited, or bump the version to publish
|
|
280
|
+
different dependencies. A version rebuilt from its tag, when the index lost it, has its dependencies recorded
|
|
281
|
+
from the repository as it stood at that tag, then frozen the same way. An entry written before sous
|
|
275
282
|
recorded dependencies carries none, stays that way, and installs by resolving its manifest's ranges.
|
|
276
283
|
|
|
277
284
|
**Fields this sous does not know are kept, not refused.** A later sous may add fields to the index, at any
|
|
@@ -311,12 +318,29 @@ Machine-written, committed, and the reason a fresh clone restores with no prompt
|
|
|
311
318
|
| `repos.<name>.url`, `.identity`, `.indexHash` | Where the repository lives, as recorded when it was added; the canonical identity the store and index cache file it under; and the hash of the index this lock was resolved against, when known |
|
|
312
319
|
| `recipes.<key>.repo`, `.version`, `.hash` | The project's short name for the repository, which must appear under `repos`; the version resolved; and the hash verified against the store after every fetch |
|
|
313
320
|
| `recipes.<key>.requestedBy`, `.kind` | Who holds the entry, the literal `project` or the key of a recipe that requires it, and whether that holder is a `subscribes` or a `depends` |
|
|
321
|
+
| `recipes.<key>.pins.<holder>.version`, `.hash` | A version pinned for one holder alone, keyed by that holder's recipe key; absent when every holder uses `version` |
|
|
314
322
|
|
|
315
323
|
A repository appears under two names on purpose: the key is the project's own short name, which every
|
|
316
324
|
message uses, while `identity` is what the store is keyed by, so two projects with different labels share
|
|
317
325
|
one cached copy. `identity` is optional on read only, for older lockfiles, and is derived from the URL on
|
|
318
326
|
the next write. `requestedBy` makes removal safe; an entry goes when its last holder does.
|
|
319
327
|
|
|
328
|
+
`pins` appears only when a holder that reaches the recipe through `depends` needs a version no other
|
|
329
|
+
holder's range allows. The entry's `version` is the one the project uses (a recipe some holder reaches
|
|
330
|
+
through `subscribes` has exactly one); each holder under `pins` uses its own version instead, for its
|
|
331
|
+
includes and its questions, and nothing from that version reaches the project's files. Every holder under
|
|
332
|
+
`pins` is also listed in `requestedBy`, and loses its pin when it stops holding the entry. Each pinned
|
|
333
|
+
version is fetched, checked against its hash and kept in the store like the shared one.
|
|
334
|
+
|
|
335
|
+
```json
|
|
336
|
+
"support/base": { "kind": "depends", "repo": "fixtures", "version": "1.0.0", "hash": "sha256-1b...",
|
|
337
|
+
"requestedBy": ["lib/one", "lib/two"],
|
|
338
|
+
"pins": { "lib/two": { "version": "2.0.0", "hash": "sha256-9c..." } } }
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
A lockfile with no `pins` reads exactly as it did before. A version of sous older than this field refuses a
|
|
342
|
+
lockfile that carries one, naming the unknown key, because the format is strict.
|
|
343
|
+
|
|
320
344
|
## The store on disk
|
|
321
345
|
|
|
322
346
|
The store is machine-wide, immutable per version, and disposable (everything is re-fetchable from a
|
|
@@ -93,8 +93,8 @@ sous recipe show workflow/task-files
|
|
|
93
93
|
```
|
|
94
94
|
|
|
95
95
|
On a machine that has never fetched the recipe, sous shows what the index knows: every published
|
|
96
|
-
version, and every dependency with
|
|
97
|
-
it
|
|
96
|
+
version, and every dependency with the range it was declared with and the range the index records
|
|
97
|
+
for it. The questions it asks are not known until it is fetched; run the same command after
|
|
98
98
|
subscribing and it adds a table of the variables the recipe publishes.
|
|
99
99
|
|
|
100
100
|
## 4. Subscribe to a recipe
|
|
@@ -31,6 +31,37 @@ match on a worker under a fixed budget of 100 milliseconds, and a pattern that e
|
|
|
31
31
|
naming the pattern and the recipe rather than blaming your answer. See
|
|
32
32
|
[A variable pattern that runs out of time](repositories-troubleshooting.md#a-variable-pattern-that-runs-out-of-time).
|
|
33
33
|
|
|
34
|
+
## Two recipes, one name
|
|
35
|
+
|
|
36
|
+
Answers are shared by name, so when several recipes, or several versions of one recipe, define a variable of
|
|
37
|
+
the same name, sous asks **one** question, built from the strictest combination of every definition:
|
|
38
|
+
|
|
39
|
+
- secret when any definition is secret, `scope: local` when any is local, and required when any is required;
|
|
40
|
+
- only the values every definition accepts: the `enum` options they share, the highest `min` and `minLength`,
|
|
41
|
+
the lowest `max` and `maxLength`, and every `pattern`;
|
|
42
|
+
- the first definition's prompt, description and example, with the question naming the other recipes
|
|
43
|
+
(`workflow/notes, also used by review/checklist`);
|
|
44
|
+
- the first `default` that passes the combination; a default that fails it is dropped.
|
|
45
|
+
|
|
46
|
+
For example, one recipe defines `port` as a number of at least 1000 and another as a secret number of at most
|
|
47
|
+
9000: you are asked once, for a secret number from 1000 to 9000, stored locally.
|
|
48
|
+
|
|
49
|
+
When no answer could satisfy every definition (one says `number` and the other `string`, their `enum` lists
|
|
50
|
+
share no option, or one's `min` is above another's `max`), the definitions are not combined. Sous says why,
|
|
51
|
+
naming both, and asks each recipe separately, storing each answer under that recipe's
|
|
52
|
+
[recipe-scoped name](#how-sous-finds-an-answer-the-ladder) (`SOUS_VAR_<NAMESPACE>_<RECIPE>_<VARIABLE>`).
|
|
53
|
+
|
|
54
|
+
Two versions of one recipe (a recipe pinned at a different version for some of the recipes that depend on it)
|
|
55
|
+
would share that recipe-scoped name, so when their definitions cannot be combined, sous asks only one of them:
|
|
56
|
+
the version the lockfile shares, or else the first version the lockfile lists. The other version gets no
|
|
57
|
+
answer, not even its default, and the variable renders empty where that version is used. `sous vars ask`,
|
|
58
|
+
`sous vars list` and `sous vars show`, a build, and the question preview of `sous subscription add --dry-run`
|
|
59
|
+
and `sous recipe show` warn about it, naming both versions, the recipes that use each, and why the definitions
|
|
60
|
+
cannot be combined.
|
|
61
|
+
|
|
62
|
+
A recipe that only reads another recipe's variable, by listing that recipe under `depends` and using the
|
|
63
|
+
name in its templates, does not define it, so it adds nothing to the combination.
|
|
64
|
+
|
|
34
65
|
## Answer the questions
|
|
35
66
|
|
|
36
67
|
Subscribing asks whatever is unanswered, so in normal use you rarely run `sous vars ask` yourself; reach for
|
|
@@ -93,8 +93,8 @@ with the project.
|
|
|
93
93
|
A recipe manifest can declare two relationships to other recipes, and they differ in exactly one
|
|
94
94
|
respect: whose files end up in your project. `depends` fetches, pins and trust-gates the target
|
|
95
95
|
and makes it addressable while rendering, but keeps its files out of your output; `subscribes`
|
|
96
|
-
does all of that and lands the target's files in your project too
|
|
97
|
-
questions
|
|
96
|
+
does all of that and lands the target's files in your project too. Under either list, the variable
|
|
97
|
+
questions the target publishes are asked (see [Recipe variables](repositories-variables.md)).
|
|
98
98
|
|
|
99
99
|
```yaml
|
|
100
100
|
depends:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sous-io/sous",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.14",
|
|
4
4
|
"description": "Compiles AI coding agent configuration (CLAUDE.md, skills, memories) from LiquidJS templates",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -39,44 +39,44 @@
|
|
|
39
39
|
"sous.config.schema.json"
|
|
40
40
|
],
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@sous-io/plugin-api": "1.0.
|
|
42
|
+
"@sous-io/plugin-api": "1.0.14"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"esbuild": "^0.27.4",
|
|
46
46
|
"jsonc-parser": "^3.3.1",
|
|
47
47
|
"yaml": "^2.9.0",
|
|
48
48
|
"zod": "^4.4.3",
|
|
49
|
-
"@sous-io/
|
|
50
|
-
"@sous-io/
|
|
51
|
-
"@sous-io/plugin-build": "1.0.
|
|
52
|
-
"@sous-io/plugin-claude-code": "1.0.
|
|
53
|
-
"@sous-io/
|
|
54
|
-
"@sous-io/plugin-cli": "1.0.
|
|
55
|
-
"@sous-io/plugin-
|
|
56
|
-
"@sous-io/plugin-config-files": "1.0.
|
|
57
|
-
"@sous-io/plugin-formats": "1.0.
|
|
58
|
-
"@sous-io/plugin-
|
|
59
|
-
"@sous-io/plugin-
|
|
60
|
-
"@sous-io/plugin-git": "1.0.
|
|
61
|
-
"@sous-io/plugin-
|
|
62
|
-
"@sous-io/plugin-
|
|
63
|
-
"@sous-io/plugin-init": "1.0.
|
|
64
|
-
"@sous-io/plugin-
|
|
65
|
-
"@sous-io/plugin-inspect": "1.0.
|
|
66
|
-
"@sous-io/plugin-
|
|
67
|
-
"@sous-io/plugin-
|
|
68
|
-
"@sous-io/plugin-
|
|
69
|
-
"@sous-io/plugin-mcp": "1.0.
|
|
70
|
-
"@sous-io/plugin-memories": "1.0.
|
|
71
|
-
"@sous-io/plugin-
|
|
72
|
-
"@sous-io/plugin-
|
|
73
|
-
"@sous-io/plugin-
|
|
74
|
-
"@sous-io/plugin-recipes": "1.0.
|
|
75
|
-
"@sous-io/plugin-skills": "1.0.
|
|
76
|
-
"@sous-io/plugin-
|
|
77
|
-
"@sous-io/plugin-
|
|
78
|
-
"@sous-io/plugin-
|
|
79
|
-
"@sous-io/plugin-
|
|
49
|
+
"@sous-io/core": "1.0.14",
|
|
50
|
+
"@sous-io/documents": "1.0.14",
|
|
51
|
+
"@sous-io/plugin-build": "1.0.14",
|
|
52
|
+
"@sous-io/plugin-claude-code": "1.0.14",
|
|
53
|
+
"@sous-io/plugin-authoring": "1.0.14",
|
|
54
|
+
"@sous-io/plugin-cli": "1.0.14",
|
|
55
|
+
"@sous-io/plugin-compiler": "1.0.14",
|
|
56
|
+
"@sous-io/plugin-config-files": "1.0.14",
|
|
57
|
+
"@sous-io/plugin-formats": "1.0.14",
|
|
58
|
+
"@sous-io/plugin-expressions": "1.0.14",
|
|
59
|
+
"@sous-io/plugin-confd": "1.0.14",
|
|
60
|
+
"@sous-io/plugin-git": "1.0.14",
|
|
61
|
+
"@sous-io/plugin-github": "1.0.14",
|
|
62
|
+
"@sous-io/plugin-harnesses": "1.0.14",
|
|
63
|
+
"@sous-io/plugin-init": "1.0.14",
|
|
64
|
+
"@sous-io/plugin-host": "1.0.14",
|
|
65
|
+
"@sous-io/plugin-inspect": "1.0.14",
|
|
66
|
+
"@sous-io/plugin-gitlab": "1.0.14",
|
|
67
|
+
"@sous-io/plugin-local": "1.0.14",
|
|
68
|
+
"@sous-io/plugin-liquid": "1.0.14",
|
|
69
|
+
"@sous-io/plugin-mcp": "1.0.14",
|
|
70
|
+
"@sous-io/plugin-memories": "1.0.14",
|
|
71
|
+
"@sous-io/plugin-pnpm": "1.0.14",
|
|
72
|
+
"@sous-io/plugin-recipe-answers": "1.0.14",
|
|
73
|
+
"@sous-io/plugin-npm": "1.0.14",
|
|
74
|
+
"@sous-io/plugin-recipes": "1.0.14",
|
|
75
|
+
"@sous-io/plugin-skills": "1.0.14",
|
|
76
|
+
"@sous-io/plugin-update": "1.0.14",
|
|
77
|
+
"@sous-io/plugin-variables": "1.0.14",
|
|
78
|
+
"@sous-io/plugin-refs": "1.0.14",
|
|
79
|
+
"@sous-io/plugin-yarn": "1.0.14"
|
|
80
80
|
},
|
|
81
81
|
"engines": {
|
|
82
82
|
"node": ">=22"
|
|
@@ -134,8 +134,13 @@ The fields in that example, and the ones it leaves out:
|
|
|
134
134
|
answers already stored.
|
|
135
135
|
|
|
136
136
|
A template may also read a variable another recipe defines. List that recipe under `depends`, so
|
|
137
|
-
the variable is there wherever this recipe is, and branch on it in the
|
|
138
|
-
the agent to look the setting up
|
|
137
|
+
the variable is there wherever this recipe is, and MUST NOT redefine it; branch on it in the
|
|
138
|
+
template rather than telling the agent to look the setting up (`about-liquid-templates` shows how).
|
|
139
|
+
|
|
140
|
+
When two recipes do define one name, the project is asked one question built from the strictest
|
|
141
|
+
combination: secret, `local` or required if any definition is, and only the values every definition
|
|
142
|
+
accepts. When no value can satisfy both (different types, no shared `enum` option), each recipe is
|
|
143
|
+
asked separately under its recipe-scoped name.
|
|
139
144
|
|
|
140
145
|
## Depends and Subscribes
|
|
141
146
|
|
|
@@ -144,14 +149,18 @@ Both lists name other recipes, and they do different things:
|
|
|
144
149
|
- `depends` makes the other recipe a **library** for this one. It is fetched and pinned, and its
|
|
145
150
|
files can be included from this recipe's templates, but its files never reach the subscriber's
|
|
146
151
|
output.
|
|
147
|
-
- `subscribes` is a **co-subscription**. The other recipe's files land
|
|
148
|
-
|
|
152
|
+
- `subscribes` is a **co-subscription**. The other recipe's files land, as if the project had
|
|
153
|
+
subscribed to it too.
|
|
154
|
+
|
|
155
|
+
Under either list, the other recipe's questions are asked, and its answers are in this recipe's
|
|
156
|
+
templates.
|
|
149
157
|
|
|
150
158
|
Each entry names its target by where it lives:
|
|
151
159
|
|
|
152
160
|
- a bare `namespace/recipe` (or `namespace` for all of it) for a sibling in the same repository.
|
|
153
|
-
With no range it means the version
|
|
154
|
-
|
|
161
|
+
With no range it means `^<the sibling's version at release>`, the same major version. An `@`
|
|
162
|
+
range follows npm's rules and MAY be exact (`workflow/qa-helper@1.2.0`) when this recipe needs
|
|
163
|
+
certainty; the subscribing project's lockfile is the only thing that pins an exact version.
|
|
155
164
|
- a location for a recipe in another repository, such as
|
|
156
165
|
`github://example-org/team-recipes/review/wording@^1.0`, an HTTPS or SSH URL, or a URL copied
|
|
157
166
|
from the browser. A ref is stored and printed as its published identity (namespace and recipe),
|
|
@@ -65,8 +65,9 @@ contribute: https://github.com/harbor-labs/team-recipes/blob/main/CONTRIBUTING.m
|
|
|
65
65
|
A recipe's version lives in its manifest, which is the source of truth. A version is **published**
|
|
66
66
|
once a git tag shaped `namespace/recipe@version` exists for it (for example
|
|
67
67
|
`review/checklist@1.2.0`). The index records each published version with its content hash, its
|
|
68
|
-
tag, the
|
|
69
|
-
|
|
68
|
+
tag, the range each of its dependencies may take (the declared range, or `^<version at release>`
|
|
69
|
+
for a sibling named with no range; each with the manifest entry that brought it in and whether it
|
|
70
|
+
is a co-subscription or a build dependency) and the variable
|
|
70
71
|
definitions it publishes, which is how a project lists what a recipe installs and asks before
|
|
71
72
|
fetching it; for the length of one release commit it also records the version each manifest
|
|
72
73
|
declares, whose tag that release cuts next. A published version never changes: new files need a
|