valise-sh 0.1.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.
- package/CHANGELOG.md +320 -9
- package/README.md +104 -127
- package/bin/valise +67 -3266
- package/docs/architecture.md +76 -51
- package/docs/contrib-modules.md +180 -173
- package/docs/installation.md +210 -69
- package/docs/module-abi.md +211 -148
- package/docs/projects.md +249 -0
- package/docs/release-policy.md +90 -11
- package/docs/shared-modules.md +149 -26
- package/examples/README.md +20 -8
- package/examples/e2e/README.md +61 -68
- package/examples/e2e/bundles.tsv +6 -0
- package/examples/e2e/module.d/e2e_aliases.meta +1 -2
- package/examples/e2e/module.d/e2e_completions_bash.meta +0 -1
- package/examples/e2e/module.d/e2e_completions_zsh.meta +0 -1
- package/examples/e2e/module.d/e2e_env_setup.meta +2 -3
- package/examples/e2e/module.d/e2e_fish_features.meta +0 -1
- package/examples/e2e/module.d/e2e_generated_config.meta +1 -2
- package/examples/e2e/module.d/e2e_ksh_features.meta +0 -1
- package/examples/e2e/module.d/e2e_layer_probe.meta +1 -2
- package/examples/e2e/module.d/e2e_optional_network.meta +1 -2
- package/examples/e2e/module.d/e2e_platform_tools.meta +8 -0
- package/examples/e2e/module.d/e2e_platform_tools_bsd.meta +2 -3
- package/examples/e2e/module.d/e2e_platform_tools_darwin.meta +2 -3
- package/examples/e2e/module.d/e2e_platform_tools_linux.meta +2 -3
- package/examples/e2e/valise.conf +4 -0
- package/examples/e2e/variants.tsv +3 -0
- package/examples/local/module.d/hello_valise.meta +1 -2
- package/examples/profile-project/README.md +151 -0
- package/examples/profile-project/bundles.tsv +8 -0
- package/examples/profile-project/layers/demo/module.d/contrib_demo_greeting.meta +9 -0
- package/examples/profile-project/layers/demo/modules/shared/contrib_demo_greeting.sh +4 -0
- package/examples/profile-project/module.d/greeting.meta +9 -0
- package/examples/profile-project/module.d/profile_main.meta +8 -0
- package/examples/profile-project/modules/greeting.sh +5 -0
- package/examples/profile-project/valise.conf +4 -0
- package/examples/profile-project/variants.tsv +3 -0
- package/examples/shared/README.md +13 -34
- package/examples/shared/module.d/contrib_shared_paths.meta +2 -3
- package/examples/shared/module.d/contrib_shared_umask.meta +1 -2
- package/examples/shared/modules/shared/contrib_shared_paths.sh +2 -2
- package/lib/capabilities.sh +40 -13
- package/lib/cli/commands.sh +278 -0
- package/lib/cli/common.sh +326 -0
- package/lib/cli/devtools.sh +539 -0
- package/lib/cli/fish-hook.sh +986 -0
- package/lib/cli/integration.sh +337 -0
- package/lib/cli/lifecycle.sh +578 -0
- package/lib/cli/project.sh +1807 -0
- package/lib/cli/store.sh +1023 -0
- package/lib/cli/usage.sh +308 -0
- package/lib/compiler.awk +352 -24
- package/lib/fish/loader.fish +163 -28
- package/lib/fish/metadata.fish +62 -19
- package/lib/fish/profile.fish +170 -0
- package/lib/loader.sh +736 -158
- package/lib/metadata.sh +137 -55
- package/manifests/parser-support.tsv +2 -2
- package/module.d/valise_editor.meta +9 -0
- package/module.d/valise_history.meta +9 -0
- package/module.d/valise_pager.meta +9 -0
- package/module.d/valise_path.meta +9 -0
- package/module.d/{platform_bsd.meta → valise_platform_bsd.meta} +3 -4
- package/module.d/{platform_linux.meta → valise_platform_linux.meta} +3 -4
- package/module.d/{platform_macos.meta → valise_platform_macos.meta} +3 -4
- package/module.d/{platform_posix.meta → valise_platform_posix.meta} +2 -3
- package/module.d/valise_xdg.meta +9 -0
- package/modules/system/{contrib_editor.sh → valise_editor.sh} +2 -2
- package/modules/system/{contrib_history.sh → valise_history.sh} +2 -2
- package/modules/system/{contrib_pager.sh → valise_pager.sh} +2 -2
- package/modules/system/{contrib_path.sh → valise_path.sh} +3 -3
- package/modules/system/{contrib_xdg.sh → valise_xdg.sh} +2 -2
- package/package.json +91 -9
- package/docs/variants.md +0 -63
- package/entrypoints/.gitkeep +0 -0
- package/entrypoints/fish/profile.fish +0 -99
- package/examples/e2e/build-manifest.sh +0 -250
- package/examples/local/.gitkeep +0 -0
- package/lib/.gitkeep +0 -0
- package/manifests/.gitkeep +0 -0
- package/module.d/.gitkeep +0 -0
- package/module.d/contrib_editor.meta +0 -10
- package/module.d/contrib_history.meta +0 -10
- package/module.d/contrib_pager.meta +0 -10
- package/module.d/contrib_path.meta +0 -10
- package/module.d/contrib_xdg.meta +0 -10
- package/modules/.gitkeep +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,14 +3,325 @@
|
|
|
3
3
|
Notable user-facing changes are recorded here. Versions before 1.0 may include
|
|
4
4
|
module ABI or CLI changes; see [the release policy](docs/release-policy.md).
|
|
5
5
|
|
|
6
|
-
##
|
|
6
|
+
## [0.3.0] - 2026-11-06
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
0.3.0 changes the project layout, the metadata, and the release format. A
|
|
9
|
+
0.2 project must be moved to the new layout and its releases rebuilt; see
|
|
10
|
+
[What changed in 0.3.0](docs/release-policy.md#what-changed-in-030).
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Published commands. Metadata `commands=` names exports to publish and
|
|
15
|
+
`executables=` names scripts. `valise build` writes a command plan per
|
|
16
|
+
module under `plans/commands/` and a launcher per name under `bin/`, and
|
|
17
|
+
install writes a stub for each into
|
|
18
|
+
`${VALISE_BIN_DIR:-${XDG_BIN_HOME:-$HOME/.local/bin}}`. valise records
|
|
19
|
+
the stubs it writes in `$XDG_STATE_HOME/valise/commands.tsv` and never
|
|
20
|
+
replaces or removes a file it did not write. `valise doctor` reports
|
|
21
|
+
collisions and a command directory missing from `PATH`.
|
|
22
|
+
- `valise lint [--require-parsers] [module...]` checks metadata, layers,
|
|
23
|
+
every bundle compiled for every variant and shell, and the syntax of each
|
|
24
|
+
body and test with the parser of every shell the module declares. The
|
|
25
|
+
`valise.conf` key `lint_layer_forbid` makes lint reject a pattern, such as
|
|
26
|
+
an employer name, anywhere under `layers/`.
|
|
27
|
+
- `valise test [--shell=<class>] [--require-shells] [module...]` runs each
|
|
28
|
+
module's `tests=` scripts in every declared shell that is installed, in
|
|
29
|
+
an `env -i` environment with a fresh `HOME` and XDG tree.
|
|
30
|
+
`valise_test_reload` lets a test write fixtures and load the module again.
|
|
31
|
+
- `valise run [--shell=<class>] [--module=<m>]... [--bundle=<b>]
|
|
32
|
+
[--variant=<v>] [--keep-env] -- <script>` loads modules into a shell and
|
|
33
|
+
runs a script there.
|
|
34
|
+
- `valise env` prints the engine, project, and storage paths as shell-quoted
|
|
35
|
+
`KEY=value` lines.
|
|
36
|
+
- `valise test` and `valise run` export `VALISE_TEST_RELEASE` and
|
|
37
|
+
`VALISE_TEST_PLAN`, so a test can load the same modules in a child shell.
|
|
38
|
+
- `valise uninstall [--keep-releases]` removes the managed blocks (keeping
|
|
39
|
+
every other byte and the file mode), the startup files install created
|
|
40
|
+
that are left empty, the Fish hook, the owned command stubs, the active
|
|
41
|
+
link, and the installed releases.
|
|
42
|
+
- `valise release rollback` makes the previously active release active
|
|
43
|
+
again. Every switch records the release it replaced in
|
|
44
|
+
`$XDG_STATE_HOME/valise/previous`.
|
|
45
|
+
- `valise apply --dry-run` builds the project and prints what install would
|
|
46
|
+
change in the release store, the startup files, the Fish hook, and the
|
|
47
|
+
command directory, without writing outside `build/`.
|
|
48
|
+
- A bundle's `fish` rows build the native Fish runtime into the release
|
|
49
|
+
under `runtime/fish/`, and the Fish hook loads the bundle's Fish roots
|
|
50
|
+
from it. `valise new` scaffolds a Fish seed module.
|
|
51
|
+
- `valise -C <dir>` runs a command as if started in `dir`. Project commands
|
|
52
|
+
find the project from any subdirectory.
|
|
53
|
+
- `valise.conf` key `requires_valise`: an older valise refuses to build the
|
|
54
|
+
project.
|
|
55
|
+
- `valise module new --into=<module>[,...]` and `--no-wire` for projects
|
|
56
|
+
whose default bundle has several POSIX roots.
|
|
57
|
+
- Metadata `tests=` names the test scripts of a module.
|
|
58
|
+
- `shells=posix` names every POSIX shell.
|
|
59
|
+
- `docs/projects.md` describes the project layout, bundles, variants,
|
|
60
|
+
compile, and build.
|
|
61
|
+
|
|
62
|
+
### Changed
|
|
63
|
+
|
|
64
|
+
- A project is the directory holding `valise.conf`, with `module.d/`,
|
|
65
|
+
`modules/`, `layers/<provider>/`, `bundles.tsv`, and `variants.tsv` at its
|
|
66
|
+
root. `valise.conf` replaces `shell/release/project.conf`, `bundles.tsv`
|
|
67
|
+
replaces `shell/release/bundle-roots`, and `variants.tsv` replaces
|
|
68
|
+
`shell/release/install-variants`. The `shell/` layout is not read.
|
|
69
|
+
- The registry is internal: `valise build` generates it on demand from the
|
|
70
|
+
metadata, and `valise registry` prints it. It has columns for `commands`,
|
|
71
|
+
`executables`, and `tests` and a `source` of `module.d`,
|
|
72
|
+
`layers/<provider>/module.d`, or `valise`.
|
|
73
|
+
- The engine modules are renamed into the reserved `valise_` namespace
|
|
74
|
+
(`valise_path`, `valise_editor`, `valise_history`, `valise_pager`,
|
|
75
|
+
`valise_xdg`, `valise_platform_posix`, `valise_platform_macos`,
|
|
76
|
+
`valise_platform_linux`, `valise_platform_bsd`), with exports renamed to
|
|
77
|
+
match, such as `valise_path_prepend`. They are available to every
|
|
78
|
+
project without vendoring. A project or layer module may not use the
|
|
79
|
+
`valise_` prefix, and layer modules must use `contrib_`.
|
|
80
|
+
- `shells=sh` names only the generic POSIX class (dash, BusyBox ash, and
|
|
81
|
+
other plain `sh`), so `shells=sh bash ksh` loads in dash, bash, and ksh
|
|
82
|
+
and not in zsh. Use `shells=posix` for every POSIX shell.
|
|
83
|
+
- Release format 2. A release holds `plans/<shell>.sh` for `sh`, `bash`,
|
|
84
|
+
`zsh`, and `ksh`, `runtime/capabilities.sh`, `valise-release.conf`
|
|
85
|
+
(`format=2`, the bundle, the variant, the roots per shell, the modules,
|
|
86
|
+
and the commands), and `manifest.tsv`. It contains only the modules some
|
|
87
|
+
plan loads, so a module a variant excludes is absent with its body.
|
|
88
|
+
Install refuses a tree without `format=2`.
|
|
89
|
+
- The POSIX managed block picks the plan for `ksh`, `zsh`, `bash`, or `sh`
|
|
90
|
+
and sets its guard only after the plan loaded, so a later startup file
|
|
91
|
+
retries after a failure.
|
|
92
|
+
- Install is transactional. It checks every startup file, the Fish hook
|
|
93
|
+
path, and (when commands are published or already tracked) the command
|
|
94
|
+
directory before changing the active release and, if a later step fails,
|
|
95
|
+
restores the previous active release, the previous-release record, and
|
|
96
|
+
the command stubs, and names the files it already wrote. A new managed
|
|
97
|
+
block is appended with nothing around it, so uninstall restores the file
|
|
98
|
+
exactly. Text after a block keeps the file's ending, with or without a
|
|
99
|
+
final newline, and a repeat install rewrites nothing.
|
|
100
|
+
- Install warns, and `valise doctor` fails, on a line outside a managed block
|
|
101
|
+
that loads valise by hand.
|
|
102
|
+
- `valise build` moves the previous `build/release` aside and restores it if
|
|
103
|
+
publication fails.
|
|
104
|
+
- An identical installed Fish hook is left in place, and apply reports
|
|
105
|
+
`Fish hook current`.
|
|
106
|
+
- `valise status` reports the bundle, variant, and valise version the active
|
|
107
|
+
release was built with, separately from the project defaults.
|
|
108
|
+
- `valise explain-variant` counts the roots and modules a variant keeps per
|
|
109
|
+
shell, resolving qualified names.
|
|
110
|
+
- `bin/valise` is a dispatcher over the parts in `lib/cli/`.
|
|
111
|
+
- The package `files` list names every shipped file, so packing a local tree
|
|
112
|
+
ships only the runtime, the docs, and the example sources, not stray local
|
|
113
|
+
files. A test fails when a tracked file is missing from the list.
|
|
114
|
+
|
|
115
|
+
### Removed
|
|
116
|
+
|
|
117
|
+
- The `shell/` project layout, `registry --check`, and the committed
|
|
118
|
+
registry.
|
|
119
|
+
- Metadata `updates=`. Metadata naming it fails with a message naming
|
|
120
|
+
0.3.0.
|
|
121
|
+
- The engine release shape: `entrypoints/fish/profile.fish`, the POSIX
|
|
122
|
+
block's loader fallback, and the Fish hook's `generated/`, `vendor/`, and
|
|
123
|
+
entrypoint routes.
|
|
124
|
+
- `examples/e2e/build-manifest.sh`; `examples/e2e` is a valise project built
|
|
125
|
+
with `valise build`.
|
|
126
|
+
- `docs/variants.md`, replaced by `docs/projects.md`.
|
|
127
|
+
|
|
128
|
+
### Fixed
|
|
129
|
+
|
|
130
|
+
- `sp_cap_secure_local_bin_check` accepts `allow-owned-symlinks`. The default
|
|
131
|
+
still rejects every symlink in `~/.local/bin`; the option accepts a symlink
|
|
132
|
+
whose link entry is owned by the current user, which is how pipx and uv
|
|
133
|
+
publish commands, while still rejecting unowned entries and group- or
|
|
134
|
+
other-writable regular files.
|
|
135
|
+
- A repeated metadata field was silently overwritten by the last value; the
|
|
136
|
+
POSIX and Fish readers now reject it.
|
|
137
|
+
- The Fish loader rejected caller aliases, because `functions --copy` drops
|
|
138
|
+
`--wraps`.
|
|
139
|
+
- Fish 3 lists autoloadable but undefined functions in `functions --all
|
|
140
|
+
--names`, and that list grows as the loader introspects it. The Fish loader
|
|
141
|
+
and the generated hook now take their "created by this activation" baseline
|
|
142
|
+
after that introspection, so Fish's own system functions are no longer
|
|
143
|
+
attributed to a module or an entrypoint and published in an ownership
|
|
144
|
+
ledger whose `/usr/share/fish` source can never be authenticated.
|
|
145
|
+
- A body that replaced `cd` on Fish 3, where `cd` is a file-backed system
|
|
146
|
+
function rather than an embedded one, was reported as a generic loader-state
|
|
147
|
+
mutation. It now fails closed as a mutated critical Fish function, matching
|
|
148
|
+
Fish 4.
|
|
149
|
+
- A module body that sourced a Fish completion or function file, or ran
|
|
150
|
+
completions, materialized Fish's own system functions. Those entered the
|
|
151
|
+
ownership ledger, so the next activation failed closed before its cleanup
|
|
152
|
+
erased real Fish functions. Fish system functions are no longer recorded as
|
|
153
|
+
module- or entrypoint-owned, on Fish 3 (file paths) and Fish 4 (embedded
|
|
154
|
+
paths) alike.
|
|
155
|
+
- `valise doctor` did not accept FreeBSD's `sha256`.
|
|
156
|
+
- `valise module new` assumed the seed module was `profile_main`.
|
|
157
|
+
|
|
158
|
+
## [0.2.0] - 2026-10-31
|
|
159
|
+
|
|
160
|
+
### Added
|
|
161
|
+
|
|
162
|
+
- `valise new`, `valise module new`, `valise module list`,
|
|
163
|
+
`valise module remove`, `valise build`, `valise apply`, and
|
|
164
|
+
`valise status`. A new project can be scaffolded, given a module, built,
|
|
165
|
+
installed, and checked without hand-writing a registry or a build script.
|
|
166
|
+
`valise module new` writes the module body and its declared export, and
|
|
167
|
+
wires the module into the seed aggregator. `valise apply` builds, installs,
|
|
168
|
+
writes the shell integration, and verifies the result; it is idempotent.
|
|
169
|
+
`valise status` reports the project, the active release, the integration
|
|
170
|
+
state, and whether the active release has drifted from the build output.
|
|
171
|
+
- `valise registry`, which generates `shell/release/module-registry.tsv` from
|
|
172
|
+
the project's metadata. `valise build` regenerates and validates the
|
|
173
|
+
registry, so a committed registry is a generated artifact rather than a
|
|
174
|
+
hand-maintained catalog. The row order is fixed: the primary modules of
|
|
175
|
+
`shell/module.d/` first, then the layer modules of each
|
|
176
|
+
`shell/layers/<provider>/module.d/`, each group in C-locale name order.
|
|
177
|
+
- `valise release list`, `valise release use`, `valise release prune`, and
|
|
178
|
+
`valise release verify`. They manage installed releases; source variants
|
|
179
|
+
remain the business of `valise build` and `valise apply`.
|
|
180
|
+
- Command-specific `--help` for `build`, `compile`, `install`, `init`, `new`,
|
|
181
|
+
`module`, `release`, `doctor`, and `status`, so each prints its own
|
|
182
|
+
contract rather than the global command list.
|
|
183
|
+
- Meta modules: metadata with `requires=` and no `load` is a
|
|
184
|
+
dependency-only aggregator and loads successfully without a body. `load`
|
|
185
|
+
and `requires` may be combined.
|
|
186
|
+
- `side_effect=local-state`, a source-safe side-effect class for modules
|
|
187
|
+
that write under the XDG state directory.
|
|
188
|
+
- `VALISE_RELOAD=1`, which unsets the declared exports of the requested
|
|
189
|
+
closure before loading so a profile can be re-sourced.
|
|
190
|
+
- The `sp_cap_*` capability helpers remain available at runtime after a
|
|
191
|
+
compiled plan or a loader load finishes, so a module can call them.
|
|
192
|
+
- `examples/profile-project/`, a complete consuming project with two
|
|
193
|
+
modules, a provider layer, two variants, and a bundle, and a README that
|
|
194
|
+
walks from clone to a loaded profile.
|
|
195
|
+
- A consumer end-to-end test target that builds the reference consumer
|
|
196
|
+
profile from a temporary copy, runs the consumer's own metadata, shells,
|
|
197
|
+
release, and features suites, installs and verifies the release, and
|
|
198
|
+
proves a second build is byte-identical. The original tree and the live
|
|
199
|
+
profile are never touched.
|
|
200
|
+
|
|
201
|
+
### Changed
|
|
202
|
+
|
|
203
|
+
- `valise build` builds a complete release tree to `build/release` by
|
|
204
|
+
default, reads the variant and bundle defaults from
|
|
205
|
+
`shell/release/project.conf`, and requires an explicit output directory to
|
|
206
|
+
be empty or absent. A failed build preserves the previous build output.
|
|
207
|
+
- `valise build` produces no Fish surface: no Fish entrypoint, generated
|
|
208
|
+
plan, or native loader. A built release therefore loads nothing in Fish;
|
|
209
|
+
the Fish hook verifies the active release and stays silent. Only an engine
|
|
210
|
+
release with `entrypoints/fish/profile.fish` uses the native Fish loader.
|
|
211
|
+
- `valise install` writes shell integration by default. It always writes
|
|
212
|
+
`~/.profile`; it adds `~/.bash_profile` or `~/.bash_login` when one of
|
|
213
|
+
those exists, because bash reads that file instead of `~/.profile`; it
|
|
214
|
+
writes `~/.bashrc` when bash is the current shell or that file exists; it
|
|
215
|
+
writes `~/.zprofile` when zsh is on `PATH` or that file exists, because zsh
|
|
216
|
+
reads nothing else at login; and it writes `~/.zshrc` when zsh is the
|
|
217
|
+
current shell or that file exists. Existing files are kept current rather
|
|
218
|
+
than replaced. A symlinked startup file is reported and left untouched.
|
|
219
|
+
`--no-integration` installs without writing any startup file. Install also
|
|
220
|
+
writes the Fish `conf.d` hook when it finds Fish in a trusted location;
|
|
221
|
+
`valise apply` runs the same install path.
|
|
222
|
+
- The startup integration is a managed block between `# BEGIN valise managed
|
|
223
|
+
block` and `# END valise managed block`. Repeat installs are idempotent and
|
|
224
|
+
existing profile content is preserved. An unpaired marker is refused and
|
|
225
|
+
stops the install. Install prints each path it wrote and how to remove the
|
|
226
|
+
block.
|
|
227
|
+
- `valise init` takes `posix` or `fish`; any other argument is rejected.
|
|
228
|
+
It is a one-time snippet generator, not something to evaluate at every
|
|
229
|
+
prompt.
|
|
230
|
+
- A project's default variant is `default`. An unknown variant is an error
|
|
231
|
+
in every command that accepts one.
|
|
232
|
+
- Compiled plans and the loader now agree on required dependency closure.
|
|
233
|
+
Platform skips are recorded during discovery and reported once the full
|
|
234
|
+
required closure is known; strict mode fails when a required module is
|
|
235
|
+
blocked during ordering; permissive mode continues and returns zero. Fish
|
|
236
|
+
reports a platform-skipped optional dependency silently.
|
|
237
|
+
- Compiled plans reach parity with the loader: they gate modules by
|
|
238
|
+
`platforms=` at runtime, pre-check and post-check declared exports, report
|
|
239
|
+
each failing module by name, continue past a failure in permissive mode
|
|
240
|
+
while returning zero, stop in strict mode, and support meta modules with no
|
|
241
|
+
source line.
|
|
242
|
+
- The loader saves the logical `$PWD` and `$OLDPWD` before sourcing each
|
|
243
|
+
module and restores them afterwards, so a module that changes directory
|
|
244
|
+
during its load leaves the caller's logical directory as it was.
|
|
245
|
+
- The loader's export pre-check accepts a name that currently resolves to an
|
|
246
|
+
external command, which is how a deliberate wrapper is exported. It still
|
|
247
|
+
rejects a name already defined as a function, builtin, or alias.
|
|
248
|
+
- The loader resolves each metadata record with shell builtins instead of
|
|
249
|
+
repeated `sed`, `grep`, and `cat` processes, so the number of external
|
|
250
|
+
processes a load spawns does not grow with the number of modules.
|
|
251
|
+
- `valise compile` and `valise build` find the packaged
|
|
252
|
+
`lib/capabilities.sh` relative to the CLI, so a symlinked or relocated
|
|
253
|
+
install works. A compiled plan rejects a module that has neither a load
|
|
254
|
+
path nor dependencies, and names the module.
|
|
255
|
+
- Layer handling accepts any `shell/layers/<provider>` path rather than only
|
|
256
|
+
the `contrib` provider, and produces a deterministic manifest.
|
|
257
|
+
- `valise doctor` reports a missing active release as a failure and reads the
|
|
258
|
+
startup files the running shell actually reads. `--pre-install` skips the
|
|
259
|
+
release and integration checks; `--no-integration` checks only the
|
|
260
|
+
environment and the active release.
|
|
261
|
+
- `valise explain-bundles` and `valise layer-lint` are implemented in POSIX sh
|
|
262
|
+
and awk. `layer-lint` validates a provider layer's structure, `contrib_`
|
|
263
|
+
name prefix, version, load path, symlink freedom, file modes, and
|
|
264
|
+
dependency containment.
|
|
265
|
+
- The unused Python consumer-release helpers, wrapper lifecycle hooks, and
|
|
266
|
+
the submodule build prelude override are gone. No command requires
|
|
267
|
+
Python 3.
|
|
268
|
+
|
|
269
|
+
### Removed
|
|
270
|
+
|
|
271
|
+
- `load_hook` and the compatibility bridge in the POSIX loader, the Fish
|
|
272
|
+
loader, and compiled plans. A module declares `load`, `requires`, or both.
|
|
273
|
+
Metadata naming `load_hook` fails with
|
|
274
|
+
`metadata field load_hook is not supported; use load`.
|
|
275
|
+
- `variant list`, `variant use`, and `verify-active`; installed releases are
|
|
276
|
+
managed by `valise release list|use|prune|verify`. `variant` now refers
|
|
277
|
+
only to build variants.
|
|
278
|
+
- The per-shell `valise init` arguments `bash`, `zsh`, `ksh`, and `sh`; use
|
|
279
|
+
`valise init posix` or `valise init fish`.
|
|
280
|
+
|
|
281
|
+
### Fixed
|
|
282
|
+
|
|
283
|
+
- `valise` with no arguments: under `set -e`, a zero-argument `shift` could
|
|
284
|
+
terminate the CLI before it displayed its help text.
|
|
285
|
+
- Fish activation: functions loaded from package paths such as Homebrew are
|
|
286
|
+
authenticated and preserved through the load instead of being rejected or
|
|
287
|
+
lost.
|
|
288
|
+
- The primary-root symlink diagnostic was printed on stdout while every
|
|
289
|
+
other loader diagnostic went to stderr.
|
|
290
|
+
- `valise compile` reported that a Fish plan requires a Python compiler and
|
|
291
|
+
named a file that does not exist in this repository. Fish plans are not
|
|
292
|
+
generated; a Fish integration uses the native Fish loader.
|
|
293
|
+
- Applying to a home directory with a trailing slash could skip the zsh
|
|
294
|
+
startup file, because the target was compared against the raw `HOME`
|
|
295
|
+
string rather than a normalized path.
|
|
296
|
+
- A built release's Fish hook printed an error on every Fish start. It now
|
|
297
|
+
verifies the release quietly and returns when there is no Fish surface to
|
|
298
|
+
load.
|
|
299
|
+
- A module that makes `PWD`, `OLDPWD`, or `IFS` readonly no longer aborts the
|
|
300
|
+
loader mid-transaction. The module fails as caller-state modification, and
|
|
301
|
+
the loader's cleanup still runs.
|
|
302
|
+
- Loader temp-directory cleanup resolves `rm` from a fixed absolute path, so a
|
|
303
|
+
module that changes `PATH` cannot leave its metadata scratch directory
|
|
304
|
+
behind.
|
|
305
|
+
- Compiled plans remove a failed module's declared exports, like the loader.
|
|
306
|
+
A meta module that declares exports is rejected at compile time, and an
|
|
307
|
+
optional-only cycle inside a required graph is quarantined instead of
|
|
308
|
+
failing the whole plan.
|
|
309
|
+
- The compiler rejects an unsafe layer directory name and a reserved-word
|
|
310
|
+
export instead of emitting an unparseable or misleading plan.
|
|
311
|
+
- `release list`, `release use`, `release prune`, `doctor`, and `status`
|
|
312
|
+
identify the active release by its canonical directory name, so a trailing
|
|
313
|
+
slash or an alias symlink cannot hide it from the list or make prune delete
|
|
314
|
+
it.
|
|
315
|
+
- `module remove` keeps a body that another module still loads, and checks
|
|
316
|
+
every directory it will rewrite before changing anything. `module new`
|
|
317
|
+
checks the seed metadata before writing and rejects reserved-word exports.
|
|
318
|
+
- `make-manifest` rejects a directory or symlink as its output, and a
|
|
319
|
+
normalized in-tree output path is excluded from its own manifest.
|
|
320
|
+
- `valise install` holds its lock through the Fish and POSIX integration
|
|
321
|
+
writes, so concurrent installs cannot interleave them.
|
|
322
|
+
- The editor-defaults test is independent of host-installed editors by
|
|
9
323
|
supplying a temporary test `vi` executable.
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
-
|
|
13
|
-
|
|
14
|
-
rejected or lost.
|
|
15
|
-
- Added an isolated sample install walkthrough and documented the release
|
|
16
|
-
checklist.
|
|
324
|
+
|
|
325
|
+
[0.3.0]: https://github.com/joeycumines/valise-sh/compare/v0.2.0...v0.3.0
|
|
326
|
+
[0.2.0]: https://github.com/joeycumines/valise-sh/compare/v0.1.0...v0.2.0
|
|
327
|
+
[0.1.0]: https://github.com/joeycumines/valise-sh/releases/tag/v0.1.0
|
package/README.md
CHANGED
|
@@ -1,146 +1,123 @@
|
|
|
1
1
|
# valise-sh
|
|
2
2
|
|
|
3
|
-
valise
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
engine is designed to be vendored by that project, for example as a Git
|
|
14
|
-
submodule; the consumer owns its profile and release contents.
|
|
15
|
-
|
|
16
|
-
## Try a sample release
|
|
17
|
-
|
|
18
|
-
This walkthrough builds and installs the included sample profile in an
|
|
19
|
-
isolated temporary home. `valise install` deploys its normal shell
|
|
20
|
-
integration there, so your real home directory and startup files are left
|
|
21
|
-
untouched.
|
|
3
|
+
valise builds your shell profile from modules. Each module is a metadata file
|
|
4
|
+
and a shell body; valise reads the metadata as data, compiles a static
|
|
5
|
+
startup plan for each shell, and installs the result as a sealed, verified
|
|
6
|
+
release. sh, dash, BusyBox ash, bash, zsh, and ksh load the compiled POSIX
|
|
7
|
+
plans; Fish has a native loader.
|
|
8
|
+
|
|
9
|
+
You keep your modules in a valise project. The engine supplies the `valise`
|
|
10
|
+
CLI and a few generic modules (`valise_path`, `valise_editor`, and others).
|
|
11
|
+
|
|
12
|
+
## Quick start
|
|
22
13
|
|
|
23
14
|
```sh
|
|
24
15
|
git clone https://github.com/joeycumines/valise-sh.git
|
|
25
|
-
|
|
26
|
-
|
|
16
|
+
export PATH="$PWD/valise-sh/bin:$PATH"
|
|
17
|
+
|
|
18
|
+
valise new my-profile
|
|
19
|
+
cd my-profile
|
|
20
|
+
valise module new hello --exports=hello
|
|
21
|
+
$EDITOR modules/hello.sh
|
|
22
|
+
valise lint
|
|
23
|
+
valise apply
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
`valise apply` builds the project, installs the release, writes a managed
|
|
27
|
+
block into your startup files, and verifies the active release. Open a new
|
|
28
|
+
login shell to load it. `valise apply --dry-run` shows what would change
|
|
29
|
+
first, and `valise uninstall` removes everything install wrote.
|
|
27
30
|
|
|
28
|
-
|
|
31
|
+
To try it without touching your real home directory, point `HOME` and the
|
|
32
|
+
XDG directories at a scratch directory:
|
|
33
|
+
|
|
34
|
+
```sh
|
|
29
35
|
(
|
|
30
36
|
set -eu
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
export HOME="$_demo_state/home"
|
|
41
|
-
export XDG_DATA_HOME="$_demo_state/data"
|
|
42
|
-
export XDG_CONFIG_HOME="$_demo_state/config"
|
|
43
|
-
export XDG_STATE_HOME="$_demo_state/state"
|
|
44
|
-
|
|
45
|
-
# Build, install, and verify the sample release.
|
|
46
|
-
sh examples/e2e/build-manifest.sh
|
|
47
|
-
(cd examples/e2e && valise install)
|
|
48
|
-
valise verify-active
|
|
49
|
-
|
|
50
|
-
# Load two shipped utilities from the installed release.
|
|
51
|
-
_active=$(cd "$XDG_CONFIG_HOME/valise/active" && pwd -P)
|
|
52
|
-
VALISE_MODULE_ROOT="$_active" \
|
|
53
|
-
VALISE_MODULES='contrib_path contrib_editor' \
|
|
54
|
-
VALISE_MODE=strict \
|
|
55
|
-
. "$_active/entrypoints/profile.sh"
|
|
56
|
-
contrib_path_prepend "$HOME/.local/bin"
|
|
57
|
-
contrib_editor_defaults
|
|
58
|
-
printf 'EDITOR=%s\nPATH=%s\n' "${EDITOR-(unset: no supported editor found on PATH)}" "$PATH"
|
|
37
|
+
demo=$(mktemp -d)
|
|
38
|
+
trap 'chmod -R u+w "$demo"; rm -rf "$demo"' EXIT
|
|
39
|
+
export HOME="$demo/home" XDG_DATA_HOME="$demo/data" \
|
|
40
|
+
XDG_CONFIG_HOME="$demo/config" XDG_STATE_HOME="$demo/state" \
|
|
41
|
+
XDG_BIN_HOME="$demo/bin"
|
|
42
|
+
mkdir -p "$HOME"
|
|
43
|
+
cd valise-sh/examples/profile-project
|
|
44
|
+
valise apply
|
|
45
|
+
bash -l -c greet
|
|
59
46
|
)
|
|
60
47
|
```
|
|
61
48
|
|
|
62
|
-
|
|
63
|
-
and other modules in
|
|
64
|
-
[examples/e2e/README.md](examples/e2e/README.md). For the smallest possible
|
|
65
|
-
loader example without installation, use `examples/local/` as described in
|
|
66
|
-
[examples/README.md](examples/README.md).
|
|
67
|
-
|
|
68
|
-
## Repository layout
|
|
69
|
-
|
|
70
|
-
- `entrypoints/profile.sh` — the portable entrypoint. It is sourced, not
|
|
71
|
-
executed: it resolves the engine root, sources the three libraries, and
|
|
72
|
-
calls the loader with the requested modules.
|
|
73
|
-
- `lib/metadata.sh` — parses `module.d/*.meta` files as data and validates
|
|
74
|
-
identifiers, lists, paths, shells, platforms, and side-effect classes.
|
|
75
|
-
- `lib/loader.sh` — resolves the dependency closure, selects modules by
|
|
76
|
-
shell/platform/phase, sources bodies, checks declared exports, and cleans
|
|
77
|
-
up on failure.
|
|
78
|
-
- `lib/capabilities.sh` — portable helpers (`sp_cap_*`) that modules call
|
|
79
|
-
instead of platform-specific commands.
|
|
80
|
-
- `lib/fish/` — native Fish loader and metadata reader. The Fish path never
|
|
81
|
-
sources POSIX shell bodies.
|
|
82
|
-
- `bin/valise` — the CLI: init, install, doctor, variant, make-manifest,
|
|
83
|
-
compile, verify-active, explain-variant, explain-bundles, layer-lint,
|
|
84
|
-
version. `init`, `install`, `doctor`, `variant`, `make-manifest`,
|
|
85
|
-
`verify-active`, and `version` run from a bare checkout; `compile`,
|
|
86
|
-
`explain-variant`, `explain-bundles`, and `layer-lint` require the
|
|
87
|
-
consuming project's source tree (see
|
|
88
|
-
[docs/variants.md](docs/variants.md) and
|
|
89
|
-
[docs/contrib-modules.md](docs/contrib-modules.md).
|
|
90
|
-
- `module.d/` and `modules/platform/` — generic platform modules
|
|
91
|
-
(`platform_posix`, `platform_macos`, `platform_linux`, `platform_bsd`).
|
|
92
|
-
- `manifests/parser-support.tsv` — declares the shell parsers used to check
|
|
93
|
-
each source-file class.
|
|
94
|
-
- `tests/` — the test suite. Every test runs in a quarantined environment:
|
|
95
|
-
fresh temporary HOME, controlled TMPDIR and PATH, cleared startup hooks.
|
|
96
|
-
- `examples/local/` — a minimal runnable module demonstrating the metadata
|
|
97
|
-
contract.
|
|
98
|
-
|
|
99
|
-
Product-specific modules, adapters, release packaging, and installer
|
|
100
|
-
transactions belong in the consuming project, not here. See
|
|
101
|
-
[docs/architecture.md](docs/architecture.md) for the scope.
|
|
102
|
-
|
|
103
|
-
## Documentation
|
|
49
|
+
## A project
|
|
104
50
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
exclusion lists.
|
|
114
|
-
- [docs/contrib-modules.md](docs/contrib-modules.md) — module authoring
|
|
115
|
-
reference.
|
|
116
|
-
- [docs/shared-modules.md](docs/shared-modules.md) — governance and index
|
|
117
|
-
for shared modules: namespace ownership, review, deprecation, removal.
|
|
118
|
-
- [docs/release-policy.md](docs/release-policy.md) — compatibility surfaces,
|
|
119
|
-
current pre-1.0 status, and the release checklist.
|
|
120
|
-
- [CHANGELOG.md](CHANGELOG.md) — user-facing changes.
|
|
121
|
-
|
|
122
|
-
## Running the tests
|
|
51
|
+
```
|
|
52
|
+
valise.conf project settings
|
|
53
|
+
module.d/ <name>.meta: one metadata file per module
|
|
54
|
+
modules/ module bodies
|
|
55
|
+
layers/<p>/ modules vendored from another provider (optional)
|
|
56
|
+
bundles.tsv the root modules for each shell
|
|
57
|
+
variants.tsv named sets of modules to leave out (optional)
|
|
58
|
+
```
|
|
123
59
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
60
|
+
A module's metadata names its dependencies, the shells and platforms it
|
|
61
|
+
supports, the functions it exports, and optionally the exports to publish
|
|
62
|
+
as commands on `PATH`:
|
|
63
|
+
|
|
64
|
+
```text
|
|
65
|
+
name=hello
|
|
66
|
+
version=1.0.0
|
|
67
|
+
side_effect=read-only
|
|
68
|
+
requires=valise_path
|
|
69
|
+
optional=
|
|
70
|
+
shells=posix
|
|
71
|
+
platforms=any
|
|
72
|
+
exports=hello
|
|
73
|
+
commands=hello
|
|
74
|
+
tests=tests/hello.sh
|
|
75
|
+
load=modules/hello.sh
|
|
127
76
|
```
|
|
128
77
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
`
|
|
134
|
-
and run
|
|
135
|
-
|
|
78
|
+
## Commands
|
|
79
|
+
|
|
80
|
+
| Command | Does |
|
|
81
|
+
|---|---|
|
|
82
|
+
| `new`, `module new\|list\|remove` | Scaffold a project and its modules. |
|
|
83
|
+
| `lint`, `test`, `run`, `env` | Check metadata and syntax, run module tests in a clean shell, run a script with modules loaded, print paths. |
|
|
84
|
+
| `build`, `apply`, `status` | Build a release, build and install it, compare the active release with the build. |
|
|
85
|
+
| `install`, `release list\|use\|rollback\|prune\|verify`, `uninstall` | Manage installed releases. |
|
|
86
|
+
| `init`, `doctor` | Print the startup snippet; diagnose the installation. |
|
|
87
|
+
| `compile`, `registry`, `explain-bundles`, `explain-variant`, `layer-lint`, `make-manifest` | Inspect and debug a build. |
|
|
88
|
+
|
|
89
|
+
`valise <command> --help` prints each command's contract.
|
|
90
|
+
|
|
91
|
+
## Documentation
|
|
92
|
+
|
|
93
|
+
- [docs/projects.md](docs/projects.md): the project layout, bundles,
|
|
94
|
+
variants, compile, and build.
|
|
95
|
+
- [docs/contrib-modules.md](docs/contrib-modules.md): writing, linting, and
|
|
96
|
+
testing modules.
|
|
97
|
+
- [docs/module-abi.md](docs/module-abi.md): every metadata field and what
|
|
98
|
+
the plans do with it.
|
|
99
|
+
- [docs/installation.md](docs/installation.md): installing the CLI, startup
|
|
100
|
+
files, published commands, the release store, and uninstalling.
|
|
101
|
+
- [docs/architecture.md](docs/architecture.md): how the pieces fit and what
|
|
102
|
+
stays in your project.
|
|
103
|
+
- [docs/shared-modules.md](docs/shared-modules.md): layers other people
|
|
104
|
+
consume.
|
|
105
|
+
- [docs/release-policy.md](docs/release-policy.md): compatibility and the
|
|
106
|
+
release checklist.
|
|
107
|
+
- [examples/](examples/README.md): a sample project, a multi-shell test
|
|
108
|
+
project, and a sample provider layer.
|
|
109
|
+
- [CHANGELOG.md](CHANGELOG.md)
|
|
110
|
+
|
|
111
|
+
## Development
|
|
136
112
|
|
|
137
113
|
```sh
|
|
138
|
-
make
|
|
114
|
+
make check-fast # quick lane; no optional shells required
|
|
115
|
+
make check # every available shell and runtime lane
|
|
139
116
|
```
|
|
140
117
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
118
|
+
`make check` uses the parsers in `manifests/parser-support.tsv`, the shells
|
|
119
|
+
`sh`, `bash`, `zsh`, `ksh`, `dash`, and `fish`, and BusyBox. A missing tool
|
|
120
|
+
is a visible skip locally and a failure when `CI=true` or
|
|
121
|
+
`GITHUB_ACTIONS=true`; `make VALISE_REQUIRE_TOOLING=1 check` requires them
|
|
122
|
+
locally. Machine-local settings go in an untracked `config.mk` (see
|
|
123
|
+
`config.mk.example`). Lima VM lanes run only when the instances exist.
|