valise-sh 0.2.0 → 0.3.0

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.
Files changed (92) hide show
  1. package/CHANGELOG.md +152 -2
  2. package/README.md +99 -146
  3. package/bin/valise +57 -5376
  4. package/docs/architecture.md +77 -121
  5. package/docs/contrib-modules.md +172 -218
  6. package/docs/installation.md +137 -83
  7. package/docs/module-abi.md +125 -126
  8. package/docs/projects.md +249 -0
  9. package/docs/release-policy.md +68 -93
  10. package/docs/shared-modules.md +40 -39
  11. package/examples/README.md +12 -11
  12. package/examples/e2e/README.md +59 -66
  13. package/examples/e2e/bundles.tsv +6 -0
  14. package/examples/e2e/module.d/e2e_aliases.meta +1 -2
  15. package/examples/e2e/module.d/e2e_completions_bash.meta +0 -1
  16. package/examples/e2e/module.d/e2e_completions_zsh.meta +0 -1
  17. package/examples/e2e/module.d/e2e_env_setup.meta +2 -3
  18. package/examples/e2e/module.d/e2e_fish_features.meta +0 -1
  19. package/examples/e2e/module.d/e2e_generated_config.meta +1 -2
  20. package/examples/e2e/module.d/e2e_ksh_features.meta +0 -1
  21. package/examples/e2e/module.d/e2e_layer_probe.meta +1 -2
  22. package/examples/e2e/module.d/e2e_optional_network.meta +1 -2
  23. package/examples/e2e/module.d/e2e_platform_tools.meta +8 -0
  24. package/examples/e2e/module.d/e2e_platform_tools_bsd.meta +2 -3
  25. package/examples/e2e/module.d/e2e_platform_tools_darwin.meta +2 -3
  26. package/examples/e2e/module.d/e2e_platform_tools_linux.meta +2 -3
  27. package/examples/e2e/valise.conf +4 -0
  28. package/examples/e2e/variants.tsv +3 -0
  29. package/examples/local/module.d/hello_valise.meta +1 -2
  30. package/examples/profile-project/README.md +78 -108
  31. package/examples/profile-project/bundles.tsv +8 -0
  32. package/examples/profile-project/{shell/layers → layers}/demo/module.d/contrib_demo_greeting.meta +1 -2
  33. package/examples/profile-project/{shell/module.d → module.d}/greeting.meta +1 -2
  34. package/examples/profile-project/{shell/module.d → module.d}/profile_main.meta +0 -1
  35. package/examples/profile-project/{shell/modules → modules}/greeting.sh +1 -1
  36. package/examples/profile-project/valise.conf +4 -0
  37. package/examples/profile-project/variants.tsv +3 -0
  38. package/examples/shared/README.md +13 -34
  39. package/examples/shared/module.d/contrib_shared_paths.meta +2 -3
  40. package/examples/shared/module.d/contrib_shared_umask.meta +1 -2
  41. package/examples/shared/modules/shared/contrib_shared_paths.sh +2 -2
  42. package/lib/capabilities.sh +40 -13
  43. package/lib/cli/commands.sh +278 -0
  44. package/lib/cli/common.sh +326 -0
  45. package/lib/cli/devtools.sh +539 -0
  46. package/lib/cli/fish-hook.sh +986 -0
  47. package/lib/cli/integration.sh +337 -0
  48. package/lib/cli/lifecycle.sh +578 -0
  49. package/lib/cli/project.sh +1807 -0
  50. package/lib/cli/store.sh +1023 -0
  51. package/lib/cli/usage.sh +308 -0
  52. package/lib/compiler.awk +11 -4
  53. package/lib/fish/loader.fish +69 -9
  54. package/lib/fish/metadata.fish +49 -5
  55. package/lib/fish/profile.fish +170 -0
  56. package/lib/loader.sh +6 -8
  57. package/lib/metadata.sh +111 -5
  58. package/manifests/parser-support.tsv +2 -2
  59. package/module.d/valise_editor.meta +9 -0
  60. package/module.d/valise_history.meta +9 -0
  61. package/module.d/valise_pager.meta +9 -0
  62. package/module.d/valise_path.meta +9 -0
  63. package/module.d/{platform_bsd.meta → valise_platform_bsd.meta} +3 -4
  64. package/module.d/{platform_linux.meta → valise_platform_linux.meta} +3 -4
  65. package/module.d/{platform_macos.meta → valise_platform_macos.meta} +3 -4
  66. package/module.d/{platform_posix.meta → valise_platform_posix.meta} +2 -3
  67. package/module.d/valise_xdg.meta +9 -0
  68. package/modules/system/{contrib_editor.sh → valise_editor.sh} +2 -2
  69. package/modules/system/{contrib_history.sh → valise_history.sh} +2 -2
  70. package/modules/system/{contrib_pager.sh → valise_pager.sh} +2 -2
  71. package/modules/system/{contrib_path.sh → valise_path.sh} +3 -3
  72. package/modules/system/{contrib_xdg.sh → valise_xdg.sh} +2 -2
  73. package/package.json +91 -10
  74. package/docs/variants.md +0 -327
  75. package/entrypoints/.gitkeep +0 -0
  76. package/entrypoints/fish/profile.fish +0 -99
  77. package/examples/e2e/build-manifest.sh +0 -138
  78. package/examples/local/.gitkeep +0 -0
  79. package/examples/profile-project/shell/release/bundle-roots +0 -9
  80. package/examples/profile-project/shell/release/install-variants +0 -3
  81. package/examples/profile-project/shell/release/module-registry.tsv +0 -4
  82. package/examples/profile-project/shell/release/project.conf +0 -3
  83. package/lib/.gitkeep +0 -0
  84. package/manifests/.gitkeep +0 -0
  85. package/module.d/.gitkeep +0 -0
  86. package/module.d/contrib_editor.meta +0 -10
  87. package/module.d/contrib_history.meta +0 -10
  88. package/module.d/contrib_pager.meta +0 -10
  89. package/module.d/contrib_path.meta +0 -10
  90. package/module.d/contrib_xdg.meta +0 -10
  91. package/modules/.gitkeep +0 -0
  92. /package/examples/profile-project/{shell/layers → layers}/demo/modules/shared/contrib_demo_greeting.sh +0 -0
@@ -2,9 +2,11 @@
2
2
 
3
3
  ## Current status
4
4
 
5
- `valise-sh` is at **0.2.0**. Before 1.0, the CLI, module ABI, and release
6
- format do not have a backward-compatibility guarantee. Consumers should pin
7
- updates, review release notes, and run their profile's tests before upgrading.
5
+ `valise-sh` is at **0.3.0**. Before 1.0, the CLI, module ABI, and release
6
+ format do not have a backward-compatibility guarantee. Pin the version you
7
+ use, read the release notes, and run `valise lint` and `valise test` on your
8
+ project before upgrading. A project can set `requires_valise=` in
9
+ `valise.conf` so an older valise refuses to build it.
8
10
 
9
11
  ## Compatibility surface
10
12
 
@@ -23,107 +25,80 @@ minor releases, and release notes must state what consumers have to change.
23
25
  After 1.0, use semantic versioning: patch for compatible fixes,
24
26
  minor for backward-compatible features, and major for incompatible changes.
25
27
 
26
- ## What changed in 0.2.0
27
-
28
- `0.1.0` had no external users, so `0.2.0` provides no migration path for its
29
- CLI or shell integration. The items below describe the 0.2.0 contract; each is
30
- also recorded in [CHANGELOG.md](../CHANGELOG.md).
31
-
32
- ### The registry is a generated artifact
33
-
34
- `shell/release/module-registry.tsv` is generated from the project's metadata
35
- by `valise registry`, and `valise build` regenerates it while `valise registry
36
- --check` validates it. A hand-written registry is no longer the source of truth, and a
37
- project needs no registry file at all to build: it keeps its `.meta` files,
38
- their bodies, the bundle roots, and the variants. A committed registry is
39
- accepted as input, but it is overwritten on the next build.
40
-
41
- The row order is fixed and does not depend on the caller's locale: the
42
- primary modules of `shell/module.d/` first, then the layer modules of each
43
- `shell/layers/<provider>/module.d/`, each group in C-locale name order.
44
-
45
- ### The metadata ABI gained fields and classes
46
-
47
- - **Meta modules.** Metadata with `requires=` and no `load` is a
48
- dependency-only aggregator. It loads successfully without a body. `load`
49
- and `requires` may be combined.
50
- - **`side_effect=local-state`.** A source-safe class for modules that write
51
- under the XDG state directory. It loads in the ordinary phase where
52
- `generated-file` still fails.
53
- - **`shells=sh` covers every POSIX shell.** A module that declares `shells=sh`
54
- loads under `sh`, `dash`, `bash`, `zsh`, and `ksh`, and is skipped under
55
- Fish unless it is requested directly in strict mode.
56
-
57
- ### Compiled plans follow the loader
58
-
59
- A compiled plan uses the loader's dependency rules. The required closure is
60
- the bundle's roots plus their transitive `requires`. A module whose required
61
- dependency is unavailable, failed, or skipped for the platform does not run.
62
- Strict mode stops at the first failure in that closure and returns nonzero;
63
- permissive mode reports each failure, continues with unrelated modules, and
64
- returns zero. An optional dependency loads first when it is available for the
65
- shell and variant; its absence never blocks the module that declared it. A
66
- cross-platform profile declares platform-specific modules with `optional=`.
67
- A meta module that declares exports is a compile error, and a module that
68
- fails has its declared exports removed from the function namespace.
69
-
70
- ### Capabilities are available at runtime
71
-
72
- The `sp_cap_*` helpers remain sourced and callable after a compiled plan or a
73
- loader load finishes. A module may call `sp_cap_os` and the other helpers
74
- from its own functions. A plan that removed them at the end of the load left
75
- module functions unusable.
76
-
77
- ### Startup integration is managed
78
-
79
- `valise install` writes a managed block into `~/.profile` and into each
80
- further startup file it manages: the existing `~/.bash_profile` or
81
- `~/.bash_login`, `~/.bashrc` and `~/.zshrc` when that shell is current or the
82
- file exists, and `~/.zprofile` when zsh is on `PATH` or the file exists. It
83
- does not create `~/.bash_profile` or `~/.bash_login`, because either would
84
- stop bash from reading `~/.profile`. A Fish `conf.d` hook is written when
85
- valise finds a Fish executable in a trusted location. `--no-integration`
86
- writes no startup file and no Fish hook. `valise apply` uses the same writer
87
- after building and installing.
88
-
89
- Each POSIX file receives the block between `# BEGIN valise managed block` and
90
- `# END valise managed block`. A repeat install replaces the block in place
91
- and preserves the rest of the file. An unpaired marker is refused and stops
92
- the install; a file already processed keeps its updated block. A symlinked
93
- startup file is reported and left untouched.
94
-
95
- ### Commands
96
-
97
- The command surface has one command per job. `valise init` takes `posix` or
98
- `fish`; with no argument it prints the Fish hook when `$SHELL` names fish and
99
- the POSIX block otherwise. `valise new`, `valise module`, `valise build`,
100
- `valise apply`, `valise status`, and `valise registry` are new. `valise build`
101
- builds a release tree, and `valise apply` builds, installs, writes the shell
102
- integration, and verifies the result.
103
-
104
- Installed releases are managed by `valise release list|use|prune|verify`.
105
- `variant list`, `variant use`, and `verify-active` are gone; `variant` now
106
- refers only to a build variant. `valise doctor` gained `--pre-install` and
107
- `--no-integration`; it reads the startup files the running shell actually
108
- reads and exits nonzero when the active release is missing or fails
109
- verification, or when no startup file carries the block. `valise
110
- explain-bundles` and `valise layer-lint` no longer use Python.
28
+ ## What changed in 0.3.0
29
+
30
+ 0.3.0 changes the project layout, the metadata, the release format, and the
31
+ startup block. A 0.2 project does not build until it is moved to the new
32
+ layout, and a 0.2 release cannot be installed; rebuild it. Every change is
33
+ also in [CHANGELOG.md](../CHANGELOG.md).
34
+
35
+ ### Moving a 0.2 project
36
+
37
+ | 0.2 | 0.3 |
38
+ |---|---|
39
+ | `shell/module.d/`, `shell/modules/` | `module.d/`, `modules/` at the project root |
40
+ | `shell/layers/<p>/` | `layers/<p>/` |
41
+ | `shell/release/bundle-roots` | `bundles.tsv` (bundle, shell, roots) |
42
+ | `shell/release/install-variants` | `variants.tsv` (variant, description, excluded) |
43
+ | `shell/release/project.conf` | `valise.conf` (`bundle=`, `variant=`, `requires_valise=`, `lint_layer_forbid=`) |
44
+ | `shell/release/module-registry.tsv` | nothing: the registry is internal; delete the file |
45
+ | `valise registry --check` | nothing: `valise lint` checks the metadata |
46
+ | `@shell/layers/<p>/module.d` in a qualified name | `@layers/<p>/module.d` |
47
+
48
+ valise does not read the `shell/` layout: until `valise.conf` exists,
49
+ project commands report that they are not inside a valise project.
50
+
51
+ ### Metadata
52
+
53
+ - `shells=posix` means every POSIX shell. `shells=sh` now means only the
54
+ generic class (dash, BusyBox ash, and other plain `sh`), so a module that
55
+ used `shells=sh` for "all POSIX shells" must change to `shells=posix`.
56
+ - `updates=` is rejected. Remove it.
57
+ - A repeated field is rejected.
58
+ - The engine modules moved into the reserved `valise_` namespace:
59
+ `contrib_path` is now `valise_path` (exports `valise_path_prepend` and
60
+ `valise_path_append`), `contrib_editor`, `contrib_history`,
61
+ `contrib_pager`, and `contrib_xdg` are `valise_editor`, `valise_history`,
62
+ `valise_pager`, and `valise_xdg`, and `platform_<os>` is
63
+ `valise_platform_<os>`. Update `requires=` and the calls to their
64
+ exports.
65
+ - New fields: `commands=` publishes exports as commands on `PATH`,
66
+ `executables=` publishes scripts, and `tests=` names the scripts
67
+ `valise test` runs.
68
+
69
+ ### Releases and startup
70
+
71
+ - A release has one shape: `plans/<shell>.sh`, `runtime/`, `bin/`,
72
+ `valise-release.conf` with `format=2`, and `manifest.tsv`. It contains
73
+ only the modules some plan loads. The `generated/`, `vendor/`,
74
+ `shell/install/`, and engine-release (`entrypoints/`) shapes are gone, and
75
+ install refuses a tree without `format=2`.
76
+ - The POSIX block picks a plan for `ksh`, `zsh`, `bash`, or `sh` and has no
77
+ loader fallback. Run `valise apply` once to rewrite the block in each
78
+ startup file. Install warns about any line outside a managed block that
79
+ still loads a 0.2 release.
80
+ - A bundle's `fish` rows build the native Fish runtime into the release.
81
+
82
+ ### New commands
83
+
84
+ `valise lint`, `test`, `run`, `env`, `uninstall`, `release rollback`, and
85
+ `apply --dry-run`. Install is transactional: a failure puts the previous
86
+ active release back.
111
87
 
112
88
  ## Release checklist
113
89
 
114
90
  Before tagging or publishing a release:
115
91
 
116
- 1. Update `package.json` and `bin/valise` version together; add a dated entry
117
- to [CHANGELOG.md](../CHANGELOG.md). The CLI's test suite asserts that the
92
+ 1. Update the `package.json` version and `VALISE_VERSION` in `bin/valise`
93
+ together; add a dated entry to [CHANGELOG.md](../CHANGELOG.md). The CLI's test suite asserts that the
118
94
  two versions match, so a bump that updates one and forgets the other
119
95
  fails the build.
120
96
  2. Run `make check-fast`, then run `make VALISE_REQUIRE_TOOLING=1 check`
121
97
  locally or use the GitHub Actions job. Keep the successful strict run as
122
98
  release evidence for every lane, including Fish, zsh, BusyBox, dash, and
123
99
  ksh.
124
- 3. Run the README isolated quickstart from a clean checkout and verify that
125
- install, `release verify`, and example module loading work in the temporary
126
- home. Confirm cleanup removes the entire demo state.
100
+ 3. Run the README's scratch-home example from a clean checkout and check
101
+ that `greet` runs and the cleanup removes the scratch directory.
127
102
  4. Inspect the result of `npm pack --dry-run` and install/test the packed
128
103
  tarball. The CLI's tests currently cover pack contents, installation, and
129
104
  module loading. The probe in `tests/cli-posix.test.sh` builds a tree from
@@ -7,18 +7,20 @@ removed.
7
7
 
8
8
  ## Namespace and ownership
9
9
 
10
- The loader enforces the layer namespace. This policy assigns ownership and
11
- review responsibility.
10
+ `valise build`, `valise lint`, and `valise layer-lint` enforce the layer
11
+ namespace. This policy assigns ownership and review responsibility.
12
12
 
13
- - Layer-only modules must use the `contrib_` prefix. The loader rejects
14
- other layer-only names (see [module-abi.md](module-abi.md)).
13
+ - Layer modules must use the `contrib_` prefix, and the `valise_` prefix
14
+ belongs to the engine (see [module-abi.md](module-abi.md#layers)).
15
15
  - Module names are owned by the tree that ships them. The engine
16
16
  repository owns every module under its `module.d/`. A provider
17
17
  repository owns every module in its layer tree.
18
- - A module with the same name in multiple roots must have matching metadata
19
- and body bytes. Different bytes or different `version=` values make the
20
- load fail with a diagnostic naming the providers. Identical copies resolve
21
- by root priority; providers should still agree on which tree owns the name.
18
+ - When two sources in a project define the same name, a bare bundle root
19
+ or exclusion naming it is ambiguous and the build fails until it is
20
+ qualified as `name@source`; a dependency resolves to its own source first. The Fish loader and the development loader accept several
21
+ providers of one name only when their metadata and bodies are
22
+ byte-identical. Either way, providers should agree on which tree owns a
23
+ name.
22
24
  - A provider repository that wants its modules consumed must document them
23
25
  in an index of its own, following this document's shape (name, version,
24
26
  exports, source, status). Consumers read the provider's index to
@@ -46,7 +48,7 @@ consistently across all of its modules, so a consumer can see at a glance
46
48
  which provider owns what.
47
49
 
48
50
  If you must ship a module whose name another provider might already use,
49
- prefix it with your owner segment anyway — a name collision between two
51
+ prefix it with your owner segment anyway: a name collision between two
50
52
  vendored providers is otherwise unresolvable without renaming one of them.
51
53
 
52
54
  ## What belongs in a layer
@@ -64,19 +66,21 @@ A layer module must have:
64
66
  editor, no particular toolchain, model, or theme.
65
67
  - **No dependency outside the layer**, apart from the engine's own modules.
66
68
  A layer module may require an engine module, but it may not require a
67
- module that lives in the consumer's primary root — that dependency cannot
69
+ module that lives in the consumer's primary root, because that dependency cannot
68
70
  be satisfied when someone else vendors the layer.
69
71
 
70
72
  Everything else stays in the primary root: environment setup, completions,
71
73
  tool wrappers, work-specific modules, and the aggregators.
72
74
 
73
- `valise layer-lint <layer-name>` enforces the mechanical half of this. It
75
+ `valise layer-lint <layer-name>` and `valise lint` enforce the mechanical
76
+ half of this. It
74
77
  checks that the layer has a `module.d/` directory, that every metadata file
75
78
  is a regular file with a safe mode, that every module name carries the
76
79
  `contrib_` prefix, that the metadata validates as data, that the version is
77
80
  present, that the load target exists as a regular file, and that every
78
- dependency resolves inside the layer or to an engine module. It needs no
79
- Python.
81
+ dependency resolves inside the layer or to an engine module. Set
82
+ `lint_layer_forbid` in `valise.conf` to make `valise lint` reject named
83
+ identifiers, such as an employer's, anywhere under `layers/`.
80
84
 
81
85
  ### 1. Separate generic engines from opinionated presets
82
86
 
@@ -116,7 +120,7 @@ contrib_owner_cli_quote # POSIX, no dependencies
116
120
  contrib_owner_cli_local # needs a non-POSIX shell
117
121
  ```
118
122
 
119
- Now the first module keeps `shells=sh bash zsh ksh` and the second declares
123
+ Now the first module keeps `shells=posix` and the second declares
120
124
  what it actually needs. The same rule applies to dependencies: a module that
121
125
  pulls in a heavy dependency should be separate from one that does not.
122
126
 
@@ -130,12 +134,7 @@ consistently.
130
134
  A layer module **may** call `sp_cap_*` helpers at run time. A compiled plan
131
135
  sources the capability prelude and leaves it in place, so a function the
132
136
  module defines can call `sp_cap_os`, `sp_cap_cpu_count`, or any other helper
133
- long after the profile finished loading. The loader behaves the same way.
134
-
135
- This is a change from earlier engine behavior, where the helpers were
136
- removed after loading and a module function that called one broke. If you
137
- have a layer that avoided the helpers to work around that, you can now use
138
- them directly.
137
+ long after the profile finished loading.
139
138
 
140
139
  Prefer the `sp_cap_*` helpers over open-coding platform-specific commands.
141
140
  See [contrib-modules.md](contrib-modules.md) for the list.
@@ -144,11 +143,15 @@ See [contrib-modules.md](contrib-modules.md) for the list.
144
143
 
145
144
  | Module | Version | Exports | Source | Status |
146
145
  |---|---|---|---|---|
147
- | `contrib_path` | 1.0.0 | `contrib_path_prepend`, `contrib_path_append` | `modules/system/contrib_path.sh` | active |
148
- | `contrib_editor` | 1.0.0 | `contrib_editor_defaults` | `modules/system/contrib_editor.sh` | active |
149
- | `contrib_pager` | 1.0.0 | `contrib_pager_defaults` | `modules/system/contrib_pager.sh` | active |
150
- | `contrib_xdg` | 1.0.0 | `contrib_xdg_defaults` | `modules/system/contrib_xdg.sh` | active |
151
- | `contrib_history` | 1.0.0 | `contrib_history_defaults` | `modules/system/contrib_history.sh` | active |
146
+ | `valise_path` | 1.0.0 | `valise_path_prepend`, `valise_path_append` | `modules/system/valise_path.sh` | active |
147
+ | `valise_editor` | 1.0.0 | `valise_editor_defaults` | `modules/system/valise_editor.sh` | active |
148
+ | `valise_pager` | 1.0.0 | `valise_pager_defaults` | `modules/system/valise_pager.sh` | active |
149
+ | `valise_xdg` | 1.0.0 | `valise_xdg_defaults` | `modules/system/valise_xdg.sh` | active |
150
+ | `valise_history` | 1.0.0 | `valise_history_defaults` | `modules/system/valise_history.sh` | active |
151
+ | `valise_platform_posix` | — | `sp_platform_*` helpers | `modules/platform/posix.sh` | active |
152
+ | `valise_platform_macos` | — | `sp_platform_macos_*` helpers | `modules/platform/macos/capabilities.sh` | active |
153
+ | `valise_platform_linux` | — | `sp_platform_linux_*` helpers | `modules/platform/linux/capabilities.sh` | active |
154
+ | `valise_platform_bsd` | — | `sp_platform_bsd_*` helpers | `modules/platform/bsd/capabilities.sh` | active |
152
155
 
153
156
  The example provider tree in this repository
154
157
  (`examples/shared/`) additionally ships:
@@ -158,9 +161,7 @@ The example provider tree in this repository
158
161
  | `contrib_shared_paths` | 1.0.0 | `contrib_shared_paths_setup` | `examples/shared/modules/shared/contrib_shared_paths.sh` | active |
159
162
  | `contrib_shared_umask` | 1.0.0 | `contrib_shared_umask_secure` | `examples/shared/modules/shared/contrib_shared_umask.sh` | active |
160
163
 
161
- These engine-shipped modules predate the owner-segment recommendation and
162
- keep their existing names; renaming them would break every consumer that
163
- already vendors them. New modules should use the owner-segment form.
164
+ The example provider's owner segment is `shared`.
164
165
 
165
166
  Update the index in the same change that adds, renames, deprecates, or
166
167
  removes a shared module. Provider repositories should maintain a corresponding
@@ -181,27 +182,27 @@ Every change to a shared module passes the same floor:
181
182
  and quiet.
182
183
  3. For engine modules, review happens in this repository's normal commit
183
184
  review. For provider modules, review happens in the provider
184
- repository; the consumer re-applies judgment at re-pin time by
185
- reviewing the vendored diff (see the update policy in
186
- [module-abi.md](module-abi.md)).
185
+ repository, and the consumer reviews the vendored diff again when
186
+ copying a new revision into `layers/<provider>/` (see
187
+ [module-abi.md](module-abi.md#layers)).
187
188
 
188
189
  Breaking changes to behavior require a `version=` bump so the skew rule
189
190
  can catch mixed-version compositions.
190
191
 
191
192
  ## Deprecation
192
193
 
193
- A deprecated module keeps shipping unchanged — its bytes stay available
194
- to every consumer that already pinned them — but is marked for eventual
194
+ A deprecated module keeps shipping unchanged, so its bytes stay available
195
+ to every consumer that already pinned them, but it is marked for eventual
195
196
  removal:
196
197
 
197
198
  1. Set the module's status to `deprecated` in this index.
198
199
  2. Freeze its `version=`: no feature work lands; fixes that cannot wait
199
- follow the normal re-pin policy with the deprecation still visible.
200
+ follow the normal update policy with the deprecation still visible.
200
201
  3. State the replacement (another module, or none) in the index row.
201
202
 
202
203
  A module stays deprecated for at least one release before it may be
203
- removed, so consumers see the deprecation in a re-pin before the
204
- disappearance. The loader continues to load a deprecated module;
204
+ removed, so consumers see the deprecation in an update before the
205
+ disappearance. Builds continue to include a deprecated module;
205
206
  deprecation is a signal to consumers, not a gate.
206
207
 
207
208
  ## Removal
@@ -214,6 +215,6 @@ Removing a shared module is a release-visible change:
214
215
  3. Rebuild the manifest and install: the content-derived release ID
215
216
  changes, making the switch to a post-removal release an explicit,
216
217
  reviewed act.
217
- 4. Consumers keep working on their already-installed sealed releases —
218
- each verifies against its own manifest — and notice the removal at
219
- their next re-pin, when the module is absent from the diff.
218
+ 4. Consumers keep working on their already-installed sealed releases,
219
+ each of which verifies against its own manifest, and notice the removal at
220
+ their next update, when the module is absent from the diff.
@@ -2,12 +2,13 @@
2
2
 
3
3
  - `local/` is the smallest example: one metadata file and one POSIX shell
4
4
  module. It demonstrates sourcing a module without installing a release.
5
- - `profile-project/` is a complete consuming project: metadata-driven
6
- modules, a provider layer, a bundle, a variant, and project defaults.
7
- It is the shortest path from a clone to a loaded profile.
8
- - `e2e/` is a sample consumer profile. Its twelve modules cover dependency
9
- resolution, platform and shell selection, exports, optional dependencies,
10
- release installation, and shared-module composition.
5
+ - `profile-project/` is a small complete project: two modules, a provider
6
+ layer, a bundle, and two variants. It is the shortest path from a clone to
7
+ a loaded profile.
8
+ - `e2e/` is the project `tests/e2e.test.sh` builds. Its thirteen modules
9
+ cover dependency resolution, platform and shell selection, exports,
10
+ optional dependencies, a Fish module, and composition with a layer.
11
+ - `shared/` is a sample provider whose modules a project vendors as a layer.
11
12
 
12
13
  ## Complete project
13
14
 
@@ -19,7 +20,8 @@ login shell.
19
20
 
20
21
  ## Minimal module
21
22
 
22
- From the repository root, load the example with:
23
+ `local/` loads through the development loader, without a project or a
24
+ release. From the repository root:
23
25
 
24
26
  ```sh
25
27
  VALISE_MODULE_ROOT="$PWD/examples/local" \
@@ -38,7 +40,6 @@ The metadata is in `examples/local/module.d/hello_valise.meta`; the body is
38
40
 
39
41
  ## Sample consumer profile
40
42
 
41
- `e2e/README.md` describes how to build its release manifest, install and
42
- verify the release, load its modules, and compose the `examples/shared/`
43
- provider. The example installer writes shell integration under `HOME`, so
44
- use a temporary home if you do not want to change your normal startup files.
43
+ [e2e/README.md](e2e/README.md) builds, installs, and verifies that project
44
+ in a temporary home, loads it in each shell, and composes the `shared/`
45
+ provider as a layer.
@@ -1,31 +1,40 @@
1
1
  # End-to-end example
2
2
 
3
- This directory is a sample consuming profile. It includes twelve modules
4
- that exercise dependencies, shell and platform selection, exports, optional
5
- dependencies, and composition with the shared provider in `examples/shared/`.
3
+ This directory is a valise project used by `tests/e2e.test.sh`. Its modules
4
+ exercise dependencies, shell and platform selection, exports, optional
5
+ dependencies, a Fish module, and composition with the shared provider in
6
+ `examples/shared/`.
6
7
 
7
8
  ## Modules
8
9
 
9
10
  | Module | Shells | Platforms | Depends on | Export |
10
11
  |---|---|---|---|---|
11
- | `e2e_env_setup` | sh bash zsh ksh | any | `platform_posix` | `e2e_env_ready` |
12
- | `e2e_aliases` | sh bash zsh ksh | any | `e2e_env_setup` | `e2e_show_aliases` |
12
+ | `e2e_env_setup` | posix | any | `valise_platform_posix` | `e2e_env_ready` |
13
+ | `e2e_aliases` | posix | any | `e2e_env_setup` | `e2e_show_aliases` |
13
14
  | `e2e_completions_bash` | bash | any | `e2e_aliases` | `e2e_bash_completions_loaded` |
14
15
  | `e2e_completions_zsh` | zsh | any | `e2e_aliases` | `e2e_zsh_completions_loaded` |
15
16
  | `e2e_ksh_features` | ksh | any | `e2e_env_setup` | `e2e_ksh_loaded` |
16
17
  | `e2e_fish_features` | fish | any | optional `e2e_env_setup` | `e2e_fish_loaded` |
17
- | `e2e_platform_tools_darwin` | sh bash zsh ksh | darwin | `platform_macos` | `e2e_darwin_tools_ready` |
18
- | `e2e_platform_tools_linux` | sh bash zsh ksh | linux | `platform_linux` | `e2e_linux_tools_ready` |
19
- | `e2e_platform_tools_bsd` | sh bash zsh ksh | bsd | `platform_bsd` | `e2e_bsd_tools_ready` |
20
- | `e2e_optional_network` | sh bash zsh ksh | any | optional `e2e_env_setup` | `e2e_net_available` |
21
- | `e2e_generated_config` | sh bash zsh ksh | any | `e2e_env_setup` | `e2e_config_loaded` |
22
- | `e2e_layer_probe` | sh bash zsh ksh | any | `e2e_env_setup`, optional `contrib_shared_paths` | `e2e_layer_probe_ok` |
23
-
24
- `e2e_layer_probe` depends on a primary-root module and optionally on a
25
- module in the shared layer. It tests dependency resolution in both directions
26
- across the two roots.
27
-
28
- ## Build, install, and verify
18
+ | `e2e_platform_tools` | posix | any | `e2e_env_setup`, optional the three below | none |
19
+ | `e2e_platform_tools_darwin` | posix | darwin | `valise_platform_macos` | `e2e_darwin_tools_ready` |
20
+ | `e2e_platform_tools_linux` | posix | linux | `valise_platform_linux` | `e2e_linux_tools_ready` |
21
+ | `e2e_platform_tools_bsd` | posix | bsd | `valise_platform_bsd` | `e2e_bsd_tools_ready` |
22
+ | `e2e_optional_network` | posix | any | optional `e2e_env_setup` | `e2e_net_available` |
23
+ | `e2e_generated_config` | posix | any | `e2e_env_setup` | `e2e_config_loaded` |
24
+ | `e2e_layer_probe` | posix | any | `e2e_env_setup`, optional `contrib_shared_paths` | `e2e_layer_probe_ok` |
25
+
26
+ `bundles.tsv` gives each shell its roots. The POSIX rows name
27
+ `e2e_platform_tools`, which lists the per-platform modules as optional
28
+ dependencies: a platform module that does not match the running system is
29
+ skipped quietly, while naming it as a root would be a strict-mode failure on
30
+ every other platform. `variants.tsv` has `default` and `no-network`, which
31
+ excludes `e2e_optional_network`.
32
+
33
+ `e2e_layer_probe` optionally depends on `contrib_shared_paths` from the
34
+ shared provider. Without the provider it reports a standalone load; with the
35
+ provider vendored as a layer it reports that the layer resolved.
36
+
37
+ ## Build, install, and load
29
38
 
30
39
  Run these commands from the repository root. Installation writes shell
31
40
  integration under `HOME`; this example uses a temporary home so it does not
@@ -33,7 +42,7 @@ touch your normal startup files.
33
42
 
34
43
  ```sh
35
44
  export PATH="$PWD/bin:$PATH"
36
- sh examples/e2e/build-manifest.sh
45
+ valise -C examples/e2e build
37
46
 
38
47
  _demo=$(mktemp -d)
39
48
  mkdir -p "$_demo/home"
@@ -46,35 +55,20 @@ export XDG_STATE_HOME="$_demo/state"
46
55
  valise release verify
47
56
  ```
48
57
 
49
- The build script copies the engine runtime and shared example into
50
- `examples/e2e/build/release`, then writes `shell/install/profile-release.manifest`
51
- with each file's size and SHA-256 digest using `valise make-manifest`. Generated
52
- release files are isolated in `build/` and can be rebuilt at any time.
58
+ `valise build` writes the release to `examples/e2e/build/release`: one plan
59
+ per POSIX shell class under `plans/`, the Fish runtime under `runtime/fish/`,
60
+ and only the modules some shell loads. `valise install` seals it, makes it
61
+ active, and writes the managed block to `~/.profile` (plus `~/.bashrc` or
62
+ `~/.zshrc` for those shells) and the Fish hook.
53
63
 
54
- Load sample modules in a POSIX shell:
64
+ Start a shell through the startup file valise wrote:
55
65
 
56
66
  ```sh
57
- _active=$(cd "$XDG_CONFIG_HOME/valise/active" && pwd -P)
58
- VALISE_MODULE_ROOT="$_active" \
59
- VALISE_MODULES='e2e_env_setup e2e_aliases e2e_generated_config e2e_optional_network' \
60
- VALISE_MODE=strict \
61
- . "$_active/entrypoints/profile.sh"
62
-
63
- e2e_env_ready
64
- e2e_show_aliases
65
- e2e_config_loaded
67
+ bash -c '. "$HOME/.bashrc"; e2e_env_ready; e2e_show_aliases; e2e_config_loaded'
68
+ fish -c 'functions -q e2e_fish_loaded; and valise release verify'
66
69
  ```
67
70
 
68
- Try the Fish module in a new Fish process. The installed `conf.d` hook loads
69
- the sealed release at startup, so set the module list in the child's
70
- environment before starting Fish:
71
-
72
- ```sh
73
- VALISE_MODULES=e2e_fish_features VALISE_MODE=strict fish -c \
74
- 'functions -q e2e_fish_loaded; and valise release verify'
75
- ```
76
-
77
- When finished, stop using the functions and remove the temporary installation:
71
+ When finished, remove the temporary installation:
78
72
 
79
73
  ```sh
80
74
  chmod -R u+w "$_demo"
@@ -83,31 +77,30 @@ rm -rf "$_demo"
83
77
 
84
78
  ## Shared provider composition
85
79
 
86
- The build script vendors `examples/shared/` under `layer/shared/` and records
87
- its source revision in `layer/shared/layer-pin.txt`. The release manifest
88
- covers both the profile and provider files. After the build, installation,
89
- and verification above, load the cross-root probe and shared utilities:
80
+ A project composes a provider by vendoring its tree as `layers/<provider>/`.
81
+ To try it, copy this project, vendor `examples/shared/` as `layers/shared/`,
82
+ and add the provider's modules to the POSIX roots:
90
83
 
91
84
  ```sh
92
- _active=$(cd "$XDG_CONFIG_HOME/valise/active" && pwd -P)
93
- VALISE_MODULE_ROOT="$_active" \
94
- VALISE_MODULE_PATH="$_active/layer/shared" \
95
- VALISE_MODULES='e2e_layer_probe contrib_shared_paths contrib_shared_umask' \
96
- VALISE_MODE=strict \
97
- . "$_active/entrypoints/profile.sh"
98
-
99
- e2e_layer_probe_ok
100
- contrib_shared_paths_setup
101
- contrib_shared_umask_secure # explicitly changes umask to 077
85
+ _proj=$(mktemp -d)
86
+ cp -R examples/e2e/valise.conf examples/e2e/variants.tsv \
87
+ examples/e2e/module.d examples/e2e/modules "$_proj/"
88
+ mkdir -p "$_proj/layers/shared"
89
+ cp -R examples/shared/module.d examples/shared/modules "$_proj/layers/shared/"
90
+ awk -F '\t' 'BEGIN { OFS = "\t" } NR > 1 && $2 != "fish" { $3 = $3 " contrib_shared_umask" } { print }' \
91
+ examples/e2e/bundles.tsv >"$_proj/bundles.tsv"
92
+ valise -C "$_proj" build
102
93
  ```
103
94
 
104
- The provider modules are POSIX-only; Fish users can load the profile's Fish
105
- modules but not these utilities. To update the provider in a real consuming
106
- project, vendor a reviewed commit, inspect the diff, then rebuild and verify
107
- the release. See [the module ABI](../../docs/module-abi.md) for multi-root
108
- resolution and [the installation guide](../../docs/installation.md) for the
109
- integrity and provenance limits.
110
-
111
- `tests/e2e.test.sh` runs the install, verification, tamper, and composition
112
- scenarios in quarantined homes. It also runs available host-shell lanes;
113
- configured Lima Linux, BusyBox, and BSD lanes run when their VMs are present.
95
+ The release then carries the provider's modules under `layers/shared/`, and
96
+ `e2e_layer_probe_ok` reports that the shared layer resolved. The provider
97
+ modules are POSIX-only, so the Fish closure is unchanged. To update a
98
+ vendored provider in a real project, copy a reviewed commit, inspect the
99
+ diff, then rebuild and verify. See [the module ABI](../../docs/module-abi.md)
100
+ for dependency resolution and [the installation guide](../../docs/installation.md)
101
+ for the integrity and provenance limits.
102
+
103
+ `tests/e2e.test.sh` runs these scenarios in quarantined homes: every
104
+ available host shell, a tamper lane, and the composition lane. Configured
105
+ Lima Linux, BusyBox, and BSD guests run the same install and load checks
106
+ when their VMs are present.
@@ -0,0 +1,6 @@
1
+ bundle shell roots
2
+ default sh e2e_env_setup e2e_generated_config e2e_optional_network e2e_layer_probe e2e_platform_tools
3
+ default bash e2e_env_setup e2e_generated_config e2e_optional_network e2e_layer_probe e2e_platform_tools e2e_aliases e2e_completions_bash
4
+ default zsh e2e_env_setup e2e_generated_config e2e_optional_network e2e_layer_probe e2e_platform_tools e2e_aliases e2e_completions_zsh
5
+ default ksh e2e_env_setup e2e_generated_config e2e_optional_network e2e_layer_probe e2e_platform_tools e2e_ksh_features
6
+ default fish e2e_fish_features
@@ -1,9 +1,8 @@
1
1
  name=e2e_aliases
2
2
  requires=e2e_env_setup
3
3
  optional=
4
- shells=sh bash zsh ksh
4
+ shells=posix bash zsh ksh
5
5
  platforms=any
6
6
  side_effect=read-only
7
7
  exports=e2e_show_aliases
8
- updates=
9
8
  load=modules/e2e/aliases.sh
@@ -5,5 +5,4 @@ shells=bash
5
5
  platforms=any
6
6
  side_effect=read-only
7
7
  exports=e2e_bash_completions_loaded
8
- updates=
9
8
  load=modules/e2e/completions_bash.sh
@@ -5,5 +5,4 @@ shells=zsh
5
5
  platforms=any
6
6
  side_effect=read-only
7
7
  exports=e2e_zsh_completions_loaded
8
- updates=
9
8
  load=modules/e2e/completions_zsh.sh
@@ -1,9 +1,8 @@
1
1
  name=e2e_env_setup
2
- requires=platform_posix
2
+ requires=valise_platform_posix
3
3
  optional=
4
- shells=sh bash zsh ksh
4
+ shells=posix bash zsh ksh
5
5
  platforms=any
6
6
  side_effect=read-only
7
7
  exports=e2e_env_ready
8
- updates=
9
8
  load=modules/e2e/env_setup.sh
@@ -5,5 +5,4 @@ shells=fish
5
5
  platforms=any
6
6
  side_effect=read-only
7
7
  exports=e2e_fish_loaded
8
- updates=
9
8
  load=modules/e2e/fish_features.fish